javaclass

bytecode.py

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