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