javaclass

Changeset

181:39d5f9ecb58b
2006-08-16 Paul Boddie raw files shortlog changelog graph Reverted "interfaces as superclasses" change. branch-rel-0-1-mostly-working
javaclass/bytecode.py (file)
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/javaclass/bytecode.py	Wed Aug 16 01:06:37 2006 +0200
     1.3 @@ -0,0 +1,2413 @@
     1.4 +#!/usr/bin/env python
     1.5 +
     1.6 +"""
     1.7 +Java bytecode conversion. Specification found at the following URL:
     1.8 +http://java.sun.com/docs/books/vmspec/2nd-edition/html/Instructions2.doc.html
     1.9 +
    1.10 +NOTE: Synchronized constructs are not actually supported.
    1.11 +"""
    1.12 +
    1.13 +import classfile
    1.14 +from dis import cmp_op, opname # for access to Python bytecode values and operators
    1.15 +try:
    1.16 +    from dis import opmap
    1.17 +except ImportError:
    1.18 +    opmap = {}
    1.19 +    for i in range(0, len(opname)):
    1.20 +        opmap[opname[i]] = i
    1.21 +from UserDict import UserDict
    1.22 +import new
    1.23 +
    1.24 +# Bytecode production classes.
    1.25 +
    1.26 +class BytecodeWriter:
    1.27 +
    1.28 +    "A Python bytecode writer."
    1.29 +
    1.30 +    def __init__(self):
    1.31 +
    1.32 +        "Initialise the writer."
    1.33 +
    1.34 +        # A stack of loop start instructions corresponding to loop blocks.
    1.35 +        self.loops = []
    1.36 +
    1.37 +        # A stack of loop block or exception block start positions.
    1.38 +        self.blocks = []
    1.39 +
    1.40 +        # A stack of exception block handler pointers.
    1.41 +        self.exception_handlers = []
    1.42 +
    1.43 +        # A list of exception offset details.
    1.44 +        self.exception_offsets = []
    1.45 +
    1.46 +        # A dictionary mapping labels to jump instructions referencing such labels.
    1.47 +        self.jumps = {}
    1.48 +
    1.49 +        # The output values, including "lazy" subvalues which will need evaluating.
    1.50 +        self.output = []
    1.51 +
    1.52 +        # The current Python bytecode instruction position.
    1.53 +        self.position = 0
    1.54 +
    1.55 +        # Stack depth estimation.
    1.56 +        self.stack_depth = 0
    1.57 +        self.max_stack_depth = 0
    1.58 +
    1.59 +        # Local variable estimation.
    1.60 +        self.max_locals = 0
    1.61 +
    1.62 +        # Mapping from values to indexes.
    1.63 +        self.constants = {}
    1.64 +
    1.65 +        # Mapping from names to indexes.
    1.66 +        # NOTE: This may be acquired from elsewhere.
    1.67 +        #self.globals = {}
    1.68 +
    1.69 +        # Mapping from names to indexes.
    1.70 +        self.names = {}
    1.71 +
    1.72 +        # A list of constants used as exception handler return addresses.
    1.73 +        self.constants_for_exceptions = []
    1.74 +
    1.75 +        # A list of external names.
    1.76 +        self.external_names = []
    1.77 +
    1.78 +    def get_bytecodes(self):
    1.79 +
    1.80 +        "Return the list of bytecodes written to the writer."
    1.81 +
    1.82 +        output = []
    1.83 +        for element in self.output:
    1.84 +            if isinstance(element, LazySubValue):
    1.85 +                value = element.value
    1.86 +            else:
    1.87 +                value = element
    1.88 +            output.append(value)
    1.89 +        return output
    1.90 +
    1.91 +    def get_output(self):
    1.92 +
    1.93 +        "Return the output of the writer as a string."
    1.94 +
    1.95 +        output = []
    1.96 +        for value in self.get_bytecodes():
    1.97 +            # NOTE: ValueError gets raised for bad values here.
    1.98 +            output.append(chr(value))
    1.99 +        return "".join(output)
   1.100 +
   1.101 +    def get_constants(self):
   1.102 +
   1.103 +        """
   1.104 +        Return a list of constants with ordering significant to the code
   1.105 +        employing them.
   1.106 +        """
   1.107 +
   1.108 +        l = self._get_list(self._invert(self.constants))
   1.109 +        result = []
   1.110 +        for i in l:
   1.111 +            if isinstance(i, LazyValue):
   1.112 +                result.append(i.get_value())
   1.113 +            else:
   1.114 +                result.append(i)
   1.115 +        return result
   1.116 +
   1.117 +    #def get_globals(self):
   1.118 +    #    return self._get_list(self._invert(self.globals))
   1.119 +
   1.120 +    def get_names(self):
   1.121 +
   1.122 +        """
   1.123 +        Return a list of names with ordering significant to the code employing
   1.124 +        them.
   1.125 +        """
   1.126 +
   1.127 +        return self._get_list(self._invert(self.names))
   1.128 +
   1.129 +    def _invert(self, d):
   1.130 +
   1.131 +        """
   1.132 +        Return a new dictionary whose key-to-value mapping is in the inverse of
   1.133 +        that found in 'd'.
   1.134 +        """
   1.135 +
   1.136 +        inverted = {}
   1.137 +        for k, v in d.items():
   1.138 +            inverted[v] = k
   1.139 +        return inverted
   1.140 +
   1.141 +    def _get_list(self, d):
   1.142 +
   1.143 +        """
   1.144 +        Traverse the dictionary 'd' returning a list whose values appear at the
   1.145 +        position denoted by each value's key in 'd'.
   1.146 +        """
   1.147 +
   1.148 +        l = []
   1.149 +        for i in range(0, len(d.keys())):
   1.150 +            l.append(d[i])
   1.151 +        return l
   1.152 +
   1.153 +    # Administrative methods.
   1.154 +
   1.155 +    def update_stack_depth(self, change):
   1.156 +
   1.157 +        """
   1.158 +        Given the stated 'change' in stack depth, update the maximum stack depth
   1.159 +        where appropriate.
   1.160 +        """
   1.161 +
   1.162 +        self.stack_depth += change
   1.163 +        if self.stack_depth > self.max_stack_depth:
   1.164 +            self.max_stack_depth = self.stack_depth
   1.165 +
   1.166 +    def update_locals(self, index):
   1.167 +
   1.168 +        """
   1.169 +        Given the stated 'index' of a local variable, update the maximum local
   1.170 +        variable index where appropriate.
   1.171 +        """
   1.172 +
   1.173 +        if index > self.max_locals:
   1.174 +            self.max_locals = index
   1.175 +
   1.176 +    # Special methods.
   1.177 +
   1.178 +    def _write_value(self, value):
   1.179 +
   1.180 +        """
   1.181 +        Write the given 'value' at the current output position.
   1.182 +        """
   1.183 +
   1.184 +        if isinstance(value, LazyValue):
   1.185 +            # NOTE: Assume a 16-bit value.
   1.186 +            self.output.append(value.values[0])
   1.187 +            self.output.append(value.values[1])
   1.188 +            self.position += 2
   1.189 +        elif value <= 0xffff:
   1.190 +            self.output.append(value & 0xff)
   1.191 +            self.output.append((value & 0xff00) >> 8)
   1.192 +            self.position += 2
   1.193 +        else:
   1.194 +            # NOTE: EXTENDED_ARG not yet supported.
   1.195 +            raise ValueError, value
   1.196 +
   1.197 +    def _rewrite_value(self, position, value):
   1.198 +
   1.199 +        """
   1.200 +        At the given output 'position', rewrite the given 'value'.
   1.201 +        """
   1.202 +
   1.203 +        # NOTE: Assume a 16-bit value.
   1.204 +        if value <= 0xffff:
   1.205 +            self.output[position] = (value & 0xff)
   1.206 +            self.output[position + 1] = ((value & 0xff00) >> 8)
   1.207 +        else:
   1.208 +            # NOTE: EXTENDED_ARG not yet supported.
   1.209 +            raise ValueError, value
   1.210 +
   1.211 +    # Higher level methods.
   1.212 +
   1.213 +    def use_external_name(self, name):
   1.214 +        # NOTE: Remove array and object indicators.
   1.215 +        self.external_names.append(name)
   1.216 +
   1.217 +    def setup_loop(self):
   1.218 +        self.loops.append(self.position)
   1.219 +        self.output.append(opmap["SETUP_LOOP"])
   1.220 +        self.position += 1
   1.221 +        self._write_value(0) # To be filled in later
   1.222 +
   1.223 +    def end_loop(self):
   1.224 +        current_loop_start = self.loops.pop()
   1.225 +        current_loop_real_start = self.blocks.pop()
   1.226 +        #print "<", self.blocks, current_loop_real_start
   1.227 +        # Fix the iterator delta.
   1.228 +        # NOTE: Using 3 as the assumed length of the FOR_ITER instruction.
   1.229 +        self.jump_absolute(current_loop_real_start)
   1.230 +        self._rewrite_value(current_loop_real_start + 1, self.position - current_loop_real_start - 3)
   1.231 +        self.pop_block()
   1.232 +        # Fix the loop delta.
   1.233 +        # NOTE: Using 3 as the assumed length of the SETUP_LOOP instruction.
   1.234 +        self._rewrite_value(current_loop_start + 1, self.position - current_loop_start - 3)
   1.235 +
   1.236 +    def jump_to_label(self, status, name):
   1.237 +        # Record the instruction using the jump.
   1.238 +        jump_instruction = self.position
   1.239 +        if status is None:
   1.240 +            self.jump_forward()
   1.241 +        elif status:
   1.242 +            self.jump_if_true()
   1.243 +        else:
   1.244 +            self.jump_if_false()
   1.245 +        # Record the following instruction, too.
   1.246 +        if not self.jumps.has_key(name):
   1.247 +            self.jumps[name] = []
   1.248 +        self.jumps[name].append((jump_instruction, self.position))
   1.249 +
   1.250 +    def start_label(self, name):
   1.251 +        # Fill in all jump instructions.
   1.252 +        for jump_instruction, following_instruction in self.jumps[name]:
   1.253 +            self._rewrite_value(jump_instruction + 1, self.position - following_instruction)
   1.254 +        del self.jumps[name]
   1.255 +
   1.256 +    def load_const_ret(self, value):
   1.257 +        self.constants_for_exceptions.append(value)
   1.258 +        self.load_const(value)
   1.259 +
   1.260 +    def ret(self, index):
   1.261 +        self.load_fast(index)
   1.262 +
   1.263 +        # Previously, the constant stored on the stack by jsr/jsr_w was stored
   1.264 +        # in a local variable. In the JVM, extracting the value from the local
   1.265 +        # variable and jumping can be done at runtime. In the Python VM, any
   1.266 +        # jump target must be known in advance and written into the bytecode.
   1.267 +
   1.268 +        for constant in self.constants_for_exceptions:
   1.269 +            self.dup_top()              # Stack: actual-address, actual-address
   1.270 +            self.load_const(constant)   # Stack: actual-address, actual-address, suggested-address
   1.271 +            self.compare_op("==")       # Stack: actual-address, result
   1.272 +            self.jump_to_label(0, "const")
   1.273 +            self.pop_top()              # Stack: actual-address
   1.274 +            self.pop_top()              # Stack:
   1.275 +            self.jump_absolute(constant)
   1.276 +            self.start_label("const")
   1.277 +            self.pop_top()              # Stack: actual-address
   1.278 +
   1.279 +        # NOTE: If we get here, something is really wrong.
   1.280 +
   1.281 +        self.pop_top()              # Stack:
   1.282 +
   1.283 +    def setup_except(self, target):
   1.284 +        self.blocks.append(self.position)
   1.285 +        self.exception_handlers.append(target)
   1.286 +        #print "-", self.position, target
   1.287 +        self.output.append(opmap["SETUP_EXCEPT"])
   1.288 +        self.position += 1
   1.289 +        self._write_value(0) # To be filled in later
   1.290 +
   1.291 +    def setup_finally(self, target):
   1.292 +        self.blocks.append(self.position)
   1.293 +        self.exception_handlers.append(target)
   1.294 +        #print "-", self.position, target
   1.295 +        self.output.append(opmap["SETUP_FINALLY"])
   1.296 +        self.position += 1
   1.297 +        self._write_value(0) # To be filled in later
   1.298 +
   1.299 +    def end_exception(self):
   1.300 +        current_exception_start = self.blocks.pop()
   1.301 +        # Convert the "lazy" absolute value.
   1.302 +        current_exception_target = self.exception_handlers.pop()
   1.303 +        # NOTE: Using 3 as the assumed length of the SETUP_* instruction.
   1.304 +        self.exception_offsets.append((current_exception_start + 1, current_exception_target, current_exception_start))
   1.305 +
   1.306 +    def end_exceptions(self):
   1.307 +        for position, exception_target, exception_start in self.exception_offsets:
   1.308 +            #print "*", exception_start, exception_target.get_value()
   1.309 +            self._rewrite_value(position, exception_target.get_value() - exception_start - 3)
   1.310 +
   1.311 +    def start_handler(self, exc_name, class_file):
   1.312 +
   1.313 +        # Where handlers are begun, produce bytecode to test the type of
   1.314 +        # the exception.
   1.315 +        # NOTE: Since RAISE_VARARGS and END_FINALLY are not really documented,
   1.316 +        # NOTE: we store the top of the stack and use it later to trigger the
   1.317 +        # NOTE: magic processes when re-raising.
   1.318 +        self.use_external_name(str(exc_name))
   1.319 +
   1.320 +        self.rot_two()                      # Stack: raised-exception, exception
   1.321 +        self.dup_top()                      # Stack: raised-exception, exception, exception
   1.322 +        # Handled exceptions are wrapped before being thrown.
   1.323 +        self.load_global("Exception")       # Stack: raised-exception, exception, exception, Exception
   1.324 +        self.compare_op("exception match")  # Stack: raised-exception, exception, result
   1.325 +        self.jump_to_label(0, "next")
   1.326 +        self.pop_top()                      # Stack: raised-exception, exception
   1.327 +        self.dup_top()                      # Stack: raised-exception, exception, exception
   1.328 +        self.load_attr("args")              # Stack: raised-exception, exception, args
   1.329 +        self.load_const(0)                  # Stack: raised-exception, exception, args, 0
   1.330 +        self.binary_subscr()                # Stack: raised-exception, exception, exception-object
   1.331 +        load_class_name(class_file, str(exc_name), self)
   1.332 +                                            # Stack: raised-exception, exception, exception-object, handled-exception
   1.333 +        self.load_global("isinstance")      # Stack: raised-exception, exception, exception-object, handled-exception, isinstance
   1.334 +        self.rot_three()                    # Stack: raised-exception, exception, isinstance, exception-object, handled-exception
   1.335 +        self.call_function(2)               # Stack: raised-exception, exception, result
   1.336 +        self.jump_to_label(1, "handler")
   1.337 +        self.start_label("next")
   1.338 +        self.pop_top()                      # Stack: raised-exception, exception
   1.339 +        self.rot_two()                      # Stack: exception, raised-exception
   1.340 +        self.end_finally()
   1.341 +        self.start_label("handler")
   1.342 +        self.pop_top()                      # Stack: raised-exception, exception
   1.343 +
   1.344 +    # Complicated methods.
   1.345 +
   1.346 +    def load_const(self, value):
   1.347 +        self.output.append(opmap["LOAD_CONST"])
   1.348 +        if not self.constants.has_key(value):
   1.349 +            self.constants[value] = len(self.constants.keys())
   1.350 +        self.position += 1
   1.351 +        self._write_value(self.constants[value])
   1.352 +        self.update_stack_depth(1)
   1.353 +
   1.354 +    def load_global(self, name):
   1.355 +        self.output.append(opmap["LOAD_GLOBAL"])
   1.356 +        if not self.names.has_key(name):
   1.357 +            self.names[name] = len(self.names.keys())
   1.358 +        self.position += 1
   1.359 +        self._write_value(self.names[name])
   1.360 +        self.update_stack_depth(1)
   1.361 +
   1.362 +    def load_attr(self, name):
   1.363 +        self.output.append(opmap["LOAD_ATTR"])
   1.364 +        if not self.names.has_key(name):
   1.365 +            self.names[name] = len(self.names.keys())
   1.366 +        self.position += 1
   1.367 +        self._write_value(self.names[name])
   1.368 +
   1.369 +    def load_name(self, name):
   1.370 +        self.output.append(opmap["LOAD_NAME"])
   1.371 +        if not self.names.has_key(name):
   1.372 +            self.names[name] = len(self.names.keys())
   1.373 +        self.position += 1
   1.374 +        self._write_value(self.names[name])
   1.375 +        self.update_stack_depth(1)
   1.376 +
   1.377 +    def load_fast(self, index):
   1.378 +        self.output.append(opmap["LOAD_FAST"])
   1.379 +        self.position += 1
   1.380 +        self._write_value(index)
   1.381 +        self.update_stack_depth(1)
   1.382 +        self.update_locals(index)
   1.383 +
   1.384 +    def store_attr(self, name):
   1.385 +        self.output.append(opmap["STORE_ATTR"])
   1.386 +        if not self.names.has_key(name):
   1.387 +            self.names[name] = len(self.names.keys())
   1.388 +        self.position += 1
   1.389 +        self._write_value(self.names[name])
   1.390 +        self.update_stack_depth(-1)
   1.391 +
   1.392 +    def store_fast(self, index):
   1.393 +        self.output.append(opmap["STORE_FAST"])
   1.394 +        self.position += 1
   1.395 +        self._write_value(index)
   1.396 +        self.update_stack_depth(-1)
   1.397 +        self.update_locals(index)
   1.398 +
   1.399 +    def for_iter(self):
   1.400 +        self.blocks.append(self.position)
   1.401 +        #print ">", self.blocks
   1.402 +        self.output.append(opmap["FOR_ITER"])
   1.403 +        self.position += 1
   1.404 +        self._write_value(0) # To be filled in later
   1.405 +        self.update_stack_depth(1)
   1.406 +
   1.407 +    def break_loop(self):
   1.408 +        self.output.append(opmap["BREAK_LOOP"])
   1.409 +        self.position += 1
   1.410 +        self.jump_absolute(self.blocks[-1])
   1.411 +
   1.412 +    # Normal bytecode generators.
   1.413 +
   1.414 +    def get_iter(self):
   1.415 +        self.output.append(opmap["GET_ITER"])
   1.416 +        self.position += 1
   1.417 +
   1.418 +    def jump_if_false(self, offset=0):
   1.419 +        self.output.append(opmap["JUMP_IF_FALSE"])
   1.420 +        self.position += 1
   1.421 +        self._write_value(offset) # May be filled in later
   1.422 +
   1.423 +    def jump_if_true(self, offset=0):
   1.424 +        self.output.append(opmap["JUMP_IF_TRUE"])
   1.425 +        self.position += 1
   1.426 +        self._write_value(offset) # May be filled in later
   1.427 +
   1.428 +    def jump_forward(self, offset=0):
   1.429 +        self.output.append(opmap["JUMP_FORWARD"])
   1.430 +        self.position += 1
   1.431 +        self._write_value(offset) # May be filled in later
   1.432 +
   1.433 +    def jump_absolute(self, address=0):
   1.434 +        self.output.append(opmap["JUMP_ABSOLUTE"])
   1.435 +        self.position += 1
   1.436 +        self._write_value(address) # May be filled in later
   1.437 +
   1.438 +    def build_tuple(self, count):
   1.439 +        self.output.append(opmap["BUILD_TUPLE"])
   1.440 +        self.position += 1
   1.441 +        self._write_value(count)
   1.442 +        self.update_stack_depth(-(count - 1))
   1.443 +
   1.444 +    def build_list(self, count):
   1.445 +        self.output.append(opmap["BUILD_LIST"])
   1.446 +        self.position += 1
   1.447 +        self._write_value(count)
   1.448 +        self.update_stack_depth(-(count - 1))
   1.449 +
   1.450 +    def pop_top(self):
   1.451 +        self.output.append(opmap["POP_TOP"])
   1.452 +        self.position += 1
   1.453 +        self.update_stack_depth(-1)
   1.454 +
   1.455 +    def dup_top(self):
   1.456 +        self.output.append(opmap["DUP_TOP"])
   1.457 +        self.position += 1
   1.458 +        self.update_stack_depth(1)
   1.459 +
   1.460 +    def dup_topx(self, count):
   1.461 +        self.output.append(opmap["DUP_TOPX"])
   1.462 +        self.position += 1
   1.463 +        self._write_value(count)
   1.464 +        self.update_stack_depth(count)
   1.465 +
   1.466 +    def rot_two(self):
   1.467 +        self.output.append(opmap["ROT_TWO"])
   1.468 +        self.position += 1
   1.469 +
   1.470 +    def rot_three(self):
   1.471 +        self.output.append(opmap["ROT_THREE"])
   1.472 +        self.position += 1
   1.473 +
   1.474 +    def rot_four(self):
   1.475 +        self.output.append(opmap["ROT_FOUR"])
   1.476 +        self.position += 1
   1.477 +
   1.478 +    def call_function(self, count):
   1.479 +        self.output.append(opmap["CALL_FUNCTION"])
   1.480 +        self.position += 1
   1.481 +        self._write_value(count)
   1.482 +        self.update_stack_depth(-count)
   1.483 +
   1.484 +    def call_function_var(self, count):
   1.485 +        self.output.append(opmap["CALL_FUNCTION_VAR"])
   1.486 +        self.position += 1
   1.487 +        self._write_value(count)
   1.488 +        self.update_stack_depth(-count-1)
   1.489 +
   1.490 +    def binary_subscr(self):
   1.491 +        self.output.append(opmap["BINARY_SUBSCR"])
   1.492 +        self.position += 1
   1.493 +        self.update_stack_depth(-1)
   1.494 +
   1.495 +    def binary_add(self):
   1.496 +        self.output.append(opmap["BINARY_ADD"])
   1.497 +        self.position += 1
   1.498 +        self.update_stack_depth(-1)
   1.499 +
   1.500 +    def binary_divide(self):
   1.501 +        self.output.append(opmap["BINARY_DIVIDE"])
   1.502 +        self.position += 1
   1.503 +        self.update_stack_depth(-1)
   1.504 +
   1.505 +    def binary_multiply(self):
   1.506 +        self.output.append(opmap["BINARY_MULTIPLY"])
   1.507 +        self.position += 1
   1.508 +        self.update_stack_depth(-1)
   1.509 +
   1.510 +    def binary_modulo(self):
   1.511 +        self.output.append(opmap["BINARY_MODULO"])
   1.512 +        self.position += 1
   1.513 +        self.update_stack_depth(-1)
   1.514 +
   1.515 +    def binary_subtract(self):
   1.516 +        self.output.append(opmap["BINARY_SUBTRACT"])
   1.517 +        self.position += 1
   1.518 +        self.update_stack_depth(-1)
   1.519 +
   1.520 +    def binary_and(self):
   1.521 +        self.output.append(opmap["BINARY_AND"])
   1.522 +        self.position += 1
   1.523 +        self.update_stack_depth(-1)
   1.524 +
   1.525 +    def binary_or(self):
   1.526 +        self.output.append(opmap["BINARY_XOR"])
   1.527 +        self.position += 1
   1.528 +        self.update_stack_depth(-1)
   1.529 +
   1.530 +    def binary_lshift(self):
   1.531 +        self.output.append(opmap["BINARY_LSHIFT"])
   1.532 +        self.position += 1
   1.533 +        self.update_stack_depth(-1)
   1.534 +
   1.535 +    def binary_rshift(self):
   1.536 +        self.output.append(opmap["BINARY_RSHIFT"])
   1.537 +        self.position += 1
   1.538 +        self.update_stack_depth(-1)
   1.539 +
   1.540 +    def binary_xor(self):
   1.541 +        self.output.append(opmap["BINARY_XOR"])
   1.542 +        self.position += 1
   1.543 +        self.update_stack_depth(-1)
   1.544 +
   1.545 +    def store_subscr(self):
   1.546 +        self.output.append(opmap["STORE_SUBSCR"])
   1.547 +        self.position += 1
   1.548 +        self.update_stack_depth(-3)
   1.549 +
   1.550 +    def unary_negative(self):
   1.551 +        self.output.append(opmap["UNARY_NEGATIVE"])
   1.552 +        self.position += 1
   1.553 +
   1.554 +    def slice_0(self):
   1.555 +        self.output.append(opmap["SLICE+0"])
   1.556 +        self.position += 1
   1.557 +
   1.558 +    def slice_1(self):
   1.559 +        self.output.append(opmap["SLICE+1"])
   1.560 +        self.position += 1
   1.561 +
   1.562 +    def compare_op(self, op):
   1.563 +        self.output.append(opmap["COMPARE_OP"])
   1.564 +        self.position += 1
   1.565 +        self._write_value(list(cmp_op).index(op))
   1.566 +        self.update_stack_depth(-1)
   1.567 +
   1.568 +    def return_value(self):
   1.569 +        self.output.append(opmap["RETURN_VALUE"])
   1.570 +        self.position += 1
   1.571 +        self.update_stack_depth(-1)
   1.572 +
   1.573 +    def raise_varargs(self, count):
   1.574 +        self.output.append(opmap["RAISE_VARARGS"])
   1.575 +        self.position += 1
   1.576 +        self._write_value(count)
   1.577 +
   1.578 +    def pop_block(self):
   1.579 +        self.output.append(opmap["POP_BLOCK"])
   1.580 +        self.position += 1
   1.581 +
   1.582 +    def end_finally(self):
   1.583 +        self.output.append(opmap["END_FINALLY"])
   1.584 +        self.position += 1
   1.585 +
   1.586 +    def unpack_sequence(self, count):
   1.587 +        self.output.append(opmap["UNPACK_SEQUENCE"])
   1.588 +        self.position += 1
   1.589 +        self._write_value(count)
   1.590 +
   1.591 +    # Debugging.
   1.592 +
   1.593 +    def print_item(self):
   1.594 +        self.output.append(opmap["PRINT_ITEM"])
   1.595 +        self.position += 1
   1.596 +
   1.597 +# Utility classes and functions.
   1.598 +
   1.599 +class LazyDict(UserDict):
   1.600 +    def __getitem__(self, key):
   1.601 +        if not self.data.has_key(key):
   1.602 +            # NOTE: Assume 16-bit value.
   1.603 +            self.data[key] = LazyValue(2)
   1.604 +        return self.data[key]
   1.605 +    def __setitem__(self, key, value):
   1.606 +        if self.data.has_key(key):
   1.607 +            existing_value = self.data[key]
   1.608 +            if isinstance(existing_value, LazyValue):
   1.609 +                existing_value.set_value(value)
   1.610 +                return
   1.611 +        self.data[key] = value
   1.612 +
   1.613 +class LazyValue:
   1.614 +    def __init__(self, nvalues):
   1.615 +        self.values = []
   1.616 +        for i in range(0, nvalues):
   1.617 +            self.values.append(LazySubValue())
   1.618 +    def set_value(self, value):
   1.619 +        # NOTE: Assume at least 16-bit value. No "filling" performed.
   1.620 +        if value <= 0xffff:
   1.621 +            self.values[0].set_value(value & 0xff)
   1.622 +            self.values[1].set_value((value & 0xff00) >> 8)
   1.623 +        else:
   1.624 +            # NOTE: EXTENDED_ARG not yet supported.
   1.625 +            raise ValueError, value
   1.626 +    def get_value(self):
   1.627 +        value = 0
   1.628 +        values = self.values[:]
   1.629 +        for i in range(0, len(values)):
   1.630 +            value = (value << 8) + values.pop().value
   1.631 +        return value
   1.632 +
   1.633 +class LazySubValue:
   1.634 +    def __init__(self):
   1.635 +        self.value = 0
   1.636 +    def set_value(self, value):
   1.637 +        self.value = value
   1.638 +
   1.639 +def signed(value, limit):
   1.640 +
   1.641 +    """
   1.642 +    Return the signed integer from the unsigned 'value', where 'limit' (a value
   1.643 +    one greater than the highest possible positive integer) is used to determine
   1.644 +    whether a negative or positive result is produced.
   1.645 +    """
   1.646 +
   1.647 +    d, r = divmod(value, limit)
   1.648 +    if d == 1:
   1.649 +        mask = limit * 2 - 1
   1.650 +        return -1 - (value ^ mask)
   1.651 +    else:
   1.652 +        return value
   1.653 +
   1.654 +def signed1(value):
   1.655 +    return signed(value, 0x80)
   1.656 +
   1.657 +def signed2(value):
   1.658 +    return signed(value, 0x8000)
   1.659 +
   1.660 +def signed4(value):
   1.661 +    return signed(value, 0x80000000)
   1.662 +
   1.663 +def load_class_name(class_file, full_class_name, program):
   1.664 +    this_class_name = str(class_file.this_class.get_python_name())
   1.665 +    this_class_parts = this_class_name.split(".")
   1.666 +    class_parts = full_class_name.split(".")
   1.667 +
   1.668 +    # Only use the full path if different from this class's path.
   1.669 +
   1.670 +    if class_parts[:-1] != this_class_parts[:-1]:
   1.671 +        program.use_external_name(full_class_name)
   1.672 +        program.load_global(class_parts[0])
   1.673 +        for class_part in class_parts[1:]:
   1.674 +            program.load_attr(class_part)   # Stack: classref
   1.675 +    else:
   1.676 +        program.load_global(class_parts[-1])
   1.677 +
   1.678 +atypes_to_default_values = {
   1.679 +    4 : 0,      # bool (NOTE: Should be False.)
   1.680 +    5 : u"",    # char
   1.681 +    6 : 0.0,    # float
   1.682 +    7 : 0.0,    # double
   1.683 +    8 : 0,      # byte
   1.684 +    9 : 0,      # short
   1.685 +    10: 0,      # int
   1.686 +    11: 0       # long
   1.687 +}
   1.688 +
   1.689 +def get_default_for_atype(atype):
   1.690 +    global atypes_to_default_values
   1.691 +    return atypes_to_default_values.get(atype)
   1.692 +
   1.693 +# Bytecode conversion.
   1.694 +
   1.695 +class BytecodeReader:
   1.696 +
   1.697 +    "A generic Java bytecode reader."
   1.698 +
   1.699 +    def __init__(self, class_file):
   1.700 +
   1.701 +        """
   1.702 +        Initialise the reader with a 'class_file' containing essential
   1.703 +        information for any bytecode inspection activity.
   1.704 +        """
   1.705 +
   1.706 +        self.class_file = class_file
   1.707 +        self.position_mapping = LazyDict()
   1.708 +
   1.709 +    def process(self, method, program):
   1.710 +
   1.711 +        """
   1.712 +        Process the given 'method' (obtained from the class file), using the
   1.713 +        given 'program' to write translated Python bytecode instructions.
   1.714 +        """
   1.715 +
   1.716 +        self.java_position = 0
   1.717 +        self.in_finally = 0
   1.718 +        self.method = method
   1.719 +
   1.720 +        # NOTE: Potentially unreliable way of getting necessary information.
   1.721 +
   1.722 +        code, exception_table = None, None
   1.723 +        for attribute in method.attributes:
   1.724 +            if isinstance(attribute, classfile.CodeAttributeInfo):
   1.725 +                code, exception_table = attribute.code, attribute.exception_table
   1.726 +                break
   1.727 +
   1.728 +        # Where no code was found, write a very simple placeholder routine.
   1.729 +        # This is useful for interfaces and abstract classes.
   1.730 +        # NOTE: Assess the correctness of doing this. An exception should really
   1.731 +        # NOTE: be raised instead.
   1.732 +
   1.733 +        if code is None:
   1.734 +            program.load_const(None)
   1.735 +            program.return_value()
   1.736 +            return
   1.737 +
   1.738 +        # Produce a structure which permits fast access to exception details.
   1.739 +
   1.740 +        exception_block_start = {}
   1.741 +        exception_block_end = {}
   1.742 +        exception_block_handler = {}
   1.743 +        reversed_exception_table = exception_table[:]
   1.744 +        reversed_exception_table.reverse()
   1.745 +
   1.746 +        # Later entries have wider coverage than earlier entries.
   1.747 +
   1.748 +        for exception in reversed_exception_table:
   1.749 +
   1.750 +            # NOTE: Strange case with javac from JDK 1.4 but not JDK 1.3:
   1.751 +            # NOTE: start_pc == handler_pc
   1.752 +            # Merge all finally handlers with the same handler location.
   1.753 +
   1.754 +            if exception.catch_type == 0 and exception_block_handler.get(exception.handler_pc, []) != []:
   1.755 +
   1.756 +                # Make a new definition.
   1.757 +
   1.758 +                new_exception = classfile.ExceptionInfo()
   1.759 +                new_exception.catch_type = exception.catch_type
   1.760 +                new_exception.handler_pc = exception.handler_pc
   1.761 +                new_exception.end_pc = exception.end_pc
   1.762 +                new_exception.start_pc = exception.start_pc
   1.763 +
   1.764 +                # Find the previous exception handler definition.
   1.765 + 
   1.766 +                for previous_exception in exception_block_handler[exception.handler_pc][:]:
   1.767 +                    if previous_exception.catch_type == 0:
   1.768 +                        new_exception.end_pc = max(new_exception.end_pc, previous_exception.end_pc)
   1.769 +                        new_exception.start_pc = min(new_exception.start_pc, previous_exception.start_pc)
   1.770 +
   1.771 +                        # Remove this exception from the lists.
   1.772 +
   1.773 +                        exception_block_handler[previous_exception.handler_pc].remove(previous_exception)
   1.774 +                        exception_block_start[previous_exception.start_pc].remove(previous_exception)
   1.775 +                        exception_block_end[previous_exception.end_pc].remove(previous_exception)
   1.776 +                        break
   1.777 +
   1.778 +                # Use the new definition instead.
   1.779 +
   1.780 +                exception = new_exception
   1.781 +
   1.782 +            # Index start positions.
   1.783 +
   1.784 +            if not exception_block_start.has_key(exception.start_pc):
   1.785 +                exception_block_start[exception.start_pc] = []
   1.786 +            exception_block_start[exception.start_pc].append(exception)
   1.787 +
   1.788 +            # Index end positions.
   1.789 +
   1.790 +            if not exception_block_end.has_key(exception.end_pc):
   1.791 +                exception_block_end[exception.end_pc] = []
   1.792 +            exception_block_end[exception.end_pc].append(exception)
   1.793 +
   1.794 +            # Index handler positions.
   1.795 +
   1.796 +            if not exception_block_handler.has_key(exception.handler_pc):
   1.797 +                exception_block_handler[exception.handler_pc] = []
   1.798 +            exception_block_handler[exception.handler_pc].append(exception)
   1.799 +
   1.800 +        # Process each instruction in the code.
   1.801 +
   1.802 +        while self.java_position < len(code):
   1.803 +            self.position_mapping[self.java_position] = program.position
   1.804 +
   1.805 +            # Insert exception handling constructs.
   1.806 +
   1.807 +            block_starts = exception_block_start.get(self.java_position, [])
   1.808 +            for exception in block_starts:
   1.809 +
   1.810 +                # Note that the absolute position is used.
   1.811 +
   1.812 +                if exception.catch_type == 0:
   1.813 +                    program.setup_finally(self.position_mapping[exception.handler_pc])
   1.814 +                else:
   1.815 +                    program.setup_except(self.position_mapping[exception.handler_pc])
   1.816 +
   1.817 +            if block_starts:
   1.818 +                self.in_finally = 0
   1.819 +
   1.820 +            # Insert exception handler details.
   1.821 +            # NOTE: Ensure that pop_block is reachable by possibly inserting it at the start of finally handlers.
   1.822 +            # NOTE: Insert a check for the correct exception at the start of each handler.
   1.823 +
   1.824 +            for exception in exception_block_handler.get(self.java_position, []):
   1.825 +                program.end_exception()
   1.826 +                if exception.catch_type == 0:
   1.827 +                    self.in_finally = 1
   1.828 +                else:
   1.829 +                    program.start_handler(self.class_file.constants[exception.catch_type - 1].get_python_name(), self.class_file)
   1.830 +
   1.831 +            # Process the bytecode at the current position.
   1.832 +
   1.833 +            bytecode = ord(code[self.java_position])
   1.834 +            mnemonic, number_of_arguments = self.java_bytecodes[bytecode]
   1.835 +            number_of_arguments = self.process_bytecode(mnemonic, number_of_arguments, code, program)
   1.836 +            next_java_position = self.java_position + 1 + number_of_arguments
   1.837 +
   1.838 +            # Insert exception block end details.
   1.839 +
   1.840 +            for exception in exception_block_end.get(next_java_position, []):
   1.841 +
   1.842 +                # NOTE: Insert jump beyond handlers.
   1.843 +                # NOTE: program.jump_forward/absolute(...)
   1.844 +                # NOTE: Insert end finally at end of handlers as well as where "ret" occurs.
   1.845 +
   1.846 +                if exception.catch_type != 0:
   1.847 +                    program.pop_block()
   1.848 +
   1.849 +            # Only advance the JVM position after sneaking in extra Python
   1.850 +            # instructions.
   1.851 +
   1.852 +            self.java_position = next_java_position
   1.853 +
   1.854 +        # Tidy up exceptions.
   1.855 +
   1.856 +        program.end_exceptions()
   1.857 +
   1.858 +    def process_bytecode(self, mnemonic, number_of_arguments, code, program):
   1.859 +
   1.860 +        """
   1.861 +        Process a bytecode instruction with the given 'mnemonic' and
   1.862 +        'number_of_arguments'. The 'code' parameter contains the full method
   1.863 +        code so that argument data can be inspected. The 'program' parameter is
   1.864 +        used to produce a Python translation of the instruction.
   1.865 +        """
   1.866 +
   1.867 +        if number_of_arguments is not None:
   1.868 +            arguments = [ord(b) for b in code[self.java_position + 1:self.java_position + 1 + number_of_arguments]]
   1.869 +
   1.870 +            # Call the handler.
   1.871 +
   1.872 +            getattr(self, mnemonic)(arguments, program)
   1.873 +            return number_of_arguments
   1.874 +        else:
   1.875 +            # Call the handler.
   1.876 +
   1.877 +            return getattr(self, mnemonic)(code[self.java_position+1:], program)
   1.878 +
   1.879 +    java_bytecodes = {
   1.880 +        # code : (mnemonic, number of following bytes, change in stack)
   1.881 +        0 : ("nop", 0),
   1.882 +        1 : ("aconst_null", 0),
   1.883 +        2 : ("iconst_m1", 0),
   1.884 +        3 : ("iconst_0", 0),
   1.885 +        4 : ("iconst_1", 0),
   1.886 +        5 : ("iconst_2", 0),
   1.887 +        6 : ("iconst_3", 0),
   1.888 +        7 : ("iconst_4", 0),
   1.889 +        8 : ("iconst_5", 0),
   1.890 +        9 : ("lconst_0", 0),
   1.891 +        10 : ("lconst_1", 0),
   1.892 +        11 : ("fconst_0", 0),
   1.893 +        12 : ("fconst_1", 0),
   1.894 +        13 : ("fconst_2", 0),
   1.895 +        14 : ("dconst_0", 0),
   1.896 +        15 : ("dconst_1", 0),
   1.897 +        16 : ("bipush", 1),
   1.898 +        17 : ("sipush", 2),
   1.899 +        18 : ("ldc", 1),
   1.900 +        19 : ("ldc_w", 2),
   1.901 +        20 : ("ldc2_w", 2),
   1.902 +        21 : ("iload", 1),
   1.903 +        22 : ("lload", 1),
   1.904 +        23 : ("fload", 1),
   1.905 +        24 : ("dload", 1),
   1.906 +        25 : ("aload", 1),
   1.907 +        26 : ("iload_0", 0),
   1.908 +        27 : ("iload_1", 0),
   1.909 +        28 : ("iload_2", 0),
   1.910 +        29 : ("iload_3", 0),
   1.911 +        30 : ("lload_0", 0),
   1.912 +        31 : ("lload_1", 0),
   1.913 +        32 : ("lload_2", 0),
   1.914 +        33 : ("lload_3", 0),
   1.915 +        34 : ("fload_0", 0),
   1.916 +        35 : ("fload_1", 0),
   1.917 +        36 : ("fload_2", 0),
   1.918 +        37 : ("fload_3", 0),
   1.919 +        38 : ("dload_0", 0),
   1.920 +        39 : ("dload_1", 0),
   1.921 +        40 : ("dload_2", 0),
   1.922 +        41 : ("dload_3", 0),
   1.923 +        42 : ("aload_0", 0),
   1.924 +        43 : ("aload_1", 0),
   1.925 +        44 : ("aload_2", 0),
   1.926 +        45 : ("aload_3", 0),
   1.927 +        46 : ("iaload", 0),
   1.928 +        47 : ("laload", 0),
   1.929 +        48 : ("faload", 0),
   1.930 +        49 : ("daload", 0),
   1.931 +        50 : ("aaload", 0),
   1.932 +        51 : ("baload", 0),
   1.933 +        52 : ("caload", 0),
   1.934 +        53 : ("saload", 0),
   1.935 +        54 : ("istore", 1),
   1.936 +        55 : ("lstore", 1),
   1.937 +        56 : ("fstore", 1),
   1.938 +        57 : ("dstore", 1),
   1.939 +        58 : ("astore", 1),
   1.940 +        59 : ("istore_0", 0),
   1.941 +        60 : ("istore_1", 0),
   1.942 +        61 : ("istore_2", 0),
   1.943 +        62 : ("istore_3", 0),
   1.944 +        63 : ("lstore_0", 0),
   1.945 +        64 : ("lstore_1", 0),
   1.946 +        65 : ("lstore_2", 0),
   1.947 +        66 : ("lstore_3", 0),
   1.948 +        67 : ("fstore_0", 0),
   1.949 +        68 : ("fstore_1", 0),
   1.950 +        69 : ("fstore_2", 0),
   1.951 +        70 : ("fstore_3", 0),
   1.952 +        71 : ("dstore_0", 0),
   1.953 +        72 : ("dstore_1", 0),
   1.954 +        73 : ("dstore_2", 0),
   1.955 +        74 : ("dstore_3", 0),
   1.956 +        75 : ("astore_0", 0),
   1.957 +        76 : ("astore_1", 0),
   1.958 +        77 : ("astore_2", 0),
   1.959 +        78 : ("astore_3", 0),
   1.960 +        79 : ("iastore", 0),
   1.961 +        80 : ("lastore", 0),
   1.962 +        81 : ("fastore", 0),
   1.963 +        82 : ("dastore", 0),
   1.964 +        83 : ("aastore", 0),
   1.965 +        84 : ("bastore", 0),
   1.966 +        85 : ("castore", 0),
   1.967 +        86 : ("sastore", 0),
   1.968 +        87 : ("pop", 0),
   1.969 +        88 : ("pop2", 0),
   1.970 +        89 : ("dup", 0),
   1.971 +        90 : ("dup_x1", 0),
   1.972 +        91 : ("dup_x2", 0),
   1.973 +        92 : ("dup2", 0),
   1.974 +        93 : ("dup2_x1", 0),
   1.975 +        94 : ("dup2_x2", 0),
   1.976 +        95 : ("swap", 0),
   1.977 +        96 : ("iadd", 0),
   1.978 +        97 : ("ladd", 0),
   1.979 +        98 : ("fadd", 0),
   1.980 +        99 : ("dadd", 0),
   1.981 +        100 : ("isub", 0),
   1.982 +        101 : ("lsub", 0),
   1.983 +        102 : ("fsub", 0),
   1.984 +        103 : ("dsub", 0),
   1.985 +        104 : ("imul", 0),
   1.986 +        105 : ("lmul", 0),
   1.987 +        106 : ("fmul", 0),
   1.988 +        107 : ("dmul", 0),
   1.989 +        108 : ("idiv", 0),
   1.990 +        109 : ("ldiv", 0),
   1.991 +        110 : ("fdiv", 0),
   1.992 +        111 : ("ddiv", 0),
   1.993 +        112 : ("irem", 0),
   1.994 +        113 : ("lrem", 0),
   1.995 +        114 : ("frem", 0),
   1.996 +        115 : ("drem", 0),
   1.997 +        116 : ("ineg", 0),
   1.998 +        117 : ("lneg", 0),
   1.999 +        118 : ("fneg", 0),
  1.1000 +        119 : ("dneg", 0),
  1.1001 +        120 : ("ishl", 0),
  1.1002 +        121 : ("lshl", 0),
  1.1003 +        122 : ("ishr", 0),
  1.1004 +        123 : ("lshr", 0),
  1.1005 +        124 : ("iushr", 0),
  1.1006 +        125 : ("lushr", 0),
  1.1007 +        126 : ("iand", 0),
  1.1008 +        127 : ("land", 0),
  1.1009 +        128 : ("ior", 0),
  1.1010 +        129 : ("lor", 0),
  1.1011 +        130 : ("ixor", 0),
  1.1012 +        131 : ("lxor", 0),
  1.1013 +        132 : ("iinc", 2),
  1.1014 +        133 : ("i2l", 0),
  1.1015 +        134 : ("i2f", 0),
  1.1016 +        135 : ("i2d", 0),
  1.1017 +        136 : ("l2i", 0),
  1.1018 +        137 : ("l2f", 0),
  1.1019 +        138 : ("l2d", 0),
  1.1020 +        139 : ("f2i", 0),
  1.1021 +        140 : ("f2l", 0),
  1.1022 +        141 : ("f2d", 0),
  1.1023 +        142 : ("d2i", 0),
  1.1024 +        143 : ("d2l", 0),
  1.1025 +        144 : ("d2f", 0),
  1.1026 +        145 : ("i2b", 0),
  1.1027 +        146 : ("i2c", 0),
  1.1028 +        147 : ("i2s", 0),
  1.1029 +        148 : ("lcmp", 0),
  1.1030 +        149 : ("fcmpl", 0),
  1.1031 +        150 : ("fcmpg", 0),
  1.1032 +        151 : ("dcmpl", 0),
  1.1033 +        152 : ("dcmpg", 0),
  1.1034 +        153 : ("ifeq", 2),
  1.1035 +        154 : ("ifne", 2),
  1.1036 +        155 : ("iflt", 2),
  1.1037 +        156 : ("ifge", 2),
  1.1038 +        157 : ("ifgt", 2),
  1.1039 +        158 : ("ifle", 2),
  1.1040 +        159 : ("if_icmpeq", 2),
  1.1041 +        160 : ("if_icmpne", 2),
  1.1042 +        161 : ("if_icmplt", 2),
  1.1043 +        162 : ("if_icmpge", 2),
  1.1044 +        163 : ("if_icmpgt", 2),
  1.1045 +        164 : ("if_icmple", 2),
  1.1046 +        165 : ("if_acmpeq", 2),
  1.1047 +        166 : ("if_acmpne", 2),
  1.1048 +        167 : ("goto", 2),
  1.1049 +        168 : ("jsr", 2),
  1.1050 +        169 : ("ret", 1),
  1.1051 +        170 : ("tableswitch", None), # variable number of arguments
  1.1052 +        171 : ("lookupswitch", None), # variable number of arguments
  1.1053 +        172 : ("ireturn", 0),
  1.1054 +        173 : ("lreturn", 0),
  1.1055 +        174 : ("freturn", 0),
  1.1056 +        175 : ("dreturn", 0),
  1.1057 +        176 : ("areturn", 0),
  1.1058 +        177 : ("return_", 0),
  1.1059 +        178 : ("getstatic", 2),
  1.1060 +        179 : ("putstatic", 2),
  1.1061 +        180 : ("getfield", 2),
  1.1062 +        181 : ("putfield", 2),
  1.1063 +        182 : ("invokevirtual", 2),
  1.1064 +        183 : ("invokespecial", 2),
  1.1065 +        184 : ("invokestatic", 2),
  1.1066 +        185 : ("invokeinterface", 4),
  1.1067 +        187 : ("new", 2),
  1.1068 +        188 : ("newarray", 1),
  1.1069 +        189 : ("anewarray", 2),
  1.1070 +        190 : ("arraylength", 0),
  1.1071 +        191 : ("athrow", 0),
  1.1072 +        192 : ("checkcast", 2),
  1.1073 +        193 : ("instanceof", 2),
  1.1074 +        194 : ("monitorenter", 0),
  1.1075 +        195 : ("monitorexit", 0),
  1.1076 +        196 : ("wide", None), # 3 or 5 arguments, stack changes according to modified element
  1.1077 +        197 : ("multianewarray", 3),
  1.1078 +        198 : ("ifnull", 2),
  1.1079 +        199 : ("ifnonnull", 2),
  1.1080 +        200 : ("goto_w", 4),
  1.1081 +        201 : ("jsr_w", 4),
  1.1082 +        }
  1.1083 +
  1.1084 +class BytecodeDisassembler(BytecodeReader):
  1.1085 +
  1.1086 +    "A Java bytecode disassembler."
  1.1087 +
  1.1088 +    bytecode_methods = [spec[0] for spec in BytecodeReader.java_bytecodes.values()]
  1.1089 +
  1.1090 +    def __getattr__(self, name):
  1.1091 +        if name in self.bytecode_methods:
  1.1092 +            print "%5s %s" % (self.java_position, name),
  1.1093 +            return self.generic
  1.1094 +        else:
  1.1095 +            raise AttributeError, name
  1.1096 +
  1.1097 +    def generic(self, arguments, program):
  1.1098 +        print arguments
  1.1099 +
  1.1100 +    def lookupswitch(self, code, program):
  1.1101 +        print "%5s lookupswitch" % (self.java_position,),
  1.1102 +        d, r = divmod(self.java_position + 1, 4)
  1.1103 +        to_boundary = (4 - r) % 4
  1.1104 +        code = code[to_boundary:]
  1.1105 +        default = classfile.s4(code[0:4])
  1.1106 +        npairs = classfile.s4(code[4:8])
  1.1107 +        print default, npairs
  1.1108 +        return to_boundary + 8 + npairs * 8
  1.1109 +
  1.1110 +    def tableswitch(self, code, program):
  1.1111 +        print "%5s tableswitch" % (self.java_position,),
  1.1112 +        d, r = divmod(self.java_position + 1, 4)
  1.1113 +        to_boundary = (4 - r) % 4
  1.1114 +        code = code[to_boundary:]
  1.1115 +        default = classfile.s4(code[0:4])
  1.1116 +        low = classfile.s4(code[4:8])
  1.1117 +        high = classfile.s4(code[8:12])
  1.1118 +        print default, low, high
  1.1119 +        return to_boundary + 12 + (high - low + 1) * 4
  1.1120 +
  1.1121 +class BytecodeDisassemblerProgram:
  1.1122 +    position = 0
  1.1123 +    def setup_except(self, target):
  1.1124 +        print "(setup_except %s)" % target
  1.1125 +    def setup_finally(self, target):
  1.1126 +        print "(setup_finally %s)" % target
  1.1127 +    def end_exception(self):
  1.1128 +        print "(end_exception)"
  1.1129 +    def end_exceptions(self):
  1.1130 +        print "(end_exceptions)"
  1.1131 +    def start_handler(self, exc_name, class_file):
  1.1132 +        print "(start_handler %s)" % exc_name
  1.1133 +    def pop_block(self):
  1.1134 +        print "(pop_block)"
  1.1135 +    def load_const(self, const):
  1.1136 +        print "(load_const %s)" % const
  1.1137 +    def return_value(self):
  1.1138 +        print "(return_value)"
  1.1139 +
  1.1140 +class BytecodeTranslator(BytecodeReader):
  1.1141 +
  1.1142 +    "A Java bytecode translator which uses a Python bytecode writer."
  1.1143 +
  1.1144 +    def aaload(self, arguments, program):
  1.1145 +        # NOTE: No type checking performed.
  1.1146 +        program.binary_subscr()
  1.1147 +
  1.1148 +    def aastore(self, arguments, program):
  1.1149 +        # NOTE: No type checking performed.
  1.1150 +        # Stack: arrayref, index, value
  1.1151 +        program.rot_three() # Stack: value, arrayref, index
  1.1152 +        program.store_subscr()
  1.1153 +
  1.1154 +    def aconst_null(self, arguments, program):
  1.1155 +        program.load_const(None)
  1.1156 +
  1.1157 +    def aload(self, arguments, program):
  1.1158 +        program.load_fast(arguments[0])
  1.1159 +
  1.1160 +    def aload_0(self, arguments, program):
  1.1161 +        program.load_fast(0)
  1.1162 +
  1.1163 +    def aload_1(self, arguments, program):
  1.1164 +        program.load_fast(1)
  1.1165 +
  1.1166 +    def aload_2(self, arguments, program):
  1.1167 +        program.load_fast(2)
  1.1168 +
  1.1169 +    def aload_3(self, arguments, program):
  1.1170 +        program.load_fast(3)
  1.1171 +
  1.1172 +    def anewarray(self, arguments, program):
  1.1173 +        # NOTE: Does not raise NegativeArraySizeException.
  1.1174 +        # NOTE: Not using the index to type the list/array.
  1.1175 +        index = (arguments[0] << 8) + arguments[1]
  1.1176 +        type_name = self.class_file.constants[index - 1].get_python_name()
  1.1177 +        default_value = classfile.get_default_for_type(type_name)
  1.1178 +        self._newarray(program, type_name)
  1.1179 +
  1.1180 +    def _newarray(self, program, default_value):
  1.1181 +        program.build_list(0)               # Stack: count, list
  1.1182 +        program.rot_two()                   # Stack: list, count
  1.1183 +        program.setup_loop()
  1.1184 +        program.load_global("range")
  1.1185 +        program.load_const(0)               # Stack: list, count, range, 0
  1.1186 +        program.rot_three()                 # Stack: list, 0, count, range
  1.1187 +        program.rot_three()                 # Stack: list, range, 0, count
  1.1188 +        program.call_function(2)            # Stack: list, range_list
  1.1189 +        program.get_iter()                  # Stack: list, iter
  1.1190 +        program.for_iter()                  # Stack: list, iter, value
  1.1191 +        program.pop_top()                   # Stack: list, iter
  1.1192 +        program.rot_two()                   # Stack: iter, list
  1.1193 +        program.dup_top()                   # Stack: iter, list, list
  1.1194 +        program.load_attr("append")         # Stack: iter, list, append
  1.1195 +        program.load_const(default_value)   # Stack: iter, list, append, default
  1.1196 +        program.call_function(1)            # Stack: iter, list, default
  1.1197 +        program.pop_top()                   # Stack: iter, list
  1.1198 +        program.rot_two()                   # Stack: list, iter
  1.1199 +        program.end_loop()                  # Back to for_iter above
  1.1200 +
  1.1201 +    def areturn(self, arguments, program):
  1.1202 +        program.return_value()
  1.1203 +
  1.1204 +    def arraylength(self, arguments, program):
  1.1205 +        program.load_global("len")  # Stack: arrayref, len
  1.1206 +        program.rot_two()           # Stack: len, arrayref
  1.1207 +        program.call_function(1)
  1.1208 +
  1.1209 +    def astore(self, arguments, program):
  1.1210 +        program.store_fast(arguments[0])
  1.1211 +
  1.1212 +    def astore_0(self, arguments, program):
  1.1213 +        program.store_fast(0)
  1.1214 +
  1.1215 +    def astore_1(self, arguments, program):
  1.1216 +        program.store_fast(1)
  1.1217 +
  1.1218 +    def astore_2(self, arguments, program):
  1.1219 +        program.store_fast(2)
  1.1220 +
  1.1221 +    def astore_3(self, arguments, program):
  1.1222 +        program.store_fast(3)
  1.1223 +
  1.1224 +    def athrow(self, arguments, program):
  1.1225 +        # NOTE: NullPointerException not raised where null/None is found on the stack.
  1.1226 +        # If this instruction appears in a finally handler, use end_finally instead.
  1.1227 +        if self.in_finally:
  1.1228 +            program.end_finally()
  1.1229 +        else:
  1.1230 +            # Wrap the exception in a Python exception.
  1.1231 +            program.load_global("Exception")    # Stack: objectref, Exception
  1.1232 +            program.rot_two()                   # Stack: Exception, objectref
  1.1233 +            program.call_function(1)            # Stack: exception
  1.1234 +            program.raise_varargs(1)
  1.1235 +            # NOTE: This seems to put another object on the stack.
  1.1236 +
  1.1237 +    baload = aaload
  1.1238 +    bastore = aastore
  1.1239 +
  1.1240 +    def bipush(self, arguments, program):
  1.1241 +        program.load_const(signed1(arguments[0]))
  1.1242 +
  1.1243 +    caload = aaload
  1.1244 +    castore = aastore
  1.1245 +
  1.1246 +    def checkcast(self, arguments, program):
  1.1247 +        index = (arguments[0] << 8) + arguments[1]
  1.1248 +        target_name = self.class_file.constants[index - 1].get_python_name()
  1.1249 +        program.use_external_name(target_name)
  1.1250 +        program.dup_top()                   # Stack: objectref, objectref
  1.1251 +        program.load_const(None)            # Stack: objectref, objectref, None
  1.1252 +        program.compare_op("is")            # Stack: objectref, result
  1.1253 +        program.jump_to_label(1, "next")
  1.1254 +        program.pop_top()                   # Stack: objectref
  1.1255 +        program.dup_top()                   # Stack: objectref, objectref
  1.1256 +        program.load_global("isinstance")   # Stack: objectref, objectref, isinstance
  1.1257 +        program.rot_two()                   # Stack: objectref, isinstance, objectref
  1.1258 +        load_class_name(self.class_file, target_name, program)
  1.1259 +        program.call_function(2)            # Stack: objectref, result
  1.1260 +        program.jump_to_label(1, "next")
  1.1261 +        program.pop_top()                   # Stack: objectref
  1.1262 +        program.pop_top()                   # Stack:
  1.1263 +        program.use_external_name("java.lang.ClassCastException")
  1.1264 +        load_class_name(self.class_file, "java.lang.ClassCastException", program)
  1.1265 +        program.call_function(0)            # Stack: exception
  1.1266 +        # Wrap the exception in a Python exception.
  1.1267 +        program.load_global("Exception")    # Stack: exception, Exception
  1.1268 +        program.rot_two()                   # Stack: Exception, exception
  1.1269 +        program.call_function(1)            # Stack: exception
  1.1270 +        program.raise_varargs(1)
  1.1271 +        # NOTE: This seems to put another object on the stack.
  1.1272 +        program.start_label("next")
  1.1273 +        program.pop_top()                   # Stack: objectref
  1.1274 +
  1.1275 +    def d2f(self, arguments, program):
  1.1276 +        pass
  1.1277 +
  1.1278 +    def d2i(self, arguments, program):
  1.1279 +        program.load_global("int")  # Stack: value, int
  1.1280 +        program.rot_two()           # Stack: int, value
  1.1281 +        program.call_function(1)    # Stack: result
  1.1282 +
  1.1283 +    d2l = d2i # Preserving Java semantics
  1.1284 +
  1.1285 +    def dadd(self, arguments, program):
  1.1286 +        # NOTE: No type checking performed.
  1.1287 +        program.binary_add()
  1.1288 +
  1.1289 +    daload = aaload
  1.1290 +    dastore = aastore
  1.1291 +
  1.1292 +    def dcmpg(self, arguments, program):
  1.1293 +        # NOTE: No type checking performed.
  1.1294 +        program.compare_op(">")
  1.1295 +
  1.1296 +    def dcmpl(self, arguments, program):
  1.1297 +        # NOTE: No type checking performed.
  1.1298 +        program.compare_op("<")
  1.1299 +
  1.1300 +    def dconst_0(self, arguments, program):
  1.1301 +        program.load_const(0.0)
  1.1302 +
  1.1303 +    def dconst_1(self, arguments, program):
  1.1304 +        program.load_const(1.0)
  1.1305 +
  1.1306 +    def ddiv(self, arguments, program):
  1.1307 +        # NOTE: No type checking performed.
  1.1308 +        program.binary_divide()
  1.1309 +
  1.1310 +    dload = aload
  1.1311 +    dload_0 = aload_0
  1.1312 +    dload_1 = aload_1
  1.1313 +    dload_2 = aload_2
  1.1314 +    dload_3 = aload_3
  1.1315 +
  1.1316 +    def dmul(self, arguments, program):
  1.1317 +        # NOTE: No type checking performed.
  1.1318 +        program.binary_multiply()
  1.1319 +
  1.1320 +    def dneg(self, arguments, program):
  1.1321 +        # NOTE: No type checking performed.
  1.1322 +        program.unary_negative()
  1.1323 +
  1.1324 +    def drem(self, arguments, program):
  1.1325 +        # NOTE: No type checking performed.
  1.1326 +        program.binary_modulo()
  1.1327 +
  1.1328 +    dreturn = areturn
  1.1329 +    dstore = astore
  1.1330 +    dstore_0 = astore_0
  1.1331 +    dstore_1 = astore_1
  1.1332 +    dstore_2 = astore_2
  1.1333 +    dstore_3 = astore_3
  1.1334 +
  1.1335 +    def dsub(self, arguments, program):
  1.1336 +        # NOTE: No type checking performed.
  1.1337 +        program.binary_subtract()
  1.1338 +
  1.1339 +    def dup(self, arguments, program):
  1.1340 +        program.dup_top()
  1.1341 +
  1.1342 +    def dup_x1(self, arguments, program):
  1.1343 +        # Ignoring computational type categories.
  1.1344 +        program.dup_top()
  1.1345 +        program.rot_three()
  1.1346 +
  1.1347 +    def dup_x2(self, arguments, program):
  1.1348 +        # Ignoring computational type categories.
  1.1349 +        program.dup_top()
  1.1350 +        program.rot_four()
  1.1351 +
  1.1352 +    dup2 = dup # Ignoring computational type categories
  1.1353 +    dup2_x1 = dup_x1 # Ignoring computational type categories
  1.1354 +    dup2_x2 = dup_x2 # Ignoring computational type categories
  1.1355 +
  1.1356 +    def f2d(self, arguments, program):
  1.1357 +        pass # Preserving Java semantics
  1.1358 +
  1.1359 +    def f2i(self, arguments, program):
  1.1360 +        program.load_global("int")  # Stack: value, int
  1.1361 +        program.rot_two()           # Stack: int, value
  1.1362 +        program.call_function(1)    # Stack: result
  1.1363 +
  1.1364 +    f2l = f2i # Preserving Java semantics
  1.1365 +    fadd = dadd
  1.1366 +    faload = daload
  1.1367 +    fastore = dastore
  1.1368 +    fcmpg = dcmpg
  1.1369 +    fcmpl = dcmpl
  1.1370 +    fconst_0 = dconst_0
  1.1371 +    fconst_1 = dconst_1
  1.1372 +
  1.1373 +    def fconst_2(self, arguments, program):
  1.1374 +        program.load_const(2.0)
  1.1375 +
  1.1376 +    fdiv = ddiv
  1.1377 +    fload = dload
  1.1378 +    fload_0 = dload_0
  1.1379 +    fload_1 = dload_1
  1.1380 +    fload_2 = dload_2
  1.1381 +    fload_3 = dload_3
  1.1382 +    fmul = dmul
  1.1383 +    fneg = dneg
  1.1384 +    frem = drem
  1.1385 +    freturn = dreturn
  1.1386 +    fstore = dstore
  1.1387 +    fstore_0 = dstore_0
  1.1388 +    fstore_1 = dstore_1
  1.1389 +    fstore_2 = dstore_2
  1.1390 +    fstore_3 = dstore_3
  1.1391 +    fsub = dsub
  1.1392 +
  1.1393 +    def getfield(self, arguments, program):
  1.1394 +        index = (arguments[0] << 8) + arguments[1]
  1.1395 +        target_name = self.class_file.constants[index - 1].get_python_name()
  1.1396 +        # NOTE: Using the string version of the name which may contain incompatible characters.
  1.1397 +        program.load_attr(str(target_name))
  1.1398 +
  1.1399 +    def getstatic(self, arguments, program):
  1.1400 +        index = (arguments[0] << 8) + arguments[1]
  1.1401 +        target = self.class_file.constants[index - 1]
  1.1402 +        target_name = target.get_python_name()
  1.1403 +
  1.1404 +        # Get the class name instead of the fully qualified name.
  1.1405 +
  1.1406 +        full_class_name = target.get_class().get_python_name()
  1.1407 +        program.use_external_name(full_class_name)
  1.1408 +        load_class_name(self.class_file, full_class_name, program)
  1.1409 +        # NOTE: Using the string version of the name which may contain incompatible characters.
  1.1410 +        program.load_attr(str(target_name))
  1.1411 +
  1.1412 +    def goto(self, arguments, program):
  1.1413 +        offset = signed2((arguments[0] << 8) + arguments[1])
  1.1414 +        java_absolute = self.java_position + offset
  1.1415 +        program.jump_absolute(self.position_mapping[java_absolute])
  1.1416 +
  1.1417 +    def goto_w(self, arguments, program):
  1.1418 +        offset = signed4((arguments[0] << 24) + (arguments[1] << 16) + (arguments[2] << 8) + arguments[3])
  1.1419 +        java_absolute = self.java_position + offset
  1.1420 +        program.jump_absolute(self.position_mapping[java_absolute])
  1.1421 +
  1.1422 +    def i2b(self, arguments, program):
  1.1423 +        pass
  1.1424 +
  1.1425 +    def i2c(self, arguments, program):
  1.1426 +        pass
  1.1427 +
  1.1428 +    def i2d(self, arguments, program):
  1.1429 +        program.load_global("float")    # Stack: value, float
  1.1430 +        program.rot_two()               # Stack: float, value
  1.1431 +        program.call_function(1)        # Stack: result
  1.1432 +
  1.1433 +    i2f = i2d # Not distinguishing between float and double
  1.1434 +
  1.1435 +    def i2l(self, arguments, program):
  1.1436 +        pass # Preserving Java semantics
  1.1437 +
  1.1438 +    def i2s(self, arguments, program):
  1.1439 +        pass # Not distinguishing between int and short
  1.1440 +
  1.1441 +    iadd = fadd
  1.1442 +    iaload = faload
  1.1443 +
  1.1444 +    def iand(self, arguments, program):
  1.1445 +        # NOTE: No type checking performed.
  1.1446 +        program.binary_and()
  1.1447 +
  1.1448 +    iastore = fastore
  1.1449 +
  1.1450 +    def iconst_m1(self, arguments, program):
  1.1451 +        program.load_const(-1)
  1.1452 +
  1.1453 +    def iconst_0(self, arguments, program):
  1.1454 +        program.load_const(0)
  1.1455 +
  1.1456 +    def iconst_1(self, arguments, program):
  1.1457 +        program.load_const(1)
  1.1458 +
  1.1459 +    def iconst_2(self, arguments, program):
  1.1460 +        program.load_const(2)
  1.1461 +
  1.1462 +    def iconst_3(self, arguments, program):
  1.1463 +        program.load_const(3)
  1.1464 +
  1.1465 +    def iconst_4(self, arguments, program):
  1.1466 +        program.load_const(4)
  1.1467 +
  1.1468 +    def iconst_5(self, arguments, program):
  1.1469 +        program.load_const(5)
  1.1470 +
  1.1471 +    idiv = fdiv
  1.1472 +
  1.1473 +    def _if_xcmpx(self, arguments, program, op):
  1.1474 +        offset = signed2((arguments[0] << 8) + arguments[1])
  1.1475 +        java_absolute = self.java_position + offset
  1.1476 +        program.compare_op(op)
  1.1477 +        program.jump_to_label(0, "next") # skip if false
  1.1478 +        program.pop_top()
  1.1479 +        program.jump_absolute(self.position_mapping[java_absolute])
  1.1480 +        program.start_label("next")
  1.1481 +        program.pop_top()
  1.1482 +
  1.1483 +    def if_acmpeq(self, arguments, program):
  1.1484 +        # NOTE: No type checking performed.
  1.1485 +        self._if_xcmpx(arguments, program, "is")
  1.1486 +
  1.1487 +    def if_acmpne(self, arguments, program):
  1.1488 +        # NOTE: No type checking performed.
  1.1489 +        self._if_xcmpx(arguments, program, "is not")
  1.1490 +
  1.1491 +    def if_icmpeq(self, arguments, program):
  1.1492 +        # NOTE: No type checking performed.
  1.1493 +        self._if_xcmpx(arguments, program, "==")
  1.1494 +
  1.1495 +    def if_icmpne(self, arguments, program):
  1.1496 +        # NOTE: No type checking performed.
  1.1497 +        self._if_xcmpx(arguments, program, "!=")
  1.1498 +
  1.1499 +    def if_icmplt(self, arguments, program):
  1.1500 +        # NOTE: No type checking performed.
  1.1501 +        self._if_xcmpx(arguments, program, "<")
  1.1502 +
  1.1503 +    def if_icmpge(self, arguments, program):
  1.1504 +        # NOTE: No type checking performed.
  1.1505 +        self._if_xcmpx(arguments, program, ">=")
  1.1506 +
  1.1507 +    def if_icmpgt(self, arguments, program):
  1.1508 +        # NOTE: No type checking performed.
  1.1509 +        self._if_xcmpx(arguments, program, ">")
  1.1510 +
  1.1511 +    def if_icmple(self, arguments, program):
  1.1512 +        # NOTE: No type checking performed.
  1.1513 +        self._if_xcmpx(arguments, program, "<=")
  1.1514 +
  1.1515 +    def ifeq(self, arguments, program):
  1.1516 +        # NOTE: No type checking performed.
  1.1517 +        program.load_const(0)
  1.1518 +        self._if_xcmpx(arguments, program, "==")
  1.1519 +
  1.1520 +    def ifne(self, arguments, program):
  1.1521 +        # NOTE: No type checking performed.
  1.1522 +        program.load_const(0)
  1.1523 +        self._if_xcmpx(arguments, program, "!=")
  1.1524 +
  1.1525 +    def iflt(self, arguments, program):
  1.1526 +        # NOTE: No type checking performed.
  1.1527 +        program.load_const(0)
  1.1528 +        self._if_xcmpx(arguments, program, "<")
  1.1529 +
  1.1530 +    def ifge(self, arguments, program):
  1.1531 +        # NOTE: No type checking performed.
  1.1532 +        program.load_const(0)
  1.1533 +        self._if_xcmpx(arguments, program, ">=")
  1.1534 +
  1.1535 +    def ifgt(self, arguments, program):
  1.1536 +        # NOTE: No type checking performed.
  1.1537 +        program.load_const(0)
  1.1538 +        self._if_xcmpx(arguments, program, ">")
  1.1539 +
  1.1540 +    def ifle(self, arguments, program):
  1.1541 +        # NOTE: No type checking performed.
  1.1542 +        program.load_const(0)
  1.1543 +        self._if_xcmpx(arguments, program, "<=")
  1.1544 +
  1.1545 +    def ifnonnull(self, arguments, program):
  1.1546 +        # NOTE: No type checking performed.
  1.1547 +        program.load_const(None)
  1.1548 +        self._if_xcmpx(arguments, program, "is not")
  1.1549 +
  1.1550 +    def ifnull(self, arguments, program):
  1.1551 +        # NOTE: No type checking performed.
  1.1552 +        program.load_const(None)
  1.1553 +        self._if_xcmpx(arguments, program, "is")
  1.1554 +
  1.1555 +    def iinc(self, arguments, program):
  1.1556 +        # NOTE: No type checking performed.
  1.1557 +        program.load_fast(arguments[0])
  1.1558 +        program.load_const(arguments[1])
  1.1559 +        program.binary_add()
  1.1560 +        program.store_fast(arguments[0])
  1.1561 +
  1.1562 +    iload = fload
  1.1563 +    iload_0 = fload_0
  1.1564 +    iload_1 = fload_1
  1.1565 +    iload_2 = fload_2
  1.1566 +    iload_3 = fload_3
  1.1567 +    imul = fmul
  1.1568 +    ineg = fneg
  1.1569 +
  1.1570 +    def instanceof(self, arguments, program):
  1.1571 +        index = (arguments[0] << 8) + arguments[1]
  1.1572 +        target_name = self.class_file.constants[index - 1].get_python_name()
  1.1573 +        program.use_external_name(target_name)
  1.1574 +        program.load_global("isinstance")   # Stack: objectref, isinstance
  1.1575 +        program.rot_two()                   # Stack: isinstance, objectref
  1.1576 +        load_class_name(self.class_file, target_name, program)
  1.1577 +        program.call_function(2)            # Stack: result
  1.1578 +
  1.1579 +    def _invoke(self, target_name, program):
  1.1580 +        # NOTE: Using the string version of the name which may contain incompatible characters.
  1.1581 +        program.load_attr(str(target_name)) # Stack: tuple, method
  1.1582 +        program.rot_two()                   # Stack: method, tuple
  1.1583 +        program.call_function_var(0)        # Stack: result
  1.1584 +
  1.1585 +    def invokeinterface(self, arguments, program):
  1.1586 +        # NOTE: This implementation does not perform the necessary checks for
  1.1587 +        # NOTE: signature-based polymorphism.
  1.1588 +        # NOTE: Java rules not specifically obeyed.
  1.1589 +        index = (arguments[0] << 8) + arguments[1]
  1.1590 +        # NOTE: "count" == nargs + 1, apparently.
  1.1591 +        count = arguments[2] - 1
  1.1592 +        target_name = self.class_file.constants[index - 1].get_python_name()
  1.1593 +        # Stack: objectref, arg1, arg2, ...
  1.1594 +        program.build_tuple(count)          # Stack: objectref, tuple
  1.1595 +        program.rot_two()                   # Stack: tuple, objectref
  1.1596 +        # NOTE: The interface information is not used to discover the correct
  1.1597 +        # NOTE: method.
  1.1598 +        self._invoke(target_name, program)
  1.1599 +
  1.1600 +    def invokespecial(self, arguments, program):
  1.1601 +        # NOTE: This implementation does not perform the necessary checks for
  1.1602 +        # NOTE: signature-based polymorphism.
  1.1603 +        # NOTE: Java rules not specifically obeyed.
  1.1604 +        index = (arguments[0] << 8) + arguments[1]
  1.1605 +        target = self.class_file.constants[index - 1]
  1.1606 +        original_name = target.get_name()
  1.1607 +        target_name = target.get_python_name()
  1.1608 +
  1.1609 +        # Get the number of parameters from the descriptor.
  1.1610 +
  1.1611 +        count = len(target.get_descriptor()[0])
  1.1612 +
  1.1613 +        # First, we build a tuple of the reference and arguments.
  1.1614 +
  1.1615 +        program.build_tuple(count + 1)          # Stack: tuple
  1.1616 +
  1.1617 +        # Get the class name instead of the fully qualified name.
  1.1618 +        # NOTE: Not bothering with Object initialisation.
  1.1619 +
  1.1620 +        full_class_name = target.get_class().get_python_name()
  1.1621 +        if full_class_name not in ("java.lang.Object", "java.lang.Exception"):
  1.1622 +            program.use_external_name(full_class_name)
  1.1623 +            load_class_name(self.class_file, full_class_name, program)
  1.1624 +            self._invoke(target_name, program)
  1.1625 +
  1.1626 +        # Remove Python None return value.
  1.1627 +
  1.1628 +        if str(original_name) == "<init>":
  1.1629 +            program.pop_top()
  1.1630 +
  1.1631 +    def invokestatic(self, arguments, program):
  1.1632 +        # NOTE: This implementation does not perform the necessary checks for
  1.1633 +        # NOTE: signature-based polymorphism.
  1.1634 +        # NOTE: Java rules not specifically obeyed.
  1.1635 +        index = (arguments[0] << 8) + arguments[1]
  1.1636 +        target = self.class_file.constants[index - 1]
  1.1637 +        target_name = target.get_python_name()
  1.1638 +
  1.1639 +        # Get the number of parameters from the descriptor.
  1.1640 +
  1.1641 +        count = len(target.get_descriptor()[0])
  1.1642 +
  1.1643 +        # Stack: arg1, arg2, ...
  1.1644 +
  1.1645 +        program.build_tuple(count)              # Stack: tuple
  1.1646 +
  1.1647 +        # Use the class to provide access to static methods.
  1.1648 +        # Get the class name instead of the fully qualified name.
  1.1649 +
  1.1650 +        full_class_name = target.get_class().get_python_name()
  1.1651 +        if full_class_name not in ("java.lang.Object", "java.lang.Exception"):
  1.1652 +            program.use_external_name(full_class_name)
  1.1653 +            load_class_name(self.class_file, full_class_name, program)
  1.1654 +            self._invoke(target_name, program)
  1.1655 +
  1.1656 +    def invokevirtual (self, arguments, program):
  1.1657 +        # NOTE: This implementation does not perform the necessary checks for
  1.1658 +        # NOTE: signature-based polymorphism.
  1.1659 +        # NOTE: Java rules not specifically obeyed.
  1.1660 +        index = (arguments[0] << 8) + arguments[1]
  1.1661 +        target = self.class_file.constants[index - 1]
  1.1662 +        target_name = target.get_python_name()
  1.1663 +        # Get the number of parameters from the descriptor.
  1.1664 +        count = len(target.get_descriptor()[0])
  1.1665 +        # Stack: objectref, arg1, arg2, ...
  1.1666 +        program.build_tuple(count)          # Stack: objectref, tuple
  1.1667 +        program.rot_two()                   # Stack: tuple, objectref
  1.1668 +        self._invoke(target_name, program)
  1.1669 +
  1.1670 +    def ior(self, arguments, program):
  1.1671 +        # NOTE: No type checking performed.
  1.1672 +        program.binary_or()
  1.1673 +
  1.1674 +    irem = frem
  1.1675 +    ireturn = freturn
  1.1676 +
  1.1677 +    def ishl(self, arguments, program):
  1.1678 +        # NOTE: No type checking performed.
  1.1679 +        # NOTE: Not verified.
  1.1680 +        program.binary_lshift()
  1.1681 +
  1.1682 +    def ishr(self, arguments, program):
  1.1683 +        # NOTE: No type checking performed.
  1.1684 +        # NOTE: Not verified.
  1.1685 +        program.binary_rshift()
  1.1686 +
  1.1687 +    istore = fstore
  1.1688 +    istore_0 = fstore_0
  1.1689 +    istore_1 = fstore_1
  1.1690 +    istore_2 = fstore_2
  1.1691 +    istore_3 = fstore_3
  1.1692 +    isub = fsub
  1.1693 +    iushr = ishr # Ignoring distinctions between arithmetic and logical shifts
  1.1694 +
  1.1695 +    def ixor(self, arguments, program):
  1.1696 +        # NOTE: No type checking performed.
  1.1697 +        program.binary_xor()
  1.1698 +
  1.1699 +    def jsr(self, arguments, program):
  1.1700 +        offset = signed2((arguments[0] << 8) + arguments[1])
  1.1701 +        java_absolute = self.java_position + offset
  1.1702 +        # Store the address of the next instruction.
  1.1703 +        program.load_const_ret(self.position_mapping[self.java_position + 3])
  1.1704 +        program.jump_absolute(self.position_mapping[java_absolute])
  1.1705 +
  1.1706 +    def jsr_w(self, arguments, program):
  1.1707 +        offset = signed4((arguments[0] << 24) + (arguments[1] << 16) + (arguments[2] << 8) + arguments[3])
  1.1708 +        java_absolute = self.java_position + offset
  1.1709 +        # Store the address of the next instruction.
  1.1710 +        program.load_const_ret(self.position_mapping[self.java_position + 5])
  1.1711 +        program.jump_absolute(self.position_mapping[java_absolute])
  1.1712 +
  1.1713 +    l2d = i2d
  1.1714 +    l2f = i2f
  1.1715 +
  1.1716 +    def l2i(self, arguments, program):
  1.1717 +        pass # Preserving Java semantics
  1.1718 +
  1.1719 +    ladd = iadd
  1.1720 +    laload = iaload
  1.1721 +    land = iand
  1.1722 +    lastore = iastore
  1.1723 +
  1.1724 +    def lcmp(self, arguments, program):
  1.1725 +        # NOTE: No type checking performed.
  1.1726 +        program.dup_topx(2)                 # Stack: value1, value2, value1, value2
  1.1727 +        program.compare_op(">")             # Stack: value1, value2, result
  1.1728 +        program.jump_to_label(0, "equals")
  1.1729 +        # True - produce result and branch.
  1.1730 +        program.pop_top()                   # Stack: value1, value2
  1.1731 +        program.pop_top()                   # Stack: value1
  1.1732 +        program.pop_top()                   # Stack:
  1.1733 +        program.load_const(1)               # Stack: 1
  1.1734 +        program.jump_to_label(None, "next")
  1.1735 +        # False - test equality.
  1.1736 +        program.start_label("equals")
  1.1737 +        program.pop_top()                   # Stack: value1, value2
  1.1738 +        program.dup_topx(2)                 # Stack: value1, value2, value1, value2
  1.1739 +        program.compare_op("==")            # Stack: value1, value2, result
  1.1740 +        program.jump_to_label(0, "less")
  1.1741 +        # True - produce result and branch.
  1.1742 +        program.pop_top()                   # Stack: value1, value2
  1.1743 +        program.pop_top()                   # Stack: value1
  1.1744 +        program.pop_top()                   # Stack:
  1.1745 +        program.load_const(0)               # Stack: 0
  1.1746 +        program.jump_to_label(None, "next")
  1.1747 +        # False - produce result.
  1.1748 +        program.start_label("less")
  1.1749 +        program.pop_top()                   # Stack: value1, value2
  1.1750 +        program.pop_top()                   # Stack: value1
  1.1751 +        program.pop_top()                   # Stack:
  1.1752 +        program.load_const(-1)              # Stack: -1
  1.1753 +        program.start_label("next")
  1.1754 +
  1.1755 +    lconst_0 = iconst_0
  1.1756 +    lconst_1 = iconst_1
  1.1757 +
  1.1758 +    def ldc(self, arguments, program):
  1.1759 +        const = self.class_file.constants[arguments[0] - 1]
  1.1760 +        if isinstance(const, classfile.StringInfo):
  1.1761 +            program.use_external_name("java.lang.String")
  1.1762 +            program.load_global("java")
  1.1763 +            program.load_attr("lang")
  1.1764 +            program.load_attr("String")
  1.1765 +            program.load_const(const.get_value())
  1.1766 +            program.call_function(1)
  1.1767 +        else:
  1.1768 +            program.load_const(const.get_value())
  1.1769 +
  1.1770 +    def ldc_w(self, arguments, program):
  1.1771 +        const = self.class_file.constants[(arguments[0] << 8) + arguments[1] - 1]
  1.1772 +        if isinstance(const, classfile.StringInfo):
  1.1773 +            program.use_external_name("java.lang.String")
  1.1774 +            program.load_global("java")
  1.1775 +            program.load_attr("lang")
  1.1776 +            program.load_attr("String")
  1.1777 +            program.load_const(const.get_value())
  1.1778 +            program.call_function(1)
  1.1779 +        else:
  1.1780 +            program.load_const(const.get_value())
  1.1781 +
  1.1782 +    ldc2_w = ldc_w
  1.1783 +    ldiv = idiv
  1.1784 +    lload = iload
  1.1785 +    lload_0 = iload_0
  1.1786 +    lload_1 = iload_1
  1.1787 +    lload_2 = iload_2
  1.1788 +    lload_3 = iload_3
  1.1789 +    lmul = imul
  1.1790 +    lneg = ineg
  1.1791 +
  1.1792 +    def lookupswitch(self, code, program):
  1.1793 +
  1.1794 +        # Find the offset to the next 4 byte boundary in the code.
  1.1795 +
  1.1796 +        d, r = divmod(self.java_position + 1, 4)
  1.1797 +        to_boundary = (4 - r) % 4
  1.1798 +
  1.1799 +        # Get the pertinent arguments.
  1.1800 +
  1.1801 +        code = code[to_boundary:]
  1.1802 +        default = classfile.s4(code[0:4])
  1.1803 +        npairs = classfile.s4(code[4:8])
  1.1804 +
  1.1805 +        # Process the pairs.
  1.1806 +        # NOTE: This is not the most optimal implementation.
  1.1807 +
  1.1808 +        pair_index = 8
  1.1809 +        for pair in range(0, npairs):
  1.1810 +            match = classfile.u4(code[pair_index:pair_index+4])
  1.1811 +            offset = classfile.s4(code[pair_index+4:pair_index+8])
  1.1812 +            # Calculate the branch target.
  1.1813 +            java_absolute = self.java_position + offset
  1.1814 +            # Generate branching code.
  1.1815 +            program.dup_top()                                           # Stack: key, key
  1.1816 +            program.load_const(match)                                   # Stack: key, key, match
  1.1817 +            program.compare_op("==")                                    # Stack: key, result
  1.1818 +            program.jump_to_label(0, "end")
  1.1819 +            program.pop_top()                                           # Stack: key
  1.1820 +            program.pop_top()                                           # Stack:
  1.1821 +            program.jump_absolute(self.position_mapping[java_absolute])
  1.1822 +            # Generate the label for the end of the branching code.
  1.1823 +            program.start_label("end")
  1.1824 +            program.pop_top()                                           # Stack: key
  1.1825 +            # Update the index.
  1.1826 +            pair_index += 8
  1.1827 +
  1.1828 +        # Generate the default.
  1.1829 +
  1.1830 +        java_absolute = self.java_position + default
  1.1831 +        program.jump_absolute(self.position_mapping[java_absolute])
  1.1832 +        return pair_index + to_boundary
  1.1833 +
  1.1834 +    lor = ior
  1.1835 +    lrem = irem
  1.1836 +    lreturn = ireturn
  1.1837 +    lshl = ishl
  1.1838 +    lshr = ishr
  1.1839 +    lstore = istore
  1.1840 +    lstore_0 = istore_0
  1.1841 +    lstore_1 = istore_1
  1.1842 +    lstore_2 = istore_2
  1.1843 +    lstore_3 = istore_3
  1.1844 +    lsub = isub
  1.1845 +    lushr = iushr
  1.1846 +    lxor = ixor
  1.1847 +
  1.1848 +    def monitorenter(self, arguments, program):
  1.1849 +        # NOTE: To be implemented.
  1.1850 +        pass
  1.1851 +
  1.1852 +    def monitorexit(self, arguments, program):
  1.1853 +        # NOTE: To be implemented.
  1.1854 +        pass
  1.1855 +
  1.1856 +    def multianewarray(self, arguments, program):
  1.1857 +        index = (arguments[0] << 8) + arguments[1]
  1.1858 +        dimensions = arguments[2]
  1.1859 +        # Stack: count1, ..., countN-1, countN
  1.1860 +        type_name = self.class_file.constants[index - 1].get_python_name()
  1.1861 +        default_value = classfile.get_default_for_type(type_name)
  1.1862 +        self._newarray(program, default_value)  # Stack: count1, ..., countN-1, list
  1.1863 +        for dimension in range(1, dimensions):
  1.1864 +            program.rot_two()               # Stack: count1, ..., list, countN-1
  1.1865 +            program.build_list(0)           # Stack: count1, ..., list, countN-1, new-list
  1.1866 +            program.rot_three()             # Stack: count1, ..., new-list, list, countN-1
  1.1867 +            program.setup_loop()
  1.1868 +            program.load_const(0)           # Stack: count1, ..., new-list, list, countN-1, 0
  1.1869 +            program.rot_two()               # Stack: count1, ..., new-list, list, 0, countN-1
  1.1870 +            program.load_global("range")    # Stack: count1, ..., new-list, list, 0, countN-1, range
  1.1871 +            program.rot_three()             # Stack: count1, ..., new-list, list, range, 0, countN-1
  1.1872 +            program.call_function(2)        # Stack: count1, ..., new-list, list, range-list
  1.1873 +            program.get_iter()              # Stack: count1, ..., new-list, list, iter
  1.1874 +            program.for_iter()              # Stack: count1, ..., new-list, list, iter, value
  1.1875 +            program.pop_top()               # Stack: count1, ..., new-list, list, iter
  1.1876 +            program.rot_three()             # Stack: count1, ..., iter, new-list, list
  1.1877 +            program.slice_0()               # Stack: count1, ..., iter, new-list, list[:]
  1.1878 +            program.dup_top()               # Stack: count1, ..., iter, new-list, list[:], list[:]
  1.1879 +            program.rot_three()             # Stack: count1, ..., iter, list[:], new-list, list[:]
  1.1880 +            program.rot_two()               # Stack: count1, ..., iter, list[:], list[:], new-list
  1.1881 +            program.dup_top()               # Stack: count1, ..., iter, list[:], list[:], new-list, new-list
  1.1882 +            program.load_attr("append")     # Stack: count1, ..., iter, list[:], list[:], new-list, append
  1.1883 +            program.rot_three()             # Stack: count1, ..., iter, list[:], append, list[:], new-list
  1.1884 +            program.rot_three()             # Stack: count1, ..., iter, list[:], new-list, append, list[:]
  1.1885 +            program.call_function(1)        # Stack: count1, ..., iter, list[:], new-list, None
  1.1886 +            program.pop_top()               # Stack: count1, ..., iter, list[:], new-list
  1.1887 +            program.rot_two()               # Stack: count1, ..., iter, new-list, list[:]
  1.1888 +            program.rot_three()             # Stack: count1, ..., list[:], iter, new-list
  1.1889 +            program.rot_three()             # Stack: count1, ..., new-list, list[:], iter
  1.1890 +            program.end_loop()              # Stack: count1, ..., new-list, list[:], iter
  1.1891 +            program.pop_top()               # Stack: count1, ..., new-list
  1.1892 +
  1.1893 +    def new(self, arguments, program):
  1.1894 +        # This operation is considered to be the same as the calling of the
  1.1895 +        # initialisation method of the given class with no arguments.
  1.1896 +
  1.1897 +        index = (arguments[0] << 8) + arguments[1]
  1.1898 +        target_name = self.class_file.constants[index - 1].get_python_name()
  1.1899 +        program.use_external_name(target_name)
  1.1900 +
  1.1901 +        # NOTE: Using the string version of the name which may contain incompatible characters.
  1.1902 +        program.load_global("object")
  1.1903 +        program.load_attr("__new__")
  1.1904 +        load_class_name(self.class_file, target_name, program)
  1.1905 +        program.call_function(1)
  1.1906 +
  1.1907 +    def newarray(self, arguments, program):
  1.1908 +        # NOTE: Does not raise NegativeArraySizeException.
  1.1909 +        # NOTE: Not completely using the arguments to type the list/array.
  1.1910 +        atype = arguments[0]
  1.1911 +        default_value = get_default_for_atype(atype)
  1.1912 +        self._newarray(program, default_value)
  1.1913 +
  1.1914 +    def nop(self, arguments, program):
  1.1915 +        pass
  1.1916 +
  1.1917 +    def pop(self, arguments, program):
  1.1918 +        program.pop_top()
  1.1919 +
  1.1920 +    pop2 = pop # ignoring Java stack value distinctions
  1.1921 +
  1.1922 +    def putfield(self, arguments, program):
  1.1923 +        index = (arguments[0] << 8) + arguments[1]
  1.1924 +        target_name = self.class_file.constants[index - 1].get_python_name()
  1.1925 +        program.rot_two()
  1.1926 +        # NOTE: Using the string version of the name which may contain incompatible characters.
  1.1927 +        program.store_attr(str(target_name))
  1.1928 +
  1.1929 +    def putstatic(self, arguments, program):
  1.1930 +        index = (arguments[0] << 8) + arguments[1]
  1.1931 +        target = self.class_file.constants[index - 1]
  1.1932 +        target_name = target.get_python_name()
  1.1933 +
  1.1934 +        # Get the class name instead of the fully qualified name.
  1.1935 +
  1.1936 +        full_class_name = target.get_class().get_python_name()
  1.1937 +        program.use_external_name(full_class_name)
  1.1938 +        load_class_name(self.class_file, full_class_name, program)
  1.1939 +        # NOTE: Using the string version of the name which may contain incompatible characters.
  1.1940 +        program.store_attr(str(target_name))
  1.1941 +
  1.1942 +    def ret(self, arguments, program):
  1.1943 +        program.ret(arguments[0])
  1.1944 +        # Indicate that the finally handler is probably over.
  1.1945 +        # NOTE: This is seemingly not guaranteed.
  1.1946 +        self.in_finally = 0
  1.1947 +
  1.1948 +    def return_(self, arguments, program):
  1.1949 +        program.load_const(None)
  1.1950 +        program.return_value()
  1.1951 +
  1.1952 +    saload = laload
  1.1953 +    sastore = lastore
  1.1954 +
  1.1955 +    def sipush(self, arguments, program):
  1.1956 +        program.load_const(signed2((arguments[0] << 8) + arguments[1]))
  1.1957 +
  1.1958 +    def swap(self, arguments, program):
  1.1959 +        program.rot_two()
  1.1960 +
  1.1961 +    def tableswitch(self, code, program):
  1.1962 +
  1.1963 +        # Find the offset to the next 4 byte boundary in the code.
  1.1964 +
  1.1965 +        d, r = divmod(self.java_position + 1, 4)
  1.1966 +        to_boundary = (4 - r) % 4
  1.1967 +
  1.1968 +        # Get the pertinent arguments.
  1.1969 +
  1.1970 +        code = code[to_boundary:]
  1.1971 +        default = classfile.s4(code[0:4])
  1.1972 +        low = classfile.s4(code[4:8])
  1.1973 +        high = classfile.s4(code[8:12])
  1.1974 +
  1.1975 +        # Process the jump entries.
  1.1976 +        # NOTE: This is not the most optimal implementation.
  1.1977 +
  1.1978 +        jump_index = 12
  1.1979 +        for jump in range(low, high + 1):
  1.1980 +            offset = classfile.s4(code[jump_index:jump_index + 4])
  1.1981 +
  1.1982 +            # Calculate the branch target.
  1.1983 +
  1.1984 +            java_absolute = self.java_position + offset
  1.1985 +
  1.1986 +            # Generate branching code.
  1.1987 +
  1.1988 +            program.dup_top()                                           # Stack: key, key
  1.1989 +            program.load_const(jump)                                    # Stack: key, key, jump
  1.1990 +            program.compare_op("==")                                    # Stack: key, result
  1.1991 +            program.jump_to_label(0, "end")
  1.1992 +            program.pop_top()                                           # Stack: key
  1.1993 +            program.pop_top()                                           # Stack:
  1.1994 +            program.jump_absolute(self.position_mapping[java_absolute])
  1.1995 +
  1.1996 +            # Generate the label for the end of the branching code.
  1.1997 +
  1.1998 +            program.start_label("end")
  1.1999 +            program.pop_top()                                           # Stack: key
  1.2000 +
  1.2001 +            # Update the index.
  1.2002 +
  1.2003 +            jump_index += 4
  1.2004 +
  1.2005 +        # Generate the default.
  1.2006 +
  1.2007 +        java_absolute = self.java_position + default
  1.2008 +        program.jump_absolute(self.position_mapping[java_absolute])
  1.2009 +        return jump_index + to_boundary
  1.2010 +
  1.2011 +    def wide(self, code, program):
  1.2012 +        # NOTE: To be implemented.
  1.2013 +        raise NotImplementedError, "wide"
  1.2014 +
  1.2015 +def disassemble(class_file, method):
  1.2016 +    disassembler = BytecodeDisassembler(class_file)
  1.2017 +    disassembler.process(method, BytecodeDisassemblerProgram())
  1.2018 +    return disassembler
  1.2019 +
  1.2020 +class ClassTranslator:
  1.2021 +
  1.2022 +    """
  1.2023 +    A class which provides a wrapper around a class file and the means to
  1.2024 +    translate the represented class into a Python class.
  1.2025 +    """
  1.2026 +
  1.2027 +    def __init__(self, class_file):
  1.2028 +
  1.2029 +        "Initialise the object with the given 'class_file'."
  1.2030 +
  1.2031 +        self.class_file = class_file
  1.2032 +        self.filename = ""
  1.2033 +
  1.2034 +        for attribute in self.class_file.attributes:
  1.2035 +            if isinstance(attribute, classfile.SourceFileAttributeInfo):
  1.2036 +                self.filename = str(attribute.get_name())
  1.2037 +
  1.2038 +    def translate_method(self, method):
  1.2039 +
  1.2040 +        "Translate the given 'method' - an object obtained from the class file."
  1.2041 +
  1.2042 +        translator = BytecodeTranslator(self.class_file)
  1.2043 +        writer = BytecodeWriter()
  1.2044 +        try:
  1.2045 +            translator.process(method, writer)
  1.2046 +        except:
  1.2047 +            print "Translation error in", str(self.class_file.this_class.get_name()), str(method.get_name())
  1.2048 +            disassemble(self.class_file, method)
  1.2049 +            raise
  1.2050 +        return translator, writer
  1.2051 +
  1.2052 +    def make_method(self, real_method_name, methods, global_names):
  1.2053 +
  1.2054 +        """
  1.2055 +        Make a dispatcher method with the given 'real_method_name', providing
  1.2056 +        dispatch to the supplied type-sensitive 'methods', accessing the given
  1.2057 +        'global_names' where necessary, and storing the new method in the
  1.2058 +        class's namespace.
  1.2059 +        """
  1.2060 +
  1.2061 +        if real_method_name == "<init>":
  1.2062 +            method_name = "__init__"
  1.2063 +        else:
  1.2064 +            method_name = real_method_name
  1.2065 +
  1.2066 +        # Where only one method exists, just make an alias.
  1.2067 +
  1.2068 +        if len(methods) == 1:
  1.2069 +            method, fn = methods[0]
  1.2070 +            self.namespace[method_name] = fn
  1.2071 +            return
  1.2072 +
  1.2073 +        # Write a simple bytecode dispatching mechanism.
  1.2074 +
  1.2075 +        program = BytecodeWriter()
  1.2076 +
  1.2077 +        # Remember whether any of the methods are static.
  1.2078 +        # NOTE: This should be an all or nothing situation.
  1.2079 +
  1.2080 +        method_is_static = 0
  1.2081 +
  1.2082 +        # NOTE: The code below should use dictionary-based dispatch for better performance.
  1.2083 +
  1.2084 +        for method, fn in methods:
  1.2085 +            method_is_static = real_method_name != "<init>" and method_is_static or \
  1.2086 +                classfile.has_flags(method.access_flags, [classfile.STATIC])
  1.2087 +
  1.2088 +            if method_is_static:
  1.2089 +                program.load_fast(0)                # Stack: arguments
  1.2090 +            else:
  1.2091 +                program.load_fast(1)                # Stack: arguments
  1.2092 +
  1.2093 +            program.setup_loop()
  1.2094 +            program.load_const(1)                   # Stack: arguments, 1
  1.2095 +
  1.2096 +            if method_is_static:
  1.2097 +                program.store_fast(1)               # Stack: arguments (found = 1)
  1.2098 +            else:
  1.2099 +                program.store_fast(2)               # Stack: arguments (found = 1)
  1.2100 +
  1.2101 +            # Emit a list of parameter types.
  1.2102 +
  1.2103 +            descriptor_types = method.get_descriptor()[0]
  1.2104 +            for descriptor_type in descriptor_types:
  1.2105 +                base_type, object_type, array_type = descriptor_type
  1.2106 +                python_type = classfile.descriptor_base_type_mapping[base_type]
  1.2107 +                if python_type == "instance":
  1.2108 +                    # NOTE: This will need extending.
  1.2109 +                    python_type = object_type
  1.2110 +                program.load_global(python_type)    # Stack: arguments, type, ...
  1.2111 +            program.build_list(len(descriptor_types))
  1.2112 +                                                    # Stack: arguments, types
  1.2113 +            # Make a map of arguments and types.
  1.2114 +            program.load_const(None)                # Stack: arguments, types, None
  1.2115 +            program.rot_three()                     # Stack: None, arguments, types
  1.2116 +            program.build_tuple(3)                  # Stack: tuple
  1.2117 +            program.load_global("map")              # Stack: tuple, map
  1.2118 +            program.rot_two()                       # Stack: map, tuple
  1.2119 +            program.call_function_var(0)            # Stack: list (mapping arguments to types)
  1.2120 +            # Loop over each pair.
  1.2121 +            program.get_iter()                      # Stack: iter
  1.2122 +            program.for_iter()                      # Stack: iter, (argument, type)
  1.2123 +            program.unpack_sequence(2)              # Stack: iter, type, argument
  1.2124 +            program.dup_top()                       # Stack: iter, type, argument, argument
  1.2125 +            program.load_const(None)                # Stack: iter, type, argument, argument, None
  1.2126 +            program.compare_op("is")                # Stack: iter, type, argument, result
  1.2127 +            # Missing argument?
  1.2128 +            program.jump_to_label(0, "present")
  1.2129 +            program.pop_top()                       # Stack: iter, type, argument
  1.2130 +            program.pop_top()                       # Stack: iter, type
  1.2131 +            program.pop_top()                       # Stack: iter
  1.2132 +            program.load_const(0)                   # Stack: iter, 0
  1.2133 +
  1.2134 +            if method_is_static:
  1.2135 +                program.store_fast(1)               # Stack: iter (found = 0)
  1.2136 +            else:
  1.2137 +                program.store_fast(2)               # Stack: iter (found = 0)
  1.2138 +
  1.2139 +            program.break_loop()
  1.2140 +            # Argument was present.
  1.2141 +            program.start_label("present")
  1.2142 +            program.pop_top()                       # Stack: iter, type, argument
  1.2143 +            program.rot_two()                       # Stack: iter, argument, type
  1.2144 +            program.dup_top()                       # Stack: iter, argument, type, type
  1.2145 +            program.load_const(None)                # Stack: iter, argument, type, type, None
  1.2146 +            program.compare_op("is")                # Stack: iter, argument, type, result
  1.2147 +            # Missing parameter type?
  1.2148 +            program.jump_to_label(0, "present")
  1.2149 +            program.pop_top()                       # Stack: iter, argument, type
  1.2150 +            program.pop_top()                       # Stack: iter, argument
  1.2151 +            program.pop_top()                       # Stack: iter
  1.2152 +            program.load_const(0)                   # Stack: iter, 0
  1.2153 +
  1.2154 +            if method_is_static:
  1.2155 +                program.store_fast(1)               # Stack: iter (found = 0)
  1.2156 +            else:
  1.2157 +                program.store_fast(2)               # Stack: iter (found = 0)
  1.2158 +
  1.2159 +            program.break_loop()
  1.2160 +            # Parameter was present.
  1.2161 +            program.start_label("present")
  1.2162 +            program.pop_top()                       # Stack: iter, argument, type
  1.2163 +            program.build_tuple(2)                  # Stack: iter, (argument, type)
  1.2164 +            program.load_global("isinstance")       # Stack: iter, (argument, type), isinstance
  1.2165 +            program.rot_two()                       # Stack: iter, isinstance, (argument, type)
  1.2166 +            program.call_function_var(0)            # Stack: iter, result
  1.2167 +            program.jump_to_label(1, "match")
  1.2168 +            program.pop_top()                       # Stack: iter
  1.2169 +            program.load_const(0)                   # Stack: iter, 0
  1.2170 +
  1.2171 +            if method_is_static:
  1.2172 +                program.store_fast(1)               # Stack: iter (found = 0)
  1.2173 +            else:
  1.2174 +                program.store_fast(2)               # Stack: iter (found = 0)
  1.2175 +
  1.2176 +            program.break_loop()
  1.2177 +            # Argument type and parameter type matched.
  1.2178 +            program.start_label("match")
  1.2179 +            program.pop_top()                       # Stack: iter
  1.2180 +            program.end_loop()                      # Stack:
  1.2181 +            # If all the parameters matched, call the method.
  1.2182 +
  1.2183 +            if method_is_static:
  1.2184 +                program.load_fast(1)                # Stack: match
  1.2185 +            else:
  1.2186 +                program.load_fast(2)                # Stack: match
  1.2187 +
  1.2188 +            program.jump_to_label(0, "failed")
  1.2189 +            # All the parameters matched.
  1.2190 +            program.pop_top()                       # Stack:
  1.2191 +
  1.2192 +            if method_is_static:
  1.2193 +                program.load_fast(0)                # Stack: arguments
  1.2194 +                program.load_global(str(self.class_file.this_class.get_python_name()))
  1.2195 +                                                    # Stack: arguments, class
  1.2196 +            else:
  1.2197 +                program.load_fast(1)                # Stack: arguments
  1.2198 +                program.load_fast(0)                # Stack: arguments, self
  1.2199 +
  1.2200 +            program.load_attr(str(method.get_python_name()))
  1.2201 +                                                    # Stack: arguments, method
  1.2202 +            program.rot_two()                       # Stack: method, arguments
  1.2203 +            program.call_function_var(0)            # Stack: result
  1.2204 +            program.return_value()
  1.2205 +            # Try the next method if arguments or parameters were missing or incorrect.
  1.2206 +            program.start_label("failed")
  1.2207 +            program.pop_top()                       # Stack:
  1.2208 +
  1.2209 +        # Raise an exception if nothing matched.
  1.2210 +        # NOTE: Improve this.
  1.2211 +
  1.2212 +        program.load_const("No matching method")
  1.2213 +        program.raise_varargs(1)
  1.2214 +        program.load_const(None)
  1.2215 +        program.return_value()
  1.2216 +
  1.2217 +        # Add the code as a method in the namespace.
  1.2218 +        # NOTE: One actual parameter, flags as 71 apparently means that a list
  1.2219 +        # NOTE: parameter is used in a method.
  1.2220 +
  1.2221 +        if method_is_static:
  1.2222 +            nargs = 0
  1.2223 +        else:
  1.2224 +            nargs = 1
  1.2225 +        nlocals = program.max_locals + 1
  1.2226 +
  1.2227 +        code = new.code(nargs, nlocals, program.max_stack_depth, 71, program.get_output(),
  1.2228 +            tuple(program.get_constants()), tuple(program.get_names()), tuple(self.make_varnames(nlocals, method_is_static)),
  1.2229 +            self.filename, method_name, 0, "")
  1.2230 +        fn = new.function(code, global_names)
  1.2231 +
  1.2232 +        if method_is_static:
  1.2233 +            fn = staticmethod(fn)
  1.2234 +
  1.2235 +        self.namespace[method_name] = fn
  1.2236 +
  1.2237 +    def process(self, global_names):
  1.2238 +
  1.2239 +        """
  1.2240 +        Process the class, storing it in the 'global_names' dictionary provided.
  1.2241 +        Return a list of external names referenced by the class's methods.
  1.2242 +        """
  1.2243 +
  1.2244 +        self.namespace = {}
  1.2245 +
  1.2246 +        # Make the fields.
  1.2247 +
  1.2248 +        for field in self.class_file.fields:
  1.2249 +            if classfile.has_flags(field.access_flags, [classfile.STATIC]):
  1.2250 +                field_name = str(field.get_python_name())
  1.2251 +                self.namespace[field_name] = None
  1.2252 +
  1.2253 +        # Make the methods.
  1.2254 +
  1.2255 +        self.real_methods = {}
  1.2256 +        external_names = []
  1.2257 +
  1.2258 +        for method in self.class_file.methods:
  1.2259 +            real_method_name = str(method.get_name())
  1.2260 +            method_name = str(method.get_python_name())
  1.2261 +            translator, writer = self.translate_method(method)
  1.2262 +
  1.2263 +            # Add external names to the master list.
  1.2264 +
  1.2265 +            for external_name in writer.external_names:
  1.2266 +                if external_name not in external_names:
  1.2267 +                    external_names.append(external_name)
  1.2268 +
  1.2269 +            # Fix up special class initialisation methods and static methods.
  1.2270 +
  1.2271 +            method_is_static = real_method_name != "<init>" and classfile.has_flags(method.access_flags, [classfile.STATIC])
  1.2272 +            if method_is_static:
  1.2273 +                nargs = len(method.get_descriptor()[0])
  1.2274 +            else:
  1.2275 +                nargs = len(method.get_descriptor()[0]) + 1
  1.2276 +            nlocals = writer.max_locals + 1
  1.2277 +            flags = 67
  1.2278 +
  1.2279 +            # NOTE: Add line number table later.
  1.2280 +
  1.2281 +            code = new.code(nargs, nlocals, writer.max_stack_depth, flags, writer.get_output(),
  1.2282 +                tuple(writer.get_constants()), tuple(writer.get_names()),
  1.2283 +                tuple(self.make_varnames(nlocals, method_is_static)), self.filename, method_name, 0, "")
  1.2284 +
  1.2285 +            # NOTE: May need more globals.
  1.2286 +
  1.2287 +            fn = new.function(code, global_names)
  1.2288 +
  1.2289 +            # Fix up special class initialisation methods and static methods.
  1.2290 +
  1.2291 +            if method_is_static:
  1.2292 +                fn = staticmethod(fn)
  1.2293 +
  1.2294 +            # Remember the real method name and the corresponding methods produced.
  1.2295 +
  1.2296 +            if not self.real_methods.has_key(real_method_name):
  1.2297 +                self.real_methods[real_method_name] = []
  1.2298 +            self.real_methods[real_method_name].append((method, fn))
  1.2299 +
  1.2300 +            # Add the method to the class's namespace.
  1.2301 +
  1.2302 +            self.namespace[method_name] = fn
  1.2303 +
  1.2304 +        # Add the super class as an external name, if appropriate.
  1.2305 +
  1.2306 +        if self.class_file.super_class is not None:
  1.2307 +            external_names.append(self.class_file.super_class.get_python_name())
  1.2308 +
  1.2309 +        return external_names
  1.2310 +
  1.2311 +    def get_class(self, global_names):
  1.2312 +
  1.2313 +        """
  1.2314 +        Get the Python class representing the underlying Java class, using the
  1.2315 +        given 'global_names' to define dispatcher methods.
  1.2316 +        """
  1.2317 +
  1.2318 +        # Define superclasses.
  1.2319 +
  1.2320 +        bases = self.get_base_classes(global_names)
  1.2321 +
  1.2322 +        # Define method dispatchers.
  1.2323 +
  1.2324 +        for real_method_name, methods in self.real_methods.items():
  1.2325 +            if real_method_name != "<clinit>":
  1.2326 +                self.make_method(real_method_name, methods, global_names)
  1.2327 +
  1.2328 +        # Use only the last part of the fully qualified name.
  1.2329 +
  1.2330 +        full_class_name = str(self.class_file.this_class.get_python_name())
  1.2331 +        class_name = full_class_name.split(".")[-1]
  1.2332 +        cls = new.classobj(class_name, bases, self.namespace)
  1.2333 +        global_names[cls.__name__] = cls
  1.2334 +
  1.2335 +        return cls
  1.2336 +
  1.2337 +    def get_base_class_references(self):
  1.2338 +        class_names = []
  1.2339 +        if self.class_file.super_class is not None:
  1.2340 +            class_names.append(self.class_file.super_class)
  1.2341 +        # NOTE: This prevents an MRO error, but may prevent proper functioning.
  1.2342 +        #class_names += self.class_file.interfaces
  1.2343 +        return class_names
  1.2344 +
  1.2345 +    def get_base_classes(self, global_names):
  1.2346 +
  1.2347 +        """
  1.2348 +        Identify the superclass, then either load it from the given
  1.2349 +        'global_names' if available, or import the class from its parent module.
  1.2350 +        Return a tuple containing all base classes (typically a single element
  1.2351 +        tuple).
  1.2352 +        """
  1.2353 +
  1.2354 +        base_classes = []
  1.2355 +
  1.2356 +        for class_ in self.get_base_class_references():
  1.2357 +            base_classes.append(self._get_class(class_, global_names))
  1.2358 +
  1.2359 +        return tuple(base_classes)
  1.2360 +
  1.2361 +    def _get_class(self, class_, global_names):
  1.2362 +        class_name = class_.get_python_name()
  1.2363 +        class_name_parts = class_name.split(".")
  1.2364 +        obj = global_names
  1.2365 +        for class_name_part in class_name_parts[:-1]:
  1.2366 +            try:
  1.2367 +                obj = obj[class_name_part].__dict__
  1.2368 +            except KeyError:
  1.2369 +                raise AttributeError, "Cannot find '%s' when referencing Java class '%s'" % (
  1.2370 +                    class_name_part, class_name)
  1.2371 +        return obj[class_name_parts[-1]]
  1.2372 +
  1.2373 +    def make_varnames(self, nlocals, method_is_static=0):
  1.2374 +
  1.2375 +        """
  1.2376 +        A utility method which invents variable names for the given number -
  1.2377 +        'nlocals' - of local variables in a method. Returns a list of such
  1.2378 +        variable names.
  1.2379 +
  1.2380 +        If the optional 'method_is_static' is set to true, do not use "self" as
  1.2381 +        the first argument name.
  1.2382 +        """
  1.2383 +
  1.2384 +        if method_is_static:
  1.2385 +            l = ["cls"]
  1.2386 +        else:
  1.2387 +            l = ["self"]
  1.2388 +        for i in range(1, nlocals):
  1.2389 +            l.append("_l%s" % i)
  1.2390 +        return l[:nlocals]
  1.2391 +
  1.2392 +# Test functions, useful for tracing generated bytecode operations.
  1.2393 +
  1.2394 +def _map(*args):
  1.2395 +    print args
  1.2396 +    return apply(__builtins__.map, args)
  1.2397 +
  1.2398 +def _isinstance(*args):
  1.2399 +    print args
  1.2400 +    return apply(__builtins__.isinstance, args)
  1.2401 +
  1.2402 +if __name__ == "__main__":
  1.2403 +    import sys
  1.2404 +    import dis
  1.2405 +    import java.lang
  1.2406 +    global_names = globals()
  1.2407 +    #global_names["isinstance"] = _isinstance
  1.2408 +    #global_names["map"] = _map
  1.2409 +    for filename in sys.argv[1:]:
  1.2410 +        f = open(filename, "rb")
  1.2411 +        c = classfile.ClassFile(f.read())
  1.2412 +        translator = ClassTranslator(c)
  1.2413 +        external_names = translator.process(global_names)
  1.2414 +        cls = translator.get_class(global_names)
  1.2415 +
  1.2416 +# vim: tabstop=4 expandtab shiftwidth=4