javaclass

bytecode.py

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