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