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