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