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