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