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