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 # for access to Python bytecode values 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 # Mapping from values to indexes. 26 self.constants = {} 27 28 # Mapping from names to indexes. 29 # NOTE: This may be acquired from elsewhere. 30 self.globals = {} 31 32 # Mapping from names to indexes. 33 self.names = {} 34 35 def get_output(self): 36 output = [] 37 for element in self.output: 38 if isinstance(element, LazyValue): 39 output.append(chr(element.value)) 40 else: 41 output.append(chr(element)) 42 return "".join(output) 43 44 # Special methods. 45 46 def end_loop(self): 47 current_loop_start = self.loops.pop() 48 self.jump_absolute(current_loop_start) 49 self.output[current_loop_start + 1] = self.position 50 self.pop_block() 51 52 def jump_to_label(self, status, name): 53 # Record the instruction using the jump. 54 if not self.jumps.has_key(name): 55 self.jumps[name] = [] 56 self.jumps[name].append(self.position) 57 if status is None: 58 self.jump_forward() 59 elif status: 60 self.jump_if_true() 61 else: 62 self.jump_if_false() 63 64 def start_label(self, name): 65 # Fill in all jump instructions. 66 for jump_instruction in self.jumps[name]: 67 self.output[jump_instruction + 1] = self.position 68 69 # Complicated methods. 70 71 def load_const(self, value): 72 self.output.append(opmap["LOAD_CONST"]) 73 if not self.constants.has_key(value): 74 self.constants[value] = len(self.constants.keys()) 75 self.output.append(self.constants[value]) 76 self.position += 2 77 78 def load_global(self, name): 79 self.output.append(opmap["LOAD_GLOBAL"]) 80 if not self.globals.has_key(name): 81 self.globals[name] = len(self.globals.keys()) 82 self.output.append(self.globals[name]) 83 self.position += 2 84 85 def load_attr(self, name): 86 self.output.append(opmap["LOAD_ATTR"]) 87 if not self.names.has_key(name): 88 self.names[name] = len(self.names.keys()) 89 self.output.append(self.names[name]) 90 self.position += 2 91 92 def load_fast(self, index): 93 self.output.append(opmap["LOAD_FAST"]) 94 self.output.append(index) 95 self.position += 2 96 97 # Normal bytecode generators. 98 99 def for_iter(self): 100 self.loops.push(self.position) 101 self.output.append(opmap["FOR_ITER"]) 102 self.output.append(None) # To be filled in later 103 self.position += 2 104 105 def jump_if_false(self, offset=None): 106 self.output.append(opmap["JUMP_IF_FALSE"]) 107 self.output.append(offset) # May be filled in later 108 self.position += 2 109 110 def jump_if_true(self, offset=None): 111 self.output.append(opmap["JUMP_IF_TRUE"]) 112 self.output.append(offset) # May be filled in later 113 self.position += 2 114 115 def jump_forward(self, offset=None): 116 self.output.append(opmap["JUMP_FORWARD"]) 117 self.output.append(offset) # May be filled in later 118 self.position += 2 119 120 def build_tuple(self, count): 121 self.output.append(opmap["BUILD_TUPLE"]) 122 self.output.append(count) 123 self.position += 2 124 125 def rot_two(self): 126 self.output.append(opmap["ROT_TWO"]) 127 self.position += 1 128 129 def rot_three(self): 130 self.output.append(opmap["ROT_THREE"]) 131 self.position += 1 132 133 def rot_four(self): 134 self.output.append(opmap["ROT_FOUR"]) 135 self.position += 1 136 137 def call_function(self, count): 138 self.output.append(opmap["CALL_FUNCTION"]) 139 self.output.append(count) 140 self.position += 2 141 142 # Utility classes and functions. 143 144 class LazyDict(UserDict): 145 def __getitem__(self, key): 146 if not self.data.has_key(key): 147 self.data[key] = LazyValue() 148 return self.data[key] 149 def __setitem__(self, key, value): 150 if self.data.has_key(key): 151 existing_value = self.data[key] 152 if isinstance(existing_value, LazyValue): 153 existing_value.value = value 154 return 155 self.data[key] = value 156 157 class LazyValue: 158 def __init__(self, value=None): 159 self.value = value 160 161 def signed(value, limit): 162 163 """ 164 Return the signed integer from the unsigned 'value', where 'limit' (a value 165 one greater than the highest possible positive integer) is used to determine 166 whether a negative or positive result is produced. 167 """ 168 169 d, r = divmod(value, limit) 170 if d == 1: 171 mask = limit * 2 - 1 172 return -1 - (value ^ mask) 173 else: 174 return value 175 176 def signed2(value): 177 return signed(value, 0x8000) 178 179 def signed4(value): 180 return signed(value, 0x80000000) 181 182 # Bytecode conversion. 183 184 class BytecodeReader: 185 186 "A generic Java bytecode reader." 187 188 def __init__(self, class_file): 189 self.class_file = class_file 190 self.position_mapping = LazyDict() 191 192 def process(self, code, program): 193 self.java_position = 0 194 while self.java_position < len(code): 195 self.position_mapping[self.java_position] = program.position 196 bytecode = ord(code[self.java_position]) 197 mnemonic, number_of_arguments = self.java_bytecodes[bytecode] 198 self.process_bytecode(mnemonic, number_of_arguments, code, program) 199 200 def process_bytecode(self, mnemonic, number_of_arguments, code, program): 201 if number_of_arguments is not None: 202 arguments = [] 203 for j in range(0, number_of_arguments): 204 arguments.append(ord(code[self.java_position + 1 + j])) 205 206 # Call the handler. 207 getattr(self, mnemonic)(arguments, program) 208 else: 209 # Call the handler. 210 number_of_arguments = getattr(self, mnemonic)(code[self.java_position+1:], program) 211 212 self.java_position = self.java_position + 1 + number_of_arguments 213 214 java_bytecodes = { 215 # code : (mnemonic, number of following bytes, change in stack) 216 0 : ("nop", 0), 217 1 : ("aconst_null", 0), 218 2 : ("iconst_m1", 0), 219 3 : ("iconst_0", 0), 220 4 : ("iconst_1", 0), 221 5 : ("iconst_2", 0), 222 6 : ("iconst_3", 0), 223 7 : ("iconst_4", 0), 224 8 : ("iconst_5", 0), 225 9 : ("lconst_0", 0), 226 10 : ("lconst_1", 0), 227 11 : ("fconst_0", 0), 228 12 : ("fconst_1", 0), 229 13 : ("fconst_2", 0), 230 14 : ("dconst_0", 0), 231 15 : ("dconst_1", 0), 232 16 : ("bipush", 1), 233 17 : ("sipush", 2), 234 18 : ("ldc", 1), 235 19 : ("ldc_w", 2), 236 20 : ("ldc2_w", 2), 237 21 : ("iload", 1), 238 22 : ("lload", 1), 239 23 : ("fload", 1), 240 24 : ("dload", 1), 241 25 : ("aload", 1), 242 26 : ("iload_0", 0), 243 27 : ("iload_1", 0), 244 28 : ("iload_2", 0), 245 29 : ("iload_3", 0), 246 30 : ("lload_0", 0), 247 31 : ("lload_1", 0), 248 32 : ("lload_2", 0), 249 33 : ("lload_3", 0), 250 34 : ("fload_0", 0), 251 35 : ("fload_1", 0), 252 36 : ("fload_2", 0), 253 37 : ("fload_3", 0), 254 38 : ("dload_0", 0), 255 39 : ("dload_1", 0), 256 40 : ("dload_2", 0), 257 41 : ("dload_3", 0), 258 42 : ("aload_0", 0), 259 43 : ("aload_1", 0), 260 44 : ("aload_2", 0), 261 45 : ("aload_3", 0), 262 46 : ("iaload", 0), 263 47 : ("laload", 0), 264 48 : ("faload", 0), 265 49 : ("daload", 0), 266 50 : ("aaload", 0), 267 51 : ("baload", 0), 268 52 : ("caload", 0), 269 53 : ("saload", 0), 270 54 : ("istore", 1), 271 55 : ("lstore", 1), 272 56 : ("fstore", 1), 273 57 : ("dstore", 1), 274 58 : ("astore", 1), 275 59 : ("istore_0", 0), 276 60 : ("istore_1", 0), 277 61 : ("istore_2", 0), 278 62 : ("istore_3", 0), 279 63 : ("lstore_0", 0), 280 64 : ("lstore_1", 0), 281 65 : ("lstore_2", 0), 282 66 : ("lstore_3", 0), 283 67 : ("fstore_0", 0), 284 68 : ("fstore_1", 0), 285 69 : ("fstore_2", 0), 286 70 : ("fstore_3", 0), 287 71 : ("dstore_0", 0), 288 72 : ("dstore_1", 0), 289 73 : ("dstore_2", 0), 290 74 : ("dstore_3", 0), 291 75 : ("astore_0", 0), 292 76 : ("astore_1", 0), 293 77 : ("astore_2", 0), 294 78 : ("astore_3", 0), 295 79 : ("iastore", 0), 296 80 : ("lastore", 0), 297 81 : ("fastore", 0), 298 82 : ("dastore", 0), 299 83 : ("aastore", 0), 300 84 : ("bastore", 0), 301 85 : ("castore", 0), 302 86 : ("sastore", 0), 303 87 : ("pop", 0), 304 88 : ("pop2", 0), 305 89 : ("dup", 0), 306 90 : ("dup_x1", 0), 307 91 : ("dup_x2", 0), 308 92 : ("dup2", 0), 309 93 : ("dup2_x1", 0), 310 94 : ("dup2_x2", 0), 311 95 : ("swap", 0), 312 96 : ("iadd", 0), 313 97 : ("ladd", 0), 314 98 : ("fadd", 0), 315 99 : ("dadd", 0), 316 100 : ("isub", 0), 317 101 : ("lsub", 0), 318 102 : ("fsub", 0), 319 103 : ("dsub", 0), 320 104 : ("imul", 0), 321 105 : ("lmul", 0), 322 106 : ("fmul", 0), 323 107 : ("dmul", 0), 324 108 : ("idiv", 0), 325 109 : ("ldiv", 0), 326 110 : ("fdiv", 0), 327 111 : ("ddiv", 0), 328 112 : ("irem", 0), 329 113 : ("lrem", 0), 330 114 : ("frem", 0), 331 115 : ("drem", 0), 332 116 : ("ineg", 0), 333 117 : ("lneg", 0), 334 118 : ("fneg", 0), 335 119 : ("dneg", 0), 336 120 : ("ishl", 0), 337 121 : ("lshl", 0), 338 122 : ("ishr", 0), 339 123 : ("lshr", 0), 340 124 : ("iushr", 0), 341 125 : ("lushr", 0), 342 126 : ("iand", 0), 343 127 : ("land", 0), 344 128 : ("ior", 0), 345 129 : ("lor", 0), 346 130 : ("ixor", 0), 347 131 : ("lxor", 0), 348 132 : ("iinc", 2), 349 133 : ("i2l", 0), 350 134 : ("i2f", 0), 351 135 : ("i2d", 0), 352 136 : ("l2i", 0), 353 137 : ("l2f", 0), 354 138 : ("l2d", 0), 355 139 : ("f2i", 0), 356 140 : ("f2l", 0), 357 141 : ("f2d", 0), 358 142 : ("d2i", 0), 359 143 : ("d2l", 0), 360 144 : ("d2f", 0), 361 145 : ("i2b", 0), 362 146 : ("i2c", 0), 363 147 : ("i2s", 0), 364 148 : ("lcmp", 0), 365 149 : ("fcmpl", 0), 366 150 : ("fcmpg", 0), 367 151 : ("dcmpl", 0), 368 152 : ("dcmpg", 0), 369 153 : ("ifeq", 2), 370 154 : ("ifne", 2), 371 155 : ("iflt", 2), 372 156 : ("ifge", 2), 373 157 : ("ifgt", 2), 374 158 : ("ifle", 2), 375 159 : ("if_icmpeq", 2), 376 160 : ("if_icmpne", 2), 377 161 : ("if_icmplt", 2), 378 162 : ("if_icmpge", 2), 379 163 : ("if_icmpgt", 2), 380 164 : ("if_icmple", 2), 381 165 : ("if_acmpeq", 2), 382 166 : ("if_acmpne", 2), 383 167 : ("goto", 2), 384 168 : ("jsr", 2), 385 169 : ("ret", 1), 386 170 : ("tableswitch", None), # variable number of arguments 387 171 : ("lookupswitch", None), # variable number of arguments 388 172 : ("ireturn", 0), 389 173 : ("lreturn", 0), 390 174 : ("freturn", 0), 391 175 : ("dreturn", 0), 392 176 : ("areturn", 0), 393 177 : ("return", 0), 394 178 : ("getstatic", 2), 395 179 : ("putstatic", 2), 396 180 : ("getfield", 2), 397 181 : ("putfield", 2), 398 182 : ("invokevirtual", 2), 399 183 : ("invokespecial", 2), 400 184 : ("invokestatic", 2), 401 185 : ("invokeinterface", 4), 402 187 : ("new", 2), 403 188 : ("newarray", 1), 404 189 : ("anewarray", 2), 405 190 : ("arraylength", 0), 406 191 : ("athrow", 0), 407 192 : ("checkcast", 2), 408 193 : ("instanceof", 2), 409 194 : ("monitorenter", 0), 410 195 : ("monitorexit", 0), 411 196 : ("wide", None), # 3 or 5 arguments, stack changes according to modified element 412 197 : ("multianewarray", 3), 413 198 : ("ifnull", 2), 414 199 : ("ifnonnull", 2), 415 200 : ("goto_w", 4), 416 201 : ("jsr_w", 4), 417 } 418 419 class BytecodeDisassembler(BytecodeReader): 420 421 "A Java bytecode disassembler." 422 423 bytecode_methods = [spec[0] for spec in BytecodeReader.java_bytecodes.values()] 424 425 def __getattr__(self, name): 426 if name in self.bytecode_methods: 427 print name, 428 return self.generic 429 else: 430 raise AttributeError, name 431 432 def generic(self, arguments, program): 433 print arguments 434 435 class BytecodeDisassemblerProgram: 436 position = 0 437 438 class BytecodeTranslator(BytecodeReader): 439 440 "A Java bytecode translator which uses a Python bytecode writer." 441 442 def nop(self, arguments, program): 443 pass 444 445 def aaload(self, arguments, program): 446 # NOTE: No type checking performed. 447 program.binary_subscr() 448 449 def aastore(self, arguments, program): 450 # NOTE: No type checking performed. 451 # Stack: arrayref, index, value 452 program.rot_three() # Stack: value, arrayref, index 453 program.store_subscr() 454 455 def aconst_null(self, arguments, program): 456 program.load_global(None) 457 458 def aload(self, arguments, program): 459 program.load_fast(arguments[0]) 460 461 def aload_0(self, arguments, program): 462 program.load_fast(0) 463 464 def aload_1(self, arguments, program): 465 program.load_fast(1) 466 467 def aload_2(self, arguments, program): 468 program.load_fast(2) 469 470 def aload_3(self, arguments, program): 471 program.load_fast(3) 472 473 def anewarray(self, arguments, program): 474 # NOTE: Does not raise NegativeArraySizeException. 475 # NOTE: Not using the index to type the list/array. 476 index = (arguments[0] << 8) + arguments[1] 477 478 program.build_list() # Stack: count, list 479 program.rot_two() # Stack: list, count 480 program.setup_loop() 481 program.load_global("range") 482 program.load_const(0) # Stack: list, count, range, 0 483 program.rot_three() # Stack: list, 0, count, range 484 program.rot_three() # Stack: list, range, 0, count 485 program.call_function(2) # Stack: list, range_list 486 program.get_iter() # Stack: list, iter 487 program.for_iter() # Stack: list, iter, value 488 program.pop_top() # Stack: list, iter 489 program.rot_two() # Stack: iter, list 490 program.dup_top() # Stack: iter, list, list 491 program.load_attr("append") # Stack: iter, list, append 492 program.load_global(None) # Stack: iter, list, append, None 493 program.call_function(1) # Stack: iter, list, None 494 program.pop_top() # Stack: iter, list 495 program.rot_two() # Stack: list, iter 496 program.end_loop() # Back to for_iter above 497 498 def areturn(self, arguments, program): 499 program.return_value() 500 501 def arraylength(self, arguments, program): 502 program.load_global("len") # Stack: arrayref, len 503 program.rot_two() # Stack: len, arrayref 504 program.call_function(1) 505 506 def astore(self, arguments, program): 507 program.store_fast(arguments[0]) 508 509 def astore_0(self, arguments, program): 510 program.store_fast(0) 511 512 def astore_1(self, arguments, program): 513 program.store_fast(1) 514 515 def astore_2(self, arguments, program): 516 program.store_fast(2) 517 518 def astore_3(self, arguments, program): 519 program.store_fast(3) 520 521 def athrow(self, arguments, program): 522 # NOTE: NullPointerException not raised where null/None is found on the stack. 523 program.raise_varargs(1) 524 525 baload = aaload 526 bastore = aastore 527 528 def bipush(self, arguments, program): 529 program.load_const(arguments[0]) 530 531 caload = aaload 532 castore = aastore 533 534 def checkcast(self, arguments, program): 535 index = (arguments[0] << 8) + arguments[1] 536 target_name = self.class_file.constants[index - 1].get_name() 537 target_components = target_name.split("/") 538 539 program.dup_top() # Stack: objectref, objectref 540 program.load_global("isinstance") # Stack: objectref, objectref, isinstance 541 program.rot_two() # Stack: objectref, isinstance, objectref 542 program.load_global(target_components[0]) 543 for target_component in target_components[1:]: 544 program.load_attr(target_component) 545 program.call_function(2) # Stack: objectref 546 547 def d2f(self, arguments, program): 548 pass 549 550 def d2i(self, arguments, program): 551 program.load_global("int") # Stack: value, int 552 program.rot_two() # Stack: int, value 553 program.call_function(1) # Stack: result 554 555 d2l = d2i # Preserving Java semantics 556 557 def dadd(self, arguments, program): 558 # NOTE: No type checking performed. 559 program.binary_add() 560 561 daload = aaload 562 dastore = aastore 563 564 def dcmpg(self, arguments, program): 565 # NOTE: No type checking performed. 566 program.compare_op(">") 567 568 def dcmpl(self, arguments, program): 569 # NOTE: No type checking performed. 570 program.compare_op("<") 571 572 def dconst_0(self, arguments, program): 573 program.load_const(0.0) 574 575 def dconst_1(self, arguments, program): 576 program.load_const(1.0) 577 578 def ddiv(self, arguments, program): 579 # NOTE: No type checking performed. 580 program.binary_divide() 581 582 dload = aload 583 dload_0 = aload_0 584 dload_1 = aload_1 585 dload_2 = aload_2 586 dload_3 = aload_3 587 588 def dmul(self, arguments, program): 589 # NOTE: No type checking performed. 590 program.binary_multiply() 591 592 def dneg(self, arguments, program): 593 # NOTE: No type checking performed. 594 program.unary_negative() 595 596 def drem(self, arguments, program): 597 # NOTE: No type checking performed. 598 program.binary_modulo() 599 600 dreturn = areturn 601 dstore = astore 602 dstore_0 = astore_0 603 dstore_1 = astore_1 604 dstore_2 = astore_2 605 dstore_3 = astore_3 606 607 def dsub(self, arguments, program): 608 # NOTE: No type checking performed. 609 program.binary_subtract() 610 611 def dup(self, arguments, program): 612 program.dup_top() 613 614 def dup_x1(self, arguments, program): 615 # Ignoring computational type categories. 616 program.dup_top() 617 program.rot_three() 618 619 def dup_x2(self, arguments, program): 620 # Ignoring computational type categories. 621 program.dup_top() 622 program.rot_four() 623 624 dup2 = dup # Ignoring computational type categories 625 dup2_x1 = dup_x1 # Ignoring computational type categories 626 dup2_x2 = dup_x2 # Ignoring computational type categories 627 628 def f2d(self, arguments, program): 629 pass # Preserving Java semantics 630 631 def f2i(self, arguments, program): 632 program.load_global("int") # Stack: value, int 633 program.rot_two() # Stack: int, value 634 program.call_function(1) # Stack: result 635 636 f2l = f2i # Preserving Java semantics 637 fadd = dadd 638 faload = daload 639 fastore = dastore 640 fcmpg = dcmpg 641 fcmpl = dcmpl 642 fconst_0 = dconst_0 643 fconst_1 = dconst_1 644 645 def fconst_2(self, arguments, program): 646 program.load_const(2.0) 647 648 fdiv = ddiv 649 fload = dload 650 fload_0 = dload_0 651 fload_1 = dload_1 652 fload_2 = dload_2 653 fload_3 = dload_3 654 fmul = dmul 655 fneg = dneg 656 frem = drem 657 freturn = dreturn 658 fstore = dstore 659 fstore_0 = dstore_0 660 fstore_1 = dstore_1 661 fstore_2 = dstore_2 662 fstore_3 = dstore_3 663 fsub = dsub 664 665 def getfield(self, arguments, program): 666 index = (arguments[0] << 8) + arguments[1] 667 target_name = self.class_file.constants[index - 1].get_name() 668 # NOTE: Using the string version of the name which may contain incompatible characters. 669 program.load_attr(str(target_name)) 670 671 getstatic = getfield # Ignoring Java restrictions 672 673 def goto(self, arguments, program): 674 offset = signed2((arguments[0] << 8) + arguments[1]) 675 java_absolute = self.java_position + offset 676 program.jump_absolute(self.position_mapping[java_absolute]) 677 678 def goto_w(self, arguments, program): 679 offset = signed4((arguments[0] << 24) + (arguments[1] << 16) + (arguments[2] << 8) + arguments[3]) 680 java_absolute = self.java_position + offset 681 program.jump_absolute(self.position_mapping[java_absolute]) 682 683 def i2b(self, arguments, program): 684 pass 685 686 def i2c(self, arguments, program): 687 program.load_global("chr") # Stack: value, chr 688 program.rot_two() # Stack: chr, value 689 program.call_function(1) # Stack: result 690 691 def i2d(self, arguments, program): 692 program.load_global("float") # Stack: value, float 693 program.rot_two() # Stack: float, value 694 program.call_function(1) # Stack: result 695 696 i2f = i2d # Not distinguishing between float and double 697 698 def i2l(self, arguments, program): 699 pass # Preserving Java semantics 700 701 def i2s(self, arguments, program): 702 pass # Not distinguishing between int and short 703 704 iadd = fadd 705 iaload = faload 706 707 def iand(self, arguments, program): 708 # NOTE: No type checking performed. 709 program.binary_and() 710 711 iastore = fastore 712 713 def iconst_m1(self, arguments, program): 714 program.load_const(-1) 715 716 def iconst_0(self, arguments, program): 717 program.load_const(0) 718 719 def iconst_1(self, arguments, program): 720 program.load_const(1) 721 722 def iconst_2(self, arguments, program): 723 program.load_const(2) 724 725 def iconst_3(self, arguments, program): 726 program.load_const(3) 727 728 def iconst_4(self, arguments, program): 729 program.load_const(4) 730 731 def iconst_5(self, arguments, program): 732 program.load_const(5) 733 734 idiv = fdiv 735 736 def _if_xcmpx(self, arguments, program, op): 737 offset = signed2((arguments[0] << 8) + arguments[1]) 738 java_absolute = self.java_position + offset 739 program.compare_op(op) 740 program.jump_to_label(0, "next") # skip if false 741 program.goto(offset) 742 program.start_label("next") 743 744 def if_acmpeq(self, arguments, program): 745 # NOTE: No type checking performed. 746 self._if_xcmpx(arguments, program, "is") 747 748 def if_acmpne(self, arguments, program): 749 # NOTE: No type checking performed. 750 self._if_xcmpx(arguments, program, "is not") 751 752 def if_icmpeq(self, arguments, program): 753 # NOTE: No type checking performed. 754 self._if_xcmpx(arguments, program, "==") 755 756 def if_icmpne(self, arguments, program): 757 # NOTE: No type checking performed. 758 self._if_xcmpx(arguments, program, "!=") 759 760 def if_icmplt(self, arguments, program): 761 # NOTE: No type checking performed. 762 self._if_xcmpx(arguments, program, "<") 763 764 def if_icmpge(self, arguments, program): 765 # NOTE: No type checking performed. 766 self._if_xcmpx(arguments, program, ">=") 767 768 def if_icmpgt(self, arguments, program): 769 # NOTE: No type checking performed. 770 self._if_xcmpx(arguments, program, ">") 771 772 def if_icmple(self, arguments, program): 773 # NOTE: No type checking performed. 774 self._if_xcmpx(arguments, program, "<=") 775 776 def ifeq(self, arguments, program): 777 # NOTE: No type checking performed. 778 program.load_const(0) 779 self._if_xcmpx(arguments, program, "==") 780 781 def ifne(self, arguments, program): 782 # NOTE: No type checking performed. 783 program.load_const(0) 784 self._if_xcmpx(arguments, program, "!=") 785 786 def iflt(self, arguments, program): 787 # NOTE: No type checking performed. 788 program.load_const(0) 789 self._if_xcmpx(arguments, program, "<") 790 791 def ifge(self, arguments, program): 792 # NOTE: No type checking performed. 793 program.load_const(0) 794 self._if_xcmpx(arguments, program, ">=") 795 796 def ifgt(self, arguments, program): 797 # NOTE: No type checking performed. 798 program.load_const(0) 799 self._if_xcmpx(arguments, program, ">") 800 801 def ifle(self, arguments, program): 802 # NOTE: No type checking performed. 803 program.load_const(0) 804 self._if_xcmpx(arguments, program, "<=") 805 806 def ifnonnull(self, arguments, program): 807 # NOTE: No type checking performed. 808 program.load_const(None) 809 self._if_xcmpx(arguments, program, "is not") 810 811 def ifnull(self, arguments, program): 812 # NOTE: No type checking performed. 813 program.load_const(None) 814 self._if_xcmpx(arguments, program, "is") 815 816 def iinc(self, arguments, program): 817 # NOTE: No type checking performed. 818 program.load_fast(arguments[0]) 819 program.load_const(arguments[1]) 820 program.binary_add() 821 822 iload = fload 823 iload_0 = fload_0 824 iload_1 = fload_1 825 iload_2 = fload_2 826 iload_3 = fload_3 827 imul = fmul 828 ineg = fneg 829 830 def instanceof(self, arguments, program): 831 index = (arguments[0] << 8) + arguments[1] 832 target_name = self.class_file.constants[index - 1].get_name() 833 target_components = target_name.split("/") 834 835 program.load_global("isinstance") # Stack: objectref, isinstance 836 program.rot_two() # Stack: isinstance, objectref 837 program.load_global(target_components[0]) 838 for target_component in target_components[1:]: 839 program.load_attr(target_component) 840 program.call_function(2) # Stack: result 841 842 def _invoke(self, target_name, program): 843 program.rot_two() # Stack: tuple, objectref 844 # NOTE: Using the string version of the name which may contain incompatible characters. 845 program.load_attr(str(target_name)) # Stack: tuple, method 846 program.rot_two() # Stack: method, tuple 847 program.load_global("apply") # Stack: method, tuple, apply 848 program.rot_three() # Stack: apply, method, tuple 849 program.call_function(2) 850 851 def invokeinterface(self, arguments, program): 852 # NOTE: This implementation does not perform the necessary checks for 853 # NOTE: signature-based polymorphism. 854 # NOTE: Java rules not specifically obeyed. 855 index = (arguments[0] << 8) + arguments[1] 856 count = arguments[2] 857 target_name = self.class_file.constants[index - 1].get_name() 858 # Stack: objectref, arg1, arg2, ... 859 program.build_tuple(count) # Stack: objectref, tuple 860 self._invoke(target_name, program) 861 862 def invokespecial(self, arguments, program): 863 # NOTE: This implementation does not perform the necessary checks for 864 # NOTE: signature-based polymorphism. 865 # NOTE: Java rules not specifically obeyed. 866 index = (arguments[0] << 8) + arguments[1] 867 target = self.class_file.constants[index - 1] 868 target_name = target.get_name() 869 # Get the number of parameters from the descriptor. 870 count = len(target.get_descriptor()[0]) 871 # Stack: objectref, arg1, arg2, ... 872 program.build_tuple(count) # Stack: objectref, tuple 873 self._invoke(target_name, program) 874 875 def invokestatic(self, arguments, program): 876 # NOTE: This implementation does not perform the necessary checks for 877 # NOTE: signature-based polymorphism. 878 # NOTE: Java rules not specifically obeyed. 879 index = (arguments[0] << 8) + arguments[1] 880 target = self.class_file.constants[index - 1] 881 target_name = target.get_name() 882 # Get the number of parameters from the descriptor. 883 count = len(target.get_descriptor()[0]) 884 # Stack: arg1, arg2, ... 885 program.build_tuple(count) # Stack: tuple 886 # NOTE: Should probably use Python static methods. 887 program.load_name("self") # Stack: tuple, self 888 self._invoke(target_name, program) 889 890 invokevirtual = invokeinterface # Ignoring Java rules 891 892 def ior(self, arguments, program): 893 # NOTE: No type checking performed. 894 program.binary_or() 895 896 irem = frem 897 ireturn = freturn 898 899 def ishl(self, arguments, program): 900 # NOTE: No type checking performed. 901 # NOTE: Not verified. 902 program.binary_lshift() 903 904 def ishr(self, arguments, program): 905 # NOTE: No type checking performed. 906 # NOTE: Not verified. 907 program.binary_rshift() 908 909 istore = fstore 910 istore_0 = fstore_0 911 istore_1 = fstore_1 912 istore_2 = fstore_2 913 istore_3 = fstore_3 914 isub = fsub 915 iushr = ishr # Ignoring distinctions between arithmetic and logical shifts 916 917 def ixor(self, arguments, program): 918 # NOTE: No type checking performed. 919 program.binary_xor() 920 921 def jsr(self, arguments, program): 922 offset = signed2((arguments[0] << 8) + arguments[1]) 923 java_absolute = self.java_position + offset 924 # Store the address of the next instruction. 925 program.load_const(self.position_mapping[self.java_position + 3]) 926 program.jump_absolute(self.position_mapping[java_absolute]) 927 928 def jsr_w(self, arguments, program): 929 offset = signed4((arguments[0] << 24) + (arguments[1] << 16) + (arguments[2] << 8) + arguments[3]) 930 java_absolute = self.java_position + offset 931 # Store the address of the next instruction. 932 program.load_const(self.position_mapping[self.java_position + 5]) 933 program.jump_absolute(self.position_mapping[java_absolute]) 934 935 l2d = i2d 936 l2f = i2f 937 938 def l2i(self, arguments, program): 939 pass # Preserving Java semantics 940 941 ladd = iadd 942 laload = iaload 943 land = iand 944 lastore = iastore 945 946 def lcmp(self, arguments, program): 947 # NOTE: No type checking performed. 948 program.dup_topx(2) # Stack: value1, value2, value1, value2 949 program.compare_op(">") # Stack: value1, value2, result 950 program.jump_to_label(0, "equals") 951 # True - produce result and branch. 952 program.pop_top() # Stack: value1, value2 953 program.pop_top() # Stack: value1 954 program.pop_top() # Stack: 955 program.load_const(1) # Stack: 1 956 program.jump_to_label(None, "next") 957 # False - test equality. 958 program.start_label("equals") 959 program.pop_top() # Stack: value1, value2 960 program.dup_topx(2) # Stack: value1, value2, value1, value2 961 program.compare_op("==") # Stack: value1, value2, result 962 program.jump_to_label(0, "less") 963 # True - produce result and branch. 964 program.pop_top() # Stack: value1, value2 965 program.pop_top() # Stack: value1 966 program.pop_top() # Stack: 967 program.load_const(0) # Stack: 0 968 program.jump_to_label(None, "next") 969 # False - produce result. 970 program.start_label("less") 971 program.pop_top() # Stack: value1, value2 972 program.pop_top() # Stack: value1 973 program.pop_top() # Stack: 974 program.load_const(-1) # Stack: -1 975 program.start_label("next") 976 977 lconst_0 = iconst_0 978 lconst_1 = iconst_1 979 980 def ldc(self, arguments, program): 981 program.load_const(self.class_file.constants[arguments[0] - 1]) 982 983 def ldc_w(self, arguments, program): 984 program.load_const(self.class_file.constants[(arguments[0] << 8) + arguments[1] - 1]) 985 986 ldc2_w = ldc_w 987 ldiv = idiv 988 lload = iload 989 lload_0 = iload_0 990 lload_1 = iload_1 991 lload_2 = iload_2 992 lload_3 = iload_3 993 lmul = imul 994 lneg = ineg 995 996 def lookupswitch(self, arguments, program): 997 # Find the offset to the next 4 byte boundary in the code. 998 d, r = divmod(self.java_position, 4) 999 to_boundary = (4 - r) % 4 1000 # Get the pertinent arguments. 1001 arguments = arguments[to_boundary:] 1002 default = (arguments[0] << 24) + (arguments[1] << 16) + (arguments[2] << 8) + arguments[3] 1003 npairs = (arguments[4] << 24) + (arguments[5] << 16) + (arguments[6] << 8) + arguments[7] 1004 # Process the pairs. 1005 # NOTE: This is not the most optimal implementation. 1006 pair_index = 8 1007 for pair in range(0, npairs): 1008 match = ((arguments[pair_index] << 24) + (arguments[pair_index + 1] << 16) + 1009 (arguments[pair_index + 2] << 8) + arguments[pair_index + 3]) 1010 offset = signed4((arguments[pair_index + 4] << 24) + (arguments[pair_index + 5] << 16) + 1011 (arguments[pair_index + 6] << 8) + arguments[pair_index + 7]) 1012 # Calculate the branch target. 1013 java_absolute = self.java_position + offset 1014 # Generate branching code. 1015 program.dup_top() # Stack: key, key 1016 program.load_const(match) # Stack: key, key, match 1017 program.compare_op("==") # Stack: key, result 1018 program.jump_to_label(0, "end" + str(pair)) 1019 program.pop_top() # Stack: key 1020 program.pop_top() # Stack: 1021 program.jump_absolute(self.position_mapping[java_absolute]) 1022 # Generate the label for the end of the branching code. 1023 program.start_label("end" + str(pair)) 1024 program.pop_top() # Stack: key 1025 # Update the index. 1026 pair_index += 8 1027 # Generate the default. 1028 java_absolute = self.java_position + default 1029 program.jump_absolute(self.position_mapping[java_absolute]) 1030 1031 lor = ior 1032 lrem = irem 1033 lreturn = ireturn 1034 lshl = ishl 1035 lshr = ishr 1036 lstore = istore 1037 lstore_0 = istore_0 1038 lstore_1 = istore_1 1039 lstore_2 = istore_2 1040 lstore_3 = istore_3 1041 lsub = isub 1042 lushr = iushr 1043 lxor = ixor 1044 1045 def monitorenter(self, arguments, program): 1046 # NOTE: To be implemented. 1047 pass 1048 1049 def monitorexit(self, arguments, program): 1050 # NOTE: To be implemented. 1051 pass 1052 1053 def multianewarray(self, arguments, program): 1054 program.build_list() # Stack: count1, count2, ..., countN, list 1055 program.rot_two() # Stack: count1, count2, ..., list, countN 1056 program.setup_loop() 1057 program.load_global("range") 1058 program.load_const(0) # Stack: list, count, range, 0 1059 program.rot_three() # Stack: list, 0, count, range 1060 program.rot_three() # Stack: list, range, 0, count 1061 program.call_function(2) # Stack: list, range_list 1062 program.get_iter() # Stack: list, iter 1063 program.for_iter() # Stack: list, iter, value 1064 for i in range(0, arguments[2]): 1065 # Stack: 1066 self.anewarray(arguments, program) # Stack: list, iter 1067 1068 def wide(self, code, program): 1069 # NOTE: To be implemented. 1070 return number_of_arguments 1071 1072 def disassemble(class_file, code): 1073 disassembler = BytecodeDisassembler(class_file) 1074 disassembler.process(code, BytecodeDisassemblerProgram()) 1075 1076 def translate(class_file, code): 1077 translator = BytecodeTranslator(class_file) 1078 writer = BytecodeWriter() 1079 translator.process(code, writer) 1080 return writer 1081 1082 if __name__ == "__main__": 1083 import sys 1084 from classfile import ClassFile 1085 f = open(sys.argv[1]) 1086 c = ClassFile(f.read()) 1087 1088 # vim: tabstop=4 expandtab shiftwidth=4