2.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2.2 +++ b/javaclass/bytecode.py Fri Jan 21 17:05:06 2005 +0100
2.3 @@ -0,0 +1,2311 @@
2.4 +#!/usr/bin/env python
2.5 +
2.6 +"""
2.7 +Java bytecode conversion. Specification found at the following URL:
2.8 +http://java.sun.com/docs/books/vmspec/2nd-edition/html/Instructions2.doc.html
2.9 +
2.10 +NOTE: Synchronized constructs are not actually supported.
2.11 +"""
2.12 +
2.13 +import classfile
2.14 +from dis import cmp_op # for access to Python bytecode values and operators
2.15 +try:
2.16 + from dis import opmap
2.17 +except ImportError:
2.18 + from dis import opname
2.19 + opmap = {}
2.20 + for i in range(0, len(opname)):
2.21 + opmap[opname[i]] = i
2.22 +from UserDict import UserDict
2.23 +import new
2.24 +
2.25 +# Bytecode production classes.
2.26 +
2.27 +class BytecodeWriter:
2.28 +
2.29 + "A Python bytecode writer."
2.30 +
2.31 + def __init__(self):
2.32 +
2.33 + "Initialise the writer."
2.34 +
2.35 + # A stack of loop start instructions corresponding to loop blocks.
2.36 + self.loops = []
2.37 +
2.38 + # A stack of loop block or exception block start positions.
2.39 + self.blocks = []
2.40 +
2.41 + # A stack of exception block handler pointers.
2.42 + self.exception_handlers = []
2.43 +
2.44 + # A dictionary mapping labels to jump instructions referencing such labels.
2.45 + self.jumps = {}
2.46 +
2.47 + # The output values, including "lazy" subvalues which will need evaluating.
2.48 + self.output = []
2.49 +
2.50 + # The current Python bytecode instruction position.
2.51 + self.position = 0
2.52 +
2.53 + # Stack depth estimation.
2.54 + self.stack_depth = 0
2.55 + self.max_stack_depth = 0
2.56 +
2.57 + # Local variable estimation.
2.58 + self.max_locals = 0
2.59 +
2.60 + # Mapping from values to indexes.
2.61 + self.constants = {}
2.62 +
2.63 + # Mapping from names to indexes.
2.64 + # NOTE: This may be acquired from elsewhere.
2.65 + #self.globals = {}
2.66 +
2.67 + # Mapping from names to indexes.
2.68 + self.names = {}
2.69 +
2.70 + # A list of constants used as exception handler return addresses.
2.71 + self.constants_for_exceptions = []
2.72 +
2.73 + # A list of external names.
2.74 + self.external_names = []
2.75 +
2.76 + def get_output(self):
2.77 +
2.78 + "Return the output of the writer as a string."
2.79 +
2.80 + output = []
2.81 + for element in self.output:
2.82 + if isinstance(element, LazySubValue):
2.83 + value = element.value
2.84 + else:
2.85 + value = element
2.86 + # NOTE: ValueError gets raised for bad values here.
2.87 + output.append(chr(value))
2.88 + return "".join(output)
2.89 +
2.90 + def get_constants(self):
2.91 +
2.92 + """
2.93 + Return a list of constants with ordering significant to the code
2.94 + employing them.
2.95 + """
2.96 +
2.97 + l = self._get_list(self._invert(self.constants))
2.98 + result = []
2.99 + for i in l:
2.100 + if isinstance(i, LazyValue):
2.101 + result.append(i.get_value())
2.102 + else:
2.103 + result.append(i)
2.104 + return result
2.105 +
2.106 + #def get_globals(self):
2.107 + # return self._get_list(self._invert(self.globals))
2.108 +
2.109 + def get_names(self):
2.110 +
2.111 + """
2.112 + Return a list of names with ordering significant to the code employing
2.113 + them.
2.114 + """
2.115 +
2.116 + return self._get_list(self._invert(self.names))
2.117 +
2.118 + def _invert(self, d):
2.119 +
2.120 + """
2.121 + Return a new dictionary whose key-to-value mapping is in the inverse of
2.122 + that found in 'd'.
2.123 + """
2.124 +
2.125 + inverted = {}
2.126 + for k, v in d.items():
2.127 + inverted[v] = k
2.128 + return inverted
2.129 +
2.130 + def _get_list(self, d):
2.131 +
2.132 + """
2.133 + Traverse the dictionary 'd' returning a list whose values appear at the
2.134 + position denoted by each value's key in 'd'.
2.135 + """
2.136 +
2.137 + l = []
2.138 + for i in range(0, len(d.keys())):
2.139 + l.append(d[i])
2.140 + return l
2.141 +
2.142 + # Administrative methods.
2.143 +
2.144 + def update_stack_depth(self, change):
2.145 +
2.146 + """
2.147 + Given the stated 'change' in stack depth, update the maximum stack depth
2.148 + where appropriate.
2.149 + """
2.150 +
2.151 + self.stack_depth += change
2.152 + if self.stack_depth > self.max_stack_depth:
2.153 + self.max_stack_depth = self.stack_depth
2.154 +
2.155 + def update_locals(self, index):
2.156 +
2.157 + """
2.158 + Given the stated 'index' of a local variable, update the maximum local
2.159 + variable index where appropriate.
2.160 + """
2.161 +
2.162 + if index > self.max_locals:
2.163 + self.max_locals = index
2.164 +
2.165 + # Special methods.
2.166 +
2.167 + def _write_value(self, value):
2.168 +
2.169 + """
2.170 + Write the given 'value' at the current output position.
2.171 + """
2.172 +
2.173 + if isinstance(value, LazyValue):
2.174 + # NOTE: Assume a 16-bit value.
2.175 + self.output.append(value.values[0])
2.176 + self.output.append(value.values[1])
2.177 + self.position += 2
2.178 + elif value <= 0xffff:
2.179 + self.output.append(value & 0xff)
2.180 + self.output.append((value & 0xff00) >> 8)
2.181 + self.position += 2
2.182 + else:
2.183 + # NOTE: EXTENDED_ARG not yet supported.
2.184 + raise ValueError, value
2.185 +
2.186 + def _rewrite_value(self, position, value):
2.187 +
2.188 + """
2.189 + At the given output 'position', rewrite the given 'value'.
2.190 + """
2.191 +
2.192 + # NOTE: Assume a 16-bit value.
2.193 + if value <= 0xffff:
2.194 + self.output[position] = (value & 0xff)
2.195 + self.output[position + 1] = ((value & 0xff00) >> 8)
2.196 + else:
2.197 + # NOTE: EXTENDED_ARG not yet supported.
2.198 + raise ValueError, value
2.199 +
2.200 + # Higher level methods.
2.201 +
2.202 + def use_external_name(self, name):
2.203 + # NOTE: Remove array and object indicators.
2.204 + self.external_names.append(name)
2.205 +
2.206 + def setup_loop(self):
2.207 + self.loops.append(self.position)
2.208 + self.output.append(opmap["SETUP_LOOP"])
2.209 + self.position += 1
2.210 + self._write_value(0) # To be filled in later
2.211 +
2.212 + def end_loop(self):
2.213 + current_loop_start = self.loops.pop()
2.214 + current_loop_real_start = self.blocks.pop()
2.215 + #print "<", self.blocks, current_loop_real_start
2.216 + # Fix the iterator delta.
2.217 + # NOTE: Using 3 as the assumed length of the FOR_ITER instruction.
2.218 + self.jump_absolute(current_loop_real_start)
2.219 + self._rewrite_value(current_loop_real_start + 1, self.position - current_loop_real_start - 3)
2.220 + self.pop_block()
2.221 + # Fix the loop delta.
2.222 + # NOTE: Using 3 as the assumed length of the SETUP_LOOP instruction.
2.223 + self._rewrite_value(current_loop_start + 1, self.position - current_loop_start - 3)
2.224 +
2.225 + def jump_to_label(self, status, name):
2.226 + # Record the instruction using the jump.
2.227 + jump_instruction = self.position
2.228 + if status is None:
2.229 + self.jump_forward()
2.230 + elif status:
2.231 + self.jump_if_true()
2.232 + else:
2.233 + self.jump_if_false()
2.234 + # Record the following instruction, too.
2.235 + if not self.jumps.has_key(name):
2.236 + self.jumps[name] = []
2.237 + self.jumps[name].append((jump_instruction, self.position))
2.238 +
2.239 + def start_label(self, name):
2.240 + # Fill in all jump instructions.
2.241 + for jump_instruction, following_instruction in self.jumps[name]:
2.242 + self._rewrite_value(jump_instruction + 1, self.position - following_instruction)
2.243 + del self.jumps[name]
2.244 +
2.245 + def load_const_ret(self, value):
2.246 + self.constants_for_exceptions.append(value)
2.247 + self.load_const(value)
2.248 +
2.249 + def ret(self, index):
2.250 + self.load_fast(index)
2.251 +
2.252 + # Previously, the constant stored on the stack by jsr/jsr_w was stored
2.253 + # in a local variable. In the JVM, extracting the value from the local
2.254 + # variable and jumping can be done at runtime. In the Python VM, any
2.255 + # jump target must be known in advance and written into the bytecode.
2.256 +
2.257 + for constant in self.constants_for_exceptions:
2.258 + self.dup_top() # Stack: actual-address, actual-address
2.259 + self.load_const(constant) # Stack: actual-address, actual-address, suggested-address
2.260 + self.compare_op("==") # Stack: actual-address, result
2.261 + self.jump_to_label(0, "const")
2.262 + self.pop_top() # Stack: actual-address
2.263 + self.pop_top() # Stack:
2.264 + self.jump_absolute(constant)
2.265 + self.start_label("const")
2.266 + self.pop_top() # Stack: actual-address
2.267 +
2.268 + # NOTE: If we get here, something is really wrong.
2.269 +
2.270 + self.pop_top() # Stack:
2.271 +
2.272 + def setup_except(self, target):
2.273 + self.blocks.append(self.position)
2.274 + self.exception_handlers.append(target)
2.275 + #print "-", self.position, target
2.276 + self.output.append(opmap["SETUP_EXCEPT"])
2.277 + self.position += 1
2.278 + self._write_value(0) # To be filled in later
2.279 +
2.280 + def setup_finally(self, target):
2.281 + self.blocks.append(self.position)
2.282 + self.exception_handlers.append(target)
2.283 + #print "-", self.position, target
2.284 + self.output.append(opmap["SETUP_FINALLY"])
2.285 + self.position += 1
2.286 + self._write_value(0) # To be filled in later
2.287 +
2.288 + def end_exception(self):
2.289 + current_exception_start = self.blocks.pop()
2.290 + # Convert the "lazy" absolute value.
2.291 + current_exception_target = self.exception_handlers.pop()
2.292 + target = current_exception_target.get_value()
2.293 + #print "*", current_exception_start, target
2.294 + # NOTE: Using 3 as the assumed length of the SETUP_* instruction.
2.295 + self._rewrite_value(current_exception_start + 1, target - current_exception_start - 3)
2.296 +
2.297 + def start_handler(self, exc_name, class_file):
2.298 +
2.299 + # Where handlers are begun, produce bytecode to test the type of
2.300 + # the exception.
2.301 + # NOTE: Since RAISE_VARARGS and END_FINALLY are not really documented,
2.302 + # NOTE: we store the top of the stack and use it later to trigger the
2.303 + # NOTE: magic processes when re-raising.
2.304 + self.use_external_name(str(exc_name))
2.305 +
2.306 + self.rot_two() # Stack: raised-exception, exception
2.307 + self.dup_top() # Stack: raised-exception, exception, exception
2.308 + # Handled exceptions are wrapped before being thrown.
2.309 + self.load_global("Exception") # Stack: raised-exception, exception, exception, Exception
2.310 + self.compare_op("exception match") # Stack: raised-exception, exception, result
2.311 + self.jump_to_label(0, "next")
2.312 + self.pop_top() # Stack: raised-exception, exception
2.313 + self.dup_top() # Stack: raised-exception, exception, exception
2.314 + self.load_attr("args") # Stack: raised-exception, exception, args
2.315 + self.load_const(0) # Stack: raised-exception, exception, args, 0
2.316 + self.binary_subscr() # Stack: raised-exception, exception, exception-object
2.317 + load_class_name(class_file, str(exc_name), self)
2.318 + # Stack: raised-exception, exception, exception-object, handled-exception
2.319 + self.load_global("isinstance") # Stack: raised-exception, exception, exception-object, handled-exception, isinstance
2.320 + self.rot_three() # Stack: raised-exception, exception, isinstance, exception-object, handled-exception
2.321 + self.call_function(2) # Stack: raised-exception, exception, result
2.322 + self.jump_to_label(1, "handler")
2.323 + self.start_label("next")
2.324 + self.pop_top() # Stack: raised-exception, exception
2.325 + self.rot_two() # Stack: exception, raised-exception
2.326 + self.end_finally()
2.327 + self.start_label("handler")
2.328 + self.pop_top() # Stack: raised-exception, exception
2.329 +
2.330 + # Complicated methods.
2.331 +
2.332 + def load_const(self, value):
2.333 + self.output.append(opmap["LOAD_CONST"])
2.334 + if not self.constants.has_key(value):
2.335 + self.constants[value] = len(self.constants.keys())
2.336 + self.position += 1
2.337 + self._write_value(self.constants[value])
2.338 + self.update_stack_depth(1)
2.339 +
2.340 + def load_global(self, name):
2.341 + self.output.append(opmap["LOAD_GLOBAL"])
2.342 + if not self.names.has_key(name):
2.343 + self.names[name] = len(self.names.keys())
2.344 + self.position += 1
2.345 + self._write_value(self.names[name])
2.346 + self.update_stack_depth(1)
2.347 +
2.348 + def load_attr(self, name):
2.349 + self.output.append(opmap["LOAD_ATTR"])
2.350 + if not self.names.has_key(name):
2.351 + self.names[name] = len(self.names.keys())
2.352 + self.position += 1
2.353 + self._write_value(self.names[name])
2.354 +
2.355 + def load_name(self, name):
2.356 + self.output.append(opmap["LOAD_NAME"])
2.357 + if not self.names.has_key(name):
2.358 + self.names[name] = len(self.names.keys())
2.359 + self.position += 1
2.360 + self._write_value(self.names[name])
2.361 + self.update_stack_depth(1)
2.362 +
2.363 + def load_fast(self, index):
2.364 + self.output.append(opmap["LOAD_FAST"])
2.365 + self.position += 1
2.366 + self._write_value(index)
2.367 + self.update_stack_depth(1)
2.368 + self.update_locals(index)
2.369 +
2.370 + def store_attr(self, name):
2.371 + self.output.append(opmap["STORE_ATTR"])
2.372 + if not self.names.has_key(name):
2.373 + self.names[name] = len(self.names.keys())
2.374 + self.position += 1
2.375 + self._write_value(self.names[name])
2.376 + self.update_stack_depth(-1)
2.377 +
2.378 + def store_fast(self, index):
2.379 + self.output.append(opmap["STORE_FAST"])
2.380 + self.position += 1
2.381 + self._write_value(index)
2.382 + self.update_stack_depth(-1)
2.383 + self.update_locals(index)
2.384 +
2.385 + def for_iter(self):
2.386 + self.blocks.append(self.position)
2.387 + #print ">", self.blocks
2.388 + self.output.append(opmap["FOR_ITER"])
2.389 + self.position += 1
2.390 + self._write_value(0) # To be filled in later
2.391 + self.update_stack_depth(1)
2.392 +
2.393 + def break_loop(self):
2.394 + self.output.append(opmap["BREAK_LOOP"])
2.395 + self.position += 1
2.396 + self.jump_absolute(self.blocks[-1])
2.397 +
2.398 + # Normal bytecode generators.
2.399 +
2.400 + def get_iter(self):
2.401 + self.output.append(opmap["GET_ITER"])
2.402 + self.position += 1
2.403 +
2.404 + def jump_if_false(self, offset=0):
2.405 + self.output.append(opmap["JUMP_IF_FALSE"])
2.406 + self.position += 1
2.407 + self._write_value(offset) # May be filled in later
2.408 +
2.409 + def jump_if_true(self, offset=0):
2.410 + self.output.append(opmap["JUMP_IF_TRUE"])
2.411 + self.position += 1
2.412 + self._write_value(offset) # May be filled in later
2.413 +
2.414 + def jump_forward(self, offset=0):
2.415 + self.output.append(opmap["JUMP_FORWARD"])
2.416 + self.position += 1
2.417 + self._write_value(offset) # May be filled in later
2.418 +
2.419 + def jump_absolute(self, address=0):
2.420 + self.output.append(opmap["JUMP_ABSOLUTE"])
2.421 + self.position += 1
2.422 + self._write_value(address) # May be filled in later
2.423 +
2.424 + def build_tuple(self, count):
2.425 + self.output.append(opmap["BUILD_TUPLE"])
2.426 + self.position += 1
2.427 + self._write_value(count)
2.428 + self.update_stack_depth(-(count - 1))
2.429 +
2.430 + def build_list(self, count):
2.431 + self.output.append(opmap["BUILD_LIST"])
2.432 + self.position += 1
2.433 + self._write_value(count)
2.434 + self.update_stack_depth(-(count - 1))
2.435 +
2.436 + def pop_top(self):
2.437 + self.output.append(opmap["POP_TOP"])
2.438 + self.position += 1
2.439 + self.update_stack_depth(-1)
2.440 +
2.441 + def dup_top(self):
2.442 + self.output.append(opmap["DUP_TOP"])
2.443 + self.position += 1
2.444 + self.update_stack_depth(1)
2.445 +
2.446 + def dup_topx(self, count):
2.447 + self.output.append(opmap["DUP_TOPX"])
2.448 + self.position += 1
2.449 + self._write_value(count)
2.450 + self.update_stack_depth(count)
2.451 +
2.452 + def rot_two(self):
2.453 + self.output.append(opmap["ROT_TWO"])
2.454 + self.position += 1
2.455 +
2.456 + def rot_three(self):
2.457 + self.output.append(opmap["ROT_THREE"])
2.458 + self.position += 1
2.459 +
2.460 + def rot_four(self):
2.461 + self.output.append(opmap["ROT_FOUR"])
2.462 + self.position += 1
2.463 +
2.464 + def call_function(self, count):
2.465 + self.output.append(opmap["CALL_FUNCTION"])
2.466 + self.position += 1
2.467 + self._write_value(count)
2.468 + self.update_stack_depth(-count)
2.469 +
2.470 + def call_function_var(self, count):
2.471 + self.output.append(opmap["CALL_FUNCTION_VAR"])
2.472 + self.position += 1
2.473 + self._write_value(count)
2.474 + self.update_stack_depth(-count-1)
2.475 +
2.476 + def binary_subscr(self):
2.477 + self.output.append(opmap["BINARY_SUBSCR"])
2.478 + self.position += 1
2.479 + self.update_stack_depth(-1)
2.480 +
2.481 + def binary_add(self):
2.482 + self.output.append(opmap["BINARY_ADD"])
2.483 + self.position += 1
2.484 + self.update_stack_depth(-1)
2.485 +
2.486 + def binary_divide(self):
2.487 + self.output.append(opmap["BINARY_DIVIDE"])
2.488 + self.position += 1
2.489 + self.update_stack_depth(-1)
2.490 +
2.491 + def binary_multiply(self):
2.492 + self.output.append(opmap["BINARY_MULTIPLY"])
2.493 + self.position += 1
2.494 + self.update_stack_depth(-1)
2.495 +
2.496 + def binary_modulo(self):
2.497 + self.output.append(opmap["BINARY_MODULO"])
2.498 + self.position += 1
2.499 + self.update_stack_depth(-1)
2.500 +
2.501 + def binary_subtract(self):
2.502 + self.output.append(opmap["BINARY_SUBTRACT"])
2.503 + self.position += 1
2.504 + self.update_stack_depth(-1)
2.505 +
2.506 + def binary_and(self):
2.507 + self.output.append(opmap["BINARY_AND"])
2.508 + self.position += 1
2.509 + self.update_stack_depth(-1)
2.510 +
2.511 + def binary_or(self):
2.512 + self.output.append(opmap["BINARY_XOR"])
2.513 + self.position += 1
2.514 + self.update_stack_depth(-1)
2.515 +
2.516 + def binary_lshift(self):
2.517 + self.output.append(opmap["BINARY_LSHIFT"])
2.518 + self.position += 1
2.519 + self.update_stack_depth(-1)
2.520 +
2.521 + def binary_rshift(self):
2.522 + self.output.append(opmap["BINARY_RSHIFT"])
2.523 + self.position += 1
2.524 + self.update_stack_depth(-1)
2.525 +
2.526 + def binary_xor(self):
2.527 + self.output.append(opmap["BINARY_XOR"])
2.528 + self.position += 1
2.529 + self.update_stack_depth(-1)
2.530 +
2.531 + def store_subscr(self):
2.532 + self.output.append(opmap["STORE_SUBSCR"])
2.533 + self.position += 1
2.534 + self.update_stack_depth(-3)
2.535 +
2.536 + def unary_negative(self):
2.537 + self.output.append(opmap["UNARY_NEGATIVE"])
2.538 + self.position += 1
2.539 +
2.540 + def slice_0(self):
2.541 + self.output.append(opmap["SLICE+0"])
2.542 + self.position += 1
2.543 +
2.544 + def slice_1(self):
2.545 + self.output.append(opmap["SLICE+1"])
2.546 + self.position += 1
2.547 +
2.548 + def compare_op(self, op):
2.549 + self.output.append(opmap["COMPARE_OP"])
2.550 + self.position += 1
2.551 + self._write_value(list(cmp_op).index(op))
2.552 + self.update_stack_depth(-1)
2.553 +
2.554 + def return_value(self):
2.555 + self.output.append(opmap["RETURN_VALUE"])
2.556 + self.position += 1
2.557 + self.update_stack_depth(-1)
2.558 +
2.559 + def raise_varargs(self, count):
2.560 + self.output.append(opmap["RAISE_VARARGS"])
2.561 + self.position += 1
2.562 + self._write_value(count)
2.563 +
2.564 + def pop_block(self):
2.565 + self.output.append(opmap["POP_BLOCK"])
2.566 + self.position += 1
2.567 +
2.568 + def end_finally(self):
2.569 + self.output.append(opmap["END_FINALLY"])
2.570 + self.position += 1
2.571 +
2.572 + def unpack_sequence(self, count):
2.573 + self.output.append(opmap["UNPACK_SEQUENCE"])
2.574 + self.position += 1
2.575 + self._write_value(count)
2.576 +
2.577 + # Debugging.
2.578 +
2.579 + def print_item(self):
2.580 + self.output.append(opmap["PRINT_ITEM"])
2.581 + self.position += 1
2.582 +
2.583 +# Utility classes and functions.
2.584 +
2.585 +class LazyDict(UserDict):
2.586 + def __getitem__(self, key):
2.587 + if not self.data.has_key(key):
2.588 + # NOTE: Assume 16-bit value.
2.589 + self.data[key] = LazyValue(2)
2.590 + return self.data[key]
2.591 + def __setitem__(self, key, value):
2.592 + if self.data.has_key(key):
2.593 + existing_value = self.data[key]
2.594 + if isinstance(existing_value, LazyValue):
2.595 + existing_value.set_value(value)
2.596 + return
2.597 + self.data[key] = value
2.598 +
2.599 +class LazyValue:
2.600 + def __init__(self, nvalues):
2.601 + self.values = []
2.602 + for i in range(0, nvalues):
2.603 + self.values.append(LazySubValue())
2.604 + def set_value(self, value):
2.605 + # NOTE: Assume at least 16-bit value. No "filling" performed.
2.606 + if value <= 0xffff:
2.607 + self.values[0].set_value(value & 0xff)
2.608 + self.values[1].set_value((value & 0xff00) >> 8)
2.609 + else:
2.610 + # NOTE: EXTENDED_ARG not yet supported.
2.611 + raise ValueError, value
2.612 + def get_value(self):
2.613 + value = 0
2.614 + values = self.values[:]
2.615 + for i in range(0, len(values)):
2.616 + value = (value << 8) + values.pop().value
2.617 + return value
2.618 +
2.619 +class LazySubValue:
2.620 + def __init__(self):
2.621 + self.value = 0
2.622 + def set_value(self, value):
2.623 + self.value = value
2.624 +
2.625 +def signed(value, limit):
2.626 +
2.627 + """
2.628 + Return the signed integer from the unsigned 'value', where 'limit' (a value
2.629 + one greater than the highest possible positive integer) is used to determine
2.630 + whether a negative or positive result is produced.
2.631 + """
2.632 +
2.633 + d, r = divmod(value, limit)
2.634 + if d == 1:
2.635 + mask = limit * 2 - 1
2.636 + return -1 - (value ^ mask)
2.637 + else:
2.638 + return value
2.639 +
2.640 +def signed1(value):
2.641 + return signed(value, 0x80)
2.642 +
2.643 +def signed2(value):
2.644 + return signed(value, 0x8000)
2.645 +
2.646 +def signed4(value):
2.647 + return signed(value, 0x80000000)
2.648 +
2.649 +def load_class_name(class_file, full_class_name, program):
2.650 + this_class_name = str(class_file.this_class.get_python_name())
2.651 + this_class_parts = this_class_name.split(".")
2.652 + class_parts = full_class_name.split(".")
2.653 +
2.654 + # Only use the full path if different from this class's path.
2.655 +
2.656 + if class_parts[:-1] != this_class_parts[:-1]:
2.657 + program.use_external_name(full_class_name)
2.658 + program.load_global(class_parts[0])
2.659 + for class_part in class_parts[1:]:
2.660 + program.load_attr(class_part) # Stack: classref
2.661 + else:
2.662 + program.load_global(class_parts[-1])
2.663 +
2.664 +# Bytecode conversion.
2.665 +
2.666 +class BytecodeReader:
2.667 +
2.668 + "A generic Java bytecode reader."
2.669 +
2.670 + def __init__(self, class_file):
2.671 +
2.672 + """
2.673 + Initialise the reader with a 'class_file' containing essential
2.674 + information for any bytecode inspection activity.
2.675 + """
2.676 +
2.677 + self.class_file = class_file
2.678 + self.position_mapping = LazyDict()
2.679 +
2.680 + def process(self, method, program):
2.681 +
2.682 + """
2.683 + Process the given 'method' (obtained from the class file), using the
2.684 + given 'program' to write translated Python bytecode instructions.
2.685 + """
2.686 +
2.687 + self.java_position = 0
2.688 + self.in_finally = 0
2.689 + self.method = method
2.690 +
2.691 + # NOTE: Potentially unreliable way of getting necessary information.
2.692 +
2.693 + code, exception_table = None, None
2.694 + for attribute in method.attributes:
2.695 + if isinstance(attribute, classfile.CodeAttributeInfo):
2.696 + code, exception_table = attribute.code, attribute.exception_table
2.697 + break
2.698 +
2.699 + # Where no code was found, write a very simple placeholder routine.
2.700 + # This is useful for interfaces and abstract classes.
2.701 + # NOTE: Assess the correctness of doing this. An exception should really
2.702 + # NOTE: be raised instead.
2.703 +
2.704 + if code is None:
2.705 + program.load_const(None)
2.706 + program.return_value()
2.707 + return
2.708 +
2.709 + # Produce a structure which permits fast access to exception details.
2.710 +
2.711 + exception_block_start = {}
2.712 + exception_block_end = {}
2.713 + exception_block_handler = {}
2.714 + reversed_exception_table = exception_table[:]
2.715 + reversed_exception_table.reverse()
2.716 +
2.717 + # Later entries have wider coverage than earlier entries.
2.718 +
2.719 + for exception in reversed_exception_table:
2.720 +
2.721 + # Index start positions.
2.722 +
2.723 + if not exception_block_start.has_key(exception.start_pc):
2.724 + exception_block_start[exception.start_pc] = []
2.725 + exception_block_start[exception.start_pc].append(exception)
2.726 +
2.727 + # Index end positions.
2.728 +
2.729 + if not exception_block_end.has_key(exception.end_pc):
2.730 + exception_block_end[exception.end_pc] = []
2.731 + exception_block_end[exception.end_pc].append(exception)
2.732 +
2.733 + # Index handler positions.
2.734 +
2.735 + if not exception_block_handler.has_key(exception.handler_pc):
2.736 + exception_block_handler[exception.handler_pc] = []
2.737 + exception_block_handler[exception.handler_pc].append(exception)
2.738 +
2.739 + # Process each instruction in the code.
2.740 +
2.741 + while self.java_position < len(code):
2.742 + self.position_mapping[self.java_position] = program.position
2.743 +
2.744 + # Insert exception handling constructs.
2.745 +
2.746 + block_starts = exception_block_start.get(self.java_position, [])
2.747 + for exception in block_starts:
2.748 +
2.749 + # Note that the absolute position is used.
2.750 +
2.751 + if exception.catch_type == 0:
2.752 + program.setup_finally(self.position_mapping[exception.handler_pc])
2.753 + else:
2.754 + program.setup_except(self.position_mapping[exception.handler_pc])
2.755 +
2.756 + if block_starts:
2.757 + self.in_finally = 0
2.758 +
2.759 + # Insert exception handler details.
2.760 + # NOTE: Ensure that pop_block is reachable by possibly inserting it at the start of finally handlers.
2.761 + # NOTE: Insert a check for the correct exception at the start of each handler.
2.762 +
2.763 + for exception in exception_block_handler.get(self.java_position, []):
2.764 + program.end_exception()
2.765 + if exception.catch_type == 0:
2.766 + self.in_finally = 1
2.767 + else:
2.768 + program.start_handler(self.class_file.constants[exception.catch_type - 1].get_python_name(), self.class_file)
2.769 +
2.770 + # Process the bytecode at the current position.
2.771 +
2.772 + bytecode = ord(code[self.java_position])
2.773 + mnemonic, number_of_arguments = self.java_bytecodes[bytecode]
2.774 + number_of_arguments = self.process_bytecode(mnemonic, number_of_arguments, code, program)
2.775 + next_java_position = self.java_position + 1 + number_of_arguments
2.776 +
2.777 + # Insert exception block end details.
2.778 +
2.779 + for exception in exception_block_end.get(next_java_position, []):
2.780 +
2.781 + # NOTE: Insert jump beyond handlers.
2.782 + # NOTE: program.jump_forward/absolute(...)
2.783 + # NOTE: Insert end finally at end of handlers as well as where "ret" occurs.
2.784 +
2.785 + if exception.catch_type != 0:
2.786 + program.pop_block()
2.787 +
2.788 + # Only advance the JVM position after sneaking in extra Python
2.789 + # instructions.
2.790 +
2.791 + self.java_position = next_java_position
2.792 +
2.793 + def process_bytecode(self, mnemonic, number_of_arguments, code, program):
2.794 +
2.795 + """
2.796 + Process a bytecode instruction with the given 'mnemonic' and
2.797 + 'number_of_arguments'. The 'code' parameter contains the full method
2.798 + code so that argument data can be inspected. The 'program' parameter is
2.799 + used to produce a Python translation of the instruction.
2.800 + """
2.801 +
2.802 + if number_of_arguments is not None:
2.803 + arguments = []
2.804 + for j in range(0, number_of_arguments):
2.805 + arguments.append(ord(code[self.java_position + 1 + j]))
2.806 +
2.807 + # Call the handler.
2.808 +
2.809 + getattr(self, mnemonic)(arguments, program)
2.810 + return number_of_arguments
2.811 + else:
2.812 + # Call the handler.
2.813 +
2.814 + return getattr(self, mnemonic)(code[self.java_position+1:], program)
2.815 +
2.816 + java_bytecodes = {
2.817 + # code : (mnemonic, number of following bytes, change in stack)
2.818 + 0 : ("nop", 0),
2.819 + 1 : ("aconst_null", 0),
2.820 + 2 : ("iconst_m1", 0),
2.821 + 3 : ("iconst_0", 0),
2.822 + 4 : ("iconst_1", 0),
2.823 + 5 : ("iconst_2", 0),
2.824 + 6 : ("iconst_3", 0),
2.825 + 7 : ("iconst_4", 0),
2.826 + 8 : ("iconst_5", 0),
2.827 + 9 : ("lconst_0", 0),
2.828 + 10 : ("lconst_1", 0),
2.829 + 11 : ("fconst_0", 0),
2.830 + 12 : ("fconst_1", 0),
2.831 + 13 : ("fconst_2", 0),
2.832 + 14 : ("dconst_0", 0),
2.833 + 15 : ("dconst_1", 0),
2.834 + 16 : ("bipush", 1),
2.835 + 17 : ("sipush", 2),
2.836 + 18 : ("ldc", 1),
2.837 + 19 : ("ldc_w", 2),
2.838 + 20 : ("ldc2_w", 2),
2.839 + 21 : ("iload", 1),
2.840 + 22 : ("lload", 1),
2.841 + 23 : ("fload", 1),
2.842 + 24 : ("dload", 1),
2.843 + 25 : ("aload", 1),
2.844 + 26 : ("iload_0", 0),
2.845 + 27 : ("iload_1", 0),
2.846 + 28 : ("iload_2", 0),
2.847 + 29 : ("iload_3", 0),
2.848 + 30 : ("lload_0", 0),
2.849 + 31 : ("lload_1", 0),
2.850 + 32 : ("lload_2", 0),
2.851 + 33 : ("lload_3", 0),
2.852 + 34 : ("fload_0", 0),
2.853 + 35 : ("fload_1", 0),
2.854 + 36 : ("fload_2", 0),
2.855 + 37 : ("fload_3", 0),
2.856 + 38 : ("dload_0", 0),
2.857 + 39 : ("dload_1", 0),
2.858 + 40 : ("dload_2", 0),
2.859 + 41 : ("dload_3", 0),
2.860 + 42 : ("aload_0", 0),
2.861 + 43 : ("aload_1", 0),
2.862 + 44 : ("aload_2", 0),
2.863 + 45 : ("aload_3", 0),
2.864 + 46 : ("iaload", 0),
2.865 + 47 : ("laload", 0),
2.866 + 48 : ("faload", 0),
2.867 + 49 : ("daload", 0),
2.868 + 50 : ("aaload", 0),
2.869 + 51 : ("baload", 0),
2.870 + 52 : ("caload", 0),
2.871 + 53 : ("saload", 0),
2.872 + 54 : ("istore", 1),
2.873 + 55 : ("lstore", 1),
2.874 + 56 : ("fstore", 1),
2.875 + 57 : ("dstore", 1),
2.876 + 58 : ("astore", 1),
2.877 + 59 : ("istore_0", 0),
2.878 + 60 : ("istore_1", 0),
2.879 + 61 : ("istore_2", 0),
2.880 + 62 : ("istore_3", 0),
2.881 + 63 : ("lstore_0", 0),
2.882 + 64 : ("lstore_1", 0),
2.883 + 65 : ("lstore_2", 0),
2.884 + 66 : ("lstore_3", 0),
2.885 + 67 : ("fstore_0", 0),
2.886 + 68 : ("fstore_1", 0),
2.887 + 69 : ("fstore_2", 0),
2.888 + 70 : ("fstore_3", 0),
2.889 + 71 : ("dstore_0", 0),
2.890 + 72 : ("dstore_1", 0),
2.891 + 73 : ("dstore_2", 0),
2.892 + 74 : ("dstore_3", 0),
2.893 + 75 : ("astore_0", 0),
2.894 + 76 : ("astore_1", 0),
2.895 + 77 : ("astore_2", 0),
2.896 + 78 : ("astore_3", 0),
2.897 + 79 : ("iastore", 0),
2.898 + 80 : ("lastore", 0),
2.899 + 81 : ("fastore", 0),
2.900 + 82 : ("dastore", 0),
2.901 + 83 : ("aastore", 0),
2.902 + 84 : ("bastore", 0),
2.903 + 85 : ("castore", 0),
2.904 + 86 : ("sastore", 0),
2.905 + 87 : ("pop", 0),
2.906 + 88 : ("pop2", 0),
2.907 + 89 : ("dup", 0),
2.908 + 90 : ("dup_x1", 0),
2.909 + 91 : ("dup_x2", 0),
2.910 + 92 : ("dup2", 0),
2.911 + 93 : ("dup2_x1", 0),
2.912 + 94 : ("dup2_x2", 0),
2.913 + 95 : ("swap", 0),
2.914 + 96 : ("iadd", 0),
2.915 + 97 : ("ladd", 0),
2.916 + 98 : ("fadd", 0),
2.917 + 99 : ("dadd", 0),
2.918 + 100 : ("isub", 0),
2.919 + 101 : ("lsub", 0),
2.920 + 102 : ("fsub", 0),
2.921 + 103 : ("dsub", 0),
2.922 + 104 : ("imul", 0),
2.923 + 105 : ("lmul", 0),
2.924 + 106 : ("fmul", 0),
2.925 + 107 : ("dmul", 0),
2.926 + 108 : ("idiv", 0),
2.927 + 109 : ("ldiv", 0),
2.928 + 110 : ("fdiv", 0),
2.929 + 111 : ("ddiv", 0),
2.930 + 112 : ("irem", 0),
2.931 + 113 : ("lrem", 0),
2.932 + 114 : ("frem", 0),
2.933 + 115 : ("drem", 0),
2.934 + 116 : ("ineg", 0),
2.935 + 117 : ("lneg", 0),
2.936 + 118 : ("fneg", 0),
2.937 + 119 : ("dneg", 0),
2.938 + 120 : ("ishl", 0),
2.939 + 121 : ("lshl", 0),
2.940 + 122 : ("ishr", 0),
2.941 + 123 : ("lshr", 0),
2.942 + 124 : ("iushr", 0),
2.943 + 125 : ("lushr", 0),
2.944 + 126 : ("iand", 0),
2.945 + 127 : ("land", 0),
2.946 + 128 : ("ior", 0),
2.947 + 129 : ("lor", 0),
2.948 + 130 : ("ixor", 0),
2.949 + 131 : ("lxor", 0),
2.950 + 132 : ("iinc", 2),
2.951 + 133 : ("i2l", 0),
2.952 + 134 : ("i2f", 0),
2.953 + 135 : ("i2d", 0),
2.954 + 136 : ("l2i", 0),
2.955 + 137 : ("l2f", 0),
2.956 + 138 : ("l2d", 0),
2.957 + 139 : ("f2i", 0),
2.958 + 140 : ("f2l", 0),
2.959 + 141 : ("f2d", 0),
2.960 + 142 : ("d2i", 0),
2.961 + 143 : ("d2l", 0),
2.962 + 144 : ("d2f", 0),
2.963 + 145 : ("i2b", 0),
2.964 + 146 : ("i2c", 0),
2.965 + 147 : ("i2s", 0),
2.966 + 148 : ("lcmp", 0),
2.967 + 149 : ("fcmpl", 0),
2.968 + 150 : ("fcmpg", 0),
2.969 + 151 : ("dcmpl", 0),
2.970 + 152 : ("dcmpg", 0),
2.971 + 153 : ("ifeq", 2),
2.972 + 154 : ("ifne", 2),
2.973 + 155 : ("iflt", 2),
2.974 + 156 : ("ifge", 2),
2.975 + 157 : ("ifgt", 2),
2.976 + 158 : ("ifle", 2),
2.977 + 159 : ("if_icmpeq", 2),
2.978 + 160 : ("if_icmpne", 2),
2.979 + 161 : ("if_icmplt", 2),
2.980 + 162 : ("if_icmpge", 2),
2.981 + 163 : ("if_icmpgt", 2),
2.982 + 164 : ("if_icmple", 2),
2.983 + 165 : ("if_acmpeq", 2),
2.984 + 166 : ("if_acmpne", 2),
2.985 + 167 : ("goto", 2),
2.986 + 168 : ("jsr", 2),
2.987 + 169 : ("ret", 1),
2.988 + 170 : ("tableswitch", None), # variable number of arguments
2.989 + 171 : ("lookupswitch", None), # variable number of arguments
2.990 + 172 : ("ireturn", 0),
2.991 + 173 : ("lreturn", 0),
2.992 + 174 : ("freturn", 0),
2.993 + 175 : ("dreturn", 0),
2.994 + 176 : ("areturn", 0),
2.995 + 177 : ("return_", 0),
2.996 + 178 : ("getstatic", 2),
2.997 + 179 : ("putstatic", 2),
2.998 + 180 : ("getfield", 2),
2.999 + 181 : ("putfield", 2),
2.1000 + 182 : ("invokevirtual", 2),
2.1001 + 183 : ("invokespecial", 2),
2.1002 + 184 : ("invokestatic", 2),
2.1003 + 185 : ("invokeinterface", 4),
2.1004 + 187 : ("new", 2),
2.1005 + 188 : ("newarray", 1),
2.1006 + 189 : ("anewarray", 2),
2.1007 + 190 : ("arraylength", 0),
2.1008 + 191 : ("athrow", 0),
2.1009 + 192 : ("checkcast", 2),
2.1010 + 193 : ("instanceof", 2),
2.1011 + 194 : ("monitorenter", 0),
2.1012 + 195 : ("monitorexit", 0),
2.1013 + 196 : ("wide", None), # 3 or 5 arguments, stack changes according to modified element
2.1014 + 197 : ("multianewarray", 3),
2.1015 + 198 : ("ifnull", 2),
2.1016 + 199 : ("ifnonnull", 2),
2.1017 + 200 : ("goto_w", 4),
2.1018 + 201 : ("jsr_w", 4),
2.1019 + }
2.1020 +
2.1021 +class BytecodeDisassembler(BytecodeReader):
2.1022 +
2.1023 + "A Java bytecode disassembler."
2.1024 +
2.1025 + bytecode_methods = [spec[0] for spec in BytecodeReader.java_bytecodes.values()]
2.1026 +
2.1027 + def __getattr__(self, name):
2.1028 + if name in self.bytecode_methods:
2.1029 + print "%5s %s" % (self.java_position, name),
2.1030 + return self.generic
2.1031 + else:
2.1032 + raise AttributeError, name
2.1033 +
2.1034 + def generic(self, arguments, program):
2.1035 + print arguments
2.1036 +
2.1037 + def lookupswitch(self, code, program):
2.1038 + print "%5s lookupswitch" % (self.java_position,),
2.1039 + d, r = divmod(self.java_position + 1, 4)
2.1040 + to_boundary = (4 - r) % 4
2.1041 + code = code[to_boundary:]
2.1042 + default = classfile.u4(code[0:4])
2.1043 + npairs = classfile.u4(code[4:8])
2.1044 + print default, npairs
2.1045 + return to_boundary + 8 + npairs * 8
2.1046 +
2.1047 + def tableswitch(self, code, program):
2.1048 + print "%5s tableswitch" % (self.java_position,),
2.1049 + d, r = divmod(self.java_position + 1, 4)
2.1050 + to_boundary = (4 - r) % 4
2.1051 + code = code[to_boundary:]
2.1052 + default = classfile.u4(code[0:4])
2.1053 + low = classfile.u4(code[4:8])
2.1054 + high = classfile.u4(code[8:12])
2.1055 + print default, low, high
2.1056 + return to_boundary + 12 + (high - low + 1) * 4
2.1057 +
2.1058 +class BytecodeDisassemblerProgram:
2.1059 + position = 0
2.1060 + def setup_except(self, target):
2.1061 + print "(setup_except %s)" % target
2.1062 + def setup_finally(self, target):
2.1063 + print "(setup_finally %s)" % target
2.1064 + def end_exception(self):
2.1065 + print "(end_exception)"
2.1066 + def start_handler(self, exc_name, class_file):
2.1067 + print "(start_handler %s)" % exc_name
2.1068 + def pop_block(self):
2.1069 + print "(pop_block)"
2.1070 +
2.1071 +class BytecodeTranslator(BytecodeReader):
2.1072 +
2.1073 + "A Java bytecode translator which uses a Python bytecode writer."
2.1074 +
2.1075 + def aaload(self, arguments, program):
2.1076 + # NOTE: No type checking performed.
2.1077 + program.binary_subscr()
2.1078 +
2.1079 + def aastore(self, arguments, program):
2.1080 + # NOTE: No type checking performed.
2.1081 + # Stack: arrayref, index, value
2.1082 + program.rot_three() # Stack: value, arrayref, index
2.1083 + program.store_subscr()
2.1084 +
2.1085 + def aconst_null(self, arguments, program):
2.1086 + program.load_const(None)
2.1087 +
2.1088 + def aload(self, arguments, program):
2.1089 + program.load_fast(arguments[0])
2.1090 +
2.1091 + def aload_0(self, arguments, program):
2.1092 + program.load_fast(0)
2.1093 +
2.1094 + def aload_1(self, arguments, program):
2.1095 + program.load_fast(1)
2.1096 +
2.1097 + def aload_2(self, arguments, program):
2.1098 + program.load_fast(2)
2.1099 +
2.1100 + def aload_3(self, arguments, program):
2.1101 + program.load_fast(3)
2.1102 +
2.1103 + def anewarray(self, arguments, program):
2.1104 + # NOTE: Does not raise NegativeArraySizeException.
2.1105 + # NOTE: Not using the index to type the list/array.
2.1106 + index = (arguments[0] << 8) + arguments[1]
2.1107 + self._newarray(program)
2.1108 +
2.1109 + def _newarray(self, program):
2.1110 + program.build_list(0) # Stack: count, list
2.1111 + program.rot_two() # Stack: list, count
2.1112 + program.setup_loop()
2.1113 + program.load_global("range")
2.1114 + program.load_const(0) # Stack: list, count, range, 0
2.1115 + program.rot_three() # Stack: list, 0, count, range
2.1116 + program.rot_three() # Stack: list, range, 0, count
2.1117 + program.call_function(2) # Stack: list, range_list
2.1118 + program.get_iter() # Stack: list, iter
2.1119 + program.for_iter() # Stack: list, iter, value
2.1120 + program.pop_top() # Stack: list, iter
2.1121 + program.rot_two() # Stack: iter, list
2.1122 + program.dup_top() # Stack: iter, list, list
2.1123 + program.load_attr("append") # Stack: iter, list, append
2.1124 + program.load_const(None) # Stack: iter, list, append, None
2.1125 + program.call_function(1) # Stack: iter, list, None
2.1126 + program.pop_top() # Stack: iter, list
2.1127 + program.rot_two() # Stack: list, iter
2.1128 + program.end_loop() # Back to for_iter above
2.1129 +
2.1130 + def areturn(self, arguments, program):
2.1131 + program.return_value()
2.1132 +
2.1133 + def arraylength(self, arguments, program):
2.1134 + program.load_global("len") # Stack: arrayref, len
2.1135 + program.rot_two() # Stack: len, arrayref
2.1136 + program.call_function(1)
2.1137 +
2.1138 + def astore(self, arguments, program):
2.1139 + program.store_fast(arguments[0])
2.1140 +
2.1141 + def astore_0(self, arguments, program):
2.1142 + program.store_fast(0)
2.1143 +
2.1144 + def astore_1(self, arguments, program):
2.1145 + program.store_fast(1)
2.1146 +
2.1147 + def astore_2(self, arguments, program):
2.1148 + program.store_fast(2)
2.1149 +
2.1150 + def astore_3(self, arguments, program):
2.1151 + program.store_fast(3)
2.1152 +
2.1153 + def athrow(self, arguments, program):
2.1154 + # NOTE: NullPointerException not raised where null/None is found on the stack.
2.1155 + # If this instruction appears in a finally handler, use end_finally instead.
2.1156 + if self.in_finally:
2.1157 + program.end_finally()
2.1158 + else:
2.1159 + # Wrap the exception in a Python exception.
2.1160 + program.load_global("Exception") # Stack: objectref, Exception
2.1161 + program.rot_two() # Stack: Exception, objectref
2.1162 + program.call_function(1) # Stack: exception
2.1163 + program.raise_varargs(1)
2.1164 + # NOTE: This seems to put another object on the stack.
2.1165 +
2.1166 + baload = aaload
2.1167 + bastore = aastore
2.1168 +
2.1169 + def bipush(self, arguments, program):
2.1170 + program.load_const(signed1(arguments[0]))
2.1171 +
2.1172 + caload = aaload
2.1173 + castore = aastore
2.1174 +
2.1175 + def checkcast(self, arguments, program):
2.1176 + index = (arguments[0] << 8) + arguments[1]
2.1177 + target_name = self.class_file.constants[index - 1].get_python_name()
2.1178 + program.use_external_name(target_name)
2.1179 + program.dup_top() # Stack: objectref, objectref
2.1180 + program.load_const(None) # Stack: objectref, objectref, None
2.1181 + program.compare_op("is") # Stack: objectref, result
2.1182 + program.jump_to_label(1, "next")
2.1183 + program.pop_top() # Stack: objectref
2.1184 + program.dup_top() # Stack: objectref, objectref
2.1185 + program.load_global("isinstance") # Stack: objectref, objectref, isinstance
2.1186 + program.rot_two() # Stack: objectref, isinstance, objectref
2.1187 + load_class_name(self.class_file, target_name, program)
2.1188 + program.call_function(2) # Stack: objectref, result
2.1189 + program.jump_to_label(1, "next")
2.1190 + program.pop_top() # Stack: objectref
2.1191 + program.pop_top() # Stack:
2.1192 + program.use_external_name("java.lang.ClassCastException")
2.1193 + load_class_name(self.class_file, "java.lang.ClassCastException", program)
2.1194 + program.call_function(0) # Stack: exception
2.1195 + # Wrap the exception in a Python exception.
2.1196 + program.load_global("Exception") # Stack: exception, Exception
2.1197 + program.rot_two() # Stack: Exception, exception
2.1198 + program.call_function(1) # Stack: exception
2.1199 + program.raise_varargs(1)
2.1200 + # NOTE: This seems to put another object on the stack.
2.1201 + program.start_label("next")
2.1202 + program.pop_top() # Stack: objectref
2.1203 +
2.1204 + def d2f(self, arguments, program):
2.1205 + pass
2.1206 +
2.1207 + def d2i(self, arguments, program):
2.1208 + program.load_global("int") # Stack: value, int
2.1209 + program.rot_two() # Stack: int, value
2.1210 + program.call_function(1) # Stack: result
2.1211 +
2.1212 + d2l = d2i # Preserving Java semantics
2.1213 +
2.1214 + def dadd(self, arguments, program):
2.1215 + # NOTE: No type checking performed.
2.1216 + program.binary_add()
2.1217 +
2.1218 + daload = aaload
2.1219 + dastore = aastore
2.1220 +
2.1221 + def dcmpg(self, arguments, program):
2.1222 + # NOTE: No type checking performed.
2.1223 + program.compare_op(">")
2.1224 +
2.1225 + def dcmpl(self, arguments, program):
2.1226 + # NOTE: No type checking performed.
2.1227 + program.compare_op("<")
2.1228 +
2.1229 + def dconst_0(self, arguments, program):
2.1230 + program.load_const(0.0)
2.1231 +
2.1232 + def dconst_1(self, arguments, program):
2.1233 + program.load_const(1.0)
2.1234 +
2.1235 + def ddiv(self, arguments, program):
2.1236 + # NOTE: No type checking performed.
2.1237 + program.binary_divide()
2.1238 +
2.1239 + dload = aload
2.1240 + dload_0 = aload_0
2.1241 + dload_1 = aload_1
2.1242 + dload_2 = aload_2
2.1243 + dload_3 = aload_3
2.1244 +
2.1245 + def dmul(self, arguments, program):
2.1246 + # NOTE: No type checking performed.
2.1247 + program.binary_multiply()
2.1248 +
2.1249 + def dneg(self, arguments, program):
2.1250 + # NOTE: No type checking performed.
2.1251 + program.unary_negative()
2.1252 +
2.1253 + def drem(self, arguments, program):
2.1254 + # NOTE: No type checking performed.
2.1255 + program.binary_modulo()
2.1256 +
2.1257 + dreturn = areturn
2.1258 + dstore = astore
2.1259 + dstore_0 = astore_0
2.1260 + dstore_1 = astore_1
2.1261 + dstore_2 = astore_2
2.1262 + dstore_3 = astore_3
2.1263 +
2.1264 + def dsub(self, arguments, program):
2.1265 + # NOTE: No type checking performed.
2.1266 + program.binary_subtract()
2.1267 +
2.1268 + def dup(self, arguments, program):
2.1269 + program.dup_top()
2.1270 +
2.1271 + def dup_x1(self, arguments, program):
2.1272 + # Ignoring computational type categories.
2.1273 + program.dup_top()
2.1274 + program.rot_three()
2.1275 +
2.1276 + def dup_x2(self, arguments, program):
2.1277 + # Ignoring computational type categories.
2.1278 + program.dup_top()
2.1279 + program.rot_four()
2.1280 +
2.1281 + dup2 = dup # Ignoring computational type categories
2.1282 + dup2_x1 = dup_x1 # Ignoring computational type categories
2.1283 + dup2_x2 = dup_x2 # Ignoring computational type categories
2.1284 +
2.1285 + def f2d(self, arguments, program):
2.1286 + pass # Preserving Java semantics
2.1287 +
2.1288 + def f2i(self, arguments, program):
2.1289 + program.load_global("int") # Stack: value, int
2.1290 + program.rot_two() # Stack: int, value
2.1291 + program.call_function(1) # Stack: result
2.1292 +
2.1293 + f2l = f2i # Preserving Java semantics
2.1294 + fadd = dadd
2.1295 + faload = daload
2.1296 + fastore = dastore
2.1297 + fcmpg = dcmpg
2.1298 + fcmpl = dcmpl
2.1299 + fconst_0 = dconst_0
2.1300 + fconst_1 = dconst_1
2.1301 +
2.1302 + def fconst_2(self, arguments, program):
2.1303 + program.load_const(2.0)
2.1304 +
2.1305 + fdiv = ddiv
2.1306 + fload = dload
2.1307 + fload_0 = dload_0
2.1308 + fload_1 = dload_1
2.1309 + fload_2 = dload_2
2.1310 + fload_3 = dload_3
2.1311 + fmul = dmul
2.1312 + fneg = dneg
2.1313 + frem = drem
2.1314 + freturn = dreturn
2.1315 + fstore = dstore
2.1316 + fstore_0 = dstore_0
2.1317 + fstore_1 = dstore_1
2.1318 + fstore_2 = dstore_2
2.1319 + fstore_3 = dstore_3
2.1320 + fsub = dsub
2.1321 +
2.1322 + def getfield(self, arguments, program):
2.1323 + index = (arguments[0] << 8) + arguments[1]
2.1324 + target_name = self.class_file.constants[index - 1].get_python_name()
2.1325 + # NOTE: Using the string version of the name which may contain incompatible characters.
2.1326 + program.load_attr(str(target_name))
2.1327 +
2.1328 + def getstatic(self, arguments, program):
2.1329 + index = (arguments[0] << 8) + arguments[1]
2.1330 + target = self.class_file.constants[index - 1]
2.1331 + target_name = target.get_python_name()
2.1332 +
2.1333 + # Get the class name instead of the fully qualified name.
2.1334 +
2.1335 + full_class_name = target.get_class().get_python_name()
2.1336 + program.use_external_name(full_class_name)
2.1337 + load_class_name(self.class_file, full_class_name, program)
2.1338 + # NOTE: Using the string version of the name which may contain incompatible characters.
2.1339 + program.load_attr(str(target_name))
2.1340 +
2.1341 + def goto(self, arguments, program):
2.1342 + offset = signed2((arguments[0] << 8) + arguments[1])
2.1343 + java_absolute = self.java_position + offset
2.1344 + program.jump_absolute(self.position_mapping[java_absolute])
2.1345 +
2.1346 + def goto_w(self, arguments, program):
2.1347 + offset = signed4((arguments[0] << 24) + (arguments[1] << 16) + (arguments[2] << 8) + arguments[3])
2.1348 + java_absolute = self.java_position + offset
2.1349 + program.jump_absolute(self.position_mapping[java_absolute])
2.1350 +
2.1351 + def i2b(self, arguments, program):
2.1352 + pass
2.1353 +
2.1354 + def i2c(self, arguments, program):
2.1355 + pass
2.1356 +
2.1357 + def i2d(self, arguments, program):
2.1358 + program.load_global("float") # Stack: value, float
2.1359 + program.rot_two() # Stack: float, value
2.1360 + program.call_function(1) # Stack: result
2.1361 +
2.1362 + i2f = i2d # Not distinguishing between float and double
2.1363 +
2.1364 + def i2l(self, arguments, program):
2.1365 + pass # Preserving Java semantics
2.1366 +
2.1367 + def i2s(self, arguments, program):
2.1368 + pass # Not distinguishing between int and short
2.1369 +
2.1370 + iadd = fadd
2.1371 + iaload = faload
2.1372 +
2.1373 + def iand(self, arguments, program):
2.1374 + # NOTE: No type checking performed.
2.1375 + program.binary_and()
2.1376 +
2.1377 + iastore = fastore
2.1378 +
2.1379 + def iconst_m1(self, arguments, program):
2.1380 + program.load_const(-1)
2.1381 +
2.1382 + def iconst_0(self, arguments, program):
2.1383 + program.load_const(0)
2.1384 +
2.1385 + def iconst_1(self, arguments, program):
2.1386 + program.load_const(1)
2.1387 +
2.1388 + def iconst_2(self, arguments, program):
2.1389 + program.load_const(2)
2.1390 +
2.1391 + def iconst_3(self, arguments, program):
2.1392 + program.load_const(3)
2.1393 +
2.1394 + def iconst_4(self, arguments, program):
2.1395 + program.load_const(4)
2.1396 +
2.1397 + def iconst_5(self, arguments, program):
2.1398 + program.load_const(5)
2.1399 +
2.1400 + idiv = fdiv
2.1401 +
2.1402 + def _if_xcmpx(self, arguments, program, op):
2.1403 + offset = signed2((arguments[0] << 8) + arguments[1])
2.1404 + java_absolute = self.java_position + offset
2.1405 + program.compare_op(op)
2.1406 + program.jump_to_label(0, "next") # skip if false
2.1407 + program.pop_top()
2.1408 + program.jump_absolute(self.position_mapping[java_absolute])
2.1409 + program.start_label("next")
2.1410 + program.pop_top()
2.1411 +
2.1412 + def if_acmpeq(self, arguments, program):
2.1413 + # NOTE: No type checking performed.
2.1414 + self._if_xcmpx(arguments, program, "is")
2.1415 +
2.1416 + def if_acmpne(self, arguments, program):
2.1417 + # NOTE: No type checking performed.
2.1418 + self._if_xcmpx(arguments, program, "is not")
2.1419 +
2.1420 + def if_icmpeq(self, arguments, program):
2.1421 + # NOTE: No type checking performed.
2.1422 + self._if_xcmpx(arguments, program, "==")
2.1423 +
2.1424 + def if_icmpne(self, arguments, program):
2.1425 + # NOTE: No type checking performed.
2.1426 + self._if_xcmpx(arguments, program, "!=")
2.1427 +
2.1428 + def if_icmplt(self, arguments, program):
2.1429 + # NOTE: No type checking performed.
2.1430 + self._if_xcmpx(arguments, program, "<")
2.1431 +
2.1432 + def if_icmpge(self, arguments, program):
2.1433 + # NOTE: No type checking performed.
2.1434 + self._if_xcmpx(arguments, program, ">=")
2.1435 +
2.1436 + def if_icmpgt(self, arguments, program):
2.1437 + # NOTE: No type checking performed.
2.1438 + self._if_xcmpx(arguments, program, ">")
2.1439 +
2.1440 + def if_icmple(self, arguments, program):
2.1441 + # NOTE: No type checking performed.
2.1442 + self._if_xcmpx(arguments, program, "<=")
2.1443 +
2.1444 + def ifeq(self, arguments, program):
2.1445 + # NOTE: No type checking performed.
2.1446 + program.load_const(0)
2.1447 + self._if_xcmpx(arguments, program, "==")
2.1448 +
2.1449 + def ifne(self, arguments, program):
2.1450 + # NOTE: No type checking performed.
2.1451 + program.load_const(0)
2.1452 + self._if_xcmpx(arguments, program, "!=")
2.1453 +
2.1454 + def iflt(self, arguments, program):
2.1455 + # NOTE: No type checking performed.
2.1456 + program.load_const(0)
2.1457 + self._if_xcmpx(arguments, program, "<")
2.1458 +
2.1459 + def ifge(self, arguments, program):
2.1460 + # NOTE: No type checking performed.
2.1461 + program.load_const(0)
2.1462 + self._if_xcmpx(arguments, program, ">=")
2.1463 +
2.1464 + def ifgt(self, arguments, program):
2.1465 + # NOTE: No type checking performed.
2.1466 + program.load_const(0)
2.1467 + self._if_xcmpx(arguments, program, ">")
2.1468 +
2.1469 + def ifle(self, arguments, program):
2.1470 + # NOTE: No type checking performed.
2.1471 + program.load_const(0)
2.1472 + self._if_xcmpx(arguments, program, "<=")
2.1473 +
2.1474 + def ifnonnull(self, arguments, program):
2.1475 + # NOTE: No type checking performed.
2.1476 + program.load_const(None)
2.1477 + self._if_xcmpx(arguments, program, "is not")
2.1478 +
2.1479 + def ifnull(self, arguments, program):
2.1480 + # NOTE: No type checking performed.
2.1481 + program.load_const(None)
2.1482 + self._if_xcmpx(arguments, program, "is")
2.1483 +
2.1484 + def iinc(self, arguments, program):
2.1485 + # NOTE: No type checking performed.
2.1486 + program.load_fast(arguments[0])
2.1487 + program.load_const(arguments[1])
2.1488 + program.binary_add()
2.1489 + program.store_fast(arguments[0])
2.1490 +
2.1491 + iload = fload
2.1492 + iload_0 = fload_0
2.1493 + iload_1 = fload_1
2.1494 + iload_2 = fload_2
2.1495 + iload_3 = fload_3
2.1496 + imul = fmul
2.1497 + ineg = fneg
2.1498 +
2.1499 + def instanceof(self, arguments, program):
2.1500 + index = (arguments[0] << 8) + arguments[1]
2.1501 + target_name = self.class_file.constants[index - 1].get_python_name()
2.1502 + program.use_external_name(target_name)
2.1503 + program.load_global("isinstance") # Stack: objectref, isinstance
2.1504 + program.rot_two() # Stack: isinstance, objectref
2.1505 + load_class_name(self.class_file, target_name, program)
2.1506 + program.call_function(2) # Stack: result
2.1507 +
2.1508 + def _invoke(self, target_name, program):
2.1509 + # NOTE: Using the string version of the name which may contain incompatible characters.
2.1510 + program.load_attr(str(target_name)) # Stack: tuple, method
2.1511 + program.rot_two() # Stack: method, tuple
2.1512 + program.call_function_var(0) # Stack: result
2.1513 +
2.1514 + def invokeinterface(self, arguments, program):
2.1515 + # NOTE: This implementation does not perform the necessary checks for
2.1516 + # NOTE: signature-based polymorphism.
2.1517 + # NOTE: Java rules not specifically obeyed.
2.1518 + index = (arguments[0] << 8) + arguments[1]
2.1519 + # NOTE: "count" == nargs + 1, apparently.
2.1520 + count = arguments[2] - 1
2.1521 + target_name = self.class_file.constants[index - 1].get_python_name()
2.1522 + # Stack: objectref, arg1, arg2, ...
2.1523 + program.build_tuple(count) # Stack: objectref, tuple
2.1524 + program.rot_two() # Stack: tuple, objectref
2.1525 + # NOTE: The interface information is not used to discover the correct
2.1526 + # NOTE: method.
2.1527 + self._invoke(target_name, program)
2.1528 +
2.1529 + def invokespecial(self, arguments, program):
2.1530 + # NOTE: This implementation does not perform the necessary checks for
2.1531 + # NOTE: signature-based polymorphism.
2.1532 + # NOTE: Java rules not specifically obeyed.
2.1533 + index = (arguments[0] << 8) + arguments[1]
2.1534 + target = self.class_file.constants[index - 1]
2.1535 + original_name = target.get_name()
2.1536 + target_name = target.get_python_name()
2.1537 +
2.1538 + # Get the number of parameters from the descriptor.
2.1539 +
2.1540 + count = len(target.get_descriptor()[0])
2.1541 +
2.1542 + # First, we build a tuple of the reference and arguments.
2.1543 +
2.1544 + program.build_tuple(count + 1) # Stack: tuple
2.1545 +
2.1546 + # Get the class name instead of the fully qualified name.
2.1547 + # NOTE: Not bothering with Object initialisation.
2.1548 +
2.1549 + full_class_name = target.get_class().get_python_name()
2.1550 + if full_class_name not in ("java.lang.Object", "java.lang.Exception"):
2.1551 + program.use_external_name(full_class_name)
2.1552 + load_class_name(self.class_file, full_class_name, program)
2.1553 + self._invoke(target_name, program)
2.1554 +
2.1555 + # Remove Python None return value.
2.1556 +
2.1557 + if str(original_name) == "<init>":
2.1558 + program.pop_top()
2.1559 +
2.1560 + def invokestatic(self, arguments, program):
2.1561 + # NOTE: This implementation does not perform the necessary checks for
2.1562 + # NOTE: signature-based polymorphism.
2.1563 + # NOTE: Java rules not specifically obeyed.
2.1564 + index = (arguments[0] << 8) + arguments[1]
2.1565 + target = self.class_file.constants[index - 1]
2.1566 + target_name = target.get_python_name()
2.1567 +
2.1568 + # Get the number of parameters from the descriptor.
2.1569 +
2.1570 + count = len(target.get_descriptor()[0])
2.1571 +
2.1572 + # Stack: arg1, arg2, ...
2.1573 +
2.1574 + program.build_tuple(count) # Stack: tuple
2.1575 +
2.1576 + # Use the class to provide access to static methods.
2.1577 + # Get the class name instead of the fully qualified name.
2.1578 +
2.1579 + full_class_name = target.get_class().get_python_name()
2.1580 + if full_class_name not in ("java.lang.Object", "java.lang.Exception"):
2.1581 + program.use_external_name(full_class_name)
2.1582 + load_class_name(self.class_file, full_class_name, program)
2.1583 + self._invoke(target_name, program)
2.1584 +
2.1585 + def invokevirtual (self, arguments, program):
2.1586 + # NOTE: This implementation does not perform the necessary checks for
2.1587 + # NOTE: signature-based polymorphism.
2.1588 + # NOTE: Java rules not specifically obeyed.
2.1589 + index = (arguments[0] << 8) + arguments[1]
2.1590 + target = self.class_file.constants[index - 1]
2.1591 + target_name = target.get_python_name()
2.1592 + # Get the number of parameters from the descriptor.
2.1593 + count = len(target.get_descriptor()[0])
2.1594 + # Stack: objectref, arg1, arg2, ...
2.1595 + program.build_tuple(count) # Stack: objectref, tuple
2.1596 + program.rot_two() # Stack: tuple, objectref
2.1597 + self._invoke(target_name, program)
2.1598 +
2.1599 + def ior(self, arguments, program):
2.1600 + # NOTE: No type checking performed.
2.1601 + program.binary_or()
2.1602 +
2.1603 + irem = frem
2.1604 + ireturn = freturn
2.1605 +
2.1606 + def ishl(self, arguments, program):
2.1607 + # NOTE: No type checking performed.
2.1608 + # NOTE: Not verified.
2.1609 + program.binary_lshift()
2.1610 +
2.1611 + def ishr(self, arguments, program):
2.1612 + # NOTE: No type checking performed.
2.1613 + # NOTE: Not verified.
2.1614 + program.binary_rshift()
2.1615 +
2.1616 + istore = fstore
2.1617 + istore_0 = fstore_0
2.1618 + istore_1 = fstore_1
2.1619 + istore_2 = fstore_2
2.1620 + istore_3 = fstore_3
2.1621 + isub = fsub
2.1622 + iushr = ishr # Ignoring distinctions between arithmetic and logical shifts
2.1623 +
2.1624 + def ixor(self, arguments, program):
2.1625 + # NOTE: No type checking performed.
2.1626 + program.binary_xor()
2.1627 +
2.1628 + def jsr(self, arguments, program):
2.1629 + offset = signed2((arguments[0] << 8) + arguments[1])
2.1630 + java_absolute = self.java_position + offset
2.1631 + # Store the address of the next instruction.
2.1632 + program.load_const_ret(self.position_mapping[self.java_position + 3])
2.1633 + program.jump_absolute(self.position_mapping[java_absolute])
2.1634 +
2.1635 + def jsr_w(self, arguments, program):
2.1636 + offset = signed4((arguments[0] << 24) + (arguments[1] << 16) + (arguments[2] << 8) + arguments[3])
2.1637 + java_absolute = self.java_position + offset
2.1638 + # Store the address of the next instruction.
2.1639 + program.load_const_ret(self.position_mapping[self.java_position + 5])
2.1640 + program.jump_absolute(self.position_mapping[java_absolute])
2.1641 +
2.1642 + l2d = i2d
2.1643 + l2f = i2f
2.1644 +
2.1645 + def l2i(self, arguments, program):
2.1646 + pass # Preserving Java semantics
2.1647 +
2.1648 + ladd = iadd
2.1649 + laload = iaload
2.1650 + land = iand
2.1651 + lastore = iastore
2.1652 +
2.1653 + def lcmp(self, arguments, program):
2.1654 + # NOTE: No type checking performed.
2.1655 + program.dup_topx(2) # Stack: value1, value2, value1, value2
2.1656 + program.compare_op(">") # Stack: value1, value2, result
2.1657 + program.jump_to_label(0, "equals")
2.1658 + # True - produce result and branch.
2.1659 + program.pop_top() # Stack: value1, value2
2.1660 + program.pop_top() # Stack: value1
2.1661 + program.pop_top() # Stack:
2.1662 + program.load_const(1) # Stack: 1
2.1663 + program.jump_to_label(None, "next")
2.1664 + # False - test equality.
2.1665 + program.start_label("equals")
2.1666 + program.pop_top() # Stack: value1, value2
2.1667 + program.dup_topx(2) # Stack: value1, value2, value1, value2
2.1668 + program.compare_op("==") # Stack: value1, value2, result
2.1669 + program.jump_to_label(0, "less")
2.1670 + # True - produce result and branch.
2.1671 + program.pop_top() # Stack: value1, value2
2.1672 + program.pop_top() # Stack: value1
2.1673 + program.pop_top() # Stack:
2.1674 + program.load_const(0) # Stack: 0
2.1675 + program.jump_to_label(None, "next")
2.1676 + # False - produce result.
2.1677 + program.start_label("less")
2.1678 + program.pop_top() # Stack: value1, value2
2.1679 + program.pop_top() # Stack: value1
2.1680 + program.pop_top() # Stack:
2.1681 + program.load_const(-1) # Stack: -1
2.1682 + program.start_label("next")
2.1683 +
2.1684 + lconst_0 = iconst_0
2.1685 + lconst_1 = iconst_1
2.1686 +
2.1687 + def ldc(self, arguments, program):
2.1688 + const = self.class_file.constants[arguments[0] - 1]
2.1689 + if isinstance(const, classfile.StringInfo):
2.1690 + program.use_external_name("java.lang.String")
2.1691 + program.load_global("java")
2.1692 + program.load_attr("lang")
2.1693 + program.load_attr("String")
2.1694 + program.load_const(const.get_value())
2.1695 + program.call_function(1)
2.1696 + else:
2.1697 + program.load_const(const.get_value())
2.1698 +
2.1699 + def ldc_w(self, arguments, program):
2.1700 + const = self.class_file.constants[(arguments[0] << 8) + arguments[1] - 1]
2.1701 + if isinstance(const, classfile.StringInfo):
2.1702 + program.use_external_name("java.lang.String")
2.1703 + program.load_global("java")
2.1704 + program.load_attr("lang")
2.1705 + program.load_attr("String")
2.1706 + program.load_const(const.get_value())
2.1707 + program.call_function(1)
2.1708 + else:
2.1709 + program.load_const(const.get_value())
2.1710 +
2.1711 + ldc2_w = ldc_w
2.1712 + ldiv = idiv
2.1713 + lload = iload
2.1714 + lload_0 = iload_0
2.1715 + lload_1 = iload_1
2.1716 + lload_2 = iload_2
2.1717 + lload_3 = iload_3
2.1718 + lmul = imul
2.1719 + lneg = ineg
2.1720 +
2.1721 + def lookupswitch(self, code, program):
2.1722 +
2.1723 + # Find the offset to the next 4 byte boundary in the code.
2.1724 +
2.1725 + d, r = divmod(self.java_position + 1, 4)
2.1726 + to_boundary = (4 - r) % 4
2.1727 +
2.1728 + # Get the pertinent arguments.
2.1729 +
2.1730 + code = code[to_boundary:]
2.1731 + default = classfile.u4(code[0:4])
2.1732 + npairs = classfile.u4(code[4:8])
2.1733 +
2.1734 + # Process the pairs.
2.1735 + # NOTE: This is not the most optimal implementation.
2.1736 +
2.1737 + pair_index = 8
2.1738 + for pair in range(0, npairs):
2.1739 + match = classfile.u4(code[pair_index:pair_index+4])
2.1740 + offset = classfile.s4(code[pair_index+4:pair_index+8])
2.1741 + # Calculate the branch target.
2.1742 + java_absolute = self.java_position + offset
2.1743 + # Generate branching code.
2.1744 + program.dup_top() # Stack: key, key
2.1745 + program.load_const(match) # Stack: key, key, match
2.1746 + program.compare_op("==") # Stack: key, result
2.1747 + program.jump_to_label(0, "end")
2.1748 + program.pop_top() # Stack: key
2.1749 + program.pop_top() # Stack:
2.1750 + program.jump_absolute(self.position_mapping[java_absolute])
2.1751 + # Generate the label for the end of the branching code.
2.1752 + program.start_label("end")
2.1753 + program.pop_top() # Stack: key
2.1754 + # Update the index.
2.1755 + pair_index += 4
2.1756 +
2.1757 + # Generate the default.
2.1758 +
2.1759 + java_absolute = self.java_position + default
2.1760 + program.jump_absolute(self.position_mapping[java_absolute])
2.1761 + return pair_index + to_boundary
2.1762 +
2.1763 + lor = ior
2.1764 + lrem = irem
2.1765 + lreturn = ireturn
2.1766 + lshl = ishl
2.1767 + lshr = ishr
2.1768 + lstore = istore
2.1769 + lstore_0 = istore_0
2.1770 + lstore_1 = istore_1
2.1771 + lstore_2 = istore_2
2.1772 + lstore_3 = istore_3
2.1773 + lsub = isub
2.1774 + lushr = iushr
2.1775 + lxor = ixor
2.1776 +
2.1777 + def monitorenter(self, arguments, program):
2.1778 + # NOTE: To be implemented.
2.1779 + pass
2.1780 +
2.1781 + def monitorexit(self, arguments, program):
2.1782 + # NOTE: To be implemented.
2.1783 + pass
2.1784 +
2.1785 + def multianewarray(self, arguments, program):
2.1786 + index = (arguments[0] << 8) + arguments[1]
2.1787 + dimensions = arguments[2]
2.1788 + # Stack: count1, ..., countN-1, countN
2.1789 + self._newarray(program) # Stack: count1, ..., countN-1, list
2.1790 + for dimension in range(1, dimensions):
2.1791 + program.rot_two() # Stack: count1, ..., list, countN-1
2.1792 + program.build_list(0) # Stack: count1, ..., list, countN-1, new-list
2.1793 + program.rot_three() # Stack: count1, ..., new-list, list, countN-1
2.1794 + program.setup_loop()
2.1795 + program.load_const(0) # Stack: count1, ..., new-list, list, countN-1, 0
2.1796 + program.rot_two() # Stack: count1, ..., new-list, list, 0, countN-1
2.1797 + program.load_global("range") # Stack: count1, ..., new-list, list, 0, countN-1, range
2.1798 + program.rot_three() # Stack: count1, ..., new-list, list, range, 0, countN-1
2.1799 + program.call_function(2) # Stack: count1, ..., new-list, list, range-list
2.1800 + program.get_iter() # Stack: count1, ..., new-list, list, iter
2.1801 + program.for_iter() # Stack: count1, ..., new-list, list, iter, value
2.1802 + program.pop_top() # Stack: count1, ..., new-list, list, iter
2.1803 + program.rot_three() # Stack: count1, ..., iter, new-list, list
2.1804 + program.slice_0() # Stack: count1, ..., iter, new-list, list[:]
2.1805 + program.dup_top() # Stack: count1, ..., iter, new-list, list[:], list[:]
2.1806 + program.rot_three() # Stack: count1, ..., iter, list[:], new-list, list[:]
2.1807 + program.rot_two() # Stack: count1, ..., iter, list[:], list[:], new-list
2.1808 + program.dup_top() # Stack: count1, ..., iter, list[:], list[:], new-list, new-list
2.1809 + program.load_attr("append") # Stack: count1, ..., iter, list[:], list[:], new-list, append
2.1810 + program.rot_three() # Stack: count1, ..., iter, list[:], append, list[:], new-list
2.1811 + program.rot_three() # Stack: count1, ..., iter, list[:], new-list, append, list[:]
2.1812 + program.call_function(1) # Stack: count1, ..., iter, list[:], new-list, None
2.1813 + program.pop_top() # Stack: count1, ..., iter, list[:], new-list
2.1814 + program.rot_two() # Stack: count1, ..., iter, new-list, list[:]
2.1815 + program.rot_three() # Stack: count1, ..., list[:], iter, new-list
2.1816 + program.rot_three() # Stack: count1, ..., new-list, list[:], iter
2.1817 + program.end_loop() # Stack: count1, ..., new-list, list[:], iter
2.1818 + program.pop_top() # Stack: count1, ..., new-list
2.1819 +
2.1820 + def new(self, arguments, program):
2.1821 + # This operation is considered to be the same as the calling of the
2.1822 + # initialisation method of the given class with no arguments.
2.1823 +
2.1824 + index = (arguments[0] << 8) + arguments[1]
2.1825 + target_name = self.class_file.constants[index - 1].get_python_name()
2.1826 + program.use_external_name(target_name)
2.1827 +
2.1828 + # NOTE: Using the string version of the name which may contain incompatible characters.
2.1829 + program.load_global("object")
2.1830 + program.load_attr("__new__")
2.1831 + load_class_name(self.class_file, target_name, program)
2.1832 + program.call_function(1)
2.1833 +
2.1834 + def newarray(self, arguments, program):
2.1835 + # NOTE: Does not raise NegativeArraySizeException.
2.1836 + # NOTE: Not using the arguments to type the list/array.
2.1837 + self._newarray(program)
2.1838 +
2.1839 + def nop(self, arguments, program):
2.1840 + pass
2.1841 +
2.1842 + def pop(self, arguments, program):
2.1843 + program.pop_top()
2.1844 +
2.1845 + pop2 = pop # ignoring Java stack value distinctions
2.1846 +
2.1847 + def putfield(self, arguments, program):
2.1848 + index = (arguments[0] << 8) + arguments[1]
2.1849 + target_name = self.class_file.constants[index - 1].get_python_name()
2.1850 + program.rot_two()
2.1851 + # NOTE: Using the string version of the name which may contain incompatible characters.
2.1852 + program.store_attr(str(target_name))
2.1853 +
2.1854 + def putstatic(self, arguments, program):
2.1855 + index = (arguments[0] << 8) + arguments[1]
2.1856 + target = self.class_file.constants[index - 1]
2.1857 + target_name = target.get_python_name()
2.1858 +
2.1859 + # Get the class name instead of the fully qualified name.
2.1860 +
2.1861 + full_class_name = target.get_class().get_python_name()
2.1862 + program.use_external_name(full_class_name)
2.1863 + load_class_name(self.class_file, full_class_name, program)
2.1864 + # NOTE: Using the string version of the name which may contain incompatible characters.
2.1865 + program.store_attr(str(target_name))
2.1866 +
2.1867 + def ret(self, arguments, program):
2.1868 + program.ret(arguments[0])
2.1869 + # Indicate that the finally handler is probably over.
2.1870 + # NOTE: This is seemingly not guaranteed.
2.1871 + self.in_finally = 0
2.1872 +
2.1873 + def return_(self, arguments, program):
2.1874 + program.load_const(None)
2.1875 + program.return_value()
2.1876 +
2.1877 + saload = laload
2.1878 + sastore = lastore
2.1879 +
2.1880 + def sipush(self, arguments, program):
2.1881 + program.load_const(signed2((arguments[0] << 8) + arguments[1]))
2.1882 +
2.1883 + def swap(self, arguments, program):
2.1884 + program.rot_two()
2.1885 +
2.1886 + def tableswitch(self, code, program):
2.1887 +
2.1888 + # Find the offset to the next 4 byte boundary in the code.
2.1889 +
2.1890 + d, r = divmod(self.java_position + 1, 4)
2.1891 + to_boundary = (4 - r) % 4
2.1892 +
2.1893 + # Get the pertinent arguments.
2.1894 +
2.1895 + code = code[to_boundary:]
2.1896 + default = classfile.u4(code[0:4])
2.1897 + low = classfile.u4(code[4:8])
2.1898 + high = classfile.u4(code[8:12])
2.1899 +
2.1900 + # Process the jump entries.
2.1901 + # NOTE: This is not the most optimal implementation.
2.1902 +
2.1903 + jump_index = 12
2.1904 + for jump in range(low, high + 1):
2.1905 + offset = classfile.s4(code[jump_index:jump_index + 4])
2.1906 +
2.1907 + # Calculate the branch target.
2.1908 +
2.1909 + java_absolute = self.java_position + offset
2.1910 +
2.1911 + # Generate branching code.
2.1912 +
2.1913 + program.dup_top() # Stack: key, key
2.1914 + program.load_const(jump) # Stack: key, key, jump
2.1915 + program.compare_op("==") # Stack: key, result
2.1916 + program.jump_to_label(0, "end")
2.1917 + program.pop_top() # Stack: key
2.1918 + program.pop_top() # Stack:
2.1919 + program.jump_absolute(self.position_mapping[java_absolute])
2.1920 +
2.1921 + # Generate the label for the end of the branching code.
2.1922 +
2.1923 + program.start_label("end")
2.1924 + program.pop_top() # Stack: key
2.1925 +
2.1926 + # Update the index.
2.1927 +
2.1928 + jump_index += 4
2.1929 +
2.1930 + # Generate the default.
2.1931 +
2.1932 + java_absolute = self.java_position + default
2.1933 + program.jump_absolute(self.position_mapping[java_absolute])
2.1934 + return jump_index + to_boundary
2.1935 +
2.1936 + def wide(self, code, program):
2.1937 + # NOTE: To be implemented.
2.1938 + return number_of_arguments
2.1939 +
2.1940 +def disassemble(class_file, method):
2.1941 + disassembler = BytecodeDisassembler(class_file)
2.1942 + disassembler.process(method, BytecodeDisassemblerProgram())
2.1943 +
2.1944 +class ClassTranslator:
2.1945 +
2.1946 + """
2.1947 + A class which provides a wrapper around a class file and the means to
2.1948 + translate the represented class into a Python class.
2.1949 + """
2.1950 +
2.1951 + def __init__(self, class_file):
2.1952 +
2.1953 + "Initialise the object with the given 'class_file'."
2.1954 +
2.1955 + self.class_file = class_file
2.1956 + self.filename = ""
2.1957 +
2.1958 + for attribute in self.class_file.attributes:
2.1959 + if isinstance(attribute, classfile.SourceFileAttributeInfo):
2.1960 + self.filename = str(attribute.get_name())
2.1961 +
2.1962 + def translate_method(self, method):
2.1963 +
2.1964 + "Translate the given 'method' - an object obtained from the class file."
2.1965 +
2.1966 + translator = BytecodeTranslator(self.class_file)
2.1967 + writer = BytecodeWriter()
2.1968 + translator.process(method, writer)
2.1969 + return translator, writer
2.1970 +
2.1971 + def make_method(self, real_method_name, methods, global_names, namespace):
2.1972 +
2.1973 + """
2.1974 + Make a dispatcher method with the given 'real_method_name', providing
2.1975 + dispatch to the supplied type-sensitive 'methods', accessing the given
2.1976 + 'global_names' where necessary, and storing the new method in the
2.1977 + 'namespace' provided.
2.1978 + """
2.1979 +
2.1980 + if real_method_name == "<init>":
2.1981 + method_name = "__init__"
2.1982 + else:
2.1983 + method_name = real_method_name
2.1984 +
2.1985 + # Where only one method exists, just make an alias.
2.1986 +
2.1987 + if len(methods) == 1:
2.1988 + method, fn = methods[0]
2.1989 + namespace[method_name] = fn
2.1990 + return
2.1991 +
2.1992 + # Write a simple bytecode dispatching mechanism.
2.1993 +
2.1994 + program = BytecodeWriter()
2.1995 +
2.1996 + # Remember whether any of the methods are static.
2.1997 + # NOTE: This should be an all or nothing situation.
2.1998 +
2.1999 + method_is_static = 0
2.2000 +
2.2001 + # NOTE: The code below should use dictionary-based dispatch for better performance.
2.2002 +
2.2003 + for method, fn in methods:
2.2004 + method_is_static = real_method_name != "<init>" and method_is_static or \
2.2005 + classfile.has_flags(method.access_flags, [classfile.STATIC])
2.2006 +
2.2007 + if method_is_static:
2.2008 + program.load_fast(0) # Stack: arguments
2.2009 + else:
2.2010 + program.load_fast(1) # Stack: arguments
2.2011 +
2.2012 + program.setup_loop()
2.2013 + program.load_const(1) # Stack: arguments, 1
2.2014 +
2.2015 + if method_is_static:
2.2016 + program.store_fast(1) # Stack: arguments (found = 1)
2.2017 + else:
2.2018 + program.store_fast(2) # Stack: arguments (found = 1)
2.2019 +
2.2020 + # Emit a list of parameter types.
2.2021 +
2.2022 + descriptor_types = method.get_descriptor()[0]
2.2023 + for descriptor_type in descriptor_types:
2.2024 + base_type, object_type, array_type = descriptor_type
2.2025 + python_type = classfile.descriptor_base_type_mapping[base_type]
2.2026 + if python_type == "instance":
2.2027 + # NOTE: This will need extending.
2.2028 + python_type = object_type
2.2029 + program.load_global(python_type) # Stack: arguments, type, ...
2.2030 + program.build_list(len(descriptor_types))
2.2031 + # Stack: arguments, types
2.2032 + # Make a map of arguments and types.
2.2033 + program.load_const(None) # Stack: arguments, types, None
2.2034 + program.rot_three() # Stack: None, arguments, types
2.2035 + program.build_tuple(3) # Stack: tuple
2.2036 + program.load_global("map") # Stack: tuple, map
2.2037 + program.rot_two() # Stack: map, tuple
2.2038 + program.call_function_var(0) # Stack: list (mapping arguments to types)
2.2039 + # Loop over each pair.
2.2040 + program.get_iter() # Stack: iter
2.2041 + program.for_iter() # Stack: iter, (argument, type)
2.2042 + program.unpack_sequence(2) # Stack: iter, type, argument
2.2043 + program.dup_top() # Stack: iter, type, argument, argument
2.2044 + program.load_const(None) # Stack: iter, type, argument, argument, None
2.2045 + program.compare_op("is") # Stack: iter, type, argument, result
2.2046 + # Missing argument?
2.2047 + program.jump_to_label(0, "present")
2.2048 + program.pop_top() # Stack: iter, type, argument
2.2049 + program.pop_top() # Stack: iter, type
2.2050 + program.pop_top() # Stack: iter
2.2051 + program.load_const(0) # Stack: iter, 0
2.2052 +
2.2053 + if method_is_static:
2.2054 + program.store_fast(1) # Stack: iter (found = 0)
2.2055 + else:
2.2056 + program.store_fast(2) # Stack: iter (found = 0)
2.2057 +
2.2058 + program.break_loop()
2.2059 + # Argument was present.
2.2060 + program.start_label("present")
2.2061 + program.pop_top() # Stack: iter, type, argument
2.2062 + program.rot_two() # Stack: iter, argument, type
2.2063 + program.dup_top() # Stack: iter, argument, type, type
2.2064 + program.load_const(None) # Stack: iter, argument, type, type, None
2.2065 + program.compare_op("is") # Stack: iter, argument, type, result
2.2066 + # Missing parameter type?
2.2067 + program.jump_to_label(0, "present")
2.2068 + program.pop_top() # Stack: iter, argument, type
2.2069 + program.pop_top() # Stack: iter, argument
2.2070 + program.pop_top() # Stack: iter
2.2071 + program.load_const(0) # Stack: iter, 0
2.2072 +
2.2073 + if method_is_static:
2.2074 + program.store_fast(1) # Stack: iter (found = 0)
2.2075 + else:
2.2076 + program.store_fast(2) # Stack: iter (found = 0)
2.2077 +
2.2078 + program.break_loop()
2.2079 + # Parameter was present.
2.2080 + program.start_label("present")
2.2081 + program.pop_top() # Stack: iter, argument, type
2.2082 + program.build_tuple(2) # Stack: iter, (argument, type)
2.2083 + program.load_global("isinstance") # Stack: iter, (argument, type), isinstance
2.2084 + program.rot_two() # Stack: iter, isinstance, (argument, type)
2.2085 + program.call_function_var(0) # Stack: iter, result
2.2086 + program.jump_to_label(1, "match")
2.2087 + program.pop_top() # Stack: iter
2.2088 + program.load_const(0) # Stack: iter, 0
2.2089 +
2.2090 + if method_is_static:
2.2091 + program.store_fast(1) # Stack: iter (found = 0)
2.2092 + else:
2.2093 + program.store_fast(2) # Stack: iter (found = 0)
2.2094 +
2.2095 + program.break_loop()
2.2096 + # Argument type and parameter type matched.
2.2097 + program.start_label("match")
2.2098 + program.pop_top() # Stack: iter
2.2099 + program.end_loop() # Stack:
2.2100 + # If all the parameters matched, call the method.
2.2101 +
2.2102 + if method_is_static:
2.2103 + program.load_fast(1) # Stack: match
2.2104 + else:
2.2105 + program.load_fast(2) # Stack: match
2.2106 +
2.2107 + program.jump_to_label(0, "failed")
2.2108 + # All the parameters matched.
2.2109 + program.pop_top() # Stack:
2.2110 +
2.2111 + if method_is_static:
2.2112 + program.load_fast(0) # Stack: arguments
2.2113 + program.load_global(str(self.class_file.this_class.get_python_name()))
2.2114 + # Stack: arguments, class
2.2115 + else:
2.2116 + program.load_fast(1) # Stack: arguments
2.2117 + program.load_fast(0) # Stack: arguments, self
2.2118 +
2.2119 + program.load_attr(str(method.get_python_name()))
2.2120 + # Stack: arguments, method
2.2121 + program.rot_two() # Stack: method, arguments
2.2122 + program.call_function_var(0) # Stack: result
2.2123 + program.return_value()
2.2124 + # Try the next method if arguments or parameters were missing or incorrect.
2.2125 + program.start_label("failed")
2.2126 + program.pop_top() # Stack:
2.2127 +
2.2128 + # Raise an exception if nothing matched.
2.2129 + # NOTE: Improve this.
2.2130 +
2.2131 + program.load_const("No matching method")
2.2132 + program.raise_varargs(1)
2.2133 + program.load_const(None)
2.2134 + program.return_value()
2.2135 +
2.2136 + # Add the code as a method in the namespace.
2.2137 + # NOTE: One actual parameter, flags as 71 apparently means that a list
2.2138 + # NOTE: parameter is used in a method.
2.2139 +
2.2140 + if method_is_static:
2.2141 + nargs = 0
2.2142 + else:
2.2143 + nargs = 1
2.2144 + nlocals = program.max_locals + 1
2.2145 +
2.2146 + code = new.code(nargs, nlocals, program.max_stack_depth, 71, program.get_output(),
2.2147 + tuple(program.get_constants()), tuple(program.get_names()), tuple(self.make_varnames(nlocals, method_is_static)),
2.2148 + self.filename, method_name, 0, "")
2.2149 + fn = new.function(code, global_names)
2.2150 +
2.2151 + if method_is_static:
2.2152 + fn = staticmethod(fn)
2.2153 +
2.2154 + namespace[method_name] = fn
2.2155 +
2.2156 + def process(self, global_names):
2.2157 +
2.2158 + """
2.2159 + Process the class, storing it in the 'global_names' dictionary provided.
2.2160 + Return a tuple containing the class and a list of external names
2.2161 + referenced by the class's methods.
2.2162 + """
2.2163 +
2.2164 + namespace = {}
2.2165 +
2.2166 + # Make the fields.
2.2167 +
2.2168 + for field in self.class_file.fields:
2.2169 + if classfile.has_flags(field.access_flags, [classfile.STATIC]):
2.2170 + field_name = str(field.get_python_name())
2.2171 + namespace[field_name] = None
2.2172 +
2.2173 + # Make the methods.
2.2174 +
2.2175 + real_methods = {}
2.2176 + external_names = []
2.2177 +
2.2178 + for method in self.class_file.methods:
2.2179 + real_method_name = str(method.get_name())
2.2180 + method_name = str(method.get_python_name())
2.2181 +
2.2182 + translator, writer = self.translate_method(method)
2.2183 +
2.2184 + # Add external names to the master list.
2.2185 +
2.2186 + for external_name in writer.external_names:
2.2187 + if external_name not in external_names:
2.2188 + external_names.append(external_name)
2.2189 +
2.2190 + # Fix up special class initialisation methods and static methods.
2.2191 +
2.2192 + method_is_static = real_method_name != "<init>" and classfile.has_flags(method.access_flags, [classfile.STATIC])
2.2193 + if method_is_static:
2.2194 + nargs = len(method.get_descriptor()[0])
2.2195 + else:
2.2196 + nargs = len(method.get_descriptor()[0]) + 1
2.2197 + nlocals = writer.max_locals + 1
2.2198 + flags = 67
2.2199 +
2.2200 + # NOTE: Add line number table later.
2.2201 +
2.2202 + code = new.code(nargs, nlocals, writer.max_stack_depth, flags, writer.get_output(),
2.2203 + tuple(writer.get_constants()), tuple(writer.get_names()),
2.2204 + tuple(self.make_varnames(nlocals, method_is_static)), self.filename, method_name, 0, "")
2.2205 +
2.2206 + # NOTE: May need more globals.
2.2207 +
2.2208 + fn = new.function(code, global_names)
2.2209 +
2.2210 + # Fix up special class initialisation methods and static methods.
2.2211 +
2.2212 + if method_is_static:
2.2213 + fn = staticmethod(fn)
2.2214 +
2.2215 + # Remember the real method name and the corresponding methods produced.
2.2216 +
2.2217 + if not real_methods.has_key(real_method_name):
2.2218 + real_methods[real_method_name] = []
2.2219 + real_methods[real_method_name].append((method, fn))
2.2220 +
2.2221 + # Add the method to the class's namespace.
2.2222 +
2.2223 + namespace[method_name] = fn
2.2224 +
2.2225 + # Define superclasses.
2.2226 +
2.2227 + bases = self.get_base_classes(global_names)
2.2228 +
2.2229 + # Define method dispatchers.
2.2230 +
2.2231 + for real_method_name, methods in real_methods.items():
2.2232 + if real_method_name != "<clinit>":
2.2233 + self.make_method(real_method_name, methods, global_names, namespace)
2.2234 +
2.2235 + # Use only the last part of the fully qualified name.
2.2236 +
2.2237 + full_class_name = str(self.class_file.this_class.get_python_name())
2.2238 + class_name = full_class_name.split(".")[-1]
2.2239 + cls = new.classobj(class_name, bases, namespace)
2.2240 + global_names[cls.__name__] = cls
2.2241 +
2.2242 + return cls, external_names
2.2243 +
2.2244 + def get_base_classes(self, global_names):
2.2245 +
2.2246 + """
2.2247 + Identify the superclass, then either load it from the given
2.2248 + 'global_names' if available, or import the class from its parent module.
2.2249 + Return a tuple containing all base classes (typically a single element
2.2250 + tuple).
2.2251 + """
2.2252 +
2.2253 + original_name = str(self.class_file.super_class.get_name())
2.2254 + full_this_class_name = str(self.class_file.this_class.get_python_name())
2.2255 + this_class_name_parts = full_this_class_name.split(".")
2.2256 + this_class_module_name = ".".join(this_class_name_parts[:-1])
2.2257 + full_super_class_name = str(self.class_file.super_class.get_python_name())
2.2258 + super_class_name_parts = full_super_class_name.split(".")
2.2259 + super_class_name = super_class_name_parts[-1]
2.2260 + super_class_module_name = ".".join(super_class_name_parts[:-1])
2.2261 + if super_class_module_name == "":
2.2262 + obj = global_names[super_class_name]
2.2263 + elif super_class_module_name == this_class_module_name:
2.2264 + obj = global_names[super_class_name]
2.2265 + else:
2.2266 + #print "Importing", super_class_module_name, super_class_name
2.2267 + obj = __import__(super_class_module_name, global_names, {}, [])
2.2268 + for super_class_name_part in super_class_name_parts[1:] or [super_class_name]:
2.2269 + #print "*", obj, super_class_name_part
2.2270 + obj = getattr(obj, super_class_name_part)
2.2271 + return (obj,)
2.2272 +
2.2273 + def make_varnames(self, nlocals, method_is_static=0):
2.2274 +
2.2275 + """
2.2276 + A utility method which invents variable names for the given number -
2.2277 + 'nlocals' - of local variables in a method. Returns a list of such
2.2278 + variable names.
2.2279 +
2.2280 + If the optional 'method_is_static' is set to true, do not use "self" as
2.2281 + the first argument name.
2.2282 + """
2.2283 +
2.2284 + if method_is_static:
2.2285 + l = ["cls"]
2.2286 + else:
2.2287 + l = ["self"]
2.2288 + for i in range(1, nlocals):
2.2289 + l.append("_l%s" % i)
2.2290 + return l[:nlocals]
2.2291 +
2.2292 +# Test functions, useful for tracing generated bytecode operations.
2.2293 +
2.2294 +def _map(*args):
2.2295 + print args
2.2296 + return apply(__builtins__.map, args)
2.2297 +
2.2298 +def _isinstance(*args):
2.2299 + print args
2.2300 + return apply(__builtins__.isinstance, args)
2.2301 +
2.2302 +if __name__ == "__main__":
2.2303 + import sys
2.2304 + import dis
2.2305 + global_names = globals()
2.2306 + #global_names["isinstance"] = _isinstance
2.2307 + #global_names["map"] = _map
2.2308 + for filename in sys.argv[1:]:
2.2309 + f = open(filename, "rb")
2.2310 + c = classfile.ClassFile(f.read())
2.2311 + translator = ClassTranslator(c)
2.2312 + cls, external_names = translator.process(global_names)
2.2313 +
2.2314 +# vim: tabstop=4 expandtab shiftwidth=4