javaclass

bytecode.py

8:60fb5a7b7181
2004-11-08 Paul Boddie Attempted to provide proper bytecode output with 16-bit operands, special "lazy" subvalues which should be correctly completed for each byte of uncomputed constants. Attempted to make branches perform correctly, presumably needing to involve offsets from the following instruction in the Python VM. Attempted to add support for the jsr/jsr_w/ret mechanism. Note that the usage of RAISE_VARARGS is probably inappropriate. Added convenience methods to get details of the names, constants and stack depth from the BytecodeWriter, although the globals have been removed as a separate mapping and a variable name registry is missing.
     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