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 import classfile 11 from dis import cmp_op # for access to Python bytecode values and operators 12 try: 13 from dis import opmap 14 except ImportError: 15 from dis import opname 16 opmap = {} 17 for i in range(0, len(opname)): 18 opmap[opname[i]] = i 19 from UserDict import UserDict 20 import new 21 22 # Bytecode production classes. 23 24 class BytecodeWriter: 25 26 "A Python bytecode writer." 27 28 def __init__(self): 29 30 "Initialise the writer." 31 32 # A stack of loop start instructions corresponding to loop blocks. 33 self.loops = [] 34 35 # A stack of loop block or exception block start positions. 36 self.blocks = [] 37 38 # A stack of exception block handler pointers. 39 self.exception_handlers = [] 40 41 # A dictionary mapping labels to jump instructions referencing such labels. 42 self.jumps = {} 43 44 # The output values, including "lazy" subvalues which will need evaluating. 45 self.output = [] 46 47 # The current Python bytecode instruction position. 48 self.position = 0 49 50 # Stack depth estimation. 51 self.stack_depth = 0 52 self.max_stack_depth = 0 53 54 # Local variable estimation. 55 self.max_locals = 0 56 57 # Mapping from values to indexes. 58 self.constants = {} 59 60 # Mapping from names to indexes. 61 # NOTE: This may be acquired from elsewhere. 62 #self.globals = {} 63 64 # Mapping from names to indexes. 65 self.names = {} 66 67 # A list of constants used as exception handler return addresses. 68 self.constants_for_exceptions = [] 69 70 # A list of external names. 71 self.external_names = [] 72 73 def get_output(self): 74 75 "Return the output of the writer as a string." 76 77 output = [] 78 for element in self.output: 79 if isinstance(element, LazySubValue): 80 value = element.value 81 else: 82 value = element 83 # NOTE: ValueError gets raised for bad values here. 84 output.append(chr(value)) 85 return "".join(output) 86 87 def get_constants(self): 88 89 """ 90 Return a list of constants with ordering significant to the code 91 employing them. 92 """ 93 94 l = self._get_list(self._invert(self.constants)) 95 result = [] 96 for i in l: 97 if isinstance(i, LazyValue): 98 result.append(i.get_value()) 99 else: 100 result.append(i) 101 return result 102 103 #def get_globals(self): 104 # return self._get_list(self._invert(self.globals)) 105 106 def get_names(self): 107 108 """ 109 Return a list of names with ordering significant to the code employing 110 them. 111 """ 112 113 return self._get_list(self._invert(self.names)) 114 115 def _invert(self, d): 116 117 """ 118 Return a new dictionary whose key-to-value mapping is in the inverse of 119 that found in 'd'. 120 """ 121 122 inverted = {} 123 for k, v in d.items(): 124 inverted[v] = k 125 return inverted 126 127 def _get_list(self, d): 128 129 """ 130 Traverse the dictionary 'd' returning a list whose values appear at the 131 position denoted by each value's key in 'd'. 132 """ 133 134 l = [] 135 for i in range(0, len(d.keys())): 136 l.append(d[i]) 137 return l 138 139 # Administrative methods. 140 141 def update_stack_depth(self, change): 142 143 """ 144 Given the stated 'change' in stack depth, update the maximum stack depth 145 where appropriate. 146 """ 147 148 self.stack_depth += change 149 if self.stack_depth > self.max_stack_depth: 150 self.max_stack_depth = self.stack_depth 151 152 def update_locals(self, index): 153 154 """ 155 Given the stated 'index' of a local variable, update the maximum local 156 variable index where appropriate. 157 """ 158 159 if index > self.max_locals: 160 self.max_locals = index 161 162 # Special methods. 163 164 def _write_value(self, value): 165 166 """ 167 Write the given 'value' at the current output position. 168 """ 169 170 if isinstance(value, LazyValue): 171 # NOTE: Assume a 16-bit value. 172 self.output.append(value.values[0]) 173 self.output.append(value.values[1]) 174 self.position += 2 175 elif value <= 0xffff: 176 self.output.append(value & 0xff) 177 self.output.append((value & 0xff00) >> 8) 178 self.position += 2 179 else: 180 # NOTE: EXTENDED_ARG not yet supported. 181 raise ValueError, value 182 183 def _rewrite_value(self, position, value): 184 185 """ 186 At the given output 'position', rewrite the given 'value'. 187 """ 188 189 # NOTE: Assume a 16-bit value. 190 if value <= 0xffff: 191 self.output[position] = (value & 0xff) 192 self.output[position + 1] = ((value & 0xff00) >> 8) 193 else: 194 # NOTE: EXTENDED_ARG not yet supported. 195 raise ValueError, value 196 197 # Higher level methods. 198 199 def use_external_name(self, name): 200 # NOTE: Remove array and object indicators. 201 self.external_names.append(name) 202 203 def setup_loop(self): 204 self.loops.append(self.position) 205 self.output.append(opmap["SETUP_LOOP"]) 206 self.position += 1 207 self._write_value(0) # To be filled in later 208 209 def end_loop(self): 210 current_loop_start = self.loops.pop() 211 current_loop_real_start = self.blocks.pop() 212 #print "<", self.blocks, current_loop_real_start 213 # Fix the iterator delta. 214 # NOTE: Using 3 as the assumed length of the FOR_ITER instruction. 215 self.jump_absolute(current_loop_real_start) 216 self._rewrite_value(current_loop_real_start + 1, self.position - current_loop_real_start - 3) 217 self.pop_block() 218 # Fix the loop delta. 219 # NOTE: Using 3 as the assumed length of the SETUP_LOOP instruction. 220 self._rewrite_value(current_loop_start + 1, self.position - current_loop_start - 3) 221 222 def jump_to_label(self, status, name): 223 # Record the instruction using the jump. 224 jump_instruction = self.position 225 if status is None: 226 self.jump_forward() 227 elif status: 228 self.jump_if_true() 229 else: 230 self.jump_if_false() 231 # Record the following instruction, too. 232 if not self.jumps.has_key(name): 233 self.jumps[name] = [] 234 self.jumps[name].append((jump_instruction, self.position)) 235 236 def start_label(self, name): 237 # Fill in all jump instructions. 238 for jump_instruction, following_instruction in self.jumps[name]: 239 self._rewrite_value(jump_instruction + 1, self.position - following_instruction) 240 del self.jumps[name] 241 242 def load_const_ret(self, value): 243 self.constants_for_exceptions.append(value) 244 self.load_const(value) 245 246 def ret(self, index): 247 self.load_fast(index) 248 249 # Previously, the constant stored on the stack by jsr/jsr_w was stored 250 # in a local variable. In the JVM, extracting the value from the local 251 # variable and jumping can be done at runtime. In the Python VM, any 252 # jump target must be known in advance and written into the bytecode. 253 254 for constant in self.constants_for_exceptions: 255 self.dup_top() # Stack: actual-address, actual-address 256 self.load_const(constant) # Stack: actual-address, actual-address, suggested-address 257 self.compare_op("==") # Stack: actual-address, result 258 self.jump_to_label(0, "const") 259 self.pop_top() # Stack: actual-address 260 self.pop_top() # Stack: 261 self.jump_absolute(constant) 262 self.start_label("const") 263 self.pop_top() # Stack: actual-address 264 265 # NOTE: If we get here, something is really wrong. 266 267 self.pop_top() # Stack: 268 269 def setup_except(self, target): 270 self.blocks.append(self.position) 271 self.exception_handlers.append(target) 272 #print "-", self.position, target 273 self.output.append(opmap["SETUP_EXCEPT"]) 274 self.position += 1 275 self._write_value(0) # To be filled in later 276 277 def setup_finally(self, target): 278 self.blocks.append(self.position) 279 self.exception_handlers.append(target) 280 #print "-", self.position, target 281 self.output.append(opmap["SETUP_FINALLY"]) 282 self.position += 1 283 self._write_value(0) # To be filled in later 284 285 def end_exception(self): 286 current_exception_start = self.blocks.pop() 287 # Convert the "lazy" absolute value. 288 current_exception_target = self.exception_handlers.pop() 289 target = current_exception_target.get_value() 290 #print "*", current_exception_start, target 291 # NOTE: Using 3 as the assumed length of the SETUP_* instruction. 292 self._rewrite_value(current_exception_start + 1, target - current_exception_start - 3) 293 294 def start_handler(self, exc_name, class_file): 295 296 # Where handlers are begun, produce bytecode to test the type of 297 # the exception. 298 # NOTE: Since RAISE_VARARGS and END_FINALLY are not really documented, 299 # NOTE: we store the top of the stack and use it later to trigger the 300 # NOTE: magic processes when re-raising. 301 self.use_external_name(str(exc_name)) 302 303 self.rot_two() # Stack: raised-exception, exception 304 self.dup_top() # Stack: raised-exception, exception, exception 305 # Handled exceptions are wrapped before being thrown. 306 self.load_global("Exception") # Stack: raised-exception, exception, exception, Exception 307 self.compare_op("exception match") # Stack: raised-exception, exception, result 308 self.jump_to_label(0, "next") 309 self.pop_top() # Stack: raised-exception, exception 310 self.dup_top() # Stack: raised-exception, exception, exception 311 self.load_attr("args") # Stack: raised-exception, exception, args 312 self.load_const(0) # Stack: raised-exception, exception, args, 0 313 self.binary_subscr() # Stack: raised-exception, exception, exception-object 314 load_class_name(class_file, str(exc_name), self) 315 # Stack: raised-exception, exception, exception-object, handled-exception 316 self.load_global("isinstance") # Stack: raised-exception, exception, exception-object, handled-exception, isinstance 317 self.rot_three() # Stack: raised-exception, exception, isinstance, exception-object, handled-exception 318 self.call_function(2) # Stack: raised-exception, exception, result 319 self.jump_to_label(1, "handler") 320 self.start_label("next") 321 self.pop_top() # Stack: raised-exception, exception 322 self.rot_two() # Stack: exception, raised-exception 323 self.end_finally() 324 self.start_label("handler") 325 self.pop_top() # Stack: raised-exception, exception 326 327 # Complicated methods. 328 329 def load_const(self, value): 330 self.output.append(opmap["LOAD_CONST"]) 331 if not self.constants.has_key(value): 332 self.constants[value] = len(self.constants.keys()) 333 self.position += 1 334 self._write_value(self.constants[value]) 335 self.update_stack_depth(1) 336 337 def load_global(self, name): 338 self.output.append(opmap["LOAD_GLOBAL"]) 339 if not self.names.has_key(name): 340 self.names[name] = len(self.names.keys()) 341 self.position += 1 342 self._write_value(self.names[name]) 343 self.update_stack_depth(1) 344 345 def load_attr(self, name): 346 self.output.append(opmap["LOAD_ATTR"]) 347 if not self.names.has_key(name): 348 self.names[name] = len(self.names.keys()) 349 self.position += 1 350 self._write_value(self.names[name]) 351 352 def load_name(self, name): 353 self.output.append(opmap["LOAD_NAME"]) 354 if not self.names.has_key(name): 355 self.names[name] = len(self.names.keys()) 356 self.position += 1 357 self._write_value(self.names[name]) 358 self.update_stack_depth(1) 359 360 def load_fast(self, index): 361 self.output.append(opmap["LOAD_FAST"]) 362 self.position += 1 363 self._write_value(index) 364 self.update_stack_depth(1) 365 self.update_locals(index) 366 367 def store_attr(self, name): 368 self.output.append(opmap["STORE_ATTR"]) 369 if not self.names.has_key(name): 370 self.names[name] = len(self.names.keys()) 371 self.position += 1 372 self._write_value(self.names[name]) 373 self.update_stack_depth(-1) 374 375 def store_fast(self, index): 376 self.output.append(opmap["STORE_FAST"]) 377 self.position += 1 378 self._write_value(index) 379 self.update_stack_depth(-1) 380 self.update_locals(index) 381 382 def for_iter(self): 383 self.blocks.append(self.position) 384 #print ">", self.blocks 385 self.output.append(opmap["FOR_ITER"]) 386 self.position += 1 387 self._write_value(0) # To be filled in later 388 self.update_stack_depth(1) 389 390 def break_loop(self): 391 self.output.append(opmap["BREAK_LOOP"]) 392 self.position += 1 393 self.jump_absolute(self.blocks[-1]) 394 395 # Normal bytecode generators. 396 397 def get_iter(self): 398 self.output.append(opmap["GET_ITER"]) 399 self.position += 1 400 401 def jump_if_false(self, offset=0): 402 self.output.append(opmap["JUMP_IF_FALSE"]) 403 self.position += 1 404 self._write_value(offset) # May be filled in later 405 406 def jump_if_true(self, offset=0): 407 self.output.append(opmap["JUMP_IF_TRUE"]) 408 self.position += 1 409 self._write_value(offset) # May be filled in later 410 411 def jump_forward(self, offset=0): 412 self.output.append(opmap["JUMP_FORWARD"]) 413 self.position += 1 414 self._write_value(offset) # May be filled in later 415 416 def jump_absolute(self, address=0): 417 self.output.append(opmap["JUMP_ABSOLUTE"]) 418 self.position += 1 419 self._write_value(address) # May be filled in later 420 421 def build_tuple(self, count): 422 self.output.append(opmap["BUILD_TUPLE"]) 423 self.position += 1 424 self._write_value(count) 425 self.update_stack_depth(-(count - 1)) 426 427 def build_list(self, count): 428 self.output.append(opmap["BUILD_LIST"]) 429 self.position += 1 430 self._write_value(count) 431 self.update_stack_depth(-(count - 1)) 432 433 def pop_top(self): 434 self.output.append(opmap["POP_TOP"]) 435 self.position += 1 436 self.update_stack_depth(-1) 437 438 def dup_top(self): 439 self.output.append(opmap["DUP_TOP"]) 440 self.position += 1 441 self.update_stack_depth(1) 442 443 def dup_topx(self, count): 444 self.output.append(opmap["DUP_TOPX"]) 445 self.position += 1 446 self._write_value(count) 447 self.update_stack_depth(count) 448 449 def rot_two(self): 450 self.output.append(opmap["ROT_TWO"]) 451 self.position += 1 452 453 def rot_three(self): 454 self.output.append(opmap["ROT_THREE"]) 455 self.position += 1 456 457 def rot_four(self): 458 self.output.append(opmap["ROT_FOUR"]) 459 self.position += 1 460 461 def call_function(self, count): 462 self.output.append(opmap["CALL_FUNCTION"]) 463 self.position += 1 464 self._write_value(count) 465 self.update_stack_depth(-count) 466 467 def call_function_var(self, count): 468 self.output.append(opmap["CALL_FUNCTION_VAR"]) 469 self.position += 1 470 self._write_value(count) 471 self.update_stack_depth(-count-1) 472 473 def binary_subscr(self): 474 self.output.append(opmap["BINARY_SUBSCR"]) 475 self.position += 1 476 self.update_stack_depth(-1) 477 478 def binary_add(self): 479 self.output.append(opmap["BINARY_ADD"]) 480 self.position += 1 481 self.update_stack_depth(-1) 482 483 def binary_divide(self): 484 self.output.append(opmap["BINARY_DIVIDE"]) 485 self.position += 1 486 self.update_stack_depth(-1) 487 488 def binary_multiply(self): 489 self.output.append(opmap["BINARY_MULTIPLY"]) 490 self.position += 1 491 self.update_stack_depth(-1) 492 493 def binary_modulo(self): 494 self.output.append(opmap["BINARY_MODULO"]) 495 self.position += 1 496 self.update_stack_depth(-1) 497 498 def binary_subtract(self): 499 self.output.append(opmap["BINARY_SUBTRACT"]) 500 self.position += 1 501 self.update_stack_depth(-1) 502 503 def binary_and(self): 504 self.output.append(opmap["BINARY_AND"]) 505 self.position += 1 506 self.update_stack_depth(-1) 507 508 def binary_or(self): 509 self.output.append(opmap["BINARY_XOR"]) 510 self.position += 1 511 self.update_stack_depth(-1) 512 513 def binary_lshift(self): 514 self.output.append(opmap["BINARY_LSHIFT"]) 515 self.position += 1 516 self.update_stack_depth(-1) 517 518 def binary_rshift(self): 519 self.output.append(opmap["BINARY_RSHIFT"]) 520 self.position += 1 521 self.update_stack_depth(-1) 522 523 def binary_xor(self): 524 self.output.append(opmap["BINARY_XOR"]) 525 self.position += 1 526 self.update_stack_depth(-1) 527 528 def store_subscr(self): 529 self.output.append(opmap["STORE_SUBSCR"]) 530 self.position += 1 531 self.update_stack_depth(-3) 532 533 def unary_negative(self): 534 self.output.append(opmap["UNARY_NEGATIVE"]) 535 self.position += 1 536 537 def slice_0(self): 538 self.output.append(opmap["SLICE+0"]) 539 self.position += 1 540 541 def slice_1(self): 542 self.output.append(opmap["SLICE+1"]) 543 self.position += 1 544 545 def compare_op(self, op): 546 self.output.append(opmap["COMPARE_OP"]) 547 self.position += 1 548 self._write_value(list(cmp_op).index(op)) 549 self.update_stack_depth(-1) 550 551 def return_value(self): 552 self.output.append(opmap["RETURN_VALUE"]) 553 self.position += 1 554 self.update_stack_depth(-1) 555 556 def raise_varargs(self, count): 557 self.output.append(opmap["RAISE_VARARGS"]) 558 self.position += 1 559 self._write_value(count) 560 561 def pop_block(self): 562 self.output.append(opmap["POP_BLOCK"]) 563 self.position += 1 564 565 def end_finally(self): 566 self.output.append(opmap["END_FINALLY"]) 567 self.position += 1 568 569 def unpack_sequence(self, count): 570 self.output.append(opmap["UNPACK_SEQUENCE"]) 571 self.position += 1 572 self._write_value(count) 573 574 # Debugging. 575 576 def print_item(self): 577 self.output.append(opmap["PRINT_ITEM"]) 578 self.position += 1 579 580 # Utility classes and functions. 581 582 class LazyDict(UserDict): 583 def __getitem__(self, key): 584 if not self.data.has_key(key): 585 # NOTE: Assume 16-bit value. 586 self.data[key] = LazyValue(2) 587 return self.data[key] 588 def __setitem__(self, key, value): 589 if self.data.has_key(key): 590 existing_value = self.data[key] 591 if isinstance(existing_value, LazyValue): 592 existing_value.set_value(value) 593 return 594 self.data[key] = value 595 596 class LazyValue: 597 def __init__(self, nvalues): 598 self.values = [] 599 for i in range(0, nvalues): 600 self.values.append(LazySubValue()) 601 def set_value(self, value): 602 # NOTE: Assume at least 16-bit value. No "filling" performed. 603 if value <= 0xffff: 604 self.values[0].set_value(value & 0xff) 605 self.values[1].set_value((value & 0xff00) >> 8) 606 else: 607 # NOTE: EXTENDED_ARG not yet supported. 608 raise ValueError, value 609 def get_value(self): 610 value = 0 611 values = self.values[:] 612 for i in range(0, len(values)): 613 value = (value << 8) + values.pop().value 614 return value 615 616 class LazySubValue: 617 def __init__(self): 618 self.value = 0 619 def set_value(self, value): 620 self.value = value 621 622 def signed(value, limit): 623 624 """ 625 Return the signed integer from the unsigned 'value', where 'limit' (a value 626 one greater than the highest possible positive integer) is used to determine 627 whether a negative or positive result is produced. 628 """ 629 630 d, r = divmod(value, limit) 631 if d == 1: 632 mask = limit * 2 - 1 633 return -1 - (value ^ mask) 634 else: 635 return value 636 637 def signed2(value): 638 return signed(value, 0x8000) 639 640 def signed4(value): 641 return signed(value, 0x80000000) 642 643 def load_class_name(class_file, full_class_name, program): 644 this_class_name = str(class_file.this_class.get_python_name()) 645 this_class_parts = this_class_name.split(".") 646 class_parts = full_class_name.split(".") 647 648 # Only use the full path if different from this class's path. 649 650 if class_parts[:-1] != this_class_parts[:-1]: 651 program.use_external_name(full_class_name) 652 program.load_global(class_parts[0]) 653 for class_part in class_parts[1:]: 654 program.load_attr(class_part) # Stack: classref 655 else: 656 program.load_global(class_parts[-1]) 657 658 # Bytecode conversion. 659 660 class BytecodeReader: 661 662 "A generic Java bytecode reader." 663 664 def __init__(self, class_file): 665 666 """ 667 Initialise the reader with a 'class_file' containing essential 668 information for any bytecode inspection activity. 669 """ 670 671 self.class_file = class_file 672 self.position_mapping = LazyDict() 673 674 def process(self, method, program): 675 676 """ 677 Process the given 'method' (obtained from the class file), using the 678 given 'program' to write translated Python bytecode instructions. 679 """ 680 681 self.java_position = 0 682 self.in_finally = 0 683 self.method = method 684 685 # NOTE: Potentially unreliable way of getting necessary information. 686 687 code, exception_table = None, None 688 for attribute in method.attributes: 689 if isinstance(attribute, classfile.CodeAttributeInfo): 690 code, exception_table = attribute.code, attribute.exception_table 691 break 692 693 # Where no code was found, write a very simple placeholder routine. 694 # This is useful for interfaces and abstract classes. 695 # NOTE: Assess the correctness of doing this. An exception should really 696 # NOTE: be raised instead. 697 698 if code is None: 699 program.load_const(None) 700 program.return_value() 701 return 702 703 # Produce a structure which permits fast access to exception details. 704 705 exception_block_start = {} 706 exception_block_end = {} 707 exception_block_handler = {} 708 reversed_exception_table = exception_table[:] 709 reversed_exception_table.reverse() 710 711 # Later entries have wider coverage than earlier entries. 712 713 for exception in reversed_exception_table: 714 715 # Index start positions. 716 717 if not exception_block_start.has_key(exception.start_pc): 718 exception_block_start[exception.start_pc] = [] 719 exception_block_start[exception.start_pc].append(exception) 720 721 # Index end positions. 722 723 if not exception_block_end.has_key(exception.end_pc): 724 exception_block_end[exception.end_pc] = [] 725 exception_block_end[exception.end_pc].append(exception) 726 727 # Index handler positions. 728 729 if not exception_block_handler.has_key(exception.handler_pc): 730 exception_block_handler[exception.handler_pc] = [] 731 exception_block_handler[exception.handler_pc].append(exception) 732 733 # Process each instruction in the code. 734 735 while self.java_position < len(code): 736 self.position_mapping[self.java_position] = program.position 737 738 # Insert exception handling constructs. 739 740 block_starts = exception_block_start.get(self.java_position, []) 741 for exception in block_starts: 742 743 # Note that the absolute position is used. 744 745 if exception.catch_type == 0: 746 program.setup_finally(self.position_mapping[exception.handler_pc]) 747 else: 748 program.setup_except(self.position_mapping[exception.handler_pc]) 749 750 if block_starts: 751 self.in_finally = 0 752 753 # Insert exception handler details. 754 # NOTE: Ensure that pop_block is reachable by possibly inserting it at the start of finally handlers. 755 # NOTE: Insert a check for the correct exception at the start of each handler. 756 757 for exception in exception_block_handler.get(self.java_position, []): 758 program.end_exception() 759 if exception.catch_type == 0: 760 self.in_finally = 1 761 else: 762 program.start_handler(self.class_file.constants[exception.catch_type - 1].get_python_name(), self.class_file) 763 764 # Process the bytecode at the current position. 765 766 bytecode = ord(code[self.java_position]) 767 mnemonic, number_of_arguments = self.java_bytecodes[bytecode] 768 number_of_arguments = self.process_bytecode(mnemonic, number_of_arguments, code, program) 769 next_java_position = self.java_position + 1 + number_of_arguments 770 771 # Insert exception block end details. 772 773 for exception in exception_block_end.get(next_java_position, []): 774 775 # NOTE: Insert jump beyond handlers. 776 # NOTE: program.jump_forward/absolute(...) 777 # NOTE: Insert end finally at end of handlers as well as where "ret" occurs. 778 779 if exception.catch_type != 0: 780 program.pop_block() 781 782 # Only advance the JVM position after sneaking in extra Python 783 # instructions. 784 785 self.java_position = next_java_position 786 787 def process_bytecode(self, mnemonic, number_of_arguments, code, program): 788 789 """ 790 Process a bytecode instruction with the given 'mnemonic' and 791 'number_of_arguments'. The 'code' parameter contains the full method 792 code so that argument data can be inspected. The 'program' parameter is 793 used to produce a Python translation of the instruction. 794 """ 795 796 if number_of_arguments is not None: 797 arguments = [] 798 for j in range(0, number_of_arguments): 799 arguments.append(ord(code[self.java_position + 1 + j])) 800 801 # Call the handler. 802 803 getattr(self, mnemonic)(arguments, program) 804 return number_of_arguments 805 else: 806 # Call the handler. 807 808 return getattr(self, mnemonic)(code[self.java_position+1:], program) 809 810 java_bytecodes = { 811 # code : (mnemonic, number of following bytes, change in stack) 812 0 : ("nop", 0), 813 1 : ("aconst_null", 0), 814 2 : ("iconst_m1", 0), 815 3 : ("iconst_0", 0), 816 4 : ("iconst_1", 0), 817 5 : ("iconst_2", 0), 818 6 : ("iconst_3", 0), 819 7 : ("iconst_4", 0), 820 8 : ("iconst_5", 0), 821 9 : ("lconst_0", 0), 822 10 : ("lconst_1", 0), 823 11 : ("fconst_0", 0), 824 12 : ("fconst_1", 0), 825 13 : ("fconst_2", 0), 826 14 : ("dconst_0", 0), 827 15 : ("dconst_1", 0), 828 16 : ("bipush", 1), 829 17 : ("sipush", 2), 830 18 : ("ldc", 1), 831 19 : ("ldc_w", 2), 832 20 : ("ldc2_w", 2), 833 21 : ("iload", 1), 834 22 : ("lload", 1), 835 23 : ("fload", 1), 836 24 : ("dload", 1), 837 25 : ("aload", 1), 838 26 : ("iload_0", 0), 839 27 : ("iload_1", 0), 840 28 : ("iload_2", 0), 841 29 : ("iload_3", 0), 842 30 : ("lload_0", 0), 843 31 : ("lload_1", 0), 844 32 : ("lload_2", 0), 845 33 : ("lload_3", 0), 846 34 : ("fload_0", 0), 847 35 : ("fload_1", 0), 848 36 : ("fload_2", 0), 849 37 : ("fload_3", 0), 850 38 : ("dload_0", 0), 851 39 : ("dload_1", 0), 852 40 : ("dload_2", 0), 853 41 : ("dload_3", 0), 854 42 : ("aload_0", 0), 855 43 : ("aload_1", 0), 856 44 : ("aload_2", 0), 857 45 : ("aload_3", 0), 858 46 : ("iaload", 0), 859 47 : ("laload", 0), 860 48 : ("faload", 0), 861 49 : ("daload", 0), 862 50 : ("aaload", 0), 863 51 : ("baload", 0), 864 52 : ("caload", 0), 865 53 : ("saload", 0), 866 54 : ("istore", 1), 867 55 : ("lstore", 1), 868 56 : ("fstore", 1), 869 57 : ("dstore", 1), 870 58 : ("astore", 1), 871 59 : ("istore_0", 0), 872 60 : ("istore_1", 0), 873 61 : ("istore_2", 0), 874 62 : ("istore_3", 0), 875 63 : ("lstore_0", 0), 876 64 : ("lstore_1", 0), 877 65 : ("lstore_2", 0), 878 66 : ("lstore_3", 0), 879 67 : ("fstore_0", 0), 880 68 : ("fstore_1", 0), 881 69 : ("fstore_2", 0), 882 70 : ("fstore_3", 0), 883 71 : ("dstore_0", 0), 884 72 : ("dstore_1", 0), 885 73 : ("dstore_2", 0), 886 74 : ("dstore_3", 0), 887 75 : ("astore_0", 0), 888 76 : ("astore_1", 0), 889 77 : ("astore_2", 0), 890 78 : ("astore_3", 0), 891 79 : ("iastore", 0), 892 80 : ("lastore", 0), 893 81 : ("fastore", 0), 894 82 : ("dastore", 0), 895 83 : ("aastore", 0), 896 84 : ("bastore", 0), 897 85 : ("castore", 0), 898 86 : ("sastore", 0), 899 87 : ("pop", 0), 900 88 : ("pop2", 0), 901 89 : ("dup", 0), 902 90 : ("dup_x1", 0), 903 91 : ("dup_x2", 0), 904 92 : ("dup2", 0), 905 93 : ("dup2_x1", 0), 906 94 : ("dup2_x2", 0), 907 95 : ("swap", 0), 908 96 : ("iadd", 0), 909 97 : ("ladd", 0), 910 98 : ("fadd", 0), 911 99 : ("dadd", 0), 912 100 : ("isub", 0), 913 101 : ("lsub", 0), 914 102 : ("fsub", 0), 915 103 : ("dsub", 0), 916 104 : ("imul", 0), 917 105 : ("lmul", 0), 918 106 : ("fmul", 0), 919 107 : ("dmul", 0), 920 108 : ("idiv", 0), 921 109 : ("ldiv", 0), 922 110 : ("fdiv", 0), 923 111 : ("ddiv", 0), 924 112 : ("irem", 0), 925 113 : ("lrem", 0), 926 114 : ("frem", 0), 927 115 : ("drem", 0), 928 116 : ("ineg", 0), 929 117 : ("lneg", 0), 930 118 : ("fneg", 0), 931 119 : ("dneg", 0), 932 120 : ("ishl", 0), 933 121 : ("lshl", 0), 934 122 : ("ishr", 0), 935 123 : ("lshr", 0), 936 124 : ("iushr", 0), 937 125 : ("lushr", 0), 938 126 : ("iand", 0), 939 127 : ("land", 0), 940 128 : ("ior", 0), 941 129 : ("lor", 0), 942 130 : ("ixor", 0), 943 131 : ("lxor", 0), 944 132 : ("iinc", 2), 945 133 : ("i2l", 0), 946 134 : ("i2f", 0), 947 135 : ("i2d", 0), 948 136 : ("l2i", 0), 949 137 : ("l2f", 0), 950 138 : ("l2d", 0), 951 139 : ("f2i", 0), 952 140 : ("f2l", 0), 953 141 : ("f2d", 0), 954 142 : ("d2i", 0), 955 143 : ("d2l", 0), 956 144 : ("d2f", 0), 957 145 : ("i2b", 0), 958 146 : ("i2c", 0), 959 147 : ("i2s", 0), 960 148 : ("lcmp", 0), 961 149 : ("fcmpl", 0), 962 150 : ("fcmpg", 0), 963 151 : ("dcmpl", 0), 964 152 : ("dcmpg", 0), 965 153 : ("ifeq", 2), 966 154 : ("ifne", 2), 967 155 : ("iflt", 2), 968 156 : ("ifge", 2), 969 157 : ("ifgt", 2), 970 158 : ("ifle", 2), 971 159 : ("if_icmpeq", 2), 972 160 : ("if_icmpne", 2), 973 161 : ("if_icmplt", 2), 974 162 : ("if_icmpge", 2), 975 163 : ("if_icmpgt", 2), 976 164 : ("if_icmple", 2), 977 165 : ("if_acmpeq", 2), 978 166 : ("if_acmpne", 2), 979 167 : ("goto", 2), 980 168 : ("jsr", 2), 981 169 : ("ret", 1), 982 170 : ("tableswitch", None), # variable number of arguments 983 171 : ("lookupswitch", None), # variable number of arguments 984 172 : ("ireturn", 0), 985 173 : ("lreturn", 0), 986 174 : ("freturn", 0), 987 175 : ("dreturn", 0), 988 176 : ("areturn", 0), 989 177 : ("return_", 0), 990 178 : ("getstatic", 2), 991 179 : ("putstatic", 2), 992 180 : ("getfield", 2), 993 181 : ("putfield", 2), 994 182 : ("invokevirtual", 2), 995 183 : ("invokespecial", 2), 996 184 : ("invokestatic", 2), 997 185 : ("invokeinterface", 4), 998 187 : ("new", 2), 999 188 : ("newarray", 1), 1000 189 : ("anewarray", 2), 1001 190 : ("arraylength", 0), 1002 191 : ("athrow", 0), 1003 192 : ("checkcast", 2), 1004 193 : ("instanceof", 2), 1005 194 : ("monitorenter", 0), 1006 195 : ("monitorexit", 0), 1007 196 : ("wide", None), # 3 or 5 arguments, stack changes according to modified element 1008 197 : ("multianewarray", 3), 1009 198 : ("ifnull", 2), 1010 199 : ("ifnonnull", 2), 1011 200 : ("goto_w", 4), 1012 201 : ("jsr_w", 4), 1013 } 1014 1015 class BytecodeDisassembler(BytecodeReader): 1016 1017 "A Java bytecode disassembler." 1018 1019 bytecode_methods = [spec[0] for spec in BytecodeReader.java_bytecodes.values()] 1020 1021 def __getattr__(self, name): 1022 if name in self.bytecode_methods: 1023 print "%5s %s" % (self.java_position, name), 1024 return self.generic 1025 else: 1026 raise AttributeError, name 1027 1028 def generic(self, arguments, program): 1029 print arguments 1030 1031 def lookupswitch(self, code, program): 1032 print "%5s lookupswitch" % (self.java_position,), 1033 d, r = divmod(self.java_position + 1, 4) 1034 to_boundary = (4 - r) % 4 1035 code = code[to_boundary:] 1036 default = classfile.u4(code[0:4]) 1037 npairs = classfile.u4(code[4:8]) 1038 print default, npairs 1039 return to_boundary + 8 + npairs * 8 1040 1041 def tableswitch(self, code, program): 1042 print "%5s tableswitch" % (self.java_position,), 1043 d, r = divmod(self.java_position + 1, 4) 1044 to_boundary = (4 - r) % 4 1045 code = code[to_boundary:] 1046 default = classfile.u4(code[0:4]) 1047 low = classfile.u4(code[4:8]) 1048 high = classfile.u4(code[8:12]) 1049 print default, low, high 1050 return to_boundary + 12 + (high - low + 1) * 4 1051 1052 class BytecodeDisassemblerProgram: 1053 position = 0 1054 def setup_except(self, target): 1055 print "(setup_except %s)" % target 1056 def setup_finally(self, target): 1057 print "(setup_finally %s)" % target 1058 def end_exception(self): 1059 print "(end_exception)" 1060 def start_handler(self, exc_name, class_file): 1061 print "(start_handler %s)" % exc_name 1062 def pop_block(self): 1063 print "(pop_block)" 1064 1065 class BytecodeTranslator(BytecodeReader): 1066 1067 "A Java bytecode translator which uses a Python bytecode writer." 1068 1069 def aaload(self, arguments, program): 1070 # NOTE: No type checking performed. 1071 program.binary_subscr() 1072 1073 def aastore(self, arguments, program): 1074 # NOTE: No type checking performed. 1075 # Stack: arrayref, index, value 1076 program.rot_three() # Stack: value, arrayref, index 1077 program.store_subscr() 1078 1079 def aconst_null(self, arguments, program): 1080 program.load_const(None) 1081 1082 def aload(self, arguments, program): 1083 program.load_fast(arguments[0]) 1084 1085 def aload_0(self, arguments, program): 1086 program.load_fast(0) 1087 1088 def aload_1(self, arguments, program): 1089 program.load_fast(1) 1090 1091 def aload_2(self, arguments, program): 1092 program.load_fast(2) 1093 1094 def aload_3(self, arguments, program): 1095 program.load_fast(3) 1096 1097 def anewarray(self, arguments, program): 1098 # NOTE: Does not raise NegativeArraySizeException. 1099 # NOTE: Not using the index to type the list/array. 1100 index = (arguments[0] << 8) + arguments[1] 1101 self._newarray(program) 1102 1103 def _newarray(self, program): 1104 program.build_list(0) # Stack: count, list 1105 program.rot_two() # Stack: list, count 1106 program.setup_loop() 1107 program.load_global("range") 1108 program.load_const(0) # Stack: list, count, range, 0 1109 program.rot_three() # Stack: list, 0, count, range 1110 program.rot_three() # Stack: list, range, 0, count 1111 program.call_function(2) # Stack: list, range_list 1112 program.get_iter() # Stack: list, iter 1113 program.for_iter() # Stack: list, iter, value 1114 program.pop_top() # Stack: list, iter 1115 program.rot_two() # Stack: iter, list 1116 program.dup_top() # Stack: iter, list, list 1117 program.load_attr("append") # Stack: iter, list, append 1118 program.load_const(None) # Stack: iter, list, append, None 1119 program.call_function(1) # Stack: iter, list, None 1120 program.pop_top() # Stack: iter, list 1121 program.rot_two() # Stack: list, iter 1122 program.end_loop() # Back to for_iter above 1123 1124 def areturn(self, arguments, program): 1125 program.return_value() 1126 1127 def arraylength(self, arguments, program): 1128 program.load_global("len") # Stack: arrayref, len 1129 program.rot_two() # Stack: len, arrayref 1130 program.call_function(1) 1131 1132 def astore(self, arguments, program): 1133 program.store_fast(arguments[0]) 1134 1135 def astore_0(self, arguments, program): 1136 program.store_fast(0) 1137 1138 def astore_1(self, arguments, program): 1139 program.store_fast(1) 1140 1141 def astore_2(self, arguments, program): 1142 program.store_fast(2) 1143 1144 def astore_3(self, arguments, program): 1145 program.store_fast(3) 1146 1147 def athrow(self, arguments, program): 1148 # NOTE: NullPointerException not raised where null/None is found on the stack. 1149 # If this instruction appears in a finally handler, use end_finally instead. 1150 if self.in_finally: 1151 program.end_finally() 1152 else: 1153 # Wrap the exception in a Python exception. 1154 program.load_global("Exception") # Stack: objectref, Exception 1155 program.rot_two() # Stack: Exception, objectref 1156 program.call_function(1) # Stack: exception 1157 program.raise_varargs(1) 1158 # NOTE: This seems to put another object on the stack. 1159 1160 baload = aaload 1161 bastore = aastore 1162 1163 def bipush(self, arguments, program): 1164 program.load_const(arguments[0]) 1165 1166 caload = aaload 1167 castore = aastore 1168 1169 def checkcast(self, arguments, program): 1170 index = (arguments[0] << 8) + arguments[1] 1171 target_name = self.class_file.constants[index - 1].get_python_name() 1172 program.use_external_name(target_name) 1173 program.dup_top() # Stack: objectref, objectref 1174 program.load_const(None) # Stack: objectref, objectref, None 1175 program.compare_op("is") # Stack: objectref, result 1176 program.jump_to_label(1, "next") 1177 program.pop_top() # Stack: objectref 1178 program.dup_top() # Stack: objectref, objectref 1179 program.load_global("isinstance") # Stack: objectref, objectref, isinstance 1180 program.rot_two() # Stack: objectref, isinstance, objectref 1181 load_class_name(self.class_file, target_name, program) 1182 program.call_function(2) # Stack: objectref, result 1183 program.jump_to_label(1, "next") 1184 program.pop_top() # Stack: objectref 1185 program.pop_top() # Stack: 1186 program.use_external_name("java.lang.ClassCastException") 1187 load_class_name(self.class_file, "java.lang.ClassCastException", program) 1188 program.call_function(0) # Stack: exception 1189 # Wrap the exception in a Python exception. 1190 program.load_global("Exception") # Stack: exception, Exception 1191 program.rot_two() # Stack: Exception, exception 1192 program.call_function(1) # Stack: exception 1193 program.raise_varargs(1) 1194 # NOTE: This seems to put another object on the stack. 1195 program.start_label("next") 1196 program.pop_top() # Stack: objectref 1197 1198 def d2f(self, arguments, program): 1199 pass 1200 1201 def d2i(self, arguments, program): 1202 program.load_global("int") # Stack: value, int 1203 program.rot_two() # Stack: int, value 1204 program.call_function(1) # Stack: result 1205 1206 d2l = d2i # Preserving Java semantics 1207 1208 def dadd(self, arguments, program): 1209 # NOTE: No type checking performed. 1210 program.binary_add() 1211 1212 daload = aaload 1213 dastore = aastore 1214 1215 def dcmpg(self, arguments, program): 1216 # NOTE: No type checking performed. 1217 program.compare_op(">") 1218 1219 def dcmpl(self, arguments, program): 1220 # NOTE: No type checking performed. 1221 program.compare_op("<") 1222 1223 def dconst_0(self, arguments, program): 1224 program.load_const(0.0) 1225 1226 def dconst_1(self, arguments, program): 1227 program.load_const(1.0) 1228 1229 def ddiv(self, arguments, program): 1230 # NOTE: No type checking performed. 1231 program.binary_divide() 1232 1233 dload = aload 1234 dload_0 = aload_0 1235 dload_1 = aload_1 1236 dload_2 = aload_2 1237 dload_3 = aload_3 1238 1239 def dmul(self, arguments, program): 1240 # NOTE: No type checking performed. 1241 program.binary_multiply() 1242 1243 def dneg(self, arguments, program): 1244 # NOTE: No type checking performed. 1245 program.unary_negative() 1246 1247 def drem(self, arguments, program): 1248 # NOTE: No type checking performed. 1249 program.binary_modulo() 1250 1251 dreturn = areturn 1252 dstore = astore 1253 dstore_0 = astore_0 1254 dstore_1 = astore_1 1255 dstore_2 = astore_2 1256 dstore_3 = astore_3 1257 1258 def dsub(self, arguments, program): 1259 # NOTE: No type checking performed. 1260 program.binary_subtract() 1261 1262 def dup(self, arguments, program): 1263 program.dup_top() 1264 1265 def dup_x1(self, arguments, program): 1266 # Ignoring computational type categories. 1267 program.dup_top() 1268 program.rot_three() 1269 1270 def dup_x2(self, arguments, program): 1271 # Ignoring computational type categories. 1272 program.dup_top() 1273 program.rot_four() 1274 1275 dup2 = dup # Ignoring computational type categories 1276 dup2_x1 = dup_x1 # Ignoring computational type categories 1277 dup2_x2 = dup_x2 # Ignoring computational type categories 1278 1279 def f2d(self, arguments, program): 1280 pass # Preserving Java semantics 1281 1282 def f2i(self, arguments, program): 1283 program.load_global("int") # Stack: value, int 1284 program.rot_two() # Stack: int, value 1285 program.call_function(1) # Stack: result 1286 1287 f2l = f2i # Preserving Java semantics 1288 fadd = dadd 1289 faload = daload 1290 fastore = dastore 1291 fcmpg = dcmpg 1292 fcmpl = dcmpl 1293 fconst_0 = dconst_0 1294 fconst_1 = dconst_1 1295 1296 def fconst_2(self, arguments, program): 1297 program.load_const(2.0) 1298 1299 fdiv = ddiv 1300 fload = dload 1301 fload_0 = dload_0 1302 fload_1 = dload_1 1303 fload_2 = dload_2 1304 fload_3 = dload_3 1305 fmul = dmul 1306 fneg = dneg 1307 frem = drem 1308 freturn = dreturn 1309 fstore = dstore 1310 fstore_0 = dstore_0 1311 fstore_1 = dstore_1 1312 fstore_2 = dstore_2 1313 fstore_3 = dstore_3 1314 fsub = dsub 1315 1316 def getfield(self, arguments, program): 1317 index = (arguments[0] << 8) + arguments[1] 1318 target_name = self.class_file.constants[index - 1].get_python_name() 1319 # NOTE: Using the string version of the name which may contain incompatible characters. 1320 program.load_attr(str(target_name)) 1321 1322 def getstatic(self, arguments, program): 1323 index = (arguments[0] << 8) + arguments[1] 1324 target = self.class_file.constants[index - 1] 1325 target_name = target.get_python_name() 1326 1327 # Get the class name instead of the fully qualified name. 1328 1329 full_class_name = target.get_class().get_python_name() 1330 program.use_external_name(full_class_name) 1331 load_class_name(self.class_file, full_class_name, program) 1332 # NOTE: Using the string version of the name which may contain incompatible characters. 1333 program.load_attr(str(target_name)) 1334 1335 def goto(self, arguments, program): 1336 offset = signed2((arguments[0] << 8) + arguments[1]) 1337 java_absolute = self.java_position + offset 1338 program.jump_absolute(self.position_mapping[java_absolute]) 1339 1340 def goto_w(self, arguments, program): 1341 offset = signed4((arguments[0] << 24) + (arguments[1] << 16) + (arguments[2] << 8) + arguments[3]) 1342 java_absolute = self.java_position + offset 1343 program.jump_absolute(self.position_mapping[java_absolute]) 1344 1345 def i2b(self, arguments, program): 1346 pass 1347 1348 def i2c(self, arguments, program): 1349 pass 1350 1351 def i2d(self, arguments, program): 1352 program.load_global("float") # Stack: value, float 1353 program.rot_two() # Stack: float, value 1354 program.call_function(1) # Stack: result 1355 1356 i2f = i2d # Not distinguishing between float and double 1357 1358 def i2l(self, arguments, program): 1359 pass # Preserving Java semantics 1360 1361 def i2s(self, arguments, program): 1362 pass # Not distinguishing between int and short 1363 1364 iadd = fadd 1365 iaload = faload 1366 1367 def iand(self, arguments, program): 1368 # NOTE: No type checking performed. 1369 program.binary_and() 1370 1371 iastore = fastore 1372 1373 def iconst_m1(self, arguments, program): 1374 program.load_const(-1) 1375 1376 def iconst_0(self, arguments, program): 1377 program.load_const(0) 1378 1379 def iconst_1(self, arguments, program): 1380 program.load_const(1) 1381 1382 def iconst_2(self, arguments, program): 1383 program.load_const(2) 1384 1385 def iconst_3(self, arguments, program): 1386 program.load_const(3) 1387 1388 def iconst_4(self, arguments, program): 1389 program.load_const(4) 1390 1391 def iconst_5(self, arguments, program): 1392 program.load_const(5) 1393 1394 idiv = fdiv 1395 1396 def _if_xcmpx(self, arguments, program, op): 1397 offset = signed2((arguments[0] << 8) + arguments[1]) 1398 java_absolute = self.java_position + offset 1399 program.compare_op(op) 1400 program.jump_to_label(0, "next") # skip if false 1401 program.pop_top() 1402 program.jump_absolute(self.position_mapping[java_absolute]) 1403 program.start_label("next") 1404 program.pop_top() 1405 1406 def if_acmpeq(self, arguments, program): 1407 # NOTE: No type checking performed. 1408 self._if_xcmpx(arguments, program, "is") 1409 1410 def if_acmpne(self, arguments, program): 1411 # NOTE: No type checking performed. 1412 self._if_xcmpx(arguments, program, "is not") 1413 1414 def if_icmpeq(self, arguments, program): 1415 # NOTE: No type checking performed. 1416 self._if_xcmpx(arguments, program, "==") 1417 1418 def if_icmpne(self, arguments, program): 1419 # NOTE: No type checking performed. 1420 self._if_xcmpx(arguments, program, "!=") 1421 1422 def if_icmplt(self, arguments, program): 1423 # NOTE: No type checking performed. 1424 self._if_xcmpx(arguments, program, "<") 1425 1426 def if_icmpge(self, arguments, program): 1427 # NOTE: No type checking performed. 1428 self._if_xcmpx(arguments, program, ">=") 1429 1430 def if_icmpgt(self, arguments, program): 1431 # NOTE: No type checking performed. 1432 self._if_xcmpx(arguments, program, ">") 1433 1434 def if_icmple(self, arguments, program): 1435 # NOTE: No type checking performed. 1436 self._if_xcmpx(arguments, program, "<=") 1437 1438 def ifeq(self, arguments, program): 1439 # NOTE: No type checking performed. 1440 program.load_const(0) 1441 self._if_xcmpx(arguments, program, "==") 1442 1443 def ifne(self, arguments, program): 1444 # NOTE: No type checking performed. 1445 program.load_const(0) 1446 self._if_xcmpx(arguments, program, "!=") 1447 1448 def iflt(self, arguments, program): 1449 # NOTE: No type checking performed. 1450 program.load_const(0) 1451 self._if_xcmpx(arguments, program, "<") 1452 1453 def ifge(self, arguments, program): 1454 # NOTE: No type checking performed. 1455 program.load_const(0) 1456 self._if_xcmpx(arguments, program, ">=") 1457 1458 def ifgt(self, arguments, program): 1459 # NOTE: No type checking performed. 1460 program.load_const(0) 1461 self._if_xcmpx(arguments, program, ">") 1462 1463 def ifle(self, arguments, program): 1464 # NOTE: No type checking performed. 1465 program.load_const(0) 1466 self._if_xcmpx(arguments, program, "<=") 1467 1468 def ifnonnull(self, arguments, program): 1469 # NOTE: No type checking performed. 1470 program.load_const(None) 1471 self._if_xcmpx(arguments, program, "is not") 1472 1473 def ifnull(self, arguments, program): 1474 # NOTE: No type checking performed. 1475 program.load_const(None) 1476 self._if_xcmpx(arguments, program, "is") 1477 1478 def iinc(self, arguments, program): 1479 # NOTE: No type checking performed. 1480 program.load_fast(arguments[0]) 1481 program.load_const(arguments[1]) 1482 program.binary_add() 1483 program.store_fast(arguments[0]) 1484 1485 iload = fload 1486 iload_0 = fload_0 1487 iload_1 = fload_1 1488 iload_2 = fload_2 1489 iload_3 = fload_3 1490 imul = fmul 1491 ineg = fneg 1492 1493 def instanceof(self, arguments, program): 1494 index = (arguments[0] << 8) + arguments[1] 1495 target_name = self.class_file.constants[index - 1].get_python_name() 1496 program.use_external_name(target_name) 1497 program.load_global("isinstance") # Stack: objectref, isinstance 1498 program.rot_two() # Stack: isinstance, objectref 1499 load_class_name(self.class_file, target_name, program) 1500 program.call_function(2) # Stack: result 1501 1502 def _invoke(self, target_name, program): 1503 # NOTE: Using the string version of the name which may contain incompatible characters. 1504 program.load_attr(str(target_name)) # Stack: tuple, method 1505 program.rot_two() # Stack: method, tuple 1506 program.call_function_var(0) # Stack: result 1507 1508 def invokeinterface(self, arguments, program): 1509 # NOTE: This implementation does not perform the necessary checks for 1510 # NOTE: signature-based polymorphism. 1511 # NOTE: Java rules not specifically obeyed. 1512 index = (arguments[0] << 8) + arguments[1] 1513 # NOTE: "count" == nargs + 1, apparently. 1514 count = arguments[2] - 1 1515 target_name = self.class_file.constants[index - 1].get_python_name() 1516 # Stack: objectref, arg1, arg2, ... 1517 program.build_tuple(count) # Stack: objectref, tuple 1518 program.rot_two() # Stack: tuple, objectref 1519 # NOTE: The interface information is not used to discover the correct 1520 # NOTE: method. 1521 self._invoke(target_name, program) 1522 1523 def invokespecial(self, arguments, program): 1524 # NOTE: This implementation does not perform the necessary checks for 1525 # NOTE: signature-based polymorphism. 1526 # NOTE: Java rules not specifically obeyed. 1527 index = (arguments[0] << 8) + arguments[1] 1528 target = self.class_file.constants[index - 1] 1529 original_name = target.get_name() 1530 target_name = target.get_python_name() 1531 1532 # Get the number of parameters from the descriptor. 1533 1534 count = len(target.get_descriptor()[0]) 1535 1536 # First, we build a tuple of the reference and arguments. 1537 1538 program.build_tuple(count + 1) # Stack: tuple 1539 1540 # Get the class name instead of the fully qualified name. 1541 # NOTE: Not bothering with Object initialisation. 1542 1543 full_class_name = target.get_class().get_python_name() 1544 if full_class_name not in ("java.lang.Object", "java.lang.Exception"): 1545 program.use_external_name(full_class_name) 1546 load_class_name(self.class_file, full_class_name, program) 1547 self._invoke(target_name, program) 1548 1549 # Remove Python None return value. 1550 1551 if str(original_name) == "<init>": 1552 program.pop_top() 1553 1554 def invokestatic(self, arguments, program): 1555 # NOTE: This implementation does not perform the necessary checks for 1556 # NOTE: signature-based polymorphism. 1557 # NOTE: Java rules not specifically obeyed. 1558 index = (arguments[0] << 8) + arguments[1] 1559 target = self.class_file.constants[index - 1] 1560 target_name = target.get_python_name() 1561 1562 # Get the number of parameters from the descriptor. 1563 1564 count = len(target.get_descriptor()[0]) 1565 1566 # Stack: arg1, arg2, ... 1567 1568 program.build_tuple(count) # Stack: tuple 1569 1570 # Use the class to provide access to static methods. 1571 # Get the class name instead of the fully qualified name. 1572 1573 full_class_name = target.get_class().get_python_name() 1574 if full_class_name not in ("java.lang.Object", "java.lang.Exception"): 1575 program.use_external_name(full_class_name) 1576 load_class_name(self.class_file, full_class_name, program) 1577 self._invoke(target_name, program) 1578 1579 def invokevirtual (self, arguments, program): 1580 # NOTE: This implementation does not perform the necessary checks for 1581 # NOTE: signature-based polymorphism. 1582 # NOTE: Java rules not specifically obeyed. 1583 index = (arguments[0] << 8) + arguments[1] 1584 target = self.class_file.constants[index - 1] 1585 target_name = target.get_python_name() 1586 # Get the number of parameters from the descriptor. 1587 count = len(target.get_descriptor()[0]) 1588 # Stack: objectref, arg1, arg2, ... 1589 program.build_tuple(count) # Stack: objectref, tuple 1590 program.rot_two() # Stack: tuple, objectref 1591 self._invoke(target_name, program) 1592 1593 def ior(self, arguments, program): 1594 # NOTE: No type checking performed. 1595 program.binary_or() 1596 1597 irem = frem 1598 ireturn = freturn 1599 1600 def ishl(self, arguments, program): 1601 # NOTE: No type checking performed. 1602 # NOTE: Not verified. 1603 program.binary_lshift() 1604 1605 def ishr(self, arguments, program): 1606 # NOTE: No type checking performed. 1607 # NOTE: Not verified. 1608 program.binary_rshift() 1609 1610 istore = fstore 1611 istore_0 = fstore_0 1612 istore_1 = fstore_1 1613 istore_2 = fstore_2 1614 istore_3 = fstore_3 1615 isub = fsub 1616 iushr = ishr # Ignoring distinctions between arithmetic and logical shifts 1617 1618 def ixor(self, arguments, program): 1619 # NOTE: No type checking performed. 1620 program.binary_xor() 1621 1622 def jsr(self, arguments, program): 1623 offset = signed2((arguments[0] << 8) + arguments[1]) 1624 java_absolute = self.java_position + offset 1625 # Store the address of the next instruction. 1626 program.load_const_ret(self.position_mapping[self.java_position + 3]) 1627 program.jump_absolute(self.position_mapping[java_absolute]) 1628 1629 def jsr_w(self, arguments, program): 1630 offset = signed4((arguments[0] << 24) + (arguments[1] << 16) + (arguments[2] << 8) + arguments[3]) 1631 java_absolute = self.java_position + offset 1632 # Store the address of the next instruction. 1633 program.load_const_ret(self.position_mapping[self.java_position + 5]) 1634 program.jump_absolute(self.position_mapping[java_absolute]) 1635 1636 l2d = i2d 1637 l2f = i2f 1638 1639 def l2i(self, arguments, program): 1640 pass # Preserving Java semantics 1641 1642 ladd = iadd 1643 laload = iaload 1644 land = iand 1645 lastore = iastore 1646 1647 def lcmp(self, arguments, program): 1648 # NOTE: No type checking performed. 1649 program.dup_topx(2) # Stack: value1, value2, value1, value2 1650 program.compare_op(">") # Stack: value1, value2, result 1651 program.jump_to_label(0, "equals") 1652 # True - produce result and branch. 1653 program.pop_top() # Stack: value1, value2 1654 program.pop_top() # Stack: value1 1655 program.pop_top() # Stack: 1656 program.load_const(1) # Stack: 1 1657 program.jump_to_label(None, "next") 1658 # False - test equality. 1659 program.start_label("equals") 1660 program.pop_top() # Stack: value1, value2 1661 program.dup_topx(2) # Stack: value1, value2, value1, value2 1662 program.compare_op("==") # Stack: value1, value2, result 1663 program.jump_to_label(0, "less") 1664 # True - produce result and branch. 1665 program.pop_top() # Stack: value1, value2 1666 program.pop_top() # Stack: value1 1667 program.pop_top() # Stack: 1668 program.load_const(0) # Stack: 0 1669 program.jump_to_label(None, "next") 1670 # False - produce result. 1671 program.start_label("less") 1672 program.pop_top() # Stack: value1, value2 1673 program.pop_top() # Stack: value1 1674 program.pop_top() # Stack: 1675 program.load_const(-1) # Stack: -1 1676 program.start_label("next") 1677 1678 lconst_0 = iconst_0 1679 lconst_1 = iconst_1 1680 1681 def ldc(self, arguments, program): 1682 const = self.class_file.constants[arguments[0] - 1] 1683 if isinstance(const, classfile.StringInfo): 1684 program.use_external_name("java.lang.String") 1685 program.load_global("java") 1686 program.load_attr("lang") 1687 program.load_attr("String") 1688 program.load_const(const.get_value()) 1689 program.call_function(1) 1690 else: 1691 program.load_const(const.get_value()) 1692 1693 def ldc_w(self, arguments, program): 1694 const = self.class_file.constants[(arguments[0] << 8) + arguments[1] - 1] 1695 if isinstance(const, classfile.StringInfo): 1696 program.use_external_name("java.lang.String") 1697 program.load_global("java") 1698 program.load_attr("lang") 1699 program.load_attr("String") 1700 program.load_const(const.get_value()) 1701 program.call_function(1) 1702 else: 1703 program.load_const(const.get_value()) 1704 1705 ldc2_w = ldc_w 1706 ldiv = idiv 1707 lload = iload 1708 lload_0 = iload_0 1709 lload_1 = iload_1 1710 lload_2 = iload_2 1711 lload_3 = iload_3 1712 lmul = imul 1713 lneg = ineg 1714 1715 def lookupswitch(self, code, program): 1716 1717 # Find the offset to the next 4 byte boundary in the code. 1718 1719 d, r = divmod(self.java_position + 1, 4) 1720 to_boundary = (4 - r) % 4 1721 1722 # Get the pertinent arguments. 1723 1724 code = code[to_boundary:] 1725 default = classfile.u4(code[0:4]) 1726 npairs = classfile.u4(code[4:8]) 1727 1728 # Process the pairs. 1729 # NOTE: This is not the most optimal implementation. 1730 1731 pair_index = 8 1732 for pair in range(0, npairs): 1733 match = classfile.u4(code[pair_index:pair_index+4]) 1734 offset = classfile.s4(code[pair_index+4:pair_index+8]) 1735 # Calculate the branch target. 1736 java_absolute = self.java_position + offset 1737 # Generate branching code. 1738 program.dup_top() # Stack: key, key 1739 program.load_const(match) # Stack: key, key, match 1740 program.compare_op("==") # Stack: key, result 1741 program.jump_to_label(0, "end") 1742 program.pop_top() # Stack: key 1743 program.pop_top() # Stack: 1744 program.jump_absolute(self.position_mapping[java_absolute]) 1745 # Generate the label for the end of the branching code. 1746 program.start_label("end") 1747 program.pop_top() # Stack: key 1748 # Update the index. 1749 pair_index += 4 1750 1751 # Generate the default. 1752 1753 java_absolute = self.java_position + default 1754 program.jump_absolute(self.position_mapping[java_absolute]) 1755 return pair_index + to_boundary 1756 1757 lor = ior 1758 lrem = irem 1759 lreturn = ireturn 1760 lshl = ishl 1761 lshr = ishr 1762 lstore = istore 1763 lstore_0 = istore_0 1764 lstore_1 = istore_1 1765 lstore_2 = istore_2 1766 lstore_3 = istore_3 1767 lsub = isub 1768 lushr = iushr 1769 lxor = ixor 1770 1771 def monitorenter(self, arguments, program): 1772 # NOTE: To be implemented. 1773 pass 1774 1775 def monitorexit(self, arguments, program): 1776 # NOTE: To be implemented. 1777 pass 1778 1779 def multianewarray(self, arguments, program): 1780 index = (arguments[0] << 8) + arguments[1] 1781 dimensions = arguments[2] 1782 # Stack: count1, ..., countN-1, countN 1783 self._newarray(program) # Stack: count1, ..., countN-1, list 1784 for dimension in range(1, dimensions): 1785 program.rot_two() # Stack: count1, ..., list, countN-1 1786 program.build_list(0) # Stack: count1, ..., list, countN-1, new-list 1787 program.rot_three() # Stack: count1, ..., new-list, list, countN-1 1788 program.setup_loop() 1789 program.load_const(0) # Stack: count1, ..., new-list, list, countN-1, 0 1790 program.rot_two() # Stack: count1, ..., new-list, list, 0, countN-1 1791 program.load_global("range") # Stack: count1, ..., new-list, list, 0, countN-1, range 1792 program.rot_three() # Stack: count1, ..., new-list, list, range, 0, countN-1 1793 program.call_function(2) # Stack: count1, ..., new-list, list, range-list 1794 program.get_iter() # Stack: count1, ..., new-list, list, iter 1795 program.for_iter() # Stack: count1, ..., new-list, list, iter, value 1796 program.pop_top() # Stack: count1, ..., new-list, list, iter 1797 program.rot_three() # Stack: count1, ..., iter, new-list, list 1798 program.slice_0() # Stack: count1, ..., iter, new-list, list[:] 1799 program.dup_top() # Stack: count1, ..., iter, new-list, list[:], list[:] 1800 program.rot_three() # Stack: count1, ..., iter, list[:], new-list, list[:] 1801 program.rot_two() # Stack: count1, ..., iter, list[:], list[:], new-list 1802 program.dup_top() # Stack: count1, ..., iter, list[:], list[:], new-list, new-list 1803 program.load_attr("append") # Stack: count1, ..., iter, list[:], list[:], new-list, append 1804 program.rot_three() # Stack: count1, ..., iter, list[:], append, list[:], new-list 1805 program.rot_three() # Stack: count1, ..., iter, list[:], new-list, append, list[:] 1806 program.call_function(1) # Stack: count1, ..., iter, list[:], new-list, None 1807 program.pop_top() # Stack: count1, ..., iter, list[:], new-list 1808 program.rot_two() # Stack: count1, ..., iter, new-list, list[:] 1809 program.rot_three() # Stack: count1, ..., list[:], iter, new-list 1810 program.rot_three() # Stack: count1, ..., new-list, list[:], iter 1811 program.end_loop() # Stack: count1, ..., new-list, list[:], iter 1812 program.pop_top() # Stack: count1, ..., new-list 1813 1814 def new(self, arguments, program): 1815 # This operation is considered to be the same as the calling of the 1816 # initialisation method of the given class with no arguments. 1817 1818 index = (arguments[0] << 8) + arguments[1] 1819 target_name = self.class_file.constants[index - 1].get_python_name() 1820 program.use_external_name(target_name) 1821 1822 # NOTE: Using the string version of the name which may contain incompatible characters. 1823 program.load_global("object") 1824 program.load_attr("__new__") 1825 load_class_name(self.class_file, target_name, program) 1826 program.call_function(1) 1827 1828 def newarray(self, arguments, program): 1829 # NOTE: Does not raise NegativeArraySizeException. 1830 # NOTE: Not using the arguments to type the list/array. 1831 self._newarray(program) 1832 1833 def nop(self, arguments, program): 1834 pass 1835 1836 def pop(self, arguments, program): 1837 program.pop_top() 1838 1839 pop2 = pop # ignoring Java stack value distinctions 1840 1841 def putfield(self, arguments, program): 1842 index = (arguments[0] << 8) + arguments[1] 1843 target_name = self.class_file.constants[index - 1].get_python_name() 1844 program.rot_two() 1845 # NOTE: Using the string version of the name which may contain incompatible characters. 1846 program.store_attr(str(target_name)) 1847 1848 def putstatic(self, arguments, program): 1849 index = (arguments[0] << 8) + arguments[1] 1850 target = self.class_file.constants[index - 1] 1851 target_name = target.get_python_name() 1852 1853 # Get the class name instead of the fully qualified name. 1854 1855 full_class_name = target.get_class().get_python_name() 1856 program.use_external_name(full_class_name) 1857 load_class_name(self.class_file, full_class_name, program) 1858 # NOTE: Using the string version of the name which may contain incompatible characters. 1859 program.store_attr(str(target_name)) 1860 1861 def ret(self, arguments, program): 1862 program.ret(arguments[0]) 1863 # Indicate that the finally handler is probably over. 1864 # NOTE: This is seemingly not guaranteed. 1865 self.in_finally = 0 1866 1867 def return_(self, arguments, program): 1868 program.load_const(None) 1869 program.return_value() 1870 1871 saload = laload 1872 sastore = lastore 1873 1874 def sipush(self, arguments, program): 1875 program.load_const((arguments[0] << 8) + arguments[1]) 1876 1877 def swap(self, arguments, program): 1878 program.rot_two() 1879 1880 def tableswitch(self, code, program): 1881 1882 # Find the offset to the next 4 byte boundary in the code. 1883 1884 d, r = divmod(self.java_position + 1, 4) 1885 to_boundary = (4 - r) % 4 1886 1887 # Get the pertinent arguments. 1888 1889 code = code[to_boundary:] 1890 default = classfile.u4(code[0:4]) 1891 low = classfile.u4(code[4:8]) 1892 high = classfile.u4(code[8:12]) 1893 1894 # Process the jump entries. 1895 # NOTE: This is not the most optimal implementation. 1896 1897 jump_index = 12 1898 for jump in range(low, high + 1): 1899 offset = classfile.s4(code[jump_index:jump_index + 4]) 1900 1901 # Calculate the branch target. 1902 1903 java_absolute = self.java_position + offset 1904 1905 # Generate branching code. 1906 1907 program.dup_top() # Stack: key, key 1908 program.load_const(jump) # Stack: key, key, jump 1909 program.compare_op("==") # Stack: key, result 1910 program.jump_to_label(0, "end") 1911 program.pop_top() # Stack: key 1912 program.pop_top() # Stack: 1913 program.jump_absolute(self.position_mapping[java_absolute]) 1914 1915 # Generate the label for the end of the branching code. 1916 1917 program.start_label("end") 1918 program.pop_top() # Stack: key 1919 1920 # Update the index. 1921 1922 jump_index += 4 1923 1924 # Generate the default. 1925 1926 java_absolute = self.java_position + default 1927 program.jump_absolute(self.position_mapping[java_absolute]) 1928 return jump_index + to_boundary 1929 1930 def wide(self, code, program): 1931 # NOTE: To be implemented. 1932 return number_of_arguments 1933 1934 def disassemble(class_file, method): 1935 disassembler = BytecodeDisassembler(class_file) 1936 disassembler.process(method, BytecodeDisassemblerProgram()) 1937 1938 class ClassTranslator: 1939 1940 """ 1941 A class which provides a wrapper around a class file and the means to 1942 translate the represented class into a Python class. 1943 """ 1944 1945 def __init__(self, class_file): 1946 1947 "Initialise the object with the given 'class_file'." 1948 1949 self.class_file = class_file 1950 self.filename = "" 1951 1952 for attribute in self.class_file.attributes: 1953 if isinstance(attribute, classfile.SourceFileAttributeInfo): 1954 self.filename = str(attribute.get_name()) 1955 1956 def translate_method(self, method): 1957 1958 "Translate the given 'method' - an object obtained from the class file." 1959 1960 translator = BytecodeTranslator(self.class_file) 1961 writer = BytecodeWriter() 1962 translator.process(method, writer) 1963 return translator, writer 1964 1965 def make_method(self, real_method_name, methods, global_names, namespace): 1966 1967 """ 1968 Make a dispatcher method with the given 'real_method_name', providing 1969 dispatch to the supplied type-sensitive 'methods', accessing the given 1970 'global_names' where necessary, and storing the new method in the 1971 'namespace' provided. 1972 """ 1973 1974 if real_method_name == "<init>": 1975 method_name = "__init__" 1976 else: 1977 method_name = real_method_name 1978 1979 # Where only one method exists, just make an alias. 1980 1981 if len(methods) == 1: 1982 method, fn = methods[0] 1983 namespace[method_name] = fn 1984 return 1985 1986 # Write a simple bytecode dispatching mechanism. 1987 1988 program = BytecodeWriter() 1989 1990 # Remember whether any of the methods are static. 1991 # NOTE: This should be an all or nothing situation. 1992 1993 method_is_static = 0 1994 1995 # NOTE: The code below should use dictionary-based dispatch for better performance. 1996 1997 for method, fn in methods: 1998 method_is_static = real_method_name != "<init>" and method_is_static or \ 1999 classfile.has_flags(method.access_flags, [classfile.STATIC]) 2000 2001 if method_is_static: 2002 program.load_fast(0) # Stack: arguments 2003 else: 2004 program.load_fast(1) # Stack: arguments 2005 2006 program.setup_loop() 2007 program.load_const(1) # Stack: arguments, 1 2008 2009 if method_is_static: 2010 program.store_fast(1) # Stack: arguments (found = 1) 2011 else: 2012 program.store_fast(2) # Stack: arguments (found = 1) 2013 2014 # Emit a list of parameter types. 2015 2016 descriptor_types = method.get_descriptor()[0] 2017 for descriptor_type in descriptor_types: 2018 base_type, object_type, array_type = descriptor_type 2019 python_type = classfile.descriptor_base_type_mapping[base_type] 2020 if python_type == "instance": 2021 # NOTE: This will need extending. 2022 python_type = object_type 2023 program.load_global(python_type) # Stack: arguments, type, ... 2024 program.build_list(len(descriptor_types)) 2025 # Stack: arguments, types 2026 # Make a map of arguments and types. 2027 program.load_const(None) # Stack: arguments, types, None 2028 program.rot_three() # Stack: None, arguments, types 2029 program.build_tuple(3) # Stack: tuple 2030 program.load_global("map") # Stack: tuple, map 2031 program.rot_two() # Stack: map, tuple 2032 program.call_function_var(0) # Stack: list (mapping arguments to types) 2033 # Loop over each pair. 2034 program.get_iter() # Stack: iter 2035 program.for_iter() # Stack: iter, (argument, type) 2036 program.unpack_sequence(2) # Stack: iter, type, argument 2037 program.dup_top() # Stack: iter, type, argument, argument 2038 program.load_const(None) # Stack: iter, type, argument, argument, None 2039 program.compare_op("is") # Stack: iter, type, argument, result 2040 # Missing argument? 2041 program.jump_to_label(0, "present") 2042 program.pop_top() # Stack: iter, type, argument 2043 program.pop_top() # Stack: iter, type 2044 program.pop_top() # Stack: iter 2045 program.load_const(0) # Stack: iter, 0 2046 2047 if method_is_static: 2048 program.store_fast(1) # Stack: iter (found = 0) 2049 else: 2050 program.store_fast(2) # Stack: iter (found = 0) 2051 2052 program.break_loop() 2053 # Argument was present. 2054 program.start_label("present") 2055 program.pop_top() # Stack: iter, type, argument 2056 program.rot_two() # Stack: iter, argument, type 2057 program.dup_top() # Stack: iter, argument, type, type 2058 program.load_const(None) # Stack: iter, argument, type, type, None 2059 program.compare_op("is") # Stack: iter, argument, type, result 2060 # Missing parameter type? 2061 program.jump_to_label(0, "present") 2062 program.pop_top() # Stack: iter, argument, type 2063 program.pop_top() # Stack: iter, argument 2064 program.pop_top() # Stack: iter 2065 program.load_const(0) # Stack: iter, 0 2066 2067 if method_is_static: 2068 program.store_fast(1) # Stack: iter (found = 0) 2069 else: 2070 program.store_fast(2) # Stack: iter (found = 0) 2071 2072 program.break_loop() 2073 # Parameter was present. 2074 program.start_label("present") 2075 program.pop_top() # Stack: iter, argument, type 2076 program.build_tuple(2) # Stack: iter, (argument, type) 2077 program.load_global("isinstance") # Stack: iter, (argument, type), isinstance 2078 program.rot_two() # Stack: iter, isinstance, (argument, type) 2079 program.call_function_var(0) # Stack: iter, result 2080 program.jump_to_label(1, "match") 2081 program.pop_top() # Stack: iter 2082 program.load_const(0) # Stack: iter, 0 2083 2084 if method_is_static: 2085 program.store_fast(1) # Stack: iter (found = 0) 2086 else: 2087 program.store_fast(2) # Stack: iter (found = 0) 2088 2089 program.break_loop() 2090 # Argument type and parameter type matched. 2091 program.start_label("match") 2092 program.pop_top() # Stack: iter 2093 program.end_loop() # Stack: 2094 # If all the parameters matched, call the method. 2095 2096 if method_is_static: 2097 program.load_fast(1) # Stack: match 2098 else: 2099 program.load_fast(2) # Stack: match 2100 2101 program.jump_to_label(0, "failed") 2102 # All the parameters matched. 2103 program.pop_top() # Stack: 2104 2105 if method_is_static: 2106 program.load_fast(0) # Stack: arguments 2107 program.load_global(str(self.class_file.this_class.get_python_name())) 2108 # Stack: arguments, class 2109 else: 2110 program.load_fast(1) # Stack: arguments 2111 program.load_fast(0) # Stack: arguments, self 2112 2113 program.load_attr(str(method.get_python_name())) 2114 # Stack: arguments, method 2115 program.rot_two() # Stack: method, arguments 2116 program.call_function_var(0) # Stack: result 2117 program.return_value() 2118 # Try the next method if arguments or parameters were missing or incorrect. 2119 program.start_label("failed") 2120 program.pop_top() # Stack: 2121 2122 # Raise an exception if nothing matched. 2123 # NOTE: Improve this. 2124 2125 program.load_const("No matching method") 2126 program.raise_varargs(1) 2127 program.load_const(None) 2128 program.return_value() 2129 2130 # Add the code as a method in the namespace. 2131 # NOTE: One actual parameter, flags as 71 apparently means that a list 2132 # NOTE: parameter is used in a method. 2133 2134 if method_is_static: 2135 nargs = 0 2136 else: 2137 nargs = 1 2138 nlocals = program.max_locals + 1 2139 2140 code = new.code(nargs, nlocals, program.max_stack_depth, 71, program.get_output(), 2141 tuple(program.get_constants()), tuple(program.get_names()), tuple(self.make_varnames(nlocals, method_is_static)), 2142 self.filename, method_name, 0, "") 2143 fn = new.function(code, global_names) 2144 2145 if method_is_static: 2146 fn = staticmethod(fn) 2147 2148 namespace[method_name] = fn 2149 2150 def process(self, global_names): 2151 2152 """ 2153 Process the class, storing it in the 'global_names' dictionary provided. 2154 Return a tuple containing the class and a list of external names 2155 referenced by the class's methods. 2156 """ 2157 2158 namespace = {} 2159 2160 # Make the fields. 2161 2162 for field in self.class_file.fields: 2163 if classfile.has_flags(field.access_flags, [classfile.STATIC]): 2164 field_name = str(field.get_python_name()) 2165 namespace[field_name] = None 2166 2167 # Make the methods. 2168 2169 real_methods = {} 2170 external_names = [] 2171 2172 for method in self.class_file.methods: 2173 real_method_name = str(method.get_name()) 2174 method_name = str(method.get_python_name()) 2175 2176 translator, writer = self.translate_method(method) 2177 2178 # Add external names to the master list. 2179 2180 for external_name in writer.external_names: 2181 if external_name not in external_names: 2182 external_names.append(external_name) 2183 2184 # Fix up special class initialisation methods and static methods. 2185 2186 method_is_static = real_method_name != "<init>" and classfile.has_flags(method.access_flags, [classfile.STATIC]) 2187 if method_is_static: 2188 nargs = len(method.get_descriptor()[0]) 2189 else: 2190 nargs = len(method.get_descriptor()[0]) + 1 2191 nlocals = writer.max_locals + 1 2192 flags = 67 2193 2194 # NOTE: Add line number table later. 2195 2196 code = new.code(nargs, nlocals, writer.max_stack_depth, flags, writer.get_output(), 2197 tuple(writer.get_constants()), tuple(writer.get_names()), 2198 tuple(self.make_varnames(nlocals, method_is_static)), self.filename, method_name, 0, "") 2199 2200 # NOTE: May need more globals. 2201 2202 fn = new.function(code, global_names) 2203 2204 # Fix up special class initialisation methods and static methods. 2205 2206 if method_is_static: 2207 fn = staticmethod(fn) 2208 2209 # Remember the real method name and the corresponding methods produced. 2210 2211 if not real_methods.has_key(real_method_name): 2212 real_methods[real_method_name] = [] 2213 real_methods[real_method_name].append((method, fn)) 2214 2215 # Add the method to the class's namespace. 2216 2217 namespace[method_name] = fn 2218 2219 # Define superclasses. 2220 2221 bases = self.get_base_classes(global_names) 2222 2223 # Define method dispatchers. 2224 2225 for real_method_name, methods in real_methods.items(): 2226 if real_method_name != "<clinit>": 2227 self.make_method(real_method_name, methods, global_names, namespace) 2228 2229 # Use only the last part of the fully qualified name. 2230 2231 full_class_name = str(self.class_file.this_class.get_python_name()) 2232 class_name = full_class_name.split(".")[-1] 2233 cls = new.classobj(class_name, bases, namespace) 2234 global_names[cls.__name__] = cls 2235 2236 return cls, external_names 2237 2238 def get_base_classes(self, global_names): 2239 2240 """ 2241 Identify the superclass, then either load it from the given 2242 'global_names' if available, or import the class from its parent module. 2243 Return a tuple containing all base classes (typically a single element 2244 tuple). 2245 """ 2246 2247 original_name = str(self.class_file.super_class.get_name()) 2248 full_this_class_name = str(self.class_file.this_class.get_python_name()) 2249 this_class_name_parts = full_this_class_name.split(".") 2250 this_class_module_name = ".".join(this_class_name_parts[:-1]) 2251 full_super_class_name = str(self.class_file.super_class.get_python_name()) 2252 super_class_name_parts = full_super_class_name.split(".") 2253 super_class_name = super_class_name_parts[-1] 2254 super_class_module_name = ".".join(super_class_name_parts[:-1]) 2255 if super_class_module_name == "": 2256 obj = global_names[super_class_name] 2257 elif super_class_module_name == this_class_module_name: 2258 obj = global_names[super_class_name] 2259 else: 2260 print "Importing", super_class_module_name, super_class_name 2261 obj = __import__(super_class_module_name, global_names, {}, []) 2262 for super_class_name_part in super_class_name_parts[1:] or [super_class_name]: 2263 print "*", obj, super_class_name_part 2264 obj = getattr(obj, super_class_name_part) 2265 return (obj,) 2266 2267 def make_varnames(self, nlocals, method_is_static=0): 2268 2269 """ 2270 A utility method which invents variable names for the given number - 2271 'nlocals' - of local variables in a method. Returns a list of such 2272 variable names. 2273 2274 If the optional 'method_is_static' is set to true, do not use "self" as 2275 the first argument name. 2276 """ 2277 2278 if method_is_static: 2279 l = ["cls"] 2280 else: 2281 l = ["self"] 2282 for i in range(1, nlocals): 2283 l.append("_l%s" % i) 2284 return l[:nlocals] 2285 2286 # Test functions, useful for tracing generated bytecode operations. 2287 2288 def _map(*args): 2289 print args 2290 return apply(__builtins__.map, args) 2291 2292 def _isinstance(*args): 2293 print args 2294 return apply(__builtins__.isinstance, args) 2295 2296 if __name__ == "__main__": 2297 import sys 2298 import dis 2299 global_names = globals() 2300 #global_names["isinstance"] = _isinstance 2301 #global_names["map"] = _map 2302 for filename in sys.argv[1:]: 2303 f = open(filename, "rb") 2304 c = classfile.ClassFile(f.read()) 2305 translator = ClassTranslator(c) 2306 cls, external_names = translator.process(global_names) 2307 2308 # vim: tabstop=4 expandtab shiftwidth=4