javaclass

bytecode.py

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