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