javaclass

Changeset

137:182cba61327c
2005-01-21 Paul Boddie raw files shortlog changelog graph Moved the modules into the javaclass package.
javaclass/__init__.py (file) javaclass/bytecode.py (file) javaclass/classfile.py (file) javaclass/classhook.py (file)
     2.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     2.2 +++ b/javaclass/bytecode.py	Fri Jan 21 17:05:06 2005 +0100
     2.3 @@ -0,0 +1,2311 @@
     2.4 +#!/usr/bin/env python
     2.5 +
     2.6 +"""
     2.7 +Java bytecode conversion. Specification found at the following URL:
     2.8 +http://java.sun.com/docs/books/vmspec/2nd-edition/html/Instructions2.doc.html
     2.9 +
    2.10 +NOTE: Synchronized constructs are not actually supported.
    2.11 +"""
    2.12 +
    2.13 +import classfile
    2.14 +from dis import cmp_op # for access to Python bytecode values and operators
    2.15 +try:
    2.16 +    from dis import opmap
    2.17 +except ImportError:
    2.18 +    from dis import opname
    2.19 +    opmap = {}
    2.20 +    for i in range(0, len(opname)):
    2.21 +        opmap[opname[i]] = i
    2.22 +from UserDict import UserDict
    2.23 +import new
    2.24 +
    2.25 +# Bytecode production classes.
    2.26 +
    2.27 +class BytecodeWriter:
    2.28 +
    2.29 +    "A Python bytecode writer."
    2.30 +
    2.31 +    def __init__(self):
    2.32 +
    2.33 +        "Initialise the writer."
    2.34 +
    2.35 +        # A stack of loop start instructions corresponding to loop blocks.
    2.36 +        self.loops = []
    2.37 +
    2.38 +        # A stack of loop block or exception block start positions.
    2.39 +        self.blocks = []
    2.40 +
    2.41 +        # A stack of exception block handler pointers.
    2.42 +        self.exception_handlers = []
    2.43 +
    2.44 +        # A dictionary mapping labels to jump instructions referencing such labels.
    2.45 +        self.jumps = {}
    2.46 +
    2.47 +        # The output values, including "lazy" subvalues which will need evaluating.
    2.48 +        self.output = []
    2.49 +
    2.50 +        # The current Python bytecode instruction position.
    2.51 +        self.position = 0
    2.52 +
    2.53 +        # Stack depth estimation.
    2.54 +        self.stack_depth = 0
    2.55 +        self.max_stack_depth = 0
    2.56 +
    2.57 +        # Local variable estimation.
    2.58 +        self.max_locals = 0
    2.59 +
    2.60 +        # Mapping from values to indexes.
    2.61 +        self.constants = {}
    2.62 +
    2.63 +        # Mapping from names to indexes.
    2.64 +        # NOTE: This may be acquired from elsewhere.
    2.65 +        #self.globals = {}
    2.66 +
    2.67 +        # Mapping from names to indexes.
    2.68 +        self.names = {}
    2.69 +
    2.70 +        # A list of constants used as exception handler return addresses.
    2.71 +        self.constants_for_exceptions = []
    2.72 +
    2.73 +        # A list of external names.
    2.74 +        self.external_names = []
    2.75 +
    2.76 +    def get_output(self):
    2.77 +
    2.78 +        "Return the output of the writer as a string."
    2.79 +
    2.80 +        output = []
    2.81 +        for element in self.output:
    2.82 +            if isinstance(element, LazySubValue):
    2.83 +                value = element.value
    2.84 +            else:
    2.85 +                value = element
    2.86 +            # NOTE: ValueError gets raised for bad values here.
    2.87 +            output.append(chr(value))
    2.88 +        return "".join(output)
    2.89 +
    2.90 +    def get_constants(self):
    2.91 +
    2.92 +        """
    2.93 +        Return a list of constants with ordering significant to the code
    2.94 +        employing them.
    2.95 +        """
    2.96 +
    2.97 +        l = self._get_list(self._invert(self.constants))
    2.98 +        result = []
    2.99 +        for i in l:
   2.100 +            if isinstance(i, LazyValue):
   2.101 +                result.append(i.get_value())
   2.102 +            else:
   2.103 +                result.append(i)
   2.104 +        return result
   2.105 +
   2.106 +    #def get_globals(self):
   2.107 +    #    return self._get_list(self._invert(self.globals))
   2.108 +
   2.109 +    def get_names(self):
   2.110 +
   2.111 +        """
   2.112 +        Return a list of names with ordering significant to the code employing
   2.113 +        them.
   2.114 +        """
   2.115 +
   2.116 +        return self._get_list(self._invert(self.names))
   2.117 +
   2.118 +    def _invert(self, d):
   2.119 +
   2.120 +        """
   2.121 +        Return a new dictionary whose key-to-value mapping is in the inverse of
   2.122 +        that found in 'd'.
   2.123 +        """
   2.124 +
   2.125 +        inverted = {}
   2.126 +        for k, v in d.items():
   2.127 +            inverted[v] = k
   2.128 +        return inverted
   2.129 +
   2.130 +    def _get_list(self, d):
   2.131 +
   2.132 +        """
   2.133 +        Traverse the dictionary 'd' returning a list whose values appear at the
   2.134 +        position denoted by each value's key in 'd'.
   2.135 +        """
   2.136 +
   2.137 +        l = []
   2.138 +        for i in range(0, len(d.keys())):
   2.139 +            l.append(d[i])
   2.140 +        return l
   2.141 +
   2.142 +    # Administrative methods.
   2.143 +
   2.144 +    def update_stack_depth(self, change):
   2.145 +
   2.146 +        """
   2.147 +        Given the stated 'change' in stack depth, update the maximum stack depth
   2.148 +        where appropriate.
   2.149 +        """
   2.150 +
   2.151 +        self.stack_depth += change
   2.152 +        if self.stack_depth > self.max_stack_depth:
   2.153 +            self.max_stack_depth = self.stack_depth
   2.154 +
   2.155 +    def update_locals(self, index):
   2.156 +
   2.157 +        """
   2.158 +        Given the stated 'index' of a local variable, update the maximum local
   2.159 +        variable index where appropriate.
   2.160 +        """
   2.161 +
   2.162 +        if index > self.max_locals:
   2.163 +            self.max_locals = index
   2.164 +
   2.165 +    # Special methods.
   2.166 +
   2.167 +    def _write_value(self, value):
   2.168 +
   2.169 +        """
   2.170 +        Write the given 'value' at the current output position.
   2.171 +        """
   2.172 +
   2.173 +        if isinstance(value, LazyValue):
   2.174 +            # NOTE: Assume a 16-bit value.
   2.175 +            self.output.append(value.values[0])
   2.176 +            self.output.append(value.values[1])
   2.177 +            self.position += 2
   2.178 +        elif value <= 0xffff:
   2.179 +            self.output.append(value & 0xff)
   2.180 +            self.output.append((value & 0xff00) >> 8)
   2.181 +            self.position += 2
   2.182 +        else:
   2.183 +            # NOTE: EXTENDED_ARG not yet supported.
   2.184 +            raise ValueError, value
   2.185 +
   2.186 +    def _rewrite_value(self, position, value):
   2.187 +
   2.188 +        """
   2.189 +        At the given output 'position', rewrite the given 'value'.
   2.190 +        """
   2.191 +
   2.192 +        # NOTE: Assume a 16-bit value.
   2.193 +        if value <= 0xffff:
   2.194 +            self.output[position] = (value & 0xff)
   2.195 +            self.output[position + 1] = ((value & 0xff00) >> 8)
   2.196 +        else:
   2.197 +            # NOTE: EXTENDED_ARG not yet supported.
   2.198 +            raise ValueError, value
   2.199 +
   2.200 +    # Higher level methods.
   2.201 +
   2.202 +    def use_external_name(self, name):
   2.203 +        # NOTE: Remove array and object indicators.
   2.204 +        self.external_names.append(name)
   2.205 +
   2.206 +    def setup_loop(self):
   2.207 +        self.loops.append(self.position)
   2.208 +        self.output.append(opmap["SETUP_LOOP"])
   2.209 +        self.position += 1
   2.210 +        self._write_value(0) # To be filled in later
   2.211 +
   2.212 +    def end_loop(self):
   2.213 +        current_loop_start = self.loops.pop()
   2.214 +        current_loop_real_start = self.blocks.pop()
   2.215 +        #print "<", self.blocks, current_loop_real_start
   2.216 +        # Fix the iterator delta.
   2.217 +        # NOTE: Using 3 as the assumed length of the FOR_ITER instruction.
   2.218 +        self.jump_absolute(current_loop_real_start)
   2.219 +        self._rewrite_value(current_loop_real_start + 1, self.position - current_loop_real_start - 3)
   2.220 +        self.pop_block()
   2.221 +        # Fix the loop delta.
   2.222 +        # NOTE: Using 3 as the assumed length of the SETUP_LOOP instruction.
   2.223 +        self._rewrite_value(current_loop_start + 1, self.position - current_loop_start - 3)
   2.224 +
   2.225 +    def jump_to_label(self, status, name):
   2.226 +        # Record the instruction using the jump.
   2.227 +        jump_instruction = self.position
   2.228 +        if status is None:
   2.229 +            self.jump_forward()
   2.230 +        elif status:
   2.231 +            self.jump_if_true()
   2.232 +        else:
   2.233 +            self.jump_if_false()
   2.234 +        # Record the following instruction, too.
   2.235 +        if not self.jumps.has_key(name):
   2.236 +            self.jumps[name] = []
   2.237 +        self.jumps[name].append((jump_instruction, self.position))
   2.238 +
   2.239 +    def start_label(self, name):
   2.240 +        # Fill in all jump instructions.
   2.241 +        for jump_instruction, following_instruction in self.jumps[name]:
   2.242 +            self._rewrite_value(jump_instruction + 1, self.position - following_instruction)
   2.243 +        del self.jumps[name]
   2.244 +
   2.245 +    def load_const_ret(self, value):
   2.246 +        self.constants_for_exceptions.append(value)
   2.247 +        self.load_const(value)
   2.248 +
   2.249 +    def ret(self, index):
   2.250 +        self.load_fast(index)
   2.251 +
   2.252 +        # Previously, the constant stored on the stack by jsr/jsr_w was stored
   2.253 +        # in a local variable. In the JVM, extracting the value from the local
   2.254 +        # variable and jumping can be done at runtime. In the Python VM, any
   2.255 +        # jump target must be known in advance and written into the bytecode.
   2.256 +
   2.257 +        for constant in self.constants_for_exceptions:
   2.258 +            self.dup_top()              # Stack: actual-address, actual-address
   2.259 +            self.load_const(constant)   # Stack: actual-address, actual-address, suggested-address
   2.260 +            self.compare_op("==")       # Stack: actual-address, result
   2.261 +            self.jump_to_label(0, "const")
   2.262 +            self.pop_top()              # Stack: actual-address
   2.263 +            self.pop_top()              # Stack:
   2.264 +            self.jump_absolute(constant)
   2.265 +            self.start_label("const")
   2.266 +            self.pop_top()              # Stack: actual-address
   2.267 +
   2.268 +        # NOTE: If we get here, something is really wrong.
   2.269 +
   2.270 +        self.pop_top()              # Stack:
   2.271 +
   2.272 +    def setup_except(self, target):
   2.273 +        self.blocks.append(self.position)
   2.274 +        self.exception_handlers.append(target)
   2.275 +        #print "-", self.position, target
   2.276 +        self.output.append(opmap["SETUP_EXCEPT"])
   2.277 +        self.position += 1
   2.278 +        self._write_value(0) # To be filled in later
   2.279 +
   2.280 +    def setup_finally(self, target):
   2.281 +        self.blocks.append(self.position)
   2.282 +        self.exception_handlers.append(target)
   2.283 +        #print "-", self.position, target
   2.284 +        self.output.append(opmap["SETUP_FINALLY"])
   2.285 +        self.position += 1
   2.286 +        self._write_value(0) # To be filled in later
   2.287 +
   2.288 +    def end_exception(self):
   2.289 +        current_exception_start = self.blocks.pop()
   2.290 +        # Convert the "lazy" absolute value.
   2.291 +        current_exception_target = self.exception_handlers.pop()
   2.292 +        target = current_exception_target.get_value()
   2.293 +        #print "*", current_exception_start, target
   2.294 +        # NOTE: Using 3 as the assumed length of the SETUP_* instruction.
   2.295 +        self._rewrite_value(current_exception_start + 1, target - current_exception_start - 3)
   2.296 +
   2.297 +    def start_handler(self, exc_name, class_file):
   2.298 +
   2.299 +        # Where handlers are begun, produce bytecode to test the type of
   2.300 +        # the exception.
   2.301 +        # NOTE: Since RAISE_VARARGS and END_FINALLY are not really documented,
   2.302 +        # NOTE: we store the top of the stack and use it later to trigger the
   2.303 +        # NOTE: magic processes when re-raising.
   2.304 +        self.use_external_name(str(exc_name))
   2.305 +
   2.306 +        self.rot_two()                      # Stack: raised-exception, exception
   2.307 +        self.dup_top()                      # Stack: raised-exception, exception, exception
   2.308 +        # Handled exceptions are wrapped before being thrown.
   2.309 +        self.load_global("Exception")       # Stack: raised-exception, exception, exception, Exception
   2.310 +        self.compare_op("exception match")  # Stack: raised-exception, exception, result
   2.311 +        self.jump_to_label(0, "next")
   2.312 +        self.pop_top()                      # Stack: raised-exception, exception
   2.313 +        self.dup_top()                      # Stack: raised-exception, exception, exception
   2.314 +        self.load_attr("args")              # Stack: raised-exception, exception, args
   2.315 +        self.load_const(0)                  # Stack: raised-exception, exception, args, 0
   2.316 +        self.binary_subscr()                # Stack: raised-exception, exception, exception-object
   2.317 +        load_class_name(class_file, str(exc_name), self)
   2.318 +                                            # Stack: raised-exception, exception, exception-object, handled-exception
   2.319 +        self.load_global("isinstance")      # Stack: raised-exception, exception, exception-object, handled-exception, isinstance
   2.320 +        self.rot_three()                    # Stack: raised-exception, exception, isinstance, exception-object, handled-exception
   2.321 +        self.call_function(2)               # Stack: raised-exception, exception, result
   2.322 +        self.jump_to_label(1, "handler")
   2.323 +        self.start_label("next")
   2.324 +        self.pop_top()                      # Stack: raised-exception, exception
   2.325 +        self.rot_two()                      # Stack: exception, raised-exception
   2.326 +        self.end_finally()
   2.327 +        self.start_label("handler")
   2.328 +        self.pop_top()                      # Stack: raised-exception, exception
   2.329 +
   2.330 +    # Complicated methods.
   2.331 +
   2.332 +    def load_const(self, value):
   2.333 +        self.output.append(opmap["LOAD_CONST"])
   2.334 +        if not self.constants.has_key(value):
   2.335 +            self.constants[value] = len(self.constants.keys())
   2.336 +        self.position += 1
   2.337 +        self._write_value(self.constants[value])
   2.338 +        self.update_stack_depth(1)
   2.339 +
   2.340 +    def load_global(self, name):
   2.341 +        self.output.append(opmap["LOAD_GLOBAL"])
   2.342 +        if not self.names.has_key(name):
   2.343 +            self.names[name] = len(self.names.keys())
   2.344 +        self.position += 1
   2.345 +        self._write_value(self.names[name])
   2.346 +        self.update_stack_depth(1)
   2.347 +
   2.348 +    def load_attr(self, name):
   2.349 +        self.output.append(opmap["LOAD_ATTR"])
   2.350 +        if not self.names.has_key(name):
   2.351 +            self.names[name] = len(self.names.keys())
   2.352 +        self.position += 1
   2.353 +        self._write_value(self.names[name])
   2.354 +
   2.355 +    def load_name(self, name):
   2.356 +        self.output.append(opmap["LOAD_NAME"])
   2.357 +        if not self.names.has_key(name):
   2.358 +            self.names[name] = len(self.names.keys())
   2.359 +        self.position += 1
   2.360 +        self._write_value(self.names[name])
   2.361 +        self.update_stack_depth(1)
   2.362 +
   2.363 +    def load_fast(self, index):
   2.364 +        self.output.append(opmap["LOAD_FAST"])
   2.365 +        self.position += 1
   2.366 +        self._write_value(index)
   2.367 +        self.update_stack_depth(1)
   2.368 +        self.update_locals(index)
   2.369 +
   2.370 +    def store_attr(self, name):
   2.371 +        self.output.append(opmap["STORE_ATTR"])
   2.372 +        if not self.names.has_key(name):
   2.373 +            self.names[name] = len(self.names.keys())
   2.374 +        self.position += 1
   2.375 +        self._write_value(self.names[name])
   2.376 +        self.update_stack_depth(-1)
   2.377 +
   2.378 +    def store_fast(self, index):
   2.379 +        self.output.append(opmap["STORE_FAST"])
   2.380 +        self.position += 1
   2.381 +        self._write_value(index)
   2.382 +        self.update_stack_depth(-1)
   2.383 +        self.update_locals(index)
   2.384 +
   2.385 +    def for_iter(self):
   2.386 +        self.blocks.append(self.position)
   2.387 +        #print ">", self.blocks
   2.388 +        self.output.append(opmap["FOR_ITER"])
   2.389 +        self.position += 1
   2.390 +        self._write_value(0) # To be filled in later
   2.391 +        self.update_stack_depth(1)
   2.392 +
   2.393 +    def break_loop(self):
   2.394 +        self.output.append(opmap["BREAK_LOOP"])
   2.395 +        self.position += 1
   2.396 +        self.jump_absolute(self.blocks[-1])
   2.397 +
   2.398 +    # Normal bytecode generators.
   2.399 +
   2.400 +    def get_iter(self):
   2.401 +        self.output.append(opmap["GET_ITER"])
   2.402 +        self.position += 1
   2.403 +
   2.404 +    def jump_if_false(self, offset=0):
   2.405 +        self.output.append(opmap["JUMP_IF_FALSE"])
   2.406 +        self.position += 1
   2.407 +        self._write_value(offset) # May be filled in later
   2.408 +
   2.409 +    def jump_if_true(self, offset=0):
   2.410 +        self.output.append(opmap["JUMP_IF_TRUE"])
   2.411 +        self.position += 1
   2.412 +        self._write_value(offset) # May be filled in later
   2.413 +
   2.414 +    def jump_forward(self, offset=0):
   2.415 +        self.output.append(opmap["JUMP_FORWARD"])
   2.416 +        self.position += 1
   2.417 +        self._write_value(offset) # May be filled in later
   2.418 +
   2.419 +    def jump_absolute(self, address=0):
   2.420 +        self.output.append(opmap["JUMP_ABSOLUTE"])
   2.421 +        self.position += 1
   2.422 +        self._write_value(address) # May be filled in later
   2.423 +
   2.424 +    def build_tuple(self, count):
   2.425 +        self.output.append(opmap["BUILD_TUPLE"])
   2.426 +        self.position += 1
   2.427 +        self._write_value(count)
   2.428 +        self.update_stack_depth(-(count - 1))
   2.429 +
   2.430 +    def build_list(self, count):
   2.431 +        self.output.append(opmap["BUILD_LIST"])
   2.432 +        self.position += 1
   2.433 +        self._write_value(count)
   2.434 +        self.update_stack_depth(-(count - 1))
   2.435 +
   2.436 +    def pop_top(self):
   2.437 +        self.output.append(opmap["POP_TOP"])
   2.438 +        self.position += 1
   2.439 +        self.update_stack_depth(-1)
   2.440 +
   2.441 +    def dup_top(self):
   2.442 +        self.output.append(opmap["DUP_TOP"])
   2.443 +        self.position += 1
   2.444 +        self.update_stack_depth(1)
   2.445 +
   2.446 +    def dup_topx(self, count):
   2.447 +        self.output.append(opmap["DUP_TOPX"])
   2.448 +        self.position += 1
   2.449 +        self._write_value(count)
   2.450 +        self.update_stack_depth(count)
   2.451 +
   2.452 +    def rot_two(self):
   2.453 +        self.output.append(opmap["ROT_TWO"])
   2.454 +        self.position += 1
   2.455 +
   2.456 +    def rot_three(self):
   2.457 +        self.output.append(opmap["ROT_THREE"])
   2.458 +        self.position += 1
   2.459 +
   2.460 +    def rot_four(self):
   2.461 +        self.output.append(opmap["ROT_FOUR"])
   2.462 +        self.position += 1
   2.463 +
   2.464 +    def call_function(self, count):
   2.465 +        self.output.append(opmap["CALL_FUNCTION"])
   2.466 +        self.position += 1
   2.467 +        self._write_value(count)
   2.468 +        self.update_stack_depth(-count)
   2.469 +
   2.470 +    def call_function_var(self, count):
   2.471 +        self.output.append(opmap["CALL_FUNCTION_VAR"])
   2.472 +        self.position += 1
   2.473 +        self._write_value(count)
   2.474 +        self.update_stack_depth(-count-1)
   2.475 +
   2.476 +    def binary_subscr(self):
   2.477 +        self.output.append(opmap["BINARY_SUBSCR"])
   2.478 +        self.position += 1
   2.479 +        self.update_stack_depth(-1)
   2.480 +
   2.481 +    def binary_add(self):
   2.482 +        self.output.append(opmap["BINARY_ADD"])
   2.483 +        self.position += 1
   2.484 +        self.update_stack_depth(-1)
   2.485 +
   2.486 +    def binary_divide(self):
   2.487 +        self.output.append(opmap["BINARY_DIVIDE"])
   2.488 +        self.position += 1
   2.489 +        self.update_stack_depth(-1)
   2.490 +
   2.491 +    def binary_multiply(self):
   2.492 +        self.output.append(opmap["BINARY_MULTIPLY"])
   2.493 +        self.position += 1
   2.494 +        self.update_stack_depth(-1)
   2.495 +
   2.496 +    def binary_modulo(self):
   2.497 +        self.output.append(opmap["BINARY_MODULO"])
   2.498 +        self.position += 1
   2.499 +        self.update_stack_depth(-1)
   2.500 +
   2.501 +    def binary_subtract(self):
   2.502 +        self.output.append(opmap["BINARY_SUBTRACT"])
   2.503 +        self.position += 1
   2.504 +        self.update_stack_depth(-1)
   2.505 +
   2.506 +    def binary_and(self):
   2.507 +        self.output.append(opmap["BINARY_AND"])
   2.508 +        self.position += 1
   2.509 +        self.update_stack_depth(-1)
   2.510 +
   2.511 +    def binary_or(self):
   2.512 +        self.output.append(opmap["BINARY_XOR"])
   2.513 +        self.position += 1
   2.514 +        self.update_stack_depth(-1)
   2.515 +
   2.516 +    def binary_lshift(self):
   2.517 +        self.output.append(opmap["BINARY_LSHIFT"])
   2.518 +        self.position += 1
   2.519 +        self.update_stack_depth(-1)
   2.520 +
   2.521 +    def binary_rshift(self):
   2.522 +        self.output.append(opmap["BINARY_RSHIFT"])
   2.523 +        self.position += 1
   2.524 +        self.update_stack_depth(-1)
   2.525 +
   2.526 +    def binary_xor(self):
   2.527 +        self.output.append(opmap["BINARY_XOR"])
   2.528 +        self.position += 1
   2.529 +        self.update_stack_depth(-1)
   2.530 +
   2.531 +    def store_subscr(self):
   2.532 +        self.output.append(opmap["STORE_SUBSCR"])
   2.533 +        self.position += 1
   2.534 +        self.update_stack_depth(-3)
   2.535 +
   2.536 +    def unary_negative(self):
   2.537 +        self.output.append(opmap["UNARY_NEGATIVE"])
   2.538 +        self.position += 1
   2.539 +
   2.540 +    def slice_0(self):
   2.541 +        self.output.append(opmap["SLICE+0"])
   2.542 +        self.position += 1
   2.543 +
   2.544 +    def slice_1(self):
   2.545 +        self.output.append(opmap["SLICE+1"])
   2.546 +        self.position += 1
   2.547 +
   2.548 +    def compare_op(self, op):
   2.549 +        self.output.append(opmap["COMPARE_OP"])
   2.550 +        self.position += 1
   2.551 +        self._write_value(list(cmp_op).index(op))
   2.552 +        self.update_stack_depth(-1)
   2.553 +
   2.554 +    def return_value(self):
   2.555 +        self.output.append(opmap["RETURN_VALUE"])
   2.556 +        self.position += 1
   2.557 +        self.update_stack_depth(-1)
   2.558 +
   2.559 +    def raise_varargs(self, count):
   2.560 +        self.output.append(opmap["RAISE_VARARGS"])
   2.561 +        self.position += 1
   2.562 +        self._write_value(count)
   2.563 +
   2.564 +    def pop_block(self):
   2.565 +        self.output.append(opmap["POP_BLOCK"])
   2.566 +        self.position += 1
   2.567 +
   2.568 +    def end_finally(self):
   2.569 +        self.output.append(opmap["END_FINALLY"])
   2.570 +        self.position += 1
   2.571 +
   2.572 +    def unpack_sequence(self, count):
   2.573 +        self.output.append(opmap["UNPACK_SEQUENCE"])
   2.574 +        self.position += 1
   2.575 +        self._write_value(count)
   2.576 +
   2.577 +    # Debugging.
   2.578 +
   2.579 +    def print_item(self):
   2.580 +        self.output.append(opmap["PRINT_ITEM"])
   2.581 +        self.position += 1
   2.582 +
   2.583 +# Utility classes and functions.
   2.584 +
   2.585 +class LazyDict(UserDict):
   2.586 +    def __getitem__(self, key):
   2.587 +        if not self.data.has_key(key):
   2.588 +            # NOTE: Assume 16-bit value.
   2.589 +            self.data[key] = LazyValue(2)
   2.590 +        return self.data[key]
   2.591 +    def __setitem__(self, key, value):
   2.592 +        if self.data.has_key(key):
   2.593 +            existing_value = self.data[key]
   2.594 +            if isinstance(existing_value, LazyValue):
   2.595 +                existing_value.set_value(value)
   2.596 +                return
   2.597 +        self.data[key] = value
   2.598 +
   2.599 +class LazyValue:
   2.600 +    def __init__(self, nvalues):
   2.601 +        self.values = []
   2.602 +        for i in range(0, nvalues):
   2.603 +            self.values.append(LazySubValue())
   2.604 +    def set_value(self, value):
   2.605 +        # NOTE: Assume at least 16-bit value. No "filling" performed.
   2.606 +        if value <= 0xffff:
   2.607 +            self.values[0].set_value(value & 0xff)
   2.608 +            self.values[1].set_value((value & 0xff00) >> 8)
   2.609 +        else:
   2.610 +            # NOTE: EXTENDED_ARG not yet supported.
   2.611 +            raise ValueError, value
   2.612 +    def get_value(self):
   2.613 +        value = 0
   2.614 +        values = self.values[:]
   2.615 +        for i in range(0, len(values)):
   2.616 +            value = (value << 8) + values.pop().value
   2.617 +        return value
   2.618 +
   2.619 +class LazySubValue:
   2.620 +    def __init__(self):
   2.621 +        self.value = 0
   2.622 +    def set_value(self, value):
   2.623 +        self.value = value
   2.624 +
   2.625 +def signed(value, limit):
   2.626 +
   2.627 +    """
   2.628 +    Return the signed integer from the unsigned 'value', where 'limit' (a value
   2.629 +    one greater than the highest possible positive integer) is used to determine
   2.630 +    whether a negative or positive result is produced.
   2.631 +    """
   2.632 +
   2.633 +    d, r = divmod(value, limit)
   2.634 +    if d == 1:
   2.635 +        mask = limit * 2 - 1
   2.636 +        return -1 - (value ^ mask)
   2.637 +    else:
   2.638 +        return value
   2.639 +
   2.640 +def signed1(value):
   2.641 +    return signed(value, 0x80)
   2.642 +
   2.643 +def signed2(value):
   2.644 +    return signed(value, 0x8000)
   2.645 +
   2.646 +def signed4(value):
   2.647 +    return signed(value, 0x80000000)
   2.648 +
   2.649 +def load_class_name(class_file, full_class_name, program):
   2.650 +    this_class_name = str(class_file.this_class.get_python_name())
   2.651 +    this_class_parts = this_class_name.split(".")
   2.652 +    class_parts = full_class_name.split(".")
   2.653 +
   2.654 +    # Only use the full path if different from this class's path.
   2.655 +
   2.656 +    if class_parts[:-1] != this_class_parts[:-1]:
   2.657 +        program.use_external_name(full_class_name)
   2.658 +        program.load_global(class_parts[0])
   2.659 +        for class_part in class_parts[1:]:
   2.660 +            program.load_attr(class_part)   # Stack: classref
   2.661 +    else:
   2.662 +        program.load_global(class_parts[-1])
   2.663 +
   2.664 +# Bytecode conversion.
   2.665 +
   2.666 +class BytecodeReader:
   2.667 +
   2.668 +    "A generic Java bytecode reader."
   2.669 +
   2.670 +    def __init__(self, class_file):
   2.671 +
   2.672 +        """
   2.673 +        Initialise the reader with a 'class_file' containing essential
   2.674 +        information for any bytecode inspection activity.
   2.675 +        """
   2.676 +
   2.677 +        self.class_file = class_file
   2.678 +        self.position_mapping = LazyDict()
   2.679 +
   2.680 +    def process(self, method, program):
   2.681 +
   2.682 +        """
   2.683 +        Process the given 'method' (obtained from the class file), using the
   2.684 +        given 'program' to write translated Python bytecode instructions.
   2.685 +        """
   2.686 +
   2.687 +        self.java_position = 0
   2.688 +        self.in_finally = 0
   2.689 +        self.method = method
   2.690 +
   2.691 +        # NOTE: Potentially unreliable way of getting necessary information.
   2.692 +
   2.693 +        code, exception_table = None, None
   2.694 +        for attribute in method.attributes:
   2.695 +            if isinstance(attribute, classfile.CodeAttributeInfo):
   2.696 +                code, exception_table = attribute.code, attribute.exception_table
   2.697 +                break
   2.698 +
   2.699 +        # Where no code was found, write a very simple placeholder routine.
   2.700 +        # This is useful for interfaces and abstract classes.
   2.701 +        # NOTE: Assess the correctness of doing this. An exception should really
   2.702 +        # NOTE: be raised instead.
   2.703 +
   2.704 +        if code is None:
   2.705 +            program.load_const(None)
   2.706 +            program.return_value()
   2.707 +            return
   2.708 +
   2.709 +        # Produce a structure which permits fast access to exception details.
   2.710 +
   2.711 +        exception_block_start = {}
   2.712 +        exception_block_end = {}
   2.713 +        exception_block_handler = {}
   2.714 +        reversed_exception_table = exception_table[:]
   2.715 +        reversed_exception_table.reverse()
   2.716 +
   2.717 +        # Later entries have wider coverage than earlier entries.
   2.718 +
   2.719 +        for exception in reversed_exception_table:
   2.720 +
   2.721 +            # Index start positions.
   2.722 +
   2.723 +            if not exception_block_start.has_key(exception.start_pc):
   2.724 +                exception_block_start[exception.start_pc] = []
   2.725 +            exception_block_start[exception.start_pc].append(exception)
   2.726 +
   2.727 +            # Index end positions.
   2.728 +
   2.729 +            if not exception_block_end.has_key(exception.end_pc):
   2.730 +                exception_block_end[exception.end_pc] = []
   2.731 +            exception_block_end[exception.end_pc].append(exception)
   2.732 +
   2.733 +            # Index handler positions.
   2.734 +
   2.735 +            if not exception_block_handler.has_key(exception.handler_pc):
   2.736 +                exception_block_handler[exception.handler_pc] = []
   2.737 +            exception_block_handler[exception.handler_pc].append(exception)
   2.738 +
   2.739 +        # Process each instruction in the code.
   2.740 +
   2.741 +        while self.java_position < len(code):
   2.742 +            self.position_mapping[self.java_position] = program.position
   2.743 +
   2.744 +            # Insert exception handling constructs.
   2.745 +
   2.746 +            block_starts = exception_block_start.get(self.java_position, [])
   2.747 +            for exception in block_starts:
   2.748 +
   2.749 +                # Note that the absolute position is used.
   2.750 +
   2.751 +                if exception.catch_type == 0:
   2.752 +                    program.setup_finally(self.position_mapping[exception.handler_pc])
   2.753 +                else:
   2.754 +                    program.setup_except(self.position_mapping[exception.handler_pc])
   2.755 +
   2.756 +            if block_starts:
   2.757 +                self.in_finally = 0
   2.758 +
   2.759 +            # Insert exception handler details.
   2.760 +            # NOTE: Ensure that pop_block is reachable by possibly inserting it at the start of finally handlers.
   2.761 +            # NOTE: Insert a check for the correct exception at the start of each handler.
   2.762 +
   2.763 +            for exception in exception_block_handler.get(self.java_position, []):
   2.764 +                program.end_exception()
   2.765 +                if exception.catch_type == 0:
   2.766 +                    self.in_finally = 1
   2.767 +                else:
   2.768 +                    program.start_handler(self.class_file.constants[exception.catch_type - 1].get_python_name(), self.class_file)
   2.769 +
   2.770 +            # Process the bytecode at the current position.
   2.771 +
   2.772 +            bytecode = ord(code[self.java_position])
   2.773 +            mnemonic, number_of_arguments = self.java_bytecodes[bytecode]
   2.774 +            number_of_arguments = self.process_bytecode(mnemonic, number_of_arguments, code, program)
   2.775 +            next_java_position = self.java_position + 1 + number_of_arguments
   2.776 +
   2.777 +            # Insert exception block end details.
   2.778 +
   2.779 +            for exception in exception_block_end.get(next_java_position, []):
   2.780 +
   2.781 +                # NOTE: Insert jump beyond handlers.
   2.782 +                # NOTE: program.jump_forward/absolute(...)
   2.783 +                # NOTE: Insert end finally at end of handlers as well as where "ret" occurs.
   2.784 +
   2.785 +                if exception.catch_type != 0:
   2.786 +                    program.pop_block()
   2.787 +
   2.788 +            # Only advance the JVM position after sneaking in extra Python
   2.789 +            # instructions.
   2.790 +
   2.791 +            self.java_position = next_java_position
   2.792 +
   2.793 +    def process_bytecode(self, mnemonic, number_of_arguments, code, program):
   2.794 +
   2.795 +        """
   2.796 +        Process a bytecode instruction with the given 'mnemonic' and
   2.797 +        'number_of_arguments'. The 'code' parameter contains the full method
   2.798 +        code so that argument data can be inspected. The 'program' parameter is
   2.799 +        used to produce a Python translation of the instruction.
   2.800 +        """
   2.801 +
   2.802 +        if number_of_arguments is not None:
   2.803 +            arguments = []
   2.804 +            for j in range(0, number_of_arguments):
   2.805 +                arguments.append(ord(code[self.java_position + 1 + j]))
   2.806 +
   2.807 +            # Call the handler.
   2.808 +
   2.809 +            getattr(self, mnemonic)(arguments, program)
   2.810 +            return number_of_arguments
   2.811 +        else:
   2.812 +            # Call the handler.
   2.813 +
   2.814 +            return getattr(self, mnemonic)(code[self.java_position+1:], program)
   2.815 +
   2.816 +    java_bytecodes = {
   2.817 +        # code : (mnemonic, number of following bytes, change in stack)
   2.818 +        0 : ("nop", 0),
   2.819 +        1 : ("aconst_null", 0),
   2.820 +        2 : ("iconst_m1", 0),
   2.821 +        3 : ("iconst_0", 0),
   2.822 +        4 : ("iconst_1", 0),
   2.823 +        5 : ("iconst_2", 0),
   2.824 +        6 : ("iconst_3", 0),
   2.825 +        7 : ("iconst_4", 0),
   2.826 +        8 : ("iconst_5", 0),
   2.827 +        9 : ("lconst_0", 0),
   2.828 +        10 : ("lconst_1", 0),
   2.829 +        11 : ("fconst_0", 0),
   2.830 +        12 : ("fconst_1", 0),
   2.831 +        13 : ("fconst_2", 0),
   2.832 +        14 : ("dconst_0", 0),
   2.833 +        15 : ("dconst_1", 0),
   2.834 +        16 : ("bipush", 1),
   2.835 +        17 : ("sipush", 2),
   2.836 +        18 : ("ldc", 1),
   2.837 +        19 : ("ldc_w", 2),
   2.838 +        20 : ("ldc2_w", 2),
   2.839 +        21 : ("iload", 1),
   2.840 +        22 : ("lload", 1),
   2.841 +        23 : ("fload", 1),
   2.842 +        24 : ("dload", 1),
   2.843 +        25 : ("aload", 1),
   2.844 +        26 : ("iload_0", 0),
   2.845 +        27 : ("iload_1", 0),
   2.846 +        28 : ("iload_2", 0),
   2.847 +        29 : ("iload_3", 0),
   2.848 +        30 : ("lload_0", 0),
   2.849 +        31 : ("lload_1", 0),
   2.850 +        32 : ("lload_2", 0),
   2.851 +        33 : ("lload_3", 0),
   2.852 +        34 : ("fload_0", 0),
   2.853 +        35 : ("fload_1", 0),
   2.854 +        36 : ("fload_2", 0),
   2.855 +        37 : ("fload_3", 0),
   2.856 +        38 : ("dload_0", 0),
   2.857 +        39 : ("dload_1", 0),
   2.858 +        40 : ("dload_2", 0),
   2.859 +        41 : ("dload_3", 0),
   2.860 +        42 : ("aload_0", 0),
   2.861 +        43 : ("aload_1", 0),
   2.862 +        44 : ("aload_2", 0),
   2.863 +        45 : ("aload_3", 0),
   2.864 +        46 : ("iaload", 0),
   2.865 +        47 : ("laload", 0),
   2.866 +        48 : ("faload", 0),
   2.867 +        49 : ("daload", 0),
   2.868 +        50 : ("aaload", 0),
   2.869 +        51 : ("baload", 0),
   2.870 +        52 : ("caload", 0),
   2.871 +        53 : ("saload", 0),
   2.872 +        54 : ("istore", 1),
   2.873 +        55 : ("lstore", 1),
   2.874 +        56 : ("fstore", 1),
   2.875 +        57 : ("dstore", 1),
   2.876 +        58 : ("astore", 1),
   2.877 +        59 : ("istore_0", 0),
   2.878 +        60 : ("istore_1", 0),
   2.879 +        61 : ("istore_2", 0),
   2.880 +        62 : ("istore_3", 0),
   2.881 +        63 : ("lstore_0", 0),
   2.882 +        64 : ("lstore_1", 0),
   2.883 +        65 : ("lstore_2", 0),
   2.884 +        66 : ("lstore_3", 0),
   2.885 +        67 : ("fstore_0", 0),
   2.886 +        68 : ("fstore_1", 0),
   2.887 +        69 : ("fstore_2", 0),
   2.888 +        70 : ("fstore_3", 0),
   2.889 +        71 : ("dstore_0", 0),
   2.890 +        72 : ("dstore_1", 0),
   2.891 +        73 : ("dstore_2", 0),
   2.892 +        74 : ("dstore_3", 0),
   2.893 +        75 : ("astore_0", 0),
   2.894 +        76 : ("astore_1", 0),
   2.895 +        77 : ("astore_2", 0),
   2.896 +        78 : ("astore_3", 0),
   2.897 +        79 : ("iastore", 0),
   2.898 +        80 : ("lastore", 0),
   2.899 +        81 : ("fastore", 0),
   2.900 +        82 : ("dastore", 0),
   2.901 +        83 : ("aastore", 0),
   2.902 +        84 : ("bastore", 0),
   2.903 +        85 : ("castore", 0),
   2.904 +        86 : ("sastore", 0),
   2.905 +        87 : ("pop", 0),
   2.906 +        88 : ("pop2", 0),
   2.907 +        89 : ("dup", 0),
   2.908 +        90 : ("dup_x1", 0),
   2.909 +        91 : ("dup_x2", 0),
   2.910 +        92 : ("dup2", 0),
   2.911 +        93 : ("dup2_x1", 0),
   2.912 +        94 : ("dup2_x2", 0),
   2.913 +        95 : ("swap", 0),
   2.914 +        96 : ("iadd", 0),
   2.915 +        97 : ("ladd", 0),
   2.916 +        98 : ("fadd", 0),
   2.917 +        99 : ("dadd", 0),
   2.918 +        100 : ("isub", 0),
   2.919 +        101 : ("lsub", 0),
   2.920 +        102 : ("fsub", 0),
   2.921 +        103 : ("dsub", 0),
   2.922 +        104 : ("imul", 0),
   2.923 +        105 : ("lmul", 0),
   2.924 +        106 : ("fmul", 0),
   2.925 +        107 : ("dmul", 0),
   2.926 +        108 : ("idiv", 0),
   2.927 +        109 : ("ldiv", 0),
   2.928 +        110 : ("fdiv", 0),
   2.929 +        111 : ("ddiv", 0),
   2.930 +        112 : ("irem", 0),
   2.931 +        113 : ("lrem", 0),
   2.932 +        114 : ("frem", 0),
   2.933 +        115 : ("drem", 0),
   2.934 +        116 : ("ineg", 0),
   2.935 +        117 : ("lneg", 0),
   2.936 +        118 : ("fneg", 0),
   2.937 +        119 : ("dneg", 0),
   2.938 +        120 : ("ishl", 0),
   2.939 +        121 : ("lshl", 0),
   2.940 +        122 : ("ishr", 0),
   2.941 +        123 : ("lshr", 0),
   2.942 +        124 : ("iushr", 0),
   2.943 +        125 : ("lushr", 0),
   2.944 +        126 : ("iand", 0),
   2.945 +        127 : ("land", 0),
   2.946 +        128 : ("ior", 0),
   2.947 +        129 : ("lor", 0),
   2.948 +        130 : ("ixor", 0),
   2.949 +        131 : ("lxor", 0),
   2.950 +        132 : ("iinc", 2),
   2.951 +        133 : ("i2l", 0),
   2.952 +        134 : ("i2f", 0),
   2.953 +        135 : ("i2d", 0),
   2.954 +        136 : ("l2i", 0),
   2.955 +        137 : ("l2f", 0),
   2.956 +        138 : ("l2d", 0),
   2.957 +        139 : ("f2i", 0),
   2.958 +        140 : ("f2l", 0),
   2.959 +        141 : ("f2d", 0),
   2.960 +        142 : ("d2i", 0),
   2.961 +        143 : ("d2l", 0),
   2.962 +        144 : ("d2f", 0),
   2.963 +        145 : ("i2b", 0),
   2.964 +        146 : ("i2c", 0),
   2.965 +        147 : ("i2s", 0),
   2.966 +        148 : ("lcmp", 0),
   2.967 +        149 : ("fcmpl", 0),
   2.968 +        150 : ("fcmpg", 0),
   2.969 +        151 : ("dcmpl", 0),
   2.970 +        152 : ("dcmpg", 0),
   2.971 +        153 : ("ifeq", 2),
   2.972 +        154 : ("ifne", 2),
   2.973 +        155 : ("iflt", 2),
   2.974 +        156 : ("ifge", 2),
   2.975 +        157 : ("ifgt", 2),
   2.976 +        158 : ("ifle", 2),
   2.977 +        159 : ("if_icmpeq", 2),
   2.978 +        160 : ("if_icmpne", 2),
   2.979 +        161 : ("if_icmplt", 2),
   2.980 +        162 : ("if_icmpge", 2),
   2.981 +        163 : ("if_icmpgt", 2),
   2.982 +        164 : ("if_icmple", 2),
   2.983 +        165 : ("if_acmpeq", 2),
   2.984 +        166 : ("if_acmpne", 2),
   2.985 +        167 : ("goto", 2),
   2.986 +        168 : ("jsr", 2),
   2.987 +        169 : ("ret", 1),
   2.988 +        170 : ("tableswitch", None), # variable number of arguments
   2.989 +        171 : ("lookupswitch", None), # variable number of arguments
   2.990 +        172 : ("ireturn", 0),
   2.991 +        173 : ("lreturn", 0),
   2.992 +        174 : ("freturn", 0),
   2.993 +        175 : ("dreturn", 0),
   2.994 +        176 : ("areturn", 0),
   2.995 +        177 : ("return_", 0),
   2.996 +        178 : ("getstatic", 2),
   2.997 +        179 : ("putstatic", 2),
   2.998 +        180 : ("getfield", 2),
   2.999 +        181 : ("putfield", 2),
  2.1000 +        182 : ("invokevirtual", 2),
  2.1001 +        183 : ("invokespecial", 2),
  2.1002 +        184 : ("invokestatic", 2),
  2.1003 +        185 : ("invokeinterface", 4),
  2.1004 +        187 : ("new", 2),
  2.1005 +        188 : ("newarray", 1),
  2.1006 +        189 : ("anewarray", 2),
  2.1007 +        190 : ("arraylength", 0),
  2.1008 +        191 : ("athrow", 0),
  2.1009 +        192 : ("checkcast", 2),
  2.1010 +        193 : ("instanceof", 2),
  2.1011 +        194 : ("monitorenter", 0),
  2.1012 +        195 : ("monitorexit", 0),
  2.1013 +        196 : ("wide", None), # 3 or 5 arguments, stack changes according to modified element
  2.1014 +        197 : ("multianewarray", 3),
  2.1015 +        198 : ("ifnull", 2),
  2.1016 +        199 : ("ifnonnull", 2),
  2.1017 +        200 : ("goto_w", 4),
  2.1018 +        201 : ("jsr_w", 4),
  2.1019 +        }
  2.1020 +
  2.1021 +class BytecodeDisassembler(BytecodeReader):
  2.1022 +
  2.1023 +    "A Java bytecode disassembler."
  2.1024 +
  2.1025 +    bytecode_methods = [spec[0] for spec in BytecodeReader.java_bytecodes.values()]
  2.1026 +
  2.1027 +    def __getattr__(self, name):
  2.1028 +        if name in self.bytecode_methods:
  2.1029 +            print "%5s %s" % (self.java_position, name),
  2.1030 +            return self.generic
  2.1031 +        else:
  2.1032 +            raise AttributeError, name
  2.1033 +
  2.1034 +    def generic(self, arguments, program):
  2.1035 +        print arguments
  2.1036 +
  2.1037 +    def lookupswitch(self, code, program):
  2.1038 +        print "%5s lookupswitch" % (self.java_position,),
  2.1039 +        d, r = divmod(self.java_position + 1, 4)
  2.1040 +        to_boundary = (4 - r) % 4
  2.1041 +        code = code[to_boundary:]
  2.1042 +        default = classfile.u4(code[0:4])
  2.1043 +        npairs = classfile.u4(code[4:8])
  2.1044 +        print default, npairs
  2.1045 +        return to_boundary + 8 + npairs * 8
  2.1046 +
  2.1047 +    def tableswitch(self, code, program):
  2.1048 +        print "%5s tableswitch" % (self.java_position,),
  2.1049 +        d, r = divmod(self.java_position + 1, 4)
  2.1050 +        to_boundary = (4 - r) % 4
  2.1051 +        code = code[to_boundary:]
  2.1052 +        default = classfile.u4(code[0:4])
  2.1053 +        low = classfile.u4(code[4:8])
  2.1054 +        high = classfile.u4(code[8:12])
  2.1055 +        print default, low, high
  2.1056 +        return to_boundary + 12 + (high - low + 1) * 4
  2.1057 +
  2.1058 +class BytecodeDisassemblerProgram:
  2.1059 +    position = 0
  2.1060 +    def setup_except(self, target):
  2.1061 +        print "(setup_except %s)" % target
  2.1062 +    def setup_finally(self, target):
  2.1063 +        print "(setup_finally %s)" % target
  2.1064 +    def end_exception(self):
  2.1065 +        print "(end_exception)"
  2.1066 +    def start_handler(self, exc_name, class_file):
  2.1067 +        print "(start_handler %s)" % exc_name
  2.1068 +    def pop_block(self):
  2.1069 +        print "(pop_block)"
  2.1070 +
  2.1071 +class BytecodeTranslator(BytecodeReader):
  2.1072 +
  2.1073 +    "A Java bytecode translator which uses a Python bytecode writer."
  2.1074 +
  2.1075 +    def aaload(self, arguments, program):
  2.1076 +        # NOTE: No type checking performed.
  2.1077 +        program.binary_subscr()
  2.1078 +
  2.1079 +    def aastore(self, arguments, program):
  2.1080 +        # NOTE: No type checking performed.
  2.1081 +        # Stack: arrayref, index, value
  2.1082 +        program.rot_three() # Stack: value, arrayref, index
  2.1083 +        program.store_subscr()
  2.1084 +
  2.1085 +    def aconst_null(self, arguments, program):
  2.1086 +        program.load_const(None)
  2.1087 +
  2.1088 +    def aload(self, arguments, program):
  2.1089 +        program.load_fast(arguments[0])
  2.1090 +
  2.1091 +    def aload_0(self, arguments, program):
  2.1092 +        program.load_fast(0)
  2.1093 +
  2.1094 +    def aload_1(self, arguments, program):
  2.1095 +        program.load_fast(1)
  2.1096 +
  2.1097 +    def aload_2(self, arguments, program):
  2.1098 +        program.load_fast(2)
  2.1099 +
  2.1100 +    def aload_3(self, arguments, program):
  2.1101 +        program.load_fast(3)
  2.1102 +
  2.1103 +    def anewarray(self, arguments, program):
  2.1104 +        # NOTE: Does not raise NegativeArraySizeException.
  2.1105 +        # NOTE: Not using the index to type the list/array.
  2.1106 +        index = (arguments[0] << 8) + arguments[1]
  2.1107 +        self._newarray(program)
  2.1108 +
  2.1109 +    def _newarray(self, program):
  2.1110 +        program.build_list(0)       # Stack: count, list
  2.1111 +        program.rot_two()           # Stack: list, count
  2.1112 +        program.setup_loop()
  2.1113 +        program.load_global("range")
  2.1114 +        program.load_const(0)       # Stack: list, count, range, 0
  2.1115 +        program.rot_three()         # Stack: list, 0, count, range
  2.1116 +        program.rot_three()         # Stack: list, range, 0, count
  2.1117 +        program.call_function(2)    # Stack: list, range_list
  2.1118 +        program.get_iter()          # Stack: list, iter
  2.1119 +        program.for_iter()          # Stack: list, iter, value
  2.1120 +        program.pop_top()           # Stack: list, iter
  2.1121 +        program.rot_two()           # Stack: iter, list
  2.1122 +        program.dup_top()           # Stack: iter, list, list
  2.1123 +        program.load_attr("append") # Stack: iter, list, append
  2.1124 +        program.load_const(None)    # Stack: iter, list, append, None
  2.1125 +        program.call_function(1)    # Stack: iter, list, None
  2.1126 +        program.pop_top()           # Stack: iter, list
  2.1127 +        program.rot_two()           # Stack: list, iter
  2.1128 +        program.end_loop()          # Back to for_iter above
  2.1129 +
  2.1130 +    def areturn(self, arguments, program):
  2.1131 +        program.return_value()
  2.1132 +
  2.1133 +    def arraylength(self, arguments, program):
  2.1134 +        program.load_global("len")  # Stack: arrayref, len
  2.1135 +        program.rot_two()           # Stack: len, arrayref
  2.1136 +        program.call_function(1)
  2.1137 +
  2.1138 +    def astore(self, arguments, program):
  2.1139 +        program.store_fast(arguments[0])
  2.1140 +
  2.1141 +    def astore_0(self, arguments, program):
  2.1142 +        program.store_fast(0)
  2.1143 +
  2.1144 +    def astore_1(self, arguments, program):
  2.1145 +        program.store_fast(1)
  2.1146 +
  2.1147 +    def astore_2(self, arguments, program):
  2.1148 +        program.store_fast(2)
  2.1149 +
  2.1150 +    def astore_3(self, arguments, program):
  2.1151 +        program.store_fast(3)
  2.1152 +
  2.1153 +    def athrow(self, arguments, program):
  2.1154 +        # NOTE: NullPointerException not raised where null/None is found on the stack.
  2.1155 +        # If this instruction appears in a finally handler, use end_finally instead.
  2.1156 +        if self.in_finally:
  2.1157 +            program.end_finally()
  2.1158 +        else:
  2.1159 +            # Wrap the exception in a Python exception.
  2.1160 +            program.load_global("Exception")    # Stack: objectref, Exception
  2.1161 +            program.rot_two()                   # Stack: Exception, objectref
  2.1162 +            program.call_function(1)            # Stack: exception
  2.1163 +            program.raise_varargs(1)
  2.1164 +            # NOTE: This seems to put another object on the stack.
  2.1165 +
  2.1166 +    baload = aaload
  2.1167 +    bastore = aastore
  2.1168 +
  2.1169 +    def bipush(self, arguments, program):
  2.1170 +        program.load_const(signed1(arguments[0]))
  2.1171 +
  2.1172 +    caload = aaload
  2.1173 +    castore = aastore
  2.1174 +
  2.1175 +    def checkcast(self, arguments, program):
  2.1176 +        index = (arguments[0] << 8) + arguments[1]
  2.1177 +        target_name = self.class_file.constants[index - 1].get_python_name()
  2.1178 +        program.use_external_name(target_name)
  2.1179 +        program.dup_top()                   # Stack: objectref, objectref
  2.1180 +        program.load_const(None)            # Stack: objectref, objectref, None
  2.1181 +        program.compare_op("is")            # Stack: objectref, result
  2.1182 +        program.jump_to_label(1, "next")
  2.1183 +        program.pop_top()                   # Stack: objectref
  2.1184 +        program.dup_top()                   # Stack: objectref, objectref
  2.1185 +        program.load_global("isinstance")   # Stack: objectref, objectref, isinstance
  2.1186 +        program.rot_two()                   # Stack: objectref, isinstance, objectref
  2.1187 +        load_class_name(self.class_file, target_name, program)
  2.1188 +        program.call_function(2)            # Stack: objectref, result
  2.1189 +        program.jump_to_label(1, "next")
  2.1190 +        program.pop_top()                   # Stack: objectref
  2.1191 +        program.pop_top()                   # Stack:
  2.1192 +        program.use_external_name("java.lang.ClassCastException")
  2.1193 +        load_class_name(self.class_file, "java.lang.ClassCastException", program)
  2.1194 +        program.call_function(0)            # Stack: exception
  2.1195 +        # Wrap the exception in a Python exception.
  2.1196 +        program.load_global("Exception")    # Stack: exception, Exception
  2.1197 +        program.rot_two()                   # Stack: Exception, exception
  2.1198 +        program.call_function(1)            # Stack: exception
  2.1199 +        program.raise_varargs(1)
  2.1200 +        # NOTE: This seems to put another object on the stack.
  2.1201 +        program.start_label("next")
  2.1202 +        program.pop_top()                   # Stack: objectref
  2.1203 +
  2.1204 +    def d2f(self, arguments, program):
  2.1205 +        pass
  2.1206 +
  2.1207 +    def d2i(self, arguments, program):
  2.1208 +        program.load_global("int")  # Stack: value, int
  2.1209 +        program.rot_two()           # Stack: int, value
  2.1210 +        program.call_function(1)    # Stack: result
  2.1211 +
  2.1212 +    d2l = d2i # Preserving Java semantics
  2.1213 +
  2.1214 +    def dadd(self, arguments, program):
  2.1215 +        # NOTE: No type checking performed.
  2.1216 +        program.binary_add()
  2.1217 +
  2.1218 +    daload = aaload
  2.1219 +    dastore = aastore
  2.1220 +
  2.1221 +    def dcmpg(self, arguments, program):
  2.1222 +        # NOTE: No type checking performed.
  2.1223 +        program.compare_op(">")
  2.1224 +
  2.1225 +    def dcmpl(self, arguments, program):
  2.1226 +        # NOTE: No type checking performed.
  2.1227 +        program.compare_op("<")
  2.1228 +
  2.1229 +    def dconst_0(self, arguments, program):
  2.1230 +        program.load_const(0.0)
  2.1231 +
  2.1232 +    def dconst_1(self, arguments, program):
  2.1233 +        program.load_const(1.0)
  2.1234 +
  2.1235 +    def ddiv(self, arguments, program):
  2.1236 +        # NOTE: No type checking performed.
  2.1237 +        program.binary_divide()
  2.1238 +
  2.1239 +    dload = aload
  2.1240 +    dload_0 = aload_0
  2.1241 +    dload_1 = aload_1
  2.1242 +    dload_2 = aload_2
  2.1243 +    dload_3 = aload_3
  2.1244 +
  2.1245 +    def dmul(self, arguments, program):
  2.1246 +        # NOTE: No type checking performed.
  2.1247 +        program.binary_multiply()
  2.1248 +
  2.1249 +    def dneg(self, arguments, program):
  2.1250 +        # NOTE: No type checking performed.
  2.1251 +        program.unary_negative()
  2.1252 +
  2.1253 +    def drem(self, arguments, program):
  2.1254 +        # NOTE: No type checking performed.
  2.1255 +        program.binary_modulo()
  2.1256 +
  2.1257 +    dreturn = areturn
  2.1258 +    dstore = astore
  2.1259 +    dstore_0 = astore_0
  2.1260 +    dstore_1 = astore_1
  2.1261 +    dstore_2 = astore_2
  2.1262 +    dstore_3 = astore_3
  2.1263 +
  2.1264 +    def dsub(self, arguments, program):
  2.1265 +        # NOTE: No type checking performed.
  2.1266 +        program.binary_subtract()
  2.1267 +
  2.1268 +    def dup(self, arguments, program):
  2.1269 +        program.dup_top()
  2.1270 +
  2.1271 +    def dup_x1(self, arguments, program):
  2.1272 +        # Ignoring computational type categories.
  2.1273 +        program.dup_top()
  2.1274 +        program.rot_three()
  2.1275 +
  2.1276 +    def dup_x2(self, arguments, program):
  2.1277 +        # Ignoring computational type categories.
  2.1278 +        program.dup_top()
  2.1279 +        program.rot_four()
  2.1280 +
  2.1281 +    dup2 = dup # Ignoring computational type categories
  2.1282 +    dup2_x1 = dup_x1 # Ignoring computational type categories
  2.1283 +    dup2_x2 = dup_x2 # Ignoring computational type categories
  2.1284 +
  2.1285 +    def f2d(self, arguments, program):
  2.1286 +        pass # Preserving Java semantics
  2.1287 +
  2.1288 +    def f2i(self, arguments, program):
  2.1289 +        program.load_global("int")  # Stack: value, int
  2.1290 +        program.rot_two()           # Stack: int, value
  2.1291 +        program.call_function(1)    # Stack: result
  2.1292 +
  2.1293 +    f2l = f2i # Preserving Java semantics
  2.1294 +    fadd = dadd
  2.1295 +    faload = daload
  2.1296 +    fastore = dastore
  2.1297 +    fcmpg = dcmpg
  2.1298 +    fcmpl = dcmpl
  2.1299 +    fconst_0 = dconst_0
  2.1300 +    fconst_1 = dconst_1
  2.1301 +
  2.1302 +    def fconst_2(self, arguments, program):
  2.1303 +        program.load_const(2.0)
  2.1304 +
  2.1305 +    fdiv = ddiv
  2.1306 +    fload = dload
  2.1307 +    fload_0 = dload_0
  2.1308 +    fload_1 = dload_1
  2.1309 +    fload_2 = dload_2
  2.1310 +    fload_3 = dload_3
  2.1311 +    fmul = dmul
  2.1312 +    fneg = dneg
  2.1313 +    frem = drem
  2.1314 +    freturn = dreturn
  2.1315 +    fstore = dstore
  2.1316 +    fstore_0 = dstore_0
  2.1317 +    fstore_1 = dstore_1
  2.1318 +    fstore_2 = dstore_2
  2.1319 +    fstore_3 = dstore_3
  2.1320 +    fsub = dsub
  2.1321 +
  2.1322 +    def getfield(self, arguments, program):
  2.1323 +        index = (arguments[0] << 8) + arguments[1]
  2.1324 +        target_name = self.class_file.constants[index - 1].get_python_name()
  2.1325 +        # NOTE: Using the string version of the name which may contain incompatible characters.
  2.1326 +        program.load_attr(str(target_name))
  2.1327 +
  2.1328 +    def getstatic(self, arguments, program):
  2.1329 +        index = (arguments[0] << 8) + arguments[1]
  2.1330 +        target = self.class_file.constants[index - 1]
  2.1331 +        target_name = target.get_python_name()
  2.1332 +
  2.1333 +        # Get the class name instead of the fully qualified name.
  2.1334 +
  2.1335 +        full_class_name = target.get_class().get_python_name()
  2.1336 +        program.use_external_name(full_class_name)
  2.1337 +        load_class_name(self.class_file, full_class_name, program)
  2.1338 +        # NOTE: Using the string version of the name which may contain incompatible characters.
  2.1339 +        program.load_attr(str(target_name))
  2.1340 +
  2.1341 +    def goto(self, arguments, program):
  2.1342 +        offset = signed2((arguments[0] << 8) + arguments[1])
  2.1343 +        java_absolute = self.java_position + offset
  2.1344 +        program.jump_absolute(self.position_mapping[java_absolute])
  2.1345 +
  2.1346 +    def goto_w(self, arguments, program):
  2.1347 +        offset = signed4((arguments[0] << 24) + (arguments[1] << 16) + (arguments[2] << 8) + arguments[3])
  2.1348 +        java_absolute = self.java_position + offset
  2.1349 +        program.jump_absolute(self.position_mapping[java_absolute])
  2.1350 +
  2.1351 +    def i2b(self, arguments, program):
  2.1352 +        pass
  2.1353 +
  2.1354 +    def i2c(self, arguments, program):
  2.1355 +        pass
  2.1356 +
  2.1357 +    def i2d(self, arguments, program):
  2.1358 +        program.load_global("float")    # Stack: value, float
  2.1359 +        program.rot_two()               # Stack: float, value
  2.1360 +        program.call_function(1)        # Stack: result
  2.1361 +
  2.1362 +    i2f = i2d # Not distinguishing between float and double
  2.1363 +
  2.1364 +    def i2l(self, arguments, program):
  2.1365 +        pass # Preserving Java semantics
  2.1366 +
  2.1367 +    def i2s(self, arguments, program):
  2.1368 +        pass # Not distinguishing between int and short
  2.1369 +
  2.1370 +    iadd = fadd
  2.1371 +    iaload = faload
  2.1372 +
  2.1373 +    def iand(self, arguments, program):
  2.1374 +        # NOTE: No type checking performed.
  2.1375 +        program.binary_and()
  2.1376 +
  2.1377 +    iastore = fastore
  2.1378 +
  2.1379 +    def iconst_m1(self, arguments, program):
  2.1380 +        program.load_const(-1)
  2.1381 +
  2.1382 +    def iconst_0(self, arguments, program):
  2.1383 +        program.load_const(0)
  2.1384 +
  2.1385 +    def iconst_1(self, arguments, program):
  2.1386 +        program.load_const(1)
  2.1387 +
  2.1388 +    def iconst_2(self, arguments, program):
  2.1389 +        program.load_const(2)
  2.1390 +
  2.1391 +    def iconst_3(self, arguments, program):
  2.1392 +        program.load_const(3)
  2.1393 +
  2.1394 +    def iconst_4(self, arguments, program):
  2.1395 +        program.load_const(4)
  2.1396 +
  2.1397 +    def iconst_5(self, arguments, program):
  2.1398 +        program.load_const(5)
  2.1399 +
  2.1400 +    idiv = fdiv
  2.1401 +
  2.1402 +    def _if_xcmpx(self, arguments, program, op):
  2.1403 +        offset = signed2((arguments[0] << 8) + arguments[1])
  2.1404 +        java_absolute = self.java_position + offset
  2.1405 +        program.compare_op(op)
  2.1406 +        program.jump_to_label(0, "next") # skip if false
  2.1407 +        program.pop_top()
  2.1408 +        program.jump_absolute(self.position_mapping[java_absolute])
  2.1409 +        program.start_label("next")
  2.1410 +        program.pop_top()
  2.1411 +
  2.1412 +    def if_acmpeq(self, arguments, program):
  2.1413 +        # NOTE: No type checking performed.
  2.1414 +        self._if_xcmpx(arguments, program, "is")
  2.1415 +
  2.1416 +    def if_acmpne(self, arguments, program):
  2.1417 +        # NOTE: No type checking performed.
  2.1418 +        self._if_xcmpx(arguments, program, "is not")
  2.1419 +
  2.1420 +    def if_icmpeq(self, arguments, program):
  2.1421 +        # NOTE: No type checking performed.
  2.1422 +        self._if_xcmpx(arguments, program, "==")
  2.1423 +
  2.1424 +    def if_icmpne(self, arguments, program):
  2.1425 +        # NOTE: No type checking performed.
  2.1426 +        self._if_xcmpx(arguments, program, "!=")
  2.1427 +
  2.1428 +    def if_icmplt(self, arguments, program):
  2.1429 +        # NOTE: No type checking performed.
  2.1430 +        self._if_xcmpx(arguments, program, "<")
  2.1431 +
  2.1432 +    def if_icmpge(self, arguments, program):
  2.1433 +        # NOTE: No type checking performed.
  2.1434 +        self._if_xcmpx(arguments, program, ">=")
  2.1435 +
  2.1436 +    def if_icmpgt(self, arguments, program):
  2.1437 +        # NOTE: No type checking performed.
  2.1438 +        self._if_xcmpx(arguments, program, ">")
  2.1439 +
  2.1440 +    def if_icmple(self, arguments, program):
  2.1441 +        # NOTE: No type checking performed.
  2.1442 +        self._if_xcmpx(arguments, program, "<=")
  2.1443 +
  2.1444 +    def ifeq(self, arguments, program):
  2.1445 +        # NOTE: No type checking performed.
  2.1446 +        program.load_const(0)
  2.1447 +        self._if_xcmpx(arguments, program, "==")
  2.1448 +
  2.1449 +    def ifne(self, arguments, program):
  2.1450 +        # NOTE: No type checking performed.
  2.1451 +        program.load_const(0)
  2.1452 +        self._if_xcmpx(arguments, program, "!=")
  2.1453 +
  2.1454 +    def iflt(self, arguments, program):
  2.1455 +        # NOTE: No type checking performed.
  2.1456 +        program.load_const(0)
  2.1457 +        self._if_xcmpx(arguments, program, "<")
  2.1458 +
  2.1459 +    def ifge(self, arguments, program):
  2.1460 +        # NOTE: No type checking performed.
  2.1461 +        program.load_const(0)
  2.1462 +        self._if_xcmpx(arguments, program, ">=")
  2.1463 +
  2.1464 +    def ifgt(self, arguments, program):
  2.1465 +        # NOTE: No type checking performed.
  2.1466 +        program.load_const(0)
  2.1467 +        self._if_xcmpx(arguments, program, ">")
  2.1468 +
  2.1469 +    def ifle(self, arguments, program):
  2.1470 +        # NOTE: No type checking performed.
  2.1471 +        program.load_const(0)
  2.1472 +        self._if_xcmpx(arguments, program, "<=")
  2.1473 +
  2.1474 +    def ifnonnull(self, arguments, program):
  2.1475 +        # NOTE: No type checking performed.
  2.1476 +        program.load_const(None)
  2.1477 +        self._if_xcmpx(arguments, program, "is not")
  2.1478 +
  2.1479 +    def ifnull(self, arguments, program):
  2.1480 +        # NOTE: No type checking performed.
  2.1481 +        program.load_const(None)
  2.1482 +        self._if_xcmpx(arguments, program, "is")
  2.1483 +
  2.1484 +    def iinc(self, arguments, program):
  2.1485 +        # NOTE: No type checking performed.
  2.1486 +        program.load_fast(arguments[0])
  2.1487 +        program.load_const(arguments[1])
  2.1488 +        program.binary_add()
  2.1489 +        program.store_fast(arguments[0])
  2.1490 +
  2.1491 +    iload = fload
  2.1492 +    iload_0 = fload_0
  2.1493 +    iload_1 = fload_1
  2.1494 +    iload_2 = fload_2
  2.1495 +    iload_3 = fload_3
  2.1496 +    imul = fmul
  2.1497 +    ineg = fneg
  2.1498 +
  2.1499 +    def instanceof(self, arguments, program):
  2.1500 +        index = (arguments[0] << 8) + arguments[1]
  2.1501 +        target_name = self.class_file.constants[index - 1].get_python_name()
  2.1502 +        program.use_external_name(target_name)
  2.1503 +        program.load_global("isinstance")   # Stack: objectref, isinstance
  2.1504 +        program.rot_two()                   # Stack: isinstance, objectref
  2.1505 +        load_class_name(self.class_file, target_name, program)
  2.1506 +        program.call_function(2)            # Stack: result
  2.1507 +
  2.1508 +    def _invoke(self, target_name, program):
  2.1509 +        # NOTE: Using the string version of the name which may contain incompatible characters.
  2.1510 +        program.load_attr(str(target_name)) # Stack: tuple, method
  2.1511 +        program.rot_two()                   # Stack: method, tuple
  2.1512 +        program.call_function_var(0)        # Stack: result
  2.1513 +
  2.1514 +    def invokeinterface(self, arguments, program):
  2.1515 +        # NOTE: This implementation does not perform the necessary checks for
  2.1516 +        # NOTE: signature-based polymorphism.
  2.1517 +        # NOTE: Java rules not specifically obeyed.
  2.1518 +        index = (arguments[0] << 8) + arguments[1]
  2.1519 +        # NOTE: "count" == nargs + 1, apparently.
  2.1520 +        count = arguments[2] - 1
  2.1521 +        target_name = self.class_file.constants[index - 1].get_python_name()
  2.1522 +        # Stack: objectref, arg1, arg2, ...
  2.1523 +        program.build_tuple(count)          # Stack: objectref, tuple
  2.1524 +        program.rot_two()                   # Stack: tuple, objectref
  2.1525 +        # NOTE: The interface information is not used to discover the correct
  2.1526 +        # NOTE: method.
  2.1527 +        self._invoke(target_name, program)
  2.1528 +
  2.1529 +    def invokespecial(self, arguments, program):
  2.1530 +        # NOTE: This implementation does not perform the necessary checks for
  2.1531 +        # NOTE: signature-based polymorphism.
  2.1532 +        # NOTE: Java rules not specifically obeyed.
  2.1533 +        index = (arguments[0] << 8) + arguments[1]
  2.1534 +        target = self.class_file.constants[index - 1]
  2.1535 +        original_name = target.get_name()
  2.1536 +        target_name = target.get_python_name()
  2.1537 +
  2.1538 +        # Get the number of parameters from the descriptor.
  2.1539 +
  2.1540 +        count = len(target.get_descriptor()[0])
  2.1541 +
  2.1542 +        # First, we build a tuple of the reference and arguments.
  2.1543 +
  2.1544 +        program.build_tuple(count + 1)          # Stack: tuple
  2.1545 +
  2.1546 +        # Get the class name instead of the fully qualified name.
  2.1547 +        # NOTE: Not bothering with Object initialisation.
  2.1548 +
  2.1549 +        full_class_name = target.get_class().get_python_name()
  2.1550 +        if full_class_name not in ("java.lang.Object", "java.lang.Exception"):
  2.1551 +            program.use_external_name(full_class_name)
  2.1552 +            load_class_name(self.class_file, full_class_name, program)
  2.1553 +            self._invoke(target_name, program)
  2.1554 +
  2.1555 +        # Remove Python None return value.
  2.1556 +
  2.1557 +        if str(original_name) == "<init>":
  2.1558 +            program.pop_top()
  2.1559 +
  2.1560 +    def invokestatic(self, arguments, program):
  2.1561 +        # NOTE: This implementation does not perform the necessary checks for
  2.1562 +        # NOTE: signature-based polymorphism.
  2.1563 +        # NOTE: Java rules not specifically obeyed.
  2.1564 +        index = (arguments[0] << 8) + arguments[1]
  2.1565 +        target = self.class_file.constants[index - 1]
  2.1566 +        target_name = target.get_python_name()
  2.1567 +
  2.1568 +        # Get the number of parameters from the descriptor.
  2.1569 +
  2.1570 +        count = len(target.get_descriptor()[0])
  2.1571 +
  2.1572 +        # Stack: arg1, arg2, ...
  2.1573 +
  2.1574 +        program.build_tuple(count)              # Stack: tuple
  2.1575 +
  2.1576 +        # Use the class to provide access to static methods.
  2.1577 +        # Get the class name instead of the fully qualified name.
  2.1578 +
  2.1579 +        full_class_name = target.get_class().get_python_name()
  2.1580 +        if full_class_name not in ("java.lang.Object", "java.lang.Exception"):
  2.1581 +            program.use_external_name(full_class_name)
  2.1582 +            load_class_name(self.class_file, full_class_name, program)
  2.1583 +            self._invoke(target_name, program)
  2.1584 +
  2.1585 +    def invokevirtual (self, arguments, program):
  2.1586 +        # NOTE: This implementation does not perform the necessary checks for
  2.1587 +        # NOTE: signature-based polymorphism.
  2.1588 +        # NOTE: Java rules not specifically obeyed.
  2.1589 +        index = (arguments[0] << 8) + arguments[1]
  2.1590 +        target = self.class_file.constants[index - 1]
  2.1591 +        target_name = target.get_python_name()
  2.1592 +        # Get the number of parameters from the descriptor.
  2.1593 +        count = len(target.get_descriptor()[0])
  2.1594 +        # Stack: objectref, arg1, arg2, ...
  2.1595 +        program.build_tuple(count)          # Stack: objectref, tuple
  2.1596 +        program.rot_two()                   # Stack: tuple, objectref
  2.1597 +        self._invoke(target_name, program)
  2.1598 +
  2.1599 +    def ior(self, arguments, program):
  2.1600 +        # NOTE: No type checking performed.
  2.1601 +        program.binary_or()
  2.1602 +
  2.1603 +    irem = frem
  2.1604 +    ireturn = freturn
  2.1605 +
  2.1606 +    def ishl(self, arguments, program):
  2.1607 +        # NOTE: No type checking performed.
  2.1608 +        # NOTE: Not verified.
  2.1609 +        program.binary_lshift()
  2.1610 +
  2.1611 +    def ishr(self, arguments, program):
  2.1612 +        # NOTE: No type checking performed.
  2.1613 +        # NOTE: Not verified.
  2.1614 +        program.binary_rshift()
  2.1615 +
  2.1616 +    istore = fstore
  2.1617 +    istore_0 = fstore_0
  2.1618 +    istore_1 = fstore_1
  2.1619 +    istore_2 = fstore_2
  2.1620 +    istore_3 = fstore_3
  2.1621 +    isub = fsub
  2.1622 +    iushr = ishr # Ignoring distinctions between arithmetic and logical shifts
  2.1623 +
  2.1624 +    def ixor(self, arguments, program):
  2.1625 +        # NOTE: No type checking performed.
  2.1626 +        program.binary_xor()
  2.1627 +
  2.1628 +    def jsr(self, arguments, program):
  2.1629 +        offset = signed2((arguments[0] << 8) + arguments[1])
  2.1630 +        java_absolute = self.java_position + offset
  2.1631 +        # Store the address of the next instruction.
  2.1632 +        program.load_const_ret(self.position_mapping[self.java_position + 3])
  2.1633 +        program.jump_absolute(self.position_mapping[java_absolute])
  2.1634 +
  2.1635 +    def jsr_w(self, arguments, program):
  2.1636 +        offset = signed4((arguments[0] << 24) + (arguments[1] << 16) + (arguments[2] << 8) + arguments[3])
  2.1637 +        java_absolute = self.java_position + offset
  2.1638 +        # Store the address of the next instruction.
  2.1639 +        program.load_const_ret(self.position_mapping[self.java_position + 5])
  2.1640 +        program.jump_absolute(self.position_mapping[java_absolute])
  2.1641 +
  2.1642 +    l2d = i2d
  2.1643 +    l2f = i2f
  2.1644 +
  2.1645 +    def l2i(self, arguments, program):
  2.1646 +        pass # Preserving Java semantics
  2.1647 +
  2.1648 +    ladd = iadd
  2.1649 +    laload = iaload
  2.1650 +    land = iand
  2.1651 +    lastore = iastore
  2.1652 +
  2.1653 +    def lcmp(self, arguments, program):
  2.1654 +        # NOTE: No type checking performed.
  2.1655 +        program.dup_topx(2)                 # Stack: value1, value2, value1, value2
  2.1656 +        program.compare_op(">")             # Stack: value1, value2, result
  2.1657 +        program.jump_to_label(0, "equals")
  2.1658 +        # True - produce result and branch.
  2.1659 +        program.pop_top()                   # Stack: value1, value2
  2.1660 +        program.pop_top()                   # Stack: value1
  2.1661 +        program.pop_top()                   # Stack:
  2.1662 +        program.load_const(1)               # Stack: 1
  2.1663 +        program.jump_to_label(None, "next")
  2.1664 +        # False - test equality.
  2.1665 +        program.start_label("equals")
  2.1666 +        program.pop_top()                   # Stack: value1, value2
  2.1667 +        program.dup_topx(2)                 # Stack: value1, value2, value1, value2
  2.1668 +        program.compare_op("==")            # Stack: value1, value2, result
  2.1669 +        program.jump_to_label(0, "less")
  2.1670 +        # True - produce result and branch.
  2.1671 +        program.pop_top()                   # Stack: value1, value2
  2.1672 +        program.pop_top()                   # Stack: value1
  2.1673 +        program.pop_top()                   # Stack:
  2.1674 +        program.load_const(0)               # Stack: 0
  2.1675 +        program.jump_to_label(None, "next")
  2.1676 +        # False - produce result.
  2.1677 +        program.start_label("less")
  2.1678 +        program.pop_top()                   # Stack: value1, value2
  2.1679 +        program.pop_top()                   # Stack: value1
  2.1680 +        program.pop_top()                   # Stack:
  2.1681 +        program.load_const(-1)              # Stack: -1
  2.1682 +        program.start_label("next")
  2.1683 +
  2.1684 +    lconst_0 = iconst_0
  2.1685 +    lconst_1 = iconst_1
  2.1686 +
  2.1687 +    def ldc(self, arguments, program):
  2.1688 +        const = self.class_file.constants[arguments[0] - 1]
  2.1689 +        if isinstance(const, classfile.StringInfo):
  2.1690 +            program.use_external_name("java.lang.String")
  2.1691 +            program.load_global("java")
  2.1692 +            program.load_attr("lang")
  2.1693 +            program.load_attr("String")
  2.1694 +            program.load_const(const.get_value())
  2.1695 +            program.call_function(1)
  2.1696 +        else:
  2.1697 +            program.load_const(const.get_value())
  2.1698 +
  2.1699 +    def ldc_w(self, arguments, program):
  2.1700 +        const = self.class_file.constants[(arguments[0] << 8) + arguments[1] - 1]
  2.1701 +        if isinstance(const, classfile.StringInfo):
  2.1702 +            program.use_external_name("java.lang.String")
  2.1703 +            program.load_global("java")
  2.1704 +            program.load_attr("lang")
  2.1705 +            program.load_attr("String")
  2.1706 +            program.load_const(const.get_value())
  2.1707 +            program.call_function(1)
  2.1708 +        else:
  2.1709 +            program.load_const(const.get_value())
  2.1710 +
  2.1711 +    ldc2_w = ldc_w
  2.1712 +    ldiv = idiv
  2.1713 +    lload = iload
  2.1714 +    lload_0 = iload_0
  2.1715 +    lload_1 = iload_1
  2.1716 +    lload_2 = iload_2
  2.1717 +    lload_3 = iload_3
  2.1718 +    lmul = imul
  2.1719 +    lneg = ineg
  2.1720 +
  2.1721 +    def lookupswitch(self, code, program):
  2.1722 +
  2.1723 +        # Find the offset to the next 4 byte boundary in the code.
  2.1724 +
  2.1725 +        d, r = divmod(self.java_position + 1, 4)
  2.1726 +        to_boundary = (4 - r) % 4
  2.1727 +
  2.1728 +        # Get the pertinent arguments.
  2.1729 +
  2.1730 +        code = code[to_boundary:]
  2.1731 +        default = classfile.u4(code[0:4])
  2.1732 +        npairs = classfile.u4(code[4:8])
  2.1733 +
  2.1734 +        # Process the pairs.
  2.1735 +        # NOTE: This is not the most optimal implementation.
  2.1736 +
  2.1737 +        pair_index = 8
  2.1738 +        for pair in range(0, npairs):
  2.1739 +            match = classfile.u4(code[pair_index:pair_index+4])
  2.1740 +            offset = classfile.s4(code[pair_index+4:pair_index+8])
  2.1741 +            # Calculate the branch target.
  2.1742 +            java_absolute = self.java_position + offset
  2.1743 +            # Generate branching code.
  2.1744 +            program.dup_top()                                           # Stack: key, key
  2.1745 +            program.load_const(match)                                   # Stack: key, key, match
  2.1746 +            program.compare_op("==")                                    # Stack: key, result
  2.1747 +            program.jump_to_label(0, "end")
  2.1748 +            program.pop_top()                                           # Stack: key
  2.1749 +            program.pop_top()                                           # Stack:
  2.1750 +            program.jump_absolute(self.position_mapping[java_absolute])
  2.1751 +            # Generate the label for the end of the branching code.
  2.1752 +            program.start_label("end")
  2.1753 +            program.pop_top()                                           # Stack: key
  2.1754 +            # Update the index.
  2.1755 +            pair_index += 4
  2.1756 +
  2.1757 +        # Generate the default.
  2.1758 +
  2.1759 +        java_absolute = self.java_position + default
  2.1760 +        program.jump_absolute(self.position_mapping[java_absolute])
  2.1761 +        return pair_index + to_boundary
  2.1762 +
  2.1763 +    lor = ior
  2.1764 +    lrem = irem
  2.1765 +    lreturn = ireturn
  2.1766 +    lshl = ishl
  2.1767 +    lshr = ishr
  2.1768 +    lstore = istore
  2.1769 +    lstore_0 = istore_0
  2.1770 +    lstore_1 = istore_1
  2.1771 +    lstore_2 = istore_2
  2.1772 +    lstore_3 = istore_3
  2.1773 +    lsub = isub
  2.1774 +    lushr = iushr
  2.1775 +    lxor = ixor
  2.1776 +
  2.1777 +    def monitorenter(self, arguments, program):
  2.1778 +        # NOTE: To be implemented.
  2.1779 +        pass
  2.1780 +
  2.1781 +    def monitorexit(self, arguments, program):
  2.1782 +        # NOTE: To be implemented.
  2.1783 +        pass
  2.1784 +
  2.1785 +    def multianewarray(self, arguments, program):
  2.1786 +        index = (arguments[0] << 8) + arguments[1]
  2.1787 +        dimensions = arguments[2]
  2.1788 +        # Stack: count1, ..., countN-1, countN
  2.1789 +        self._newarray(program)             # Stack: count1, ..., countN-1, list
  2.1790 +        for dimension in range(1, dimensions):
  2.1791 +            program.rot_two()               # Stack: count1, ..., list, countN-1
  2.1792 +            program.build_list(0)           # Stack: count1, ..., list, countN-1, new-list
  2.1793 +            program.rot_three()             # Stack: count1, ..., new-list, list, countN-1
  2.1794 +            program.setup_loop()
  2.1795 +            program.load_const(0)           # Stack: count1, ..., new-list, list, countN-1, 0
  2.1796 +            program.rot_two()               # Stack: count1, ..., new-list, list, 0, countN-1
  2.1797 +            program.load_global("range")    # Stack: count1, ..., new-list, list, 0, countN-1, range
  2.1798 +            program.rot_three()             # Stack: count1, ..., new-list, list, range, 0, countN-1
  2.1799 +            program.call_function(2)        # Stack: count1, ..., new-list, list, range-list
  2.1800 +            program.get_iter()              # Stack: count1, ..., new-list, list, iter
  2.1801 +            program.for_iter()              # Stack: count1, ..., new-list, list, iter, value
  2.1802 +            program.pop_top()               # Stack: count1, ..., new-list, list, iter
  2.1803 +            program.rot_three()             # Stack: count1, ..., iter, new-list, list
  2.1804 +            program.slice_0()               # Stack: count1, ..., iter, new-list, list[:]
  2.1805 +            program.dup_top()               # Stack: count1, ..., iter, new-list, list[:], list[:]
  2.1806 +            program.rot_three()             # Stack: count1, ..., iter, list[:], new-list, list[:]
  2.1807 +            program.rot_two()               # Stack: count1, ..., iter, list[:], list[:], new-list
  2.1808 +            program.dup_top()               # Stack: count1, ..., iter, list[:], list[:], new-list, new-list
  2.1809 +            program.load_attr("append")     # Stack: count1, ..., iter, list[:], list[:], new-list, append
  2.1810 +            program.rot_three()             # Stack: count1, ..., iter, list[:], append, list[:], new-list
  2.1811 +            program.rot_three()             # Stack: count1, ..., iter, list[:], new-list, append, list[:]
  2.1812 +            program.call_function(1)        # Stack: count1, ..., iter, list[:], new-list, None
  2.1813 +            program.pop_top()               # Stack: count1, ..., iter, list[:], new-list
  2.1814 +            program.rot_two()               # Stack: count1, ..., iter, new-list, list[:]
  2.1815 +            program.rot_three()             # Stack: count1, ..., list[:], iter, new-list
  2.1816 +            program.rot_three()             # Stack: count1, ..., new-list, list[:], iter
  2.1817 +            program.end_loop()              # Stack: count1, ..., new-list, list[:], iter
  2.1818 +            program.pop_top()               # Stack: count1, ..., new-list
  2.1819 +
  2.1820 +    def new(self, arguments, program):
  2.1821 +        # This operation is considered to be the same as the calling of the
  2.1822 +        # initialisation method of the given class with no arguments.
  2.1823 +
  2.1824 +        index = (arguments[0] << 8) + arguments[1]
  2.1825 +        target_name = self.class_file.constants[index - 1].get_python_name()
  2.1826 +        program.use_external_name(target_name)
  2.1827 +
  2.1828 +        # NOTE: Using the string version of the name which may contain incompatible characters.
  2.1829 +        program.load_global("object")
  2.1830 +        program.load_attr("__new__")
  2.1831 +        load_class_name(self.class_file, target_name, program)
  2.1832 +        program.call_function(1)
  2.1833 +
  2.1834 +    def newarray(self, arguments, program):
  2.1835 +        # NOTE: Does not raise NegativeArraySizeException.
  2.1836 +        # NOTE: Not using the arguments to type the list/array.
  2.1837 +        self._newarray(program)
  2.1838 +
  2.1839 +    def nop(self, arguments, program):
  2.1840 +        pass
  2.1841 +
  2.1842 +    def pop(self, arguments, program):
  2.1843 +        program.pop_top()
  2.1844 +
  2.1845 +    pop2 = pop # ignoring Java stack value distinctions
  2.1846 +
  2.1847 +    def putfield(self, arguments, program):
  2.1848 +        index = (arguments[0] << 8) + arguments[1]
  2.1849 +        target_name = self.class_file.constants[index - 1].get_python_name()
  2.1850 +        program.rot_two()
  2.1851 +        # NOTE: Using the string version of the name which may contain incompatible characters.
  2.1852 +        program.store_attr(str(target_name))
  2.1853 +
  2.1854 +    def putstatic(self, arguments, program):
  2.1855 +        index = (arguments[0] << 8) + arguments[1]
  2.1856 +        target = self.class_file.constants[index - 1]
  2.1857 +        target_name = target.get_python_name()
  2.1858 +
  2.1859 +        # Get the class name instead of the fully qualified name.
  2.1860 +
  2.1861 +        full_class_name = target.get_class().get_python_name()
  2.1862 +        program.use_external_name(full_class_name)
  2.1863 +        load_class_name(self.class_file, full_class_name, program)
  2.1864 +        # NOTE: Using the string version of the name which may contain incompatible characters.
  2.1865 +        program.store_attr(str(target_name))
  2.1866 +
  2.1867 +    def ret(self, arguments, program):
  2.1868 +        program.ret(arguments[0])
  2.1869 +        # Indicate that the finally handler is probably over.
  2.1870 +        # NOTE: This is seemingly not guaranteed.
  2.1871 +        self.in_finally = 0
  2.1872 +
  2.1873 +    def return_(self, arguments, program):
  2.1874 +        program.load_const(None)
  2.1875 +        program.return_value()
  2.1876 +
  2.1877 +    saload = laload
  2.1878 +    sastore = lastore
  2.1879 +
  2.1880 +    def sipush(self, arguments, program):
  2.1881 +        program.load_const(signed2((arguments[0] << 8) + arguments[1]))
  2.1882 +
  2.1883 +    def swap(self, arguments, program):
  2.1884 +        program.rot_two()
  2.1885 +
  2.1886 +    def tableswitch(self, code, program):
  2.1887 +
  2.1888 +        # Find the offset to the next 4 byte boundary in the code.
  2.1889 +
  2.1890 +        d, r = divmod(self.java_position + 1, 4)
  2.1891 +        to_boundary = (4 - r) % 4
  2.1892 +
  2.1893 +        # Get the pertinent arguments.
  2.1894 +
  2.1895 +        code = code[to_boundary:]
  2.1896 +        default = classfile.u4(code[0:4])
  2.1897 +        low = classfile.u4(code[4:8])
  2.1898 +        high = classfile.u4(code[8:12])
  2.1899 +
  2.1900 +        # Process the jump entries.
  2.1901 +        # NOTE: This is not the most optimal implementation.
  2.1902 +
  2.1903 +        jump_index = 12
  2.1904 +        for jump in range(low, high + 1):
  2.1905 +            offset = classfile.s4(code[jump_index:jump_index + 4])
  2.1906 +
  2.1907 +            # Calculate the branch target.
  2.1908 +
  2.1909 +            java_absolute = self.java_position + offset
  2.1910 +
  2.1911 +            # Generate branching code.
  2.1912 +
  2.1913 +            program.dup_top()                                           # Stack: key, key
  2.1914 +            program.load_const(jump)                                    # Stack: key, key, jump
  2.1915 +            program.compare_op("==")                                    # Stack: key, result
  2.1916 +            program.jump_to_label(0, "end")
  2.1917 +            program.pop_top()                                           # Stack: key
  2.1918 +            program.pop_top()                                           # Stack:
  2.1919 +            program.jump_absolute(self.position_mapping[java_absolute])
  2.1920 +
  2.1921 +            # Generate the label for the end of the branching code.
  2.1922 +
  2.1923 +            program.start_label("end")
  2.1924 +            program.pop_top()                                           # Stack: key
  2.1925 +
  2.1926 +            # Update the index.
  2.1927 +
  2.1928 +            jump_index += 4
  2.1929 +
  2.1930 +        # Generate the default.
  2.1931 +
  2.1932 +        java_absolute = self.java_position + default
  2.1933 +        program.jump_absolute(self.position_mapping[java_absolute])
  2.1934 +        return jump_index + to_boundary
  2.1935 +
  2.1936 +    def wide(self, code, program):
  2.1937 +        # NOTE: To be implemented.
  2.1938 +        return number_of_arguments
  2.1939 +
  2.1940 +def disassemble(class_file, method):
  2.1941 +    disassembler = BytecodeDisassembler(class_file)
  2.1942 +    disassembler.process(method, BytecodeDisassemblerProgram())
  2.1943 +
  2.1944 +class ClassTranslator:
  2.1945 +
  2.1946 +    """
  2.1947 +    A class which provides a wrapper around a class file and the means to
  2.1948 +    translate the represented class into a Python class.
  2.1949 +    """
  2.1950 +
  2.1951 +    def __init__(self, class_file):
  2.1952 +
  2.1953 +        "Initialise the object with the given 'class_file'."
  2.1954 +
  2.1955 +        self.class_file = class_file
  2.1956 +        self.filename = ""
  2.1957 +
  2.1958 +        for attribute in self.class_file.attributes:
  2.1959 +            if isinstance(attribute, classfile.SourceFileAttributeInfo):
  2.1960 +                self.filename = str(attribute.get_name())
  2.1961 +
  2.1962 +    def translate_method(self, method):
  2.1963 +
  2.1964 +        "Translate the given 'method' - an object obtained from the class file."
  2.1965 +
  2.1966 +        translator = BytecodeTranslator(self.class_file)
  2.1967 +        writer = BytecodeWriter()
  2.1968 +        translator.process(method, writer)
  2.1969 +        return translator, writer
  2.1970 +
  2.1971 +    def make_method(self, real_method_name, methods, global_names, namespace):
  2.1972 +
  2.1973 +        """
  2.1974 +        Make a dispatcher method with the given 'real_method_name', providing
  2.1975 +        dispatch to the supplied type-sensitive 'methods', accessing the given
  2.1976 +        'global_names' where necessary, and storing the new method in the
  2.1977 +        'namespace' provided.
  2.1978 +        """
  2.1979 +
  2.1980 +        if real_method_name == "<init>":
  2.1981 +            method_name = "__init__"
  2.1982 +        else:
  2.1983 +            method_name = real_method_name
  2.1984 +
  2.1985 +        # Where only one method exists, just make an alias.
  2.1986 +
  2.1987 +        if len(methods) == 1:
  2.1988 +            method, fn = methods[0]
  2.1989 +            namespace[method_name] = fn
  2.1990 +            return
  2.1991 +
  2.1992 +        # Write a simple bytecode dispatching mechanism.
  2.1993 +
  2.1994 +        program = BytecodeWriter()
  2.1995 +
  2.1996 +        # Remember whether any of the methods are static.
  2.1997 +        # NOTE: This should be an all or nothing situation.
  2.1998 +
  2.1999 +        method_is_static = 0
  2.2000 +
  2.2001 +        # NOTE: The code below should use dictionary-based dispatch for better performance.
  2.2002 +
  2.2003 +        for method, fn in methods:
  2.2004 +            method_is_static = real_method_name != "<init>" and method_is_static or \
  2.2005 +                classfile.has_flags(method.access_flags, [classfile.STATIC])
  2.2006 +
  2.2007 +            if method_is_static:
  2.2008 +                program.load_fast(0)                # Stack: arguments
  2.2009 +            else:
  2.2010 +                program.load_fast(1)                # Stack: arguments
  2.2011 +
  2.2012 +            program.setup_loop()
  2.2013 +            program.load_const(1)                   # Stack: arguments, 1
  2.2014 +
  2.2015 +            if method_is_static:
  2.2016 +                program.store_fast(1)               # Stack: arguments (found = 1)
  2.2017 +            else:
  2.2018 +                program.store_fast(2)               # Stack: arguments (found = 1)
  2.2019 +
  2.2020 +            # Emit a list of parameter types.
  2.2021 +
  2.2022 +            descriptor_types = method.get_descriptor()[0]
  2.2023 +            for descriptor_type in descriptor_types:
  2.2024 +                base_type, object_type, array_type = descriptor_type
  2.2025 +                python_type = classfile.descriptor_base_type_mapping[base_type]
  2.2026 +                if python_type == "instance":
  2.2027 +                    # NOTE: This will need extending.
  2.2028 +                    python_type = object_type
  2.2029 +                program.load_global(python_type)    # Stack: arguments, type, ...
  2.2030 +            program.build_list(len(descriptor_types))
  2.2031 +                                                    # Stack: arguments, types
  2.2032 +            # Make a map of arguments and types.
  2.2033 +            program.load_const(None)                # Stack: arguments, types, None
  2.2034 +            program.rot_three()                     # Stack: None, arguments, types
  2.2035 +            program.build_tuple(3)                  # Stack: tuple
  2.2036 +            program.load_global("map")              # Stack: tuple, map
  2.2037 +            program.rot_two()                       # Stack: map, tuple
  2.2038 +            program.call_function_var(0)            # Stack: list (mapping arguments to types)
  2.2039 +            # Loop over each pair.
  2.2040 +            program.get_iter()                      # Stack: iter
  2.2041 +            program.for_iter()                      # Stack: iter, (argument, type)
  2.2042 +            program.unpack_sequence(2)              # Stack: iter, type, argument
  2.2043 +            program.dup_top()                       # Stack: iter, type, argument, argument
  2.2044 +            program.load_const(None)                # Stack: iter, type, argument, argument, None
  2.2045 +            program.compare_op("is")                # Stack: iter, type, argument, result
  2.2046 +            # Missing argument?
  2.2047 +            program.jump_to_label(0, "present")
  2.2048 +            program.pop_top()                       # Stack: iter, type, argument
  2.2049 +            program.pop_top()                       # Stack: iter, type
  2.2050 +            program.pop_top()                       # Stack: iter
  2.2051 +            program.load_const(0)                   # Stack: iter, 0
  2.2052 +
  2.2053 +            if method_is_static:
  2.2054 +                program.store_fast(1)               # Stack: iter (found = 0)
  2.2055 +            else:
  2.2056 +                program.store_fast(2)               # Stack: iter (found = 0)
  2.2057 +
  2.2058 +            program.break_loop()
  2.2059 +            # Argument was present.
  2.2060 +            program.start_label("present")
  2.2061 +            program.pop_top()                       # Stack: iter, type, argument
  2.2062 +            program.rot_two()                       # Stack: iter, argument, type
  2.2063 +            program.dup_top()                       # Stack: iter, argument, type, type
  2.2064 +            program.load_const(None)                # Stack: iter, argument, type, type, None
  2.2065 +            program.compare_op("is")                # Stack: iter, argument, type, result
  2.2066 +            # Missing parameter type?
  2.2067 +            program.jump_to_label(0, "present")
  2.2068 +            program.pop_top()                       # Stack: iter, argument, type
  2.2069 +            program.pop_top()                       # Stack: iter, argument
  2.2070 +            program.pop_top()                       # Stack: iter
  2.2071 +            program.load_const(0)                   # Stack: iter, 0
  2.2072 +
  2.2073 +            if method_is_static:
  2.2074 +                program.store_fast(1)               # Stack: iter (found = 0)
  2.2075 +            else:
  2.2076 +                program.store_fast(2)               # Stack: iter (found = 0)
  2.2077 +
  2.2078 +            program.break_loop()
  2.2079 +            # Parameter was present.
  2.2080 +            program.start_label("present")
  2.2081 +            program.pop_top()                       # Stack: iter, argument, type
  2.2082 +            program.build_tuple(2)                  # Stack: iter, (argument, type)
  2.2083 +            program.load_global("isinstance")       # Stack: iter, (argument, type), isinstance
  2.2084 +            program.rot_two()                       # Stack: iter, isinstance, (argument, type)
  2.2085 +            program.call_function_var(0)            # Stack: iter, result
  2.2086 +            program.jump_to_label(1, "match")
  2.2087 +            program.pop_top()                       # Stack: iter
  2.2088 +            program.load_const(0)                   # Stack: iter, 0
  2.2089 +
  2.2090 +            if method_is_static:
  2.2091 +                program.store_fast(1)               # Stack: iter (found = 0)
  2.2092 +            else:
  2.2093 +                program.store_fast(2)               # Stack: iter (found = 0)
  2.2094 +
  2.2095 +            program.break_loop()
  2.2096 +            # Argument type and parameter type matched.
  2.2097 +            program.start_label("match")
  2.2098 +            program.pop_top()                       # Stack: iter
  2.2099 +            program.end_loop()                      # Stack:
  2.2100 +            # If all the parameters matched, call the method.
  2.2101 +
  2.2102 +            if method_is_static:
  2.2103 +                program.load_fast(1)                # Stack: match
  2.2104 +            else:
  2.2105 +                program.load_fast(2)                # Stack: match
  2.2106 +
  2.2107 +            program.jump_to_label(0, "failed")
  2.2108 +            # All the parameters matched.
  2.2109 +            program.pop_top()                       # Stack:
  2.2110 +
  2.2111 +            if method_is_static:
  2.2112 +                program.load_fast(0)                # Stack: arguments
  2.2113 +                program.load_global(str(self.class_file.this_class.get_python_name()))
  2.2114 +                                                    # Stack: arguments, class
  2.2115 +            else:
  2.2116 +                program.load_fast(1)                # Stack: arguments
  2.2117 +                program.load_fast(0)                # Stack: arguments, self
  2.2118 +
  2.2119 +            program.load_attr(str(method.get_python_name()))
  2.2120 +                                                    # Stack: arguments, method
  2.2121 +            program.rot_two()                       # Stack: method, arguments
  2.2122 +            program.call_function_var(0)            # Stack: result
  2.2123 +            program.return_value()
  2.2124 +            # Try the next method if arguments or parameters were missing or incorrect.
  2.2125 +            program.start_label("failed")
  2.2126 +            program.pop_top()                       # Stack:
  2.2127 +
  2.2128 +        # Raise an exception if nothing matched.
  2.2129 +        # NOTE: Improve this.
  2.2130 +
  2.2131 +        program.load_const("No matching method")
  2.2132 +        program.raise_varargs(1)
  2.2133 +        program.load_const(None)
  2.2134 +        program.return_value()
  2.2135 +
  2.2136 +        # Add the code as a method in the namespace.
  2.2137 +        # NOTE: One actual parameter, flags as 71 apparently means that a list
  2.2138 +        # NOTE: parameter is used in a method.
  2.2139 +
  2.2140 +        if method_is_static:
  2.2141 +            nargs = 0
  2.2142 +        else:
  2.2143 +            nargs = 1
  2.2144 +        nlocals = program.max_locals + 1
  2.2145 +
  2.2146 +        code = new.code(nargs, nlocals, program.max_stack_depth, 71, program.get_output(),
  2.2147 +            tuple(program.get_constants()), tuple(program.get_names()), tuple(self.make_varnames(nlocals, method_is_static)),
  2.2148 +            self.filename, method_name, 0, "")
  2.2149 +        fn = new.function(code, global_names)
  2.2150 +
  2.2151 +        if method_is_static:
  2.2152 +            fn = staticmethod(fn)
  2.2153 +
  2.2154 +        namespace[method_name] = fn
  2.2155 +
  2.2156 +    def process(self, global_names):
  2.2157 +
  2.2158 +        """
  2.2159 +        Process the class, storing it in the 'global_names' dictionary provided.
  2.2160 +        Return a tuple containing the class and a list of external names
  2.2161 +        referenced by the class's methods.
  2.2162 +        """
  2.2163 +
  2.2164 +        namespace = {}
  2.2165 +
  2.2166 +        # Make the fields.
  2.2167 +
  2.2168 +        for field in self.class_file.fields:
  2.2169 +            if classfile.has_flags(field.access_flags, [classfile.STATIC]):
  2.2170 +                field_name = str(field.get_python_name())
  2.2171 +                namespace[field_name] = None
  2.2172 +
  2.2173 +        # Make the methods.
  2.2174 +
  2.2175 +        real_methods = {}
  2.2176 +        external_names = []
  2.2177 +
  2.2178 +        for method in self.class_file.methods:
  2.2179 +            real_method_name = str(method.get_name())
  2.2180 +            method_name = str(method.get_python_name())
  2.2181 +
  2.2182 +            translator, writer = self.translate_method(method)
  2.2183 +
  2.2184 +            # Add external names to the master list.
  2.2185 +
  2.2186 +            for external_name in writer.external_names:
  2.2187 +                if external_name not in external_names:
  2.2188 +                    external_names.append(external_name)
  2.2189 +
  2.2190 +            # Fix up special class initialisation methods and static methods.
  2.2191 +
  2.2192 +            method_is_static = real_method_name != "<init>" and classfile.has_flags(method.access_flags, [classfile.STATIC])
  2.2193 +            if method_is_static:
  2.2194 +                nargs = len(method.get_descriptor()[0])
  2.2195 +            else:
  2.2196 +                nargs = len(method.get_descriptor()[0]) + 1
  2.2197 +            nlocals = writer.max_locals + 1
  2.2198 +            flags = 67
  2.2199 +
  2.2200 +            # NOTE: Add line number table later.
  2.2201 +
  2.2202 +            code = new.code(nargs, nlocals, writer.max_stack_depth, flags, writer.get_output(),
  2.2203 +                tuple(writer.get_constants()), tuple(writer.get_names()),
  2.2204 +                tuple(self.make_varnames(nlocals, method_is_static)), self.filename, method_name, 0, "")
  2.2205 +
  2.2206 +            # NOTE: May need more globals.
  2.2207 +
  2.2208 +            fn = new.function(code, global_names)
  2.2209 +
  2.2210 +            # Fix up special class initialisation methods and static methods.
  2.2211 +
  2.2212 +            if method_is_static:
  2.2213 +                fn = staticmethod(fn)
  2.2214 +
  2.2215 +            # Remember the real method name and the corresponding methods produced.
  2.2216 +
  2.2217 +            if not real_methods.has_key(real_method_name):
  2.2218 +                real_methods[real_method_name] = []
  2.2219 +            real_methods[real_method_name].append((method, fn))
  2.2220 +
  2.2221 +            # Add the method to the class's namespace.
  2.2222 +
  2.2223 +            namespace[method_name] = fn
  2.2224 +
  2.2225 +        # Define superclasses.
  2.2226 +
  2.2227 +        bases = self.get_base_classes(global_names)
  2.2228 +
  2.2229 +        # Define method dispatchers.
  2.2230 +
  2.2231 +        for real_method_name, methods in real_methods.items():
  2.2232 +            if real_method_name != "<clinit>":
  2.2233 +                self.make_method(real_method_name, methods, global_names, namespace)
  2.2234 +
  2.2235 +        # Use only the last part of the fully qualified name.
  2.2236 +
  2.2237 +        full_class_name = str(self.class_file.this_class.get_python_name())
  2.2238 +        class_name = full_class_name.split(".")[-1]
  2.2239 +        cls = new.classobj(class_name, bases, namespace)
  2.2240 +        global_names[cls.__name__] = cls
  2.2241 +
  2.2242 +        return cls, external_names
  2.2243 +
  2.2244 +    def get_base_classes(self, global_names):
  2.2245 +
  2.2246 +        """
  2.2247 +        Identify the superclass, then either load it from the given
  2.2248 +        'global_names' if available, or import the class from its parent module.
  2.2249 +        Return a tuple containing all base classes (typically a single element
  2.2250 +        tuple).
  2.2251 +        """
  2.2252 +
  2.2253 +        original_name = str(self.class_file.super_class.get_name())
  2.2254 +        full_this_class_name = str(self.class_file.this_class.get_python_name())
  2.2255 +        this_class_name_parts = full_this_class_name.split(".")
  2.2256 +        this_class_module_name = ".".join(this_class_name_parts[:-1])
  2.2257 +        full_super_class_name = str(self.class_file.super_class.get_python_name())
  2.2258 +        super_class_name_parts = full_super_class_name.split(".")
  2.2259 +        super_class_name = super_class_name_parts[-1]
  2.2260 +        super_class_module_name = ".".join(super_class_name_parts[:-1])
  2.2261 +        if super_class_module_name == "":
  2.2262 +            obj = global_names[super_class_name]
  2.2263 +        elif super_class_module_name == this_class_module_name:
  2.2264 +            obj = global_names[super_class_name]
  2.2265 +        else:
  2.2266 +            #print "Importing", super_class_module_name, super_class_name
  2.2267 +            obj = __import__(super_class_module_name, global_names, {}, [])
  2.2268 +            for super_class_name_part in super_class_name_parts[1:] or [super_class_name]:
  2.2269 +                #print "*", obj, super_class_name_part
  2.2270 +                obj = getattr(obj, super_class_name_part)
  2.2271 +        return (obj,)
  2.2272 +
  2.2273 +    def make_varnames(self, nlocals, method_is_static=0):
  2.2274 +
  2.2275 +        """
  2.2276 +        A utility method which invents variable names for the given number -
  2.2277 +        'nlocals' - of local variables in a method. Returns a list of such
  2.2278 +        variable names.
  2.2279 +
  2.2280 +        If the optional 'method_is_static' is set to true, do not use "self" as
  2.2281 +        the first argument name.
  2.2282 +        """
  2.2283 +
  2.2284 +        if method_is_static:
  2.2285 +            l = ["cls"]
  2.2286 +        else:
  2.2287 +            l = ["self"]
  2.2288 +        for i in range(1, nlocals):
  2.2289 +            l.append("_l%s" % i)
  2.2290 +        return l[:nlocals]
  2.2291 +
  2.2292 +# Test functions, useful for tracing generated bytecode operations.
  2.2293 +
  2.2294 +def _map(*args):
  2.2295 +    print args
  2.2296 +    return apply(__builtins__.map, args)
  2.2297 +
  2.2298 +def _isinstance(*args):
  2.2299 +    print args
  2.2300 +    return apply(__builtins__.isinstance, args)
  2.2301 +
  2.2302 +if __name__ == "__main__":
  2.2303 +    import sys
  2.2304 +    import dis
  2.2305 +    global_names = globals()
  2.2306 +    #global_names["isinstance"] = _isinstance
  2.2307 +    #global_names["map"] = _map
  2.2308 +    for filename in sys.argv[1:]:
  2.2309 +        f = open(filename, "rb")
  2.2310 +        c = classfile.ClassFile(f.read())
  2.2311 +        translator = ClassTranslator(c)
  2.2312 +        cls, external_names = translator.process(global_names)
  2.2313 +
  2.2314 +# vim: tabstop=4 expandtab shiftwidth=4
     3.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     3.2 +++ b/javaclass/classfile.py	Fri Jan 21 17:05:06 2005 +0100
     3.3 @@ -0,0 +1,633 @@
     3.4 +#!/usr/bin/env python
     3.5 +
     3.6 +"""
     3.7 +Java class file decoder. Specification found at the following URL:
     3.8 +http://java.sun.com/docs/books/vmspec/2nd-edition/html/ClassFile.doc.html
     3.9 +"""
    3.10 +
    3.11 +import struct # for general decoding of class files
    3.12 +
    3.13 +# Utility functions.
    3.14 +
    3.15 +def u1(data):
    3.16 +    return struct.unpack(">B", data[0:1])[0]
    3.17 +
    3.18 +def u2(data):
    3.19 +    return struct.unpack(">H", data[0:2])[0]
    3.20 +
    3.21 +def s2(data):
    3.22 +    return struct.unpack(">h", data[0:2])[0]
    3.23 +
    3.24 +def u4(data):
    3.25 +    return struct.unpack(">L", data[0:4])[0]
    3.26 +
    3.27 +def s4(data):
    3.28 +    return struct.unpack(">l", data[0:4])[0]
    3.29 +
    3.30 +def s8(data):
    3.31 +    return struct.unpack(">q", data[0:8])[0]
    3.32 +
    3.33 +def f4(data):
    3.34 +    return struct.unpack(">f", data[0:4])[0]
    3.35 +
    3.36 +def f8(data):
    3.37 +    return struct.unpack(">d", data[0:8])[0]
    3.38 +
    3.39 +# Useful tables and constants.
    3.40 +
    3.41 +descriptor_base_type_mapping = {
    3.42 +    "B" : "int",
    3.43 +    "C" : "str",
    3.44 +    "D" : "float",
    3.45 +    "F" : "float",
    3.46 +    "I" : "int",
    3.47 +    "J" : "int",
    3.48 +    "L" : "object",
    3.49 +    "S" : "int",
    3.50 +    "Z" : "bool",
    3.51 +    "[" : "list"
    3.52 +    }
    3.53 +
    3.54 +PUBLIC, PRIVATE, PROTECTED, STATIC, FINAL,  SUPER,  SYNCHRONIZED, VOLATILE, TRANSIENT, NATIVE, INTERFACE, ABSTRACT, STRICT = \
    3.55 +0x0001, 0x0002,  0x0004,    0x0008, 0x0010, 0x0020, 0x0020,       0x0040,   0x0080,    0x0100, 0x0200,    0x0400,   0x0800
    3.56 +
    3.57 +def has_flags(flags, desired):
    3.58 +    desired_flags = reduce(lambda a, b: a | b, desired, 0)
    3.59 +    return (flags & desired_flags) == desired_flags
    3.60 +
    3.61 +# Useful mix-ins.
    3.62 +
    3.63 +class PythonMethodUtils:
    3.64 +    symbol_sep = "___" # was "$"
    3.65 +    type_sep = "__" # replaces "/"
    3.66 +    array_sep = "_array_" # was "[]"
    3.67 +    base_seps = ("_", "_") # was "<" and ">"
    3.68 +
    3.69 +    def get_unqualified_python_name(self):
    3.70 +        name = self.get_name()
    3.71 +        if str(name) == "<init>":
    3.72 +            return "__init__"
    3.73 +        elif str(name) == "<clinit>":
    3.74 +            return "__clinit__"
    3.75 +        else:
    3.76 +            return str(name)
    3.77 +
    3.78 +    def get_python_name(self):
    3.79 +        name = self.get_unqualified_python_name()
    3.80 +        if name == "__clinit__":
    3.81 +            return name
    3.82 +        return name + self.symbol_sep + self._get_descriptor_as_name()
    3.83 +
    3.84 +    def _get_descriptor_as_name(self):
    3.85 +        l = []
    3.86 +        for descriptor_type in self.get_descriptor()[0]:
    3.87 +            l.append(self._get_type_as_name(descriptor_type))
    3.88 +        return self.symbol_sep.join(l)
    3.89 +
    3.90 +    def _get_type_as_name(self, descriptor_type, s=""):
    3.91 +        base_type, object_type, array_type = descriptor_type
    3.92 +        if base_type == "L":
    3.93 +            return object_type.replace("/", self.type_sep) + s
    3.94 +        elif base_type == "[":
    3.95 +            return self._get_type_as_name(array_type, s + self.array_sep)
    3.96 +        else:
    3.97 +            return self.base_seps[0] + base_type + self.base_seps[1] + s
    3.98 +
    3.99 +class PythonNameUtils:
   3.100 +    def get_python_name(self):
   3.101 +        # NOTE: This may not be comprehensive.
   3.102 +        if not str(self.get_name()).startswith("["):
   3.103 +            return str(self.get_name()).replace("/", ".")
   3.104 +        else:
   3.105 +            return self._get_type_name(
   3.106 +                get_field_descriptor(
   3.107 +                    str(self.get_name())
   3.108 +                    )
   3.109 +                ).replace("/", ".")
   3.110 +
   3.111 +    def _get_type_name(self, descriptor_type):
   3.112 +        base_type, object_type, array_type = descriptor_type
   3.113 +        if base_type == "L":
   3.114 +            return object_type
   3.115 +        elif base_type == "[":
   3.116 +            return self._get_type_name(array_type)
   3.117 +        else:
   3.118 +            return descriptor_base_type_mapping[base_type]
   3.119 +
   3.120 +class NameUtils:
   3.121 +    def get_name(self):
   3.122 +        if self.name_index != 0:
   3.123 +            return self.class_file.constants[self.name_index - 1]
   3.124 +        else:
   3.125 +            # Some name indexes are zero to indicate special conditions.
   3.126 +            return None
   3.127 +
   3.128 +class NameAndTypeUtils:
   3.129 +    def get_name(self):
   3.130 +        if self.name_and_type_index != 0:
   3.131 +            return self.class_file.constants[self.name_and_type_index - 1].get_name()
   3.132 +        else:
   3.133 +            # Some name indexes are zero to indicate special conditions.
   3.134 +            return None
   3.135 +
   3.136 +    def get_field_descriptor(self):
   3.137 +        if self.name_and_type_index != 0:
   3.138 +            return self.class_file.constants[self.name_and_type_index - 1].get_field_descriptor()
   3.139 +        else:
   3.140 +            # Some name indexes are zero to indicate special conditions.
   3.141 +            return None
   3.142 +
   3.143 +    def get_method_descriptor(self):
   3.144 +        if self.name_and_type_index != 0:
   3.145 +            return self.class_file.constants[self.name_and_type_index - 1].get_method_descriptor()
   3.146 +        else:
   3.147 +            # Some name indexes are zero to indicate special conditions.
   3.148 +            return None
   3.149 +
   3.150 +    def get_class(self):
   3.151 +        return self.class_file.constants[self.class_index - 1]
   3.152 +
   3.153 +# Symbol parsing.
   3.154 +
   3.155 +def get_method_descriptor(s):
   3.156 +    assert s[0] == "("
   3.157 +    params = []
   3.158 +    s = s[1:]
   3.159 +    while s[0] != ")":
   3.160 +        parameter_descriptor, s = _get_parameter_descriptor(s)
   3.161 +        params.append(parameter_descriptor)
   3.162 +    if s[1] != "V":
   3.163 +        return_type, s = _get_field_type(s[1:])
   3.164 +    else:
   3.165 +        return_type, s = None, s[1:]
   3.166 +    return params, return_type
   3.167 +
   3.168 +def get_field_descriptor(s):
   3.169 +    return _get_field_type(s)[0]
   3.170 +
   3.171 +def _get_parameter_descriptor(s):
   3.172 +    return _get_field_type(s)
   3.173 +
   3.174 +def _get_component_type(s):
   3.175 +    return _get_field_type(s)
   3.176 +
   3.177 +def _get_field_type(s):
   3.178 +    base_type, s = _get_base_type(s)
   3.179 +    object_type = None
   3.180 +    array_type = None
   3.181 +    if base_type == "L":
   3.182 +        object_type, s = _get_object_type(s)
   3.183 +    elif base_type == "[":
   3.184 +        array_type, s = _get_array_type(s)
   3.185 +    return (base_type, object_type, array_type), s
   3.186 +
   3.187 +def _get_base_type(s):
   3.188 +    if len(s) > 0:
   3.189 +        return s[0], s[1:]
   3.190 +    else:
   3.191 +        return None, s
   3.192 +
   3.193 +def _get_object_type(s):
   3.194 +    if len(s) > 0:
   3.195 +        s_end = s.find(";")
   3.196 +        assert s_end != -1
   3.197 +        return s[:s_end], s[s_end+1:]
   3.198 +    else:
   3.199 +        return None, s
   3.200 +
   3.201 +def _get_array_type(s):
   3.202 +    if len(s) > 0:
   3.203 +        return _get_component_type(s)
   3.204 +    else:
   3.205 +        return None, s
   3.206 +
   3.207 +# Constant information.
   3.208 +
   3.209 +class ClassInfo(NameUtils, PythonNameUtils):
   3.210 +    def init(self, data, class_file):
   3.211 +        self.class_file = class_file
   3.212 +        self.name_index = u2(data[0:2])
   3.213 +        return data[2:]
   3.214 +
   3.215 +class RefInfo(NameAndTypeUtils):
   3.216 +    def init(self, data, class_file):
   3.217 +        self.class_file = class_file
   3.218 +        self.class_index = u2(data[0:2])
   3.219 +        self.name_and_type_index = u2(data[2:4])
   3.220 +        return data[4:]
   3.221 +
   3.222 +class FieldRefInfo(RefInfo, PythonNameUtils):
   3.223 +    def get_descriptor(self):
   3.224 +        return RefInfo.get_field_descriptor(self)
   3.225 +
   3.226 +class MethodRefInfo(RefInfo, PythonMethodUtils):
   3.227 +    def get_descriptor(self):
   3.228 +        return RefInfo.get_method_descriptor(self)
   3.229 +
   3.230 +class InterfaceMethodRefInfo(MethodRefInfo):
   3.231 +    pass
   3.232 +
   3.233 +class NameAndTypeInfo(NameUtils, PythonNameUtils):
   3.234 +    def init(self, data, class_file):
   3.235 +        self.class_file = class_file
   3.236 +        self.name_index = u2(data[0:2])
   3.237 +        self.descriptor_index = u2(data[2:4])
   3.238 +        return data[4:]
   3.239 +
   3.240 +    def get_field_descriptor(self):
   3.241 +        return get_field_descriptor(unicode(self.class_file.constants[self.descriptor_index - 1]))
   3.242 +
   3.243 +    def get_method_descriptor(self):
   3.244 +        return get_method_descriptor(unicode(self.class_file.constants[self.descriptor_index - 1]))
   3.245 +
   3.246 +class Utf8Info:
   3.247 +    def init(self, data, class_file):
   3.248 +        self.class_file = class_file
   3.249 +        self.length = u2(data[0:2])
   3.250 +        self.bytes = data[2:2+self.length]
   3.251 +        return data[2+self.length:]
   3.252 +
   3.253 +    def __str__(self):
   3.254 +        return self.bytes
   3.255 +
   3.256 +    def __unicode__(self):
   3.257 +        return unicode(self.bytes, "utf-8")
   3.258 +
   3.259 +    def get_value(self):
   3.260 +        return str(self)
   3.261 +
   3.262 +class StringInfo:
   3.263 +    def init(self, data, class_file):
   3.264 +        self.class_file = class_file
   3.265 +        self.string_index = u2(data[0:2])
   3.266 +        return data[2:]
   3.267 +
   3.268 +    def __str__(self):
   3.269 +        return str(self.class_file.constants[self.string_index - 1])
   3.270 +
   3.271 +    def __unicode__(self):
   3.272 +        return unicode(self.class_file.constants[self.string_index - 1])
   3.273 +
   3.274 +    def get_value(self):
   3.275 +        return str(self)
   3.276 +
   3.277 +class SmallNumInfo:
   3.278 +    def init(self, data, class_file):
   3.279 +        self.class_file = class_file
   3.280 +        self.bytes = data[0:4]
   3.281 +        return data[4:]
   3.282 +
   3.283 +class IntegerInfo(SmallNumInfo):
   3.284 +    def get_value(self):
   3.285 +        return s4(self.bytes)
   3.286 +
   3.287 +class FloatInfo(SmallNumInfo):
   3.288 +    def get_value(self):
   3.289 +        return f4(self.bytes)
   3.290 +
   3.291 +class LargeNumInfo:
   3.292 +    def init(self, data, class_file):
   3.293 +        self.class_file = class_file
   3.294 +        self.high_bytes = data[0:4]
   3.295 +        self.low_bytes = data[4:8]
   3.296 +        return data[8:]
   3.297 +
   3.298 +class LongInfo(LargeNumInfo):
   3.299 +    def get_value(self):
   3.300 +        return s8(self.high_bytes + self.low_bytes)
   3.301 +
   3.302 +class DoubleInfo(LargeNumInfo):
   3.303 +    def get_value(self):
   3.304 +        return f8(self.high_bytes + self.low_bytes)
   3.305 +
   3.306 +# Other information.
   3.307 +# Objects of these classes are generally aware of the class they reside in.
   3.308 +
   3.309 +class ItemInfo(NameUtils):
   3.310 +    def init(self, data, class_file):
   3.311 +        self.class_file = class_file
   3.312 +        self.access_flags = u2(data[0:2])
   3.313 +        self.name_index = u2(data[2:4])
   3.314 +        self.descriptor_index = u2(data[4:6])
   3.315 +        self.attributes, data = self.class_file._get_attributes(data[6:])
   3.316 +        return data
   3.317 +
   3.318 +class FieldInfo(ItemInfo, PythonNameUtils):
   3.319 +    def get_descriptor(self):
   3.320 +        return get_field_descriptor(unicode(self.class_file.constants[self.descriptor_index - 1]))
   3.321 +
   3.322 +class MethodInfo(ItemInfo, PythonMethodUtils):
   3.323 +    def get_descriptor(self):
   3.324 +        return get_method_descriptor(unicode(self.class_file.constants[self.descriptor_index - 1]))
   3.325 +
   3.326 +class AttributeInfo:
   3.327 +    def init(self, data, class_file):
   3.328 +        self.attribute_length = u4(data[0:4])
   3.329 +        self.info = data[4:4+self.attribute_length]
   3.330 +        return data[4+self.attribute_length:]
   3.331 +
   3.332 +# NOTE: Decode the different attribute formats.
   3.333 +
   3.334 +class SourceFileAttributeInfo(AttributeInfo, NameUtils, PythonNameUtils):
   3.335 +    def init(self, data, class_file):
   3.336 +        self.class_file = class_file
   3.337 +        self.attribute_length = u4(data[0:4])
   3.338 +        # Permit the NameUtils mix-in.
   3.339 +        self.name_index = self.sourcefile_index = u2(data[4:6])
   3.340 +        return data[6:]
   3.341 +
   3.342 +class ConstantValueAttributeInfo(AttributeInfo):
   3.343 +    def init(self, data, class_file):
   3.344 +        self.class_file = class_file
   3.345 +        self.attribute_length = u4(data[0:4])
   3.346 +        self.constant_value_index = u2(data[4:6])
   3.347 +        assert 4+self.attribute_length == 6
   3.348 +        return data[4+self.attribute_length:]
   3.349 +
   3.350 +    def get_value(self):
   3.351 +        return self.class_file.constants[self.constant_value_index - 1].get_value()
   3.352 +
   3.353 +class CodeAttributeInfo(AttributeInfo):
   3.354 +    def init(self, data, class_file):
   3.355 +        self.class_file = class_file
   3.356 +        self.attribute_length = u4(data[0:4])
   3.357 +        self.max_stack = u2(data[4:6])
   3.358 +        self.max_locals = u2(data[6:8])
   3.359 +        self.code_length = u4(data[8:12])
   3.360 +        end_of_code = 12+self.code_length
   3.361 +        self.code = data[12:end_of_code]
   3.362 +        self.exception_table_length = u2(data[end_of_code:end_of_code+2])
   3.363 +        self.exception_table = []
   3.364 +        data = data[end_of_code + 2:]
   3.365 +        for i in range(0, self.exception_table_length):
   3.366 +            exception = ExceptionInfo()
   3.367 +            data = exception.init(data)
   3.368 +            self.exception_table.append(exception)
   3.369 +        self.attributes, data = self.class_file._get_attributes(data)
   3.370 +        return data
   3.371 +
   3.372 +class ExceptionsAttributeInfo(AttributeInfo):
   3.373 +    def init(self, data, class_file):
   3.374 +        self.class_file = class_file
   3.375 +        self.attribute_length = u4(data[0:4])
   3.376 +        self.number_of_exceptions = u2(data[4:6])
   3.377 +        self.exception_index_table = []
   3.378 +        index = 6
   3.379 +        for i in range(0, self.number_of_exceptions):
   3.380 +            self.exception_index_table.append(u2(data[index:index+2]))
   3.381 +            index += 2
   3.382 +        return data[index:]
   3.383 +
   3.384 +    def get_exception(self, i):
   3.385 +        exception_index = self.exception_index_table[i]
   3.386 +        return self.class_file.constants[exception_index - 1]
   3.387 +
   3.388 +class InnerClassesAttributeInfo(AttributeInfo):
   3.389 +    def init(self, data, class_file):
   3.390 +        self.class_file = class_file
   3.391 +        self.attribute_length = u4(data[0:4])
   3.392 +        self.number_of_classes = u2(data[4:6])
   3.393 +        self.classes = []
   3.394 +        data = data[6:]
   3.395 +        for i in range(0, self.number_of_classes):
   3.396 +            inner_class = InnerClassInfo()
   3.397 +            data = inner_class.init(data, self.class_file)
   3.398 +            self.classes.append(inner_class)
   3.399 +        return data
   3.400 +
   3.401 +class SyntheticAttributeInfo(AttributeInfo):
   3.402 +    pass
   3.403 +
   3.404 +class LineNumberAttributeInfo(AttributeInfo):
   3.405 +    def init(self, data, class_file):
   3.406 +        self.class_file = class_file
   3.407 +        self.attribute_length = u4(data[0:4])
   3.408 +        self.line_number_table_length = u2(data[4:6])
   3.409 +        self.line_number_table = []
   3.410 +        data = data[6:]
   3.411 +        for i in range(0, self.line_number_table_length):
   3.412 +            line_number = LineNumberInfo()
   3.413 +            data = line_number.init(data)
   3.414 +            self.line_number_table.append(line_number)
   3.415 +        return data
   3.416 +
   3.417 +class LocalVariableAttributeInfo(AttributeInfo):
   3.418 +    def init(self, data, class_file):
   3.419 +        self.class_file = class_file
   3.420 +        self.attribute_length = u4(data[0:4])
   3.421 +        self.local_variable_table_length = u2(data[4:6])
   3.422 +        self.local_variable_table = []
   3.423 +        data = data[6:]
   3.424 +        for i in range(0, self.local_variable_table_length):
   3.425 +            local_variable = LocalVariableInfo()
   3.426 +            data = local_variable.init(data, self.class_file)
   3.427 +            self.local_variable_table.append(local_variable)
   3.428 +        return data
   3.429 +
   3.430 +class DeprecatedAttributeInfo(AttributeInfo):
   3.431 +    pass
   3.432 +
   3.433 +# Child classes of the attribute information classes.
   3.434 +
   3.435 +class ExceptionInfo:
   3.436 +    def init(self, data):
   3.437 +        self.start_pc = u2(data[0:2])
   3.438 +        self.end_pc = u2(data[2:4])
   3.439 +        self.handler_pc = u2(data[4:6])
   3.440 +        self.catch_type = u2(data[6:8])
   3.441 +        return data[8:]
   3.442 +
   3.443 +class InnerClassInfo(NameUtils):
   3.444 +    def init(self, data, class_file):
   3.445 +        self.class_file = class_file
   3.446 +        self.inner_class_info_index = u2(data[0:2])
   3.447 +        self.outer_class_info_index = u2(data[2:4])
   3.448 +        # Permit the NameUtils mix-in.
   3.449 +        self.name_index = self.inner_name_index = u2(data[4:6])
   3.450 +        self.inner_class_access_flags = u2(data[6:8])
   3.451 +        return data[8:]
   3.452 +
   3.453 +class LineNumberInfo:
   3.454 +    def init(self, data):
   3.455 +        self.start_pc = u2(data[0:2])
   3.456 +        self.line_number = u2(data[2:4])
   3.457 +        return data[4:]
   3.458 +
   3.459 +class LocalVariableInfo(NameUtils, PythonNameUtils):
   3.460 +    def init(self, data, class_file):
   3.461 +        self.class_file = class_file
   3.462 +        self.start_pc = u2(data[0:2])
   3.463 +        self.length = u2(data[2:4])
   3.464 +        self.name_index = u2(data[4:6])
   3.465 +        self.descriptor_index = u2(data[6:8])
   3.466 +        self.index = u2(data[8:10])
   3.467 +        return data[10:]
   3.468 +
   3.469 +    def get_descriptor(self):
   3.470 +        return get_field_descriptor(unicode(self.class_file.constants[self.descriptor_index - 1]))
   3.471 +
   3.472 +# Exceptions.
   3.473 +
   3.474 +class UnknownTag(Exception):
   3.475 +    pass
   3.476 +
   3.477 +class UnknownAttribute(Exception):
   3.478 +    pass
   3.479 +
   3.480 +# Abstractions for the main structures.
   3.481 +
   3.482 +class ClassFile:
   3.483 +
   3.484 +    "A class representing a Java class file."
   3.485 +
   3.486 +    def __init__(self, s):
   3.487 +
   3.488 +        """
   3.489 +        Process the given string 's', populating the object with the class
   3.490 +        file's details.
   3.491 +        """
   3.492 +
   3.493 +        self.constants, s = self._get_constants(s[8:])
   3.494 +        self.access_flags, s = self._get_access_flags(s)
   3.495 +        self.this_class, s = self._get_this_class(s)
   3.496 +        self.super_class, s = self._get_super_class(s)
   3.497 +        self.interfaces, s = self._get_interfaces(s)
   3.498 +        self.fields, s = self._get_fields(s)
   3.499 +        self.methods, s = self._get_methods(s)
   3.500 +        self.attributes, s = self._get_attributes(s)
   3.501 +
   3.502 +    def _decode_const(self, s):
   3.503 +        tag = u1(s[0:1])
   3.504 +        if tag == 1:
   3.505 +            const = Utf8Info()
   3.506 +        elif tag == 3:
   3.507 +            const = IntegerInfo()
   3.508 +        elif tag == 4:
   3.509 +            const = FloatInfo()
   3.510 +        elif tag == 5:
   3.511 +            const = LongInfo()
   3.512 +        elif tag == 6:
   3.513 +            const = DoubleInfo()
   3.514 +        elif tag == 7:
   3.515 +            const = ClassInfo()
   3.516 +        elif tag == 8:
   3.517 +            const = StringInfo()
   3.518 +        elif tag == 9:
   3.519 +            const = FieldRefInfo()
   3.520 +        elif tag == 10:
   3.521 +            const = MethodRefInfo()
   3.522 +        elif tag == 11:
   3.523 +            const = InterfaceMethodRefInfo()
   3.524 +        elif tag == 12:
   3.525 +            const = NameAndTypeInfo()
   3.526 +        else:
   3.527 +            raise UnknownTag, tag
   3.528 +
   3.529 +        # Initialise the constant object.
   3.530 +
   3.531 +        s = const.init(s[1:], self)
   3.532 +        return const, s
   3.533 +
   3.534 +    def _get_constants_from_table(self, count, s):
   3.535 +        l = []
   3.536 +        # Have to skip certain entries specially.
   3.537 +        i = 1
   3.538 +        while i < count:
   3.539 +            c, s = self._decode_const(s)
   3.540 +            l.append(c)
   3.541 +            # Add a blank entry after "large" entries.
   3.542 +            if isinstance(c, LargeNumInfo):
   3.543 +                l.append(None)
   3.544 +                i += 1
   3.545 +            i += 1
   3.546 +        return l, s
   3.547 +
   3.548 +    def _get_items_from_table(self, cls, number, s):
   3.549 +        l = []
   3.550 +        for i in range(0, number):
   3.551 +            f = cls()
   3.552 +            s = f.init(s, self)
   3.553 +            l.append(f)
   3.554 +        return l, s
   3.555 +
   3.556 +    def _get_methods_from_table(self, number, s):
   3.557 +        return self._get_items_from_table(MethodInfo, number, s)
   3.558 +
   3.559 +    def _get_fields_from_table(self, number, s):
   3.560 +        return self._get_items_from_table(FieldInfo, number, s)
   3.561 +
   3.562 +    def _get_attribute_from_table(self, s):
   3.563 +        attribute_name_index = u2(s[0:2])
   3.564 +        constant_name = self.constants[attribute_name_index - 1].bytes
   3.565 +        if constant_name == "SourceFile":
   3.566 +            attribute = SourceFileAttributeInfo()
   3.567 +        elif constant_name == "ConstantValue":
   3.568 +            attribute = ConstantValueAttributeInfo()
   3.569 +        elif constant_name == "Code":
   3.570 +            attribute = CodeAttributeInfo()
   3.571 +        elif constant_name == "Exceptions":
   3.572 +            attribute = ExceptionsAttributeInfo()
   3.573 +        elif constant_name == "InnerClasses":
   3.574 +            attribute = InnerClassesAttributeInfo()
   3.575 +        elif constant_name == "Synthetic":
   3.576 +            attribute = SyntheticAttributeInfo()
   3.577 +        elif constant_name == "LineNumberTable":
   3.578 +            attribute = LineNumberAttributeInfo()
   3.579 +        elif constant_name == "LocalVariableTable":
   3.580 +            attribute = LocalVariableAttributeInfo()
   3.581 +        elif constant_name == "Deprecated":
   3.582 +            attribute = DeprecatedAttributeInfo()
   3.583 +        else:
   3.584 +            raise UnknownAttribute, constant_name
   3.585 +        s = attribute.init(s[2:], self)
   3.586 +        return attribute, s
   3.587 +
   3.588 +    def _get_attributes_from_table(self, number, s):
   3.589 +        attributes = []
   3.590 +        for i in range(0, number):
   3.591 +            attribute, s = self._get_attribute_from_table(s)
   3.592 +            attributes.append(attribute)
   3.593 +        return attributes, s
   3.594 +
   3.595 +    def _get_constants(self, s):
   3.596 +        count = u2(s[0:2])
   3.597 +        return self._get_constants_from_table(count, s[2:])
   3.598 +
   3.599 +    def _get_access_flags(self, s):
   3.600 +        return u2(s[0:2]), s[2:]
   3.601 +
   3.602 +    def _get_this_class(self, s):
   3.603 +        index = u2(s[0:2])
   3.604 +        return self.constants[index - 1], s[2:]
   3.605 +
   3.606 +    _get_super_class = _get_this_class
   3.607 +
   3.608 +    def _get_interfaces(self, s):
   3.609 +        interfaces = []
   3.610 +        number = u2(s[0:2])
   3.611 +        s = s[2:]
   3.612 +        for i in range(0, number):
   3.613 +            index = u2(s[0:2])
   3.614 +            interfaces.append(self.constants[index - 1])
   3.615 +            s = s[2:]
   3.616 +        return interfaces, s
   3.617 +
   3.618 +    def _get_fields(self, s):
   3.619 +        number = u2(s[0:2])
   3.620 +        return self._get_fields_from_table(number, s[2:])
   3.621 +
   3.622 +    def _get_attributes(self, s):
   3.623 +        number = u2(s[0:2])
   3.624 +        return self._get_attributes_from_table(number, s[2:])
   3.625 +
   3.626 +    def _get_methods(self, s):
   3.627 +        number = u2(s[0:2])
   3.628 +        return self._get_methods_from_table(number, s[2:])
   3.629 +
   3.630 +if __name__ == "__main__":
   3.631 +    import sys
   3.632 +    f = open(sys.argv[1], "rb")
   3.633 +    c = ClassFile(f.read())
   3.634 +    f.close()
   3.635 +
   3.636 +# vim: tabstop=4 expandtab shiftwidth=4
     4.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     4.2 +++ b/javaclass/classhook.py	Fri Jan 21 17:05:06 2005 +0100
     4.3 @@ -0,0 +1,384 @@
     4.4 +#!/usr/bin/env python
     4.5 +
     4.6 +import ihooks # for the import machinery
     4.7 +import os, glob # for getting suitably-named files
     4.8 +from imp import PY_SOURCE, PKG_DIRECTORY, C_BUILTIN # import machinery magic
     4.9 +import classfile, bytecode # Java class support
    4.10 +import zipfile # for Java archive inspection
    4.11 +
    4.12 +# NOTE: Arbitrary constants pulled from thin air.
    4.13 +
    4.14 +JAVA_PACKAGE = 20041113
    4.15 +JAVA_CLASS = 20041114
    4.16 +JAVA_ARCHIVE = 20041115
    4.17 +
    4.18 +class ClassHooks(ihooks.Hooks):
    4.19 +
    4.20 +    "A filesystem hooks class providing information about supported files."
    4.21 +
    4.22 +    def get_suffixes(self):
    4.23 +
    4.24 +        "Return the recognised suffixes."
    4.25 +
    4.26 +        return [("", "", JAVA_PACKAGE), (os.extsep + "jar", "r", JAVA_ARCHIVE)] + ihooks.Hooks.get_suffixes(self)
    4.27 +
    4.28 +    def path_isdir(self, x, archive=None):
    4.29 +
    4.30 +        "Return whether 'x' is a directory in the given 'archive'."
    4.31 +
    4.32 +        if archive is None:
    4.33 +            return ihooks.Hooks.path_isdir(self, x)
    4.34 +
    4.35 +        return self._get_dirname(x) in archive.namelist()
    4.36 +
    4.37 +    def _get_dirname(self, x):
    4.38 +
    4.39 +        """
    4.40 +        Return the directory name for 'x'.
    4.41 +        In zip files, the presence of "/" seems to indicate a directory.
    4.42 +        """
    4.43 +
    4.44 +        if x.endswith("/"):
    4.45 +            return x
    4.46 +        else:
    4.47 +            return x + "/"
    4.48 +
    4.49 +    def listdir(self, x, archive=None):
    4.50 +
    4.51 +        "Return the contents of the directory 'x' in the given 'archive'."
    4.52 +
    4.53 +        if archive is None:
    4.54 +            return ihooks.Hooks.listdir(self, x)
    4.55 +
    4.56 +        x = self._get_dirname(x)
    4.57 +        l = []
    4.58 +        for path in archive.namelist():
    4.59 +
    4.60 +            # Find out if the path is within the given directory.
    4.61 +
    4.62 +            if path != x and path.startswith(x):
    4.63 +
    4.64 +                # Get the path below the given directory.
    4.65 +
    4.66 +                subpath = path[len(x):]
    4.67 +
    4.68 +                # Find out whether the path is an object in the current directory.
    4.69 +
    4.70 +                if subpath.count("/") == 0 or subpath.count("/") == 1 and subpath.endswith("/"):
    4.71 +                    l.append(subpath)
    4.72 +
    4.73 +        return l
    4.74 +
    4.75 +    def matching(self, dir, extension, archive=None):
    4.76 +
    4.77 +        """
    4.78 +        Return the matching files in the given directory 'dir' having the given
    4.79 +        'extension' within the given 'archive'. Produce a list containing full
    4.80 +        paths as opposed to simple filenames.
    4.81 +        """
    4.82 +
    4.83 +        if archive is None:
    4.84 +            return glob.glob(self.path_join(dir, "*" + extension))
    4.85 +
    4.86 +        dir = self._get_dirname(dir)
    4.87 +        l = []
    4.88 +        for path in self.listdir(dir, archive):
    4.89 +            if path.endswith(extension):
    4.90 +                l.append(self.path_join(dir, path))
    4.91 +        return l
    4.92 +
    4.93 +    def read(self, filename, archive=None):
    4.94 +
    4.95 +        """
    4.96 +        Return the contents of the file with the given 'filename' in the given
    4.97 +        'archive'.
    4.98 +        """
    4.99 +
   4.100 +        if archive is None:
   4.101 +            f = open(filename, "rb")
   4.102 +            s = f.read()
   4.103 +            f.close()
   4.104 +            return s
   4.105 +        return archive.read(filename)
   4.106 +
   4.107 +class ClassLoader(ihooks.ModuleLoader):
   4.108 +
   4.109 +    "A class providing support for searching directories for supported files."
   4.110 +
   4.111 +    def find_module(self, name, path=None):
   4.112 +
   4.113 +        """
   4.114 +        Find the module with the given 'name', using the given 'path' to locate
   4.115 +        it. Note that ModuleLoader.find_module is almost sufficient, but does
   4.116 +        not provide enough support for "package unions" where the root of a
   4.117 +        package hierarchy may appear in several places.
   4.118 +
   4.119 +        Return a list of locations (each being the "stuff" data structure used
   4.120 +        by load_module); this replaces the single "stuff" value or None returned
   4.121 +        by ModuleLoader.find_module.
   4.122 +        """
   4.123 +
   4.124 +        if path is None:
   4.125 +            path = [None] + self.default_path()
   4.126 +
   4.127 +        found_locations = []
   4.128 +
   4.129 +        for dir in path:
   4.130 +            stuff = self.find_module_in_dir(name, dir)
   4.131 +            if stuff:
   4.132 +                found_locations.append(stuff)
   4.133 +
   4.134 +        return found_locations
   4.135 +
   4.136 +    def find_module_in_dir(self, name, dir, allow_packages=1):
   4.137 +
   4.138 +        """
   4.139 +        Find the module with the given 'name' in the given directory 'dir'.
   4.140 +        Since Java packages/modules are directories containing class files,
   4.141 +        return the required information tuple only when the path constructed
   4.142 +        from 'dir' and 'name' refers to a directory containing class files.
   4.143 +        """
   4.144 +
   4.145 +        result = ihooks.ModuleLoader.find_module_in_dir(self, name, dir, allow_packages)
   4.146 +        if result is not None:
   4.147 +            return result
   4.148 +
   4.149 +        # An archive may be opened.
   4.150 +
   4.151 +        archive = None
   4.152 +
   4.153 +        # Provide a special name for the current directory.
   4.154 +
   4.155 +        if name == "__this__":
   4.156 +            if dir == None:
   4.157 +                return (None, ".", ("", "", JAVA_PACKAGE))
   4.158 +            else:
   4.159 +                return None
   4.160 +
   4.161 +        # Where no directory is given, return failure immediately.
   4.162 +
   4.163 +        elif dir is None:
   4.164 +            return None
   4.165 +
   4.166 +        # Detect archives.
   4.167 +
   4.168 +        else:
   4.169 +            archive, archive_path, path = self._get_archive_and_path(dir, name)
   4.170 +
   4.171 +        #print "Processing name", name, "in", dir, "producing", path, "within archive", archive
   4.172 +
   4.173 +        if self._find_module_at_path(path, archive):
   4.174 +            if archive is not None:
   4.175 +                return (archive, archive_path + ":" + path, (os.extsep + "jar", "r", JAVA_ARCHIVE))
   4.176 +            else:
   4.177 +                return (None, path, ("", "", JAVA_PACKAGE))
   4.178 +        else:
   4.179 +            return None
   4.180 +
   4.181 +    def _get_archive_and_path(self, dir, name):
   4.182 +        parts = dir.split(":")
   4.183 +        archive_path = parts[0]
   4.184 +
   4.185 +        # Archives may include an internal path, but will in any case have
   4.186 +        # a primary part ending in .jar.
   4.187 +
   4.188 +        if archive_path.endswith(os.extsep + "jar"):
   4.189 +            archive = zipfile.ZipFile(archive_path, "r")
   4.190 +            path = self.hooks.path_join(":".join(parts[1:]), name)
   4.191 +
   4.192 +        # Otherwise, produce a filesystem-based path.
   4.193 +
   4.194 +        else:
   4.195 +            archive = None
   4.196 +            path = self.hooks.path_join(dir, name)
   4.197 +
   4.198 +        return archive, archive_path, path
   4.199 +
   4.200 +    def _get_path_in_archive(self, path):
   4.201 +        parts = path.split(":")
   4.202 +        if len(parts) == 1:
   4.203 +            return parts[0]
   4.204 +        else:
   4.205 +            return ":".join(parts[1:])
   4.206 +
   4.207 +    def _find_module_at_path(self, path, archive):
   4.208 +        if self.hooks.path_isdir(path, archive):
   4.209 +            #print "Looking in", path, "using archive", archive
   4.210 +
   4.211 +            # Look for classes in the directory.
   4.212 +
   4.213 +            if len(self.hooks.matching(path, os.extsep + "class", archive)) != 0:
   4.214 +                return 1
   4.215 +
   4.216 +            # Otherwise permit importing where directories containing classes exist.
   4.217 +
   4.218 +            #print "Filenames are", self.hooks.listdir(path, archive)
   4.219 +            for filename in self.hooks.listdir(path, archive):
   4.220 +                pathname = self.hooks.path_join(path, filename)
   4.221 +                result = self._find_module_at_path(pathname, archive)
   4.222 +                if result is not None:
   4.223 +                    return result
   4.224 +
   4.225 +        return 0
   4.226 +
   4.227 +    def load_module(self, name, stuff):
   4.228 +
   4.229 +        """
   4.230 +        Load the module with the given 'name', with a list of 'stuff' items,
   4.231 +        each of which describes the location of the module and is a tuple of the
   4.232 +        form (file, filename, (suffix, mode, data type)).
   4.233 +
   4.234 +        Return a module object or raise an ImportError if a problem occurred in
   4.235 +        the import operation.
   4.236 +
   4.237 +        Note that the 'stuff' parameter is a list and not a single item as in
   4.238 +        ModuleLoader.load_module. This should still work, however, since the
   4.239 +        find_module method produces such a list.
   4.240 +        """
   4.241 +
   4.242 +        # Set up the module.
   4.243 +        # A union of all locations is placed in the module's path.
   4.244 +
   4.245 +        module = self.hooks.add_module(name)
   4.246 +        module.__path__ = [item_filename for (item_archive, item_filename, item_info) in stuff]
   4.247 +
   4.248 +        # Just go into each package and find the class files.
   4.249 +
   4.250 +        for stuff_item in stuff:
   4.251 +
   4.252 +            # Extract the details, delegating loading responsibility to the
   4.253 +            # default loader where appropriate.
   4.254 +            # NOTE: Should we not be using some saved loader remembered upon
   4.255 +            # NOTE: installation?
   4.256 +
   4.257 +            archive, filename, info = stuff_item
   4.258 +            suffix, mode, datatype = info
   4.259 +            if datatype not in (JAVA_PACKAGE, JAVA_ARCHIVE):
   4.260 +                return ihooks.ModuleLoader.load_module(self, name, stuff_item)
   4.261 +
   4.262 +            #print "Loading", archive, filename, info
   4.263 +
   4.264 +            # Prepare a dictionary of globals.
   4.265 +
   4.266 +            global_names = module.__dict__
   4.267 +            global_names["__builtins__"] = __builtins__
   4.268 +
   4.269 +            # Get the real filename.
   4.270 +
   4.271 +            filename = self._get_path_in_archive(filename)
   4.272 +            #print "Real filename", filename
   4.273 +
   4.274 +            # Load the class files.
   4.275 +
   4.276 +            class_files = {}
   4.277 +            for class_filename in self.hooks.matching(filename, os.extsep + "class", archive):
   4.278 +                #print "Loading class", class_filename
   4.279 +                s = self.hooks.read(class_filename, archive)
   4.280 +                class_file = classfile.ClassFile(s)
   4.281 +                class_files[str(class_file.this_class.get_name())] = class_file
   4.282 +
   4.283 +            # Get an index of the class files.
   4.284 +
   4.285 +            class_file_index = class_files.keys()
   4.286 +
   4.287 +            # NOTE: Unnecessary sorting for test purposes.
   4.288 +
   4.289 +            class_file_index.sort()
   4.290 +
   4.291 +            # Now go through the classes arranging them in a safe loading order.
   4.292 +
   4.293 +            position = 0
   4.294 +            while position < len(class_file_index):
   4.295 +                class_name = class_file_index[position]
   4.296 +                super_class_name = str(class_files[class_name].super_class.get_name())
   4.297 +
   4.298 +                # Discover whether the superclass appears later.
   4.299 +
   4.300 +                try:
   4.301 +                    super_class_position = class_file_index.index(super_class_name)
   4.302 +                    if super_class_position > position:
   4.303 +
   4.304 +                        # If the superclass appears later, swap this class and the
   4.305 +                        # superclass, then process the superclass.
   4.306 +
   4.307 +                        class_file_index[position] = super_class_name
   4.308 +                        class_file_index[super_class_position] = class_name
   4.309 +                        continue
   4.310 +
   4.311 +                except ValueError:
   4.312 +                    pass
   4.313 +
   4.314 +                position += 1
   4.315 +
   4.316 +            # Process each class file, producing a genuine Python class.
   4.317 +            # Create the classes, but establish a proper initialisation order.
   4.318 +
   4.319 +            class_file_init_index = []
   4.320 +            class_file_init = {}
   4.321 +
   4.322 +            for class_name in class_file_index:
   4.323 +                #print "* Class", class_name
   4.324 +                class_file = class_files[class_name]
   4.325 +                translator = bytecode.ClassTranslator(class_file)
   4.326 +                cls, external_names = translator.process(global_names)
   4.327 +                module.__dict__[cls.__name__] = cls
   4.328 +
   4.329 +                # Process external names.
   4.330 +
   4.331 +                this_class_name_parts = class_file.this_class.get_python_name().split(".")
   4.332 +                this_class_module, this_class_name = this_class_name_parts[:-1], this_class_name_parts[-1]
   4.333 +
   4.334 +                for external_name in external_names:
   4.335 +                    #print "* Name", external_name
   4.336 +                    external_name_parts = external_name.split(".")
   4.337 +                    external_class_module, external_class_name = external_name_parts[:-1], external_name_parts[-1]
   4.338 +
   4.339 +                    # Names not local to this package need importing.
   4.340 +
   4.341 +                    if len(external_name_parts) > 1 and this_class_module != external_class_module:
   4.342 +
   4.343 +                        external_module_name = ".".join(external_class_module)
   4.344 +                        #print "* Importing", external_module_name
   4.345 +                        obj = __import__(external_module_name, global_names, {}, [])
   4.346 +                        global_names[external_name_parts[0]] = obj
   4.347 +
   4.348 +                    # Names local to this package may affect initialisation order.
   4.349 +
   4.350 +                    elif external_class_name not in class_file_init_index:
   4.351 +                        try:
   4.352 +                            this_class_name_index = class_file_init_index.index(this_class_name)
   4.353 +
   4.354 +                            # Either insert this name before the current class's
   4.355 +                            # name.
   4.356 +
   4.357 +                            #print "* Inserting", external_class_name
   4.358 +                            class_file_init_index.insert(this_class_name_index, external_class_name)
   4.359 +
   4.360 +                        except ValueError:
   4.361 +
   4.362 +                            # Or add this name in anticipation of the current
   4.363 +                            # class's name appearing.
   4.364 +
   4.365 +                            #print "* Including", external_class_name
   4.366 +                            class_file_init_index.append(external_class_name)
   4.367 +
   4.368 +                # Add this class name to the initialisation index.
   4.369 +
   4.370 +                if class_name not in class_file_init_index:
   4.371 +                    class_file_init_index.append(this_class_name)
   4.372 +                class_file_init[this_class_name] = (cls, class_file)
   4.373 +
   4.374 +            # Finally, call __clinit__ methods for all relevant classes.
   4.375 +
   4.376 +            #print "** Initialisation order", class_file_init_index
   4.377 +            for class_name in class_file_init_index:
   4.378 +                cls, class_file = class_file_init[class_name]
   4.379 +                #print "**", cls, class_file
   4.380 +                if hasattr(cls, "__clinit__"):
   4.381 +                    eval(cls.__clinit__.func_code, global_names)
   4.382 +
   4.383 +        return module
   4.384 +
   4.385 +ihooks.ModuleImporter(loader=ClassLoader(hooks=ClassHooks())).install()
   4.386 +
   4.387 +# vim: tabstop=4 expandtab shiftwidth=4