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