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 class BytecodeDisassemblerProgram: 896 position = 0 897 def setup_except(self, target): 898 print "(setup_except %s)" % target 899 def setup_finally(self, target): 900 print "(setup_finally %s)" % target 901 def end_exception(self): 902 print "(end_exception)" 903 def start_handler(self, exc_name): 904 print "(start_handler %s)" % exc_name 905 def pop_block(self): 906 print "(pop_block)" 907 908 class BytecodeTranslator(BytecodeReader): 909 910 "A Java bytecode translator which uses a Python bytecode writer." 911 912 def aaload(self, arguments, program): 913 # NOTE: No type checking performed. 914 program.binary_subscr() 915 916 def aastore(self, arguments, program): 917 # NOTE: No type checking performed. 918 # Stack: arrayref, index, value 919 program.rot_three() # Stack: value, arrayref, index 920 program.store_subscr() 921 922 def aconst_null(self, arguments, program): 923 program.load_const(None) 924 925 def aload(self, arguments, program): 926 program.load_fast(arguments[0]) 927 928 def aload_0(self, arguments, program): 929 program.load_fast(0) 930 931 def aload_1(self, arguments, program): 932 program.load_fast(1) 933 934 def aload_2(self, arguments, program): 935 program.load_fast(2) 936 937 def aload_3(self, arguments, program): 938 program.load_fast(3) 939 940 def anewarray(self, arguments, program): 941 # NOTE: Does not raise NegativeArraySizeException. 942 # NOTE: Not using the index to type the list/array. 943 index = (arguments[0] << 8) + arguments[1] 944 self._newarray(program) 945 946 def _newarray(self, program): 947 program.build_list(0) # Stack: count, list 948 program.rot_two() # Stack: list, count 949 program.setup_loop() 950 program.load_global("range") 951 program.load_const(0) # Stack: list, count, range, 0 952 program.rot_three() # Stack: list, 0, count, range 953 program.rot_three() # Stack: list, range, 0, count 954 program.call_function(2) # Stack: list, range_list 955 program.get_iter() # Stack: list, iter 956 program.for_iter() # Stack: list, iter, value 957 program.pop_top() # Stack: list, iter 958 program.rot_two() # Stack: iter, list 959 program.dup_top() # Stack: iter, list, list 960 program.load_attr("append") # Stack: iter, list, append 961 program.load_const(None) # Stack: iter, list, append, None 962 program.call_function(1) # Stack: iter, list, None 963 program.pop_top() # Stack: iter, list 964 program.rot_two() # Stack: list, iter 965 program.end_loop() # Back to for_iter above 966 967 def areturn(self, arguments, program): 968 program.return_value() 969 970 def arraylength(self, arguments, program): 971 program.load_global("len") # Stack: arrayref, len 972 program.rot_two() # Stack: len, arrayref 973 program.call_function(1) 974 975 def astore(self, arguments, program): 976 program.store_fast(arguments[0]) 977 978 def astore_0(self, arguments, program): 979 program.store_fast(0) 980 981 def astore_1(self, arguments, program): 982 program.store_fast(1) 983 984 def astore_2(self, arguments, program): 985 program.store_fast(2) 986 987 def astore_3(self, arguments, program): 988 program.store_fast(3) 989 990 def athrow(self, arguments, program): 991 # NOTE: NullPointerException not raised where null/None is found on the stack. 992 # If this instruction appears in a finally handler, use end_finally instead. 993 if self.in_finally: 994 program.end_finally() 995 else: 996 program.dup_top() 997 program.raise_varargs(1) 998 999 baload = aaload 1000 bastore = aastore 1001 1002 def bipush(self, arguments, program): 1003 program.load_const(arguments[0]) 1004 1005 caload = aaload 1006 castore = aastore 1007 1008 def checkcast(self, arguments, program): 1009 index = (arguments[0] << 8) + arguments[1] 1010 target_name = self.class_file.constants[index - 1].get_python_name() 1011 # NOTE: Using the string version of the name which may contain incompatible characters. 1012 target_components = str(target_name).split("/") 1013 1014 program.dup_top() # Stack: objectref, objectref 1015 program.load_global("isinstance") # Stack: objectref, objectref, isinstance 1016 program.rot_two() # Stack: objectref, isinstance, objectref 1017 program.load_global(target_components[0]) 1018 for target_component in target_components[1:]: 1019 program.load_attr(target_component) 1020 program.call_function(2) # Stack: objectref 1021 1022 def d2f(self, arguments, program): 1023 pass 1024 1025 def d2i(self, arguments, program): 1026 program.load_global("int") # Stack: value, int 1027 program.rot_two() # Stack: int, value 1028 program.call_function(1) # Stack: result 1029 1030 d2l = d2i # Preserving Java semantics 1031 1032 def dadd(self, arguments, program): 1033 # NOTE: No type checking performed. 1034 program.binary_add() 1035 1036 daload = aaload 1037 dastore = aastore 1038 1039 def dcmpg(self, arguments, program): 1040 # NOTE: No type checking performed. 1041 program.compare_op(">") 1042 1043 def dcmpl(self, arguments, program): 1044 # NOTE: No type checking performed. 1045 program.compare_op("<") 1046 1047 def dconst_0(self, arguments, program): 1048 program.load_const(0.0) 1049 1050 def dconst_1(self, arguments, program): 1051 program.load_const(1.0) 1052 1053 def ddiv(self, arguments, program): 1054 # NOTE: No type checking performed. 1055 program.binary_divide() 1056 1057 dload = aload 1058 dload_0 = aload_0 1059 dload_1 = aload_1 1060 dload_2 = aload_2 1061 dload_3 = aload_3 1062 1063 def dmul(self, arguments, program): 1064 # NOTE: No type checking performed. 1065 program.binary_multiply() 1066 1067 def dneg(self, arguments, program): 1068 # NOTE: No type checking performed. 1069 program.unary_negative() 1070 1071 def drem(self, arguments, program): 1072 # NOTE: No type checking performed. 1073 program.binary_modulo() 1074 1075 dreturn = areturn 1076 dstore = astore 1077 dstore_0 = astore_0 1078 dstore_1 = astore_1 1079 dstore_2 = astore_2 1080 dstore_3 = astore_3 1081 1082 def dsub(self, arguments, program): 1083 # NOTE: No type checking performed. 1084 program.binary_subtract() 1085 1086 def dup(self, arguments, program): 1087 program.dup_top() 1088 1089 def dup_x1(self, arguments, program): 1090 # Ignoring computational type categories. 1091 program.dup_top() 1092 program.rot_three() 1093 1094 def dup_x2(self, arguments, program): 1095 # Ignoring computational type categories. 1096 program.dup_top() 1097 program.rot_four() 1098 1099 dup2 = dup # Ignoring computational type categories 1100 dup2_x1 = dup_x1 # Ignoring computational type categories 1101 dup2_x2 = dup_x2 # Ignoring computational type categories 1102 1103 def f2d(self, arguments, program): 1104 pass # Preserving Java semantics 1105 1106 def f2i(self, arguments, program): 1107 program.load_global("int") # Stack: value, int 1108 program.rot_two() # Stack: int, value 1109 program.call_function(1) # Stack: result 1110 1111 f2l = f2i # Preserving Java semantics 1112 fadd = dadd 1113 faload = daload 1114 fastore = dastore 1115 fcmpg = dcmpg 1116 fcmpl = dcmpl 1117 fconst_0 = dconst_0 1118 fconst_1 = dconst_1 1119 1120 def fconst_2(self, arguments, program): 1121 program.load_const(2.0) 1122 1123 fdiv = ddiv 1124 fload = dload 1125 fload_0 = dload_0 1126 fload_1 = dload_1 1127 fload_2 = dload_2 1128 fload_3 = dload_3 1129 fmul = dmul 1130 fneg = dneg 1131 frem = drem 1132 freturn = dreturn 1133 fstore = dstore 1134 fstore_0 = dstore_0 1135 fstore_1 = dstore_1 1136 fstore_2 = dstore_2 1137 fstore_3 = dstore_3 1138 fsub = dsub 1139 1140 def getfield(self, arguments, program): 1141 index = (arguments[0] << 8) + arguments[1] 1142 target_name = self.class_file.constants[index - 1].get_python_name() 1143 # NOTE: Using the string version of the name which may contain incompatible characters. 1144 program.load_attr(str(target_name)) 1145 1146 def getstatic(self, arguments, program): 1147 index = (arguments[0] << 8) + arguments[1] 1148 target_name = self.class_file.constants[index - 1].get_python_name() 1149 # Get the class name instead of the fully qualified name. 1150 full_class_name = str(self.class_file.this_class.get_python_name()) 1151 class_name = full_class_name.split(".")[-1] 1152 program.load_global(class_name) # Stack: classref 1153 # NOTE: Using the string version of the name which may contain incompatible characters. 1154 program.load_attr(str(target_name)) 1155 1156 def goto(self, arguments, program): 1157 offset = signed2((arguments[0] << 8) + arguments[1]) 1158 java_absolute = self.java_position + offset 1159 program.jump_absolute(self.position_mapping[java_absolute]) 1160 1161 def goto_w(self, arguments, program): 1162 offset = signed4((arguments[0] << 24) + (arguments[1] << 16) + (arguments[2] << 8) + arguments[3]) 1163 java_absolute = self.java_position + offset 1164 program.jump_absolute(self.position_mapping[java_absolute]) 1165 1166 def i2b(self, arguments, program): 1167 pass 1168 1169 def i2c(self, arguments, program): 1170 program.load_global("chr") # Stack: value, chr 1171 program.rot_two() # Stack: chr, value 1172 program.call_function(1) # Stack: result 1173 1174 def i2d(self, arguments, program): 1175 program.load_global("float") # Stack: value, float 1176 program.rot_two() # Stack: float, value 1177 program.call_function(1) # Stack: result 1178 1179 i2f = i2d # Not distinguishing between float and double 1180 1181 def i2l(self, arguments, program): 1182 pass # Preserving Java semantics 1183 1184 def i2s(self, arguments, program): 1185 pass # Not distinguishing between int and short 1186 1187 iadd = fadd 1188 iaload = faload 1189 1190 def iand(self, arguments, program): 1191 # NOTE: No type checking performed. 1192 program.binary_and() 1193 1194 iastore = fastore 1195 1196 def iconst_m1(self, arguments, program): 1197 program.load_const(-1) 1198 1199 def iconst_0(self, arguments, program): 1200 program.load_const(0) 1201 1202 def iconst_1(self, arguments, program): 1203 program.load_const(1) 1204 1205 def iconst_2(self, arguments, program): 1206 program.load_const(2) 1207 1208 def iconst_3(self, arguments, program): 1209 program.load_const(3) 1210 1211 def iconst_4(self, arguments, program): 1212 program.load_const(4) 1213 1214 def iconst_5(self, arguments, program): 1215 program.load_const(5) 1216 1217 idiv = fdiv 1218 1219 def _if_xcmpx(self, arguments, program, op): 1220 offset = signed2((arguments[0] << 8) + arguments[1]) 1221 java_absolute = self.java_position + offset 1222 program.compare_op(op) 1223 program.jump_to_label(0, "next") # skip if false 1224 program.pop_top() 1225 program.jump_absolute(self.position_mapping[java_absolute]) 1226 program.start_label("next") 1227 program.pop_top() 1228 1229 def if_acmpeq(self, arguments, program): 1230 # NOTE: No type checking performed. 1231 self._if_xcmpx(arguments, program, "is") 1232 1233 def if_acmpne(self, arguments, program): 1234 # NOTE: No type checking performed. 1235 self._if_xcmpx(arguments, program, "is not") 1236 1237 def if_icmpeq(self, arguments, program): 1238 # NOTE: No type checking performed. 1239 self._if_xcmpx(arguments, program, "==") 1240 1241 def if_icmpne(self, arguments, program): 1242 # NOTE: No type checking performed. 1243 self._if_xcmpx(arguments, program, "!=") 1244 1245 def if_icmplt(self, arguments, program): 1246 # NOTE: No type checking performed. 1247 self._if_xcmpx(arguments, program, "<") 1248 1249 def if_icmpge(self, arguments, program): 1250 # NOTE: No type checking performed. 1251 self._if_xcmpx(arguments, program, ">=") 1252 1253 def if_icmpgt(self, arguments, program): 1254 # NOTE: No type checking performed. 1255 self._if_xcmpx(arguments, program, ">") 1256 1257 def if_icmple(self, arguments, program): 1258 # NOTE: No type checking performed. 1259 self._if_xcmpx(arguments, program, "<=") 1260 1261 def ifeq(self, arguments, program): 1262 # NOTE: No type checking performed. 1263 program.load_const(0) 1264 self._if_xcmpx(arguments, program, "==") 1265 1266 def ifne(self, arguments, program): 1267 # NOTE: No type checking performed. 1268 program.load_const(0) 1269 self._if_xcmpx(arguments, program, "!=") 1270 1271 def iflt(self, arguments, program): 1272 # NOTE: No type checking performed. 1273 program.load_const(0) 1274 self._if_xcmpx(arguments, program, "<") 1275 1276 def ifge(self, arguments, program): 1277 # NOTE: No type checking performed. 1278 program.load_const(0) 1279 self._if_xcmpx(arguments, program, ">=") 1280 1281 def ifgt(self, arguments, program): 1282 # NOTE: No type checking performed. 1283 program.load_const(0) 1284 self._if_xcmpx(arguments, program, ">") 1285 1286 def ifle(self, arguments, program): 1287 # NOTE: No type checking performed. 1288 program.load_const(0) 1289 self._if_xcmpx(arguments, program, "<=") 1290 1291 def ifnonnull(self, arguments, program): 1292 # NOTE: No type checking performed. 1293 program.load_const(None) 1294 self._if_xcmpx(arguments, program, "is not") 1295 1296 def ifnull(self, arguments, program): 1297 # NOTE: No type checking performed. 1298 program.load_const(None) 1299 self._if_xcmpx(arguments, program, "is") 1300 1301 def iinc(self, arguments, program): 1302 # NOTE: No type checking performed. 1303 program.load_fast(arguments[0]) 1304 program.load_const(arguments[1]) 1305 program.binary_add() 1306 program.store_fast(arguments[0]) 1307 1308 iload = fload 1309 iload_0 = fload_0 1310 iload_1 = fload_1 1311 iload_2 = fload_2 1312 iload_3 = fload_3 1313 imul = fmul 1314 ineg = fneg 1315 1316 def instanceof(self, arguments, program): 1317 index = (arguments[0] << 8) + arguments[1] 1318 target_name = self.class_file.constants[index - 1].get_python_name() 1319 # NOTE: Using the string version of the name which may contain incompatible characters. 1320 target_components = str(target_name).split("/") 1321 1322 program.load_global("isinstance") # Stack: objectref, isinstance 1323 program.rot_two() # Stack: isinstance, objectref 1324 program.load_global(target_components[0]) 1325 for target_component in target_components[1:]: 1326 program.load_attr(target_component) 1327 program.call_function(2) # Stack: result 1328 1329 def _invoke(self, target_name, program): 1330 # NOTE: Using the string version of the name which may contain incompatible characters. 1331 program.load_attr(str(target_name)) # Stack: tuple, method 1332 program.rot_two() # Stack: method, tuple 1333 program.call_function_var(0) # Stack: result 1334 1335 def invokeinterface(self, arguments, program): 1336 # NOTE: This implementation does not perform the necessary checks for 1337 # NOTE: signature-based polymorphism. 1338 # NOTE: Java rules not specifically obeyed. 1339 index = (arguments[0] << 8) + arguments[1] 1340 # NOTE: "count" == nargs + 1, apparently. 1341 count = arguments[2] - 1 1342 target_name = self.class_file.constants[index - 1].get_python_name() 1343 # Stack: objectref, arg1, arg2, ... 1344 program.build_tuple(count) # Stack: objectref, tuple 1345 program.rot_two() # Stack: tuple, objectref 1346 self._invoke(target_name, program) 1347 1348 def invokespecial(self, arguments, program): 1349 # NOTE: This implementation does not perform the necessary checks for 1350 # NOTE: signature-based polymorphism. 1351 # NOTE: Java rules not specifically obeyed. 1352 index = (arguments[0] << 8) + arguments[1] 1353 target = self.class_file.constants[index - 1] 1354 original_name = target.get_name() 1355 target_name = target.get_python_name() 1356 method_name = self.method.get_name() 1357 1358 # Get the number of parameters from the descriptor. 1359 1360 count = len(target.get_descriptor()[0]) 1361 1362 # The stack may contain one of the following patterns: 1363 # Stack: classref, arg1, arg2, ... 1364 # Stack: objectref, arg1, arg2, ... 1365 # method == __init__, classref -> classref(arg1, arg2, ...) 1366 # method == __init__, objectref == self -> cls.bases[0].__init__(objectref, arg1, arg2, ...) 1367 # method == __init__, objectref != self -> should not occur 1368 # method != __init__, classref -> classref.method(classref, arg1, arg2, ...) 1369 # method != __init__, objectref == self -> cls.bases[0].method(objectref, arg1, arg2, ...) 1370 # method != __init__, objectref != self -> should not occur 1371 1372 # First, we build a tuple of the reference and arguments. 1373 1374 program.build_tuple(count + 1) # Stack: tuple 1375 1376 # Then, we test the nature of the reference. 1377 1378 program.dup_top() # Stack: tuple, tuple 1379 program.load_const(0) # Stack: tuple, tuple, 0 1380 program.binary_subscr() # Stack: tuple, reference 1381 1382 # Is it self? 1383 1384 program.dup_top() # Stack: tuple, reference, reference 1385 program.load_fast(0) # Stack: tuple, reference, reference, self|cls 1386 program.compare_op("is") # Stack: tuple, reference, result 1387 program.jump_to_label(1, "is-self") 1388 program.pop_top() # Stack: tuple, reference 1389 1390 # Is another class or reference. 1391 # NOTE: Reference case not covered! 1392 1393 if str(original_name) == "<init>": 1394 program.rot_two() # Stack: reference, tuple 1395 program.load_const(1) # Stack: reference, tuple, 1 1396 program.slice_1() # Stack: reference, tuple[1:] 1397 program.call_function_var(0) # Stack: result 1398 # NOTE: Combinations of new, dup tend to produce interfering extra 1399 # NOTE: class references. 1400 program.rot_two() # Stack: objectref, classref 1401 program.pop_top() 1402 program.jump_to_label(None, "done") 1403 else: 1404 self._invoke(target_name, program) 1405 program.jump_to_label(None, "done") 1406 1407 # Is self. 1408 1409 program.start_label("is-self") 1410 program.pop_top() # Stack: tuple, reference 1411 program.pop_top() # Stack: tuple 1412 # Get the class name instead of the fully qualified name. 1413 full_class_name = str(self.class_file.this_class.get_python_name()) 1414 class_name = full_class_name.split(".")[-1] 1415 program.load_global(class_name) # Stack: tuple, classref 1416 program.load_attr("__bases__") # Stack: tuple, bases 1417 program.dup_top() # Stack: tuple, bases, bases 1418 program.load_global("len") # Stack: tuple, bases, bases, len 1419 program.rot_two() # Stack: tuple, bases, len, bases 1420 program.call_function(1) # Stack: tuple, bases, #bases 1421 program.load_const(0) # Stack: tuple, bases, #bases, 0 1422 program.compare_op("==") # Stack: tuple, bases, result 1423 program.jump_to_label(1, "no-bases") 1424 program.pop_top() # Stack: tuple, bases 1425 program.load_const(0) # Stack: tuple, bases, 0 1426 program.binary_subscr() # Stack: tuple, bases[0] 1427 self._invoke(target_name, program) 1428 program.jump_to_label(None, "done") 1429 1430 # No bases found, do no invocation. 1431 program.start_label("no-bases") 1432 program.pop_top() # Stack: tuple, bases 1433 program.pop_top() # Stack: tuple 1434 program.pop_top() # Stack: 1435 1436 program.start_label("done") 1437 1438 def invokestatic(self, arguments, program): 1439 # NOTE: This implementation does not perform the necessary checks for 1440 # NOTE: signature-based polymorphism. 1441 # NOTE: Java rules not specifically obeyed. 1442 index = (arguments[0] << 8) + arguments[1] 1443 target = self.class_file.constants[index - 1] 1444 target_name = target.get_python_name() 1445 # Get the number of parameters from the descriptor. 1446 count = len(target.get_descriptor()[0]) 1447 # Stack: arg1, arg2, ... 1448 program.build_tuple(count) # Stack: tuple 1449 # Use the class to provide access to static methods. 1450 # Get the class name instead of the fully qualified name. 1451 # NOTE: Need to find the class that declared the field being accessed. 1452 full_class_name = str(self.class_file.this_class.get_python_name()) 1453 class_name = full_class_name.split(".")[-1] 1454 program.load_global(class_name) # Stack: tuple, classref 1455 self._invoke(target_name, program) 1456 1457 def invokevirtual (self, arguments, program): 1458 # NOTE: This implementation does not perform the necessary checks for 1459 # NOTE: signature-based polymorphism. 1460 # NOTE: Java rules not specifically obeyed. 1461 index = (arguments[0] << 8) + arguments[1] 1462 target = self.class_file.constants[index - 1] 1463 target_name = target.get_python_name() 1464 # Get the number of parameters from the descriptor. 1465 count = len(target.get_descriptor()[0]) 1466 # Stack: objectref, arg1, arg2, ... 1467 program.build_tuple(count) # Stack: objectref, tuple 1468 program.rot_two() # Stack: tuple, objectref 1469 self._invoke(target_name, program) 1470 1471 def ior(self, arguments, program): 1472 # NOTE: No type checking performed. 1473 program.binary_or() 1474 1475 irem = frem 1476 ireturn = freturn 1477 1478 def ishl(self, arguments, program): 1479 # NOTE: No type checking performed. 1480 # NOTE: Not verified. 1481 program.binary_lshift() 1482 1483 def ishr(self, arguments, program): 1484 # NOTE: No type checking performed. 1485 # NOTE: Not verified. 1486 program.binary_rshift() 1487 1488 istore = fstore 1489 istore_0 = fstore_0 1490 istore_1 = fstore_1 1491 istore_2 = fstore_2 1492 istore_3 = fstore_3 1493 isub = fsub 1494 iushr = ishr # Ignoring distinctions between arithmetic and logical shifts 1495 1496 def ixor(self, arguments, program): 1497 # NOTE: No type checking performed. 1498 program.binary_xor() 1499 1500 def jsr(self, arguments, program): 1501 offset = signed2((arguments[0] << 8) + arguments[1]) 1502 java_absolute = self.java_position + offset 1503 # Store the address of the next instruction. 1504 program.load_const_ret(self.position_mapping[self.java_position + 3]) 1505 program.jump_absolute(self.position_mapping[java_absolute]) 1506 1507 def jsr_w(self, arguments, program): 1508 offset = signed4((arguments[0] << 24) + (arguments[1] << 16) + (arguments[2] << 8) + arguments[3]) 1509 java_absolute = self.java_position + offset 1510 # Store the address of the next instruction. 1511 program.load_const_ret(self.position_mapping[self.java_position + 5]) 1512 program.jump_absolute(self.position_mapping[java_absolute]) 1513 1514 l2d = i2d 1515 l2f = i2f 1516 1517 def l2i(self, arguments, program): 1518 pass # Preserving Java semantics 1519 1520 ladd = iadd 1521 laload = iaload 1522 land = iand 1523 lastore = iastore 1524 1525 def lcmp(self, arguments, program): 1526 # NOTE: No type checking performed. 1527 program.dup_topx(2) # Stack: value1, value2, value1, value2 1528 program.compare_op(">") # Stack: value1, value2, result 1529 program.jump_to_label(0, "equals") 1530 # True - produce result and branch. 1531 program.pop_top() # Stack: value1, value2 1532 program.pop_top() # Stack: value1 1533 program.pop_top() # Stack: 1534 program.load_const(1) # Stack: 1 1535 program.jump_to_label(None, "next") 1536 # False - test equality. 1537 program.start_label("equals") 1538 program.pop_top() # Stack: value1, value2 1539 program.dup_topx(2) # Stack: value1, value2, value1, value2 1540 program.compare_op("==") # Stack: value1, value2, result 1541 program.jump_to_label(0, "less") 1542 # True - produce result and branch. 1543 program.pop_top() # Stack: value1, value2 1544 program.pop_top() # Stack: value1 1545 program.pop_top() # Stack: 1546 program.load_const(0) # Stack: 0 1547 program.jump_to_label(None, "next") 1548 # False - produce result. 1549 program.start_label("less") 1550 program.pop_top() # Stack: value1, value2 1551 program.pop_top() # Stack: value1 1552 program.pop_top() # Stack: 1553 program.load_const(-1) # Stack: -1 1554 program.start_label("next") 1555 1556 lconst_0 = iconst_0 1557 lconst_1 = iconst_1 1558 1559 def ldc(self, arguments, program): 1560 program.load_const(self.class_file.constants[arguments[0] - 1]) 1561 1562 def ldc_w(self, arguments, program): 1563 program.load_const(self.class_file.constants[(arguments[0] << 8) + arguments[1] - 1]) 1564 1565 ldc2_w = ldc_w 1566 ldiv = idiv 1567 lload = iload 1568 lload_0 = iload_0 1569 lload_1 = iload_1 1570 lload_2 = iload_2 1571 lload_3 = iload_3 1572 lmul = imul 1573 lneg = ineg 1574 1575 def lookupswitch(self, arguments, program): 1576 1577 # Find the offset to the next 4 byte boundary in the code. 1578 1579 d, r = divmod(self.java_position, 4) 1580 to_boundary = (4 - r) % 4 1581 1582 # Get the pertinent arguments. 1583 1584 arguments = arguments[to_boundary:] 1585 default = (arguments[0] << 24) + (arguments[1] << 16) + (arguments[2] << 8) + arguments[3] 1586 npairs = (arguments[4] << 24) + (arguments[5] << 16) + (arguments[6] << 8) + arguments[7] 1587 1588 # Process the pairs. 1589 # NOTE: This is not the most optimal implementation. 1590 1591 pair_index = 8 1592 for pair in range(0, npairs): 1593 match = ((arguments[pair_index] << 24) + (arguments[pair_index + 1] << 16) + 1594 (arguments[pair_index + 2] << 8) + arguments[pair_index + 3]) 1595 offset = signed4((arguments[pair_index + 4] << 24) + (arguments[pair_index + 5] << 16) + 1596 (arguments[pair_index + 6] << 8) + arguments[pair_index + 7]) 1597 # Calculate the branch target. 1598 java_absolute = self.java_position + offset 1599 # Generate branching code. 1600 program.dup_top() # Stack: key, key 1601 program.load_const(match) # Stack: key, key, match 1602 program.compare_op("==") # Stack: key, result 1603 program.jump_to_label(0, "end") 1604 program.pop_top() # Stack: key 1605 program.pop_top() # Stack: 1606 program.jump_absolute(self.position_mapping[java_absolute]) 1607 # Generate the label for the end of the branching code. 1608 program.start_label("end") 1609 program.pop_top() # Stack: key 1610 # Update the index. 1611 pair_index += 8 1612 1613 # Generate the default. 1614 1615 java_absolute = self.java_position + default 1616 program.jump_absolute(self.position_mapping[java_absolute]) 1617 1618 lor = ior 1619 lrem = irem 1620 lreturn = ireturn 1621 lshl = ishl 1622 lshr = ishr 1623 lstore = istore 1624 lstore_0 = istore_0 1625 lstore_1 = istore_1 1626 lstore_2 = istore_2 1627 lstore_3 = istore_3 1628 lsub = isub 1629 lushr = iushr 1630 lxor = ixor 1631 1632 def monitorenter(self, arguments, program): 1633 # NOTE: To be implemented. 1634 pass 1635 1636 def monitorexit(self, arguments, program): 1637 # NOTE: To be implemented. 1638 pass 1639 1640 def multianewarray(self, arguments, program): 1641 index = (arguments[0] << 8) + arguments[1] 1642 dimensions = arguments[2] 1643 # Stack: count1, ..., countN-1, countN 1644 self._newarray(program) # Stack: count1, ..., countN-1, list 1645 for dimension in range(1, dimensions): 1646 program.rot_two() # Stack: count1, ..., list, countN-1 1647 program.build_list(0) # Stack: count1, ..., list, countN-1, new-list 1648 program.rot_three() # Stack: count1, ..., new-list, list, countN-1 1649 program.setup_loop() 1650 program.load_const(0) # Stack: count1, ..., new-list, list, countN-1, 0 1651 program.rot_two() # Stack: count1, ..., new-list, list, 0, countN-1 1652 program.load_global("range") # Stack: count1, ..., new-list, list, 0, countN-1, range 1653 program.rot_three() # Stack: count1, ..., new-list, list, range, 0, countN-1 1654 program.call_function(2) # Stack: count1, ..., new-list, list, range-list 1655 program.get_iter() # Stack: count1, ..., new-list, list, iter 1656 program.for_iter() # Stack: count1, ..., new-list, list, iter, value 1657 program.pop_top() # Stack: count1, ..., new-list, list, iter 1658 program.rot_three() # Stack: count1, ..., iter, new-list, list 1659 program.slice_0() # Stack: count1, ..., iter, new-list, list[:] 1660 program.dup_top() # Stack: count1, ..., iter, new-list, list[:], list[:] 1661 program.rot_three() # Stack: count1, ..., iter, list[:], new-list, list[:] 1662 program.rot_two() # Stack: count1, ..., iter, list[:], list[:], new-list 1663 program.dup_top() # Stack: count1, ..., iter, list[:], list[:], new-list, new-list 1664 program.load_attr("append") # Stack: count1, ..., iter, list[:], list[:], new-list, append 1665 program.rot_three() # Stack: count1, ..., iter, list[:], append, list[:], new-list 1666 program.rot_three() # Stack: count1, ..., iter, list[:], new-list, append, list[:] 1667 program.call_function(1) # Stack: count1, ..., iter, list[:], new-list, None 1668 program.pop_top() # Stack: count1, ..., iter, list[:], new-list 1669 program.rot_two() # Stack: count1, ..., iter, new-list, list[:] 1670 program.rot_three() # Stack: count1, ..., list[:], iter, new-list 1671 program.rot_three() # Stack: count1, ..., new-list, list[:], iter 1672 program.end_loop() # Stack: count1, ..., new-list, list[:], iter 1673 program.pop_top() # Stack: count1, ..., new-list 1674 1675 def new(self, arguments, program): 1676 # This operation is considered to be the same as the calling of the 1677 # initialisation method of the given class with no arguments. 1678 index = (arguments[0] << 8) + arguments[1] 1679 target_name = self.class_file.constants[index - 1].get_python_name() 1680 # NOTE: Using the string version of the name which may contain incompatible characters. 1681 program.load_global(str(target_name)) 1682 # NOTE: Unlike Java, we do not provide an object reference. Instead, a 1683 # NOTE: class reference is provided, and the invokespecial method's 1684 # NOTE: behaviour is changed. 1685 #program.call_function(0) 1686 1687 def newarray(self, arguments, program): 1688 # NOTE: Does not raise NegativeArraySizeException. 1689 # NOTE: Not using the arguments to type the list/array. 1690 self._newarray(program) 1691 1692 def nop(self, arguments, program): 1693 pass 1694 1695 def pop(self, arguments, program): 1696 program.pop_top() 1697 1698 pop2 = pop # ignoring Java stack value distinctions 1699 1700 def putfield(self, arguments, program): 1701 index = (arguments[0] << 8) + arguments[1] 1702 target_name = self.class_file.constants[index - 1].get_python_name() 1703 program.rot_two() 1704 # NOTE: Using the string version of the name which may contain incompatible characters. 1705 program.store_attr(str(target_name)) 1706 1707 def putstatic(self, arguments, program): 1708 index = (arguments[0] << 8) + arguments[1] 1709 target_name = self.class_file.constants[index - 1].get_python_name() 1710 # Get the class name instead of the fully qualified name. 1711 # NOTE: Need to find the class that declared the field being accessed. 1712 full_class_name = str(self.class_file.this_class.get_python_name()) 1713 class_name = full_class_name.split(".")[-1] 1714 program.load_global(class_name) # Stack: classref 1715 # NOTE: Using the string version of the name which may contain incompatible characters. 1716 program.store_attr(str(target_name)) 1717 1718 def ret(self, arguments, program): 1719 program.ret(arguments[0]) 1720 # Indicate that the finally handler is probably over. 1721 # NOTE: This is seemingly not guaranteed. 1722 self.in_finally = 0 1723 1724 def return_(self, arguments, program): 1725 program.load_const(None) 1726 program.return_value() 1727 1728 saload = laload 1729 sastore = lastore 1730 1731 def sipush(self, arguments, program): 1732 program.load_const((arguments[0] << 8) + arguments[1]) 1733 1734 def swap(self, arguments, program): 1735 program.rot_two() 1736 1737 def tableswitch(self, arguments, program): 1738 1739 # Find the offset to the next 4 byte boundary in the code. 1740 1741 d, r = divmod(self.java_position, 4) 1742 to_boundary = (4 - r) % 4 1743 1744 # Get the pertinent arguments. 1745 1746 arguments = arguments[to_boundary:] 1747 default = (arguments[0] << 24) + (arguments[1] << 16) + (arguments[2] << 8) + arguments[3] 1748 low = (arguments[4] << 24) + (arguments[5] << 16) + (arguments[6] << 8) + arguments[7] 1749 high = (arguments[8] << 24) + (arguments[9] << 16) + (arguments[10] << 8) + arguments[11] 1750 1751 # Process the jump entries. 1752 # NOTE: This is not the most optimal implementation. 1753 1754 jump_index = 8 1755 for jump in range(low, high + 1): 1756 offset = signed4((arguments[jump_index] << 24) + (arguments[jump_index + 1] << 16) + 1757 (arguments[jump_index + 2] << 8) + arguments[jump_index + 3]) 1758 1759 # Calculate the branch target. 1760 1761 java_absolute = self.java_position + offset 1762 1763 # Generate branching code. 1764 1765 program.dup_top() # Stack: key, key 1766 program.load_const(jump) # Stack: key, key, jump 1767 program.compare_op("==") # Stack: key, result 1768 program.jump_to_label(0, "end") 1769 program.pop_top() # Stack: key 1770 program.pop_top() # Stack: 1771 program.jump_absolute(self.position_mapping[java_absolute]) 1772 1773 # Generate the label for the end of the branching code. 1774 1775 program.start_label("end") 1776 program.pop_top() # Stack: key 1777 1778 # Update the index. 1779 1780 jump_index += 8 1781 1782 # Generate the default. 1783 1784 java_absolute = self.java_position + default 1785 program.jump_absolute(self.position_mapping[java_absolute]) 1786 1787 def wide(self, code, program): 1788 # NOTE: To be implemented. 1789 return number_of_arguments 1790 1791 def disassemble(class_file, method): 1792 disassembler = BytecodeDisassembler(class_file) 1793 disassembler.process(method, BytecodeDisassemblerProgram()) 1794 1795 class ClassTranslator: 1796 1797 """ 1798 A class which provides a wrapper around a class file and the means to 1799 translate the represented class into a Python class. 1800 """ 1801 1802 def __init__(self, class_file): 1803 1804 "Initialise the object with the given 'class_file'." 1805 1806 self.class_file = class_file 1807 self.filename = str(self.class_file.attributes[0].get_name()) 1808 1809 def translate_method(self, method): 1810 1811 "Translate the given 'method' - an object obtained from the class file." 1812 1813 translator = BytecodeTranslator(self.class_file) 1814 writer = BytecodeWriter() 1815 translator.process(method, writer) 1816 return translator, writer 1817 1818 def make_method(self, method_name, methods, global_names, namespace): 1819 1820 """ 1821 Make a dispatcher method with the given 'method_name', providing 1822 dispatch to the supplied type-sensitive 'methods', accessing the given 1823 'global_names' where necessary, and storing the new method in the 1824 'namespace' provided. 1825 """ 1826 1827 if method_name == "<init>": 1828 method_name = "__init__" 1829 1830 # Where only one method exists, just make an alias. 1831 1832 if len(methods) == 1: 1833 method, fn = methods[0] 1834 namespace[method_name] = fn 1835 return 1836 1837 # Find the maximum number of parameters involved. 1838 #maximum = max([len(method.get_descriptor()[0]) for method in methods]) 1839 1840 program = BytecodeWriter() 1841 1842 # NOTE: The code below should use dictionary-based dispatch for better performance. 1843 1844 program.load_fast(1) # Stack: arguments 1845 for method, fn in methods: 1846 program.setup_loop() 1847 program.dup_top() # Stack: arguments, arguments 1848 program.load_const(1) # Stack: arguments, arguments, 1 1849 program.store_fast(2) # Stack: arguments, arguments (found = 1) 1850 # Emit a list of parameter types. 1851 descriptor_types = method.get_descriptor()[0] 1852 for descriptor_type in descriptor_types: 1853 base_type, object_type, array_type = descriptor_type 1854 python_type = classfile.descriptor_base_type_mapping[base_type] 1855 if python_type == "instance": 1856 # NOTE: This will need extending. 1857 python_type = object_type 1858 program.load_global(python_type) # Stack: arguments, arguments, type, ... 1859 program.build_list(len(descriptor_types)) 1860 # Stack: arguments, arguments, types 1861 # Make a map of arguments and types. 1862 program.load_const(None) # Stack: arguments, arguments, types, None 1863 program.rot_three() # Stack: arguments, None, arguments, types 1864 program.build_tuple(3) # Stack: arguments, tuple 1865 program.load_global("map") # Stack: arguments, tuple, map 1866 program.rot_two() # Stack: arguments, map, tuple 1867 program.call_function_var(0) # Stack: arguments, list (mapping arguments to types) 1868 # Loop over each pair. 1869 program.get_iter() # Stack: arguments, iter 1870 program.for_iter() # Stack: arguments, iter, (argument, type) 1871 program.unpack_sequence(2) # Stack: arguments, iter, type, argument 1872 program.dup_top() # Stack: arguments, iter, type, argument, argument 1873 program.load_const(None) # Stack: arguments, iter, type, argument, argument, None 1874 program.compare_op("is") # Stack: arguments, iter, type, argument, result 1875 # Missing argument? 1876 program.jump_to_label(0, "present") 1877 program.pop_top() # Stack: arguments, iter, type, argument 1878 program.pop_top() # Stack: arguments, iter, type 1879 program.pop_top() # Stack: arguments, iter 1880 program.load_const(0) # Stack: arguments, iter, 0 1881 program.store_fast(2) # Stack: arguments, iter (found = 0) 1882 program.break_loop() 1883 # Argument was present. 1884 program.start_label("present") 1885 program.pop_top() # Stack: arguments, iter, type, argument 1886 program.rot_two() # Stack: arguments, iter, argument, type 1887 program.dup_top() # Stack: arguments, iter, argument, type, type 1888 program.load_const(None) # Stack: arguments, iter, argument, type, type, None 1889 program.compare_op("is") # Stack: arguments, iter, argument, type, result 1890 # Missing parameter type? 1891 program.jump_to_label(0, "present") 1892 program.pop_top() # Stack: arguments, iter, argument, type 1893 program.pop_top() # Stack: arguments, iter, argument 1894 program.pop_top() # Stack: arguments, iter 1895 program.load_const(0) # Stack: arguments, iter, 0 1896 program.store_fast(2) # Stack: arguments, iter (found = 0) 1897 program.break_loop() 1898 # Parameter was present. 1899 program.start_label("present") 1900 program.pop_top() # Stack: arguments, iter, argument, type 1901 program.build_tuple(2) # Stack: arguments, iter, (argument, type) 1902 program.load_global("isinstance") # Stack: arguments, iter, (argument, type), isinstance 1903 program.rot_two() # Stack: arguments, iter, isinstance, (argument, type) 1904 program.call_function_var(0) # Stack: arguments, iter, result 1905 program.jump_to_label(1, "match") 1906 program.pop_top() # Stack: arguments, iter 1907 program.load_const(0) # Stack: arguments, iter, 0 1908 program.store_fast(2) # Stack: arguments, iter (found = 0) 1909 program.break_loop() 1910 # Argument type and parameter type matched. 1911 program.start_label("match") 1912 program.pop_top() # Stack: arguments, iter 1913 program.end_loop() # Stack: arguments 1914 # If all the parameters matched, call the method. 1915 program.load_fast(2) # Stack: arguments, match 1916 program.jump_to_label(0, "failed") 1917 # All the parameters matched. 1918 program.pop_top() # Stack: arguments 1919 program.dup_top() # Stack: arguments, arguments 1920 program.load_fast(0) # Stack: arguments, arguments, self 1921 program.load_attr(str(method.get_python_name())) 1922 # Stack: arguments, arguments, method 1923 program.rot_two() # Stack: arguments, method, arguments 1924 program.call_function_var(0) # Stack: arguments, result 1925 program.return_value() 1926 # Try the next method if arguments or parameters were missing or incorrect. 1927 program.start_label("failed") 1928 program.pop_top() # Stack: arguments 1929 1930 # Raise an exception if nothing matched. 1931 # NOTE: Improve this. 1932 1933 program.load_const("No matching method") 1934 program.raise_varargs(1) 1935 program.load_const(None) 1936 program.return_value() 1937 1938 # Add the code as a method in the namespace. 1939 # NOTE: One actual parameter, flags as 71 apparently means that a list 1940 # NOTE: parameter is used in a method. 1941 1942 nlocals = program.max_locals + 1 1943 code = new.code(1, nlocals, program.max_stack_depth, 71, program.get_output(), 1944 tuple(program.get_constants()), tuple(program.get_names()), tuple(self.make_varnames(nlocals)), 1945 self.filename, method_name, 0, "") 1946 fn = new.function(code, global_names) 1947 namespace[method_name] = fn 1948 1949 def process(self, global_names): 1950 1951 """ 1952 Process the class, storing it in the 'global_names' dictionary provided. 1953 """ 1954 1955 namespace = {} 1956 1957 # Make the fields. 1958 1959 for field in self.class_file.fields: 1960 if classfile.has_flags(field.access_flags, [classfile.STATIC]): 1961 field_name = str(field.get_python_name()) 1962 namespace[field_name] = None 1963 1964 # Make the methods. 1965 1966 real_methods = {} 1967 for method in self.class_file.methods: 1968 real_method_name = str(method.get_name()) 1969 t, w = self.translate_method(method) 1970 1971 # Fix up special class initialisation methods. 1972 1973 if real_method_name == "<clinit>": 1974 flags = 3 1975 else: 1976 flags = 67 1977 nlocals = w.max_locals + 1 1978 nargs = len(method.get_descriptor()[0]) + 1 1979 1980 method_name = str(method.get_python_name()) 1981 1982 # NOTE: Add line number table later. 1983 1984 code = new.code(nargs, nlocals, w.max_stack_depth, flags, w.get_output(), tuple(w.get_constants()), tuple(w.get_names()), 1985 tuple(self.make_varnames(nlocals)), self.filename, method_name, 0, "") 1986 1987 # NOTE: May need more globals. 1988 1989 fn = new.function(code, global_names) 1990 1991 # Remember the real method name and the corresponding methods produced. 1992 1993 if not real_methods.has_key(real_method_name): 1994 real_methods[real_method_name] = [] 1995 real_methods[real_method_name].append((method, fn)) 1996 1997 # Fix up special class initialisation methods. 1998 1999 if real_method_name == "<clinit>": 2000 fn = classmethod(fn) 2001 2002 # Add the method to the class's namespace. 2003 2004 namespace[method_name] = fn 2005 2006 # Define superclasses. 2007 2008 bases = self.get_base_classes(global_names) 2009 2010 # Define method dispatchers. 2011 2012 for real_method_name, methods in real_methods.items(): 2013 if real_method_name != "<clinit>": 2014 self.make_method(real_method_name, methods, global_names, namespace) 2015 2016 # Use only the last part of the fully qualified name. 2017 2018 full_class_name = str(self.class_file.this_class.get_python_name()) 2019 class_name = full_class_name.split(".")[-1] 2020 cls = new.classobj(class_name, bases, namespace) 2021 global_names[cls.__name__] = cls 2022 2023 return cls 2024 2025 def get_base_classes(self, global_names): 2026 2027 """ 2028 Identify the superclass, then either load it from the given 2029 'global_names' if available, or import the class from its parent module. 2030 Return a tuple containing all base classes (typically a single element 2031 tuple). 2032 """ 2033 2034 original_name = str(self.class_file.super_class.get_name()) 2035 if original_name in ("java/lang/Object", "java/lang/Exception"): 2036 return () 2037 else: 2038 full_class_name = str(self.class_file.super_class.get_python_name()) 2039 class_name_parts = full_class_name.split(".") 2040 class_name = class_name_parts[-1] 2041 class_module_name = ".".join(class_name_parts[:-1]) 2042 if class_module_name == "": 2043 obj = global_names[class_name] 2044 else: 2045 print "Importing", class_module_name, class_name 2046 obj = __import__(class_module_name, global_names, {}, []) 2047 for class_name_part in class_name_parts[1:] or [class_name]: 2048 print "*", obj, class_name_part 2049 obj = getattr(obj, class_name_part) 2050 return (obj,) 2051 2052 def make_varnames(self, nlocals): 2053 2054 """ 2055 A utility method which invents variable names for the given number - 2056 'nlocals' - of local variables in a method. Returns a list of such 2057 variable names. 2058 """ 2059 2060 l = ["self"] 2061 for i in range(1, nlocals): 2062 l.append("_l%s" % i) 2063 return l[:nlocals] 2064 2065 def _map(*args): 2066 print args 2067 return apply(__builtins__.map, args) 2068 2069 def _isinstance(*args): 2070 print args 2071 return apply(__builtins__.isinstance, args) 2072 2073 if __name__ == "__main__": 2074 import sys 2075 import dis 2076 global_names = globals() 2077 #global_names["isinstance"] = _isinstance 2078 #global_names["map"] = _map 2079 for filename in sys.argv[1:]: 2080 f = open(filename, "rb") 2081 c = classfile.ClassFile(f.read()) 2082 translator = ClassTranslator(c) 2083 cls = translator.process(global_names) 2084 2085 # vim: tabstop=4 expandtab shiftwidth=4