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