1 #!/usr/bin/env python 2 3 """ 4 Java bytecode conversion. Specification found at the following URL: 5 http://java.sun.com/docs/books/vmspec/2nd-edition/html/Instructions2.doc.html 6 7 NOTE: Synchronized constructs are not actually supported. 8 """ 9 10 from dis import opmap, cmp_op # for access to Python bytecode values and operators 11 from UserDict import UserDict 12 13 # Bytecode production classes. 14 15 class BytecodeWriter: 16 17 "A Python bytecode writer." 18 19 def __init__(self): 20 # A stack of loop block or exception block start positions. 21 self.blocks = [] 22 23 # A stack of exception block handler pointers. 24 self.exception_handlers = [] 25 26 # A dictionary mapping labels to jump instructions referencing such labels. 27 self.jumps = {} 28 29 # The output values, including "lazy" subvalues which will need evaluating. 30 self.output = [] 31 32 # The current Python bytecode instruction position. 33 self.position = 0 34 35 # Stack depth estimation. 36 self.stack_depth = 0 37 self.max_stack_depth = 0 38 39 # Local variable estimation. 40 self.max_locals = 0 41 42 # Mapping from values to indexes. 43 self.constants = {} 44 45 # Mapping from names to indexes. 46 # NOTE: This may be acquired from elsewhere. 47 #self.globals = {} 48 49 # Mapping from names to indexes. 50 self.names = {} 51 52 # A list of constants used as exception handler return addresses. 53 self.constants_for_exceptions = [] 54 55 def get_output(self): 56 output = [] 57 for element in self.output: 58 if isinstance(element, LazySubValue): 59 value = element.value 60 else: 61 value = element 62 output.append(chr(value)) 63 return "".join(output) 64 65 def get_constants(self): 66 l = self._get_list(self._invert(self.constants)) 67 result = [] 68 for i in l: 69 if isinstance(i, LazyValue): 70 result.append(i.get_value()) 71 else: 72 result.append(i) 73 return result 74 75 #def get_globals(self): 76 # return self._get_list(self._invert(self.globals)) 77 78 def get_names(self): 79 return self._get_list(self._invert(self.names)) 80 81 def _invert(self, d): 82 inverted = {} 83 for k, v in d.items(): 84 inverted[v] = k 85 return inverted 86 87 def _get_list(self, d): 88 l = [] 89 for i in range(0, len(d.keys())): 90 l.append(d[i]) 91 return l 92 93 # Administrative methods. 94 95 def update_stack_depth(self, change): 96 self.stack_depth += change 97 if self.stack_depth > self.max_stack_depth: 98 self.max_stack_depth = self.stack_depth 99 100 def update_locals(self, index): 101 if index > self.max_locals: 102 self.max_locals = index 103 104 # Special methods. 105 106 def _write_value(self, value): 107 if isinstance(value, LazyValue): 108 # NOTE: Assume a 16-bit value. 109 self.output.append(value.values[0]) 110 self.output.append(value.values[1]) 111 self.position += 2 112 elif value <= 0xffff: 113 self.output.append(value & 0xff) 114 self.output.append((value & 0xff00) >> 8) 115 self.position += 2 116 else: 117 # NOTE: EXTENDED_ARG not yet supported. 118 raise ValueError, value 119 120 def setup_loop(self): 121 self.blocks.append(self.position) 122 self.output.append(opmap["SETUP_LOOP"]) 123 self.position += 1 124 self._write_value(0) # To be filled in later 125 126 def end_loop(self): 127 current_loop_start = self.blocks.pop() 128 self.jump_absolute(current_loop_start) 129 # NOTE: Using 3 as the assumed length of the SETUP_LOOP instruction. 130 # NOTE: 8-bit limit. 131 self.output[current_loop_start + 1] = self.position - current_loop_start - 3 132 self.output[current_loop_start + 2] = 0 133 self.pop_block() 134 135 def jump_to_label(self, status, name): 136 # Record the instruction using the jump. 137 jump_instruction = self.position 138 if status is None: 139 self.jump_forward() 140 elif status: 141 self.jump_if_true() 142 else: 143 self.jump_if_false() 144 # Record the following instruction, too. 145 if not self.jumps.has_key(name): 146 self.jumps[name] = [] 147 self.jumps[name].append((jump_instruction, self.position)) 148 149 def start_label(self, name): 150 # Fill in all jump instructions. 151 for jump_instruction, following_instruction in self.jumps[name]: 152 # NOTE: 8-bit limit. 153 self.output[jump_instruction + 1] = self.position - following_instruction 154 self.output[jump_instruction + 2] = 0 155 del self.jumps[name] 156 157 def load_const_ret(self, value): 158 self.constants_for_exceptions.append(value) 159 self.load_const(value) 160 161 def ret(self, index): 162 self.load_fast(index) 163 # Previously, the constant stored on the stack by jsr/jsr_w was stored 164 # in a local variable. In the JVM, extracting the value from the local 165 # variable and jumping can be done at runtime. In the Python VM, any 166 # jump target must be known in advance and written into the bytecode. 167 for constant in self.constants_for_exceptions: 168 self.dup_top() # Stack: actual-address, actual-address 169 self.load_const(constant) # Stack: actual-address, actual-address, suggested-address 170 self.compare_op("==") # Stack: actual-address, result 171 self.jump_to_label(0, "const") 172 self.pop_top() # Stack: actual-address 173 self.pop_top() # Stack: 174 self.jump_absolute(constant) 175 self.start_label("const") 176 self.pop_top() # Stack: actual-address 177 # NOTE: If we get here, something is really wrong. 178 self.pop_top() # Stack: 179 180 def setup_except(self, target): 181 self.blocks.append(self.position) 182 self.exception_handlers.append(target) 183 #print "-", self.position, target 184 self.output.append(opmap["SETUP_EXCEPT"]) 185 self.position += 1 186 self._write_value(0) # To be filled in later 187 188 def setup_finally(self, target): 189 self.blocks.append(self.position) 190 self.exception_handlers.append(target) 191 #print "-", self.position, target 192 self.output.append(opmap["SETUP_FINALLY"]) 193 self.position += 1 194 self._write_value(0) # To be filled in later 195 196 def end_exception(self): 197 current_exception_start = self.blocks.pop() 198 # Convert the "lazy" absolute value. 199 current_exception_target = self.exception_handlers.pop() 200 target = current_exception_target.get_value() 201 #print "*", current_exception_start, target 202 # NOTE: Using 3 as the assumed length of the SETUP_* instruction. 203 # NOTE: 8-bit limit. 204 self.output[current_exception_start + 1] = target - current_exception_start - 3 205 self.output[current_exception_start + 2] = 0 206 # NOTE: The POP_BLOCK instruction gets slipped in before this method is called. 207 208 # Complicated methods. 209 210 def load_const(self, value): 211 self.output.append(opmap["LOAD_CONST"]) 212 if not self.constants.has_key(value): 213 self.constants[value] = len(self.constants.keys()) 214 self.position += 1 215 self._write_value(self.constants[value]) 216 self.update_stack_depth(1) 217 218 def load_global(self, name): 219 self.output.append(opmap["LOAD_GLOBAL"]) 220 if not self.names.has_key(name): 221 self.names[name] = len(self.names.keys()) 222 self.position += 1 223 self._write_value(self.names[name]) 224 self.update_stack_depth(1) 225 226 def load_attr(self, name): 227 self.output.append(opmap["LOAD_ATTR"]) 228 if not self.names.has_key(name): 229 self.names[name] = len(self.names.keys()) 230 self.position += 1 231 self._write_value(self.names[name]) 232 233 def load_name(self, name): 234 self.output.append(opmap["LOAD_NAME"]) 235 if not self.names.has_key(name): 236 self.names[name] = len(self.names.keys()) 237 self.position += 1 238 self._write_value(self.names[name]) 239 self.update_stack_depth(1) 240 241 def load_fast(self, index): 242 self.output.append(opmap["LOAD_FAST"]) 243 self.position += 1 244 self._write_value(index) 245 self.update_stack_depth(1) 246 self.update_locals(index) 247 248 def store_attr(self, name): 249 self.output.append(opmap["STORE_ATTR"]) 250 if not self.names.has_key(name): 251 self.names[name] = len(self.names.keys()) 252 self.position += 1 253 self._write_value(self.names[name]) 254 self.update_stack_depth(-1) 255 256 def store_fast(self, index): 257 self.output.append(opmap["STORE_FAST"]) 258 self.position += 1 259 self._write_value(index) 260 self.update_stack_depth(-1) 261 self.update_locals(index) 262 263 # Normal bytecode generators. 264 265 def for_iter(self): 266 self.blocks.append(self.position) 267 self.output.append(opmap["FOR_ITER"]) 268 self.position += 1 269 self._write_value(0) # To be filled in later 270 self.update_stack_depth(1) 271 272 def jump_if_false(self, offset=0): 273 self.output.append(opmap["JUMP_IF_FALSE"]) 274 self.position += 1 275 self._write_value(offset) # May be filled in later 276 277 def jump_if_true(self, offset=0): 278 self.output.append(opmap["JUMP_IF_TRUE"]) 279 self.position += 1 280 self._write_value(offset) # May be filled in later 281 282 def jump_forward(self, offset=0): 283 self.output.append(opmap["JUMP_FORWARD"]) 284 self.position += 1 285 self._write_value(offset) # May be filled in later 286 287 def jump_absolute(self, address=0): 288 self.output.append(opmap["JUMP_ABSOLUTE"]) 289 self.position += 1 290 self._write_value(address) # May be filled in later 291 292 def build_tuple(self, count): 293 self.output.append(opmap["BUILD_TUPLE"]) 294 self.position += 1 295 self._write_value(count) 296 self.update_stack_depth(-(count - 1)) 297 298 def build_list(self, count): 299 self.output.append(opmap["BUILD_LIST"]) 300 self.position += 1 301 self._write_value(count) 302 self.update_stack_depth(-(count - 1)) 303 304 def pop_top(self): 305 self.output.append(opmap["POP_TOP"]) 306 self.position += 1 307 self.update_stack_depth(-1) 308 309 def dup_top(self): 310 self.output.append(opmap["DUP_TOP"]) 311 self.position += 1 312 self.update_stack_depth(1) 313 314 def rot_two(self): 315 self.output.append(opmap["ROT_TWO"]) 316 self.position += 1 317 318 def rot_three(self): 319 self.output.append(opmap["ROT_THREE"]) 320 self.position += 1 321 322 def rot_four(self): 323 self.output.append(opmap["ROT_FOUR"]) 324 self.position += 1 325 326 def call_function(self, count): 327 self.output.append(opmap["CALL_FUNCTION"]) 328 self.position += 1 329 self._write_value(count) 330 self.update_stack_depth(-count) 331 332 def binary_subscr(self): 333 self.output.append(opmap["BINARY_SUBSCR"]) 334 self.position += 1 335 self.update_stack_depth(-1) 336 337 def binary_add(self): 338 self.output.append(opmap["BINARY_ADD"]) 339 self.position += 1 340 self.update_stack_depth(-1) 341 342 def binary_divide(self): 343 self.output.append(opmap["BINARY_DIVIDE"]) 344 self.position += 1 345 self.update_stack_depth(-1) 346 347 def binary_multiply(self): 348 self.output.append(opmap["BINARY_MULTIPLY"]) 349 self.position += 1 350 self.update_stack_depth(-1) 351 352 def binary_modulo(self): 353 self.output.append(opmap["BINARY_MODULO"]) 354 self.position += 1 355 self.update_stack_depth(-1) 356 357 def binary_subtract(self): 358 self.output.append(opmap["BINARY_SUBTRACT"]) 359 self.position += 1 360 self.update_stack_depth(-1) 361 362 def binary_and(self): 363 self.output.append(opmap["BINARY_AND"]) 364 self.position += 1 365 self.update_stack_depth(-1) 366 367 def binary_or(self): 368 self.output.append(opmap["BINARY_XOR"]) 369 self.position += 1 370 self.update_stack_depth(-1) 371 372 def binary_lshift(self): 373 self.output.append(opmap["BINARY_LSHIFT"]) 374 self.position += 1 375 self.update_stack_depth(-1) 376 377 def binary_rshift(self): 378 self.output.append(opmap["BINARY_RSHIFT"]) 379 self.position += 1 380 self.update_stack_depth(-1) 381 382 def binary_xor(self): 383 self.output.append(opmap["BINARY_XOR"]) 384 self.position += 1 385 self.update_stack_depth(-1) 386 387 def compare_op(self, op): 388 self.output.append(opmap["COMPARE_OP"]) 389 self.position += 1 390 self._write_value(list(cmp_op).index(op)) 391 self.update_stack_depth(-1) 392 393 def return_value(self): 394 self.output.append(opmap["RETURN_VALUE"]) 395 self.position += 1 396 self.update_stack_depth(-1) 397 398 def raise_varargs(self, count): 399 self.output.append(opmap["RAISE_VARARGS"]) 400 self.position += 1 401 self._write_value(count) 402 403 def pop_block(self): 404 self.output.append(opmap["POP_BLOCK"]) 405 self.position += 1 406 407 def end_finally(self): 408 self.output.append(opmap["END_FINALLY"]) 409 self.position += 1 410 411 # Utility classes and functions. 412 413 class LazyDict(UserDict): 414 def __getitem__(self, key): 415 if not self.data.has_key(key): 416 # NOTE: Assume 16-bit value. 417 self.data[key] = LazyValue(2) 418 return self.data[key] 419 def __setitem__(self, key, value): 420 if self.data.has_key(key): 421 existing_value = self.data[key] 422 if isinstance(existing_value, LazyValue): 423 existing_value.set_value(value) 424 return 425 self.data[key] = value 426 427 class LazyValue: 428 def __init__(self, nvalues): 429 self.values = [] 430 for i in range(0, nvalues): 431 self.values.append(LazySubValue()) 432 def set_value(self, value): 433 # NOTE: Assume at least 16-bit value. No "filling" performed. 434 if value <= 0xffff: 435 self.values[0].set_value(value & 0xff) 436 self.values[1].set_value((value & 0xff00) >> 8) 437 else: 438 # NOTE: EXTENDED_ARG not yet supported. 439 raise ValueError, value 440 def get_value(self): 441 value = 0 442 values = self.values[:] 443 for i in range(0, len(values)): 444 value = (value << 8) + values.pop().value 445 return value 446 447 class LazySubValue: 448 def __init__(self): 449 self.value = 0 450 def set_value(self, value): 451 self.value = value 452 453 def signed(value, limit): 454 455 """ 456 Return the signed integer from the unsigned 'value', where 'limit' (a value 457 one greater than the highest possible positive integer) is used to determine 458 whether a negative or positive result is produced. 459 """ 460 461 d, r = divmod(value, limit) 462 if d == 1: 463 mask = limit * 2 - 1 464 return -1 - (value ^ mask) 465 else: 466 return value 467 468 def signed2(value): 469 return signed(value, 0x8000) 470 471 def signed4(value): 472 return signed(value, 0x80000000) 473 474 # Bytecode conversion. 475 476 class BytecodeReader: 477 478 "A generic Java bytecode reader." 479 480 def __init__(self, class_file): 481 self.class_file = class_file 482 self.position_mapping = LazyDict() 483 484 def process(self, method, program): 485 self.java_position = 0 486 self.in_finally = 0 487 self.method = method 488 489 # NOTE: Not guaranteed. 490 attribute = method.attributes[0] 491 code, exception_table = attribute.code, attribute.exception_table 492 493 # Produce a structure which permits fast access to exception details. 494 exception_block_start = {} 495 exception_block_end = {} 496 exception_block_handler = {} 497 reversed_exception_table = exception_table[:] 498 reversed_exception_table.reverse() 499 500 # Later entries have wider coverage than earlier entries. 501 for exception in reversed_exception_table: 502 # Index start positions. 503 if not exception_block_start.has_key(exception.start_pc): 504 exception_block_start[exception.start_pc] = [] 505 exception_block_start[exception.start_pc].append(exception) 506 # Index end positions. 507 if not exception_block_end.has_key(exception.end_pc): 508 exception_block_end[exception.end_pc] = [] 509 exception_block_end[exception.end_pc].append(exception) 510 # Index handler positions. 511 if not exception_block_handler.has_key(exception.handler_pc): 512 exception_block_handler[exception.handler_pc] = [] 513 exception_block_handler[exception.handler_pc].append(exception) 514 515 # Process each instruction in the code. 516 while self.java_position < len(code): 517 self.position_mapping[self.java_position] = program.position 518 519 # Insert exception handling constructs. 520 block_starts = exception_block_start.get(self.java_position, []) 521 for exception in block_starts: 522 # Note that the absolute position is used. 523 if exception.catch_type == 0: 524 program.setup_finally(self.position_mapping[exception.handler_pc]) 525 else: 526 program.setup_except(self.position_mapping[exception.handler_pc]) 527 if block_starts: 528 self.in_finally = 0 529 530 # Insert exception handler details. 531 # NOTE: Ensure that pop_block is reachable by possibly inserting it at the start of finally handlers. 532 # NOTE: Insert a check for the correct exception at the start of each handler. 533 for exception in exception_block_handler.get(self.java_position, []): 534 program.end_exception() 535 if exception.catch_type == 0: 536 self.in_finally = 1 537 538 # Where handlers are begun, do not produce equivalent bytecode since 539 # the first handler instruction typically involves saving a local 540 # variable that is not applicable to the Python VM. 541 #if not exception_block_handler.get(self.java_position, []): 542 543 # Process the bytecode at the current position. 544 bytecode = ord(code[self.java_position]) 545 mnemonic, number_of_arguments = self.java_bytecodes[bytecode] 546 number_of_arguments = self.process_bytecode(mnemonic, number_of_arguments, code, program) 547 next_java_position = self.java_position + 1 + number_of_arguments 548 549 # Insert exception block end details. 550 for exception in exception_block_end.get(next_java_position, []): 551 # NOTE: Insert jump beyond handlers. 552 # NOTE: program.jump_forward/absolute(...) 553 # NOTE: Insert end finally at end of handlers as well as where "ret" occurs. 554 if exception.catch_type != 0: 555 program.pop_block() 556 557 # Only advance the JVM position after sneaking in extra Python 558 # instructions. 559 self.java_position = next_java_position 560 561 def process_bytecode(self, mnemonic, number_of_arguments, code, program): 562 if number_of_arguments is not None: 563 arguments = [] 564 for j in range(0, number_of_arguments): 565 arguments.append(ord(code[self.java_position + 1 + j])) 566 567 # Call the handler. 568 getattr(self, mnemonic)(arguments, program) 569 return number_of_arguments 570 else: 571 # Call the handler. 572 return getattr(self, mnemonic)(code[self.java_position+1:], program) 573 574 java_bytecodes = { 575 # code : (mnemonic, number of following bytes, change in stack) 576 0 : ("nop", 0), 577 1 : ("aconst_null", 0), 578 2 : ("iconst_m1", 0), 579 3 : ("iconst_0", 0), 580 4 : ("iconst_1", 0), 581 5 : ("iconst_2", 0), 582 6 : ("iconst_3", 0), 583 7 : ("iconst_4", 0), 584 8 : ("iconst_5", 0), 585 9 : ("lconst_0", 0), 586 10 : ("lconst_1", 0), 587 11 : ("fconst_0", 0), 588 12 : ("fconst_1", 0), 589 13 : ("fconst_2", 0), 590 14 : ("dconst_0", 0), 591 15 : ("dconst_1", 0), 592 16 : ("bipush", 1), 593 17 : ("sipush", 2), 594 18 : ("ldc", 1), 595 19 : ("ldc_w", 2), 596 20 : ("ldc2_w", 2), 597 21 : ("iload", 1), 598 22 : ("lload", 1), 599 23 : ("fload", 1), 600 24 : ("dload", 1), 601 25 : ("aload", 1), 602 26 : ("iload_0", 0), 603 27 : ("iload_1", 0), 604 28 : ("iload_2", 0), 605 29 : ("iload_3", 0), 606 30 : ("lload_0", 0), 607 31 : ("lload_1", 0), 608 32 : ("lload_2", 0), 609 33 : ("lload_3", 0), 610 34 : ("fload_0", 0), 611 35 : ("fload_1", 0), 612 36 : ("fload_2", 0), 613 37 : ("fload_3", 0), 614 38 : ("dload_0", 0), 615 39 : ("dload_1", 0), 616 40 : ("dload_2", 0), 617 41 : ("dload_3", 0), 618 42 : ("aload_0", 0), 619 43 : ("aload_1", 0), 620 44 : ("aload_2", 0), 621 45 : ("aload_3", 0), 622 46 : ("iaload", 0), 623 47 : ("laload", 0), 624 48 : ("faload", 0), 625 49 : ("daload", 0), 626 50 : ("aaload", 0), 627 51 : ("baload", 0), 628 52 : ("caload", 0), 629 53 : ("saload", 0), 630 54 : ("istore", 1), 631 55 : ("lstore", 1), 632 56 : ("fstore", 1), 633 57 : ("dstore", 1), 634 58 : ("astore", 1), 635 59 : ("istore_0", 0), 636 60 : ("istore_1", 0), 637 61 : ("istore_2", 0), 638 62 : ("istore_3", 0), 639 63 : ("lstore_0", 0), 640 64 : ("lstore_1", 0), 641 65 : ("lstore_2", 0), 642 66 : ("lstore_3", 0), 643 67 : ("fstore_0", 0), 644 68 : ("fstore_1", 0), 645 69 : ("fstore_2", 0), 646 70 : ("fstore_3", 0), 647 71 : ("dstore_0", 0), 648 72 : ("dstore_1", 0), 649 73 : ("dstore_2", 0), 650 74 : ("dstore_3", 0), 651 75 : ("astore_0", 0), 652 76 : ("astore_1", 0), 653 77 : ("astore_2", 0), 654 78 : ("astore_3", 0), 655 79 : ("iastore", 0), 656 80 : ("lastore", 0), 657 81 : ("fastore", 0), 658 82 : ("dastore", 0), 659 83 : ("aastore", 0), 660 84 : ("bastore", 0), 661 85 : ("castore", 0), 662 86 : ("sastore", 0), 663 87 : ("pop", 0), 664 88 : ("pop2", 0), 665 89 : ("dup", 0), 666 90 : ("dup_x1", 0), 667 91 : ("dup_x2", 0), 668 92 : ("dup2", 0), 669 93 : ("dup2_x1", 0), 670 94 : ("dup2_x2", 0), 671 95 : ("swap", 0), 672 96 : ("iadd", 0), 673 97 : ("ladd", 0), 674 98 : ("fadd", 0), 675 99 : ("dadd", 0), 676 100 : ("isub", 0), 677 101 : ("lsub", 0), 678 102 : ("fsub", 0), 679 103 : ("dsub", 0), 680 104 : ("imul", 0), 681 105 : ("lmul", 0), 682 106 : ("fmul", 0), 683 107 : ("dmul", 0), 684 108 : ("idiv", 0), 685 109 : ("ldiv", 0), 686 110 : ("fdiv", 0), 687 111 : ("ddiv", 0), 688 112 : ("irem", 0), 689 113 : ("lrem", 0), 690 114 : ("frem", 0), 691 115 : ("drem", 0), 692 116 : ("ineg", 0), 693 117 : ("lneg", 0), 694 118 : ("fneg", 0), 695 119 : ("dneg", 0), 696 120 : ("ishl", 0), 697 121 : ("lshl", 0), 698 122 : ("ishr", 0), 699 123 : ("lshr", 0), 700 124 : ("iushr", 0), 701 125 : ("lushr", 0), 702 126 : ("iand", 0), 703 127 : ("land", 0), 704 128 : ("ior", 0), 705 129 : ("lor", 0), 706 130 : ("ixor", 0), 707 131 : ("lxor", 0), 708 132 : ("iinc", 2), 709 133 : ("i2l", 0), 710 134 : ("i2f", 0), 711 135 : ("i2d", 0), 712 136 : ("l2i", 0), 713 137 : ("l2f", 0), 714 138 : ("l2d", 0), 715 139 : ("f2i", 0), 716 140 : ("f2l", 0), 717 141 : ("f2d", 0), 718 142 : ("d2i", 0), 719 143 : ("d2l", 0), 720 144 : ("d2f", 0), 721 145 : ("i2b", 0), 722 146 : ("i2c", 0), 723 147 : ("i2s", 0), 724 148 : ("lcmp", 0), 725 149 : ("fcmpl", 0), 726 150 : ("fcmpg", 0), 727 151 : ("dcmpl", 0), 728 152 : ("dcmpg", 0), 729 153 : ("ifeq", 2), 730 154 : ("ifne", 2), 731 155 : ("iflt", 2), 732 156 : ("ifge", 2), 733 157 : ("ifgt", 2), 734 158 : ("ifle", 2), 735 159 : ("if_icmpeq", 2), 736 160 : ("if_icmpne", 2), 737 161 : ("if_icmplt", 2), 738 162 : ("if_icmpge", 2), 739 163 : ("if_icmpgt", 2), 740 164 : ("if_icmple", 2), 741 165 : ("if_acmpeq", 2), 742 166 : ("if_acmpne", 2), 743 167 : ("goto", 2), 744 168 : ("jsr", 2), 745 169 : ("ret", 1), 746 170 : ("tableswitch", None), # variable number of arguments 747 171 : ("lookupswitch", None), # variable number of arguments 748 172 : ("ireturn", 0), 749 173 : ("lreturn", 0), 750 174 : ("freturn", 0), 751 175 : ("dreturn", 0), 752 176 : ("areturn", 0), 753 177 : ("return_", 0), 754 178 : ("getstatic", 2), 755 179 : ("putstatic", 2), 756 180 : ("getfield", 2), 757 181 : ("putfield", 2), 758 182 : ("invokevirtual", 2), 759 183 : ("invokespecial", 2), 760 184 : ("invokestatic", 2), 761 185 : ("invokeinterface", 4), 762 187 : ("new", 2), 763 188 : ("newarray", 1), 764 189 : ("anewarray", 2), 765 190 : ("arraylength", 0), 766 191 : ("athrow", 0), 767 192 : ("checkcast", 2), 768 193 : ("instanceof", 2), 769 194 : ("monitorenter", 0), 770 195 : ("monitorexit", 0), 771 196 : ("wide", None), # 3 or 5 arguments, stack changes according to modified element 772 197 : ("multianewarray", 3), 773 198 : ("ifnull", 2), 774 199 : ("ifnonnull", 2), 775 200 : ("goto_w", 4), 776 201 : ("jsr_w", 4), 777 } 778 779 class BytecodeDisassembler(BytecodeReader): 780 781 "A Java bytecode disassembler." 782 783 bytecode_methods = [spec[0] for spec in BytecodeReader.java_bytecodes.values()] 784 785 def __getattr__(self, name): 786 if name in self.bytecode_methods: 787 print "%5s %s" % (self.java_position, name), 788 return self.generic 789 else: 790 raise AttributeError, name 791 792 def generic(self, arguments, program): 793 print arguments 794 795 class BytecodeDisassemblerProgram: 796 position = 0 797 def setup_except(self, target): 798 print "(setup_except %s)" % target 799 def setup_finally(self, target): 800 print "(setup_finally %s)" % target 801 def end_exception(self): 802 print "(end_exception)" 803 def pop_block(self): 804 print "(pop_block)" 805 806 class BytecodeTranslator(BytecodeReader): 807 808 "A Java bytecode translator which uses a Python bytecode writer." 809 810 def aaload(self, arguments, program): 811 # NOTE: No type checking performed. 812 program.binary_subscr() 813 814 def aastore(self, arguments, program): 815 # NOTE: No type checking performed. 816 # Stack: arrayref, index, value 817 program.rot_three() # Stack: value, arrayref, index 818 program.store_subscr() 819 820 def aconst_null(self, arguments, program): 821 program.load_const(None) 822 823 def aload(self, arguments, program): 824 program.load_fast(arguments[0]) 825 826 def aload_0(self, arguments, program): 827 program.load_fast(0) 828 829 def aload_1(self, arguments, program): 830 program.load_fast(1) 831 832 def aload_2(self, arguments, program): 833 program.load_fast(2) 834 835 def aload_3(self, arguments, program): 836 program.load_fast(3) 837 838 def anewarray(self, arguments, program): 839 # NOTE: Does not raise NegativeArraySizeException. 840 # NOTE: Not using the index to type the list/array. 841 index = (arguments[0] << 8) + arguments[1] 842 self._newarray(program) 843 844 def _newarray(self, program): 845 program.build_list() # Stack: count, list 846 program.rot_two() # Stack: list, count 847 program.setup_loop() 848 program.load_global("range") 849 program.load_const(0) # Stack: list, count, range, 0 850 program.rot_three() # Stack: list, 0, count, range 851 program.rot_three() # Stack: list, range, 0, count 852 program.call_function(2) # Stack: list, range_list 853 program.get_iter() # Stack: list, iter 854 program.for_iter() # Stack: list, iter, value 855 program.pop_top() # Stack: list, iter 856 program.rot_two() # Stack: iter, list 857 program.dup_top() # Stack: iter, list, list 858 program.load_attr("append") # Stack: iter, list, append 859 program.load_const(None) # Stack: iter, list, append, None 860 program.call_function(1) # Stack: iter, list, None 861 program.pop_top() # Stack: iter, list 862 program.rot_two() # Stack: list, iter 863 program.end_loop() # Back to for_iter above 864 865 def areturn(self, arguments, program): 866 program.return_value() 867 868 def arraylength(self, arguments, program): 869 program.load_global("len") # Stack: arrayref, len 870 program.rot_two() # Stack: len, arrayref 871 program.call_function(1) 872 873 def astore(self, arguments, program): 874 program.store_fast(arguments[0]) 875 876 def astore_0(self, arguments, program): 877 program.store_fast(0) 878 879 def astore_1(self, arguments, program): 880 program.store_fast(1) 881 882 def astore_2(self, arguments, program): 883 program.store_fast(2) 884 885 def astore_3(self, arguments, program): 886 program.store_fast(3) 887 888 def athrow(self, arguments, program): 889 # NOTE: NullPointerException not raised where null/None is found on the stack. 890 # If this instruction appears in a finally handler, use end_finally instead. 891 if self.in_finally: 892 program.end_finally() 893 else: 894 program.dup_top() 895 program.raise_varargs(1) 896 897 baload = aaload 898 bastore = aastore 899 900 def bipush(self, arguments, program): 901 program.load_const(arguments[0]) 902 903 caload = aaload 904 castore = aastore 905 906 def checkcast(self, arguments, program): 907 index = (arguments[0] << 8) + arguments[1] 908 target_name = self.class_file.constants[index - 1].get_python_name() 909 # NOTE: Using the string version of the name which may contain incompatible characters. 910 target_components = str(target_name).split("/") 911 912 program.dup_top() # Stack: objectref, objectref 913 program.load_global("isinstance") # Stack: objectref, objectref, isinstance 914 program.rot_two() # Stack: objectref, isinstance, objectref 915 program.load_global(target_components[0]) 916 for target_component in target_components[1:]: 917 program.load_attr(target_component) 918 program.call_function(2) # Stack: objectref 919 920 def d2f(self, arguments, program): 921 pass 922 923 def d2i(self, arguments, program): 924 program.load_global("int") # Stack: value, int 925 program.rot_two() # Stack: int, value 926 program.call_function(1) # Stack: result 927 928 d2l = d2i # Preserving Java semantics 929 930 def dadd(self, arguments, program): 931 # NOTE: No type checking performed. 932 program.binary_add() 933 934 daload = aaload 935 dastore = aastore 936 937 def dcmpg(self, arguments, program): 938 # NOTE: No type checking performed. 939 program.compare_op(">") 940 941 def dcmpl(self, arguments, program): 942 # NOTE: No type checking performed. 943 program.compare_op("<") 944 945 def dconst_0(self, arguments, program): 946 program.load_const(0.0) 947 948 def dconst_1(self, arguments, program): 949 program.load_const(1.0) 950 951 def ddiv(self, arguments, program): 952 # NOTE: No type checking performed. 953 program.binary_divide() 954 955 dload = aload 956 dload_0 = aload_0 957 dload_1 = aload_1 958 dload_2 = aload_2 959 dload_3 = aload_3 960 961 def dmul(self, arguments, program): 962 # NOTE: No type checking performed. 963 program.binary_multiply() 964 965 def dneg(self, arguments, program): 966 # NOTE: No type checking performed. 967 program.unary_negative() 968 969 def drem(self, arguments, program): 970 # NOTE: No type checking performed. 971 program.binary_modulo() 972 973 dreturn = areturn 974 dstore = astore 975 dstore_0 = astore_0 976 dstore_1 = astore_1 977 dstore_2 = astore_2 978 dstore_3 = astore_3 979 980 def dsub(self, arguments, program): 981 # NOTE: No type checking performed. 982 program.binary_subtract() 983 984 def dup(self, arguments, program): 985 program.dup_top() 986 987 def dup_x1(self, arguments, program): 988 # Ignoring computational type categories. 989 program.dup_top() 990 program.rot_three() 991 992 def dup_x2(self, arguments, program): 993 # Ignoring computational type categories. 994 program.dup_top() 995 program.rot_four() 996 997 dup2 = dup # Ignoring computational type categories 998 dup2_x1 = dup_x1 # Ignoring computational type categories 999 dup2_x2 = dup_x2 # Ignoring computational type categories 1000 1001 def f2d(self, arguments, program): 1002 pass # Preserving Java semantics 1003 1004 def f2i(self, arguments, program): 1005 program.load_global("int") # Stack: value, int 1006 program.rot_two() # Stack: int, value 1007 program.call_function(1) # Stack: result 1008 1009 f2l = f2i # Preserving Java semantics 1010 fadd = dadd 1011 faload = daload 1012 fastore = dastore 1013 fcmpg = dcmpg 1014 fcmpl = dcmpl 1015 fconst_0 = dconst_0 1016 fconst_1 = dconst_1 1017 1018 def fconst_2(self, arguments, program): 1019 program.load_const(2.0) 1020 1021 fdiv = ddiv 1022 fload = dload 1023 fload_0 = dload_0 1024 fload_1 = dload_1 1025 fload_2 = dload_2 1026 fload_3 = dload_3 1027 fmul = dmul 1028 fneg = dneg 1029 frem = drem 1030 freturn = dreturn 1031 fstore = dstore 1032 fstore_0 = dstore_0 1033 fstore_1 = dstore_1 1034 fstore_2 = dstore_2 1035 fstore_3 = dstore_3 1036 fsub = dsub 1037 1038 def getfield(self, arguments, program): 1039 index = (arguments[0] << 8) + arguments[1] 1040 target_name = self.class_file.constants[index - 1].get_python_name() 1041 # NOTE: Using the string version of the name which may contain incompatible characters. 1042 program.load_attr(str(target_name)) 1043 1044 def getstatic(self, arguments, program): 1045 index = (arguments[0] << 8) + arguments[1] 1046 target_name = self.class_file.constants[index - 1].get_python_name() 1047 program.load_name("self") 1048 program.load_attr("__class__") 1049 # NOTE: Using the string version of the name which may contain incompatible characters. 1050 program.load_attr(str(target_name)) 1051 1052 def goto(self, arguments, program): 1053 offset = signed2((arguments[0] << 8) + arguments[1]) 1054 java_absolute = self.java_position + offset 1055 program.jump_absolute(self.position_mapping[java_absolute]) 1056 1057 def goto_w(self, arguments, program): 1058 offset = signed4((arguments[0] << 24) + (arguments[1] << 16) + (arguments[2] << 8) + arguments[3]) 1059 java_absolute = self.java_position + offset 1060 program.jump_absolute(self.position_mapping[java_absolute]) 1061 1062 def i2b(self, arguments, program): 1063 pass 1064 1065 def i2c(self, arguments, program): 1066 program.load_global("chr") # Stack: value, chr 1067 program.rot_two() # Stack: chr, value 1068 program.call_function(1) # Stack: result 1069 1070 def i2d(self, arguments, program): 1071 program.load_global("float") # Stack: value, float 1072 program.rot_two() # Stack: float, value 1073 program.call_function(1) # Stack: result 1074 1075 i2f = i2d # Not distinguishing between float and double 1076 1077 def i2l(self, arguments, program): 1078 pass # Preserving Java semantics 1079 1080 def i2s(self, arguments, program): 1081 pass # Not distinguishing between int and short 1082 1083 iadd = fadd 1084 iaload = faload 1085 1086 def iand(self, arguments, program): 1087 # NOTE: No type checking performed. 1088 program.binary_and() 1089 1090 iastore = fastore 1091 1092 def iconst_m1(self, arguments, program): 1093 program.load_const(-1) 1094 1095 def iconst_0(self, arguments, program): 1096 program.load_const(0) 1097 1098 def iconst_1(self, arguments, program): 1099 program.load_const(1) 1100 1101 def iconst_2(self, arguments, program): 1102 program.load_const(2) 1103 1104 def iconst_3(self, arguments, program): 1105 program.load_const(3) 1106 1107 def iconst_4(self, arguments, program): 1108 program.load_const(4) 1109 1110 def iconst_5(self, arguments, program): 1111 program.load_const(5) 1112 1113 idiv = fdiv 1114 1115 def _if_xcmpx(self, arguments, program, op): 1116 offset = signed2((arguments[0] << 8) + arguments[1]) 1117 java_absolute = self.java_position + offset 1118 program.compare_op(op) 1119 program.jump_to_label(0, "next") # skip if false 1120 program.pop_top() 1121 program.jump_absolute(self.position_mapping[java_absolute]) 1122 program.start_label("next") 1123 program.pop_top() 1124 1125 def if_acmpeq(self, arguments, program): 1126 # NOTE: No type checking performed. 1127 self._if_xcmpx(arguments, program, "is") 1128 1129 def if_acmpne(self, arguments, program): 1130 # NOTE: No type checking performed. 1131 self._if_xcmpx(arguments, program, "is not") 1132 1133 def if_icmpeq(self, arguments, program): 1134 # NOTE: No type checking performed. 1135 self._if_xcmpx(arguments, program, "==") 1136 1137 def if_icmpne(self, arguments, program): 1138 # NOTE: No type checking performed. 1139 self._if_xcmpx(arguments, program, "!=") 1140 1141 def if_icmplt(self, arguments, program): 1142 # NOTE: No type checking performed. 1143 self._if_xcmpx(arguments, program, "<") 1144 1145 def if_icmpge(self, arguments, program): 1146 # NOTE: No type checking performed. 1147 self._if_xcmpx(arguments, program, ">=") 1148 1149 def if_icmpgt(self, arguments, program): 1150 # NOTE: No type checking performed. 1151 self._if_xcmpx(arguments, program, ">") 1152 1153 def if_icmple(self, arguments, program): 1154 # NOTE: No type checking performed. 1155 self._if_xcmpx(arguments, program, "<=") 1156 1157 def ifeq(self, arguments, program): 1158 # NOTE: No type checking performed. 1159 program.load_const(0) 1160 self._if_xcmpx(arguments, program, "==") 1161 1162 def ifne(self, arguments, program): 1163 # NOTE: No type checking performed. 1164 program.load_const(0) 1165 self._if_xcmpx(arguments, program, "!=") 1166 1167 def iflt(self, arguments, program): 1168 # NOTE: No type checking performed. 1169 program.load_const(0) 1170 self._if_xcmpx(arguments, program, "<") 1171 1172 def ifge(self, arguments, program): 1173 # NOTE: No type checking performed. 1174 program.load_const(0) 1175 self._if_xcmpx(arguments, program, ">=") 1176 1177 def ifgt(self, arguments, program): 1178 # NOTE: No type checking performed. 1179 program.load_const(0) 1180 self._if_xcmpx(arguments, program, ">") 1181 1182 def ifle(self, arguments, program): 1183 # NOTE: No type checking performed. 1184 program.load_const(0) 1185 self._if_xcmpx(arguments, program, "<=") 1186 1187 def ifnonnull(self, arguments, program): 1188 # NOTE: No type checking performed. 1189 program.load_const(None) 1190 self._if_xcmpx(arguments, program, "is not") 1191 1192 def ifnull(self, arguments, program): 1193 # NOTE: No type checking performed. 1194 program.load_const(None) 1195 self._if_xcmpx(arguments, program, "is") 1196 1197 def iinc(self, arguments, program): 1198 # NOTE: No type checking performed. 1199 program.load_fast(arguments[0]) 1200 program.load_const(arguments[1]) 1201 program.binary_add() 1202 1203 iload = fload 1204 iload_0 = fload_0 1205 iload_1 = fload_1 1206 iload_2 = fload_2 1207 iload_3 = fload_3 1208 imul = fmul 1209 ineg = fneg 1210 1211 def instanceof(self, arguments, program): 1212 index = (arguments[0] << 8) + arguments[1] 1213 target_name = self.class_file.constants[index - 1].get_python_name() 1214 # NOTE: Using the string version of the name which may contain incompatible characters. 1215 target_components = str(target_name).split("/") 1216 1217 program.load_global("isinstance") # Stack: objectref, isinstance 1218 program.rot_two() # Stack: isinstance, objectref 1219 program.load_global(target_components[0]) 1220 for target_component in target_components[1:]: 1221 program.load_attr(target_component) 1222 program.call_function(2) # Stack: result 1223 1224 def _invoke(self, target_name, program): 1225 # NOTE: Using the string version of the name which may contain incompatible characters. 1226 program.load_attr(str(target_name)) # Stack: tuple, method 1227 program.rot_two() # Stack: method, tuple 1228 program.load_global("apply") # Stack: method, tuple, apply 1229 program.rot_three() # Stack: apply, method, tuple 1230 program.call_function(2) 1231 1232 def invokeinterface(self, arguments, program): 1233 # NOTE: This implementation does not perform the necessary checks for 1234 # NOTE: signature-based polymorphism. 1235 # NOTE: Java rules not specifically obeyed. 1236 index = (arguments[0] << 8) + arguments[1] 1237 count = arguments[2] 1238 target_name = self.class_file.constants[index - 1].get_python_name() 1239 # Stack: objectref, arg1, arg2, ... 1240 program.build_tuple(count) # Stack: objectref, tuple 1241 program.rot_two() # Stack: tuple, objectref 1242 self._invoke(target_name, program) 1243 1244 def invokespecial(self, arguments, program): 1245 # NOTE: This implementation does not perform the necessary checks for 1246 # NOTE: signature-based polymorphism. 1247 # NOTE: Java rules not specifically obeyed. 1248 index = (arguments[0] << 8) + arguments[1] 1249 target = self.class_file.constants[index - 1] 1250 target_name = target.get_python_name() 1251 # Get the number of parameters from the descriptor. 1252 count = len(target.get_descriptor()[0]) 1253 1254 # Check for the method name and invoke superclasses where appropriate. 1255 if str(self.method.get_python_name()) == "__init__": 1256 program.build_tuple(count + 1) # Stack: tuple 1257 # Must use the actual class. 1258 # NOTE: Verify this. 1259 program.load_global(str(self.class_file.this_class.get_python_name())) 1260 # Stack: tuple, classref 1261 program.load_attr("__bases__") # Stack: tuple, bases 1262 program.dup_top() # Stack: tuple, bases, bases 1263 program.load_global("len") # Stack: tuple, bases, bases, len 1264 program.rot_two() # Stack: tuple, bases, len, bases 1265 program.call_function(1) # Stack: tuple, bases, #bases 1266 program.load_const(0) # Stack: tuple, bases, #bases, 0 1267 program.compare_op("==") # Stack: tuple, bases, result 1268 program.jump_to_label(1, "next") 1269 program.pop_top() # Stack: tuple, bases 1270 program.load_const(0) # Stack: tuple, bases, 0 1271 program.binary_subscr() # Stack: tuple, bases[0] 1272 self._invoke(target_name, program) 1273 program.jump_to_label(None, "next2") 1274 program.start_label("next") 1275 program.pop_top() # Stack: tuple, bases 1276 program.pop_top() # Stack: tuple 1277 program.pop_top() # Stack: 1278 program.start_label("next2") 1279 1280 elif str(target_name) == "__init__": 1281 # NOTE: Due to changes with the new instruction's implementation, the 1282 # NOTE: stack differs from that stated: objectref, arg1, arg2, ... 1283 # Stack: classref, arg1, arg2, ... 1284 program.build_tuple(count) # Stack: classref, tuple 1285 # NOTE: Stack: objectref, tuple 1286 program.load_global("apply") # Stack: classref, tuple, apply 1287 program.rot_three() # Stack: apply, classref, tuple 1288 program.call_function(2) 1289 1290 else: 1291 program.build_tuple(count) # Stack: objectref, tuple 1292 program.rot_two() # Stack: tuple, objectref 1293 self._invoke(target_name, program) 1294 1295 """ 1296 def invokespecial(self, arguments, program): 1297 # NOTE: This implementation does not perform the necessary checks for 1298 # NOTE: signature-based polymorphism. 1299 # NOTE: Java rules not specifically obeyed. 1300 index = (arguments[0] << 8) + arguments[1] 1301 target = self.class_file.constants[index - 1] 1302 target_name = target.get_python_name() 1303 # Get the number of parameters from the descriptor. 1304 count = len(target.get_descriptor()[0]) 1305 # Stack: objectref, arg1, arg2, ... 1306 program.build_tuple(count + 1) # Stack: tuple 1307 # Use the class to provide access to static methods. 1308 program.load_name("self") # Stack: tuple, self 1309 program.load_attr("__class__") # Stack: tuple, class 1310 program.load_attr("__bases__") # Stack: tuple, base-classes 1311 program.dup_top() # Stack: tuple, base-classes, base-classes 1312 program.load_global("len") # Stack: tuple, base-classes, base-classes, len 1313 program.rot_two() # Stack: tuple, base-classes, len, base-classes 1314 program.call_function(1) # Stack: tuple, base-classes, count 1315 program.load_const(0) # Stack: tuple, base-classes, count, 0 1316 program.compare_op("==") # Stack: tuple, base-classes, result 1317 program.jump_to_label(1, "next") 1318 program.pop_top() # Stack: tuple, base-classes 1319 program.load_const(0) # Stack: tuple, base-classes, 0 1320 program.binary_subscr() # Stack: tuple, superclass 1321 self._invoke(target_name, program) 1322 program.jump_to_label(None, "next2") 1323 program.start_label("next") 1324 program.pop_top() # Stack: tuple, base-classes 1325 program.pop_top() # Stack: tuple 1326 program.pop_top() # Stack: 1327 program.start_label("next2") 1328 """ 1329 1330 def invokestatic(self, arguments, program): 1331 # NOTE: This implementation does not perform the necessary checks for 1332 # NOTE: signature-based polymorphism. 1333 # NOTE: Java rules not specifically obeyed. 1334 index = (arguments[0] << 8) + arguments[1] 1335 target = self.class_file.constants[index - 1] 1336 target_name = target.get_python_name() 1337 # Get the number of parameters from the descriptor. 1338 count = len(target.get_descriptor()[0]) 1339 # Stack: arg1, arg2, ... 1340 program.build_tuple(count) # Stack: tuple 1341 # Use the class to provide access to static methods. 1342 program.load_name("self") # Stack: tuple, self 1343 program.load_attr("__class__") # Stack: tuple, class 1344 self._invoke(target_name, program) 1345 1346 def invokevirtual (self, arguments, program): 1347 # NOTE: This implementation does not perform the necessary checks for 1348 # NOTE: signature-based polymorphism. 1349 # NOTE: Java rules not specifically obeyed. 1350 index = (arguments[0] << 8) + arguments[1] 1351 target = self.class_file.constants[index - 1] 1352 target_name = target.get_python_name() 1353 # Get the number of parameters from the descriptor. 1354 count = len(target.get_descriptor()[0]) 1355 # Stack: objectref, arg1, arg2, ... 1356 program.build_tuple(count) # Stack: objectref, tuple 1357 program.rot_two() # Stack: tuple, objectref 1358 self._invoke(target_name, program) 1359 1360 def ior(self, arguments, program): 1361 # NOTE: No type checking performed. 1362 program.binary_or() 1363 1364 irem = frem 1365 ireturn = freturn 1366 1367 def ishl(self, arguments, program): 1368 # NOTE: No type checking performed. 1369 # NOTE: Not verified. 1370 program.binary_lshift() 1371 1372 def ishr(self, arguments, program): 1373 # NOTE: No type checking performed. 1374 # NOTE: Not verified. 1375 program.binary_rshift() 1376 1377 istore = fstore 1378 istore_0 = fstore_0 1379 istore_1 = fstore_1 1380 istore_2 = fstore_2 1381 istore_3 = fstore_3 1382 isub = fsub 1383 iushr = ishr # Ignoring distinctions between arithmetic and logical shifts 1384 1385 def ixor(self, arguments, program): 1386 # NOTE: No type checking performed. 1387 program.binary_xor() 1388 1389 def jsr(self, arguments, program): 1390 offset = signed2((arguments[0] << 8) + arguments[1]) 1391 java_absolute = self.java_position + offset 1392 # Store the address of the next instruction. 1393 program.load_const_ret(self.position_mapping[self.java_position + 3]) 1394 program.jump_absolute(self.position_mapping[java_absolute]) 1395 1396 def jsr_w(self, arguments, program): 1397 offset = signed4((arguments[0] << 24) + (arguments[1] << 16) + (arguments[2] << 8) + arguments[3]) 1398 java_absolute = self.java_position + offset 1399 # Store the address of the next instruction. 1400 program.load_const_ret(self.position_mapping[self.java_position + 5]) 1401 program.jump_absolute(self.position_mapping[java_absolute]) 1402 1403 l2d = i2d 1404 l2f = i2f 1405 1406 def l2i(self, arguments, program): 1407 pass # Preserving Java semantics 1408 1409 ladd = iadd 1410 laload = iaload 1411 land = iand 1412 lastore = iastore 1413 1414 def lcmp(self, arguments, program): 1415 # NOTE: No type checking performed. 1416 program.dup_topx(2) # Stack: value1, value2, value1, value2 1417 program.compare_op(">") # Stack: value1, value2, result 1418 program.jump_to_label(0, "equals") 1419 # True - produce result and branch. 1420 program.pop_top() # Stack: value1, value2 1421 program.pop_top() # Stack: value1 1422 program.pop_top() # Stack: 1423 program.load_const(1) # Stack: 1 1424 program.jump_to_label(None, "next") 1425 # False - test equality. 1426 program.start_label("equals") 1427 program.pop_top() # Stack: value1, value2 1428 program.dup_topx(2) # Stack: value1, value2, value1, value2 1429 program.compare_op("==") # Stack: value1, value2, result 1430 program.jump_to_label(0, "less") 1431 # True - produce result and branch. 1432 program.pop_top() # Stack: value1, value2 1433 program.pop_top() # Stack: value1 1434 program.pop_top() # Stack: 1435 program.load_const(0) # Stack: 0 1436 program.jump_to_label(None, "next") 1437 # False - produce result. 1438 program.start_label("less") 1439 program.pop_top() # Stack: value1, value2 1440 program.pop_top() # Stack: value1 1441 program.pop_top() # Stack: 1442 program.load_const(-1) # Stack: -1 1443 program.start_label("next") 1444 1445 lconst_0 = iconst_0 1446 lconst_1 = iconst_1 1447 1448 def ldc(self, arguments, program): 1449 program.load_const(self.class_file.constants[arguments[0] - 1]) 1450 1451 def ldc_w(self, arguments, program): 1452 program.load_const(self.class_file.constants[(arguments[0] << 8) + arguments[1] - 1]) 1453 1454 ldc2_w = ldc_w 1455 ldiv = idiv 1456 lload = iload 1457 lload_0 = iload_0 1458 lload_1 = iload_1 1459 lload_2 = iload_2 1460 lload_3 = iload_3 1461 lmul = imul 1462 lneg = ineg 1463 1464 def lookupswitch(self, arguments, program): 1465 # Find the offset to the next 4 byte boundary in the code. 1466 d, r = divmod(self.java_position, 4) 1467 to_boundary = (4 - r) % 4 1468 # Get the pertinent arguments. 1469 arguments = arguments[to_boundary:] 1470 default = (arguments[0] << 24) + (arguments[1] << 16) + (arguments[2] << 8) + arguments[3] 1471 npairs = (arguments[4] << 24) + (arguments[5] << 16) + (arguments[6] << 8) + arguments[7] 1472 # Process the pairs. 1473 # NOTE: This is not the most optimal implementation. 1474 pair_index = 8 1475 for pair in range(0, npairs): 1476 match = ((arguments[pair_index] << 24) + (arguments[pair_index + 1] << 16) + 1477 (arguments[pair_index + 2] << 8) + arguments[pair_index + 3]) 1478 offset = signed4((arguments[pair_index + 4] << 24) + (arguments[pair_index + 5] << 16) + 1479 (arguments[pair_index + 6] << 8) + arguments[pair_index + 7]) 1480 # Calculate the branch target. 1481 java_absolute = self.java_position + offset 1482 # Generate branching code. 1483 program.dup_top() # Stack: key, key 1484 program.load_const(match) # Stack: key, key, match 1485 program.compare_op("==") # Stack: key, result 1486 program.jump_to_label(0, "end") 1487 program.pop_top() # Stack: key 1488 program.pop_top() # Stack: 1489 program.jump_absolute(self.position_mapping[java_absolute]) 1490 # Generate the label for the end of the branching code. 1491 program.start_label("end") 1492 program.pop_top() # Stack: key 1493 # Update the index. 1494 pair_index += 8 1495 # Generate the default. 1496 java_absolute = self.java_position + default 1497 program.jump_absolute(self.position_mapping[java_absolute]) 1498 1499 lor = ior 1500 lrem = irem 1501 lreturn = ireturn 1502 lshl = ishl 1503 lshr = ishr 1504 lstore = istore 1505 lstore_0 = istore_0 1506 lstore_1 = istore_1 1507 lstore_2 = istore_2 1508 lstore_3 = istore_3 1509 lsub = isub 1510 lushr = iushr 1511 lxor = ixor 1512 1513 def monitorenter(self, arguments, program): 1514 # NOTE: To be implemented. 1515 pass 1516 1517 def monitorexit(self, arguments, program): 1518 # NOTE: To be implemented. 1519 pass 1520 1521 def multianewarray(self, arguments, program): 1522 # NOTE: To be implemented. 1523 pass 1524 1525 def new(self, arguments, program): 1526 # This operation is considered to be the same as the calling of the 1527 # initialisation method of the given class with no arguments. 1528 index = (arguments[0] << 8) + arguments[1] 1529 target_name = self.class_file.constants[index - 1].get_python_name() 1530 # NOTE: Using the string version of the name which may contain incompatible characters. 1531 program.load_global(str(target_name)) 1532 # NOTE: Unlike Java, we do not provide an object reference. Instead, a 1533 # NOTE: class reference is provided, and the invokespecial method's 1534 # NOTE: behaviour is changed. 1535 #program.call_function(0) 1536 1537 def newarray(self, arguments, program): 1538 # NOTE: Does not raise NegativeArraySizeException. 1539 # NOTE: Not using the arguments to type the list/array. 1540 self._newarray(program) 1541 1542 def nop(self, arguments, program): 1543 pass 1544 1545 def pop(self, arguments, program): 1546 program.pop_top() 1547 1548 pop2 = pop # ignoring Java stack value distinctions 1549 1550 def putfield(self, arguments, program): 1551 index = (arguments[0] << 8) + arguments[1] 1552 target_name = self.class_file.constants[index - 1].get_python_name() 1553 program.rot_two() 1554 # NOTE: Using the string version of the name which may contain incompatible characters. 1555 program.store_attr(str(target_name)) 1556 1557 def putstatic(self, arguments, program): 1558 index = (arguments[0] << 8) + arguments[1] 1559 target_name = self.class_file.constants[index - 1].get_python_name() 1560 program.load_name("self") 1561 program.load_attr("__class__") 1562 # NOTE: Using the string version of the name which may contain incompatible characters. 1563 program.store_attr(str(target_name)) 1564 1565 def ret(self, arguments, program): 1566 program.ret(arguments[0]) 1567 # Indicate that the finally handler is probably over. 1568 # NOTE: This is seemingly not guaranteed. 1569 self.in_finally = 0 1570 1571 def return_(self, arguments, program): 1572 program.load_const(None) 1573 program.return_value() 1574 1575 saload = laload 1576 sastore = lastore 1577 1578 def sipush(self, arguments, program): 1579 program.load_const((arguments[0] << 8) + arguments[1]) 1580 1581 def swap(self, arguments, program): 1582 program.rot_two() 1583 1584 def tableswitch(self, arguments, program): 1585 # Find the offset to the next 4 byte boundary in the code. 1586 d, r = divmod(self.java_position, 4) 1587 to_boundary = (4 - r) % 4 1588 # Get the pertinent arguments. 1589 arguments = arguments[to_boundary:] 1590 default = (arguments[0] << 24) + (arguments[1] << 16) + (arguments[2] << 8) + arguments[3] 1591 low = (arguments[4] << 24) + (arguments[5] << 16) + (arguments[6] << 8) + arguments[7] 1592 high = (arguments[8] << 24) + (arguments[9] << 16) + (arguments[10] << 8) + arguments[11] 1593 # Process the jump entries. 1594 # NOTE: This is not the most optimal implementation. 1595 jump_index = 8 1596 for jump in range(low, high + 1): 1597 offset = signed4((arguments[jump_index] << 24) + (arguments[jump_index + 1] << 16) + 1598 (arguments[jump_index + 2] << 8) + arguments[jump_index + 3]) 1599 # Calculate the branch target. 1600 java_absolute = self.java_position + offset 1601 # Generate branching code. 1602 program.dup_top() # Stack: key, key 1603 program.load_const(jump) # Stack: key, key, jump 1604 program.compare_op("==") # Stack: key, result 1605 program.jump_to_label(0, "end") 1606 program.pop_top() # Stack: key 1607 program.pop_top() # Stack: 1608 program.jump_absolute(self.position_mapping[java_absolute]) 1609 # Generate the label for the end of the branching code. 1610 program.start_label("end") 1611 program.pop_top() # Stack: key 1612 # Update the index. 1613 jump_index += 8 1614 # Generate the default. 1615 java_absolute = self.java_position + default 1616 program.jump_absolute(self.position_mapping[java_absolute]) 1617 1618 def wide(self, code, program): 1619 # NOTE: To be implemented. 1620 return number_of_arguments 1621 1622 def disassemble(class_file, method): 1623 disassembler = BytecodeDisassembler(class_file) 1624 disassembler.process(method, BytecodeDisassemblerProgram()) 1625 1626 def translate(class_file, method): 1627 translator = BytecodeTranslator(class_file) 1628 writer = BytecodeWriter() 1629 translator.process(method, writer) 1630 return translator, writer 1631 1632 def make_varnames(nlocals): 1633 l = ["self"] 1634 for i in range(1, nlocals): 1635 l.append("_l%s" % i) 1636 return l[:nlocals] 1637 1638 if __name__ == "__main__": 1639 import sys 1640 from classfile import ClassFile 1641 global_names = {} 1642 global_names.update(__builtins__.__dict__) 1643 for filename in sys.argv[1:]: 1644 f = open(filename, "rb") 1645 c = ClassFile(f.read()) 1646 import dis, new 1647 namespace = {} 1648 for method in c.methods: 1649 nargs = len(method.get_descriptor()[0]) + 1 1650 t, w = translate(c, method) 1651 nlocals = w.max_locals + 1 1652 filename = str(c.attributes[0].get_name()) 1653 method_name = str(method.get_python_name()) 1654 code = new.code(nargs, nlocals, w.max_stack_depth, 67, w.get_output(), tuple(w.get_constants()), tuple(w.get_names()), 1655 tuple(make_varnames(nlocals)), filename, method_name, 0, "") 1656 # NOTE: May need more globals. 1657 fn = new.function(code, global_names) 1658 namespace[method_name] = fn 1659 # NOTE: Define superclasses properly. 1660 if str(c.super_class.get_name()) not in ("java/lang/Object", "java/lang/Exception"): 1661 bases = (global_names[str(c.super_class.get_python_name())],) 1662 else: 1663 bases = () 1664 cls = new.classobj(str(c.this_class.get_python_name()), bases, namespace) 1665 global_names[cls.__name__] = cls 1666 1667 # vim: tabstop=4 expandtab shiftwidth=4