javaclass

bytecode.py

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