1.1 --- a/bytecode.py Sun Nov 21 23:22:28 2004 +0100
1.2 +++ b/bytecode.py Sun Nov 21 23:28:28 2004 +0100
1.3 @@ -57,6 +57,9 @@
1.4 # A list of constants used as exception handler return addresses.
1.5 self.constants_for_exceptions = []
1.6
1.7 + # A list of external names.
1.8 + self.external_names = []
1.9 +
1.10 def get_output(self):
1.11 output = []
1.12 for element in self.output:
1.13 @@ -132,6 +135,12 @@
1.14 # NOTE: EXTENDED_ARG not yet supported.
1.15 raise ValueError, value
1.16
1.17 + # Higher level methods.
1.18 +
1.19 + def use_external_name(self, name):
1.20 + # NOTE: Remove array and object indicators.
1.21 + self.external_names.append(name)
1.22 +
1.23 def setup_loop(self):
1.24 self.loops.append(self.position)
1.25 self.output.append(opmap["SETUP_LOOP"])
1.26 @@ -230,6 +239,7 @@
1.27 # NOTE: Since RAISE_VARARGS and END_FINALLY are not really documented,
1.28 # NOTE: we store the top of the stack and use it later to trigger the
1.29 # NOTE: magic processes when re-raising.
1.30 + self.use_external_name(exc_name)
1.31
1.32 self.rot_two() # Stack: raised-exception, exception
1.33 self.dup_top() # Stack: raised-exception, exception, exception
1.34 @@ -953,6 +963,17 @@
1.35
1.36 "A Java bytecode translator which uses a Python bytecode writer."
1.37
1.38 + def _load_class_name(self, full_class_name, program):
1.39 + this_class_name = str(self.class_file.this_class.get_python_name())
1.40 + class_parts = full_class_name.split(".")
1.41 + if full_class_name != this_class_name:
1.42 + program.use_external_name(full_class_name)
1.43 + program.load_global(class_parts[0])
1.44 + for class_part in class_parts[1:]:
1.45 + program.load_attr(class_part) # Stack: classref
1.46 + else:
1.47 + program.load_global(class_parts[-1])
1.48 +
1.49 def aaload(self, arguments, program):
1.50 # NOTE: No type checking performed.
1.51 program.binary_subscr()
1.52 @@ -1056,6 +1077,8 @@
1.53 def checkcast(self, arguments, program):
1.54 index = (arguments[0] << 8) + arguments[1]
1.55 target_name = self.class_file.constants[index - 1].get_python_name()
1.56 + program.use_external_name(target_name)
1.57 +
1.58 # NOTE: Using the string version of the name which may contain incompatible characters.
1.59 target_components = str(target_name).split("/")
1.60
1.61 @@ -1193,11 +1216,13 @@
1.62
1.63 def getstatic(self, arguments, program):
1.64 index = (arguments[0] << 8) + arguments[1]
1.65 - target_name = self.class_file.constants[index - 1].get_python_name()
1.66 + target = self.class_file.constants[index - 1]
1.67 + target_name = target.get_python_name()
1.68 +
1.69 # Get the class name instead of the fully qualified name.
1.70 - full_class_name = str(self.class_file.this_class.get_python_name())
1.71 - class_name = full_class_name.split(".")[-1]
1.72 - program.load_global(class_name) # Stack: classref
1.73 +
1.74 + full_class_name = target.get_class().get_python_name()
1.75 + self._load_class_name(full_class_name, program)
1.76 # NOTE: Using the string version of the name which may contain incompatible characters.
1.77 program.load_attr(str(target_name))
1.78
1.79 @@ -1364,6 +1389,8 @@
1.80 def instanceof(self, arguments, program):
1.81 index = (arguments[0] << 8) + arguments[1]
1.82 target_name = self.class_file.constants[index - 1].get_python_name()
1.83 + program.use_external_name(target_name)
1.84 +
1.85 # NOTE: Using the string version of the name which may contain incompatible characters.
1.86 target_components = str(target_name).split("/")
1.87
1.88 @@ -1403,19 +1430,25 @@
1.89 target = self.class_file.constants[index - 1]
1.90 original_name = target.get_name()
1.91 target_name = target.get_python_name()
1.92 +
1.93 # Get the number of parameters from the descriptor.
1.94 +
1.95 count = len(target.get_descriptor()[0])
1.96 +
1.97 # First, we build a tuple of the reference and arguments.
1.98 - program.build_tuple(count + 1) # Stack: tuple
1.99 +
1.100 + program.build_tuple(count + 1) # Stack: tuple
1.101 +
1.102 # Get the class name instead of the fully qualified name.
1.103 - # NOTE: Do proper resolution of classes,
1.104 # NOTE: Not bothering with Object initialisation.
1.105 +
1.106 full_class_name = target.get_class().get_python_name()
1.107 if full_class_name not in ("java.lang.Object", "java.lang.Exception"):
1.108 - class_name = full_class_name.split(".")[-1]
1.109 - program.load_global(class_name) # Stack: tuple, classref
1.110 + self._load_class_name(full_class_name, program)
1.111 self._invoke(target_name, program)
1.112 +
1.113 # Remove Python None return value.
1.114 +
1.115 if str(original_name) == "<init>":
1.116 program.pop_top()
1.117
1.118 @@ -1426,17 +1459,21 @@
1.119 index = (arguments[0] << 8) + arguments[1]
1.120 target = self.class_file.constants[index - 1]
1.121 target_name = target.get_python_name()
1.122 +
1.123 # Get the number of parameters from the descriptor.
1.124 +
1.125 count = len(target.get_descriptor()[0])
1.126 +
1.127 # Stack: arg1, arg2, ...
1.128 - program.build_tuple(count) # Stack: tuple
1.129 +
1.130 + program.build_tuple(count) # Stack: tuple
1.131 +
1.132 # Use the class to provide access to static methods.
1.133 # Get the class name instead of the fully qualified name.
1.134 - # NOTE: Do proper resolution of classes,
1.135 +
1.136 full_class_name = target.get_class().get_python_name()
1.137 if full_class_name not in ("java.lang.Object", "java.lang.Exception"):
1.138 - class_name = full_class_name.split(".")[-1]
1.139 - program.load_global(class_name) # Stack: tuple, classref
1.140 + self._load_class_name(full_class_name, program)
1.141 self._invoke(target_name, program)
1.142
1.143 def invokevirtual (self, arguments, program):
1.144 @@ -1544,22 +1581,24 @@
1.145 def ldc(self, arguments, program):
1.146 const = self.class_file.constants[arguments[0] - 1]
1.147 if isinstance(const, classfile.StringInfo):
1.148 + program.use_external_name("java.lang.String")
1.149 program.load_global("java")
1.150 program.load_attr("lang")
1.151 program.load_attr("String")
1.152 program.load_const(const.get_value())
1.153 - program.call_function(2)
1.154 + program.call_function(1)
1.155 else:
1.156 program.load_const(const)
1.157
1.158 def ldc_w(self, arguments, program):
1.159 const = self.class_file.constants[(arguments[0] << 8) + arguments[1] - 1]
1.160 if isinstance(const, classfile.StringInfo):
1.161 + program.use_external_name("java.lang.String")
1.162 program.load_global("java")
1.163 program.load_attr("lang")
1.164 program.load_attr("String")
1.165 program.load_const(const.get_value())
1.166 - program.call_function(2)
1.167 + program.call_function(1)
1.168 else:
1.169 program.load_const(const)
1.170
1.171 @@ -1675,12 +1714,15 @@
1.172 def new(self, arguments, program):
1.173 # This operation is considered to be the same as the calling of the
1.174 # initialisation method of the given class with no arguments.
1.175 +
1.176 index = (arguments[0] << 8) + arguments[1]
1.177 target_name = self.class_file.constants[index - 1].get_python_name()
1.178 + program.use_external_name(target_name)
1.179 +
1.180 # NOTE: Using the string version of the name which may contain incompatible characters.
1.181 program.load_global("object")
1.182 program.load_attr("__new__")
1.183 - program.load_global(str(target_name))
1.184 + self._load_class_name(target_name, program)
1.185 program.call_function(1)
1.186
1.187 def newarray(self, arguments, program):
1.188 @@ -1705,12 +1747,13 @@
1.189
1.190 def putstatic(self, arguments, program):
1.191 index = (arguments[0] << 8) + arguments[1]
1.192 - target_name = self.class_file.constants[index - 1].get_python_name()
1.193 + target = self.class_file.constants[index - 1]
1.194 + target_name = target.get_python_name()
1.195 +
1.196 # Get the class name instead of the fully qualified name.
1.197 - # NOTE: Need to find the class that declared the field being accessed.
1.198 - full_class_name = str(self.class_file.this_class.get_python_name())
1.199 - class_name = full_class_name.split(".")[-1]
1.200 - program.load_global(class_name) # Stack: classref
1.201 +
1.202 + full_class_name = target.get_class().get_python_name()
1.203 + self._load_class_name(full_class_name, program)
1.204 # NOTE: Using the string version of the name which may contain incompatible characters.
1.205 program.store_attr(str(target_name))
1.206
1.207 @@ -1863,6 +1906,7 @@
1.208 program.store_fast(2) # Stack: arguments (found = 1)
1.209
1.210 # Emit a list of parameter types.
1.211 +
1.212 descriptor_types = method.get_descriptor()[0]
1.213 for descriptor_type in descriptor_types:
1.214 base_type, object_type, array_type = descriptor_type
1.215 @@ -2001,6 +2045,8 @@
1.216
1.217 """
1.218 Process the class, storing it in the 'global_names' dictionary provided.
1.219 + Return a tuple containing the class and a list of external names
1.220 + referenced by the class's methods.
1.221 """
1.222
1.223 namespace = {}
1.224 @@ -2015,11 +2061,19 @@
1.225 # Make the methods.
1.226
1.227 real_methods = {}
1.228 + external_names = []
1.229 +
1.230 for method in self.class_file.methods:
1.231 real_method_name = str(method.get_name())
1.232 method_name = str(method.get_python_name())
1.233
1.234 - t, w = self.translate_method(method)
1.235 + translator, writer = self.translate_method(method)
1.236 +
1.237 + # Add external names to the master list.
1.238 +
1.239 + for external_name in writer.external_names:
1.240 + if external_name not in external_names:
1.241 + external_names.append(external_name)
1.242
1.243 # Fix up special class initialisation methods and static methods.
1.244
1.245 @@ -2028,12 +2082,13 @@
1.246 nargs = len(method.get_descriptor()[0])
1.247 else:
1.248 nargs = len(method.get_descriptor()[0]) + 1
1.249 - nlocals = w.max_locals + 1
1.250 + nlocals = writer.max_locals + 1
1.251 flags = 67
1.252
1.253 # NOTE: Add line number table later.
1.254
1.255 - code = new.code(nargs, nlocals, w.max_stack_depth, flags, w.get_output(), tuple(w.get_constants()), tuple(w.get_names()),
1.256 + code = new.code(nargs, nlocals, writer.max_stack_depth, flags, writer.get_output(),
1.257 + tuple(writer.get_constants()), tuple(writer.get_names()),
1.258 tuple(self.make_varnames(nlocals, method_is_static)), self.filename, method_name, 0, "")
1.259
1.260 # NOTE: May need more globals.
1.261 @@ -2072,7 +2127,7 @@
1.262 cls = new.classobj(class_name, bases, namespace)
1.263 global_names[cls.__name__] = cls
1.264
1.265 - return cls
1.266 + return cls, external_names
1.267
1.268 def get_base_classes(self, global_names):
1.269
1.270 @@ -2143,6 +2198,6 @@
1.271 f = open(filename, "rb")
1.272 c = classfile.ClassFile(f.read())
1.273 translator = ClassTranslator(c)
1.274 - cls = translator.process(global_names)
1.275 + cls, external_names = translator.process(global_names)
1.276
1.277 # vim: tabstop=4 expandtab shiftwidth=4