javaclass

Changeset

18:2a50b70c772b
2004-11-09 Paul Boddie raw files shortlog changelog graph Fixed comparison plus branch (if_acmp*) by removing the comparison result from the operand stack. Added stack top duplication before RAISE_VARARGS so that the appropriate handlers can save the value. Changed the value stored in the load_const_ret method so that None is stored (although this may need verifying). When the translated ret instruction (END_FINALLY in the Python VM, again requiring verification) is executed, the value loaded just prior to its execution should be the same as that saved at the beginning of the handler, and this should be None or a raised exception. NOTE: The load_const_ret translation should arguably retrieve the saved NOTE: value from the beginning of any active handler instead of just NOTE: loading None. This may be assured in try...finally constructs NOTE: (without catch sections), however. Rearranged Python VM instruction insertion for exceptions. Changed some load_global(None) usage to load_const(None). Added instruction positions in the disassembly output.
bytecode.py (file)
     1.1 --- a/bytecode.py	Tue Nov 09 19:49:04 2004 +0100
     1.2 +++ b/bytecode.py	Tue Nov 09 20:00:59 2004 +0100
     1.3 @@ -155,10 +155,12 @@
     1.4          del self.jumps[name]
     1.5  
     1.6      def load_const_ret(self, value):
     1.7 -        self.constants_for_exceptions.append(value)
     1.8 -        self.load_const(value)
     1.9 +        #self.constants_for_exceptions.append(value)
    1.10 +        #self.load_const(value)
    1.11 +        self.load_const(None)
    1.12  
    1.13      def ret(self, index):
    1.14 +        self.load_fast(index)
    1.15          self.end_finally()
    1.16  
    1.17      def setup_except(self, target):
    1.18 @@ -502,21 +504,13 @@
    1.19                  else:
    1.20                      program.setup_except(self.position_mapping[exception.handler_pc])
    1.21  
    1.22 -            # Insert exception block end details.
    1.23 -            for exception in exception_block_end.get(self.java_position, []):
    1.24 -                # NOTE: Insert jump beyond handlers.
    1.25 -                # NOTE: program.jump_forward/absolute(...)
    1.26 -                # NOTE: Insert end finally at end of handlers as well as where "ret" occurs.
    1.27 -                if exception.catch_type != 0:
    1.28 -                    program.pop_block()
    1.29 -
    1.30              # Insert exception handler details.
    1.31              # NOTE: Ensure that pop_block is reachable by possibly inserting it at the start of finally handlers.
    1.32              # NOTE: Insert a check for the correct exception at the start of each handler.
    1.33              for exception in exception_block_handler.get(self.java_position, []):
    1.34                  program.end_exception()
    1.35 -                if exception.catch_type == 0:
    1.36 -                    program.pop_block()
    1.37 +                #if exception.catch_type == 0:
    1.38 +                #    program.pop_block()
    1.39  
    1.40              # Where handlers are begun, do not produce equivalent bytecode since
    1.41              # the first handler instruction typically involves saving a local
    1.42 @@ -529,6 +523,14 @@
    1.43              number_of_arguments = self.process_bytecode(mnemonic, number_of_arguments, code, program)
    1.44              next_java_position = self.java_position + 1 + number_of_arguments
    1.45  
    1.46 +            # Insert exception block end details.
    1.47 +            for exception in exception_block_end.get(next_java_position, []):
    1.48 +                # NOTE: Insert jump beyond handlers.
    1.49 +                # NOTE: program.jump_forward/absolute(...)
    1.50 +                # NOTE: Insert end finally at end of handlers as well as where "ret" occurs.
    1.51 +                if exception.catch_type != 0:
    1.52 +                    program.pop_block()
    1.53 +
    1.54              # Only advance the JVM position after sneaking in extra Python
    1.55              # instructions.
    1.56              self.java_position = next_java_position
    1.57 @@ -759,7 +761,7 @@
    1.58  
    1.59      def __getattr__(self, name):
    1.60          if name in self.bytecode_methods:
    1.61 -            print name,
    1.62 +            print "%5s %s" % (self.java_position, name),
    1.63              return self.generic
    1.64          else:
    1.65              raise AttributeError, name
    1.66 @@ -793,7 +795,7 @@
    1.67          program.store_subscr()
    1.68  
    1.69      def aconst_null(self, arguments, program):
    1.70 -        program.load_global(None)
    1.71 +        program.load_const(None)
    1.72  
    1.73      def aload(self, arguments, program):
    1.74          program.load_fast(arguments[0])
    1.75 @@ -831,7 +833,7 @@
    1.76          program.rot_two()           # Stack: iter, list
    1.77          program.dup_top()           # Stack: iter, list, list
    1.78          program.load_attr("append") # Stack: iter, list, append
    1.79 -        program.load_global(None)   # Stack: iter, list, append, None
    1.80 +        program.load_const(None)    # Stack: iter, list, append, None
    1.81          program.call_function(1)    # Stack: iter, list, None
    1.82          program.pop_top()           # Stack: iter, list
    1.83          program.rot_two()           # Stack: list, iter
    1.84 @@ -862,6 +864,7 @@
    1.85  
    1.86      def athrow(self, arguments, program):
    1.87          # NOTE: NullPointerException not raised where null/None is found on the stack.
    1.88 +        program.dup_top()
    1.89          program.raise_varargs(1)
    1.90  
    1.91      baload = aaload
    1.92 @@ -1087,8 +1090,10 @@
    1.93          java_absolute = self.java_position + offset
    1.94          program.compare_op(op)
    1.95          program.jump_to_label(0, "next") # skip if false
    1.96 +        program.pop_top()
    1.97          program.jump_absolute(self.position_mapping[java_absolute])
    1.98          program.start_label("next")
    1.99 +        program.pop_top()
   1.100  
   1.101      def if_acmpeq(self, arguments, program):
   1.102          # NOTE: No type checking performed.
   1.103 @@ -1554,26 +1559,30 @@
   1.104  if __name__ == "__main__":
   1.105      import sys
   1.106      from classfile import ClassFile
   1.107 -    f = open(sys.argv[1])
   1.108 -    c = ClassFile(f.read())
   1.109 -    import dis, new
   1.110 -    namespace = {}
   1.111 -    for method in c.methods:
   1.112 -        attribute = method.attributes[0]
   1.113 -        nargs = len(method.get_descriptor()[0]) + 1
   1.114 -        t, w = translate(c, attribute.code, attribute.exception_table)
   1.115 -        nlocals = w.max_locals + 1
   1.116 -        filename = str(c.attributes[0].get_name())
   1.117 -        method_name = str(method.get_name())
   1.118 -        if method_name == "<init>":
   1.119 -            method_name = "__init__"
   1.120 -        code = new.code(nargs, nlocals, w.max_stack_depth, 67, w.get_output(), tuple(w.get_constants()), tuple(w.get_names()),
   1.121 -            tuple(make_varnames(nlocals)), filename, method_name, 0, "")
   1.122 -        # NOTE: May need more globals.
   1.123 -        fn = new.function(code, __builtins__.__dict__)
   1.124 -        namespace[method_name] = fn
   1.125 -    namespace["__java_init__"] = __java_init__
   1.126 -    # NOTE: Define superclasses properly.
   1.127 -    cls = new.classobj(str(c.this_class.get_name()), (), namespace)
   1.128 +    global_names = {}
   1.129 +    global_names.update(__builtins__.__dict__)
   1.130 +    for filename in sys.argv[1:]:
   1.131 +        f = open(filename, "rb")
   1.132 +        c = ClassFile(f.read())
   1.133 +        import dis, new
   1.134 +        namespace = {}
   1.135 +        for method in c.methods:
   1.136 +            attribute = method.attributes[0]
   1.137 +            nargs = len(method.get_descriptor()[0]) + 1
   1.138 +            t, w = translate(c, attribute.code, attribute.exception_table)
   1.139 +            nlocals = w.max_locals + 1
   1.140 +            filename = str(c.attributes[0].get_name())
   1.141 +            method_name = str(method.get_name())
   1.142 +            if method_name == "<init>":
   1.143 +                method_name = "__init__"
   1.144 +            code = new.code(nargs, nlocals, w.max_stack_depth, 67, w.get_output(), tuple(w.get_constants()), tuple(w.get_names()),
   1.145 +                tuple(make_varnames(nlocals)), filename, method_name, 0, "")
   1.146 +            # NOTE: May need more globals.
   1.147 +            fn = new.function(code, global_names)
   1.148 +            namespace[method_name] = fn
   1.149 +        namespace["__java_init__"] = __java_init__
   1.150 +        # NOTE: Define superclasses properly.
   1.151 +        cls = new.classobj(str(c.this_class.get_name()), (), namespace)
   1.152 +        global_names[cls.__name__] = cls
   1.153  
   1.154  # vim: tabstop=4 expandtab shiftwidth=4