1.1 --- a/bytecode.py Sun Nov 07 20:53:03 2004 +0100
1.2 +++ b/bytecode.py Mon Nov 08 00:30:55 2004 +0100
1.3 @@ -7,7 +7,7 @@
1.4 NOTE: Synchronized constructs are not actually supported.
1.5 """
1.6
1.7 -from dis import opmap # for access to Python bytecode values
1.8 +from dis import opmap, cmp_op # for access to Python bytecode values and operators
1.9 from UserDict import UserDict
1.10
1.11 # Bytecode production classes.
1.12 @@ -22,27 +22,83 @@
1.13 self.output = []
1.14 self.position = 0
1.15
1.16 + # Stack depth estimation.
1.17 + self.stack_depth = 0
1.18 + self.max_stack_depth = 0
1.19 +
1.20 # Mapping from values to indexes.
1.21 self.constants = {}
1.22
1.23 # Mapping from names to indexes.
1.24 # NOTE: This may be acquired from elsewhere.
1.25 - self.globals = {}
1.26 + #self.globals = {}
1.27
1.28 # Mapping from names to indexes.
1.29 self.names = {}
1.30
1.31 + # A list of constants used as exception handler return addresses.
1.32 + self.constants_for_exceptions = []
1.33 +
1.34 def get_output(self):
1.35 output = []
1.36 for element in self.output:
1.37 - if isinstance(element, LazyValue):
1.38 - output.append(chr(element.value))
1.39 + if isinstance(element, LazySubValue):
1.40 + value = element.value
1.41 else:
1.42 - output.append(chr(element))
1.43 + value = element
1.44 + output.append(chr(value))
1.45 return "".join(output)
1.46
1.47 + def get_constants(self):
1.48 + l = self._get_list(self._invert(self.constants))
1.49 + result = []
1.50 + for i in l:
1.51 + if isinstance(i, LazyValue):
1.52 + result.append(i.get_value())
1.53 + else:
1.54 + result.append(i)
1.55 + return result
1.56 +
1.57 + #def get_globals(self):
1.58 + # return self._get_list(self._invert(self.globals))
1.59 +
1.60 + def get_names(self):
1.61 + return self._get_list(self._invert(self.names))
1.62 +
1.63 + def _invert(self, d):
1.64 + inverted = {}
1.65 + for k, v in d.items():
1.66 + inverted[v] = k
1.67 + return inverted
1.68 +
1.69 + def _get_list(self, d):
1.70 + l = []
1.71 + for i in range(0, len(d.keys())):
1.72 + l.append(d[i])
1.73 + return l
1.74 +
1.75 + # Administrative methods.
1.76 +
1.77 + def update_stack_depth(self, change):
1.78 + self.stack_depth += change
1.79 + if self.stack_depth > self.max_stack_depth:
1.80 + self.max_stack_depth = self.stack_depth
1.81 +
1.82 # Special methods.
1.83
1.84 + def _write_value(self, value):
1.85 + if isinstance(value, LazyValue):
1.86 + # NOTE: Assume a 16-bit value.
1.87 + self.output.append(value.values[0])
1.88 + self.output.append(value.values[1])
1.89 + elif value <= 0xffff:
1.90 + self.output.append(value & 0xff)
1.91 + self.output.append((value & 0xff00) >> 8)
1.92 + self.position += 2
1.93 + else:
1.94 + # NOTE: EXTENDED_ARG not yet supported.
1.95 + raise ValueError, value
1.96 +
1.97 def end_loop(self):
1.98 current_loop_start = self.loops.pop()
1.99 self.jump_absolute(current_loop_start)
1.100 @@ -51,20 +107,42 @@
1.101
1.102 def jump_to_label(self, status, name):
1.103 # Record the instruction using the jump.
1.104 - if not self.jumps.has_key(name):
1.105 - self.jumps[name] = []
1.106 - self.jumps[name].append(self.position)
1.107 + jump_instruction = self.position
1.108 if status is None:
1.109 self.jump_forward()
1.110 elif status:
1.111 self.jump_if_true()
1.112 else:
1.113 self.jump_if_false()
1.114 + # Record the following instruction, too.
1.115 + if not self.jumps.has_key(name):
1.116 + self.jumps[name] = []
1.117 + self.jumps[name].append((jump_instruction, self.position))
1.118
1.119 def start_label(self, name):
1.120 # Fill in all jump instructions.
1.121 - for jump_instruction in self.jumps[name]:
1.122 - self.output[jump_instruction + 1] = self.position
1.123 + for jump_instruction, following_instruction in self.jumps[name]:
1.124 + self.output[jump_instruction + 1] = self.position - following_instruction
1.125 + del self.jumps[name]
1.126 +
1.127 + def load_const_ret(self, value):
1.128 + self.constants_for_exceptions.append(value)
1.129 + self.load_const(value)
1.130 +
1.131 + def ret(self, index):
1.132 + # Previously, the constant stored on the stack by jsr/jsr_w was stored
1.133 + # in a local variable. In the JVM, extracting the value from the local
1.134 + # variable and jumping can be done at runtime. In the Python VM, any
1.135 + # jump target must be known in advance and written into the bytecode.
1.136 + self.load_fast(index)
1.137 + for constant in self.constants_for_exceptions:
1.138 + self.dup_top() # Stack: actual-address, actual-address
1.139 + self.load_const(constant) # Stack: actual-address, actual-address, suggested-address
1.140 + self.compare_op("==") # Stack: actual-address, result
1.141 + self.jump_to_label(0, "const")
1.142 + self.jump_absolute(constant)
1.143 + self.start_label("const")
1.144 + self.pop_top() # Stack: actual-address
1.145
1.146 # Complicated methods.
1.147
1.148 @@ -72,55 +150,103 @@
1.149 self.output.append(opmap["LOAD_CONST"])
1.150 if not self.constants.has_key(value):
1.151 self.constants[value] = len(self.constants.keys())
1.152 - self.output.append(self.constants[value])
1.153 - self.position += 2
1.154 + self.position += 1
1.155 + self._write_value(self.constants[value])
1.156 + self.update_stack_depth(1)
1.157
1.158 def load_global(self, name):
1.159 self.output.append(opmap["LOAD_GLOBAL"])
1.160 - if not self.globals.has_key(name):
1.161 - self.globals[name] = len(self.globals.keys())
1.162 - self.output.append(self.globals[name])
1.163 - self.position += 2
1.164 + if not self.names.has_key(name):
1.165 + self.names[name] = len(self.names.keys())
1.166 + self.position += 1
1.167 + self._write_value(self.names[name])
1.168 + self.update_stack_depth(1)
1.169
1.170 def load_attr(self, name):
1.171 self.output.append(opmap["LOAD_ATTR"])
1.172 if not self.names.has_key(name):
1.173 self.names[name] = len(self.names.keys())
1.174 - self.output.append(self.names[name])
1.175 - self.position += 2
1.176 + self.position += 1
1.177 + self._write_value(self.names[name])
1.178 +
1.179 + def load_name(self, name):
1.180 + self.output.append(opmap["LOAD_NAME"])
1.181 + if not self.names.has_key(name):
1.182 + self.names[name] = len(self.names.keys())
1.183 + self.position += 1
1.184 + self._write_value(self.names[name])
1.185 + self.update_stack_depth(1)
1.186
1.187 def load_fast(self, index):
1.188 self.output.append(opmap["LOAD_FAST"])
1.189 - self.output.append(index)
1.190 - self.position += 2
1.191 + self.position += 1
1.192 + self._write_value(index)
1.193 + self.update_stack_depth(1)
1.194 +
1.195 + def store_attr(self, name):
1.196 + self.output.append(opmap["STORE_ATTR"])
1.197 + if not self.names.has_key(name):
1.198 + self.names[name] = len(self.names.keys())
1.199 + self.position += 1
1.200 + self._write_value(self.names[name])
1.201 + self.update_stack_depth(-1)
1.202 +
1.203 + def store_fast(self, index):
1.204 + self.output.append(opmap["STORE_FAST"])
1.205 + self.position += 1
1.206 + self._write_value(index)
1.207 + self.update_stack_depth(-1)
1.208
1.209 # Normal bytecode generators.
1.210
1.211 def for_iter(self):
1.212 self.loops.push(self.position)
1.213 self.output.append(opmap["FOR_ITER"])
1.214 - self.output.append(None) # To be filled in later
1.215 - self.position += 2
1.216 + self.position += 1
1.217 + self._write_value(0) # To be filled in later
1.218 + self.update_stack_depth(1)
1.219
1.220 - def jump_if_false(self, offset=None):
1.221 + def jump_if_false(self, offset=0):
1.222 self.output.append(opmap["JUMP_IF_FALSE"])
1.223 - self.output.append(offset) # May be filled in later
1.224 - self.position += 2
1.225 + self.position += 1
1.226 + self._write_value(offset) # May be filled in later
1.227
1.228 - def jump_if_true(self, offset=None):
1.229 + def jump_if_true(self, offset=0):
1.230 self.output.append(opmap["JUMP_IF_TRUE"])
1.231 - self.output.append(offset) # May be filled in later
1.232 - self.position += 2
1.233 + self.position += 1
1.234 + self._write_value(offset) # May be filled in later
1.235
1.236 - def jump_forward(self, offset=None):
1.237 + def jump_forward(self, offset=0):
1.238 self.output.append(opmap["JUMP_FORWARD"])
1.239 - self.output.append(offset) # May be filled in later
1.240 - self.position += 2
1.241 + self.position += 1
1.242 + self._write_value(offset) # May be filled in later
1.243 +
1.244 + def jump_absolute(self, address=0):
1.245 + self.output.append(opmap["JUMP_ABSOLUTE"])
1.246 + self.position += 1
1.247 + self._write_value(address) # May be filled in later
1.248
1.249 def build_tuple(self, count):
1.250 self.output.append(opmap["BUILD_TUPLE"])
1.251 - self.output.append(count)
1.252 - self.position += 2
1.253 + self.position += 1
1.254 + self._write_value(count)
1.255 + self.update_stack_depth(-(count - 1))
1.256 +
1.257 + def build_list(self, count):
1.258 + self.output.append(opmap["BUILD_LIST"])
1.259 + self.position += 1
1.260 + self._write_value(count)
1.261 + self.update_stack_depth(-(count - 1))
1.262 +
1.263 + def pop_top(self):
1.264 + self.output.append(opmap["POP_TOP"])
1.265 + self.position += 1
1.266 + self.update_stack_depth(-1)
1.267 +
1.268 + def dup_top(self):
1.269 + self.output.append(opmap["DUP_TOP"])
1.270 + self.position += 1
1.271 + self.update_stack_depth(1)
1.272
1.273 def rot_two(self):
1.274 self.output.append(opmap["ROT_TWO"])
1.275 @@ -136,26 +262,120 @@
1.276
1.277 def call_function(self, count):
1.278 self.output.append(opmap["CALL_FUNCTION"])
1.279 - self.output.append(count)
1.280 - self.position += 2
1.281 + self.position += 1
1.282 + self._write_value(count)
1.283 + self.update_stack_depth(-count)
1.284 +
1.285 + def binary_subscr(self):
1.286 + self.output.append(opmap["BINARY_SUBSCR"])
1.287 + self.position += 1
1.288 + self.update_stack_depth(-1)
1.289 +
1.290 + def binary_add(self):
1.291 + self.output.append(opmap["BINARY_ADD"])
1.292 + self.position += 1
1.293 + self.update_stack_depth(-1)
1.294 +
1.295 + def binary_divide(self):
1.296 + self.output.append(opmap["BINARY_DIVIDE"])
1.297 + self.position += 1
1.298 + self.update_stack_depth(-1)
1.299 +
1.300 + def binary_multiply(self):
1.301 + self.output.append(opmap["BINARY_MULTIPLY"])
1.302 + self.position += 1
1.303 + self.update_stack_depth(-1)
1.304 +
1.305 + def binary_modulo(self):
1.306 + self.output.append(opmap["BINARY_MODULO"])
1.307 + self.position += 1
1.308 + self.update_stack_depth(-1)
1.309 +
1.310 + def binary_subtract(self):
1.311 + self.output.append(opmap["BINARY_SUBTRACT"])
1.312 + self.position += 1
1.313 + self.update_stack_depth(-1)
1.314 +
1.315 + def binary_and(self):
1.316 + self.output.append(opmap["BINARY_AND"])
1.317 + self.position += 1
1.318 + self.update_stack_depth(-1)
1.319 +
1.320 + def binary_or(self):
1.321 + self.output.append(opmap["BINARY_XOR"])
1.322 + self.position += 1
1.323 + self.update_stack_depth(-1)
1.324 +
1.325 + def binary_lshift(self):
1.326 + self.output.append(opmap["BINARY_LSHIFT"])
1.327 + self.position += 1
1.328 + self.update_stack_depth(-1)
1.329 +
1.330 + def binary_rshift(self):
1.331 + self.output.append(opmap["BINARY_RSHIFT"])
1.332 + self.position += 1
1.333 + self.update_stack_depth(-1)
1.334 +
1.335 + def binary_xor(self):
1.336 + self.output.append(opmap["BINARY_XOR"])
1.337 + self.position += 1
1.338 + self.update_stack_depth(-1)
1.339 +
1.340 + def compare_op(self, op):
1.341 + self.output.append(opmap["COMPARE_OP"])
1.342 + self.position += 1
1.343 + self._write_value(list(cmp_op).index(op))
1.344 + self.update_stack_depth(-1)
1.345 +
1.346 + def return_value(self):
1.347 + self.output.append(opmap["RETURN_VALUE"])
1.348 + self.position += 1
1.349 + self.update_stack_depth(-1)
1.350 +
1.351 + def raise_varargs(self, count):
1.352 + self.output.append(opmap["RAISE_VARARGS"])
1.353 + self.position += 1
1.354 + self._write_value(count)
1.355
1.356 # Utility classes and functions.
1.357
1.358 class LazyDict(UserDict):
1.359 def __getitem__(self, key):
1.360 if not self.data.has_key(key):
1.361 - self.data[key] = LazyValue()
1.362 + # NOTE: Assume 16-bit value.
1.363 + self.data[key] = LazyValue(2)
1.364 return self.data[key]
1.365 def __setitem__(self, key, value):
1.366 if self.data.has_key(key):
1.367 existing_value = self.data[key]
1.368 if isinstance(existing_value, LazyValue):
1.369 - existing_value.value = value
1.370 + existing_value.set_value(value)
1.371 return
1.372 self.data[key] = value
1.373
1.374 class LazyValue:
1.375 - def __init__(self, value=None):
1.376 + def __init__(self, nvalues):
1.377 + self.values = []
1.378 + for i in range(0, nvalues):
1.379 + self.values.append(LazySubValue())
1.380 + def set_value(self, value):
1.381 + # NOTE: Assume at least 16-bit value. No "filling" performed.
1.382 + if value <= 0xffff:
1.383 + self.values[0].set_value(value & 0xff)
1.384 + self.values[1].set_value((value & 0xff00) >> 8)
1.385 + else:
1.386 + # NOTE: EXTENDED_ARG not yet supported.
1.387 + raise ValueError, value
1.388 + def get_value(self):
1.389 + value = 0
1.390 + for i in range(0, len(self.values)):
1.391 + value = (value << 8) + self.values.pop().value
1.392 + return value
1.393 +
1.394 +class LazySubValue:
1.395 + def __init__(self):
1.396 + self.value = 0
1.397 + def set_value(self, value):
1.398 self.value = value
1.399
1.400 def signed(value, limit):
1.401 @@ -390,7 +610,7 @@
1.402 174 : ("freturn", 0),
1.403 175 : ("dreturn", 0),
1.404 176 : ("areturn", 0),
1.405 - 177 : ("return", 0),
1.406 + 177 : ("return_", 0),
1.407 178 : ("getstatic", 2),
1.408 179 : ("putstatic", 2),
1.409 180 : ("getfield", 2),
1.410 @@ -439,9 +659,6 @@
1.411
1.412 "A Java bytecode translator which uses a Python bytecode writer."
1.413
1.414 - def nop(self, arguments, program):
1.415 - pass
1.416 -
1.417 def aaload(self, arguments, program):
1.418 # NOTE: No type checking performed.
1.419 program.binary_subscr()
1.420 @@ -474,7 +691,9 @@
1.421 # NOTE: Does not raise NegativeArraySizeException.
1.422 # NOTE: Not using the index to type the list/array.
1.423 index = (arguments[0] << 8) + arguments[1]
1.424 + self._newarray(program)
1.425
1.426 + def _newarray(self, program):
1.427 program.build_list() # Stack: count, list
1.428 program.rot_two() # Stack: list, count
1.429 program.setup_loop()
1.430 @@ -668,7 +887,13 @@
1.431 # NOTE: Using the string version of the name which may contain incompatible characters.
1.432 program.load_attr(str(target_name))
1.433
1.434 - getstatic = getfield # Ignoring Java restrictions
1.435 + def getstatic(self, arguments, program):
1.436 + index = (arguments[0] << 8) + arguments[1]
1.437 + target_name = self.class_file.constants[index - 1].get_name()
1.438 + program.load_name("self")
1.439 + program.load_attr("__class__")
1.440 + # NOTE: Using the string version of the name which may contain incompatible characters.
1.441 + program.load_attr(str(target_name))
1.442
1.443 def goto(self, arguments, program):
1.444 offset = signed2((arguments[0] << 8) + arguments[1])
1.445 @@ -840,7 +1065,6 @@
1.446 program.call_function(2) # Stack: result
1.447
1.448 def _invoke(self, target_name, program):
1.449 - program.rot_two() # Stack: tuple, objectref
1.450 # NOTE: Using the string version of the name which may contain incompatible characters.
1.451 program.load_attr(str(target_name)) # Stack: tuple, method
1.452 program.rot_two() # Stack: method, tuple
1.453 @@ -857,6 +1081,7 @@
1.454 target_name = self.class_file.constants[index - 1].get_name()
1.455 # Stack: objectref, arg1, arg2, ...
1.456 program.build_tuple(count) # Stack: objectref, tuple
1.457 + program.rot_two() # Stack: tuple, objectref
1.458 self._invoke(target_name, program)
1.459
1.460 def invokespecial(self, arguments, program):
1.461 @@ -869,8 +1094,28 @@
1.462 # Get the number of parameters from the descriptor.
1.463 count = len(target.get_descriptor()[0])
1.464 # Stack: objectref, arg1, arg2, ...
1.465 - program.build_tuple(count) # Stack: objectref, tuple
1.466 + program.build_tuple(count + 1) # Stack: tuple
1.467 + # Use the class to provide access to static methods.
1.468 + program.load_name("self") # Stack: tuple, self
1.469 + program.load_attr("__class__") # Stack: tuple, class
1.470 + program.load_attr("__bases__") # Stack: tuple, base-classes
1.471 + program.dup_top() # Stack: tuple, base-classes, base-classes
1.472 + program.load_global("len") # Stack: tuple, base-classes, base-classes, len
1.473 + program.rot_two() # Stack: tuple, base-classes, len, base-classes
1.474 + program.call_function(1) # Stack: tuple, base-classes, count
1.475 + program.load_const(0) # Stack: tuple, base-classes, count, 0
1.476 + program.compare_op("==") # Stack: tuple, base-classes, result
1.477 + program.jump_to_label(1, "next")
1.478 + program.pop_top() # Stack: tuple, base-classes
1.479 + program.load_const(0) # Stack: tuple, base-classes, 0
1.480 + program.binary_subscr() # Stack: tuple, superclass
1.481 self._invoke(target_name, program)
1.482 + program.jump_to_label(None, "next2")
1.483 + program.start_label("next")
1.484 + program.pop_top() # Stack: tuple, base-classes
1.485 + program.pop_top() # Stack: tuple
1.486 + program.pop_top() # Stack:
1.487 + program.start_label("next2")
1.488
1.489 def invokestatic(self, arguments, program):
1.490 # NOTE: This implementation does not perform the necessary checks for
1.491 @@ -882,9 +1127,10 @@
1.492 # Get the number of parameters from the descriptor.
1.493 count = len(target.get_descriptor()[0])
1.494 # Stack: arg1, arg2, ...
1.495 - program.build_tuple(count) # Stack: tuple
1.496 - # NOTE: Should probably use Python static methods.
1.497 - program.load_name("self") # Stack: tuple, self
1.498 + program.build_tuple(count) # Stack: tuple
1.499 + # Use the class to provide access to static methods.
1.500 + program.load_name("self") # Stack: tuple, self
1.501 + program.load_attr("__class__") # Stack: tuple, class
1.502 self._invoke(target_name, program)
1.503
1.504 invokevirtual = invokeinterface # Ignoring Java rules
1.505 @@ -922,14 +1168,14 @@
1.506 offset = signed2((arguments[0] << 8) + arguments[1])
1.507 java_absolute = self.java_position + offset
1.508 # Store the address of the next instruction.
1.509 - program.load_const(self.position_mapping[self.java_position + 3])
1.510 + program.load_const_ret(self.position_mapping[self.java_position + 3])
1.511 program.jump_absolute(self.position_mapping[java_absolute])
1.512
1.513 def jsr_w(self, arguments, program):
1.514 offset = signed4((arguments[0] << 24) + (arguments[1] << 16) + (arguments[2] << 8) + arguments[3])
1.515 java_absolute = self.java_position + offset
1.516 # Store the address of the next instruction.
1.517 - program.load_const(self.position_mapping[self.java_position + 5])
1.518 + program.load_const_ret(self.position_mapping[self.java_position + 5])
1.519 program.jump_absolute(self.position_mapping[java_absolute])
1.520
1.521 l2d = i2d
1.522 @@ -1015,12 +1261,12 @@
1.523 program.dup_top() # Stack: key, key
1.524 program.load_const(match) # Stack: key, key, match
1.525 program.compare_op("==") # Stack: key, result
1.526 - program.jump_to_label(0, "end" + str(pair))
1.527 + program.jump_to_label(0, "end")
1.528 program.pop_top() # Stack: key
1.529 program.pop_top() # Stack:
1.530 program.jump_absolute(self.position_mapping[java_absolute])
1.531 # Generate the label for the end of the branching code.
1.532 - program.start_label("end" + str(pair))
1.533 + program.start_label("end")
1.534 program.pop_top() # Stack: key
1.535 # Update the index.
1.536 pair_index += 8
1.537 @@ -1051,19 +1297,95 @@
1.538 pass
1.539
1.540 def multianewarray(self, arguments, program):
1.541 - program.build_list() # Stack: count1, count2, ..., countN, list
1.542 - program.rot_two() # Stack: count1, count2, ..., list, countN
1.543 - program.setup_loop()
1.544 - program.load_global("range")
1.545 - program.load_const(0) # Stack: list, count, range, 0
1.546 - program.rot_three() # Stack: list, 0, count, range
1.547 - program.rot_three() # Stack: list, range, 0, count
1.548 - program.call_function(2) # Stack: list, range_list
1.549 - program.get_iter() # Stack: list, iter
1.550 - program.for_iter() # Stack: list, iter, value
1.551 - for i in range(0, arguments[2]):
1.552 - # Stack:
1.553 - self.anewarray(arguments, program) # Stack: list, iter
1.554 + # NOTE: To be implemented.
1.555 + pass
1.556 +
1.557 + def new(self, arguments, program):
1.558 + # This operation is considered to be the same as the calling of the
1.559 + # initialisation method of the given class with no arguments.
1.560 + index = (arguments[0] << 8) + arguments[1]
1.561 + target_name = self.class_file.constants[index - 1].get_name()
1.562 + # NOTE: Using the string version of the name which may contain incompatible characters.
1.563 + program.load_global(str(target_name))
1.564 + program.call_function(0)
1.565 +
1.566 + def newarray(self, arguments, program):
1.567 + # NOTE: Does not raise NegativeArraySizeException.
1.568 + # NOTE: Not using the arguments to type the list/array.
1.569 + self._newarray(program)
1.570 +
1.571 + def nop(self, arguments, program):
1.572 + pass
1.573 +
1.574 + def pop(self, arguments, program):
1.575 + program.pop_top()
1.576 +
1.577 + pop2 = pop # ignoring Java stack value distinctions
1.578 +
1.579 + def putfield(self, arguments, program):
1.580 + index = (arguments[0] << 8) + arguments[1]
1.581 + target_name = self.class_file.constants[index - 1].get_name()
1.582 + program.rot_two()
1.583 + # NOTE: Using the string version of the name which may contain incompatible characters.
1.584 + program.store_attr(str(target_name))
1.585 +
1.586 + def putstatic(self, arguments, program):
1.587 + index = (arguments[0] << 8) + arguments[1]
1.588 + target_name = self.class_file.constants[index - 1].get_name()
1.589 + program.load_name("self")
1.590 + program.load_attr("__class__")
1.591 + # NOTE: Using the string version of the name which may contain incompatible characters.
1.592 + program.store_attr(str(target_name))
1.593 +
1.594 + def ret(self, arguments, program):
1.595 + program.ret(arguments[0])
1.596 +
1.597 + def return_(self, arguments, program):
1.598 + program.load_const(None)
1.599 + program.return_value()
1.600 +
1.601 + saload = laload
1.602 + sastore = lastore
1.603 +
1.604 + def sipush(self, arguments, program):
1.605 + program.load_const((arguments[0] << 8) + arguments[1])
1.606 +
1.607 + def swap(self, arguments, program):
1.608 + program.rot_two()
1.609 +
1.610 + def tableswitch(self, arguments, program):
1.611 + # Find the offset to the next 4 byte boundary in the code.
1.612 + d, r = divmod(self.java_position, 4)
1.613 + to_boundary = (4 - r) % 4
1.614 + # Get the pertinent arguments.
1.615 + arguments = arguments[to_boundary:]
1.616 + default = (arguments[0] << 24) + (arguments[1] << 16) + (arguments[2] << 8) + arguments[3]
1.617 + low = (arguments[4] << 24) + (arguments[5] << 16) + (arguments[6] << 8) + arguments[7]
1.618 + high = (arguments[8] << 24) + (arguments[9] << 16) + (arguments[10] << 8) + arguments[11]
1.619 + # Process the jump entries.
1.620 + # NOTE: This is not the most optimal implementation.
1.621 + jump_index = 8
1.622 + for jump in range(low, high + 1):
1.623 + offset = signed4((arguments[jump_index] << 24) + (arguments[jump_index + 1] << 16) +
1.624 + (arguments[jump_index + 2] << 8) + arguments[jump_index + 3])
1.625 + # Calculate the branch target.
1.626 + java_absolute = self.java_position + offset
1.627 + # Generate branching code.
1.628 + program.dup_top() # Stack: key, key
1.629 + program.load_const(jump) # Stack: key, key, jump
1.630 + program.compare_op("==") # Stack: key, result
1.631 + program.jump_to_label(0, "end")
1.632 + program.pop_top() # Stack: key
1.633 + program.pop_top() # Stack:
1.634 + program.jump_absolute(self.position_mapping[java_absolute])
1.635 + # Generate the label for the end of the branching code.
1.636 + program.start_label("end")
1.637 + program.pop_top() # Stack: key
1.638 + # Update the index.
1.639 + jump_index += 8
1.640 + # Generate the default.
1.641 + java_absolute = self.java_position + default
1.642 + program.jump_absolute(self.position_mapping[java_absolute])
1.643
1.644 def wide(self, code, program):
1.645 # NOTE: To be implemented.