1.1 --- a/bytecode.py Wed Nov 10 15:55:39 2004 +0100
1.2 +++ b/bytecode.py Wed Nov 10 16:00:09 2004 +0100
1.3 @@ -155,18 +155,32 @@
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.load_const(None)
1.10 + self.constants_for_exceptions.append(value)
1.11 + self.load_const(value)
1.12
1.13 def ret(self, index):
1.14 self.load_fast(index)
1.15 - self.end_finally()
1.16 + # Previously, the constant stored on the stack by jsr/jsr_w was stored
1.17 + # in a local variable. In the JVM, extracting the value from the local
1.18 + # variable and jumping can be done at runtime. In the Python VM, any
1.19 + # jump target must be known in advance and written into the bytecode.
1.20 + for constant in self.constants_for_exceptions:
1.21 + self.dup_top() # Stack: actual-address, actual-address
1.22 + self.load_const(constant) # Stack: actual-address, actual-address, suggested-address
1.23 + self.compare_op("==") # Stack: actual-address, result
1.24 + self.jump_to_label(0, "const")
1.25 + self.pop_top() # Stack: actual-address
1.26 + self.pop_top() # Stack:
1.27 + self.jump_absolute(constant)
1.28 + self.start_label("const")
1.29 + self.pop_top() # Stack: actual-address
1.30 + # NOTE: If we get here, something is really wrong.
1.31 + self.pop_top() # Stack:
1.32
1.33 def setup_except(self, target):
1.34 self.blocks.append(self.position)
1.35 self.exception_handlers.append(target)
1.36 - print "-", self.position, target
1.37 + #print "-", self.position, target
1.38 self.output.append(opmap["SETUP_EXCEPT"])
1.39 self.position += 1
1.40 self._write_value(0) # To be filled in later
1.41 @@ -174,7 +188,7 @@
1.42 def setup_finally(self, target):
1.43 self.blocks.append(self.position)
1.44 self.exception_handlers.append(target)
1.45 - print "-", self.position, target
1.46 + #print "-", self.position, target
1.47 self.output.append(opmap["SETUP_FINALLY"])
1.48 self.position += 1
1.49 self._write_value(0) # To be filled in later
1.50 @@ -184,7 +198,7 @@
1.51 # Convert the "lazy" absolute value.
1.52 current_exception_target = self.exception_handlers.pop()
1.53 target = current_exception_target.get_value()
1.54 - print "*", current_exception_start, target
1.55 + #print "*", current_exception_start, target
1.56 # NOTE: Using 3 as the assumed length of the SETUP_* instruction.
1.57 # NOTE: 8-bit limit.
1.58 self.output[current_exception_start + 1] = target - current_exception_start - 3
1.59 @@ -467,8 +481,14 @@
1.60 self.class_file = class_file
1.61 self.position_mapping = LazyDict()
1.62
1.63 - def process(self, code, exception_table, program):
1.64 + def process(self, method, program):
1.65 self.java_position = 0
1.66 + self.in_finally = 0
1.67 + self.method = method
1.68 +
1.69 + # NOTE: Not guaranteed.
1.70 + attribute = method.attributes[0]
1.71 + code, exception_table = attribute.code, attribute.exception_table
1.72
1.73 # Produce a structure which permits fast access to exception details.
1.74 exception_block_start = {}
1.75 @@ -497,20 +517,23 @@
1.76 self.position_mapping[self.java_position] = program.position
1.77
1.78 # Insert exception handling constructs.
1.79 - for exception in exception_block_start.get(self.java_position, []):
1.80 + block_starts = exception_block_start.get(self.java_position, [])
1.81 + for exception in block_starts:
1.82 # Note that the absolute position is used.
1.83 if exception.catch_type == 0:
1.84 program.setup_finally(self.position_mapping[exception.handler_pc])
1.85 else:
1.86 program.setup_except(self.position_mapping[exception.handler_pc])
1.87 + if block_starts:
1.88 + self.in_finally = 0
1.89
1.90 # Insert exception handler details.
1.91 # NOTE: Ensure that pop_block is reachable by possibly inserting it at the start of finally handlers.
1.92 # NOTE: Insert a check for the correct exception at the start of each handler.
1.93 for exception in exception_block_handler.get(self.java_position, []):
1.94 program.end_exception()
1.95 - #if exception.catch_type == 0:
1.96 - # program.pop_block()
1.97 + if exception.catch_type == 0:
1.98 + self.in_finally = 1
1.99
1.100 # Where handlers are begun, do not produce equivalent bytecode since
1.101 # the first handler instruction typically involves saving a local
1.102 @@ -864,8 +887,12 @@
1.103
1.104 def athrow(self, arguments, program):
1.105 # NOTE: NullPointerException not raised where null/None is found on the stack.
1.106 - program.dup_top()
1.107 - program.raise_varargs(1)
1.108 + # If this instruction appears in a finally handler, use end_finally instead.
1.109 + if self.in_finally:
1.110 + program.end_finally()
1.111 + else:
1.112 + program.dup_top()
1.113 + program.raise_varargs(1)
1.114
1.115 baload = aaload
1.116 bastore = aastore
1.117 @@ -1223,10 +1250,46 @@
1.118 target_name = target.get_python_name()
1.119 # Get the number of parameters from the descriptor.
1.120 count = len(target.get_descriptor()[0])
1.121 - # Stack: objectref, arg1, arg2, ...
1.122 - program.build_tuple(count) # Stack: objectref, tuple
1.123 - program.rot_two() # Stack: tuple, objectref
1.124 - self._invoke(target_name, program)
1.125 +
1.126 + # Check for the method name and invoke superclasses where appropriate.
1.127 + if str(self.method.get_name()) == "<init>":
1.128 + program.build_tuple(count + 1) # Stack: tuple
1.129 + # NOTE: Assume that local 0 is always self.
1.130 + program.load_fast(0) # Stack: tuple, objectref
1.131 + program.load_attr("__class__") # Stack: tuple, classref
1.132 + program.load_attr("__bases__") # Stack: tuple, bases
1.133 + program.dup_top() # Stack: tuple, bases, bases
1.134 + program.load_global("len") # Stack: tuple, bases, bases, len
1.135 + program.rot_two() # Stack: tuple, bases, len, bases
1.136 + program.call_function(1) # Stack: tuple, bases, #bases
1.137 + program.load_const(0) # Stack: tuple, bases, #bases, 0
1.138 + program.compare_op("==") # Stack: tuple, bases, result
1.139 + program.jump_to_label(1, "next")
1.140 + program.pop_top() # Stack: tuple, bases
1.141 + program.load_const(0) # Stack: tuple, bases, 0
1.142 + program.binary_subscr() # Stack: tuple, bases[0]
1.143 + self._invoke(target_name, program)
1.144 + program.jump_to_label(None, "next2")
1.145 + program.start_label("next")
1.146 + program.pop_top() # Stack: tuple, bases
1.147 + program.pop_top() # Stack: tuple
1.148 + program.pop_top() # Stack:
1.149 + program.start_label("next2")
1.150 +
1.151 + elif str(target_name) == "__init__":
1.152 + # NOTE: Due to changes with the new instruction's implementation, the
1.153 + # NOTE: stack differs from that stated: objectref, arg1, arg2, ...
1.154 + # Stack: classref, arg1, arg2, ...
1.155 + program.build_tuple(count) # Stack: classref, tuple
1.156 + # NOTE: Stack: objectref, tuple
1.157 + program.load_global("apply") # Stack: classref, tuple, apply
1.158 + program.rot_three() # Stack: apply, classref, tuple
1.159 + program.call_function(2)
1.160 +
1.161 + else:
1.162 + program.build_tuple(count) # Stack: objectref, tuple
1.163 + program.rot_two() # Stack: tuple, objectref
1.164 + self._invoke(target_name, program)
1.165
1.166 """
1.167 def invokespecial(self, arguments, program):
1.168 @@ -1279,7 +1342,19 @@
1.169 program.load_attr("__class__") # Stack: tuple, class
1.170 self._invoke(target_name, program)
1.171
1.172 - invokevirtual = invokeinterface # Ignoring Java rules
1.173 + def invokevirtual (self, arguments, program):
1.174 + # NOTE: This implementation does not perform the necessary checks for
1.175 + # NOTE: signature-based polymorphism.
1.176 + # NOTE: Java rules not specifically obeyed.
1.177 + index = (arguments[0] << 8) + arguments[1]
1.178 + target = self.class_file.constants[index - 1]
1.179 + target_name = target.get_python_name()
1.180 + # Get the number of parameters from the descriptor.
1.181 + count = len(target.get_descriptor()[0])
1.182 + # Stack: objectref, arg1, arg2, ...
1.183 + program.build_tuple(count) # Stack: objectref, tuple
1.184 + program.rot_two() # Stack: tuple, objectref
1.185 + self._invoke(target_name, program)
1.186
1.187 def ior(self, arguments, program):
1.188 # NOTE: No type checking performed.
1.189 @@ -1453,7 +1528,10 @@
1.190 target_name = self.class_file.constants[index - 1].get_name()
1.191 # NOTE: Using the string version of the name which may contain incompatible characters.
1.192 program.load_global(str(target_name))
1.193 - program.call_function(0)
1.194 + # NOTE: Unlike Java, we do not provide an object reference. Instead, a
1.195 + # NOTE: class reference is provided, and the invokespecial method's
1.196 + # NOTE: behaviour is changed.
1.197 + #program.call_function(0)
1.198
1.199 def newarray(self, arguments, program):
1.200 # NOTE: Does not raise NegativeArraySizeException.
1.201 @@ -1485,6 +1563,9 @@
1.202
1.203 def ret(self, arguments, program):
1.204 program.ret(arguments[0])
1.205 + # Indicate that the finally handler is probably over.
1.206 + # NOTE: This is seemingly not guaranteed.
1.207 + self.in_finally = 0
1.208
1.209 def return_(self, arguments, program):
1.210 program.load_const(None)
1.211 @@ -1537,14 +1618,14 @@
1.212 # NOTE: To be implemented.
1.213 return number_of_arguments
1.214
1.215 -def disassemble(class_file, code, exception_table):
1.216 +def disassemble(class_file, method):
1.217 disassembler = BytecodeDisassembler(class_file)
1.218 - disassembler.process(code, exception_table, BytecodeDisassemblerProgram())
1.219 + disassembler.process(method, BytecodeDisassemblerProgram())
1.220
1.221 -def translate(class_file, code, exception_table):
1.222 +def translate(class_file, method):
1.223 translator = BytecodeTranslator(class_file)
1.224 writer = BytecodeWriter()
1.225 - translator.process(code, exception_table, writer)
1.226 + translator.process(method, writer)
1.227 return translator, writer
1.228
1.229 def make_varnames(nlocals):
1.230 @@ -1553,9 +1634,6 @@
1.231 l.append("_l%s" % i)
1.232 return l[:nlocals]
1.233
1.234 -def __java_init__(self, *args):
1.235 - print "<init>", args
1.236 -
1.237 if __name__ == "__main__":
1.238 import sys
1.239 from classfile import ClassFile
1.240 @@ -1567,20 +1645,16 @@
1.241 import dis, new
1.242 namespace = {}
1.243 for method in c.methods:
1.244 - attribute = method.attributes[0]
1.245 nargs = len(method.get_descriptor()[0]) + 1
1.246 - t, w = translate(c, attribute.code, attribute.exception_table)
1.247 + t, w = translate(c, method)
1.248 nlocals = w.max_locals + 1
1.249 filename = str(c.attributes[0].get_name())
1.250 - method_name = str(method.get_name())
1.251 - if method_name == "<init>":
1.252 - method_name = "__init__"
1.253 + method_name = str(method.get_python_name())
1.254 code = new.code(nargs, nlocals, w.max_stack_depth, 67, w.get_output(), tuple(w.get_constants()), tuple(w.get_names()),
1.255 tuple(make_varnames(nlocals)), filename, method_name, 0, "")
1.256 # NOTE: May need more globals.
1.257 fn = new.function(code, global_names)
1.258 namespace[method_name] = fn
1.259 - namespace["__java_init__"] = __java_init__
1.260 # NOTE: Define superclasses properly.
1.261 cls = new.classobj(str(c.this_class.get_name()), (), namespace)
1.262 global_names[cls.__name__] = cls