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