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