javaclass

bytecode.py

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