javaclass

Change of bytecode.py

35:630f6b688af0
bytecode.py
     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