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