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