1.1 --- a/bytecode.py Thu Nov 11 22:56:50 2004 +0100
1.2 +++ b/bytecode.py Thu Nov 11 22:59:18 2004 +0100
1.3 @@ -9,6 +9,7 @@
1.4
1.5 from dis import opmap, cmp_op # for access to Python bytecode values and operators
1.6 from UserDict import UserDict
1.7 +import new
1.8
1.9 # Bytecode production classes.
1.10
1.11 @@ -1266,6 +1267,7 @@
1.12 # NOTE: Java rules not specifically obeyed.
1.13 index = (arguments[0] << 8) + arguments[1]
1.14 target = self.class_file.constants[index - 1]
1.15 + original_name = target.get_name()
1.16 target_name = target.get_python_name()
1.17 # Get the number of parameters from the descriptor.
1.18 count = len(target.get_descriptor()[0])
1.19 @@ -1297,7 +1299,7 @@
1.20
1.21 # Is another class or reference.
1.22 # NOTE: Reference case not covered!
1.23 - if str(target_name) == "__init__":
1.24 + if str(original_name) == "<init>":
1.25 program.rot_two() # Stack: reference, tuple
1.26 program.load_const(1) # Stack: reference, tuple, 1
1.27 program.slice_1() # Stack: reference, tuple[1:]
1.28 @@ -1671,11 +1673,66 @@
1.29 disassembler = BytecodeDisassembler(class_file)
1.30 disassembler.process(method, BytecodeDisassemblerProgram())
1.31
1.32 -def translate(class_file, method):
1.33 - translator = BytecodeTranslator(class_file)
1.34 - writer = BytecodeWriter()
1.35 - translator.process(method, writer)
1.36 - return translator, writer
1.37 +class ClassTranslator:
1.38 + def __init__(self, class_file):
1.39 + self.class_file = class_file
1.40 + self.filename = str(self.class_file.attributes[0].get_name())
1.41 +
1.42 + def translate_method(self, method):
1.43 + translator = BytecodeTranslator(self.class_file)
1.44 + writer = BytecodeWriter()
1.45 + translator.process(method, writer)
1.46 + return translator, writer
1.47 +
1.48 + def make_method(self, method_name, methods, namespace):
1.49 + if method_name == "<init>":
1.50 + method_name = "__init__"
1.51 + # Where only one method exists, just make an alias.
1.52 + if len(methods) == 1:
1.53 + method, fn = methods[0]
1.54 + namespace[method_name] = fn
1.55 + return
1.56 + return # for now
1.57 + # Find the maximum number of parameters involved.
1.58 + #maximum = max([len(method.get_descriptor()[0]) for method in methods])
1.59 + #program = BytecodeWriter()
1.60 + # NOTE: The code below should use dictionary-based dispatch for better performance.
1.61 + #for method in methods:
1.62 + # program.load_fast(1) # Stack: arguments
1.63 + # program.get_iter() # Stack: arguments, iter
1.64 + # program.for_iter() # Stack: arguments, iter, argument
1.65 + # program.dup_top() # Stack: arguments, iter, argument, argument
1.66 + # for parameter in method.get_descriptor()[0]:
1.67 +
1.68 + def process(self, global_names):
1.69 + namespace = {}
1.70 + real_methods = {}
1.71 + for method in self.class_file.methods:
1.72 + t, w = self.translate_method(method)
1.73 + nlocals = w.max_locals + 1
1.74 + nargs = len(method.get_descriptor()[0]) + 1
1.75 + method_name = str(method.get_python_name())
1.76 + # NOTE: Add line number table later.
1.77 + code = new.code(nargs, nlocals, w.max_stack_depth, 67, w.get_output(), tuple(w.get_constants()), tuple(w.get_names()),
1.78 + tuple(make_varnames(nlocals)), self.filename, method_name, 0, "")
1.79 + # NOTE: May need more globals.
1.80 + fn = new.function(code, global_names)
1.81 + namespace[method_name] = fn
1.82 + real_method_name = str(method.get_name())
1.83 + if not real_methods.has_key(real_method_name):
1.84 + real_methods[real_method_name] = []
1.85 + real_methods[real_method_name].append((method, fn))
1.86 + # NOTE: Define superclasses properly.
1.87 + if str(self.class_file.super_class.get_name()) not in ("java/lang/Object", "java/lang/Exception"):
1.88 + bases = (global_names[str(self.class_file.super_class.get_python_name())],)
1.89 + else:
1.90 + bases = ()
1.91 + # Define method dispatchers.
1.92 + for real_method_name, methods in real_methods.items():
1.93 + self.make_method(real_method_name, methods, namespace)
1.94 + cls = new.classobj(str(self.class_file.this_class.get_python_name()), bases, namespace)
1.95 + global_names[cls.__name__] = cls
1.96 + return cls
1.97
1.98 def make_varnames(nlocals):
1.99 l = ["self"]
1.100 @@ -1686,30 +1743,13 @@
1.101 if __name__ == "__main__":
1.102 import sys
1.103 from classfile import ClassFile
1.104 + import dis
1.105 global_names = {}
1.106 global_names.update(__builtins__.__dict__)
1.107 for filename in sys.argv[1:]:
1.108 f = open(filename, "rb")
1.109 c = ClassFile(f.read())
1.110 - import dis, new
1.111 - namespace = {}
1.112 - for method in c.methods:
1.113 - nargs = len(method.get_descriptor()[0]) + 1
1.114 - t, w = translate(c, method)
1.115 - nlocals = w.max_locals + 1
1.116 - filename = str(c.attributes[0].get_name())
1.117 - method_name = str(method.get_python_name())
1.118 - code = new.code(nargs, nlocals, w.max_stack_depth, 67, w.get_output(), tuple(w.get_constants()), tuple(w.get_names()),
1.119 - tuple(make_varnames(nlocals)), filename, method_name, 0, "")
1.120 - # NOTE: May need more globals.
1.121 - fn = new.function(code, global_names)
1.122 - namespace[method_name] = fn
1.123 - # NOTE: Define superclasses properly.
1.124 - if str(c.super_class.get_name()) not in ("java/lang/Object", "java/lang/Exception"):
1.125 - bases = (global_names[str(c.super_class.get_python_name())],)
1.126 - else:
1.127 - bases = ()
1.128 - cls = new.classobj(str(c.this_class.get_python_name()), bases, namespace)
1.129 - global_names[cls.__name__] = cls
1.130 + translator = ClassTranslator(c)
1.131 + cls = translator.process(global_names)
1.132
1.133 # vim: tabstop=4 expandtab shiftwidth=4