javaclass

bytecode.py

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