javaclass

bytecode.py

26:1622bd94b804
2004-11-10 Paul Boddie Fixed the iinc translation.
     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         program.store_fast(arguments[0])  1213   1214     iload = fload  1215     iload_0 = fload_0  1216     iload_1 = fload_1  1217     iload_2 = fload_2  1218     iload_3 = fload_3  1219     imul = fmul  1220     ineg = fneg  1221   1222     def instanceof(self, arguments, program):  1223         index = (arguments[0] << 8) + arguments[1]  1224         target_name = self.class_file.constants[index - 1].get_python_name()  1225         # NOTE: Using the string version of the name which may contain incompatible characters.  1226         target_components = str(target_name).split("/")  1227   1228         program.load_global("isinstance")   # Stack: objectref, isinstance  1229         program.rot_two()                   # Stack: isinstance, objectref  1230         program.load_global(target_components[0])  1231         for target_component in target_components[1:]:  1232             program.load_attr(target_component)  1233         program.call_function(2)            # Stack: result  1234   1235     def _invoke(self, target_name, program):  1236         # NOTE: Using the string version of the name which may contain incompatible characters.  1237         program.load_attr(str(target_name)) # Stack: tuple, method  1238         program.rot_two()                   # Stack: method, tuple  1239         program.load_global("apply")        # Stack: method, tuple, apply  1240         program.rot_three()                 # Stack: apply, method, tuple  1241         program.call_function(2)  1242   1243     def invokeinterface(self, arguments, program):  1244         # NOTE: This implementation does not perform the necessary checks for  1245         # NOTE: signature-based polymorphism.  1246         # NOTE: Java rules not specifically obeyed.  1247         index = (arguments[0] << 8) + arguments[1]  1248         count = arguments[2]  1249         target_name = self.class_file.constants[index - 1].get_python_name()  1250         # Stack: objectref, arg1, arg2, ...  1251         program.build_tuple(count)          # Stack: objectref, tuple  1252         program.rot_two()                   # Stack: tuple, objectref  1253         self._invoke(target_name, program)  1254   1255     def invokespecial(self, arguments, program):  1256         # NOTE: This implementation does not perform the necessary checks for  1257         # NOTE: signature-based polymorphism.  1258         # NOTE: Java rules not specifically obeyed.  1259         index = (arguments[0] << 8) + arguments[1]  1260         target = self.class_file.constants[index - 1]  1261         target_name = target.get_python_name()  1262         # Get the number of parameters from the descriptor.  1263         count = len(target.get_descriptor()[0])  1264   1265         # Check for the method name and invoke superclasses where appropriate.  1266         if str(self.method.get_python_name()) == "__init__":  1267             program.build_tuple(count + 1)  # Stack: tuple  1268             # Must use the actual class.  1269             # NOTE: Verify this.  1270             program.load_global(str(self.class_file.this_class.get_python_name()))  1271                                             # Stack: tuple, classref  1272             program.load_attr("__bases__")  # Stack: tuple, bases  1273             program.dup_top()               # Stack: tuple, bases, bases  1274             program.load_global("len")      # Stack: tuple, bases, bases, len  1275             program.rot_two()               # Stack: tuple, bases, len, bases  1276             program.call_function(1)        # Stack: tuple, bases, #bases  1277             program.load_const(0)           # Stack: tuple, bases, #bases, 0  1278             program.compare_op("==")        # Stack: tuple, bases, result  1279             program.jump_to_label(1, "next")  1280             program.pop_top()               # Stack: tuple, bases  1281             program.load_const(0)           # Stack: tuple, bases, 0  1282             program.binary_subscr()         # Stack: tuple, bases[0]  1283             self._invoke(target_name, program)  1284             program.jump_to_label(None, "next2")  1285             program.start_label("next")  1286             program.pop_top()               # Stack: tuple, bases  1287             program.pop_top()               # Stack: tuple  1288             program.pop_top()               # Stack:  1289             program.start_label("next2")  1290   1291         elif str(target_name) == "__init__":  1292             # NOTE: Due to changes with the new instruction's implementation, the  1293             # NOTE: stack differs from that stated: objectref, arg1, arg2, ...  1294             # Stack: classref, arg1, arg2, ...  1295             program.build_tuple(count)          # Stack: classref, tuple  1296                                                 # NOTE: Stack: objectref, tuple  1297             program.load_global("apply")        # Stack: classref, tuple, apply  1298             program.rot_three()                 # Stack: apply, classref, tuple  1299             program.call_function(2)  1300   1301         else:  1302             program.build_tuple(count)          # Stack: objectref, tuple  1303             program.rot_two()                   # Stack: tuple, objectref  1304             self._invoke(target_name, program)  1305   1306     """  1307     def invokespecial(self, arguments, program):  1308         # NOTE: This implementation does not perform the necessary checks for  1309         # NOTE: signature-based polymorphism.  1310         # NOTE: Java rules not specifically obeyed.  1311         index = (arguments[0] << 8) + arguments[1]  1312         target = self.class_file.constants[index - 1]  1313         target_name = target.get_python_name()  1314         # Get the number of parameters from the descriptor.  1315         count = len(target.get_descriptor()[0])  1316         # Stack: objectref, arg1, arg2, ...  1317         program.build_tuple(count + 1)  # Stack: tuple  1318         # Use the class to provide access to static methods.  1319         program.load_name("self")       # Stack: tuple, self  1320         program.load_attr("__class__")  # Stack: tuple, class  1321         program.load_attr("__bases__")  # Stack: tuple, base-classes  1322         program.dup_top()               # Stack: tuple, base-classes, base-classes  1323         program.load_global("len")      # Stack: tuple, base-classes, base-classes, len  1324         program.rot_two()               # Stack: tuple, base-classes, len, base-classes  1325         program.call_function(1)        # Stack: tuple, base-classes, count  1326         program.load_const(0)           # Stack: tuple, base-classes, count, 0  1327         program.compare_op("==")        # Stack: tuple, base-classes, result  1328         program.jump_to_label(1, "next")  1329         program.pop_top()               # Stack: tuple, base-classes  1330         program.load_const(0)           # Stack: tuple, base-classes, 0  1331         program.binary_subscr()         # Stack: tuple, superclass  1332         self._invoke(target_name, program)  1333         program.jump_to_label(None, "next2")  1334         program.start_label("next")  1335         program.pop_top()               # Stack: tuple, base-classes  1336         program.pop_top()               # Stack: tuple  1337         program.pop_top()               # Stack:  1338         program.start_label("next2")  1339     """  1340   1341     def invokestatic(self, arguments, program):  1342         # NOTE: This implementation does not perform the necessary checks for  1343         # NOTE: signature-based polymorphism.  1344         # NOTE: Java rules not specifically obeyed.  1345         index = (arguments[0] << 8) + arguments[1]  1346         target = self.class_file.constants[index - 1]  1347         target_name = target.get_python_name()  1348         # Get the number of parameters from the descriptor.  1349         count = len(target.get_descriptor()[0])  1350         # Stack: arg1, arg2, ...  1351         program.build_tuple(count)      # Stack: tuple  1352         # Use the class to provide access to static methods.  1353         program.load_name("self")       # Stack: tuple, self  1354         program.load_attr("__class__")  # Stack: tuple, class  1355         self._invoke(target_name, program)  1356   1357     def invokevirtual (self, arguments, program):  1358         # NOTE: This implementation does not perform the necessary checks for  1359         # NOTE: signature-based polymorphism.  1360         # NOTE: Java rules not specifically obeyed.  1361         index = (arguments[0] << 8) + arguments[1]  1362         target = self.class_file.constants[index - 1]  1363         target_name = target.get_python_name()  1364         # Get the number of parameters from the descriptor.  1365         count = len(target.get_descriptor()[0])  1366         # Stack: objectref, arg1, arg2, ...  1367         program.build_tuple(count)          # Stack: objectref, tuple  1368         program.rot_two()                   # Stack: tuple, objectref  1369         self._invoke(target_name, program)  1370   1371     def ior(self, arguments, program):  1372         # NOTE: No type checking performed.  1373         program.binary_or()  1374   1375     irem = frem  1376     ireturn = freturn  1377   1378     def ishl(self, arguments, program):  1379         # NOTE: No type checking performed.  1380         # NOTE: Not verified.  1381         program.binary_lshift()  1382   1383     def ishr(self, arguments, program):  1384         # NOTE: No type checking performed.  1385         # NOTE: Not verified.  1386         program.binary_rshift()  1387   1388     istore = fstore  1389     istore_0 = fstore_0  1390     istore_1 = fstore_1  1391     istore_2 = fstore_2  1392     istore_3 = fstore_3  1393     isub = fsub  1394     iushr = ishr # Ignoring distinctions between arithmetic and logical shifts  1395   1396     def ixor(self, arguments, program):  1397         # NOTE: No type checking performed.  1398         program.binary_xor()  1399   1400     def jsr(self, arguments, program):  1401         offset = signed2((arguments[0] << 8) + arguments[1])  1402         java_absolute = self.java_position + offset  1403         # Store the address of the next instruction.  1404         program.load_const_ret(self.position_mapping[self.java_position + 3])  1405         program.jump_absolute(self.position_mapping[java_absolute])  1406   1407     def jsr_w(self, arguments, program):  1408         offset = signed4((arguments[0] << 24) + (arguments[1] << 16) + (arguments[2] << 8) + arguments[3])  1409         java_absolute = self.java_position + offset  1410         # Store the address of the next instruction.  1411         program.load_const_ret(self.position_mapping[self.java_position + 5])  1412         program.jump_absolute(self.position_mapping[java_absolute])  1413   1414     l2d = i2d  1415     l2f = i2f  1416   1417     def l2i(self, arguments, program):  1418         pass # Preserving Java semantics  1419   1420     ladd = iadd  1421     laload = iaload  1422     land = iand  1423     lastore = iastore  1424   1425     def lcmp(self, arguments, program):  1426         # NOTE: No type checking performed.  1427         program.dup_topx(2)                 # Stack: value1, value2, value1, value2  1428         program.compare_op(">")             # Stack: value1, value2, result  1429         program.jump_to_label(0, "equals")  1430         # True - produce result and branch.  1431         program.pop_top()                   # Stack: value1, value2  1432         program.pop_top()                   # Stack: value1  1433         program.pop_top()                   # Stack:  1434         program.load_const(1)               # Stack: 1  1435         program.jump_to_label(None, "next")  1436         # False - test equality.  1437         program.start_label("equals")  1438         program.pop_top()                   # Stack: value1, value2  1439         program.dup_topx(2)                 # Stack: value1, value2, value1, value2  1440         program.compare_op("==")            # Stack: value1, value2, result  1441         program.jump_to_label(0, "less")  1442         # True - produce result and branch.  1443         program.pop_top()                   # Stack: value1, value2  1444         program.pop_top()                   # Stack: value1  1445         program.pop_top()                   # Stack:  1446         program.load_const(0)               # Stack: 0  1447         program.jump_to_label(None, "next")  1448         # False - produce result.  1449         program.start_label("less")  1450         program.pop_top()                   # Stack: value1, value2  1451         program.pop_top()                   # Stack: value1  1452         program.pop_top()                   # Stack:  1453         program.load_const(-1)              # Stack: -1  1454         program.start_label("next")  1455   1456     lconst_0 = iconst_0  1457     lconst_1 = iconst_1  1458   1459     def ldc(self, arguments, program):  1460         program.load_const(self.class_file.constants[arguments[0] - 1])  1461   1462     def ldc_w(self, arguments, program):  1463         program.load_const(self.class_file.constants[(arguments[0] << 8) + arguments[1] - 1])  1464   1465     ldc2_w = ldc_w  1466     ldiv = idiv  1467     lload = iload  1468     lload_0 = iload_0  1469     lload_1 = iload_1  1470     lload_2 = iload_2  1471     lload_3 = iload_3  1472     lmul = imul  1473     lneg = ineg  1474   1475     def lookupswitch(self, arguments, program):  1476         # Find the offset to the next 4 byte boundary in the code.  1477         d, r = divmod(self.java_position, 4)  1478         to_boundary = (4 - r) % 4  1479         # Get the pertinent arguments.  1480         arguments = arguments[to_boundary:]  1481         default = (arguments[0] << 24) + (arguments[1] << 16) + (arguments[2] << 8) + arguments[3]  1482         npairs = (arguments[4] << 24) + (arguments[5] << 16) + (arguments[6] << 8) + arguments[7]  1483         # Process the pairs.  1484         # NOTE: This is not the most optimal implementation.  1485         pair_index = 8  1486         for pair in range(0, npairs):  1487             match = ((arguments[pair_index] << 24) + (arguments[pair_index + 1] << 16) +  1488                 (arguments[pair_index + 2] << 8) + arguments[pair_index + 3])  1489             offset = signed4((arguments[pair_index + 4] << 24) + (arguments[pair_index + 5] << 16) +  1490                 (arguments[pair_index + 6] << 8) + arguments[pair_index + 7])  1491             # Calculate the branch target.  1492             java_absolute = self.java_position + offset  1493             # Generate branching code.  1494             program.dup_top()                                           # Stack: key, key  1495             program.load_const(match)                                   # Stack: key, key, match  1496             program.compare_op("==")                                    # Stack: key, result  1497             program.jump_to_label(0, "end")  1498             program.pop_top()                                           # Stack: key  1499             program.pop_top()                                           # Stack:  1500             program.jump_absolute(self.position_mapping[java_absolute])  1501             # Generate the label for the end of the branching code.  1502             program.start_label("end")  1503             program.pop_top()                                           # Stack: key  1504             # Update the index.  1505             pair_index += 8  1506         # Generate the default.  1507         java_absolute = self.java_position + default  1508         program.jump_absolute(self.position_mapping[java_absolute])  1509   1510     lor = ior  1511     lrem = irem  1512     lreturn = ireturn  1513     lshl = ishl  1514     lshr = ishr  1515     lstore = istore  1516     lstore_0 = istore_0  1517     lstore_1 = istore_1  1518     lstore_2 = istore_2  1519     lstore_3 = istore_3  1520     lsub = isub  1521     lushr = iushr  1522     lxor = ixor  1523   1524     def monitorenter(self, arguments, program):  1525         # NOTE: To be implemented.  1526         pass  1527   1528     def monitorexit(self, arguments, program):  1529         # NOTE: To be implemented.  1530         pass  1531   1532     def multianewarray(self, arguments, program):  1533         # NOTE: To be implemented.  1534         pass  1535   1536     def new(self, arguments, program):  1537         # This operation is considered to be the same as the calling of the  1538         # initialisation method of the given class with no arguments.  1539         index = (arguments[0] << 8) + arguments[1]  1540         target_name = self.class_file.constants[index - 1].get_python_name()  1541         # NOTE: Using the string version of the name which may contain incompatible characters.  1542         program.load_global(str(target_name))  1543         # NOTE: Unlike Java, we do not provide an object reference. Instead, a  1544         # NOTE: class reference is provided, and the invokespecial method's  1545         # NOTE: behaviour is changed.  1546         #program.call_function(0)  1547   1548     def newarray(self, arguments, program):  1549         # NOTE: Does not raise NegativeArraySizeException.  1550         # NOTE: Not using the arguments to type the list/array.  1551         self._newarray(program)  1552   1553     def nop(self, arguments, program):  1554         pass  1555   1556     def pop(self, arguments, program):  1557         program.pop_top()  1558   1559     pop2 = pop # ignoring Java stack value distinctions  1560   1561     def putfield(self, arguments, program):  1562         index = (arguments[0] << 8) + arguments[1]  1563         target_name = self.class_file.constants[index - 1].get_python_name()  1564         program.rot_two()  1565         # NOTE: Using the string version of the name which may contain incompatible characters.  1566         program.store_attr(str(target_name))  1567   1568     def putstatic(self, arguments, program):  1569         index = (arguments[0] << 8) + arguments[1]  1570         target_name = self.class_file.constants[index - 1].get_python_name()  1571         program.load_name("self")  1572         program.load_attr("__class__")  1573         # NOTE: Using the string version of the name which may contain incompatible characters.  1574         program.store_attr(str(target_name))  1575   1576     def ret(self, arguments, program):  1577         program.ret(arguments[0])  1578         # Indicate that the finally handler is probably over.  1579         # NOTE: This is seemingly not guaranteed.  1580         self.in_finally = 0  1581   1582     def return_(self, arguments, program):  1583         program.load_const(None)  1584         program.return_value()  1585   1586     saload = laload  1587     sastore = lastore  1588   1589     def sipush(self, arguments, program):  1590         program.load_const((arguments[0] << 8) + arguments[1])  1591   1592     def swap(self, arguments, program):  1593         program.rot_two()  1594   1595     def tableswitch(self, arguments, program):  1596         # Find the offset to the next 4 byte boundary in the code.  1597         d, r = divmod(self.java_position, 4)  1598         to_boundary = (4 - r) % 4  1599         # Get the pertinent arguments.  1600         arguments = arguments[to_boundary:]  1601         default = (arguments[0] << 24) + (arguments[1] << 16) + (arguments[2] << 8) + arguments[3]  1602         low = (arguments[4] << 24) + (arguments[5] << 16) + (arguments[6] << 8) + arguments[7]  1603         high = (arguments[8] << 24) + (arguments[9] << 16) + (arguments[10] << 8) + arguments[11]  1604         # Process the jump entries.  1605         # NOTE: This is not the most optimal implementation.  1606         jump_index = 8  1607         for jump in range(low, high + 1):  1608             offset = signed4((arguments[jump_index] << 24) + (arguments[jump_index + 1] << 16) +  1609                 (arguments[jump_index + 2] << 8) + arguments[jump_index + 3])  1610             # Calculate the branch target.  1611             java_absolute = self.java_position + offset  1612             # Generate branching code.  1613             program.dup_top()                                           # Stack: key, key  1614             program.load_const(jump)                                    # Stack: key, key, jump  1615             program.compare_op("==")                                    # Stack: key, result  1616             program.jump_to_label(0, "end")  1617             program.pop_top()                                           # Stack: key  1618             program.pop_top()                                           # Stack:  1619             program.jump_absolute(self.position_mapping[java_absolute])  1620             # Generate the label for the end of the branching code.  1621             program.start_label("end")  1622             program.pop_top()                                           # Stack: key  1623             # Update the index.  1624             jump_index += 8  1625         # Generate the default.  1626         java_absolute = self.java_position + default  1627         program.jump_absolute(self.position_mapping[java_absolute])  1628   1629     def wide(self, code, program):  1630         # NOTE: To be implemented.  1631         return number_of_arguments  1632   1633 def disassemble(class_file, method):  1634     disassembler = BytecodeDisassembler(class_file)  1635     disassembler.process(method, BytecodeDisassemblerProgram())  1636   1637 def translate(class_file, method):  1638     translator = BytecodeTranslator(class_file)  1639     writer = BytecodeWriter()  1640     translator.process(method, writer)  1641     return translator, writer  1642   1643 def make_varnames(nlocals):  1644     l = ["self"]  1645     for i in range(1, nlocals):  1646         l.append("_l%s" % i)  1647     return l[:nlocals]  1648   1649 if __name__ == "__main__":  1650     import sys  1651     from classfile import ClassFile  1652     global_names = {}  1653     global_names.update(__builtins__.__dict__)  1654     for filename in sys.argv[1:]:  1655         f = open(filename, "rb")  1656         c = ClassFile(f.read())  1657         import dis, new  1658         namespace = {}  1659         for method in c.methods:  1660             nargs = len(method.get_descriptor()[0]) + 1  1661             t, w = translate(c, method)  1662             nlocals = w.max_locals + 1  1663             filename = str(c.attributes[0].get_name())  1664             method_name = str(method.get_python_name())  1665             code = new.code(nargs, nlocals, w.max_stack_depth, 67, w.get_output(), tuple(w.get_constants()), tuple(w.get_names()),  1666                 tuple(make_varnames(nlocals)), filename, method_name, 0, "")  1667             # NOTE: May need more globals.  1668             fn = new.function(code, global_names)  1669             namespace[method_name] = fn  1670         # NOTE: Define superclasses properly.  1671         if str(c.super_class.get_name()) not in ("java/lang/Object", "java/lang/Exception"):  1672             bases = (global_names[str(c.super_class.get_python_name())],)  1673         else:  1674             bases = ()  1675         cls = new.classobj(str(c.this_class.get_python_name()), bases, namespace)  1676         global_names[cls.__name__] = cls  1677   1678 # vim: tabstop=4 expandtab shiftwidth=4