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