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