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