javaclass

bytecode.py

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