1.1 --- a/bytecode.py Fri Jan 21 17:04:41 2005 +0100
1.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
1.3 @@ -1,2311 +0,0 @@
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