# HG changeset patch # User Paul Boddie # Date 1100022726 -3600 # Node ID bd70c69bd9aea66087a6975e5a00ef3e9f724dfc # Parent 946dca5710eab90b52f148343da6663855a524de Added local variable usage tracking. Changed the invokespecial implementation, since it probably has very little to do with superclass method invocation specifically. Extended the test program to try and assemble an entire class. Attempted to fix block gymnastics for exceptions. diff -r 946dca5710ea -r bd70c69bd9ae bytecode.py --- a/bytecode.py Tue Nov 09 18:45:57 2004 +0100 +++ b/bytecode.py Tue Nov 09 18:52:06 2004 +0100 @@ -36,6 +36,9 @@ self.stack_depth = 0 self.max_stack_depth = 0 + # Local variable estimation. + self.max_locals = 0 + # Mapping from values to indexes. self.constants = {} @@ -94,6 +97,10 @@ if self.stack_depth > self.max_stack_depth: self.max_stack_depth = self.stack_depth + def update_locals(self, index): + if index > self.max_locals: + self.max_locals = index + # Special methods. def _write_value(self, value): @@ -157,6 +164,7 @@ def setup_except(self, target): self.blocks.append(self.position) self.exception_handlers.append(target) + print "-", self.position, target self.output.append(opmap["SETUP_EXCEPT"]) self.position += 1 self._write_value(0) # To be filled in later @@ -164,6 +172,7 @@ def setup_finally(self, target): self.blocks.append(self.position) self.exception_handlers.append(target) + print "-", self.position, target self.output.append(opmap["SETUP_FINALLY"]) self.position += 1 self._write_value(0) # To be filled in later @@ -173,6 +182,7 @@ # Convert the "lazy" absolute value. current_exception_target = self.exception_handlers.pop() target = current_exception_target.get_value() + print "*", current_exception_start, target # NOTE: Using 3 as the assumed length of the SETUP_* instruction. # NOTE: 8-bit limit. self.output[current_exception_start + 1] = target - current_exception_start - 3 @@ -217,6 +227,7 @@ self.position += 1 self._write_value(index) self.update_stack_depth(1) + self.update_locals(index) def store_attr(self, name): self.output.append(opmap["STORE_ATTR"]) @@ -231,6 +242,7 @@ self.position += 1 self._write_value(index) self.update_stack_depth(-1) + self.update_locals(index) # Normal bytecode generators. @@ -490,14 +502,21 @@ else: program.setup_except(self.position_mapping[exception.handler_pc]) - # Insert exception handler end details. + # Insert exception block end details. for exception in exception_block_end.get(self.java_position, []): # NOTE: Insert jump beyond handlers. # NOTE: program.jump_forward/absolute(...) + # NOTE: Insert end finally at end of handlers as well as where "ret" occurs. + if exception.catch_type != 0: + program.pop_block() + + # Insert exception handler details. + # NOTE: Ensure that pop_block is reachable by possibly inserting it at the start of finally handlers. + # NOTE: Insert a check for the correct exception at the start of each handler. + for exception in exception_block_handler.get(self.java_position, []): program.end_exception() - # NOTE: Insert a check for the correct exception at the start of each handler. - # NOTE: Insert end finally at end of handlers as well as where "ret" occurs. - # NOTE: Ensure that pop_block is reachable by possibly inserting it at the start of finally handlers. + if exception.catch_type == 0: + program.pop_block() # Where handlers are begun, do not produce equivalent bytecode since # the first handler instruction typically involves saving a local @@ -510,10 +529,6 @@ number_of_arguments = self.process_bytecode(mnemonic, number_of_arguments, code, program) next_java_position = self.java_position + 1 + number_of_arguments - # Insert exception handler end instructions. - for exception in exception_block_end.get(next_java_position, []): - program.pop_block() - # Only advance the JVM position after sneaking in extra Python # instructions. self.java_position = next_java_position @@ -1072,7 +1087,7 @@ java_absolute = self.java_position + offset program.compare_op(op) program.jump_to_label(0, "next") # skip if false - program.goto(offset) + program.jump_absolute(self.position_mapping[java_absolute]) program.start_label("next") def if_acmpeq(self, arguments, program): @@ -1204,6 +1219,21 @@ # Get the number of parameters from the descriptor. count = len(target.get_descriptor()[0]) # Stack: objectref, arg1, arg2, ... + program.build_tuple(count) # Stack: objectref, tuple + program.rot_two() # Stack: tuple, objectref + self._invoke(target_name, program) + + """ + def invokespecial(self, arguments, program): + # NOTE: This implementation does not perform the necessary checks for + # NOTE: signature-based polymorphism. + # NOTE: Java rules not specifically obeyed. + index = (arguments[0] << 8) + arguments[1] + target = self.class_file.constants[index - 1] + target_name = target.get_python_name() + # Get the number of parameters from the descriptor. + count = len(target.get_descriptor()[0]) + # Stack: objectref, arg1, arg2, ... program.build_tuple(count + 1) # Stack: tuple # Use the class to provide access to static methods. program.load_name("self") # Stack: tuple, self @@ -1226,6 +1256,7 @@ program.pop_top() # Stack: tuple program.pop_top() # Stack: program.start_label("next2") + """ def invokestatic(self, arguments, program): # NOTE: This implementation does not perform the necessary checks for @@ -1511,10 +1542,38 @@ translator.process(code, exception_table, writer) return translator, writer +def make_varnames(nlocals): + l = ["self"] + for i in range(1, nlocals): + l.append("_l%s" % i) + return l[:nlocals] + +def __java_init__(self, *args): + print "", args + if __name__ == "__main__": import sys from classfile import ClassFile f = open(sys.argv[1]) c = ClassFile(f.read()) + import dis, new + namespace = {} + for method in c.methods: + attribute = method.attributes[0] + nargs = len(method.get_descriptor()[0]) + 1 + t, w = translate(c, attribute.code, attribute.exception_table) + nlocals = w.max_locals + 1 + filename = str(c.attributes[0].get_name()) + method_name = str(method.get_name()) + if method_name == "": + method_name = "__init__" + code = new.code(nargs, nlocals, w.max_stack_depth, 67, w.get_output(), tuple(w.get_constants()), tuple(w.get_names()), + tuple(make_varnames(nlocals)), filename, method_name, 0, "") + # NOTE: May need more globals. + fn = new.function(code, __builtins__.__dict__) + namespace[method_name] = fn + namespace["__java_init__"] = __java_init__ + # NOTE: Define superclasses properly. + cls = new.classobj(str(c.this_class.get_name()), (), namespace) # vim: tabstop=4 expandtab shiftwidth=4