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