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