javaclass

Changeset

8:60fb5a7b7181
2004-11-08 Paul Boddie raw files shortlog changelog graph Attempted to provide proper bytecode output with 16-bit operands, special "lazy" subvalues which should be correctly completed for each byte of uncomputed constants. Attempted to make branches perform correctly, presumably needing to involve offsets from the following instruction in the Python VM. Attempted to add support for the jsr/jsr_w/ret mechanism. Note that the usage of RAISE_VARARGS is probably inappropriate. Added convenience methods to get details of the names, constants and stack depth from the BytecodeWriter, although the globals have been removed as a separate mapping and a variable name registry is missing.
bytecode.py (file)
     1.1 --- a/bytecode.py	Sun Nov 07 20:53:03 2004 +0100
     1.2 +++ b/bytecode.py	Mon Nov 08 00:30:55 2004 +0100
     1.3 @@ -7,7 +7,7 @@
     1.4  NOTE: Synchronized constructs are not actually supported.
     1.5  """
     1.6  
     1.7 -from dis import opmap # for access to Python bytecode values
     1.8 +from dis import opmap, cmp_op # for access to Python bytecode values and operators
     1.9  from UserDict import UserDict
    1.10  
    1.11  # Bytecode production classes.
    1.12 @@ -22,27 +22,83 @@
    1.13          self.output = []
    1.14          self.position = 0
    1.15  
    1.16 +        # Stack depth estimation.
    1.17 +        self.stack_depth = 0
    1.18 +        self.max_stack_depth = 0
    1.19 +
    1.20          # Mapping from values to indexes.
    1.21          self.constants = {}
    1.22  
    1.23          # Mapping from names to indexes.
    1.24          # NOTE: This may be acquired from elsewhere.
    1.25 -        self.globals = {}
    1.26 +        #self.globals = {}
    1.27  
    1.28          # Mapping from names to indexes.
    1.29          self.names = {}
    1.30  
    1.31 +        # A list of constants used as exception handler return addresses.
    1.32 +        self.constants_for_exceptions = []
    1.33 +
    1.34      def get_output(self):
    1.35          output = []
    1.36          for element in self.output:
    1.37 -            if isinstance(element, LazyValue):
    1.38 -                output.append(chr(element.value))
    1.39 +            if isinstance(element, LazySubValue):
    1.40 +                value = element.value
    1.41              else:
    1.42 -                output.append(chr(element))
    1.43 +                value = element
    1.44 +            output.append(chr(value))
    1.45          return "".join(output)
    1.46  
    1.47 +    def get_constants(self):
    1.48 +        l = self._get_list(self._invert(self.constants))
    1.49 +        result = []
    1.50 +        for i in l:
    1.51 +            if isinstance(i, LazyValue):
    1.52 +                result.append(i.get_value())
    1.53 +            else:
    1.54 +                result.append(i)
    1.55 +        return result
    1.56 +
    1.57 +    #def get_globals(self):
    1.58 +    #    return self._get_list(self._invert(self.globals))
    1.59 +
    1.60 +    def get_names(self):
    1.61 +        return self._get_list(self._invert(self.names))
    1.62 +
    1.63 +    def _invert(self, d):
    1.64 +        inverted = {}
    1.65 +        for k, v in d.items():
    1.66 +            inverted[v] = k
    1.67 +        return inverted
    1.68 +
    1.69 +    def _get_list(self, d):
    1.70 +        l = []
    1.71 +        for i in range(0, len(d.keys())):
    1.72 +            l.append(d[i])
    1.73 +        return l
    1.74 +
    1.75 +    # Administrative methods.
    1.76 +
    1.77 +    def update_stack_depth(self, change):
    1.78 +        self.stack_depth += change
    1.79 +        if self.stack_depth > self.max_stack_depth:
    1.80 +            self.max_stack_depth = self.stack_depth
    1.81 +
    1.82      # Special methods.
    1.83  
    1.84 +    def _write_value(self, value):
    1.85 +        if isinstance(value, LazyValue):
    1.86 +            # NOTE: Assume a 16-bit value.
    1.87 +            self.output.append(value.values[0])
    1.88 +            self.output.append(value.values[1])
    1.89 +        elif value <= 0xffff:
    1.90 +            self.output.append(value & 0xff)
    1.91 +            self.output.append((value & 0xff00) >> 8)
    1.92 +            self.position += 2
    1.93 +        else:
    1.94 +            # NOTE: EXTENDED_ARG not yet supported.
    1.95 +            raise ValueError, value
    1.96 +
    1.97      def end_loop(self):
    1.98          current_loop_start = self.loops.pop()
    1.99          self.jump_absolute(current_loop_start)
   1.100 @@ -51,20 +107,42 @@
   1.101  
   1.102      def jump_to_label(self, status, name):
   1.103          # Record the instruction using the jump.
   1.104 -        if not self.jumps.has_key(name):
   1.105 -            self.jumps[name] = []
   1.106 -        self.jumps[name].append(self.position)
   1.107 +        jump_instruction = self.position
   1.108          if status is None:
   1.109              self.jump_forward()
   1.110          elif status:
   1.111              self.jump_if_true()
   1.112          else:
   1.113              self.jump_if_false()
   1.114 +        # Record the following instruction, too.
   1.115 +        if not self.jumps.has_key(name):
   1.116 +            self.jumps[name] = []
   1.117 +        self.jumps[name].append((jump_instruction, self.position))
   1.118  
   1.119      def start_label(self, name):
   1.120          # Fill in all jump instructions.
   1.121 -        for jump_instruction in self.jumps[name]:
   1.122 -            self.output[jump_instruction + 1] = self.position
   1.123 +        for jump_instruction, following_instruction in self.jumps[name]:
   1.124 +            self.output[jump_instruction + 1] = self.position - following_instruction
   1.125 +        del self.jumps[name]
   1.126 +
   1.127 +    def load_const_ret(self, value):
   1.128 +        self.constants_for_exceptions.append(value)
   1.129 +        self.load_const(value)
   1.130 +
   1.131 +    def ret(self, index):
   1.132 +        # Previously, the constant stored on the stack by jsr/jsr_w was stored
   1.133 +        # in a local variable. In the JVM, extracting the value from the local
   1.134 +        # variable and jumping can be done at runtime. In the Python VM, any
   1.135 +        # jump target must be known in advance and written into the bytecode.
   1.136 +        self.load_fast(index)
   1.137 +        for constant in self.constants_for_exceptions:
   1.138 +            self.dup_top()              # Stack: actual-address, actual-address
   1.139 +            self.load_const(constant)   # Stack: actual-address, actual-address, suggested-address
   1.140 +            self.compare_op("==")       # Stack: actual-address, result
   1.141 +            self.jump_to_label(0, "const")
   1.142 +            self.jump_absolute(constant)
   1.143 +            self.start_label("const")
   1.144 +            self.pop_top()              # Stack: actual-address
   1.145  
   1.146      # Complicated methods.
   1.147  
   1.148 @@ -72,55 +150,103 @@
   1.149          self.output.append(opmap["LOAD_CONST"])
   1.150          if not self.constants.has_key(value):
   1.151              self.constants[value] = len(self.constants.keys())
   1.152 -        self.output.append(self.constants[value])
   1.153 -        self.position += 2
   1.154 +        self.position += 1
   1.155 +        self._write_value(self.constants[value])
   1.156 +        self.update_stack_depth(1)
   1.157  
   1.158      def load_global(self, name):
   1.159          self.output.append(opmap["LOAD_GLOBAL"])
   1.160 -        if not self.globals.has_key(name):
   1.161 -            self.globals[name] = len(self.globals.keys())
   1.162 -        self.output.append(self.globals[name])
   1.163 -        self.position += 2
   1.164 +        if not self.names.has_key(name):
   1.165 +            self.names[name] = len(self.names.keys())
   1.166 +        self.position += 1
   1.167 +        self._write_value(self.names[name])
   1.168 +        self.update_stack_depth(1)
   1.169  
   1.170      def load_attr(self, name):
   1.171          self.output.append(opmap["LOAD_ATTR"])
   1.172          if not self.names.has_key(name):
   1.173              self.names[name] = len(self.names.keys())
   1.174 -        self.output.append(self.names[name])
   1.175 -        self.position += 2
   1.176 +        self.position += 1
   1.177 +        self._write_value(self.names[name])
   1.178 +
   1.179 +    def load_name(self, name):
   1.180 +        self.output.append(opmap["LOAD_NAME"])
   1.181 +        if not self.names.has_key(name):
   1.182 +            self.names[name] = len(self.names.keys())
   1.183 +        self.position += 1
   1.184 +        self._write_value(self.names[name])
   1.185 +        self.update_stack_depth(1)
   1.186  
   1.187      def load_fast(self, index):
   1.188          self.output.append(opmap["LOAD_FAST"])
   1.189 -        self.output.append(index)
   1.190 -        self.position += 2
   1.191 +        self.position += 1
   1.192 +        self._write_value(index)
   1.193 +        self.update_stack_depth(1)
   1.194 +
   1.195 +    def store_attr(self, name):
   1.196 +        self.output.append(opmap["STORE_ATTR"])
   1.197 +        if not self.names.has_key(name):
   1.198 +            self.names[name] = len(self.names.keys())
   1.199 +        self.position += 1
   1.200 +        self._write_value(self.names[name])
   1.201 +        self.update_stack_depth(-1)
   1.202 +
   1.203 +    def store_fast(self, index):
   1.204 +        self.output.append(opmap["STORE_FAST"])
   1.205 +        self.position += 1
   1.206 +        self._write_value(index)
   1.207 +        self.update_stack_depth(-1)
   1.208  
   1.209      # Normal bytecode generators.
   1.210  
   1.211      def for_iter(self):
   1.212          self.loops.push(self.position)
   1.213          self.output.append(opmap["FOR_ITER"])
   1.214 -        self.output.append(None) # To be filled in later
   1.215 -        self.position += 2
   1.216 +        self.position += 1
   1.217 +        self._write_value(0) # To be filled in later
   1.218 +        self.update_stack_depth(1)
   1.219  
   1.220 -    def jump_if_false(self, offset=None):
   1.221 +    def jump_if_false(self, offset=0):
   1.222          self.output.append(opmap["JUMP_IF_FALSE"])
   1.223 -        self.output.append(offset) # May be filled in later
   1.224 -        self.position += 2
   1.225 +        self.position += 1
   1.226 +        self._write_value(offset) # May be filled in later
   1.227  
   1.228 -    def jump_if_true(self, offset=None):
   1.229 +    def jump_if_true(self, offset=0):
   1.230          self.output.append(opmap["JUMP_IF_TRUE"])
   1.231 -        self.output.append(offset) # May be filled in later
   1.232 -        self.position += 2
   1.233 +        self.position += 1
   1.234 +        self._write_value(offset) # May be filled in later
   1.235  
   1.236 -    def jump_forward(self, offset=None):
   1.237 +    def jump_forward(self, offset=0):
   1.238          self.output.append(opmap["JUMP_FORWARD"])
   1.239 -        self.output.append(offset) # May be filled in later
   1.240 -        self.position += 2
   1.241 +        self.position += 1
   1.242 +        self._write_value(offset) # May be filled in later
   1.243 +
   1.244 +    def jump_absolute(self, address=0):
   1.245 +        self.output.append(opmap["JUMP_ABSOLUTE"])
   1.246 +        self.position += 1
   1.247 +        self._write_value(address) # May be filled in later
   1.248  
   1.249      def build_tuple(self, count):
   1.250          self.output.append(opmap["BUILD_TUPLE"])
   1.251 -        self.output.append(count)
   1.252 -        self.position += 2
   1.253 +        self.position += 1
   1.254 +        self._write_value(count)
   1.255 +        self.update_stack_depth(-(count - 1))
   1.256 +
   1.257 +    def build_list(self, count):
   1.258 +        self.output.append(opmap["BUILD_LIST"])
   1.259 +        self.position += 1
   1.260 +        self._write_value(count)
   1.261 +        self.update_stack_depth(-(count - 1))
   1.262 +
   1.263 +    def pop_top(self):
   1.264 +        self.output.append(opmap["POP_TOP"])
   1.265 +        self.position += 1
   1.266 +        self.update_stack_depth(-1)
   1.267 +
   1.268 +    def dup_top(self):
   1.269 +        self.output.append(opmap["DUP_TOP"])
   1.270 +        self.position += 1
   1.271 +        self.update_stack_depth(1)
   1.272  
   1.273      def rot_two(self):
   1.274          self.output.append(opmap["ROT_TWO"])
   1.275 @@ -136,26 +262,120 @@
   1.276  
   1.277      def call_function(self, count):
   1.278          self.output.append(opmap["CALL_FUNCTION"])
   1.279 -        self.output.append(count)
   1.280 -        self.position += 2
   1.281 +        self.position += 1
   1.282 +        self._write_value(count)
   1.283 +        self.update_stack_depth(-count)
   1.284 +
   1.285 +    def binary_subscr(self):
   1.286 +        self.output.append(opmap["BINARY_SUBSCR"])
   1.287 +        self.position += 1
   1.288 +        self.update_stack_depth(-1)
   1.289 +
   1.290 +    def binary_add(self):
   1.291 +        self.output.append(opmap["BINARY_ADD"])
   1.292 +        self.position += 1
   1.293 +        self.update_stack_depth(-1)
   1.294 +
   1.295 +    def binary_divide(self):
   1.296 +        self.output.append(opmap["BINARY_DIVIDE"])
   1.297 +        self.position += 1
   1.298 +        self.update_stack_depth(-1)
   1.299 +
   1.300 +    def binary_multiply(self):
   1.301 +        self.output.append(opmap["BINARY_MULTIPLY"])
   1.302 +        self.position += 1
   1.303 +        self.update_stack_depth(-1)
   1.304 +
   1.305 +    def binary_modulo(self):
   1.306 +        self.output.append(opmap["BINARY_MODULO"])
   1.307 +        self.position += 1
   1.308 +        self.update_stack_depth(-1)
   1.309 +
   1.310 +    def binary_subtract(self):
   1.311 +        self.output.append(opmap["BINARY_SUBTRACT"])
   1.312 +        self.position += 1
   1.313 +        self.update_stack_depth(-1)
   1.314 +
   1.315 +    def binary_and(self):
   1.316 +        self.output.append(opmap["BINARY_AND"])
   1.317 +        self.position += 1
   1.318 +        self.update_stack_depth(-1)
   1.319 +
   1.320 +    def binary_or(self):
   1.321 +        self.output.append(opmap["BINARY_XOR"])
   1.322 +        self.position += 1
   1.323 +        self.update_stack_depth(-1)
   1.324 +
   1.325 +    def binary_lshift(self):
   1.326 +        self.output.append(opmap["BINARY_LSHIFT"])
   1.327 +        self.position += 1
   1.328 +        self.update_stack_depth(-1)
   1.329 +
   1.330 +    def binary_rshift(self):
   1.331 +        self.output.append(opmap["BINARY_RSHIFT"])
   1.332 +        self.position += 1
   1.333 +        self.update_stack_depth(-1)
   1.334 +
   1.335 +    def binary_xor(self):
   1.336 +        self.output.append(opmap["BINARY_XOR"])
   1.337 +        self.position += 1
   1.338 +        self.update_stack_depth(-1)
   1.339 +
   1.340 +    def compare_op(self, op):
   1.341 +        self.output.append(opmap["COMPARE_OP"])
   1.342 +        self.position += 1
   1.343 +        self._write_value(list(cmp_op).index(op))
   1.344 +        self.update_stack_depth(-1)
   1.345 +
   1.346 +    def return_value(self):
   1.347 +        self.output.append(opmap["RETURN_VALUE"])
   1.348 +        self.position += 1
   1.349 +        self.update_stack_depth(-1)
   1.350 +
   1.351 +    def raise_varargs(self, count):
   1.352 +        self.output.append(opmap["RAISE_VARARGS"])
   1.353 +        self.position += 1
   1.354 +        self._write_value(count)
   1.355  
   1.356  # Utility classes and functions.
   1.357  
   1.358  class LazyDict(UserDict):
   1.359      def __getitem__(self, key):
   1.360          if not self.data.has_key(key):
   1.361 -            self.data[key] = LazyValue()
   1.362 +            # NOTE: Assume 16-bit value.
   1.363 +            self.data[key] = LazyValue(2)
   1.364          return self.data[key]
   1.365      def __setitem__(self, key, value):
   1.366          if self.data.has_key(key):
   1.367              existing_value = self.data[key]
   1.368              if isinstance(existing_value, LazyValue):
   1.369 -                existing_value.value = value
   1.370 +                existing_value.set_value(value)
   1.371                  return
   1.372          self.data[key] = value
   1.373  
   1.374  class LazyValue:
   1.375 -    def __init__(self, value=None):
   1.376 +    def __init__(self, nvalues):
   1.377 +        self.values = []
   1.378 +        for i in range(0, nvalues):
   1.379 +            self.values.append(LazySubValue())
   1.380 +    def set_value(self, value):
   1.381 +        # NOTE: Assume at least 16-bit value. No "filling" performed.
   1.382 +        if value <= 0xffff:
   1.383 +            self.values[0].set_value(value & 0xff)
   1.384 +            self.values[1].set_value((value & 0xff00) >> 8)
   1.385 +        else:
   1.386 +            # NOTE: EXTENDED_ARG not yet supported.
   1.387 +            raise ValueError, value
   1.388 +    def get_value(self):
   1.389 +        value = 0
   1.390 +        for i in range(0, len(self.values)):
   1.391 +            value = (value << 8) + self.values.pop().value
   1.392 +        return value
   1.393 +
   1.394 +class LazySubValue:
   1.395 +    def __init__(self):
   1.396 +        self.value = 0
   1.397 +    def set_value(self, value):
   1.398          self.value = value
   1.399  
   1.400  def signed(value, limit):
   1.401 @@ -390,7 +610,7 @@
   1.402          174 : ("freturn", 0),
   1.403          175 : ("dreturn", 0),
   1.404          176 : ("areturn", 0),
   1.405 -        177 : ("return", 0),
   1.406 +        177 : ("return_", 0),
   1.407          178 : ("getstatic", 2),
   1.408          179 : ("putstatic", 2),
   1.409          180 : ("getfield", 2),
   1.410 @@ -439,9 +659,6 @@
   1.411  
   1.412      "A Java bytecode translator which uses a Python bytecode writer."
   1.413  
   1.414 -    def nop(self, arguments, program):
   1.415 -        pass
   1.416 -
   1.417      def aaload(self, arguments, program):
   1.418          # NOTE: No type checking performed.
   1.419          program.binary_subscr()
   1.420 @@ -474,7 +691,9 @@
   1.421          # NOTE: Does not raise NegativeArraySizeException.
   1.422          # NOTE: Not using the index to type the list/array.
   1.423          index = (arguments[0] << 8) + arguments[1]
   1.424 +        self._newarray(program)
   1.425  
   1.426 +    def _newarray(self, program):
   1.427          program.build_list()        # Stack: count, list
   1.428          program.rot_two()           # Stack: list, count
   1.429          program.setup_loop()
   1.430 @@ -668,7 +887,13 @@
   1.431          # NOTE: Using the string version of the name which may contain incompatible characters.
   1.432          program.load_attr(str(target_name))
   1.433  
   1.434 -    getstatic = getfield # Ignoring Java restrictions
   1.435 +    def getstatic(self, arguments, program):
   1.436 +        index = (arguments[0] << 8) + arguments[1]
   1.437 +        target_name = self.class_file.constants[index - 1].get_name()
   1.438 +        program.load_name("self")
   1.439 +        program.load_attr("__class__")
   1.440 +        # NOTE: Using the string version of the name which may contain incompatible characters.
   1.441 +        program.load_attr(str(target_name))
   1.442  
   1.443      def goto(self, arguments, program):
   1.444          offset = signed2((arguments[0] << 8) + arguments[1])
   1.445 @@ -840,7 +1065,6 @@
   1.446          program.call_function(2)            # Stack: result
   1.447  
   1.448      def _invoke(self, target_name, program):
   1.449 -        program.rot_two()                   # Stack: tuple, objectref
   1.450          # NOTE: Using the string version of the name which may contain incompatible characters.
   1.451          program.load_attr(str(target_name)) # Stack: tuple, method
   1.452          program.rot_two()                   # Stack: method, tuple
   1.453 @@ -857,6 +1081,7 @@
   1.454          target_name = self.class_file.constants[index - 1].get_name()
   1.455          # Stack: objectref, arg1, arg2, ...
   1.456          program.build_tuple(count)          # Stack: objectref, tuple
   1.457 +        program.rot_two()                   # Stack: tuple, objectref
   1.458          self._invoke(target_name, program)
   1.459  
   1.460      def invokespecial(self, arguments, program):
   1.461 @@ -869,8 +1094,28 @@
   1.462          # Get the number of parameters from the descriptor.
   1.463          count = len(target.get_descriptor()[0])
   1.464          # Stack: objectref, arg1, arg2, ...
   1.465 -        program.build_tuple(count)          # Stack: objectref, tuple
   1.466 +        program.build_tuple(count + 1)  # Stack: tuple
   1.467 +        # Use the class to provide access to static methods.
   1.468 +        program.load_name("self")       # Stack: tuple, self
   1.469 +        program.load_attr("__class__")  # Stack: tuple, class
   1.470 +        program.load_attr("__bases__")  # Stack: tuple, base-classes
   1.471 +        program.dup_top()               # Stack: tuple, base-classes, base-classes
   1.472 +        program.load_global("len")      # Stack: tuple, base-classes, base-classes, len
   1.473 +        program.rot_two()               # Stack: tuple, base-classes, len, base-classes
   1.474 +        program.call_function(1)        # Stack: tuple, base-classes, count
   1.475 +        program.load_const(0)           # Stack: tuple, base-classes, count, 0
   1.476 +        program.compare_op("==")        # Stack: tuple, base-classes, result
   1.477 +        program.jump_to_label(1, "next")
   1.478 +        program.pop_top()               # Stack: tuple, base-classes
   1.479 +        program.load_const(0)           # Stack: tuple, base-classes, 0
   1.480 +        program.binary_subscr()         # Stack: tuple, superclass
   1.481          self._invoke(target_name, program)
   1.482 +        program.jump_to_label(None, "next2")
   1.483 +        program.start_label("next")
   1.484 +        program.pop_top()               # Stack: tuple, base-classes
   1.485 +        program.pop_top()               # Stack: tuple
   1.486 +        program.pop_top()               # Stack:
   1.487 +        program.start_label("next2")
   1.488  
   1.489      def invokestatic(self, arguments, program):
   1.490          # NOTE: This implementation does not perform the necessary checks for
   1.491 @@ -882,9 +1127,10 @@
   1.492          # Get the number of parameters from the descriptor.
   1.493          count = len(target.get_descriptor()[0])
   1.494          # Stack: arg1, arg2, ...
   1.495 -        program.build_tuple(count)  # Stack: tuple
   1.496 -        # NOTE: Should probably use Python static methods.
   1.497 -        program.load_name("self")   # Stack: tuple, self
   1.498 +        program.build_tuple(count)      # Stack: tuple
   1.499 +        # Use the class to provide access to static methods.
   1.500 +        program.load_name("self")       # Stack: tuple, self
   1.501 +        program.load_attr("__class__")  # Stack: tuple, class
   1.502          self._invoke(target_name, program)
   1.503  
   1.504      invokevirtual = invokeinterface # Ignoring Java rules
   1.505 @@ -922,14 +1168,14 @@
   1.506          offset = signed2((arguments[0] << 8) + arguments[1])
   1.507          java_absolute = self.java_position + offset
   1.508          # Store the address of the next instruction.
   1.509 -        program.load_const(self.position_mapping[self.java_position + 3])
   1.510 +        program.load_const_ret(self.position_mapping[self.java_position + 3])
   1.511          program.jump_absolute(self.position_mapping[java_absolute])
   1.512  
   1.513      def jsr_w(self, arguments, program):
   1.514          offset = signed4((arguments[0] << 24) + (arguments[1] << 16) + (arguments[2] << 8) + arguments[3])
   1.515          java_absolute = self.java_position + offset
   1.516          # Store the address of the next instruction.
   1.517 -        program.load_const(self.position_mapping[self.java_position + 5])
   1.518 +        program.load_const_ret(self.position_mapping[self.java_position + 5])
   1.519          program.jump_absolute(self.position_mapping[java_absolute])
   1.520  
   1.521      l2d = i2d
   1.522 @@ -1015,12 +1261,12 @@
   1.523              program.dup_top()                                           # Stack: key, key
   1.524              program.load_const(match)                                   # Stack: key, key, match
   1.525              program.compare_op("==")                                    # Stack: key, result
   1.526 -            program.jump_to_label(0, "end" + str(pair))
   1.527 +            program.jump_to_label(0, "end")
   1.528              program.pop_top()                                           # Stack: key
   1.529              program.pop_top()                                           # Stack:
   1.530              program.jump_absolute(self.position_mapping[java_absolute])
   1.531              # Generate the label for the end of the branching code.
   1.532 -            program.start_label("end" + str(pair))
   1.533 +            program.start_label("end")
   1.534              program.pop_top()                                           # Stack: key
   1.535              # Update the index.
   1.536              pair_index += 8
   1.537 @@ -1051,19 +1297,95 @@
   1.538          pass
   1.539  
   1.540      def multianewarray(self, arguments, program):
   1.541 -        program.build_list()        # Stack: count1, count2, ..., countN, list
   1.542 -        program.rot_two()           # Stack: count1, count2, ..., list, countN
   1.543 -        program.setup_loop()
   1.544 -        program.load_global("range")
   1.545 -        program.load_const(0)       # Stack: list, count, range, 0
   1.546 -        program.rot_three()         # Stack: list, 0, count, range
   1.547 -        program.rot_three()         # Stack: list, range, 0, count
   1.548 -        program.call_function(2)    # Stack: list, range_list
   1.549 -        program.get_iter()          # Stack: list, iter
   1.550 -        program.for_iter()          # Stack: list, iter, value
   1.551 -        for i in range(0, arguments[2]):
   1.552 -                                                # Stack: 
   1.553 -            self.anewarray(arguments, program)  # Stack: list, iter
   1.554 +        # NOTE: To be implemented.
   1.555 +        pass
   1.556 +
   1.557 +    def new(self, arguments, program):
   1.558 +        # This operation is considered to be the same as the calling of the
   1.559 +        # initialisation method of the given class with no arguments.
   1.560 +        index = (arguments[0] << 8) + arguments[1]
   1.561 +        target_name = self.class_file.constants[index - 1].get_name()
   1.562 +        # NOTE: Using the string version of the name which may contain incompatible characters.
   1.563 +        program.load_global(str(target_name))
   1.564 +        program.call_function(0)
   1.565 +
   1.566 +    def newarray(self, arguments, program):
   1.567 +        # NOTE: Does not raise NegativeArraySizeException.
   1.568 +        # NOTE: Not using the arguments to type the list/array.
   1.569 +        self._newarray(program)
   1.570 +
   1.571 +    def nop(self, arguments, program):
   1.572 +        pass
   1.573 +
   1.574 +    def pop(self, arguments, program):
   1.575 +        program.pop_top()
   1.576 +
   1.577 +    pop2 = pop # ignoring Java stack value distinctions
   1.578 +
   1.579 +    def putfield(self, arguments, program):
   1.580 +        index = (arguments[0] << 8) + arguments[1]
   1.581 +        target_name = self.class_file.constants[index - 1].get_name()
   1.582 +        program.rot_two()
   1.583 +        # NOTE: Using the string version of the name which may contain incompatible characters.
   1.584 +        program.store_attr(str(target_name))
   1.585 +
   1.586 +    def putstatic(self, arguments, program):
   1.587 +        index = (arguments[0] << 8) + arguments[1]
   1.588 +        target_name = self.class_file.constants[index - 1].get_name()
   1.589 +        program.load_name("self")
   1.590 +        program.load_attr("__class__")
   1.591 +        # NOTE: Using the string version of the name which may contain incompatible characters.
   1.592 +        program.store_attr(str(target_name))
   1.593 +
   1.594 +    def ret(self, arguments, program):
   1.595 +        program.ret(arguments[0])
   1.596 +
   1.597 +    def return_(self, arguments, program):
   1.598 +        program.load_const(None)
   1.599 +        program.return_value()
   1.600 +
   1.601 +    saload = laload
   1.602 +    sastore = lastore
   1.603 +
   1.604 +    def sipush(self, arguments, program):
   1.605 +        program.load_const((arguments[0] << 8) + arguments[1])
   1.606 +
   1.607 +    def swap(self, arguments, program):
   1.608 +        program.rot_two()
   1.609 +
   1.610 +    def tableswitch(self, arguments, program):
   1.611 +        # Find the offset to the next 4 byte boundary in the code.
   1.612 +        d, r = divmod(self.java_position, 4)
   1.613 +        to_boundary = (4 - r) % 4
   1.614 +        # Get the pertinent arguments.
   1.615 +        arguments = arguments[to_boundary:]
   1.616 +        default = (arguments[0] << 24) + (arguments[1] << 16) + (arguments[2] << 8) + arguments[3]
   1.617 +        low = (arguments[4] << 24) + (arguments[5] << 16) + (arguments[6] << 8) + arguments[7]
   1.618 +        high = (arguments[8] << 24) + (arguments[9] << 16) + (arguments[10] << 8) + arguments[11]
   1.619 +        # Process the jump entries.
   1.620 +        # NOTE: This is not the most optimal implementation.
   1.621 +        jump_index = 8
   1.622 +        for jump in range(low, high + 1):
   1.623 +            offset = signed4((arguments[jump_index] << 24) + (arguments[jump_index + 1] << 16) +
   1.624 +                (arguments[jump_index + 2] << 8) + arguments[jump_index + 3])
   1.625 +            # Calculate the branch target.
   1.626 +            java_absolute = self.java_position + offset
   1.627 +            # Generate branching code.
   1.628 +            program.dup_top()                                           # Stack: key, key
   1.629 +            program.load_const(jump)                                    # Stack: key, key, jump
   1.630 +            program.compare_op("==")                                    # Stack: key, result
   1.631 +            program.jump_to_label(0, "end")
   1.632 +            program.pop_top()                                           # Stack: key
   1.633 +            program.pop_top()                                           # Stack:
   1.634 +            program.jump_absolute(self.position_mapping[java_absolute])
   1.635 +            # Generate the label for the end of the branching code.
   1.636 +            program.start_label("end")
   1.637 +            program.pop_top()                                           # Stack: key
   1.638 +            # Update the index.
   1.639 +            jump_index += 8
   1.640 +        # Generate the default.
   1.641 +        java_absolute = self.java_position + default
   1.642 +        program.jump_absolute(self.position_mapping[java_absolute])
   1.643  
   1.644      def wide(self, code, program):
   1.645          # NOTE: To be implemented.