javaclass

bytecode.py

102:7c84cbd6155b
2005-01-10 Paul Boddie Added various collections, iterators and maps.
     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 import classfile    11 from dis import cmp_op # for access to Python bytecode values and operators    12 try:    13     from dis import opmap    14 except ImportError:    15     from dis import opname    16     opmap = {}    17     for i in range(0, len(opname)):    18         opmap[opname[i]] = i    19 from UserDict import UserDict    20 import new    21     22 # Bytecode production classes.    23     24 class BytecodeWriter:    25     26     "A Python bytecode writer."    27     28     def __init__(self):    29     30         "Initialise the writer."    31     32         # A stack of loop start instructions corresponding to loop blocks.    33         self.loops = []    34     35         # A stack of loop block or exception block start positions.    36         self.blocks = []    37     38         # A stack of exception block handler pointers.    39         self.exception_handlers = []    40     41         # A dictionary mapping labels to jump instructions referencing such labels.    42         self.jumps = {}    43     44         # The output values, including "lazy" subvalues which will need evaluating.    45         self.output = []    46     47         # The current Python bytecode instruction position.    48         self.position = 0    49     50         # Stack depth estimation.    51         self.stack_depth = 0    52         self.max_stack_depth = 0    53     54         # Local variable estimation.    55         self.max_locals = 0    56     57         # Mapping from values to indexes.    58         self.constants = {}    59     60         # Mapping from names to indexes.    61         # NOTE: This may be acquired from elsewhere.    62         #self.globals = {}    63     64         # Mapping from names to indexes.    65         self.names = {}    66     67         # A list of constants used as exception handler return addresses.    68         self.constants_for_exceptions = []    69     70         # A list of external names.    71         self.external_names = []    72     73     def get_output(self):    74     75         "Return the output of the writer as a string."    76     77         output = []    78         for element in self.output:    79             if isinstance(element, LazySubValue):    80                 value = element.value    81             else:    82                 value = element    83             # NOTE: ValueError gets raised for bad values here.    84             output.append(chr(value))    85         return "".join(output)    86     87     def get_constants(self):    88     89         """    90         Return a list of constants with ordering significant to the code    91         employing them.    92         """    93     94         l = self._get_list(self._invert(self.constants))    95         result = []    96         for i in l:    97             if isinstance(i, LazyValue):    98                 result.append(i.get_value())    99             else:   100                 result.append(i)   101         return result   102    103     #def get_globals(self):   104     #    return self._get_list(self._invert(self.globals))   105    106     def get_names(self):   107    108         """   109         Return a list of names with ordering significant to the code employing   110         them.   111         """   112    113         return self._get_list(self._invert(self.names))   114    115     def _invert(self, d):   116    117         """   118         Return a new dictionary whose key-to-value mapping is in the inverse of   119         that found in 'd'.   120         """   121    122         inverted = {}   123         for k, v in d.items():   124             inverted[v] = k   125         return inverted   126    127     def _get_list(self, d):   128    129         """   130         Traverse the dictionary 'd' returning a list whose values appear at the   131         position denoted by each value's key in 'd'.   132         """   133    134         l = []   135         for i in range(0, len(d.keys())):   136             l.append(d[i])   137         return l   138    139     # Administrative methods.   140    141     def update_stack_depth(self, change):   142    143         """   144         Given the stated 'change' in stack depth, update the maximum stack depth   145         where appropriate.   146         """   147    148         self.stack_depth += change   149         if self.stack_depth > self.max_stack_depth:   150             self.max_stack_depth = self.stack_depth   151    152     def update_locals(self, index):   153    154         """   155         Given the stated 'index' of a local variable, update the maximum local   156         variable index where appropriate.   157         """   158    159         if index > self.max_locals:   160             self.max_locals = index   161    162     # Special methods.   163    164     def _write_value(self, value):   165    166         """   167         Write the given 'value' at the current output position.   168         """   169    170         if isinstance(value, LazyValue):   171             # NOTE: Assume a 16-bit value.   172             self.output.append(value.values[0])   173             self.output.append(value.values[1])   174             self.position += 2   175         elif value <= 0xffff:   176             self.output.append(value & 0xff)   177             self.output.append((value & 0xff00) >> 8)   178             self.position += 2   179         else:   180             # NOTE: EXTENDED_ARG not yet supported.   181             raise ValueError, value   182    183     def _rewrite_value(self, position, value):   184    185         """   186         At the given output 'position', rewrite the given 'value'.   187         """   188    189         # NOTE: Assume a 16-bit value.   190         if value <= 0xffff:   191             self.output[position] = (value & 0xff)   192             self.output[position + 1] = ((value & 0xff00) >> 8)   193         else:   194             # NOTE: EXTENDED_ARG not yet supported.   195             raise ValueError, value   196    197     # Higher level methods.   198    199     def use_external_name(self, name):   200         # NOTE: Remove array and object indicators.   201         self.external_names.append(name)   202    203     def setup_loop(self):   204         self.loops.append(self.position)   205         self.output.append(opmap["SETUP_LOOP"])   206         self.position += 1   207         self._write_value(0) # To be filled in later   208    209     def end_loop(self):   210         current_loop_start = self.loops.pop()   211         current_loop_real_start = self.blocks.pop()   212         #print "<", self.blocks, current_loop_real_start   213         # Fix the iterator delta.   214         # NOTE: Using 3 as the assumed length of the FOR_ITER instruction.   215         self.jump_absolute(current_loop_real_start)   216         self._rewrite_value(current_loop_real_start + 1, self.position - current_loop_real_start - 3)   217         self.pop_block()   218         # Fix the loop delta.   219         # NOTE: Using 3 as the assumed length of the SETUP_LOOP instruction.   220         self._rewrite_value(current_loop_start + 1, self.position - current_loop_start - 3)   221    222     def jump_to_label(self, status, name):   223         # Record the instruction using the jump.   224         jump_instruction = self.position   225         if status is None:   226             self.jump_forward()   227         elif status:   228             self.jump_if_true()   229         else:   230             self.jump_if_false()   231         # Record the following instruction, too.   232         if not self.jumps.has_key(name):   233             self.jumps[name] = []   234         self.jumps[name].append((jump_instruction, self.position))   235    236     def start_label(self, name):   237         # Fill in all jump instructions.   238         for jump_instruction, following_instruction in self.jumps[name]:   239             self._rewrite_value(jump_instruction + 1, self.position - following_instruction)   240         del self.jumps[name]   241    242     def load_const_ret(self, value):   243         self.constants_for_exceptions.append(value)   244         self.load_const(value)   245    246     def ret(self, index):   247         self.load_fast(index)   248    249         # Previously, the constant stored on the stack by jsr/jsr_w was stored   250         # in a local variable. In the JVM, extracting the value from the local   251         # variable and jumping can be done at runtime. In the Python VM, any   252         # jump target must be known in advance and written into the bytecode.   253    254         for constant in self.constants_for_exceptions:   255             self.dup_top()              # Stack: actual-address, actual-address   256             self.load_const(constant)   # Stack: actual-address, actual-address, suggested-address   257             self.compare_op("==")       # Stack: actual-address, result   258             self.jump_to_label(0, "const")   259             self.pop_top()              # Stack: actual-address   260             self.pop_top()              # Stack:   261             self.jump_absolute(constant)   262             self.start_label("const")   263             self.pop_top()              # Stack: actual-address   264    265         # NOTE: If we get here, something is really wrong.   266    267         self.pop_top()              # Stack:   268    269     def setup_except(self, target):   270         self.blocks.append(self.position)   271         self.exception_handlers.append(target)   272         #print "-", self.position, target   273         self.output.append(opmap["SETUP_EXCEPT"])   274         self.position += 1   275         self._write_value(0) # To be filled in later   276    277     def setup_finally(self, target):   278         self.blocks.append(self.position)   279         self.exception_handlers.append(target)   280         #print "-", self.position, target   281         self.output.append(opmap["SETUP_FINALLY"])   282         self.position += 1   283         self._write_value(0) # To be filled in later   284    285     def end_exception(self):   286         current_exception_start = self.blocks.pop()   287         # Convert the "lazy" absolute value.   288         current_exception_target = self.exception_handlers.pop()   289         target = current_exception_target.get_value()   290         #print "*", current_exception_start, target   291         # NOTE: Using 3 as the assumed length of the SETUP_* instruction.   292         self._rewrite_value(current_exception_start + 1, target - current_exception_start - 3)   293    294     def start_handler(self, exc_name, class_file):   295    296         # Where handlers are begun, produce bytecode to test the type of   297         # the exception.   298         # NOTE: Since RAISE_VARARGS and END_FINALLY are not really documented,   299         # NOTE: we store the top of the stack and use it later to trigger the   300         # NOTE: magic processes when re-raising.   301         self.use_external_name(str(exc_name))   302    303         self.rot_two()                      # Stack: raised-exception, exception   304         self.dup_top()                      # Stack: raised-exception, exception, exception   305         # Handled exceptions are wrapped before being thrown.   306         self.load_global("Exception")       # Stack: raised-exception, exception, exception, Exception   307         self.compare_op("exception match")  # Stack: raised-exception, exception, result   308         self.jump_to_label(0, "next")   309         self.pop_top()                      # Stack: raised-exception, exception   310         self.dup_top()                      # Stack: raised-exception, exception, exception   311         self.load_attr("args")              # Stack: raised-exception, exception, args   312         self.load_const(0)                  # Stack: raised-exception, exception, args, 0   313         self.binary_subscr()                # Stack: raised-exception, exception, exception-object   314         load_class_name(class_file, str(exc_name), self)   315                                             # Stack: raised-exception, exception, exception-object, handled-exception   316         self.load_global("isinstance")      # Stack: raised-exception, exception, exception-object, handled-exception, isinstance   317         self.rot_three()                    # Stack: raised-exception, exception, isinstance, exception-object, handled-exception   318         self.call_function(2)               # Stack: raised-exception, exception, result   319         self.jump_to_label(1, "handler")   320         self.start_label("next")   321         self.pop_top()                      # Stack: raised-exception, exception   322         self.rot_two()                      # Stack: exception, raised-exception   323         self.end_finally()   324         self.start_label("handler")   325         self.pop_top()                      # Stack: raised-exception, exception   326    327     # Complicated methods.   328    329     def load_const(self, value):   330         self.output.append(opmap["LOAD_CONST"])   331         if not self.constants.has_key(value):   332             self.constants[value] = len(self.constants.keys())   333         self.position += 1   334         self._write_value(self.constants[value])   335         self.update_stack_depth(1)   336    337     def load_global(self, name):   338         self.output.append(opmap["LOAD_GLOBAL"])   339         if not self.names.has_key(name):   340             self.names[name] = len(self.names.keys())   341         self.position += 1   342         self._write_value(self.names[name])   343         self.update_stack_depth(1)   344    345     def load_attr(self, name):   346         self.output.append(opmap["LOAD_ATTR"])   347         if not self.names.has_key(name):   348             self.names[name] = len(self.names.keys())   349         self.position += 1   350         self._write_value(self.names[name])   351    352     def load_name(self, name):   353         self.output.append(opmap["LOAD_NAME"])   354         if not self.names.has_key(name):   355             self.names[name] = len(self.names.keys())   356         self.position += 1   357         self._write_value(self.names[name])   358         self.update_stack_depth(1)   359    360     def load_fast(self, index):   361         self.output.append(opmap["LOAD_FAST"])   362         self.position += 1   363         self._write_value(index)   364         self.update_stack_depth(1)   365         self.update_locals(index)   366    367     def store_attr(self, name):   368         self.output.append(opmap["STORE_ATTR"])   369         if not self.names.has_key(name):   370             self.names[name] = len(self.names.keys())   371         self.position += 1   372         self._write_value(self.names[name])   373         self.update_stack_depth(-1)   374    375     def store_fast(self, index):   376         self.output.append(opmap["STORE_FAST"])   377         self.position += 1   378         self._write_value(index)   379         self.update_stack_depth(-1)   380         self.update_locals(index)   381    382     def for_iter(self):   383         self.blocks.append(self.position)   384         #print ">", self.blocks   385         self.output.append(opmap["FOR_ITER"])   386         self.position += 1   387         self._write_value(0) # To be filled in later   388         self.update_stack_depth(1)   389    390     def break_loop(self):   391         self.output.append(opmap["BREAK_LOOP"])   392         self.position += 1   393         self.jump_absolute(self.blocks[-1])   394    395     # Normal bytecode generators.   396    397     def get_iter(self):   398         self.output.append(opmap["GET_ITER"])   399         self.position += 1   400    401     def jump_if_false(self, offset=0):   402         self.output.append(opmap["JUMP_IF_FALSE"])   403         self.position += 1   404         self._write_value(offset) # May be filled in later   405    406     def jump_if_true(self, offset=0):   407         self.output.append(opmap["JUMP_IF_TRUE"])   408         self.position += 1   409         self._write_value(offset) # May be filled in later   410    411     def jump_forward(self, offset=0):   412         self.output.append(opmap["JUMP_FORWARD"])   413         self.position += 1   414         self._write_value(offset) # May be filled in later   415    416     def jump_absolute(self, address=0):   417         self.output.append(opmap["JUMP_ABSOLUTE"])   418         self.position += 1   419         self._write_value(address) # May be filled in later   420    421     def build_tuple(self, count):   422         self.output.append(opmap["BUILD_TUPLE"])   423         self.position += 1   424         self._write_value(count)   425         self.update_stack_depth(-(count - 1))   426    427     def build_list(self, count):   428         self.output.append(opmap["BUILD_LIST"])   429         self.position += 1   430         self._write_value(count)   431         self.update_stack_depth(-(count - 1))   432    433     def pop_top(self):   434         self.output.append(opmap["POP_TOP"])   435         self.position += 1   436         self.update_stack_depth(-1)   437    438     def dup_top(self):   439         self.output.append(opmap["DUP_TOP"])   440         self.position += 1   441         self.update_stack_depth(1)   442    443     def dup_topx(self, count):   444         self.output.append(opmap["DUP_TOPX"])   445         self.position += 1   446         self._write_value(count)   447         self.update_stack_depth(count)   448    449     def rot_two(self):   450         self.output.append(opmap["ROT_TWO"])   451         self.position += 1   452    453     def rot_three(self):   454         self.output.append(opmap["ROT_THREE"])   455         self.position += 1   456    457     def rot_four(self):   458         self.output.append(opmap["ROT_FOUR"])   459         self.position += 1   460    461     def call_function(self, count):   462         self.output.append(opmap["CALL_FUNCTION"])   463         self.position += 1   464         self._write_value(count)   465         self.update_stack_depth(-count)   466    467     def call_function_var(self, count):   468         self.output.append(opmap["CALL_FUNCTION_VAR"])   469         self.position += 1   470         self._write_value(count)   471         self.update_stack_depth(-count-1)   472    473     def binary_subscr(self):   474         self.output.append(opmap["BINARY_SUBSCR"])   475         self.position += 1   476         self.update_stack_depth(-1)   477    478     def binary_add(self):   479         self.output.append(opmap["BINARY_ADD"])   480         self.position += 1   481         self.update_stack_depth(-1)   482    483     def binary_divide(self):   484         self.output.append(opmap["BINARY_DIVIDE"])   485         self.position += 1   486         self.update_stack_depth(-1)   487    488     def binary_multiply(self):   489         self.output.append(opmap["BINARY_MULTIPLY"])   490         self.position += 1   491         self.update_stack_depth(-1)   492    493     def binary_modulo(self):   494         self.output.append(opmap["BINARY_MODULO"])   495         self.position += 1   496         self.update_stack_depth(-1)   497    498     def binary_subtract(self):   499         self.output.append(opmap["BINARY_SUBTRACT"])   500         self.position += 1   501         self.update_stack_depth(-1)   502    503     def binary_and(self):   504         self.output.append(opmap["BINARY_AND"])   505         self.position += 1   506         self.update_stack_depth(-1)   507    508     def binary_or(self):   509         self.output.append(opmap["BINARY_XOR"])   510         self.position += 1   511         self.update_stack_depth(-1)   512    513     def binary_lshift(self):   514         self.output.append(opmap["BINARY_LSHIFT"])   515         self.position += 1   516         self.update_stack_depth(-1)   517    518     def binary_rshift(self):   519         self.output.append(opmap["BINARY_RSHIFT"])   520         self.position += 1   521         self.update_stack_depth(-1)   522    523     def binary_xor(self):   524         self.output.append(opmap["BINARY_XOR"])   525         self.position += 1   526         self.update_stack_depth(-1)   527    528     def store_subscr(self):   529         self.output.append(opmap["STORE_SUBSCR"])   530         self.position += 1   531         self.update_stack_depth(-3)   532    533     def unary_negative(self):   534         self.output.append(opmap["UNARY_NEGATIVE"])   535         self.position += 1   536    537     def slice_0(self):   538         self.output.append(opmap["SLICE+0"])   539         self.position += 1   540    541     def slice_1(self):   542         self.output.append(opmap["SLICE+1"])   543         self.position += 1   544    545     def compare_op(self, op):   546         self.output.append(opmap["COMPARE_OP"])   547         self.position += 1   548         self._write_value(list(cmp_op).index(op))   549         self.update_stack_depth(-1)   550    551     def return_value(self):   552         self.output.append(opmap["RETURN_VALUE"])   553         self.position += 1   554         self.update_stack_depth(-1)   555    556     def raise_varargs(self, count):   557         self.output.append(opmap["RAISE_VARARGS"])   558         self.position += 1   559         self._write_value(count)   560    561     def pop_block(self):   562         self.output.append(opmap["POP_BLOCK"])   563         self.position += 1   564    565     def end_finally(self):   566         self.output.append(opmap["END_FINALLY"])   567         self.position += 1   568    569     def unpack_sequence(self, count):   570         self.output.append(opmap["UNPACK_SEQUENCE"])   571         self.position += 1   572         self._write_value(count)   573    574     # Debugging.   575    576     def print_item(self):   577         self.output.append(opmap["PRINT_ITEM"])   578         self.position += 1   579    580 # Utility classes and functions.   581    582 class LazyDict(UserDict):   583     def __getitem__(self, key):   584         if not self.data.has_key(key):   585             # NOTE: Assume 16-bit value.   586             self.data[key] = LazyValue(2)   587         return self.data[key]   588     def __setitem__(self, key, value):   589         if self.data.has_key(key):   590             existing_value = self.data[key]   591             if isinstance(existing_value, LazyValue):   592                 existing_value.set_value(value)   593                 return   594         self.data[key] = value   595    596 class LazyValue:   597     def __init__(self, nvalues):   598         self.values = []   599         for i in range(0, nvalues):   600             self.values.append(LazySubValue())   601     def set_value(self, value):   602         # NOTE: Assume at least 16-bit value. No "filling" performed.   603         if value <= 0xffff:   604             self.values[0].set_value(value & 0xff)   605             self.values[1].set_value((value & 0xff00) >> 8)   606         else:   607             # NOTE: EXTENDED_ARG not yet supported.   608             raise ValueError, value   609     def get_value(self):   610         value = 0   611         values = self.values[:]   612         for i in range(0, len(values)):   613             value = (value << 8) + values.pop().value   614         return value   615    616 class LazySubValue:   617     def __init__(self):   618         self.value = 0   619     def set_value(self, value):   620         self.value = value   621    622 def signed(value, limit):   623    624     """   625     Return the signed integer from the unsigned 'value', where 'limit' (a value   626     one greater than the highest possible positive integer) is used to determine   627     whether a negative or positive result is produced.   628     """   629    630     d, r = divmod(value, limit)   631     if d == 1:   632         mask = limit * 2 - 1   633         return -1 - (value ^ mask)   634     else:   635         return value   636    637 def signed2(value):   638     return signed(value, 0x8000)   639    640 def signed4(value):   641     return signed(value, 0x80000000)   642    643 def load_class_name(class_file, full_class_name, program):   644     this_class_name = str(class_file.this_class.get_python_name())   645     this_class_parts = this_class_name.split(".")   646     class_parts = full_class_name.split(".")   647    648     # Only use the full path if different from this class's path.   649    650     if class_parts[:-1] != this_class_parts[:-1]:   651         program.use_external_name(full_class_name)   652         program.load_global(class_parts[0])   653         for class_part in class_parts[1:]:   654             program.load_attr(class_part)   # Stack: classref   655     else:   656         program.load_global(class_parts[-1])   657    658 # Bytecode conversion.   659    660 class BytecodeReader:   661    662     "A generic Java bytecode reader."   663    664     def __init__(self, class_file):   665    666         """   667         Initialise the reader with a 'class_file' containing essential   668         information for any bytecode inspection activity.   669         """   670    671         self.class_file = class_file   672         self.position_mapping = LazyDict()   673    674     def process(self, method, program):   675    676         """   677         Process the given 'method' (obtained from the class file), using the   678         given 'program' to write translated Python bytecode instructions.   679         """   680    681         self.java_position = 0   682         self.in_finally = 0   683         self.method = method   684    685         # NOTE: Potentially unreliable way of getting necessary information.   686    687         code, exception_table = None, None   688         for attribute in method.attributes:   689             if isinstance(attribute, classfile.CodeAttributeInfo):   690                 code, exception_table = attribute.code, attribute.exception_table   691                 break   692    693         # Where no code was found, write a very simple placeholder routine.   694         # This is useful for interfaces and abstract classes.   695         # NOTE: Assess the correctness of doing this. An exception should really   696         # NOTE: be raised instead.   697    698         if code is None:   699             program.load_const(None)   700             program.return_value()   701             return   702    703         # Produce a structure which permits fast access to exception details.   704    705         exception_block_start = {}   706         exception_block_end = {}   707         exception_block_handler = {}   708         reversed_exception_table = exception_table[:]   709         reversed_exception_table.reverse()   710    711         # Later entries have wider coverage than earlier entries.   712    713         for exception in reversed_exception_table:   714    715             # Index start positions.   716    717             if not exception_block_start.has_key(exception.start_pc):   718                 exception_block_start[exception.start_pc] = []   719             exception_block_start[exception.start_pc].append(exception)   720    721             # Index end positions.   722    723             if not exception_block_end.has_key(exception.end_pc):   724                 exception_block_end[exception.end_pc] = []   725             exception_block_end[exception.end_pc].append(exception)   726    727             # Index handler positions.   728    729             if not exception_block_handler.has_key(exception.handler_pc):   730                 exception_block_handler[exception.handler_pc] = []   731             exception_block_handler[exception.handler_pc].append(exception)   732    733         # Process each instruction in the code.   734    735         while self.java_position < len(code):   736             self.position_mapping[self.java_position] = program.position   737    738             # Insert exception handling constructs.   739    740             block_starts = exception_block_start.get(self.java_position, [])   741             for exception in block_starts:   742    743                 # Note that the absolute position is used.   744    745                 if exception.catch_type == 0:   746                     program.setup_finally(self.position_mapping[exception.handler_pc])   747                 else:   748                     program.setup_except(self.position_mapping[exception.handler_pc])   749    750             if block_starts:   751                 self.in_finally = 0   752    753             # Insert exception handler details.   754             # NOTE: Ensure that pop_block is reachable by possibly inserting it at the start of finally handlers.   755             # NOTE: Insert a check for the correct exception at the start of each handler.   756    757             for exception in exception_block_handler.get(self.java_position, []):   758                 program.end_exception()   759                 if exception.catch_type == 0:   760                     self.in_finally = 1   761                 else:   762                     program.start_handler(self.class_file.constants[exception.catch_type - 1].get_python_name(), self.class_file)   763    764             # Process the bytecode at the current position.   765    766             bytecode = ord(code[self.java_position])   767             mnemonic, number_of_arguments = self.java_bytecodes[bytecode]   768             number_of_arguments = self.process_bytecode(mnemonic, number_of_arguments, code, program)   769             next_java_position = self.java_position + 1 + number_of_arguments   770    771             # Insert exception block end details.   772    773             for exception in exception_block_end.get(next_java_position, []):   774    775                 # NOTE: Insert jump beyond handlers.   776                 # NOTE: program.jump_forward/absolute(...)   777                 # NOTE: Insert end finally at end of handlers as well as where "ret" occurs.   778    779                 if exception.catch_type != 0:   780                     program.pop_block()   781    782             # Only advance the JVM position after sneaking in extra Python   783             # instructions.   784    785             self.java_position = next_java_position   786    787     def process_bytecode(self, mnemonic, number_of_arguments, code, program):   788    789         """   790         Process a bytecode instruction with the given 'mnemonic' and   791         'number_of_arguments'. The 'code' parameter contains the full method   792         code so that argument data can be inspected. The 'program' parameter is   793         used to produce a Python translation of the instruction.   794         """   795    796         if number_of_arguments is not None:   797             arguments = []   798             for j in range(0, number_of_arguments):   799                 arguments.append(ord(code[self.java_position + 1 + j]))   800    801             # Call the handler.   802    803             getattr(self, mnemonic)(arguments, program)   804             return number_of_arguments   805         else:   806             # Call the handler.   807    808             return getattr(self, mnemonic)(code[self.java_position+1:], program)   809    810     java_bytecodes = {   811         # code : (mnemonic, number of following bytes, change in stack)   812         0 : ("nop", 0),   813         1 : ("aconst_null", 0),   814         2 : ("iconst_m1", 0),   815         3 : ("iconst_0", 0),   816         4 : ("iconst_1", 0),   817         5 : ("iconst_2", 0),   818         6 : ("iconst_3", 0),   819         7 : ("iconst_4", 0),   820         8 : ("iconst_5", 0),   821         9 : ("lconst_0", 0),   822         10 : ("lconst_1", 0),   823         11 : ("fconst_0", 0),   824         12 : ("fconst_1", 0),   825         13 : ("fconst_2", 0),   826         14 : ("dconst_0", 0),   827         15 : ("dconst_1", 0),   828         16 : ("bipush", 1),   829         17 : ("sipush", 2),   830         18 : ("ldc", 1),   831         19 : ("ldc_w", 2),   832         20 : ("ldc2_w", 2),   833         21 : ("iload", 1),   834         22 : ("lload", 1),   835         23 : ("fload", 1),   836         24 : ("dload", 1),   837         25 : ("aload", 1),   838         26 : ("iload_0", 0),   839         27 : ("iload_1", 0),   840         28 : ("iload_2", 0),   841         29 : ("iload_3", 0),   842         30 : ("lload_0", 0),   843         31 : ("lload_1", 0),   844         32 : ("lload_2", 0),   845         33 : ("lload_3", 0),   846         34 : ("fload_0", 0),   847         35 : ("fload_1", 0),   848         36 : ("fload_2", 0),   849         37 : ("fload_3", 0),   850         38 : ("dload_0", 0),   851         39 : ("dload_1", 0),   852         40 : ("dload_2", 0),   853         41 : ("dload_3", 0),   854         42 : ("aload_0", 0),   855         43 : ("aload_1", 0),   856         44 : ("aload_2", 0),   857         45 : ("aload_3", 0),   858         46 : ("iaload", 0),   859         47 : ("laload", 0),   860         48 : ("faload", 0),   861         49 : ("daload", 0),   862         50 : ("aaload", 0),   863         51 : ("baload", 0),   864         52 : ("caload", 0),   865         53 : ("saload", 0),   866         54 : ("istore", 1),   867         55 : ("lstore", 1),   868         56 : ("fstore", 1),   869         57 : ("dstore", 1),   870         58 : ("astore", 1),   871         59 : ("istore_0", 0),   872         60 : ("istore_1", 0),   873         61 : ("istore_2", 0),   874         62 : ("istore_3", 0),   875         63 : ("lstore_0", 0),   876         64 : ("lstore_1", 0),   877         65 : ("lstore_2", 0),   878         66 : ("lstore_3", 0),   879         67 : ("fstore_0", 0),   880         68 : ("fstore_1", 0),   881         69 : ("fstore_2", 0),   882         70 : ("fstore_3", 0),   883         71 : ("dstore_0", 0),   884         72 : ("dstore_1", 0),   885         73 : ("dstore_2", 0),   886         74 : ("dstore_3", 0),   887         75 : ("astore_0", 0),   888         76 : ("astore_1", 0),   889         77 : ("astore_2", 0),   890         78 : ("astore_3", 0),   891         79 : ("iastore", 0),   892         80 : ("lastore", 0),   893         81 : ("fastore", 0),   894         82 : ("dastore", 0),   895         83 : ("aastore", 0),   896         84 : ("bastore", 0),   897         85 : ("castore", 0),   898         86 : ("sastore", 0),   899         87 : ("pop", 0),   900         88 : ("pop2", 0),   901         89 : ("dup", 0),   902         90 : ("dup_x1", 0),   903         91 : ("dup_x2", 0),   904         92 : ("dup2", 0),   905         93 : ("dup2_x1", 0),   906         94 : ("dup2_x2", 0),   907         95 : ("swap", 0),   908         96 : ("iadd", 0),   909         97 : ("ladd", 0),   910         98 : ("fadd", 0),   911         99 : ("dadd", 0),   912         100 : ("isub", 0),   913         101 : ("lsub", 0),   914         102 : ("fsub", 0),   915         103 : ("dsub", 0),   916         104 : ("imul", 0),   917         105 : ("lmul", 0),   918         106 : ("fmul", 0),   919         107 : ("dmul", 0),   920         108 : ("idiv", 0),   921         109 : ("ldiv", 0),   922         110 : ("fdiv", 0),   923         111 : ("ddiv", 0),   924         112 : ("irem", 0),   925         113 : ("lrem", 0),   926         114 : ("frem", 0),   927         115 : ("drem", 0),   928         116 : ("ineg", 0),   929         117 : ("lneg", 0),   930         118 : ("fneg", 0),   931         119 : ("dneg", 0),   932         120 : ("ishl", 0),   933         121 : ("lshl", 0),   934         122 : ("ishr", 0),   935         123 : ("lshr", 0),   936         124 : ("iushr", 0),   937         125 : ("lushr", 0),   938         126 : ("iand", 0),   939         127 : ("land", 0),   940         128 : ("ior", 0),   941         129 : ("lor", 0),   942         130 : ("ixor", 0),   943         131 : ("lxor", 0),   944         132 : ("iinc", 2),   945         133 : ("i2l", 0),   946         134 : ("i2f", 0),   947         135 : ("i2d", 0),   948         136 : ("l2i", 0),   949         137 : ("l2f", 0),   950         138 : ("l2d", 0),   951         139 : ("f2i", 0),   952         140 : ("f2l", 0),   953         141 : ("f2d", 0),   954         142 : ("d2i", 0),   955         143 : ("d2l", 0),   956         144 : ("d2f", 0),   957         145 : ("i2b", 0),   958         146 : ("i2c", 0),   959         147 : ("i2s", 0),   960         148 : ("lcmp", 0),   961         149 : ("fcmpl", 0),   962         150 : ("fcmpg", 0),   963         151 : ("dcmpl", 0),   964         152 : ("dcmpg", 0),   965         153 : ("ifeq", 2),   966         154 : ("ifne", 2),   967         155 : ("iflt", 2),   968         156 : ("ifge", 2),   969         157 : ("ifgt", 2),   970         158 : ("ifle", 2),   971         159 : ("if_icmpeq", 2),   972         160 : ("if_icmpne", 2),   973         161 : ("if_icmplt", 2),   974         162 : ("if_icmpge", 2),   975         163 : ("if_icmpgt", 2),   976         164 : ("if_icmple", 2),   977         165 : ("if_acmpeq", 2),   978         166 : ("if_acmpne", 2),   979         167 : ("goto", 2),   980         168 : ("jsr", 2),   981         169 : ("ret", 1),   982         170 : ("tableswitch", None), # variable number of arguments   983         171 : ("lookupswitch", None), # variable number of arguments   984         172 : ("ireturn", 0),   985         173 : ("lreturn", 0),   986         174 : ("freturn", 0),   987         175 : ("dreturn", 0),   988         176 : ("areturn", 0),   989         177 : ("return_", 0),   990         178 : ("getstatic", 2),   991         179 : ("putstatic", 2),   992         180 : ("getfield", 2),   993         181 : ("putfield", 2),   994         182 : ("invokevirtual", 2),   995         183 : ("invokespecial", 2),   996         184 : ("invokestatic", 2),   997         185 : ("invokeinterface", 4),   998         187 : ("new", 2),   999         188 : ("newarray", 1),  1000         189 : ("anewarray", 2),  1001         190 : ("arraylength", 0),  1002         191 : ("athrow", 0),  1003         192 : ("checkcast", 2),  1004         193 : ("instanceof", 2),  1005         194 : ("monitorenter", 0),  1006         195 : ("monitorexit", 0),  1007         196 : ("wide", None), # 3 or 5 arguments, stack changes according to modified element  1008         197 : ("multianewarray", 3),  1009         198 : ("ifnull", 2),  1010         199 : ("ifnonnull", 2),  1011         200 : ("goto_w", 4),  1012         201 : ("jsr_w", 4),  1013         }  1014   1015 class BytecodeDisassembler(BytecodeReader):  1016   1017     "A Java bytecode disassembler."  1018   1019     bytecode_methods = [spec[0] for spec in BytecodeReader.java_bytecodes.values()]  1020   1021     def __getattr__(self, name):  1022         if name in self.bytecode_methods:  1023             print "%5s %s" % (self.java_position, name),  1024             return self.generic  1025         else:  1026             raise AttributeError, name  1027   1028     def generic(self, arguments, program):  1029         print arguments  1030   1031     def lookupswitch(self, code, program):  1032         print "%5s lookupswitch" % (self.java_position,),  1033         d, r = divmod(self.java_position + 1, 4)  1034         to_boundary = (4 - r) % 4  1035         code = code[to_boundary:]  1036         default = classfile.u4(code[0:4])  1037         npairs = classfile.u4(code[4:8])  1038         print default, npairs  1039         return to_boundary + 8 + npairs * 8  1040   1041     def tableswitch(self, code, program):  1042         print "%5s tableswitch" % (self.java_position,),  1043         d, r = divmod(self.java_position + 1, 4)  1044         to_boundary = (4 - r) % 4  1045         code = code[to_boundary:]  1046         default = classfile.u4(code[0:4])  1047         low = classfile.u4(code[4:8])  1048         high = classfile.u4(code[8:12])  1049         print default, low, high  1050         return to_boundary + 12 + (high - low + 1) * 4  1051   1052 class BytecodeDisassemblerProgram:  1053     position = 0  1054     def setup_except(self, target):  1055         print "(setup_except %s)" % target  1056     def setup_finally(self, target):  1057         print "(setup_finally %s)" % target  1058     def end_exception(self):  1059         print "(end_exception)"  1060     def start_handler(self, exc_name, class_file):  1061         print "(start_handler %s)" % exc_name  1062     def pop_block(self):  1063         print "(pop_block)"  1064   1065 class BytecodeTranslator(BytecodeReader):  1066   1067     "A Java bytecode translator which uses a Python bytecode writer."  1068   1069     def aaload(self, arguments, program):  1070         # NOTE: No type checking performed.  1071         program.binary_subscr()  1072   1073     def aastore(self, arguments, program):  1074         # NOTE: No type checking performed.  1075         # Stack: arrayref, index, value  1076         program.rot_three() # Stack: value, arrayref, index  1077         program.store_subscr()  1078   1079     def aconst_null(self, arguments, program):  1080         program.load_const(None)  1081   1082     def aload(self, arguments, program):  1083         program.load_fast(arguments[0])  1084   1085     def aload_0(self, arguments, program):  1086         program.load_fast(0)  1087   1088     def aload_1(self, arguments, program):  1089         program.load_fast(1)  1090   1091     def aload_2(self, arguments, program):  1092         program.load_fast(2)  1093   1094     def aload_3(self, arguments, program):  1095         program.load_fast(3)  1096   1097     def anewarray(self, arguments, program):  1098         # NOTE: Does not raise NegativeArraySizeException.  1099         # NOTE: Not using the index to type the list/array.  1100         index = (arguments[0] << 8) + arguments[1]  1101         self._newarray(program)  1102   1103     def _newarray(self, program):  1104         program.build_list(0)       # Stack: count, list  1105         program.rot_two()           # Stack: list, count  1106         program.setup_loop()  1107         program.load_global("range")  1108         program.load_const(0)       # Stack: list, count, range, 0  1109         program.rot_three()         # Stack: list, 0, count, range  1110         program.rot_three()         # Stack: list, range, 0, count  1111         program.call_function(2)    # Stack: list, range_list  1112         program.get_iter()          # Stack: list, iter  1113         program.for_iter()          # Stack: list, iter, value  1114         program.pop_top()           # Stack: list, iter  1115         program.rot_two()           # Stack: iter, list  1116         program.dup_top()           # Stack: iter, list, list  1117         program.load_attr("append") # Stack: iter, list, append  1118         program.load_const(None)    # Stack: iter, list, append, None  1119         program.call_function(1)    # Stack: iter, list, None  1120         program.pop_top()           # Stack: iter, list  1121         program.rot_two()           # Stack: list, iter  1122         program.end_loop()          # Back to for_iter above  1123   1124     def areturn(self, arguments, program):  1125         program.return_value()  1126   1127     def arraylength(self, arguments, program):  1128         program.load_global("len")  # Stack: arrayref, len  1129         program.rot_two()           # Stack: len, arrayref  1130         program.call_function(1)  1131   1132     def astore(self, arguments, program):  1133         program.store_fast(arguments[0])  1134   1135     def astore_0(self, arguments, program):  1136         program.store_fast(0)  1137   1138     def astore_1(self, arguments, program):  1139         program.store_fast(1)  1140   1141     def astore_2(self, arguments, program):  1142         program.store_fast(2)  1143   1144     def astore_3(self, arguments, program):  1145         program.store_fast(3)  1146   1147     def athrow(self, arguments, program):  1148         # NOTE: NullPointerException not raised where null/None is found on the stack.  1149         # If this instruction appears in a finally handler, use end_finally instead.  1150         if self.in_finally:  1151             program.end_finally()  1152         else:  1153             # Wrap the exception in a Python exception.  1154             program.load_global("Exception")    # Stack: objectref, Exception  1155             program.rot_two()                   # Stack: Exception, objectref  1156             program.call_function(1)            # Stack: exception  1157             program.raise_varargs(1)  1158             # NOTE: This seems to put another object on the stack.  1159   1160     baload = aaload  1161     bastore = aastore  1162   1163     def bipush(self, arguments, program):  1164         program.load_const(arguments[0])  1165   1166     caload = aaload  1167     castore = aastore  1168   1169     def checkcast(self, arguments, program):  1170         index = (arguments[0] << 8) + arguments[1]  1171         target_name = self.class_file.constants[index - 1].get_python_name()  1172         program.use_external_name(target_name)  1173         program.dup_top()                   # Stack: objectref, objectref  1174         program.load_const(None)            # Stack: objectref, objectref, None  1175         program.compare_op("is")            # Stack: objectref, result  1176         program.jump_to_label(1, "next")  1177         program.pop_top()                   # Stack: objectref  1178         program.dup_top()                   # Stack: objectref, objectref  1179         program.load_global("isinstance")   # Stack: objectref, objectref, isinstance  1180         program.rot_two()                   # Stack: objectref, isinstance, objectref  1181         load_class_name(self.class_file, target_name, program)  1182         program.call_function(2)            # Stack: objectref, result  1183         program.jump_to_label(1, "next")  1184         program.pop_top()                   # Stack: objectref  1185         program.pop_top()                   # Stack:  1186         program.use_external_name("java.lang.ClassCastException")  1187         load_class_name(self.class_file, "java.lang.ClassCastException", program)  1188         program.call_function(0)            # Stack: exception  1189         # Wrap the exception in a Python exception.  1190         program.load_global("Exception")    # Stack: exception, Exception  1191         program.rot_two()                   # Stack: Exception, exception  1192         program.call_function(1)            # Stack: exception  1193         program.raise_varargs(1)  1194         # NOTE: This seems to put another object on the stack.  1195         program.start_label("next")  1196         program.pop_top()                   # Stack: objectref  1197   1198     def d2f(self, arguments, program):  1199         pass  1200   1201     def d2i(self, arguments, program):  1202         program.load_global("int")  # Stack: value, int  1203         program.rot_two()           # Stack: int, value  1204         program.call_function(1)    # Stack: result  1205   1206     d2l = d2i # Preserving Java semantics  1207   1208     def dadd(self, arguments, program):  1209         # NOTE: No type checking performed.  1210         program.binary_add()  1211   1212     daload = aaload  1213     dastore = aastore  1214   1215     def dcmpg(self, arguments, program):  1216         # NOTE: No type checking performed.  1217         program.compare_op(">")  1218   1219     def dcmpl(self, arguments, program):  1220         # NOTE: No type checking performed.  1221         program.compare_op("<")  1222   1223     def dconst_0(self, arguments, program):  1224         program.load_const(0.0)  1225   1226     def dconst_1(self, arguments, program):  1227         program.load_const(1.0)  1228   1229     def ddiv(self, arguments, program):  1230         # NOTE: No type checking performed.  1231         program.binary_divide()  1232   1233     dload = aload  1234     dload_0 = aload_0  1235     dload_1 = aload_1  1236     dload_2 = aload_2  1237     dload_3 = aload_3  1238   1239     def dmul(self, arguments, program):  1240         # NOTE: No type checking performed.  1241         program.binary_multiply()  1242   1243     def dneg(self, arguments, program):  1244         # NOTE: No type checking performed.  1245         program.unary_negative()  1246   1247     def drem(self, arguments, program):  1248         # NOTE: No type checking performed.  1249         program.binary_modulo()  1250   1251     dreturn = areturn  1252     dstore = astore  1253     dstore_0 = astore_0  1254     dstore_1 = astore_1  1255     dstore_2 = astore_2  1256     dstore_3 = astore_3  1257   1258     def dsub(self, arguments, program):  1259         # NOTE: No type checking performed.  1260         program.binary_subtract()  1261   1262     def dup(self, arguments, program):  1263         program.dup_top()  1264   1265     def dup_x1(self, arguments, program):  1266         # Ignoring computational type categories.  1267         program.dup_top()  1268         program.rot_three()  1269   1270     def dup_x2(self, arguments, program):  1271         # Ignoring computational type categories.  1272         program.dup_top()  1273         program.rot_four()  1274   1275     dup2 = dup # Ignoring computational type categories  1276     dup2_x1 = dup_x1 # Ignoring computational type categories  1277     dup2_x2 = dup_x2 # Ignoring computational type categories  1278   1279     def f2d(self, arguments, program):  1280         pass # Preserving Java semantics  1281   1282     def f2i(self, arguments, program):  1283         program.load_global("int")  # Stack: value, int  1284         program.rot_two()           # Stack: int, value  1285         program.call_function(1)    # Stack: result  1286   1287     f2l = f2i # Preserving Java semantics  1288     fadd = dadd  1289     faload = daload  1290     fastore = dastore  1291     fcmpg = dcmpg  1292     fcmpl = dcmpl  1293     fconst_0 = dconst_0  1294     fconst_1 = dconst_1  1295   1296     def fconst_2(self, arguments, program):  1297         program.load_const(2.0)  1298   1299     fdiv = ddiv  1300     fload = dload  1301     fload_0 = dload_0  1302     fload_1 = dload_1  1303     fload_2 = dload_2  1304     fload_3 = dload_3  1305     fmul = dmul  1306     fneg = dneg  1307     frem = drem  1308     freturn = dreturn  1309     fstore = dstore  1310     fstore_0 = dstore_0  1311     fstore_1 = dstore_1  1312     fstore_2 = dstore_2  1313     fstore_3 = dstore_3  1314     fsub = dsub  1315   1316     def getfield(self, arguments, program):  1317         index = (arguments[0] << 8) + arguments[1]  1318         target_name = self.class_file.constants[index - 1].get_python_name()  1319         # NOTE: Using the string version of the name which may contain incompatible characters.  1320         program.load_attr(str(target_name))  1321   1322     def getstatic(self, arguments, program):  1323         index = (arguments[0] << 8) + arguments[1]  1324         target = self.class_file.constants[index - 1]  1325         target_name = target.get_python_name()  1326   1327         # Get the class name instead of the fully qualified name.  1328   1329         full_class_name = target.get_class().get_python_name()  1330         program.use_external_name(full_class_name)  1331         load_class_name(self.class_file, full_class_name, program)  1332         # NOTE: Using the string version of the name which may contain incompatible characters.  1333         program.load_attr(str(target_name))  1334   1335     def goto(self, arguments, program):  1336         offset = signed2((arguments[0] << 8) + arguments[1])  1337         java_absolute = self.java_position + offset  1338         program.jump_absolute(self.position_mapping[java_absolute])  1339   1340     def goto_w(self, arguments, program):  1341         offset = signed4((arguments[0] << 24) + (arguments[1] << 16) + (arguments[2] << 8) + arguments[3])  1342         java_absolute = self.java_position + offset  1343         program.jump_absolute(self.position_mapping[java_absolute])  1344   1345     def i2b(self, arguments, program):  1346         pass  1347   1348     def i2c(self, arguments, program):  1349         pass  1350   1351     def i2d(self, arguments, program):  1352         program.load_global("float")    # Stack: value, float  1353         program.rot_two()               # Stack: float, value  1354         program.call_function(1)        # Stack: result  1355   1356     i2f = i2d # Not distinguishing between float and double  1357   1358     def i2l(self, arguments, program):  1359         pass # Preserving Java semantics  1360   1361     def i2s(self, arguments, program):  1362         pass # Not distinguishing between int and short  1363   1364     iadd = fadd  1365     iaload = faload  1366   1367     def iand(self, arguments, program):  1368         # NOTE: No type checking performed.  1369         program.binary_and()  1370   1371     iastore = fastore  1372   1373     def iconst_m1(self, arguments, program):  1374         program.load_const(-1)  1375   1376     def iconst_0(self, arguments, program):  1377         program.load_const(0)  1378   1379     def iconst_1(self, arguments, program):  1380         program.load_const(1)  1381   1382     def iconst_2(self, arguments, program):  1383         program.load_const(2)  1384   1385     def iconst_3(self, arguments, program):  1386         program.load_const(3)  1387   1388     def iconst_4(self, arguments, program):  1389         program.load_const(4)  1390   1391     def iconst_5(self, arguments, program):  1392         program.load_const(5)  1393   1394     idiv = fdiv  1395   1396     def _if_xcmpx(self, arguments, program, op):  1397         offset = signed2((arguments[0] << 8) + arguments[1])  1398         java_absolute = self.java_position + offset  1399         program.compare_op(op)  1400         program.jump_to_label(0, "next") # skip if false  1401         program.pop_top()  1402         program.jump_absolute(self.position_mapping[java_absolute])  1403         program.start_label("next")  1404         program.pop_top()  1405   1406     def if_acmpeq(self, arguments, program):  1407         # NOTE: No type checking performed.  1408         self._if_xcmpx(arguments, program, "is")  1409   1410     def if_acmpne(self, arguments, program):  1411         # NOTE: No type checking performed.  1412         self._if_xcmpx(arguments, program, "is not")  1413   1414     def if_icmpeq(self, arguments, program):  1415         # NOTE: No type checking performed.  1416         self._if_xcmpx(arguments, program, "==")  1417   1418     def if_icmpne(self, arguments, program):  1419         # NOTE: No type checking performed.  1420         self._if_xcmpx(arguments, program, "!=")  1421   1422     def if_icmplt(self, arguments, program):  1423         # NOTE: No type checking performed.  1424         self._if_xcmpx(arguments, program, "<")  1425   1426     def if_icmpge(self, arguments, program):  1427         # NOTE: No type checking performed.  1428         self._if_xcmpx(arguments, program, ">=")  1429   1430     def if_icmpgt(self, arguments, program):  1431         # NOTE: No type checking performed.  1432         self._if_xcmpx(arguments, program, ">")  1433   1434     def if_icmple(self, arguments, program):  1435         # NOTE: No type checking performed.  1436         self._if_xcmpx(arguments, program, "<=")  1437   1438     def ifeq(self, arguments, program):  1439         # NOTE: No type checking performed.  1440         program.load_const(0)  1441         self._if_xcmpx(arguments, program, "==")  1442   1443     def ifne(self, arguments, program):  1444         # NOTE: No type checking performed.  1445         program.load_const(0)  1446         self._if_xcmpx(arguments, program, "!=")  1447   1448     def iflt(self, arguments, program):  1449         # NOTE: No type checking performed.  1450         program.load_const(0)  1451         self._if_xcmpx(arguments, program, "<")  1452   1453     def ifge(self, arguments, program):  1454         # NOTE: No type checking performed.  1455         program.load_const(0)  1456         self._if_xcmpx(arguments, program, ">=")  1457   1458     def ifgt(self, arguments, program):  1459         # NOTE: No type checking performed.  1460         program.load_const(0)  1461         self._if_xcmpx(arguments, program, ">")  1462   1463     def ifle(self, arguments, program):  1464         # NOTE: No type checking performed.  1465         program.load_const(0)  1466         self._if_xcmpx(arguments, program, "<=")  1467   1468     def ifnonnull(self, arguments, program):  1469         # NOTE: No type checking performed.  1470         program.load_const(None)  1471         self._if_xcmpx(arguments, program, "is not")  1472   1473     def ifnull(self, arguments, program):  1474         # NOTE: No type checking performed.  1475         program.load_const(None)  1476         self._if_xcmpx(arguments, program, "is")  1477   1478     def iinc(self, arguments, program):  1479         # NOTE: No type checking performed.  1480         program.load_fast(arguments[0])  1481         program.load_const(arguments[1])  1482         program.binary_add()  1483         program.store_fast(arguments[0])  1484   1485     iload = fload  1486     iload_0 = fload_0  1487     iload_1 = fload_1  1488     iload_2 = fload_2  1489     iload_3 = fload_3  1490     imul = fmul  1491     ineg = fneg  1492   1493     def instanceof(self, arguments, program):  1494         index = (arguments[0] << 8) + arguments[1]  1495         target_name = self.class_file.constants[index - 1].get_python_name()  1496         program.use_external_name(target_name)  1497         program.load_global("isinstance")   # Stack: objectref, isinstance  1498         program.rot_two()                   # Stack: isinstance, objectref  1499         load_class_name(self.class_file, target_name, program)  1500         program.call_function(2)            # Stack: result  1501   1502     def _invoke(self, target_name, program):  1503         # NOTE: Using the string version of the name which may contain incompatible characters.  1504         program.load_attr(str(target_name)) # Stack: tuple, method  1505         program.rot_two()                   # Stack: method, tuple  1506         program.call_function_var(0)        # Stack: result  1507   1508     def invokeinterface(self, arguments, program):  1509         # NOTE: This implementation does not perform the necessary checks for  1510         # NOTE: signature-based polymorphism.  1511         # NOTE: Java rules not specifically obeyed.  1512         index = (arguments[0] << 8) + arguments[1]  1513         # NOTE: "count" == nargs + 1, apparently.  1514         count = arguments[2] - 1  1515         target_name = self.class_file.constants[index - 1].get_python_name()  1516         # Stack: objectref, arg1, arg2, ...  1517         program.build_tuple(count)          # Stack: objectref, tuple  1518         program.rot_two()                   # Stack: tuple, objectref  1519         # NOTE: The interface information is not used to discover the correct  1520         # NOTE: method.  1521         self._invoke(target_name, program)  1522   1523     def invokespecial(self, arguments, program):  1524         # NOTE: This implementation does not perform the necessary checks for  1525         # NOTE: signature-based polymorphism.  1526         # NOTE: Java rules not specifically obeyed.  1527         index = (arguments[0] << 8) + arguments[1]  1528         target = self.class_file.constants[index - 1]  1529         original_name = target.get_name()  1530         target_name = target.get_python_name()  1531   1532         # Get the number of parameters from the descriptor.  1533   1534         count = len(target.get_descriptor()[0])  1535   1536         # First, we build a tuple of the reference and arguments.  1537   1538         program.build_tuple(count + 1)          # Stack: tuple  1539   1540         # Get the class name instead of the fully qualified name.  1541         # NOTE: Not bothering with Object initialisation.  1542   1543         full_class_name = target.get_class().get_python_name()  1544         if full_class_name not in ("java.lang.Object", "java.lang.Exception"):  1545             program.use_external_name(full_class_name)  1546             load_class_name(self.class_file, full_class_name, program)  1547             self._invoke(target_name, program)  1548   1549         # Remove Python None return value.  1550   1551         if str(original_name) == "<init>":  1552             program.pop_top()  1553   1554     def invokestatic(self, arguments, program):  1555         # NOTE: This implementation does not perform the necessary checks for  1556         # NOTE: signature-based polymorphism.  1557         # NOTE: Java rules not specifically obeyed.  1558         index = (arguments[0] << 8) + arguments[1]  1559         target = self.class_file.constants[index - 1]  1560         target_name = target.get_python_name()  1561   1562         # Get the number of parameters from the descriptor.  1563   1564         count = len(target.get_descriptor()[0])  1565   1566         # Stack: arg1, arg2, ...  1567   1568         program.build_tuple(count)              # Stack: tuple  1569   1570         # Use the class to provide access to static methods.  1571         # Get the class name instead of the fully qualified name.  1572   1573         full_class_name = target.get_class().get_python_name()  1574         if full_class_name not in ("java.lang.Object", "java.lang.Exception"):  1575             program.use_external_name(full_class_name)  1576             load_class_name(self.class_file, full_class_name, program)  1577             self._invoke(target_name, program)  1578   1579     def invokevirtual (self, arguments, program):  1580         # NOTE: This implementation does not perform the necessary checks for  1581         # NOTE: signature-based polymorphism.  1582         # NOTE: Java rules not specifically obeyed.  1583         index = (arguments[0] << 8) + arguments[1]  1584         target = self.class_file.constants[index - 1]  1585         target_name = target.get_python_name()  1586         # Get the number of parameters from the descriptor.  1587         count = len(target.get_descriptor()[0])  1588         # Stack: objectref, arg1, arg2, ...  1589         program.build_tuple(count)          # Stack: objectref, tuple  1590         program.rot_two()                   # Stack: tuple, objectref  1591         self._invoke(target_name, program)  1592   1593     def ior(self, arguments, program):  1594         # NOTE: No type checking performed.  1595         program.binary_or()  1596   1597     irem = frem  1598     ireturn = freturn  1599   1600     def ishl(self, arguments, program):  1601         # NOTE: No type checking performed.  1602         # NOTE: Not verified.  1603         program.binary_lshift()  1604   1605     def ishr(self, arguments, program):  1606         # NOTE: No type checking performed.  1607         # NOTE: Not verified.  1608         program.binary_rshift()  1609   1610     istore = fstore  1611     istore_0 = fstore_0  1612     istore_1 = fstore_1  1613     istore_2 = fstore_2  1614     istore_3 = fstore_3  1615     isub = fsub  1616     iushr = ishr # Ignoring distinctions between arithmetic and logical shifts  1617   1618     def ixor(self, arguments, program):  1619         # NOTE: No type checking performed.  1620         program.binary_xor()  1621   1622     def jsr(self, arguments, program):  1623         offset = signed2((arguments[0] << 8) + arguments[1])  1624         java_absolute = self.java_position + offset  1625         # Store the address of the next instruction.  1626         program.load_const_ret(self.position_mapping[self.java_position + 3])  1627         program.jump_absolute(self.position_mapping[java_absolute])  1628   1629     def jsr_w(self, arguments, program):  1630         offset = signed4((arguments[0] << 24) + (arguments[1] << 16) + (arguments[2] << 8) + arguments[3])  1631         java_absolute = self.java_position + offset  1632         # Store the address of the next instruction.  1633         program.load_const_ret(self.position_mapping[self.java_position + 5])  1634         program.jump_absolute(self.position_mapping[java_absolute])  1635   1636     l2d = i2d  1637     l2f = i2f  1638   1639     def l2i(self, arguments, program):  1640         pass # Preserving Java semantics  1641   1642     ladd = iadd  1643     laload = iaload  1644     land = iand  1645     lastore = iastore  1646   1647     def lcmp(self, arguments, program):  1648         # NOTE: No type checking performed.  1649         program.dup_topx(2)                 # Stack: value1, value2, value1, value2  1650         program.compare_op(">")             # Stack: value1, value2, result  1651         program.jump_to_label(0, "equals")  1652         # True - produce result and branch.  1653         program.pop_top()                   # Stack: value1, value2  1654         program.pop_top()                   # Stack: value1  1655         program.pop_top()                   # Stack:  1656         program.load_const(1)               # Stack: 1  1657         program.jump_to_label(None, "next")  1658         # False - test equality.  1659         program.start_label("equals")  1660         program.pop_top()                   # Stack: value1, value2  1661         program.dup_topx(2)                 # Stack: value1, value2, value1, value2  1662         program.compare_op("==")            # Stack: value1, value2, result  1663         program.jump_to_label(0, "less")  1664         # True - produce result and branch.  1665         program.pop_top()                   # Stack: value1, value2  1666         program.pop_top()                   # Stack: value1  1667         program.pop_top()                   # Stack:  1668         program.load_const(0)               # Stack: 0  1669         program.jump_to_label(None, "next")  1670         # False - produce result.  1671         program.start_label("less")  1672         program.pop_top()                   # Stack: value1, value2  1673         program.pop_top()                   # Stack: value1  1674         program.pop_top()                   # Stack:  1675         program.load_const(-1)              # Stack: -1  1676         program.start_label("next")  1677   1678     lconst_0 = iconst_0  1679     lconst_1 = iconst_1  1680   1681     def ldc(self, arguments, program):  1682         const = self.class_file.constants[arguments[0] - 1]  1683         if isinstance(const, classfile.StringInfo):  1684             program.use_external_name("java.lang.String")  1685             program.load_global("java")  1686             program.load_attr("lang")  1687             program.load_attr("String")  1688             program.load_const(const.get_value())  1689             program.call_function(1)  1690         else:  1691             program.load_const(const.get_value())  1692   1693     def ldc_w(self, arguments, program):  1694         const = self.class_file.constants[(arguments[0] << 8) + arguments[1] - 1]  1695         if isinstance(const, classfile.StringInfo):  1696             program.use_external_name("java.lang.String")  1697             program.load_global("java")  1698             program.load_attr("lang")  1699             program.load_attr("String")  1700             program.load_const(const.get_value())  1701             program.call_function(1)  1702         else:  1703             program.load_const(const.get_value())  1704   1705     ldc2_w = ldc_w  1706     ldiv = idiv  1707     lload = iload  1708     lload_0 = iload_0  1709     lload_1 = iload_1  1710     lload_2 = iload_2  1711     lload_3 = iload_3  1712     lmul = imul  1713     lneg = ineg  1714   1715     def lookupswitch(self, code, program):  1716   1717         # Find the offset to the next 4 byte boundary in the code.  1718   1719         d, r = divmod(self.java_position + 1, 4)  1720         to_boundary = (4 - r) % 4  1721   1722         # Get the pertinent arguments.  1723   1724         code = code[to_boundary:]  1725         default = classfile.u4(code[0:4])  1726         npairs = classfile.u4(code[4:8])  1727   1728         # Process the pairs.  1729         # NOTE: This is not the most optimal implementation.  1730   1731         pair_index = 8  1732         for pair in range(0, npairs):  1733             match = classfile.u4(code[pair_index:pair_index+4])  1734             offset = classfile.s4(code[pair_index+4:pair_index+8])  1735             # Calculate the branch target.  1736             java_absolute = self.java_position + offset  1737             # Generate branching code.  1738             program.dup_top()                                           # Stack: key, key  1739             program.load_const(match)                                   # Stack: key, key, match  1740             program.compare_op("==")                                    # Stack: key, result  1741             program.jump_to_label(0, "end")  1742             program.pop_top()                                           # Stack: key  1743             program.pop_top()                                           # Stack:  1744             program.jump_absolute(self.position_mapping[java_absolute])  1745             # Generate the label for the end of the branching code.  1746             program.start_label("end")  1747             program.pop_top()                                           # Stack: key  1748             # Update the index.  1749             pair_index += 4  1750   1751         # Generate the default.  1752   1753         java_absolute = self.java_position + default  1754         program.jump_absolute(self.position_mapping[java_absolute])  1755         return pair_index + to_boundary  1756   1757     lor = ior  1758     lrem = irem  1759     lreturn = ireturn  1760     lshl = ishl  1761     lshr = ishr  1762     lstore = istore  1763     lstore_0 = istore_0  1764     lstore_1 = istore_1  1765     lstore_2 = istore_2  1766     lstore_3 = istore_3  1767     lsub = isub  1768     lushr = iushr  1769     lxor = ixor  1770   1771     def monitorenter(self, arguments, program):  1772         # NOTE: To be implemented.  1773         pass  1774   1775     def monitorexit(self, arguments, program):  1776         # NOTE: To be implemented.  1777         pass  1778   1779     def multianewarray(self, arguments, program):  1780         index = (arguments[0] << 8) + arguments[1]  1781         dimensions = arguments[2]  1782         # Stack: count1, ..., countN-1, countN  1783         self._newarray(program)             # Stack: count1, ..., countN-1, list  1784         for dimension in range(1, dimensions):  1785             program.rot_two()               # Stack: count1, ..., list, countN-1  1786             program.build_list(0)           # Stack: count1, ..., list, countN-1, new-list  1787             program.rot_three()             # Stack: count1, ..., new-list, list, countN-1  1788             program.setup_loop()  1789             program.load_const(0)           # Stack: count1, ..., new-list, list, countN-1, 0  1790             program.rot_two()               # Stack: count1, ..., new-list, list, 0, countN-1  1791             program.load_global("range")    # Stack: count1, ..., new-list, list, 0, countN-1, range  1792             program.rot_three()             # Stack: count1, ..., new-list, list, range, 0, countN-1  1793             program.call_function(2)        # Stack: count1, ..., new-list, list, range-list  1794             program.get_iter()              # Stack: count1, ..., new-list, list, iter  1795             program.for_iter()              # Stack: count1, ..., new-list, list, iter, value  1796             program.pop_top()               # Stack: count1, ..., new-list, list, iter  1797             program.rot_three()             # Stack: count1, ..., iter, new-list, list  1798             program.slice_0()               # Stack: count1, ..., iter, new-list, list[:]  1799             program.dup_top()               # Stack: count1, ..., iter, new-list, list[:], list[:]  1800             program.rot_three()             # Stack: count1, ..., iter, list[:], new-list, list[:]  1801             program.rot_two()               # Stack: count1, ..., iter, list[:], list[:], new-list  1802             program.dup_top()               # Stack: count1, ..., iter, list[:], list[:], new-list, new-list  1803             program.load_attr("append")     # Stack: count1, ..., iter, list[:], list[:], new-list, append  1804             program.rot_three()             # Stack: count1, ..., iter, list[:], append, list[:], new-list  1805             program.rot_three()             # Stack: count1, ..., iter, list[:], new-list, append, list[:]  1806             program.call_function(1)        # Stack: count1, ..., iter, list[:], new-list, None  1807             program.pop_top()               # Stack: count1, ..., iter, list[:], new-list  1808             program.rot_two()               # Stack: count1, ..., iter, new-list, list[:]  1809             program.rot_three()             # Stack: count1, ..., list[:], iter, new-list  1810             program.rot_three()             # Stack: count1, ..., new-list, list[:], iter  1811             program.end_loop()              # Stack: count1, ..., new-list, list[:], iter  1812             program.pop_top()               # Stack: count1, ..., new-list  1813   1814     def new(self, arguments, program):  1815         # This operation is considered to be the same as the calling of the  1816         # initialisation method of the given class with no arguments.  1817   1818         index = (arguments[0] << 8) + arguments[1]  1819         target_name = self.class_file.constants[index - 1].get_python_name()  1820         program.use_external_name(target_name)  1821   1822         # NOTE: Using the string version of the name which may contain incompatible characters.  1823         program.load_global("object")  1824         program.load_attr("__new__")  1825         load_class_name(self.class_file, target_name, program)  1826         program.call_function(1)  1827   1828     def newarray(self, arguments, program):  1829         # NOTE: Does not raise NegativeArraySizeException.  1830         # NOTE: Not using the arguments to type the list/array.  1831         self._newarray(program)  1832   1833     def nop(self, arguments, program):  1834         pass  1835   1836     def pop(self, arguments, program):  1837         program.pop_top()  1838   1839     pop2 = pop # ignoring Java stack value distinctions  1840   1841     def putfield(self, arguments, program):  1842         index = (arguments[0] << 8) + arguments[1]  1843         target_name = self.class_file.constants[index - 1].get_python_name()  1844         program.rot_two()  1845         # NOTE: Using the string version of the name which may contain incompatible characters.  1846         program.store_attr(str(target_name))  1847   1848     def putstatic(self, arguments, program):  1849         index = (arguments[0] << 8) + arguments[1]  1850         target = self.class_file.constants[index - 1]  1851         target_name = target.get_python_name()  1852   1853         # Get the class name instead of the fully qualified name.  1854   1855         full_class_name = target.get_class().get_python_name()  1856         program.use_external_name(full_class_name)  1857         load_class_name(self.class_file, full_class_name, program)  1858         # NOTE: Using the string version of the name which may contain incompatible characters.  1859         program.store_attr(str(target_name))  1860   1861     def ret(self, arguments, program):  1862         program.ret(arguments[0])  1863         # Indicate that the finally handler is probably over.  1864         # NOTE: This is seemingly not guaranteed.  1865         self.in_finally = 0  1866   1867     def return_(self, arguments, program):  1868         program.load_const(None)  1869         program.return_value()  1870   1871     saload = laload  1872     sastore = lastore  1873   1874     def sipush(self, arguments, program):  1875         program.load_const((arguments[0] << 8) + arguments[1])  1876   1877     def swap(self, arguments, program):  1878         program.rot_two()  1879   1880     def tableswitch(self, code, program):  1881   1882         # Find the offset to the next 4 byte boundary in the code.  1883   1884         d, r = divmod(self.java_position + 1, 4)  1885         to_boundary = (4 - r) % 4  1886   1887         # Get the pertinent arguments.  1888   1889         code = code[to_boundary:]  1890         default = classfile.u4(code[0:4])  1891         low = classfile.u4(code[4:8])  1892         high = classfile.u4(code[8:12])  1893   1894         # Process the jump entries.  1895         # NOTE: This is not the most optimal implementation.  1896   1897         jump_index = 12  1898         for jump in range(low, high + 1):  1899             offset = classfile.s4(code[jump_index:jump_index + 4])  1900   1901             # Calculate the branch target.  1902   1903             java_absolute = self.java_position + offset  1904   1905             # Generate branching code.  1906   1907             program.dup_top()                                           # Stack: key, key  1908             program.load_const(jump)                                    # Stack: key, key, jump  1909             program.compare_op("==")                                    # Stack: key, result  1910             program.jump_to_label(0, "end")  1911             program.pop_top()                                           # Stack: key  1912             program.pop_top()                                           # Stack:  1913             program.jump_absolute(self.position_mapping[java_absolute])  1914   1915             # Generate the label for the end of the branching code.  1916   1917             program.start_label("end")  1918             program.pop_top()                                           # Stack: key  1919   1920             # Update the index.  1921   1922             jump_index += 4  1923   1924         # Generate the default.  1925   1926         java_absolute = self.java_position + default  1927         program.jump_absolute(self.position_mapping[java_absolute])  1928         return jump_index + to_boundary  1929   1930     def wide(self, code, program):  1931         # NOTE: To be implemented.  1932         return number_of_arguments  1933   1934 def disassemble(class_file, method):  1935     disassembler = BytecodeDisassembler(class_file)  1936     disassembler.process(method, BytecodeDisassemblerProgram())  1937   1938 class ClassTranslator:  1939   1940     """  1941     A class which provides a wrapper around a class file and the means to  1942     translate the represented class into a Python class.  1943     """  1944   1945     def __init__(self, class_file):  1946   1947         "Initialise the object with the given 'class_file'."  1948   1949         self.class_file = class_file  1950         self.filename = ""  1951   1952         for attribute in self.class_file.attributes:  1953             if isinstance(attribute, classfile.SourceFileAttributeInfo):  1954                 self.filename = str(attribute.get_name())  1955   1956     def translate_method(self, method):  1957   1958         "Translate the given 'method' - an object obtained from the class file."  1959   1960         translator = BytecodeTranslator(self.class_file)  1961         writer = BytecodeWriter()  1962         translator.process(method, writer)  1963         return translator, writer  1964   1965     def make_method(self, real_method_name, methods, global_names, namespace):  1966   1967         """  1968         Make a dispatcher method with the given 'real_method_name', providing  1969         dispatch to the supplied type-sensitive 'methods', accessing the given  1970         'global_names' where necessary, and storing the new method in the  1971         'namespace' provided.  1972         """  1973   1974         if real_method_name == "<init>":  1975             method_name = "__init__"  1976         else:  1977             method_name = real_method_name  1978   1979         # Where only one method exists, just make an alias.  1980   1981         if len(methods) == 1:  1982             method, fn = methods[0]  1983             namespace[method_name] = fn  1984             return  1985   1986         # Write a simple bytecode dispatching mechanism.  1987   1988         program = BytecodeWriter()  1989   1990         # Remember whether any of the methods are static.  1991         # NOTE: This should be an all or nothing situation.  1992   1993         method_is_static = 0  1994   1995         # NOTE: The code below should use dictionary-based dispatch for better performance.  1996   1997         for method, fn in methods:  1998             method_is_static = real_method_name != "<init>" and method_is_static or \  1999                 classfile.has_flags(method.access_flags, [classfile.STATIC])  2000   2001             if method_is_static:  2002                 program.load_fast(0)                # Stack: arguments  2003             else:  2004                 program.load_fast(1)                # Stack: arguments  2005   2006             program.setup_loop()  2007             program.load_const(1)                   # Stack: arguments, 1  2008   2009             if method_is_static:  2010                 program.store_fast(1)               # Stack: arguments (found = 1)  2011             else:  2012                 program.store_fast(2)               # Stack: arguments (found = 1)  2013   2014             # Emit a list of parameter types.  2015   2016             descriptor_types = method.get_descriptor()[0]  2017             for descriptor_type in descriptor_types:  2018                 base_type, object_type, array_type = descriptor_type  2019                 python_type = classfile.descriptor_base_type_mapping[base_type]  2020                 if python_type == "instance":  2021                     # NOTE: This will need extending.  2022                     python_type = object_type  2023                 program.load_global(python_type)    # Stack: arguments, type, ...  2024             program.build_list(len(descriptor_types))  2025                                                     # Stack: arguments, types  2026             # Make a map of arguments and types.  2027             program.load_const(None)                # Stack: arguments, types, None  2028             program.rot_three()                     # Stack: None, arguments, types  2029             program.build_tuple(3)                  # Stack: tuple  2030             program.load_global("map")              # Stack: tuple, map  2031             program.rot_two()                       # Stack: map, tuple  2032             program.call_function_var(0)            # Stack: list (mapping arguments to types)  2033             # Loop over each pair.  2034             program.get_iter()                      # Stack: iter  2035             program.for_iter()                      # Stack: iter, (argument, type)  2036             program.unpack_sequence(2)              # Stack: iter, type, argument  2037             program.dup_top()                       # Stack: iter, type, argument, argument  2038             program.load_const(None)                # Stack: iter, type, argument, argument, None  2039             program.compare_op("is")                # Stack: iter, type, argument, result  2040             # Missing argument?  2041             program.jump_to_label(0, "present")  2042             program.pop_top()                       # Stack: iter, type, argument  2043             program.pop_top()                       # Stack: iter, type  2044             program.pop_top()                       # Stack: iter  2045             program.load_const(0)                   # Stack: iter, 0  2046   2047             if method_is_static:  2048                 program.store_fast(1)               # Stack: iter (found = 0)  2049             else:  2050                 program.store_fast(2)               # Stack: iter (found = 0)  2051   2052             program.break_loop()  2053             # Argument was present.  2054             program.start_label("present")  2055             program.pop_top()                       # Stack: iter, type, argument  2056             program.rot_two()                       # Stack: iter, argument, type  2057             program.dup_top()                       # Stack: iter, argument, type, type  2058             program.load_const(None)                # Stack: iter, argument, type, type, None  2059             program.compare_op("is")                # Stack: iter, argument, type, result  2060             # Missing parameter type?  2061             program.jump_to_label(0, "present")  2062             program.pop_top()                       # Stack: iter, argument, type  2063             program.pop_top()                       # Stack: iter, argument  2064             program.pop_top()                       # Stack: iter  2065             program.load_const(0)                   # Stack: iter, 0  2066   2067             if method_is_static:  2068                 program.store_fast(1)               # Stack: iter (found = 0)  2069             else:  2070                 program.store_fast(2)               # Stack: iter (found = 0)  2071   2072             program.break_loop()  2073             # Parameter was present.  2074             program.start_label("present")  2075             program.pop_top()                       # Stack: iter, argument, type  2076             program.build_tuple(2)                  # Stack: iter, (argument, type)  2077             program.load_global("isinstance")       # Stack: iter, (argument, type), isinstance  2078             program.rot_two()                       # Stack: iter, isinstance, (argument, type)  2079             program.call_function_var(0)            # Stack: iter, result  2080             program.jump_to_label(1, "match")  2081             program.pop_top()                       # Stack: iter  2082             program.load_const(0)                   # Stack: iter, 0  2083   2084             if method_is_static:  2085                 program.store_fast(1)               # Stack: iter (found = 0)  2086             else:  2087                 program.store_fast(2)               # Stack: iter (found = 0)  2088   2089             program.break_loop()  2090             # Argument type and parameter type matched.  2091             program.start_label("match")  2092             program.pop_top()                       # Stack: iter  2093             program.end_loop()                      # Stack:  2094             # If all the parameters matched, call the method.  2095   2096             if method_is_static:  2097                 program.load_fast(1)                # Stack: match  2098             else:  2099                 program.load_fast(2)                # Stack: match  2100   2101             program.jump_to_label(0, "failed")  2102             # All the parameters matched.  2103             program.pop_top()                       # Stack:  2104   2105             if method_is_static:  2106                 program.load_fast(0)                # Stack: arguments  2107                 program.load_global(str(self.class_file.this_class.get_python_name()))  2108                                                     # Stack: arguments, class  2109             else:  2110                 program.load_fast(1)                # Stack: arguments  2111                 program.load_fast(0)                # Stack: arguments, self  2112   2113             program.load_attr(str(method.get_python_name()))  2114                                                     # Stack: arguments, method  2115             program.rot_two()                       # Stack: method, arguments  2116             program.call_function_var(0)            # Stack: result  2117             program.return_value()  2118             # Try the next method if arguments or parameters were missing or incorrect.  2119             program.start_label("failed")  2120             program.pop_top()                       # Stack:  2121   2122         # Raise an exception if nothing matched.  2123         # NOTE: Improve this.  2124   2125         program.load_const("No matching method")  2126         program.raise_varargs(1)  2127         program.load_const(None)  2128         program.return_value()  2129   2130         # Add the code as a method in the namespace.  2131         # NOTE: One actual parameter, flags as 71 apparently means that a list  2132         # NOTE: parameter is used in a method.  2133   2134         if method_is_static:  2135             nargs = 0  2136         else:  2137             nargs = 1  2138         nlocals = program.max_locals + 1  2139   2140         code = new.code(nargs, nlocals, program.max_stack_depth, 71, program.get_output(),  2141             tuple(program.get_constants()), tuple(program.get_names()), tuple(self.make_varnames(nlocals, method_is_static)),  2142             self.filename, method_name, 0, "")  2143         fn = new.function(code, global_names)  2144   2145         if method_is_static:  2146             fn = staticmethod(fn)  2147   2148         namespace[method_name] = fn  2149   2150     def process(self, global_names):  2151   2152         """  2153         Process the class, storing it in the 'global_names' dictionary provided.  2154         Return a tuple containing the class and a list of external names  2155         referenced by the class's methods.  2156         """  2157   2158         namespace = {}  2159   2160         # Make the fields.  2161   2162         for field in self.class_file.fields:  2163             if classfile.has_flags(field.access_flags, [classfile.STATIC]):  2164                 field_name = str(field.get_python_name())  2165                 namespace[field_name] = None  2166   2167         # Make the methods.  2168   2169         real_methods = {}  2170         external_names = []  2171   2172         for method in self.class_file.methods:  2173             real_method_name = str(method.get_name())  2174             method_name = str(method.get_python_name())  2175   2176             translator, writer = self.translate_method(method)  2177   2178             # Add external names to the master list.  2179   2180             for external_name in writer.external_names:  2181                 if external_name not in external_names:  2182                     external_names.append(external_name)  2183   2184             # Fix up special class initialisation methods and static methods.  2185   2186             method_is_static = real_method_name != "<init>" and classfile.has_flags(method.access_flags, [classfile.STATIC])  2187             if method_is_static:  2188                 nargs = len(method.get_descriptor()[0])  2189             else:  2190                 nargs = len(method.get_descriptor()[0]) + 1  2191             nlocals = writer.max_locals + 1  2192             flags = 67  2193   2194             # NOTE: Add line number table later.  2195   2196             code = new.code(nargs, nlocals, writer.max_stack_depth, flags, writer.get_output(),  2197                 tuple(writer.get_constants()), tuple(writer.get_names()),  2198                 tuple(self.make_varnames(nlocals, method_is_static)), self.filename, method_name, 0, "")  2199   2200             # NOTE: May need more globals.  2201   2202             fn = new.function(code, global_names)  2203   2204             # Fix up special class initialisation methods and static methods.  2205   2206             if method_is_static:  2207                 fn = staticmethod(fn)  2208   2209             # Remember the real method name and the corresponding methods produced.  2210   2211             if not real_methods.has_key(real_method_name):  2212                 real_methods[real_method_name] = []  2213             real_methods[real_method_name].append((method, fn))  2214   2215             # Add the method to the class's namespace.  2216   2217             namespace[method_name] = fn  2218   2219         # Define superclasses.  2220   2221         bases = self.get_base_classes(global_names)  2222   2223         # Define method dispatchers.  2224   2225         for real_method_name, methods in real_methods.items():  2226             if real_method_name != "<clinit>":  2227                 self.make_method(real_method_name, methods, global_names, namespace)  2228   2229         # Use only the last part of the fully qualified name.  2230   2231         full_class_name = str(self.class_file.this_class.get_python_name())  2232         class_name = full_class_name.split(".")[-1]  2233         cls = new.classobj(class_name, bases, namespace)  2234         global_names[cls.__name__] = cls  2235   2236         return cls, external_names  2237   2238     def get_base_classes(self, global_names):  2239   2240         """  2241         Identify the superclass, then either load it from the given  2242         'global_names' if available, or import the class from its parent module.  2243         Return a tuple containing all base classes (typically a single element  2244         tuple).  2245         """  2246   2247         original_name = str(self.class_file.super_class.get_name())  2248         if original_name in ("java/lang/Object", "java/lang/Exception"):  2249             return (object,)  2250         else:  2251             full_this_class_name = str(self.class_file.this_class.get_python_name())  2252             this_class_name_parts = full_this_class_name.split(".")  2253             this_class_module_name = ".".join(this_class_name_parts[:-1])  2254             full_super_class_name = str(self.class_file.super_class.get_python_name())  2255             super_class_name_parts = full_super_class_name.split(".")  2256             super_class_name = super_class_name_parts[-1]  2257             super_class_module_name = ".".join(super_class_name_parts[:-1])  2258             if super_class_module_name == "":  2259                 obj = global_names[super_class_name]  2260             elif super_class_module_name == this_class_module_name:  2261                 obj = global_names[super_class_name]  2262             else:  2263                 print "Importing", super_class_module_name, super_class_name  2264                 obj = __import__(super_class_module_name, global_names, {}, [])  2265                 for super_class_name_part in super_class_name_parts[1:] or [super_class_name]:  2266                     print "*", obj, super_class_name_part  2267                     obj = getattr(obj, super_class_name_part)  2268             return (obj,)  2269   2270     def make_varnames(self, nlocals, method_is_static=0):  2271   2272         """  2273         A utility method which invents variable names for the given number -  2274         'nlocals' - of local variables in a method. Returns a list of such  2275         variable names.  2276   2277         If the optional 'method_is_static' is set to true, do not use "self" as  2278         the first argument name.  2279         """  2280   2281         if method_is_static:  2282             l = ["cls"]  2283         else:  2284             l = ["self"]  2285         for i in range(1, nlocals):  2286             l.append("_l%s" % i)  2287         return l[:nlocals]  2288   2289 # Test functions, useful for tracing generated bytecode operations.  2290   2291 def _map(*args):  2292     print args  2293     return apply(__builtins__.map, args)  2294   2295 def _isinstance(*args):  2296     print args  2297     return apply(__builtins__.isinstance, args)  2298   2299 if __name__ == "__main__":  2300     import sys  2301     import dis  2302     global_names = globals()  2303     #global_names["isinstance"] = _isinstance  2304     #global_names["map"] = _map  2305     for filename in sys.argv[1:]:  2306         f = open(filename, "rb")  2307         c = classfile.ClassFile(f.read())  2308         translator = ClassTranslator(c)  2309         cls, external_names = translator.process(global_names)  2310   2311 # vim: tabstop=4 expandtab shiftwidth=4