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