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