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