1.1 --- a/bytecode.py Tue Nov 09 18:45:57 2004 +0100
1.2 +++ b/bytecode.py Tue Nov 09 18:52:06 2004 +0100
1.3 @@ -36,6 +36,9 @@
1.4 self.stack_depth = 0
1.5 self.max_stack_depth = 0
1.6
1.7 + # Local variable estimation.
1.8 + self.max_locals = 0
1.9 +
1.10 # Mapping from values to indexes.
1.11 self.constants = {}
1.12
1.13 @@ -94,6 +97,10 @@
1.14 if self.stack_depth > self.max_stack_depth:
1.15 self.max_stack_depth = self.stack_depth
1.16
1.17 + def update_locals(self, index):
1.18 + if index > self.max_locals:
1.19 + self.max_locals = index
1.20 +
1.21 # Special methods.
1.22
1.23 def _write_value(self, value):
1.24 @@ -157,6 +164,7 @@
1.25 def setup_except(self, target):
1.26 self.blocks.append(self.position)
1.27 self.exception_handlers.append(target)
1.28 + print "-", self.position, target
1.29 self.output.append(opmap["SETUP_EXCEPT"])
1.30 self.position += 1
1.31 self._write_value(0) # To be filled in later
1.32 @@ -164,6 +172,7 @@
1.33 def setup_finally(self, target):
1.34 self.blocks.append(self.position)
1.35 self.exception_handlers.append(target)
1.36 + print "-", self.position, target
1.37 self.output.append(opmap["SETUP_FINALLY"])
1.38 self.position += 1
1.39 self._write_value(0) # To be filled in later
1.40 @@ -173,6 +182,7 @@
1.41 # Convert the "lazy" absolute value.
1.42 current_exception_target = self.exception_handlers.pop()
1.43 target = current_exception_target.get_value()
1.44 + print "*", current_exception_start, target
1.45 # NOTE: Using 3 as the assumed length of the SETUP_* instruction.
1.46 # NOTE: 8-bit limit.
1.47 self.output[current_exception_start + 1] = target - current_exception_start - 3
1.48 @@ -217,6 +227,7 @@
1.49 self.position += 1
1.50 self._write_value(index)
1.51 self.update_stack_depth(1)
1.52 + self.update_locals(index)
1.53
1.54 def store_attr(self, name):
1.55 self.output.append(opmap["STORE_ATTR"])
1.56 @@ -231,6 +242,7 @@
1.57 self.position += 1
1.58 self._write_value(index)
1.59 self.update_stack_depth(-1)
1.60 + self.update_locals(index)
1.61
1.62 # Normal bytecode generators.
1.63
1.64 @@ -490,14 +502,21 @@
1.65 else:
1.66 program.setup_except(self.position_mapping[exception.handler_pc])
1.67
1.68 - # Insert exception handler end details.
1.69 + # Insert exception block end details.
1.70 for exception in exception_block_end.get(self.java_position, []):
1.71 # NOTE: Insert jump beyond handlers.
1.72 # NOTE: program.jump_forward/absolute(...)
1.73 + # NOTE: Insert end finally at end of handlers as well as where "ret" occurs.
1.74 + if exception.catch_type != 0:
1.75 + program.pop_block()
1.76 +
1.77 + # Insert exception handler details.
1.78 + # NOTE: Ensure that pop_block is reachable by possibly inserting it at the start of finally handlers.
1.79 + # NOTE: Insert a check for the correct exception at the start of each handler.
1.80 + for exception in exception_block_handler.get(self.java_position, []):
1.81 program.end_exception()
1.82 - # NOTE: Insert a check for the correct exception at the start of each handler.
1.83 - # NOTE: Insert end finally at end of handlers as well as where "ret" occurs.
1.84 - # NOTE: Ensure that pop_block is reachable by possibly inserting it at the start of finally handlers.
1.85 + if exception.catch_type == 0:
1.86 + program.pop_block()
1.87
1.88 # Where handlers are begun, do not produce equivalent bytecode since
1.89 # the first handler instruction typically involves saving a local
1.90 @@ -510,10 +529,6 @@
1.91 number_of_arguments = self.process_bytecode(mnemonic, number_of_arguments, code, program)
1.92 next_java_position = self.java_position + 1 + number_of_arguments
1.93
1.94 - # Insert exception handler end instructions.
1.95 - for exception in exception_block_end.get(next_java_position, []):
1.96 - program.pop_block()
1.97 -
1.98 # Only advance the JVM position after sneaking in extra Python
1.99 # instructions.
1.100 self.java_position = next_java_position
1.101 @@ -1072,7 +1087,7 @@
1.102 java_absolute = self.java_position + offset
1.103 program.compare_op(op)
1.104 program.jump_to_label(0, "next") # skip if false
1.105 - program.goto(offset)
1.106 + program.jump_absolute(self.position_mapping[java_absolute])
1.107 program.start_label("next")
1.108
1.109 def if_acmpeq(self, arguments, program):
1.110 @@ -1204,6 +1219,21 @@
1.111 # Get the number of parameters from the descriptor.
1.112 count = len(target.get_descriptor()[0])
1.113 # Stack: objectref, arg1, arg2, ...
1.114 + program.build_tuple(count) # Stack: objectref, tuple
1.115 + program.rot_two() # Stack: tuple, objectref
1.116 + self._invoke(target_name, program)
1.117 +
1.118 + """
1.119 + def invokespecial(self, arguments, program):
1.120 + # NOTE: This implementation does not perform the necessary checks for
1.121 + # NOTE: signature-based polymorphism.
1.122 + # NOTE: Java rules not specifically obeyed.
1.123 + index = (arguments[0] << 8) + arguments[1]
1.124 + target = self.class_file.constants[index - 1]
1.125 + target_name = target.get_python_name()
1.126 + # Get the number of parameters from the descriptor.
1.127 + count = len(target.get_descriptor()[0])
1.128 + # Stack: objectref, arg1, arg2, ...
1.129 program.build_tuple(count + 1) # Stack: tuple
1.130 # Use the class to provide access to static methods.
1.131 program.load_name("self") # Stack: tuple, self
1.132 @@ -1226,6 +1256,7 @@
1.133 program.pop_top() # Stack: tuple
1.134 program.pop_top() # Stack:
1.135 program.start_label("next2")
1.136 + """
1.137
1.138 def invokestatic(self, arguments, program):
1.139 # NOTE: This implementation does not perform the necessary checks for
1.140 @@ -1511,10 +1542,38 @@
1.141 translator.process(code, exception_table, writer)
1.142 return translator, writer
1.143
1.144 +def make_varnames(nlocals):
1.145 + l = ["self"]
1.146 + for i in range(1, nlocals):
1.147 + l.append("_l%s" % i)
1.148 + return l[:nlocals]
1.149 +
1.150 +def __java_init__(self, *args):
1.151 + print "<init>", args
1.152 +
1.153 if __name__ == "__main__":
1.154 import sys
1.155 from classfile import ClassFile
1.156 f = open(sys.argv[1])
1.157 c = ClassFile(f.read())
1.158 + import dis, new
1.159 + namespace = {}
1.160 + for method in c.methods:
1.161 + attribute = method.attributes[0]
1.162 + nargs = len(method.get_descriptor()[0]) + 1
1.163 + t, w = translate(c, attribute.code, attribute.exception_table)
1.164 + nlocals = w.max_locals + 1
1.165 + filename = str(c.attributes[0].get_name())
1.166 + method_name = str(method.get_name())
1.167 + if method_name == "<init>":
1.168 + method_name = "__init__"
1.169 + code = new.code(nargs, nlocals, w.max_stack_depth, 67, w.get_output(), tuple(w.get_constants()), tuple(w.get_names()),
1.170 + tuple(make_varnames(nlocals)), filename, method_name, 0, "")
1.171 + # NOTE: May need more globals.
1.172 + fn = new.function(code, __builtins__.__dict__)
1.173 + namespace[method_name] = fn
1.174 + namespace["__java_init__"] = __java_init__
1.175 + # NOTE: Define superclasses properly.
1.176 + cls = new.classobj(str(c.this_class.get_name()), (), namespace)
1.177
1.178 # vim: tabstop=4 expandtab shiftwidth=4