javaclass

bytecode.py

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