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