javaclass

bytecode.py

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