1.1 --- a/bytecode.py Sat Nov 20 21:41:45 2004 +0100
1.2 +++ b/bytecode.py Sat Nov 20 21:46:33 2004 +0100
1.3 @@ -1364,6 +1364,8 @@
1.4 # Stack: objectref, arg1, arg2, ...
1.5 program.build_tuple(count) # Stack: objectref, tuple
1.6 program.rot_two() # Stack: tuple, objectref
1.7 + # NOTE: The interface information is not used to discover the correct
1.8 + # NOTE: method.
1.9 self._invoke(target_name, program)
1.10
1.11 def invokespecial(self, arguments, program):
1.12 @@ -1374,87 +1376,21 @@
1.13 target = self.class_file.constants[index - 1]
1.14 original_name = target.get_name()
1.15 target_name = target.get_python_name()
1.16 - method_name = self.method.get_name()
1.17 -
1.18 # Get the number of parameters from the descriptor.
1.19 -
1.20 count = len(target.get_descriptor()[0])
1.21 -
1.22 - # The stack may contain one of the following patterns:
1.23 - # Stack: classref, arg1, arg2, ...
1.24 - # Stack: objectref, arg1, arg2, ...
1.25 - # method == __init__, classref -> classref(arg1, arg2, ...)
1.26 - # method == __init__, objectref == self -> cls.bases[0].__init__(objectref, arg1, arg2, ...)
1.27 - # method == __init__, objectref != self -> should not occur
1.28 - # method != __init__, classref -> classref.method(classref, arg1, arg2, ...)
1.29 - # method != __init__, objectref == self -> cls.bases[0].method(objectref, arg1, arg2, ...)
1.30 - # method != __init__, objectref != self -> should not occur
1.31 -
1.32 # First, we build a tuple of the reference and arguments.
1.33 -
1.34 - program.build_tuple(count + 1) # Stack: tuple
1.35 -
1.36 - # Then, we test the nature of the reference.
1.37 -
1.38 - program.dup_top() # Stack: tuple, tuple
1.39 - program.load_const(0) # Stack: tuple, tuple, 0
1.40 - program.binary_subscr() # Stack: tuple, reference
1.41 -
1.42 - # Is it self?
1.43 -
1.44 - program.dup_top() # Stack: tuple, reference, reference
1.45 - program.load_fast(0) # Stack: tuple, reference, reference, self|cls
1.46 - program.compare_op("is") # Stack: tuple, reference, result
1.47 - program.jump_to_label(1, "is-self")
1.48 - program.pop_top() # Stack: tuple, reference
1.49 -
1.50 - # Is another class or reference.
1.51 - # NOTE: Reference case not covered!
1.52 -
1.53 + program.build_tuple(count + 1) # Stack: tuple
1.54 + # Get the class name instead of the fully qualified name.
1.55 + # NOTE: Do proper resolution of classes,
1.56 + # NOTE: Not bothering with Object initialisation.
1.57 + full_class_name = target.get_class().get_python_name()
1.58 + if full_class_name != "java.lang.Object":
1.59 + class_name = full_class_name.split(".")[-1]
1.60 + program.load_global(class_name) # Stack: tuple, classref
1.61 + self._invoke(target_name, program)
1.62 + # Remove Python None return value.
1.63 if str(original_name) == "<init>":
1.64 - program.rot_two() # Stack: reference, tuple
1.65 - program.load_const(1) # Stack: reference, tuple, 1
1.66 - program.slice_1() # Stack: reference, tuple[1:]
1.67 - program.call_function_var(0) # Stack: result
1.68 - # NOTE: Combinations of new, dup tend to produce interfering extra
1.69 - # NOTE: class references.
1.70 - program.rot_two() # Stack: objectref, classref
1.71 program.pop_top()
1.72 - program.jump_to_label(None, "done")
1.73 - else:
1.74 - self._invoke(target_name, program)
1.75 - program.jump_to_label(None, "done")
1.76 -
1.77 - # Is self.
1.78 -
1.79 - program.start_label("is-self")
1.80 - program.pop_top() # Stack: tuple, reference
1.81 - program.pop_top() # Stack: tuple
1.82 - # Get the class name instead of the fully qualified name.
1.83 - full_class_name = str(self.class_file.this_class.get_python_name())
1.84 - class_name = full_class_name.split(".")[-1]
1.85 - program.load_global(class_name) # Stack: tuple, classref
1.86 - program.load_attr("__bases__") # Stack: tuple, bases
1.87 - program.dup_top() # Stack: tuple, bases, bases
1.88 - program.load_global("len") # Stack: tuple, bases, bases, len
1.89 - program.rot_two() # Stack: tuple, bases, len, bases
1.90 - program.call_function(1) # Stack: tuple, bases, #bases
1.91 - program.load_const(0) # Stack: tuple, bases, #bases, 0
1.92 - program.compare_op("==") # Stack: tuple, bases, result
1.93 - program.jump_to_label(1, "no-bases")
1.94 - program.pop_top() # Stack: tuple, bases
1.95 - program.load_const(0) # Stack: tuple, bases, 0
1.96 - program.binary_subscr() # Stack: tuple, bases[0]
1.97 - self._invoke(target_name, program)
1.98 - program.jump_to_label(None, "done")
1.99 -
1.100 - # No bases found, do no invocation.
1.101 - program.start_label("no-bases")
1.102 - program.pop_top() # Stack: tuple, bases
1.103 - program.pop_top() # Stack: tuple
1.104 - program.pop_top() # Stack:
1.105 -
1.106 - program.start_label("done")
1.107
1.108 def invokestatic(self, arguments, program):
1.109 # NOTE: This implementation does not perform the necessary checks for
1.110 @@ -1466,14 +1402,15 @@
1.111 # Get the number of parameters from the descriptor.
1.112 count = len(target.get_descriptor()[0])
1.113 # Stack: arg1, arg2, ...
1.114 - program.build_tuple(count) # Stack: tuple
1.115 + program.build_tuple(count) # Stack: tuple
1.116 # Use the class to provide access to static methods.
1.117 # Get the class name instead of the fully qualified name.
1.118 - # NOTE: Need to find the class that declared the field being accessed.
1.119 - full_class_name = str(self.class_file.this_class.get_python_name())
1.120 - class_name = full_class_name.split(".")[-1]
1.121 - program.load_global(class_name) # Stack: tuple, classref
1.122 - self._invoke(target_name, program)
1.123 + # NOTE: Do proper resolution of classes,
1.124 + full_class_name = target.get_class().get_python_name()
1.125 + if full_class_name != "java.lang.Object":
1.126 + class_name = full_class_name.split(".")[-1]
1.127 + program.load_global(class_name) # Stack: tuple, classref
1.128 + self._invoke(target_name, program)
1.129
1.130 def invokevirtual (self, arguments, program):
1.131 # NOTE: This implementation does not perform the necessary checks for
1.132 @@ -1578,10 +1515,26 @@
1.133 lconst_1 = iconst_1
1.134
1.135 def ldc(self, arguments, program):
1.136 - program.load_const(self.class_file.constants[arguments[0] - 1].get_value())
1.137 + const = self.class_file.constants[arguments[0] - 1]
1.138 + if isinstance(const, classfile.StringInfo):
1.139 + program.load_global("java")
1.140 + program.load_attr("lang")
1.141 + program.load_attr("String")
1.142 + program.load_const(const.get_value())
1.143 + program.call_function(2)
1.144 + else:
1.145 + program.load_const(const)
1.146
1.147 def ldc_w(self, arguments, program):
1.148 - program.load_const(self.class_file.constants[(arguments[0] << 8) + arguments[1] - 1].get_value())
1.149 + const = self.class_file.constants[(arguments[0] << 8) + arguments[1] - 1]
1.150 + if isinstance(const, classfile.StringInfo):
1.151 + program.load_global("java")
1.152 + program.load_attr("lang")
1.153 + program.load_attr("String")
1.154 + program.load_const(const.get_value())
1.155 + program.call_function(2)
1.156 + else:
1.157 + program.load_const(const)
1.158
1.159 ldc2_w = ldc_w
1.160 ldiv = idiv
1.161 @@ -1698,11 +1651,10 @@
1.162 index = (arguments[0] << 8) + arguments[1]
1.163 target_name = self.class_file.constants[index - 1].get_python_name()
1.164 # NOTE: Using the string version of the name which may contain incompatible characters.
1.165 + program.load_global("object")
1.166 + program.load_attr("__new__")
1.167 program.load_global(str(target_name))
1.168 - # NOTE: Unlike Java, we do not provide an object reference. Instead, a
1.169 - # NOTE: class reference is provided, and the invokespecial method's
1.170 - # NOTE: behaviour is changed.
1.171 - #program.call_function(0)
1.172 + program.call_function(1)
1.173
1.174 def newarray(self, arguments, program):
1.175 # NOTE: Does not raise NegativeArraySizeException.
1.176 @@ -1835,17 +1787,19 @@
1.177 translator.process(method, writer)
1.178 return translator, writer
1.179
1.180 - def make_method(self, method_name, methods, global_names, namespace):
1.181 + def make_method(self, real_method_name, methods, global_names, namespace):
1.182
1.183 """
1.184 - Make a dispatcher method with the given 'method_name', providing
1.185 + Make a dispatcher method with the given 'real_method_name', providing
1.186 dispatch to the supplied type-sensitive 'methods', accessing the given
1.187 'global_names' where necessary, and storing the new method in the
1.188 'namespace' provided.
1.189 """
1.190
1.191 - if method_name == "<init>":
1.192 + if real_method_name == "<init>":
1.193 method_name = "__init__"
1.194 + else:
1.195 + method_name = real_method_name
1.196
1.197 # Where only one method exists, just make an alias.
1.198
1.199 @@ -1854,19 +1808,33 @@
1.200 namespace[method_name] = fn
1.201 return
1.202
1.203 - # Find the maximum number of parameters involved.
1.204 - #maximum = max([len(method.get_descriptor()[0]) for method in methods])
1.205 + # Write a simple bytecode dispatching mechanism.
1.206
1.207 program = BytecodeWriter()
1.208
1.209 + # Remember whether any of the methods are static.
1.210 + # NOTE: This should be an all or nothing situation.
1.211 +
1.212 + method_is_static = 0
1.213 +
1.214 # NOTE: The code below should use dictionary-based dispatch for better performance.
1.215
1.216 - program.load_fast(1) # Stack: arguments
1.217 for method, fn in methods:
1.218 + method_is_static = real_method_name != "<init>" and method_is_static or classfile.has_flags(method.access_flags, [classfile.STATIC])
1.219 +
1.220 + if method_is_static:
1.221 + program.load_fast(0) # Stack: arguments
1.222 + else:
1.223 + program.load_fast(1) # Stack: arguments
1.224 +
1.225 program.setup_loop()
1.226 - program.dup_top() # Stack: arguments, arguments
1.227 - program.load_const(1) # Stack: arguments, arguments, 1
1.228 - program.store_fast(2) # Stack: arguments, arguments (found = 1)
1.229 + program.load_const(1) # Stack: arguments, 1
1.230 +
1.231 + if method_is_static:
1.232 + program.store_fast(1) # Stack: arguments (found = 1)
1.233 + else:
1.234 + program.store_fast(2) # Stack: arguments (found = 1)
1.235 +
1.236 # Emit a list of parameter types.
1.237 descriptor_types = method.get_descriptor()[0]
1.238 for descriptor_type in descriptor_types:
1.239 @@ -1875,77 +1843,104 @@
1.240 if python_type == "instance":
1.241 # NOTE: This will need extending.
1.242 python_type = object_type
1.243 - program.load_global(python_type) # Stack: arguments, arguments, type, ...
1.244 + program.load_global(python_type) # Stack: arguments, type, ...
1.245 program.build_list(len(descriptor_types))
1.246 - # Stack: arguments, arguments, types
1.247 + # Stack: arguments, types
1.248 # Make a map of arguments and types.
1.249 - program.load_const(None) # Stack: arguments, arguments, types, None
1.250 - program.rot_three() # Stack: arguments, None, arguments, types
1.251 - program.build_tuple(3) # Stack: arguments, tuple
1.252 - program.load_global("map") # Stack: arguments, tuple, map
1.253 - program.rot_two() # Stack: arguments, map, tuple
1.254 - program.call_function_var(0) # Stack: arguments, list (mapping arguments to types)
1.255 + program.load_const(None) # Stack: arguments, types, None
1.256 + program.rot_three() # Stack: None, arguments, types
1.257 + program.build_tuple(3) # Stack: tuple
1.258 + program.load_global("map") # Stack: tuple, map
1.259 + program.rot_two() # Stack: map, tuple
1.260 + program.call_function_var(0) # Stack: list (mapping arguments to types)
1.261 # Loop over each pair.
1.262 - program.get_iter() # Stack: arguments, iter
1.263 - program.for_iter() # Stack: arguments, iter, (argument, type)
1.264 - program.unpack_sequence(2) # Stack: arguments, iter, type, argument
1.265 - program.dup_top() # Stack: arguments, iter, type, argument, argument
1.266 - program.load_const(None) # Stack: arguments, iter, type, argument, argument, None
1.267 - program.compare_op("is") # Stack: arguments, iter, type, argument, result
1.268 + program.get_iter() # Stack: iter
1.269 + program.for_iter() # Stack: iter, (argument, type)
1.270 + program.unpack_sequence(2) # Stack: iter, type, argument
1.271 + program.dup_top() # Stack: iter, type, argument, argument
1.272 + program.load_const(None) # Stack: iter, type, argument, argument, None
1.273 + program.compare_op("is") # Stack: iter, type, argument, result
1.274 # Missing argument?
1.275 program.jump_to_label(0, "present")
1.276 - program.pop_top() # Stack: arguments, iter, type, argument
1.277 - program.pop_top() # Stack: arguments, iter, type
1.278 - program.pop_top() # Stack: arguments, iter
1.279 - program.load_const(0) # Stack: arguments, iter, 0
1.280 - program.store_fast(2) # Stack: arguments, iter (found = 0)
1.281 + program.pop_top() # Stack: iter, type, argument
1.282 + program.pop_top() # Stack: iter, type
1.283 + program.pop_top() # Stack: iter
1.284 + program.load_const(0) # Stack: iter, 0
1.285 +
1.286 + if method_is_static:
1.287 + program.store_fast(1) # Stack: iter (found = 0)
1.288 + else:
1.289 + program.store_fast(2) # Stack: iter (found = 0)
1.290 +
1.291 program.break_loop()
1.292 # Argument was present.
1.293 program.start_label("present")
1.294 - program.pop_top() # Stack: arguments, iter, type, argument
1.295 - program.rot_two() # Stack: arguments, iter, argument, type
1.296 - program.dup_top() # Stack: arguments, iter, argument, type, type
1.297 - program.load_const(None) # Stack: arguments, iter, argument, type, type, None
1.298 - program.compare_op("is") # Stack: arguments, iter, argument, type, result
1.299 + program.pop_top() # Stack: iter, type, argument
1.300 + program.rot_two() # Stack: iter, argument, type
1.301 + program.dup_top() # Stack: iter, argument, type, type
1.302 + program.load_const(None) # Stack: iter, argument, type, type, None
1.303 + program.compare_op("is") # Stack: iter, argument, type, result
1.304 # Missing parameter type?
1.305 program.jump_to_label(0, "present")
1.306 - program.pop_top() # Stack: arguments, iter, argument, type
1.307 - program.pop_top() # Stack: arguments, iter, argument
1.308 - program.pop_top() # Stack: arguments, iter
1.309 - program.load_const(0) # Stack: arguments, iter, 0
1.310 - program.store_fast(2) # Stack: arguments, iter (found = 0)
1.311 + program.pop_top() # Stack: iter, argument, type
1.312 + program.pop_top() # Stack: iter, argument
1.313 + program.pop_top() # Stack: iter
1.314 + program.load_const(0) # Stack: iter, 0
1.315 +
1.316 + if method_is_static:
1.317 + program.store_fast(1) # Stack: iter (found = 0)
1.318 + else:
1.319 + program.store_fast(2) # Stack: iter (found = 0)
1.320 +
1.321 program.break_loop()
1.322 # Parameter was present.
1.323 program.start_label("present")
1.324 - program.pop_top() # Stack: arguments, iter, argument, type
1.325 - program.build_tuple(2) # Stack: arguments, iter, (argument, type)
1.326 - program.load_global("isinstance") # Stack: arguments, iter, (argument, type), isinstance
1.327 - program.rot_two() # Stack: arguments, iter, isinstance, (argument, type)
1.328 - program.call_function_var(0) # Stack: arguments, iter, result
1.329 + program.pop_top() # Stack: iter, argument, type
1.330 + program.build_tuple(2) # Stack: iter, (argument, type)
1.331 + program.load_global("isinstance") # Stack: iter, (argument, type), isinstance
1.332 + program.rot_two() # Stack: iter, isinstance, (argument, type)
1.333 + program.call_function_var(0) # Stack: iter, result
1.334 program.jump_to_label(1, "match")
1.335 - program.pop_top() # Stack: arguments, iter
1.336 - program.load_const(0) # Stack: arguments, iter, 0
1.337 - program.store_fast(2) # Stack: arguments, iter (found = 0)
1.338 + program.pop_top() # Stack: iter
1.339 + program.load_const(0) # Stack: iter, 0
1.340 +
1.341 + if method_is_static:
1.342 + program.store_fast(1) # Stack: iter (found = 0)
1.343 + else:
1.344 + program.store_fast(2) # Stack: iter (found = 0)
1.345 +
1.346 program.break_loop()
1.347 # Argument type and parameter type matched.
1.348 program.start_label("match")
1.349 - program.pop_top() # Stack: arguments, iter
1.350 - program.end_loop() # Stack: arguments
1.351 + program.pop_top() # Stack: iter
1.352 + program.end_loop() # Stack:
1.353 # If all the parameters matched, call the method.
1.354 - program.load_fast(2) # Stack: arguments, match
1.355 +
1.356 + if method_is_static:
1.357 + program.load_fast(1) # Stack: match
1.358 + else:
1.359 + program.load_fast(2) # Stack: match
1.360 +
1.361 program.jump_to_label(0, "failed")
1.362 # All the parameters matched.
1.363 - program.pop_top() # Stack: arguments
1.364 - program.dup_top() # Stack: arguments, arguments
1.365 - program.load_fast(0) # Stack: arguments, arguments, self
1.366 + program.pop_top() # Stack:
1.367 +
1.368 + if method_is_static:
1.369 + program.load_fast(0) # Stack: arguments
1.370 + program.load_global(str(self.class_file.this_class.get_python_name()))
1.371 + # Stack: arguments, class
1.372 + else:
1.373 + program.load_fast(1) # Stack: arguments
1.374 + program.load_fast(0) # Stack: arguments, self
1.375 +
1.376 program.load_attr(str(method.get_python_name()))
1.377 - # Stack: arguments, arguments, method
1.378 - program.rot_two() # Stack: arguments, method, arguments
1.379 - program.call_function_var(0) # Stack: arguments, result
1.380 + # Stack: arguments, method
1.381 + program.rot_two() # Stack: method, arguments
1.382 + program.call_function_var(0) # Stack: result
1.383 program.return_value()
1.384 # Try the next method if arguments or parameters were missing or incorrect.
1.385 program.start_label("failed")
1.386 - program.pop_top() # Stack: arguments
1.387 + program.pop_top() # Stack:
1.388
1.389 # Raise an exception if nothing matched.
1.390 # NOTE: Improve this.
1.391 @@ -1959,11 +1954,20 @@
1.392 # NOTE: One actual parameter, flags as 71 apparently means that a list
1.393 # NOTE: parameter is used in a method.
1.394
1.395 + if method_is_static:
1.396 + nargs = 0
1.397 + else:
1.398 + nargs = 1
1.399 nlocals = program.max_locals + 1
1.400 - code = new.code(1, nlocals, program.max_stack_depth, 71, program.get_output(),
1.401 - tuple(program.get_constants()), tuple(program.get_names()), tuple(self.make_varnames(nlocals)),
1.402 +
1.403 + code = new.code(nargs, nlocals, program.max_stack_depth, 71, program.get_output(),
1.404 + tuple(program.get_constants()), tuple(program.get_names()), tuple(self.make_varnames(nlocals, method_is_static)),
1.405 self.filename, method_name, 0, "")
1.406 fn = new.function(code, global_names)
1.407 +
1.408 + if method_is_static:
1.409 + fn = staticmethod(fn)
1.410 +
1.411 namespace[method_name] = fn
1.412
1.413 def process(self, global_names):
1.414 @@ -1986,39 +1990,40 @@
1.415 real_methods = {}
1.416 for method in self.class_file.methods:
1.417 real_method_name = str(method.get_name())
1.418 + method_name = str(method.get_python_name())
1.419 +
1.420 t, w = self.translate_method(method)
1.421
1.422 - # Fix up special class initialisation methods.
1.423 + # Fix up special class initialisation methods and static methods.
1.424
1.425 - if real_method_name == "<clinit>":
1.426 - flags = 3
1.427 + method_is_static = real_method_name != "<init>" and classfile.has_flags(method.access_flags, [classfile.STATIC])
1.428 + if method_is_static:
1.429 + nargs = len(method.get_descriptor()[0])
1.430 else:
1.431 - flags = 67
1.432 + nargs = len(method.get_descriptor()[0]) + 1
1.433 nlocals = w.max_locals + 1
1.434 - nargs = len(method.get_descriptor()[0]) + 1
1.435 -
1.436 - method_name = str(method.get_python_name())
1.437 + flags = 67
1.438
1.439 # NOTE: Add line number table later.
1.440
1.441 code = new.code(nargs, nlocals, w.max_stack_depth, flags, w.get_output(), tuple(w.get_constants()), tuple(w.get_names()),
1.442 - tuple(self.make_varnames(nlocals)), self.filename, method_name, 0, "")
1.443 + tuple(self.make_varnames(nlocals, method_is_static)), self.filename, method_name, 0, "")
1.444
1.445 # NOTE: May need more globals.
1.446
1.447 fn = new.function(code, global_names)
1.448
1.449 + # Fix up special class initialisation methods and static methods.
1.450 +
1.451 + if method_is_static:
1.452 + fn = staticmethod(fn)
1.453 +
1.454 # Remember the real method name and the corresponding methods produced.
1.455
1.456 if not real_methods.has_key(real_method_name):
1.457 real_methods[real_method_name] = []
1.458 real_methods[real_method_name].append((method, fn))
1.459
1.460 - # Fix up special class initialisation methods.
1.461 -
1.462 - if real_method_name == "<clinit>":
1.463 - fn = classmethod(fn)
1.464 -
1.465 # Add the method to the class's namespace.
1.466
1.467 namespace[method_name] = fn
1.468 @@ -2053,7 +2058,7 @@
1.469
1.470 original_name = str(self.class_file.super_class.get_name())
1.471 if original_name in ("java/lang/Object", "java/lang/Exception"):
1.472 - return ()
1.473 + return (object,)
1.474 else:
1.475 full_this_class_name = str(self.class_file.this_class.get_python_name())
1.476 this_class_name_parts = full_this_class_name.split(".")
1.477 @@ -2074,15 +2079,21 @@
1.478 obj = getattr(obj, super_class_name_part)
1.479 return (obj,)
1.480
1.481 - def make_varnames(self, nlocals):
1.482 + def make_varnames(self, nlocals, method_is_static=0):
1.483
1.484 """
1.485 A utility method which invents variable names for the given number -
1.486 'nlocals' - of local variables in a method. Returns a list of such
1.487 variable names.
1.488 +
1.489 + If the optional 'method_is_static' is set to true, do not use "self" as
1.490 + the first argument name.
1.491 """
1.492
1.493 - l = ["self"]
1.494 + if method_is_static:
1.495 + l = ["cls"]
1.496 + else:
1.497 + l = ["self"]
1.498 for i in range(1, nlocals):
1.499 l.append("_l%s" % i)
1.500 return l[:nlocals]