javaclass

bytecode.py

7:91cceb1bd580
2004-11-07 Paul Boddie Fixed shifting operations, observing operator precedence. Added names support in BytecodeWriter. Reorganised the BytecodeReader class hierarchy to provide disassembling support separate from translation support. Added convenience functions for disassembly and translation. Introduced some additional bytecode writing methods. Improved the classfile module to support easier access to names and descriptors through RefInfo objects.
     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