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 program.load_global("chr") # Stack: value, chr 1244 program.rot_two() # Stack: chr, value 1245 program.call_function(1) # Stack: result 1246 1247 def i2d(self, arguments, program): 1248 program.load_global("float") # Stack: value, float 1249 program.rot_two() # Stack: float, value 1250 program.call_function(1) # Stack: result 1251 1252 i2f = i2d # Not distinguishing between float and double 1253 1254 def i2l(self, arguments, program): 1255 pass # Preserving Java semantics 1256 1257 def i2s(self, arguments, program): 1258 pass # Not distinguishing between int and short 1259 1260 iadd = fadd 1261 iaload = faload 1262 1263 def iand(self, arguments, program): 1264 # NOTE: No type checking performed. 1265 program.binary_and() 1266 1267 iastore = fastore 1268 1269 def iconst_m1(self, arguments, program): 1270 program.load_const(-1) 1271 1272 def iconst_0(self, arguments, program): 1273 program.load_const(0) 1274 1275 def iconst_1(self, arguments, program): 1276 program.load_const(1) 1277 1278 def iconst_2(self, arguments, program): 1279 program.load_const(2) 1280 1281 def iconst_3(self, arguments, program): 1282 program.load_const(3) 1283 1284 def iconst_4(self, arguments, program): 1285 program.load_const(4) 1286 1287 def iconst_5(self, arguments, program): 1288 program.load_const(5) 1289 1290 idiv = fdiv 1291 1292 def _if_xcmpx(self, arguments, program, op): 1293 offset = signed2((arguments[0] << 8) + arguments[1]) 1294 java_absolute = self.java_position + offset 1295 program.compare_op(op) 1296 program.jump_to_label(0, "next") # skip if false 1297 program.pop_top() 1298 program.jump_absolute(self.position_mapping[java_absolute]) 1299 program.start_label("next") 1300 program.pop_top() 1301 1302 def if_acmpeq(self, arguments, program): 1303 # NOTE: No type checking performed. 1304 self._if_xcmpx(arguments, program, "is") 1305 1306 def if_acmpne(self, arguments, program): 1307 # NOTE: No type checking performed. 1308 self._if_xcmpx(arguments, program, "is not") 1309 1310 def if_icmpeq(self, arguments, program): 1311 # NOTE: No type checking performed. 1312 self._if_xcmpx(arguments, program, "==") 1313 1314 def if_icmpne(self, arguments, program): 1315 # NOTE: No type checking performed. 1316 self._if_xcmpx(arguments, program, "!=") 1317 1318 def if_icmplt(self, arguments, program): 1319 # NOTE: No type checking performed. 1320 self._if_xcmpx(arguments, program, "<") 1321 1322 def if_icmpge(self, arguments, program): 1323 # NOTE: No type checking performed. 1324 self._if_xcmpx(arguments, program, ">=") 1325 1326 def if_icmpgt(self, arguments, program): 1327 # NOTE: No type checking performed. 1328 self._if_xcmpx(arguments, program, ">") 1329 1330 def if_icmple(self, arguments, program): 1331 # NOTE: No type checking performed. 1332 self._if_xcmpx(arguments, program, "<=") 1333 1334 def ifeq(self, arguments, program): 1335 # NOTE: No type checking performed. 1336 program.load_const(0) 1337 self._if_xcmpx(arguments, program, "==") 1338 1339 def ifne(self, arguments, program): 1340 # NOTE: No type checking performed. 1341 program.load_const(0) 1342 self._if_xcmpx(arguments, program, "!=") 1343 1344 def iflt(self, arguments, program): 1345 # NOTE: No type checking performed. 1346 program.load_const(0) 1347 self._if_xcmpx(arguments, program, "<") 1348 1349 def ifge(self, arguments, program): 1350 # NOTE: No type checking performed. 1351 program.load_const(0) 1352 self._if_xcmpx(arguments, program, ">=") 1353 1354 def ifgt(self, arguments, program): 1355 # NOTE: No type checking performed. 1356 program.load_const(0) 1357 self._if_xcmpx(arguments, program, ">") 1358 1359 def ifle(self, arguments, program): 1360 # NOTE: No type checking performed. 1361 program.load_const(0) 1362 self._if_xcmpx(arguments, program, "<=") 1363 1364 def ifnonnull(self, arguments, program): 1365 # NOTE: No type checking performed. 1366 program.load_const(None) 1367 self._if_xcmpx(arguments, program, "is not") 1368 1369 def ifnull(self, arguments, program): 1370 # NOTE: No type checking performed. 1371 program.load_const(None) 1372 self._if_xcmpx(arguments, program, "is") 1373 1374 def iinc(self, arguments, program): 1375 # NOTE: No type checking performed. 1376 program.load_fast(arguments[0]) 1377 program.load_const(arguments[1]) 1378 program.binary_add() 1379 program.store_fast(arguments[0]) 1380 1381 iload = fload 1382 iload_0 = fload_0 1383 iload_1 = fload_1 1384 iload_2 = fload_2 1385 iload_3 = fload_3 1386 imul = fmul 1387 ineg = fneg 1388 1389 def instanceof(self, arguments, program): 1390 index = (arguments[0] << 8) + arguments[1] 1391 target_name = self.class_file.constants[index - 1].get_python_name() 1392 program.use_external_name(target_name) 1393 1394 # NOTE: Using the string version of the name which may contain incompatible characters. 1395 target_components = str(target_name).split("/") 1396 1397 program.load_global("isinstance") # Stack: objectref, isinstance 1398 program.rot_two() # Stack: isinstance, objectref 1399 program.load_global(target_components[0]) 1400 for target_component in target_components[1:]: 1401 program.load_attr(target_component) 1402 program.call_function(2) # Stack: result 1403 1404 def _invoke(self, target_name, program): 1405 # NOTE: Using the string version of the name which may contain incompatible characters. 1406 program.load_attr(str(target_name)) # Stack: tuple, method 1407 program.rot_two() # Stack: method, tuple 1408 program.call_function_var(0) # Stack: result 1409 1410 def invokeinterface(self, arguments, program): 1411 # NOTE: This implementation does not perform the necessary checks for 1412 # NOTE: signature-based polymorphism. 1413 # NOTE: Java rules not specifically obeyed. 1414 index = (arguments[0] << 8) + arguments[1] 1415 # NOTE: "count" == nargs + 1, apparently. 1416 count = arguments[2] - 1 1417 target_name = self.class_file.constants[index - 1].get_python_name() 1418 # Stack: objectref, arg1, arg2, ... 1419 program.build_tuple(count) # Stack: objectref, tuple 1420 program.rot_two() # Stack: tuple, objectref 1421 # NOTE: The interface information is not used to discover the correct 1422 # NOTE: method. 1423 self._invoke(target_name, program) 1424 1425 def invokespecial(self, arguments, program): 1426 # NOTE: This implementation does not perform the necessary checks for 1427 # NOTE: signature-based polymorphism. 1428 # NOTE: Java rules not specifically obeyed. 1429 index = (arguments[0] << 8) + arguments[1] 1430 target = self.class_file.constants[index - 1] 1431 original_name = target.get_name() 1432 target_name = target.get_python_name() 1433 1434 # Get the number of parameters from the descriptor. 1435 1436 count = len(target.get_descriptor()[0]) 1437 1438 # First, we build a tuple of the reference and arguments. 1439 1440 program.build_tuple(count + 1) # Stack: tuple 1441 1442 # Get the class name instead of the fully qualified name. 1443 # NOTE: Not bothering with Object initialisation. 1444 1445 full_class_name = target.get_class().get_python_name() 1446 if full_class_name not in ("java.lang.Object", "java.lang.Exception"): 1447 self._load_class_name(full_class_name, program) 1448 self._invoke(target_name, program) 1449 1450 # Remove Python None return value. 1451 1452 if str(original_name) == "<init>": 1453 program.pop_top() 1454 1455 def invokestatic(self, arguments, program): 1456 # NOTE: This implementation does not perform the necessary checks for 1457 # NOTE: signature-based polymorphism. 1458 # NOTE: Java rules not specifically obeyed. 1459 index = (arguments[0] << 8) + arguments[1] 1460 target = self.class_file.constants[index - 1] 1461 target_name = target.get_python_name() 1462 1463 # Get the number of parameters from the descriptor. 1464 1465 count = len(target.get_descriptor()[0]) 1466 1467 # Stack: arg1, arg2, ... 1468 1469 program.build_tuple(count) # Stack: tuple 1470 1471 # Use the class to provide access to static methods. 1472 # Get the class name instead of the fully qualified name. 1473 1474 full_class_name = target.get_class().get_python_name() 1475 if full_class_name not in ("java.lang.Object", "java.lang.Exception"): 1476 self._load_class_name(full_class_name, program) 1477 self._invoke(target_name, program) 1478 1479 def invokevirtual (self, arguments, program): 1480 # NOTE: This implementation does not perform the necessary checks for 1481 # NOTE: signature-based polymorphism. 1482 # NOTE: Java rules not specifically obeyed. 1483 index = (arguments[0] << 8) + arguments[1] 1484 target = self.class_file.constants[index - 1] 1485 target_name = target.get_python_name() 1486 # Get the number of parameters from the descriptor. 1487 count = len(target.get_descriptor()[0]) 1488 # Stack: objectref, arg1, arg2, ... 1489 program.build_tuple(count) # Stack: objectref, tuple 1490 program.rot_two() # Stack: tuple, objectref 1491 self._invoke(target_name, program) 1492 1493 def ior(self, arguments, program): 1494 # NOTE: No type checking performed. 1495 program.binary_or() 1496 1497 irem = frem 1498 ireturn = freturn 1499 1500 def ishl(self, arguments, program): 1501 # NOTE: No type checking performed. 1502 # NOTE: Not verified. 1503 program.binary_lshift() 1504 1505 def ishr(self, arguments, program): 1506 # NOTE: No type checking performed. 1507 # NOTE: Not verified. 1508 program.binary_rshift() 1509 1510 istore = fstore 1511 istore_0 = fstore_0 1512 istore_1 = fstore_1 1513 istore_2 = fstore_2 1514 istore_3 = fstore_3 1515 isub = fsub 1516 iushr = ishr # Ignoring distinctions between arithmetic and logical shifts 1517 1518 def ixor(self, arguments, program): 1519 # NOTE: No type checking performed. 1520 program.binary_xor() 1521 1522 def jsr(self, arguments, program): 1523 offset = signed2((arguments[0] << 8) + arguments[1]) 1524 java_absolute = self.java_position + offset 1525 # Store the address of the next instruction. 1526 program.load_const_ret(self.position_mapping[self.java_position + 3]) 1527 program.jump_absolute(self.position_mapping[java_absolute]) 1528 1529 def jsr_w(self, arguments, program): 1530 offset = signed4((arguments[0] << 24) + (arguments[1] << 16) + (arguments[2] << 8) + arguments[3]) 1531 java_absolute = self.java_position + offset 1532 # Store the address of the next instruction. 1533 program.load_const_ret(self.position_mapping[self.java_position + 5]) 1534 program.jump_absolute(self.position_mapping[java_absolute]) 1535 1536 l2d = i2d 1537 l2f = i2f 1538 1539 def l2i(self, arguments, program): 1540 pass # Preserving Java semantics 1541 1542 ladd = iadd 1543 laload = iaload 1544 land = iand 1545 lastore = iastore 1546 1547 def lcmp(self, arguments, program): 1548 # NOTE: No type checking performed. 1549 program.dup_topx(2) # Stack: value1, value2, value1, value2 1550 program.compare_op(">") # Stack: value1, value2, result 1551 program.jump_to_label(0, "equals") 1552 # True - produce result and branch. 1553 program.pop_top() # Stack: value1, value2 1554 program.pop_top() # Stack: value1 1555 program.pop_top() # Stack: 1556 program.load_const(1) # Stack: 1 1557 program.jump_to_label(None, "next") 1558 # False - test equality. 1559 program.start_label("equals") 1560 program.pop_top() # Stack: value1, value2 1561 program.dup_topx(2) # Stack: value1, value2, value1, value2 1562 program.compare_op("==") # Stack: value1, value2, result 1563 program.jump_to_label(0, "less") 1564 # True - produce result and branch. 1565 program.pop_top() # Stack: value1, value2 1566 program.pop_top() # Stack: value1 1567 program.pop_top() # Stack: 1568 program.load_const(0) # Stack: 0 1569 program.jump_to_label(None, "next") 1570 # False - produce result. 1571 program.start_label("less") 1572 program.pop_top() # Stack: value1, value2 1573 program.pop_top() # Stack: value1 1574 program.pop_top() # Stack: 1575 program.load_const(-1) # Stack: -1 1576 program.start_label("next") 1577 1578 lconst_0 = iconst_0 1579 lconst_1 = iconst_1 1580 1581 def ldc(self, arguments, program): 1582 const = self.class_file.constants[arguments[0] - 1] 1583 if isinstance(const, classfile.StringInfo): 1584 program.use_external_name("java.lang.String") 1585 program.load_global("java") 1586 program.load_attr("lang") 1587 program.load_attr("String") 1588 program.load_const(const.get_value()) 1589 program.call_function(1) 1590 else: 1591 program.load_const(const) 1592 1593 def ldc_w(self, arguments, program): 1594 const = self.class_file.constants[(arguments[0] << 8) + arguments[1] - 1] 1595 if isinstance(const, classfile.StringInfo): 1596 program.use_external_name("java.lang.String") 1597 program.load_global("java") 1598 program.load_attr("lang") 1599 program.load_attr("String") 1600 program.load_const(const.get_value()) 1601 program.call_function(1) 1602 else: 1603 program.load_const(const) 1604 1605 ldc2_w = ldc_w 1606 ldiv = idiv 1607 lload = iload 1608 lload_0 = iload_0 1609 lload_1 = iload_1 1610 lload_2 = iload_2 1611 lload_3 = iload_3 1612 lmul = imul 1613 lneg = ineg 1614 1615 def lookupswitch(self, code, program): 1616 1617 # Find the offset to the next 4 byte boundary in the code. 1618 1619 d, r = divmod(self.java_position + 1, 4) 1620 to_boundary = (4 - r) % 4 1621 1622 # Get the pertinent arguments. 1623 1624 code = code[to_boundary:] 1625 default = classfile.u4(code[0:4]) 1626 npairs = classfile.u4(code[4:8]) 1627 1628 # Process the pairs. 1629 # NOTE: This is not the most optimal implementation. 1630 1631 pair_index = 8 1632 for pair in range(0, npairs): 1633 match = classfile.u4(code[pair_index:pair_index+4]) 1634 offset = classfile.s4(code[pair_index+4:pair_index+8]) 1635 # Calculate the branch target. 1636 java_absolute = self.java_position + offset 1637 # Generate branching code. 1638 program.dup_top() # Stack: key, key 1639 program.load_const(match) # Stack: key, key, match 1640 program.compare_op("==") # Stack: key, result 1641 program.jump_to_label(0, "end") 1642 program.pop_top() # Stack: key 1643 program.pop_top() # Stack: 1644 program.jump_absolute(self.position_mapping[java_absolute]) 1645 # Generate the label for the end of the branching code. 1646 program.start_label("end") 1647 program.pop_top() # Stack: key 1648 # Update the index. 1649 pair_index += 4 1650 1651 # Generate the default. 1652 1653 java_absolute = self.java_position + default 1654 program.jump_absolute(self.position_mapping[java_absolute]) 1655 return pair_index + to_boundary 1656 1657 lor = ior 1658 lrem = irem 1659 lreturn = ireturn 1660 lshl = ishl 1661 lshr = ishr 1662 lstore = istore 1663 lstore_0 = istore_0 1664 lstore_1 = istore_1 1665 lstore_2 = istore_2 1666 lstore_3 = istore_3 1667 lsub = isub 1668 lushr = iushr 1669 lxor = ixor 1670 1671 def monitorenter(self, arguments, program): 1672 # NOTE: To be implemented. 1673 pass 1674 1675 def monitorexit(self, arguments, program): 1676 # NOTE: To be implemented. 1677 pass 1678 1679 def multianewarray(self, arguments, program): 1680 index = (arguments[0] << 8) + arguments[1] 1681 dimensions = arguments[2] 1682 # Stack: count1, ..., countN-1, countN 1683 self._newarray(program) # Stack: count1, ..., countN-1, list 1684 for dimension in range(1, dimensions): 1685 program.rot_two() # Stack: count1, ..., list, countN-1 1686 program.build_list(0) # Stack: count1, ..., list, countN-1, new-list 1687 program.rot_three() # Stack: count1, ..., new-list, list, countN-1 1688 program.setup_loop() 1689 program.load_const(0) # Stack: count1, ..., new-list, list, countN-1, 0 1690 program.rot_two() # Stack: count1, ..., new-list, list, 0, countN-1 1691 program.load_global("range") # Stack: count1, ..., new-list, list, 0, countN-1, range 1692 program.rot_three() # Stack: count1, ..., new-list, list, range, 0, countN-1 1693 program.call_function(2) # Stack: count1, ..., new-list, list, range-list 1694 program.get_iter() # Stack: count1, ..., new-list, list, iter 1695 program.for_iter() # Stack: count1, ..., new-list, list, iter, value 1696 program.pop_top() # Stack: count1, ..., new-list, list, iter 1697 program.rot_three() # Stack: count1, ..., iter, new-list, list 1698 program.slice_0() # Stack: count1, ..., iter, new-list, list[:] 1699 program.dup_top() # Stack: count1, ..., iter, new-list, list[:], list[:] 1700 program.rot_three() # Stack: count1, ..., iter, list[:], new-list, list[:] 1701 program.rot_two() # Stack: count1, ..., iter, list[:], list[:], new-list 1702 program.dup_top() # Stack: count1, ..., iter, list[:], list[:], new-list, new-list 1703 program.load_attr("append") # Stack: count1, ..., iter, list[:], list[:], new-list, append 1704 program.rot_three() # Stack: count1, ..., iter, list[:], append, list[:], new-list 1705 program.rot_three() # Stack: count1, ..., iter, list[:], new-list, append, list[:] 1706 program.call_function(1) # Stack: count1, ..., iter, list[:], new-list, None 1707 program.pop_top() # Stack: count1, ..., iter, list[:], new-list 1708 program.rot_two() # Stack: count1, ..., iter, new-list, list[:] 1709 program.rot_three() # Stack: count1, ..., list[:], iter, new-list 1710 program.rot_three() # Stack: count1, ..., new-list, list[:], iter 1711 program.end_loop() # Stack: count1, ..., new-list, list[:], iter 1712 program.pop_top() # Stack: count1, ..., new-list 1713 1714 def new(self, arguments, program): 1715 # This operation is considered to be the same as the calling of the 1716 # initialisation method of the given class with no arguments. 1717 1718 index = (arguments[0] << 8) + arguments[1] 1719 target_name = self.class_file.constants[index - 1].get_python_name() 1720 program.use_external_name(target_name) 1721 1722 # NOTE: Using the string version of the name which may contain incompatible characters. 1723 program.load_global("object") 1724 program.load_attr("__new__") 1725 self._load_class_name(target_name, program) 1726 program.call_function(1) 1727 1728 def newarray(self, arguments, program): 1729 # NOTE: Does not raise NegativeArraySizeException. 1730 # NOTE: Not using the arguments to type the list/array. 1731 self._newarray(program) 1732 1733 def nop(self, arguments, program): 1734 pass 1735 1736 def pop(self, arguments, program): 1737 program.pop_top() 1738 1739 pop2 = pop # ignoring Java stack value distinctions 1740 1741 def putfield(self, arguments, program): 1742 index = (arguments[0] << 8) + arguments[1] 1743 target_name = self.class_file.constants[index - 1].get_python_name() 1744 program.rot_two() 1745 # NOTE: Using the string version of the name which may contain incompatible characters. 1746 program.store_attr(str(target_name)) 1747 1748 def putstatic(self, arguments, program): 1749 index = (arguments[0] << 8) + arguments[1] 1750 target = self.class_file.constants[index - 1] 1751 target_name = target.get_python_name() 1752 1753 # Get the class name instead of the fully qualified name. 1754 1755 full_class_name = target.get_class().get_python_name() 1756 self._load_class_name(full_class_name, program) 1757 # NOTE: Using the string version of the name which may contain incompatible characters. 1758 program.store_attr(str(target_name)) 1759 1760 def ret(self, arguments, program): 1761 program.ret(arguments[0]) 1762 # Indicate that the finally handler is probably over. 1763 # NOTE: This is seemingly not guaranteed. 1764 self.in_finally = 0 1765 1766 def return_(self, arguments, program): 1767 program.load_const(None) 1768 program.return_value() 1769 1770 saload = laload 1771 sastore = lastore 1772 1773 def sipush(self, arguments, program): 1774 program.load_const((arguments[0] << 8) + arguments[1]) 1775 1776 def swap(self, arguments, program): 1777 program.rot_two() 1778 1779 def tableswitch(self, code, program): 1780 1781 # Find the offset to the next 4 byte boundary in the code. 1782 1783 d, r = divmod(self.java_position + 1, 4) 1784 to_boundary = (4 - r) % 4 1785 1786 # Get the pertinent arguments. 1787 1788 code = code[to_boundary:] 1789 default = classfile.u4(code[0:4]) 1790 low = classfile.u4(code[4:8]) 1791 high = classfile.u4(code[8:12]) 1792 1793 # Process the jump entries. 1794 # NOTE: This is not the most optimal implementation. 1795 1796 jump_index = 12 1797 for jump in range(low, high + 1): 1798 offset = classfile.s4(code[jump_index:jump_index + 4]) 1799 1800 # Calculate the branch target. 1801 1802 java_absolute = self.java_position + offset 1803 1804 # Generate branching code. 1805 1806 program.dup_top() # Stack: key, key 1807 program.load_const(jump) # Stack: key, key, jump 1808 program.compare_op("==") # Stack: key, result 1809 program.jump_to_label(0, "end") 1810 program.pop_top() # Stack: key 1811 program.pop_top() # Stack: 1812 program.jump_absolute(self.position_mapping[java_absolute]) 1813 1814 # Generate the label for the end of the branching code. 1815 1816 program.start_label("end") 1817 program.pop_top() # Stack: key 1818 1819 # Update the index. 1820 1821 jump_index += 4 1822 1823 # Generate the default. 1824 1825 java_absolute = self.java_position + default 1826 program.jump_absolute(self.position_mapping[java_absolute]) 1827 return jump_index + to_boundary 1828 1829 def wide(self, code, program): 1830 # NOTE: To be implemented. 1831 return number_of_arguments 1832 1833 def disassemble(class_file, method): 1834 disassembler = BytecodeDisassembler(class_file) 1835 disassembler.process(method, BytecodeDisassemblerProgram()) 1836 1837 class ClassTranslator: 1838 1839 """ 1840 A class which provides a wrapper around a class file and the means to 1841 translate the represented class into a Python class. 1842 """ 1843 1844 def __init__(self, class_file): 1845 1846 "Initialise the object with the given 'class_file'." 1847 1848 self.class_file = class_file 1849 self.filename = str(self.class_file.attributes[0].get_name()) 1850 1851 def translate_method(self, method): 1852 1853 "Translate the given 'method' - an object obtained from the class file." 1854 1855 translator = BytecodeTranslator(self.class_file) 1856 writer = BytecodeWriter() 1857 translator.process(method, writer) 1858 return translator, writer 1859 1860 def make_method(self, real_method_name, methods, global_names, namespace): 1861 1862 """ 1863 Make a dispatcher method with the given 'real_method_name', providing 1864 dispatch to the supplied type-sensitive 'methods', accessing the given 1865 'global_names' where necessary, and storing the new method in the 1866 'namespace' provided. 1867 """ 1868 1869 if real_method_name == "<init>": 1870 method_name = "__init__" 1871 else: 1872 method_name = real_method_name 1873 1874 # Where only one method exists, just make an alias. 1875 1876 if len(methods) == 1: 1877 method, fn = methods[0] 1878 namespace[method_name] = fn 1879 return 1880 1881 # Write a simple bytecode dispatching mechanism. 1882 1883 program = BytecodeWriter() 1884 1885 # Remember whether any of the methods are static. 1886 # NOTE: This should be an all or nothing situation. 1887 1888 method_is_static = 0 1889 1890 # NOTE: The code below should use dictionary-based dispatch for better performance. 1891 1892 for method, fn in methods: 1893 method_is_static = real_method_name != "<init>" and method_is_static or classfile.has_flags(method.access_flags, [classfile.STATIC]) 1894 1895 if method_is_static: 1896 program.load_fast(0) # Stack: arguments 1897 else: 1898 program.load_fast(1) # Stack: arguments 1899 1900 program.setup_loop() 1901 program.load_const(1) # Stack: arguments, 1 1902 1903 if method_is_static: 1904 program.store_fast(1) # Stack: arguments (found = 1) 1905 else: 1906 program.store_fast(2) # Stack: arguments (found = 1) 1907 1908 # Emit a list of parameter types. 1909 1910 descriptor_types = method.get_descriptor()[0] 1911 for descriptor_type in descriptor_types: 1912 base_type, object_type, array_type = descriptor_type 1913 python_type = classfile.descriptor_base_type_mapping[base_type] 1914 if python_type == "instance": 1915 # NOTE: This will need extending. 1916 python_type = object_type 1917 program.load_global(python_type) # Stack: arguments, type, ... 1918 program.build_list(len(descriptor_types)) 1919 # Stack: arguments, types 1920 # Make a map of arguments and types. 1921 program.load_const(None) # Stack: arguments, types, None 1922 program.rot_three() # Stack: None, arguments, types 1923 program.build_tuple(3) # Stack: tuple 1924 program.load_global("map") # Stack: tuple, map 1925 program.rot_two() # Stack: map, tuple 1926 program.call_function_var(0) # Stack: list (mapping arguments to types) 1927 # Loop over each pair. 1928 program.get_iter() # Stack: iter 1929 program.for_iter() # Stack: iter, (argument, type) 1930 program.unpack_sequence(2) # Stack: iter, type, argument 1931 program.dup_top() # Stack: iter, type, argument, argument 1932 program.load_const(None) # Stack: iter, type, argument, argument, None 1933 program.compare_op("is") # Stack: iter, type, argument, result 1934 # Missing argument? 1935 program.jump_to_label(0, "present") 1936 program.pop_top() # Stack: iter, type, argument 1937 program.pop_top() # Stack: iter, type 1938 program.pop_top() # Stack: iter 1939 program.load_const(0) # Stack: iter, 0 1940 1941 if method_is_static: 1942 program.store_fast(1) # Stack: iter (found = 0) 1943 else: 1944 program.store_fast(2) # Stack: iter (found = 0) 1945 1946 program.break_loop() 1947 # Argument was present. 1948 program.start_label("present") 1949 program.pop_top() # Stack: iter, type, argument 1950 program.rot_two() # Stack: iter, argument, type 1951 program.dup_top() # Stack: iter, argument, type, type 1952 program.load_const(None) # Stack: iter, argument, type, type, None 1953 program.compare_op("is") # Stack: iter, argument, type, result 1954 # Missing parameter type? 1955 program.jump_to_label(0, "present") 1956 program.pop_top() # Stack: iter, argument, type 1957 program.pop_top() # Stack: iter, argument 1958 program.pop_top() # Stack: iter 1959 program.load_const(0) # Stack: iter, 0 1960 1961 if method_is_static: 1962 program.store_fast(1) # Stack: iter (found = 0) 1963 else: 1964 program.store_fast(2) # Stack: iter (found = 0) 1965 1966 program.break_loop() 1967 # Parameter was present. 1968 program.start_label("present") 1969 program.pop_top() # Stack: iter, argument, type 1970 program.build_tuple(2) # Stack: iter, (argument, type) 1971 program.load_global("isinstance") # Stack: iter, (argument, type), isinstance 1972 program.rot_two() # Stack: iter, isinstance, (argument, type) 1973 program.call_function_var(0) # Stack: iter, result 1974 program.jump_to_label(1, "match") 1975 program.pop_top() # Stack: iter 1976 program.load_const(0) # Stack: iter, 0 1977 1978 if method_is_static: 1979 program.store_fast(1) # Stack: iter (found = 0) 1980 else: 1981 program.store_fast(2) # Stack: iter (found = 0) 1982 1983 program.break_loop() 1984 # Argument type and parameter type matched. 1985 program.start_label("match") 1986 program.pop_top() # Stack: iter 1987 program.end_loop() # Stack: 1988 # If all the parameters matched, call the method. 1989 1990 if method_is_static: 1991 program.load_fast(1) # Stack: match 1992 else: 1993 program.load_fast(2) # Stack: match 1994 1995 program.jump_to_label(0, "failed") 1996 # All the parameters matched. 1997 program.pop_top() # Stack: 1998 1999 if method_is_static: 2000 program.load_fast(0) # Stack: arguments 2001 program.load_global(str(self.class_file.this_class.get_python_name())) 2002 # Stack: arguments, class 2003 else: 2004 program.load_fast(1) # Stack: arguments 2005 program.load_fast(0) # Stack: arguments, self 2006 2007 program.load_attr(str(method.get_python_name())) 2008 # Stack: arguments, method 2009 program.rot_two() # Stack: method, arguments 2010 program.call_function_var(0) # Stack: result 2011 program.return_value() 2012 # Try the next method if arguments or parameters were missing or incorrect. 2013 program.start_label("failed") 2014 program.pop_top() # Stack: 2015 2016 # Raise an exception if nothing matched. 2017 # NOTE: Improve this. 2018 2019 program.load_const("No matching method") 2020 program.raise_varargs(1) 2021 program.load_const(None) 2022 program.return_value() 2023 2024 # Add the code as a method in the namespace. 2025 # NOTE: One actual parameter, flags as 71 apparently means that a list 2026 # NOTE: parameter is used in a method. 2027 2028 if method_is_static: 2029 nargs = 0 2030 else: 2031 nargs = 1 2032 nlocals = program.max_locals + 1 2033 2034 code = new.code(nargs, nlocals, program.max_stack_depth, 71, program.get_output(), 2035 tuple(program.get_constants()), tuple(program.get_names()), tuple(self.make_varnames(nlocals, method_is_static)), 2036 self.filename, method_name, 0, "") 2037 fn = new.function(code, global_names) 2038 2039 if method_is_static: 2040 fn = staticmethod(fn) 2041 2042 namespace[method_name] = fn 2043 2044 def process(self, global_names): 2045 2046 """ 2047 Process the class, storing it in the 'global_names' dictionary provided. 2048 Return a tuple containing the class and a list of external names 2049 referenced by the class's methods. 2050 """ 2051 2052 namespace = {} 2053 2054 # Make the fields. 2055 2056 for field in self.class_file.fields: 2057 if classfile.has_flags(field.access_flags, [classfile.STATIC]): 2058 field_name = str(field.get_python_name()) 2059 namespace[field_name] = None 2060 2061 # Make the methods. 2062 2063 real_methods = {} 2064 external_names = [] 2065 2066 for method in self.class_file.methods: 2067 real_method_name = str(method.get_name()) 2068 method_name = str(method.get_python_name()) 2069 2070 translator, writer = self.translate_method(method) 2071 2072 # Add external names to the master list. 2073 2074 for external_name in writer.external_names: 2075 if external_name not in external_names: 2076 external_names.append(external_name) 2077 2078 # Fix up special class initialisation methods and static methods. 2079 2080 method_is_static = real_method_name != "<init>" and classfile.has_flags(method.access_flags, [classfile.STATIC]) 2081 if method_is_static: 2082 nargs = len(method.get_descriptor()[0]) 2083 else: 2084 nargs = len(method.get_descriptor()[0]) + 1 2085 nlocals = writer.max_locals + 1 2086 flags = 67 2087 2088 # NOTE: Add line number table later. 2089 2090 code = new.code(nargs, nlocals, writer.max_stack_depth, flags, writer.get_output(), 2091 tuple(writer.get_constants()), tuple(writer.get_names()), 2092 tuple(self.make_varnames(nlocals, method_is_static)), self.filename, method_name, 0, "") 2093 2094 # NOTE: May need more globals. 2095 2096 fn = new.function(code, global_names) 2097 2098 # Fix up special class initialisation methods and static methods. 2099 2100 if method_is_static: 2101 fn = staticmethod(fn) 2102 2103 # Remember the real method name and the corresponding methods produced. 2104 2105 if not real_methods.has_key(real_method_name): 2106 real_methods[real_method_name] = [] 2107 real_methods[real_method_name].append((method, fn)) 2108 2109 # Add the method to the class's namespace. 2110 2111 namespace[method_name] = fn 2112 2113 # Define superclasses. 2114 2115 bases = self.get_base_classes(global_names) 2116 2117 # Define method dispatchers. 2118 2119 for real_method_name, methods in real_methods.items(): 2120 if real_method_name != "<clinit>": 2121 self.make_method(real_method_name, methods, global_names, namespace) 2122 2123 # Use only the last part of the fully qualified name. 2124 2125 full_class_name = str(self.class_file.this_class.get_python_name()) 2126 class_name = full_class_name.split(".")[-1] 2127 cls = new.classobj(class_name, bases, namespace) 2128 global_names[cls.__name__] = cls 2129 2130 return cls, external_names 2131 2132 def get_base_classes(self, global_names): 2133 2134 """ 2135 Identify the superclass, then either load it from the given 2136 'global_names' if available, or import the class from its parent module. 2137 Return a tuple containing all base classes (typically a single element 2138 tuple). 2139 """ 2140 2141 original_name = str(self.class_file.super_class.get_name()) 2142 if original_name in ("java/lang/Object", "java/lang/Exception"): 2143 return (object,) 2144 else: 2145 full_this_class_name = str(self.class_file.this_class.get_python_name()) 2146 this_class_name_parts = full_this_class_name.split(".") 2147 this_class_module_name = ".".join(this_class_name_parts[:-1]) 2148 full_super_class_name = str(self.class_file.super_class.get_python_name()) 2149 super_class_name_parts = full_super_class_name.split(".") 2150 super_class_name = super_class_name_parts[-1] 2151 super_class_module_name = ".".join(super_class_name_parts[:-1]) 2152 if super_class_module_name == "": 2153 obj = global_names[super_class_name] 2154 elif super_class_module_name == this_class_module_name: 2155 obj = global_names[super_class_name] 2156 else: 2157 print "Importing", super_class_module_name, super_class_name 2158 obj = __import__(super_class_module_name, global_names, {}, []) 2159 for super_class_name_part in super_class_name_parts[1:] or [super_class_name]: 2160 print "*", obj, super_class_name_part 2161 obj = getattr(obj, super_class_name_part) 2162 return (obj,) 2163 2164 def make_varnames(self, nlocals, method_is_static=0): 2165 2166 """ 2167 A utility method which invents variable names for the given number - 2168 'nlocals' - of local variables in a method. Returns a list of such 2169 variable names. 2170 2171 If the optional 'method_is_static' is set to true, do not use "self" as 2172 the first argument name. 2173 """ 2174 2175 if method_is_static: 2176 l = ["cls"] 2177 else: 2178 l = ["self"] 2179 for i in range(1, nlocals): 2180 l.append("_l%s" % i) 2181 return l[:nlocals] 2182 2183 def _map(*args): 2184 print args 2185 return apply(__builtins__.map, args) 2186 2187 def _isinstance(*args): 2188 print args 2189 return apply(__builtins__.isinstance, args) 2190 2191 if __name__ == "__main__": 2192 import sys 2193 import dis 2194 global_names = globals() 2195 #global_names["isinstance"] = _isinstance 2196 #global_names["map"] = _map 2197 for filename in sys.argv[1:]: 2198 f = open(filename, "rb") 2199 c = classfile.ClassFile(f.read()) 2200 translator = ClassTranslator(c) 2201 cls, external_names = translator.process(global_names) 2202 2203 # vim: tabstop=4 expandtab shiftwidth=4