javaclass

bytecode.py

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