javaclass

javaclass/bytecode.py

150:6c5a400aeffd
2005-01-23 Paul Boddie Fixed imports.
     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 atypes_to_default_values = {   662     4 : 0,      # bool (NOTE: Should be False.)   663     5 : u"",    # char   664     6 : 0.0,    # float   665     7 : 0.0,    # double   666     8 : 0,      # byte   667     9 : 0,      # short   668     10: 0,      # int   669     11: 0       # long   670 }   671    672 def get_default_for_atype(atype):   673     global atypes_to_default_values   674     return atypes_to_default_values.get(atype)   675    676 # Bytecode conversion.   677    678 class BytecodeReader:   679    680     "A generic Java bytecode reader."   681    682     def __init__(self, class_file):   683    684         """   685         Initialise the reader with a 'class_file' containing essential   686         information for any bytecode inspection activity.   687         """   688    689         self.class_file = class_file   690         self.position_mapping = LazyDict()   691    692     def process(self, method, program):   693    694         """   695         Process the given 'method' (obtained from the class file), using the   696         given 'program' to write translated Python bytecode instructions.   697         """   698    699         self.java_position = 0   700         self.in_finally = 0   701         self.method = method   702    703         # NOTE: Potentially unreliable way of getting necessary information.   704    705         code, exception_table = None, None   706         for attribute in method.attributes:   707             if isinstance(attribute, classfile.CodeAttributeInfo):   708                 code, exception_table = attribute.code, attribute.exception_table   709                 break   710    711         # Where no code was found, write a very simple placeholder routine.   712         # This is useful for interfaces and abstract classes.   713         # NOTE: Assess the correctness of doing this. An exception should really   714         # NOTE: be raised instead.   715    716         if code is None:   717             program.load_const(None)   718             program.return_value()   719             return   720    721         # Produce a structure which permits fast access to exception details.   722    723         exception_block_start = {}   724         exception_block_end = {}   725         exception_block_handler = {}   726         reversed_exception_table = exception_table[:]   727         reversed_exception_table.reverse()   728    729         # Later entries have wider coverage than earlier entries.   730    731         for exception in reversed_exception_table:   732    733             # Index start positions.   734    735             if not exception_block_start.has_key(exception.start_pc):   736                 exception_block_start[exception.start_pc] = []   737             exception_block_start[exception.start_pc].append(exception)   738    739             # Index end positions.   740    741             if not exception_block_end.has_key(exception.end_pc):   742                 exception_block_end[exception.end_pc] = []   743             exception_block_end[exception.end_pc].append(exception)   744    745             # Index handler positions.   746    747             if not exception_block_handler.has_key(exception.handler_pc):   748                 exception_block_handler[exception.handler_pc] = []   749             exception_block_handler[exception.handler_pc].append(exception)   750    751         # Process each instruction in the code.   752    753         while self.java_position < len(code):   754             self.position_mapping[self.java_position] = program.position   755    756             # Insert exception handling constructs.   757    758             block_starts = exception_block_start.get(self.java_position, [])   759             for exception in block_starts:   760    761                 # Note that the absolute position is used.   762    763                 if exception.catch_type == 0:   764                     program.setup_finally(self.position_mapping[exception.handler_pc])   765                 else:   766                     program.setup_except(self.position_mapping[exception.handler_pc])   767    768             if block_starts:   769                 self.in_finally = 0   770    771             # Insert exception handler details.   772             # NOTE: Ensure that pop_block is reachable by possibly inserting it at the start of finally handlers.   773             # NOTE: Insert a check for the correct exception at the start of each handler.   774    775             for exception in exception_block_handler.get(self.java_position, []):   776                 program.end_exception()   777                 if exception.catch_type == 0:   778                     self.in_finally = 1   779                 else:   780                     program.start_handler(self.class_file.constants[exception.catch_type - 1].get_python_name(), self.class_file)   781    782             # Process the bytecode at the current position.   783    784             bytecode = ord(code[self.java_position])   785             mnemonic, number_of_arguments = self.java_bytecodes[bytecode]   786             number_of_arguments = self.process_bytecode(mnemonic, number_of_arguments, code, program)   787             next_java_position = self.java_position + 1 + number_of_arguments   788    789             # Insert exception block end details.   790    791             for exception in exception_block_end.get(next_java_position, []):   792    793                 # NOTE: Insert jump beyond handlers.   794                 # NOTE: program.jump_forward/absolute(...)   795                 # NOTE: Insert end finally at end of handlers as well as where "ret" occurs.   796    797                 if exception.catch_type != 0:   798                     program.pop_block()   799    800             # Only advance the JVM position after sneaking in extra Python   801             # instructions.   802    803             self.java_position = next_java_position   804    805     def process_bytecode(self, mnemonic, number_of_arguments, code, program):   806    807         """   808         Process a bytecode instruction with the given 'mnemonic' and   809         'number_of_arguments'. The 'code' parameter contains the full method   810         code so that argument data can be inspected. The 'program' parameter is   811         used to produce a Python translation of the instruction.   812         """   813    814         if number_of_arguments is not None:   815             arguments = []   816             for j in range(0, number_of_arguments):   817                 arguments.append(ord(code[self.java_position + 1 + j]))   818    819             # Call the handler.   820    821             getattr(self, mnemonic)(arguments, program)   822             return number_of_arguments   823         else:   824             # Call the handler.   825    826             return getattr(self, mnemonic)(code[self.java_position+1:], program)   827    828     java_bytecodes = {   829         # code : (mnemonic, number of following bytes, change in stack)   830         0 : ("nop", 0),   831         1 : ("aconst_null", 0),   832         2 : ("iconst_m1", 0),   833         3 : ("iconst_0", 0),   834         4 : ("iconst_1", 0),   835         5 : ("iconst_2", 0),   836         6 : ("iconst_3", 0),   837         7 : ("iconst_4", 0),   838         8 : ("iconst_5", 0),   839         9 : ("lconst_0", 0),   840         10 : ("lconst_1", 0),   841         11 : ("fconst_0", 0),   842         12 : ("fconst_1", 0),   843         13 : ("fconst_2", 0),   844         14 : ("dconst_0", 0),   845         15 : ("dconst_1", 0),   846         16 : ("bipush", 1),   847         17 : ("sipush", 2),   848         18 : ("ldc", 1),   849         19 : ("ldc_w", 2),   850         20 : ("ldc2_w", 2),   851         21 : ("iload", 1),   852         22 : ("lload", 1),   853         23 : ("fload", 1),   854         24 : ("dload", 1),   855         25 : ("aload", 1),   856         26 : ("iload_0", 0),   857         27 : ("iload_1", 0),   858         28 : ("iload_2", 0),   859         29 : ("iload_3", 0),   860         30 : ("lload_0", 0),   861         31 : ("lload_1", 0),   862         32 : ("lload_2", 0),   863         33 : ("lload_3", 0),   864         34 : ("fload_0", 0),   865         35 : ("fload_1", 0),   866         36 : ("fload_2", 0),   867         37 : ("fload_3", 0),   868         38 : ("dload_0", 0),   869         39 : ("dload_1", 0),   870         40 : ("dload_2", 0),   871         41 : ("dload_3", 0),   872         42 : ("aload_0", 0),   873         43 : ("aload_1", 0),   874         44 : ("aload_2", 0),   875         45 : ("aload_3", 0),   876         46 : ("iaload", 0),   877         47 : ("laload", 0),   878         48 : ("faload", 0),   879         49 : ("daload", 0),   880         50 : ("aaload", 0),   881         51 : ("baload", 0),   882         52 : ("caload", 0),   883         53 : ("saload", 0),   884         54 : ("istore", 1),   885         55 : ("lstore", 1),   886         56 : ("fstore", 1),   887         57 : ("dstore", 1),   888         58 : ("astore", 1),   889         59 : ("istore_0", 0),   890         60 : ("istore_1", 0),   891         61 : ("istore_2", 0),   892         62 : ("istore_3", 0),   893         63 : ("lstore_0", 0),   894         64 : ("lstore_1", 0),   895         65 : ("lstore_2", 0),   896         66 : ("lstore_3", 0),   897         67 : ("fstore_0", 0),   898         68 : ("fstore_1", 0),   899         69 : ("fstore_2", 0),   900         70 : ("fstore_3", 0),   901         71 : ("dstore_0", 0),   902         72 : ("dstore_1", 0),   903         73 : ("dstore_2", 0),   904         74 : ("dstore_3", 0),   905         75 : ("astore_0", 0),   906         76 : ("astore_1", 0),   907         77 : ("astore_2", 0),   908         78 : ("astore_3", 0),   909         79 : ("iastore", 0),   910         80 : ("lastore", 0),   911         81 : ("fastore", 0),   912         82 : ("dastore", 0),   913         83 : ("aastore", 0),   914         84 : ("bastore", 0),   915         85 : ("castore", 0),   916         86 : ("sastore", 0),   917         87 : ("pop", 0),   918         88 : ("pop2", 0),   919         89 : ("dup", 0),   920         90 : ("dup_x1", 0),   921         91 : ("dup_x2", 0),   922         92 : ("dup2", 0),   923         93 : ("dup2_x1", 0),   924         94 : ("dup2_x2", 0),   925         95 : ("swap", 0),   926         96 : ("iadd", 0),   927         97 : ("ladd", 0),   928         98 : ("fadd", 0),   929         99 : ("dadd", 0),   930         100 : ("isub", 0),   931         101 : ("lsub", 0),   932         102 : ("fsub", 0),   933         103 : ("dsub", 0),   934         104 : ("imul", 0),   935         105 : ("lmul", 0),   936         106 : ("fmul", 0),   937         107 : ("dmul", 0),   938         108 : ("idiv", 0),   939         109 : ("ldiv", 0),   940         110 : ("fdiv", 0),   941         111 : ("ddiv", 0),   942         112 : ("irem", 0),   943         113 : ("lrem", 0),   944         114 : ("frem", 0),   945         115 : ("drem", 0),   946         116 : ("ineg", 0),   947         117 : ("lneg", 0),   948         118 : ("fneg", 0),   949         119 : ("dneg", 0),   950         120 : ("ishl", 0),   951         121 : ("lshl", 0),   952         122 : ("ishr", 0),   953         123 : ("lshr", 0),   954         124 : ("iushr", 0),   955         125 : ("lushr", 0),   956         126 : ("iand", 0),   957         127 : ("land", 0),   958         128 : ("ior", 0),   959         129 : ("lor", 0),   960         130 : ("ixor", 0),   961         131 : ("lxor", 0),   962         132 : ("iinc", 2),   963         133 : ("i2l", 0),   964         134 : ("i2f", 0),   965         135 : ("i2d", 0),   966         136 : ("l2i", 0),   967         137 : ("l2f", 0),   968         138 : ("l2d", 0),   969         139 : ("f2i", 0),   970         140 : ("f2l", 0),   971         141 : ("f2d", 0),   972         142 : ("d2i", 0),   973         143 : ("d2l", 0),   974         144 : ("d2f", 0),   975         145 : ("i2b", 0),   976         146 : ("i2c", 0),   977         147 : ("i2s", 0),   978         148 : ("lcmp", 0),   979         149 : ("fcmpl", 0),   980         150 : ("fcmpg", 0),   981         151 : ("dcmpl", 0),   982         152 : ("dcmpg", 0),   983         153 : ("ifeq", 2),   984         154 : ("ifne", 2),   985         155 : ("iflt", 2),   986         156 : ("ifge", 2),   987         157 : ("ifgt", 2),   988         158 : ("ifle", 2),   989         159 : ("if_icmpeq", 2),   990         160 : ("if_icmpne", 2),   991         161 : ("if_icmplt", 2),   992         162 : ("if_icmpge", 2),   993         163 : ("if_icmpgt", 2),   994         164 : ("if_icmple", 2),   995         165 : ("if_acmpeq", 2),   996         166 : ("if_acmpne", 2),   997         167 : ("goto", 2),   998         168 : ("jsr", 2),   999         169 : ("ret", 1),  1000         170 : ("tableswitch", None), # variable number of arguments  1001         171 : ("lookupswitch", None), # variable number of arguments  1002         172 : ("ireturn", 0),  1003         173 : ("lreturn", 0),  1004         174 : ("freturn", 0),  1005         175 : ("dreturn", 0),  1006         176 : ("areturn", 0),  1007         177 : ("return_", 0),  1008         178 : ("getstatic", 2),  1009         179 : ("putstatic", 2),  1010         180 : ("getfield", 2),  1011         181 : ("putfield", 2),  1012         182 : ("invokevirtual", 2),  1013         183 : ("invokespecial", 2),  1014         184 : ("invokestatic", 2),  1015         185 : ("invokeinterface", 4),  1016         187 : ("new", 2),  1017         188 : ("newarray", 1),  1018         189 : ("anewarray", 2),  1019         190 : ("arraylength", 0),  1020         191 : ("athrow", 0),  1021         192 : ("checkcast", 2),  1022         193 : ("instanceof", 2),  1023         194 : ("monitorenter", 0),  1024         195 : ("monitorexit", 0),  1025         196 : ("wide", None), # 3 or 5 arguments, stack changes according to modified element  1026         197 : ("multianewarray", 3),  1027         198 : ("ifnull", 2),  1028         199 : ("ifnonnull", 2),  1029         200 : ("goto_w", 4),  1030         201 : ("jsr_w", 4),  1031         }  1032   1033 class BytecodeDisassembler(BytecodeReader):  1034   1035     "A Java bytecode disassembler."  1036   1037     bytecode_methods = [spec[0] for spec in BytecodeReader.java_bytecodes.values()]  1038   1039     def __getattr__(self, name):  1040         if name in self.bytecode_methods:  1041             print "%5s %s" % (self.java_position, name),  1042             return self.generic  1043         else:  1044             raise AttributeError, name  1045   1046     def generic(self, arguments, program):  1047         print arguments  1048   1049     def lookupswitch(self, code, program):  1050         print "%5s lookupswitch" % (self.java_position,),  1051         d, r = divmod(self.java_position + 1, 4)  1052         to_boundary = (4 - r) % 4  1053         code = code[to_boundary:]  1054         default = classfile.u4(code[0:4])  1055         npairs = classfile.u4(code[4:8])  1056         print default, npairs  1057         return to_boundary + 8 + npairs * 8  1058   1059     def tableswitch(self, code, program):  1060         print "%5s tableswitch" % (self.java_position,),  1061         d, r = divmod(self.java_position + 1, 4)  1062         to_boundary = (4 - r) % 4  1063         code = code[to_boundary:]  1064         default = classfile.u4(code[0:4])  1065         low = classfile.u4(code[4:8])  1066         high = classfile.u4(code[8:12])  1067         print default, low, high  1068         return to_boundary + 12 + (high - low + 1) * 4  1069   1070 class BytecodeDisassemblerProgram:  1071     position = 0  1072     def setup_except(self, target):  1073         print "(setup_except %s)" % target  1074     def setup_finally(self, target):  1075         print "(setup_finally %s)" % target  1076     def end_exception(self):  1077         print "(end_exception)"  1078     def start_handler(self, exc_name, class_file):  1079         print "(start_handler %s)" % exc_name  1080     def pop_block(self):  1081         print "(pop_block)"  1082   1083 class BytecodeTranslator(BytecodeReader):  1084   1085     "A Java bytecode translator which uses a Python bytecode writer."  1086   1087     def aaload(self, arguments, program):  1088         # NOTE: No type checking performed.  1089         program.binary_subscr()  1090   1091     def aastore(self, arguments, program):  1092         # NOTE: No type checking performed.  1093         # Stack: arrayref, index, value  1094         program.rot_three() # Stack: value, arrayref, index  1095         program.store_subscr()  1096   1097     def aconst_null(self, arguments, program):  1098         program.load_const(None)  1099   1100     def aload(self, arguments, program):  1101         program.load_fast(arguments[0])  1102   1103     def aload_0(self, arguments, program):  1104         program.load_fast(0)  1105   1106     def aload_1(self, arguments, program):  1107         program.load_fast(1)  1108   1109     def aload_2(self, arguments, program):  1110         program.load_fast(2)  1111   1112     def aload_3(self, arguments, program):  1113         program.load_fast(3)  1114   1115     def anewarray(self, arguments, program):  1116         # NOTE: Does not raise NegativeArraySizeException.  1117         # NOTE: Not using the index to type the list/array.  1118         index = (arguments[0] << 8) + arguments[1]  1119         type_name = self.class_file.constants[index - 1].get_python_name()  1120         default_value = classfile.get_default_for_type(type_name)  1121         self._newarray(program, type_name)  1122   1123     def _newarray(self, program, default_value):  1124         program.build_list(0)               # Stack: count, list  1125         program.rot_two()                   # Stack: list, count  1126         program.setup_loop()  1127         program.load_global("range")  1128         program.load_const(0)               # Stack: list, count, range, 0  1129         program.rot_three()                 # Stack: list, 0, count, range  1130         program.rot_three()                 # Stack: list, range, 0, count  1131         program.call_function(2)            # Stack: list, range_list  1132         program.get_iter()                  # Stack: list, iter  1133         program.for_iter()                  # Stack: list, iter, value  1134         program.pop_top()                   # Stack: list, iter  1135         program.rot_two()                   # Stack: iter, list  1136         program.dup_top()                   # Stack: iter, list, list  1137         program.load_attr("append")         # Stack: iter, list, append  1138         program.load_const(default_value)   # Stack: iter, list, append, default  1139         program.call_function(1)            # Stack: iter, list, default  1140         program.pop_top()                   # Stack: iter, list  1141         program.rot_two()                   # Stack: list, iter  1142         program.end_loop()                  # Back to for_iter above  1143   1144     def areturn(self, arguments, program):  1145         program.return_value()  1146   1147     def arraylength(self, arguments, program):  1148         program.load_global("len")  # Stack: arrayref, len  1149         program.rot_two()           # Stack: len, arrayref  1150         program.call_function(1)  1151   1152     def astore(self, arguments, program):  1153         program.store_fast(arguments[0])  1154   1155     def astore_0(self, arguments, program):  1156         program.store_fast(0)  1157   1158     def astore_1(self, arguments, program):  1159         program.store_fast(1)  1160   1161     def astore_2(self, arguments, program):  1162         program.store_fast(2)  1163   1164     def astore_3(self, arguments, program):  1165         program.store_fast(3)  1166   1167     def athrow(self, arguments, program):  1168         # NOTE: NullPointerException not raised where null/None is found on the stack.  1169         # If this instruction appears in a finally handler, use end_finally instead.  1170         if self.in_finally:  1171             program.end_finally()  1172         else:  1173             # Wrap the exception in a Python exception.  1174             program.load_global("Exception")    # Stack: objectref, Exception  1175             program.rot_two()                   # Stack: Exception, objectref  1176             program.call_function(1)            # Stack: exception  1177             program.raise_varargs(1)  1178             # NOTE: This seems to put another object on the stack.  1179   1180     baload = aaload  1181     bastore = aastore  1182   1183     def bipush(self, arguments, program):  1184         program.load_const(signed1(arguments[0]))  1185   1186     caload = aaload  1187     castore = aastore  1188   1189     def checkcast(self, arguments, program):  1190         index = (arguments[0] << 8) + arguments[1]  1191         target_name = self.class_file.constants[index - 1].get_python_name()  1192         program.use_external_name(target_name)  1193         program.dup_top()                   # Stack: objectref, objectref  1194         program.load_const(None)            # Stack: objectref, objectref, None  1195         program.compare_op("is")            # Stack: objectref, result  1196         program.jump_to_label(1, "next")  1197         program.pop_top()                   # Stack: objectref  1198         program.dup_top()                   # Stack: objectref, objectref  1199         program.load_global("isinstance")   # Stack: objectref, objectref, isinstance  1200         program.rot_two()                   # Stack: objectref, isinstance, objectref  1201         load_class_name(self.class_file, target_name, program)  1202         program.call_function(2)            # Stack: objectref, result  1203         program.jump_to_label(1, "next")  1204         program.pop_top()                   # Stack: objectref  1205         program.pop_top()                   # Stack:  1206         program.use_external_name("java.lang.ClassCastException")  1207         load_class_name(self.class_file, "java.lang.ClassCastException", program)  1208         program.call_function(0)            # Stack: exception  1209         # Wrap the exception in a Python exception.  1210         program.load_global("Exception")    # Stack: exception, Exception  1211         program.rot_two()                   # Stack: Exception, exception  1212         program.call_function(1)            # Stack: exception  1213         program.raise_varargs(1)  1214         # NOTE: This seems to put another object on the stack.  1215         program.start_label("next")  1216         program.pop_top()                   # Stack: objectref  1217   1218     def d2f(self, arguments, program):  1219         pass  1220   1221     def d2i(self, arguments, program):  1222         program.load_global("int")  # Stack: value, int  1223         program.rot_two()           # Stack: int, value  1224         program.call_function(1)    # Stack: result  1225   1226     d2l = d2i # Preserving Java semantics  1227   1228     def dadd(self, arguments, program):  1229         # NOTE: No type checking performed.  1230         program.binary_add()  1231   1232     daload = aaload  1233     dastore = aastore  1234   1235     def dcmpg(self, arguments, program):  1236         # NOTE: No type checking performed.  1237         program.compare_op(">")  1238   1239     def dcmpl(self, arguments, program):  1240         # NOTE: No type checking performed.  1241         program.compare_op("<")  1242   1243     def dconst_0(self, arguments, program):  1244         program.load_const(0.0)  1245   1246     def dconst_1(self, arguments, program):  1247         program.load_const(1.0)  1248   1249     def ddiv(self, arguments, program):  1250         # NOTE: No type checking performed.  1251         program.binary_divide()  1252   1253     dload = aload  1254     dload_0 = aload_0  1255     dload_1 = aload_1  1256     dload_2 = aload_2  1257     dload_3 = aload_3  1258   1259     def dmul(self, arguments, program):  1260         # NOTE: No type checking performed.  1261         program.binary_multiply()  1262   1263     def dneg(self, arguments, program):  1264         # NOTE: No type checking performed.  1265         program.unary_negative()  1266   1267     def drem(self, arguments, program):  1268         # NOTE: No type checking performed.  1269         program.binary_modulo()  1270   1271     dreturn = areturn  1272     dstore = astore  1273     dstore_0 = astore_0  1274     dstore_1 = astore_1  1275     dstore_2 = astore_2  1276     dstore_3 = astore_3  1277   1278     def dsub(self, arguments, program):  1279         # NOTE: No type checking performed.  1280         program.binary_subtract()  1281   1282     def dup(self, arguments, program):  1283         program.dup_top()  1284   1285     def dup_x1(self, arguments, program):  1286         # Ignoring computational type categories.  1287         program.dup_top()  1288         program.rot_three()  1289   1290     def dup_x2(self, arguments, program):  1291         # Ignoring computational type categories.  1292         program.dup_top()  1293         program.rot_four()  1294   1295     dup2 = dup # Ignoring computational type categories  1296     dup2_x1 = dup_x1 # Ignoring computational type categories  1297     dup2_x2 = dup_x2 # Ignoring computational type categories  1298   1299     def f2d(self, arguments, program):  1300         pass # Preserving Java semantics  1301   1302     def f2i(self, arguments, program):  1303         program.load_global("int")  # Stack: value, int  1304         program.rot_two()           # Stack: int, value  1305         program.call_function(1)    # Stack: result  1306   1307     f2l = f2i # Preserving Java semantics  1308     fadd = dadd  1309     faload = daload  1310     fastore = dastore  1311     fcmpg = dcmpg  1312     fcmpl = dcmpl  1313     fconst_0 = dconst_0  1314     fconst_1 = dconst_1  1315   1316     def fconst_2(self, arguments, program):  1317         program.load_const(2.0)  1318   1319     fdiv = ddiv  1320     fload = dload  1321     fload_0 = dload_0  1322     fload_1 = dload_1  1323     fload_2 = dload_2  1324     fload_3 = dload_3  1325     fmul = dmul  1326     fneg = dneg  1327     frem = drem  1328     freturn = dreturn  1329     fstore = dstore  1330     fstore_0 = dstore_0  1331     fstore_1 = dstore_1  1332     fstore_2 = dstore_2  1333     fstore_3 = dstore_3  1334     fsub = dsub  1335   1336     def getfield(self, arguments, program):  1337         index = (arguments[0] << 8) + arguments[1]  1338         target_name = self.class_file.constants[index - 1].get_python_name()  1339         # NOTE: Using the string version of the name which may contain incompatible characters.  1340         program.load_attr(str(target_name))  1341   1342     def getstatic(self, arguments, program):  1343         index = (arguments[0] << 8) + arguments[1]  1344         target = self.class_file.constants[index - 1]  1345         target_name = target.get_python_name()  1346   1347         # Get the class name instead of the fully qualified name.  1348   1349         full_class_name = target.get_class().get_python_name()  1350         program.use_external_name(full_class_name)  1351         load_class_name(self.class_file, full_class_name, program)  1352         # NOTE: Using the string version of the name which may contain incompatible characters.  1353         program.load_attr(str(target_name))  1354   1355     def goto(self, arguments, program):  1356         offset = signed2((arguments[0] << 8) + arguments[1])  1357         java_absolute = self.java_position + offset  1358         program.jump_absolute(self.position_mapping[java_absolute])  1359   1360     def goto_w(self, arguments, program):  1361         offset = signed4((arguments[0] << 24) + (arguments[1] << 16) + (arguments[2] << 8) + arguments[3])  1362         java_absolute = self.java_position + offset  1363         program.jump_absolute(self.position_mapping[java_absolute])  1364   1365     def i2b(self, arguments, program):  1366         pass  1367   1368     def i2c(self, arguments, program):  1369         pass  1370   1371     def i2d(self, arguments, program):  1372         program.load_global("float")    # Stack: value, float  1373         program.rot_two()               # Stack: float, value  1374         program.call_function(1)        # Stack: result  1375   1376     i2f = i2d # Not distinguishing between float and double  1377   1378     def i2l(self, arguments, program):  1379         pass # Preserving Java semantics  1380   1381     def i2s(self, arguments, program):  1382         pass # Not distinguishing between int and short  1383   1384     iadd = fadd  1385     iaload = faload  1386   1387     def iand(self, arguments, program):  1388         # NOTE: No type checking performed.  1389         program.binary_and()  1390   1391     iastore = fastore  1392   1393     def iconst_m1(self, arguments, program):  1394         program.load_const(-1)  1395   1396     def iconst_0(self, arguments, program):  1397         program.load_const(0)  1398   1399     def iconst_1(self, arguments, program):  1400         program.load_const(1)  1401   1402     def iconst_2(self, arguments, program):  1403         program.load_const(2)  1404   1405     def iconst_3(self, arguments, program):  1406         program.load_const(3)  1407   1408     def iconst_4(self, arguments, program):  1409         program.load_const(4)  1410   1411     def iconst_5(self, arguments, program):  1412         program.load_const(5)  1413   1414     idiv = fdiv  1415   1416     def _if_xcmpx(self, arguments, program, op):  1417         offset = signed2((arguments[0] << 8) + arguments[1])  1418         java_absolute = self.java_position + offset  1419         program.compare_op(op)  1420         program.jump_to_label(0, "next") # skip if false  1421         program.pop_top()  1422         program.jump_absolute(self.position_mapping[java_absolute])  1423         program.start_label("next")  1424         program.pop_top()  1425   1426     def if_acmpeq(self, arguments, program):  1427         # NOTE: No type checking performed.  1428         self._if_xcmpx(arguments, program, "is")  1429   1430     def if_acmpne(self, arguments, program):  1431         # NOTE: No type checking performed.  1432         self._if_xcmpx(arguments, program, "is not")  1433   1434     def if_icmpeq(self, arguments, program):  1435         # NOTE: No type checking performed.  1436         self._if_xcmpx(arguments, program, "==")  1437   1438     def if_icmpne(self, arguments, program):  1439         # NOTE: No type checking performed.  1440         self._if_xcmpx(arguments, program, "!=")  1441   1442     def if_icmplt(self, arguments, program):  1443         # NOTE: No type checking performed.  1444         self._if_xcmpx(arguments, program, "<")  1445   1446     def if_icmpge(self, arguments, program):  1447         # NOTE: No type checking performed.  1448         self._if_xcmpx(arguments, program, ">=")  1449   1450     def if_icmpgt(self, arguments, program):  1451         # NOTE: No type checking performed.  1452         self._if_xcmpx(arguments, program, ">")  1453   1454     def if_icmple(self, arguments, program):  1455         # NOTE: No type checking performed.  1456         self._if_xcmpx(arguments, program, "<=")  1457   1458     def ifeq(self, arguments, program):  1459         # NOTE: No type checking performed.  1460         program.load_const(0)  1461         self._if_xcmpx(arguments, program, "==")  1462   1463     def ifne(self, arguments, program):  1464         # NOTE: No type checking performed.  1465         program.load_const(0)  1466         self._if_xcmpx(arguments, program, "!=")  1467   1468     def iflt(self, arguments, program):  1469         # NOTE: No type checking performed.  1470         program.load_const(0)  1471         self._if_xcmpx(arguments, program, "<")  1472   1473     def ifge(self, arguments, program):  1474         # NOTE: No type checking performed.  1475         program.load_const(0)  1476         self._if_xcmpx(arguments, program, ">=")  1477   1478     def ifgt(self, arguments, program):  1479         # NOTE: No type checking performed.  1480         program.load_const(0)  1481         self._if_xcmpx(arguments, program, ">")  1482   1483     def ifle(self, arguments, program):  1484         # NOTE: No type checking performed.  1485         program.load_const(0)  1486         self._if_xcmpx(arguments, program, "<=")  1487   1488     def ifnonnull(self, arguments, program):  1489         # NOTE: No type checking performed.  1490         program.load_const(None)  1491         self._if_xcmpx(arguments, program, "is not")  1492   1493     def ifnull(self, arguments, program):  1494         # NOTE: No type checking performed.  1495         program.load_const(None)  1496         self._if_xcmpx(arguments, program, "is")  1497   1498     def iinc(self, arguments, program):  1499         # NOTE: No type checking performed.  1500         program.load_fast(arguments[0])  1501         program.load_const(arguments[1])  1502         program.binary_add()  1503         program.store_fast(arguments[0])  1504   1505     iload = fload  1506     iload_0 = fload_0  1507     iload_1 = fload_1  1508     iload_2 = fload_2  1509     iload_3 = fload_3  1510     imul = fmul  1511     ineg = fneg  1512   1513     def instanceof(self, arguments, program):  1514         index = (arguments[0] << 8) + arguments[1]  1515         target_name = self.class_file.constants[index - 1].get_python_name()  1516         program.use_external_name(target_name)  1517         program.load_global("isinstance")   # Stack: objectref, isinstance  1518         program.rot_two()                   # Stack: isinstance, objectref  1519         load_class_name(self.class_file, target_name, program)  1520         program.call_function(2)            # Stack: result  1521   1522     def _invoke(self, target_name, program):  1523         # NOTE: Using the string version of the name which may contain incompatible characters.  1524         program.load_attr(str(target_name)) # Stack: tuple, method  1525         program.rot_two()                   # Stack: method, tuple  1526         program.call_function_var(0)        # Stack: result  1527   1528     def invokeinterface(self, arguments, program):  1529         # NOTE: This implementation does not perform the necessary checks for  1530         # NOTE: signature-based polymorphism.  1531         # NOTE: Java rules not specifically obeyed.  1532         index = (arguments[0] << 8) + arguments[1]  1533         # NOTE: "count" == nargs + 1, apparently.  1534         count = arguments[2] - 1  1535         target_name = self.class_file.constants[index - 1].get_python_name()  1536         # Stack: objectref, arg1, arg2, ...  1537         program.build_tuple(count)          # Stack: objectref, tuple  1538         program.rot_two()                   # Stack: tuple, objectref  1539         # NOTE: The interface information is not used to discover the correct  1540         # NOTE: method.  1541         self._invoke(target_name, program)  1542   1543     def invokespecial(self, arguments, program):  1544         # NOTE: This implementation does not perform the necessary checks for  1545         # NOTE: signature-based polymorphism.  1546         # NOTE: Java rules not specifically obeyed.  1547         index = (arguments[0] << 8) + arguments[1]  1548         target = self.class_file.constants[index - 1]  1549         original_name = target.get_name()  1550         target_name = target.get_python_name()  1551   1552         # Get the number of parameters from the descriptor.  1553   1554         count = len(target.get_descriptor()[0])  1555   1556         # First, we build a tuple of the reference and arguments.  1557   1558         program.build_tuple(count + 1)          # Stack: tuple  1559   1560         # Get the class name instead of the fully qualified name.  1561         # NOTE: Not bothering with Object initialisation.  1562   1563         full_class_name = target.get_class().get_python_name()  1564         if full_class_name not in ("java.lang.Object", "java.lang.Exception"):  1565             program.use_external_name(full_class_name)  1566             load_class_name(self.class_file, full_class_name, program)  1567             self._invoke(target_name, program)  1568   1569         # Remove Python None return value.  1570   1571         if str(original_name) == "<init>":  1572             program.pop_top()  1573   1574     def invokestatic(self, arguments, program):  1575         # NOTE: This implementation does not perform the necessary checks for  1576         # NOTE: signature-based polymorphism.  1577         # NOTE: Java rules not specifically obeyed.  1578         index = (arguments[0] << 8) + arguments[1]  1579         target = self.class_file.constants[index - 1]  1580         target_name = target.get_python_name()  1581   1582         # Get the number of parameters from the descriptor.  1583   1584         count = len(target.get_descriptor()[0])  1585   1586         # Stack: arg1, arg2, ...  1587   1588         program.build_tuple(count)              # Stack: tuple  1589   1590         # Use the class to provide access to static methods.  1591         # Get the class name instead of the fully qualified name.  1592   1593         full_class_name = target.get_class().get_python_name()  1594         if full_class_name not in ("java.lang.Object", "java.lang.Exception"):  1595             program.use_external_name(full_class_name)  1596             load_class_name(self.class_file, full_class_name, program)  1597             self._invoke(target_name, program)  1598   1599     def invokevirtual (self, arguments, program):  1600         # NOTE: This implementation does not perform the necessary checks for  1601         # NOTE: signature-based polymorphism.  1602         # NOTE: Java rules not specifically obeyed.  1603         index = (arguments[0] << 8) + arguments[1]  1604         target = self.class_file.constants[index - 1]  1605         target_name = target.get_python_name()  1606         # Get the number of parameters from the descriptor.  1607         count = len(target.get_descriptor()[0])  1608         # Stack: objectref, arg1, arg2, ...  1609         program.build_tuple(count)          # Stack: objectref, tuple  1610         program.rot_two()                   # Stack: tuple, objectref  1611         self._invoke(target_name, program)  1612   1613     def ior(self, arguments, program):  1614         # NOTE: No type checking performed.  1615         program.binary_or()  1616   1617     irem = frem  1618     ireturn = freturn  1619   1620     def ishl(self, arguments, program):  1621         # NOTE: No type checking performed.  1622         # NOTE: Not verified.  1623         program.binary_lshift()  1624   1625     def ishr(self, arguments, program):  1626         # NOTE: No type checking performed.  1627         # NOTE: Not verified.  1628         program.binary_rshift()  1629   1630     istore = fstore  1631     istore_0 = fstore_0  1632     istore_1 = fstore_1  1633     istore_2 = fstore_2  1634     istore_3 = fstore_3  1635     isub = fsub  1636     iushr = ishr # Ignoring distinctions between arithmetic and logical shifts  1637   1638     def ixor(self, arguments, program):  1639         # NOTE: No type checking performed.  1640         program.binary_xor()  1641   1642     def jsr(self, arguments, program):  1643         offset = signed2((arguments[0] << 8) + arguments[1])  1644         java_absolute = self.java_position + offset  1645         # Store the address of the next instruction.  1646         program.load_const_ret(self.position_mapping[self.java_position + 3])  1647         program.jump_absolute(self.position_mapping[java_absolute])  1648   1649     def jsr_w(self, arguments, program):  1650         offset = signed4((arguments[0] << 24) + (arguments[1] << 16) + (arguments[2] << 8) + arguments[3])  1651         java_absolute = self.java_position + offset  1652         # Store the address of the next instruction.  1653         program.load_const_ret(self.position_mapping[self.java_position + 5])  1654         program.jump_absolute(self.position_mapping[java_absolute])  1655   1656     l2d = i2d  1657     l2f = i2f  1658   1659     def l2i(self, arguments, program):  1660         pass # Preserving Java semantics  1661   1662     ladd = iadd  1663     laload = iaload  1664     land = iand  1665     lastore = iastore  1666   1667     def lcmp(self, arguments, program):  1668         # NOTE: No type checking performed.  1669         program.dup_topx(2)                 # Stack: value1, value2, value1, value2  1670         program.compare_op(">")             # Stack: value1, value2, result  1671         program.jump_to_label(0, "equals")  1672         # True - produce result and branch.  1673         program.pop_top()                   # Stack: value1, value2  1674         program.pop_top()                   # Stack: value1  1675         program.pop_top()                   # Stack:  1676         program.load_const(1)               # Stack: 1  1677         program.jump_to_label(None, "next")  1678         # False - test equality.  1679         program.start_label("equals")  1680         program.pop_top()                   # Stack: value1, value2  1681         program.dup_topx(2)                 # Stack: value1, value2, value1, value2  1682         program.compare_op("==")            # Stack: value1, value2, result  1683         program.jump_to_label(0, "less")  1684         # True - produce result and branch.  1685         program.pop_top()                   # Stack: value1, value2  1686         program.pop_top()                   # Stack: value1  1687         program.pop_top()                   # Stack:  1688         program.load_const(0)               # Stack: 0  1689         program.jump_to_label(None, "next")  1690         # False - produce result.  1691         program.start_label("less")  1692         program.pop_top()                   # Stack: value1, value2  1693         program.pop_top()                   # Stack: value1  1694         program.pop_top()                   # Stack:  1695         program.load_const(-1)              # Stack: -1  1696         program.start_label("next")  1697   1698     lconst_0 = iconst_0  1699     lconst_1 = iconst_1  1700   1701     def ldc(self, arguments, program):  1702         const = self.class_file.constants[arguments[0] - 1]  1703         if isinstance(const, classfile.StringInfo):  1704             program.use_external_name("java.lang.String")  1705             program.load_global("java")  1706             program.load_attr("lang")  1707             program.load_attr("String")  1708             program.load_const(const.get_value())  1709             program.call_function(1)  1710         else:  1711             program.load_const(const.get_value())  1712   1713     def ldc_w(self, arguments, program):  1714         const = self.class_file.constants[(arguments[0] << 8) + arguments[1] - 1]  1715         if isinstance(const, classfile.StringInfo):  1716             program.use_external_name("java.lang.String")  1717             program.load_global("java")  1718             program.load_attr("lang")  1719             program.load_attr("String")  1720             program.load_const(const.get_value())  1721             program.call_function(1)  1722         else:  1723             program.load_const(const.get_value())  1724   1725     ldc2_w = ldc_w  1726     ldiv = idiv  1727     lload = iload  1728     lload_0 = iload_0  1729     lload_1 = iload_1  1730     lload_2 = iload_2  1731     lload_3 = iload_3  1732     lmul = imul  1733     lneg = ineg  1734   1735     def lookupswitch(self, code, program):  1736   1737         # Find the offset to the next 4 byte boundary in the code.  1738   1739         d, r = divmod(self.java_position + 1, 4)  1740         to_boundary = (4 - r) % 4  1741   1742         # Get the pertinent arguments.  1743   1744         code = code[to_boundary:]  1745         default = classfile.u4(code[0:4])  1746         npairs = classfile.u4(code[4:8])  1747   1748         # Process the pairs.  1749         # NOTE: This is not the most optimal implementation.  1750   1751         pair_index = 8  1752         for pair in range(0, npairs):  1753             match = classfile.u4(code[pair_index:pair_index+4])  1754             offset = classfile.s4(code[pair_index+4:pair_index+8])  1755             # Calculate the branch target.  1756             java_absolute = self.java_position + offset  1757             # Generate branching code.  1758             program.dup_top()                                           # Stack: key, key  1759             program.load_const(match)                                   # Stack: key, key, match  1760             program.compare_op("==")                                    # Stack: key, result  1761             program.jump_to_label(0, "end")  1762             program.pop_top()                                           # Stack: key  1763             program.pop_top()                                           # Stack:  1764             program.jump_absolute(self.position_mapping[java_absolute])  1765             # Generate the label for the end of the branching code.  1766             program.start_label("end")  1767             program.pop_top()                                           # Stack: key  1768             # Update the index.  1769             pair_index += 4  1770   1771         # Generate the default.  1772   1773         java_absolute = self.java_position + default  1774         program.jump_absolute(self.position_mapping[java_absolute])  1775         return pair_index + to_boundary  1776   1777     lor = ior  1778     lrem = irem  1779     lreturn = ireturn  1780     lshl = ishl  1781     lshr = ishr  1782     lstore = istore  1783     lstore_0 = istore_0  1784     lstore_1 = istore_1  1785     lstore_2 = istore_2  1786     lstore_3 = istore_3  1787     lsub = isub  1788     lushr = iushr  1789     lxor = ixor  1790   1791     def monitorenter(self, arguments, program):  1792         # NOTE: To be implemented.  1793         pass  1794   1795     def monitorexit(self, arguments, program):  1796         # NOTE: To be implemented.  1797         pass  1798   1799     def multianewarray(self, arguments, program):  1800         index = (arguments[0] << 8) + arguments[1]  1801         dimensions = arguments[2]  1802         # Stack: count1, ..., countN-1, countN  1803         type_name = self.class_file.constants[index - 1].get_python_name()  1804         default_value = classfile.get_default_for_type(type_name)  1805         self._newarray(program, default_value)  # Stack: count1, ..., countN-1, list  1806         for dimension in range(1, dimensions):  1807             program.rot_two()               # Stack: count1, ..., list, countN-1  1808             program.build_list(0)           # Stack: count1, ..., list, countN-1, new-list  1809             program.rot_three()             # Stack: count1, ..., new-list, list, countN-1  1810             program.setup_loop()  1811             program.load_const(0)           # Stack: count1, ..., new-list, list, countN-1, 0  1812             program.rot_two()               # Stack: count1, ..., new-list, list, 0, countN-1  1813             program.load_global("range")    # Stack: count1, ..., new-list, list, 0, countN-1, range  1814             program.rot_three()             # Stack: count1, ..., new-list, list, range, 0, countN-1  1815             program.call_function(2)        # Stack: count1, ..., new-list, list, range-list  1816             program.get_iter()              # Stack: count1, ..., new-list, list, iter  1817             program.for_iter()              # Stack: count1, ..., new-list, list, iter, value  1818             program.pop_top()               # Stack: count1, ..., new-list, list, iter  1819             program.rot_three()             # Stack: count1, ..., iter, new-list, list  1820             program.slice_0()               # Stack: count1, ..., iter, new-list, list[:]  1821             program.dup_top()               # Stack: count1, ..., iter, new-list, list[:], list[:]  1822             program.rot_three()             # Stack: count1, ..., iter, list[:], new-list, list[:]  1823             program.rot_two()               # Stack: count1, ..., iter, list[:], list[:], new-list  1824             program.dup_top()               # Stack: count1, ..., iter, list[:], list[:], new-list, new-list  1825             program.load_attr("append")     # Stack: count1, ..., iter, list[:], list[:], new-list, append  1826             program.rot_three()             # Stack: count1, ..., iter, list[:], append, list[:], new-list  1827             program.rot_three()             # Stack: count1, ..., iter, list[:], new-list, append, list[:]  1828             program.call_function(1)        # Stack: count1, ..., iter, list[:], new-list, None  1829             program.pop_top()               # Stack: count1, ..., iter, list[:], new-list  1830             program.rot_two()               # Stack: count1, ..., iter, new-list, list[:]  1831             program.rot_three()             # Stack: count1, ..., list[:], iter, new-list  1832             program.rot_three()             # Stack: count1, ..., new-list, list[:], iter  1833             program.end_loop()              # Stack: count1, ..., new-list, list[:], iter  1834             program.pop_top()               # Stack: count1, ..., new-list  1835   1836     def new(self, arguments, program):  1837         # This operation is considered to be the same as the calling of the  1838         # initialisation method of the given class with no arguments.  1839   1840         index = (arguments[0] << 8) + arguments[1]  1841         target_name = self.class_file.constants[index - 1].get_python_name()  1842         program.use_external_name(target_name)  1843   1844         # NOTE: Using the string version of the name which may contain incompatible characters.  1845         program.load_global("object")  1846         program.load_attr("__new__")  1847         load_class_name(self.class_file, target_name, program)  1848         program.call_function(1)  1849   1850     def newarray(self, arguments, program):  1851         # NOTE: Does not raise NegativeArraySizeException.  1852         # NOTE: Not completely using the arguments to type the list/array.  1853         atype = arguments[0]  1854         default_value = get_default_for_atype(atype)  1855         self._newarray(program, default_value)  1856   1857     def nop(self, arguments, program):  1858         pass  1859   1860     def pop(self, arguments, program):  1861         program.pop_top()  1862   1863     pop2 = pop # ignoring Java stack value distinctions  1864   1865     def putfield(self, arguments, program):  1866         index = (arguments[0] << 8) + arguments[1]  1867         target_name = self.class_file.constants[index - 1].get_python_name()  1868         program.rot_two()  1869         # NOTE: Using the string version of the name which may contain incompatible characters.  1870         program.store_attr(str(target_name))  1871   1872     def putstatic(self, arguments, program):  1873         index = (arguments[0] << 8) + arguments[1]  1874         target = self.class_file.constants[index - 1]  1875         target_name = target.get_python_name()  1876   1877         # Get the class name instead of the fully qualified name.  1878   1879         full_class_name = target.get_class().get_python_name()  1880         program.use_external_name(full_class_name)  1881         load_class_name(self.class_file, full_class_name, program)  1882         # NOTE: Using the string version of the name which may contain incompatible characters.  1883         program.store_attr(str(target_name))  1884   1885     def ret(self, arguments, program):  1886         program.ret(arguments[0])  1887         # Indicate that the finally handler is probably over.  1888         # NOTE: This is seemingly not guaranteed.  1889         self.in_finally = 0  1890   1891     def return_(self, arguments, program):  1892         program.load_const(None)  1893         program.return_value()  1894   1895     saload = laload  1896     sastore = lastore  1897   1898     def sipush(self, arguments, program):  1899         program.load_const(signed2((arguments[0] << 8) + arguments[1]))  1900   1901     def swap(self, arguments, program):  1902         program.rot_two()  1903   1904     def tableswitch(self, code, program):  1905   1906         # Find the offset to the next 4 byte boundary in the code.  1907   1908         d, r = divmod(self.java_position + 1, 4)  1909         to_boundary = (4 - r) % 4  1910   1911         # Get the pertinent arguments.  1912   1913         code = code[to_boundary:]  1914         default = classfile.u4(code[0:4])  1915         low = classfile.u4(code[4:8])  1916         high = classfile.u4(code[8:12])  1917   1918         # Process the jump entries.  1919         # NOTE: This is not the most optimal implementation.  1920   1921         jump_index = 12  1922         for jump in range(low, high + 1):  1923             offset = classfile.s4(code[jump_index:jump_index + 4])  1924   1925             # Calculate the branch target.  1926   1927             java_absolute = self.java_position + offset  1928   1929             # Generate branching code.  1930   1931             program.dup_top()                                           # Stack: key, key  1932             program.load_const(jump)                                    # Stack: key, key, jump  1933             program.compare_op("==")                                    # Stack: key, result  1934             program.jump_to_label(0, "end")  1935             program.pop_top()                                           # Stack: key  1936             program.pop_top()                                           # Stack:  1937             program.jump_absolute(self.position_mapping[java_absolute])  1938   1939             # Generate the label for the end of the branching code.  1940   1941             program.start_label("end")  1942             program.pop_top()                                           # Stack: key  1943   1944             # Update the index.  1945   1946             jump_index += 4  1947   1948         # Generate the default.  1949   1950         java_absolute = self.java_position + default  1951         program.jump_absolute(self.position_mapping[java_absolute])  1952         return jump_index + to_boundary  1953   1954     def wide(self, code, program):  1955         # NOTE: To be implemented.  1956         return number_of_arguments  1957   1958 def disassemble(class_file, method):  1959     disassembler = BytecodeDisassembler(class_file)  1960     disassembler.process(method, BytecodeDisassemblerProgram())  1961   1962 class ClassTranslator:  1963   1964     """  1965     A class which provides a wrapper around a class file and the means to  1966     translate the represented class into a Python class.  1967     """  1968   1969     def __init__(self, class_file):  1970   1971         "Initialise the object with the given 'class_file'."  1972   1973         self.class_file = class_file  1974         self.filename = ""  1975   1976         for attribute in self.class_file.attributes:  1977             if isinstance(attribute, classfile.SourceFileAttributeInfo):  1978                 self.filename = str(attribute.get_name())  1979   1980     def translate_method(self, method):  1981   1982         "Translate the given 'method' - an object obtained from the class file."  1983   1984         translator = BytecodeTranslator(self.class_file)  1985         writer = BytecodeWriter()  1986         translator.process(method, writer)  1987         return translator, writer  1988   1989     def make_method(self, real_method_name, methods, global_names, namespace):  1990   1991         """  1992         Make a dispatcher method with the given 'real_method_name', providing  1993         dispatch to the supplied type-sensitive 'methods', accessing the given  1994         'global_names' where necessary, and storing the new method in the  1995         'namespace' provided.  1996         """  1997   1998         if real_method_name == "<init>":  1999             method_name = "__init__"  2000         else:  2001             method_name = real_method_name  2002   2003         # Where only one method exists, just make an alias.  2004   2005         if len(methods) == 1:  2006             method, fn = methods[0]  2007             namespace[method_name] = fn  2008             return  2009   2010         # Write a simple bytecode dispatching mechanism.  2011   2012         program = BytecodeWriter()  2013   2014         # Remember whether any of the methods are static.  2015         # NOTE: This should be an all or nothing situation.  2016   2017         method_is_static = 0  2018   2019         # NOTE: The code below should use dictionary-based dispatch for better performance.  2020   2021         for method, fn in methods:  2022             method_is_static = real_method_name != "<init>" and method_is_static or \  2023                 classfile.has_flags(method.access_flags, [classfile.STATIC])  2024   2025             if method_is_static:  2026                 program.load_fast(0)                # Stack: arguments  2027             else:  2028                 program.load_fast(1)                # Stack: arguments  2029   2030             program.setup_loop()  2031             program.load_const(1)                   # Stack: arguments, 1  2032   2033             if method_is_static:  2034                 program.store_fast(1)               # Stack: arguments (found = 1)  2035             else:  2036                 program.store_fast(2)               # Stack: arguments (found = 1)  2037   2038             # Emit a list of parameter types.  2039   2040             descriptor_types = method.get_descriptor()[0]  2041             for descriptor_type in descriptor_types:  2042                 base_type, object_type, array_type = descriptor_type  2043                 python_type = classfile.descriptor_base_type_mapping[base_type]  2044                 if python_type == "instance":  2045                     # NOTE: This will need extending.  2046                     python_type = object_type  2047                 program.load_global(python_type)    # Stack: arguments, type, ...  2048             program.build_list(len(descriptor_types))  2049                                                     # Stack: arguments, types  2050             # Make a map of arguments and types.  2051             program.load_const(None)                # Stack: arguments, types, None  2052             program.rot_three()                     # Stack: None, arguments, types  2053             program.build_tuple(3)                  # Stack: tuple  2054             program.load_global("map")              # Stack: tuple, map  2055             program.rot_two()                       # Stack: map, tuple  2056             program.call_function_var(0)            # Stack: list (mapping arguments to types)  2057             # Loop over each pair.  2058             program.get_iter()                      # Stack: iter  2059             program.for_iter()                      # Stack: iter, (argument, type)  2060             program.unpack_sequence(2)              # Stack: iter, type, argument  2061             program.dup_top()                       # Stack: iter, type, argument, argument  2062             program.load_const(None)                # Stack: iter, type, argument, argument, None  2063             program.compare_op("is")                # Stack: iter, type, argument, result  2064             # Missing argument?  2065             program.jump_to_label(0, "present")  2066             program.pop_top()                       # Stack: iter, type, argument  2067             program.pop_top()                       # Stack: iter, type  2068             program.pop_top()                       # Stack: iter  2069             program.load_const(0)                   # Stack: iter, 0  2070   2071             if method_is_static:  2072                 program.store_fast(1)               # Stack: iter (found = 0)  2073             else:  2074                 program.store_fast(2)               # Stack: iter (found = 0)  2075   2076             program.break_loop()  2077             # Argument was present.  2078             program.start_label("present")  2079             program.pop_top()                       # Stack: iter, type, argument  2080             program.rot_two()                       # Stack: iter, argument, type  2081             program.dup_top()                       # Stack: iter, argument, type, type  2082             program.load_const(None)                # Stack: iter, argument, type, type, None  2083             program.compare_op("is")                # Stack: iter, argument, type, result  2084             # Missing parameter type?  2085             program.jump_to_label(0, "present")  2086             program.pop_top()                       # Stack: iter, argument, type  2087             program.pop_top()                       # Stack: iter, argument  2088             program.pop_top()                       # Stack: iter  2089             program.load_const(0)                   # Stack: iter, 0  2090   2091             if method_is_static:  2092                 program.store_fast(1)               # Stack: iter (found = 0)  2093             else:  2094                 program.store_fast(2)               # Stack: iter (found = 0)  2095   2096             program.break_loop()  2097             # Parameter was present.  2098             program.start_label("present")  2099             program.pop_top()                       # Stack: iter, argument, type  2100             program.build_tuple(2)                  # Stack: iter, (argument, type)  2101             program.load_global("isinstance")       # Stack: iter, (argument, type), isinstance  2102             program.rot_two()                       # Stack: iter, isinstance, (argument, type)  2103             program.call_function_var(0)            # Stack: iter, result  2104             program.jump_to_label(1, "match")  2105             program.pop_top()                       # Stack: iter  2106             program.load_const(0)                   # Stack: iter, 0  2107   2108             if method_is_static:  2109                 program.store_fast(1)               # Stack: iter (found = 0)  2110             else:  2111                 program.store_fast(2)               # Stack: iter (found = 0)  2112   2113             program.break_loop()  2114             # Argument type and parameter type matched.  2115             program.start_label("match")  2116             program.pop_top()                       # Stack: iter  2117             program.end_loop()                      # Stack:  2118             # If all the parameters matched, call the method.  2119   2120             if method_is_static:  2121                 program.load_fast(1)                # Stack: match  2122             else:  2123                 program.load_fast(2)                # Stack: match  2124   2125             program.jump_to_label(0, "failed")  2126             # All the parameters matched.  2127             program.pop_top()                       # Stack:  2128   2129             if method_is_static:  2130                 program.load_fast(0)                # Stack: arguments  2131                 program.load_global(str(self.class_file.this_class.get_python_name()))  2132                                                     # Stack: arguments, class  2133             else:  2134                 program.load_fast(1)                # Stack: arguments  2135                 program.load_fast(0)                # Stack: arguments, self  2136   2137             program.load_attr(str(method.get_python_name()))  2138                                                     # Stack: arguments, method  2139             program.rot_two()                       # Stack: method, arguments  2140             program.call_function_var(0)            # Stack: result  2141             program.return_value()  2142             # Try the next method if arguments or parameters were missing or incorrect.  2143             program.start_label("failed")  2144             program.pop_top()                       # Stack:  2145   2146         # Raise an exception if nothing matched.  2147         # NOTE: Improve this.  2148   2149         program.load_const("No matching method")  2150         program.raise_varargs(1)  2151         program.load_const(None)  2152         program.return_value()  2153   2154         # Add the code as a method in the namespace.  2155         # NOTE: One actual parameter, flags as 71 apparently means that a list  2156         # NOTE: parameter is used in a method.  2157   2158         if method_is_static:  2159             nargs = 0  2160         else:  2161             nargs = 1  2162         nlocals = program.max_locals + 1  2163   2164         code = new.code(nargs, nlocals, program.max_stack_depth, 71, program.get_output(),  2165             tuple(program.get_constants()), tuple(program.get_names()), tuple(self.make_varnames(nlocals, method_is_static)),  2166             self.filename, method_name, 0, "")  2167         fn = new.function(code, global_names)  2168   2169         if method_is_static:  2170             fn = staticmethod(fn)  2171   2172         namespace[method_name] = fn  2173   2174     def process(self, global_names):  2175   2176         """  2177         Process the class, storing it in the 'global_names' dictionary provided.  2178         Return a tuple containing the class and a list of external names  2179         referenced by the class's methods.  2180         """  2181   2182         namespace = {}  2183   2184         # Make the fields.  2185   2186         for field in self.class_file.fields:  2187             if classfile.has_flags(field.access_flags, [classfile.STATIC]):  2188                 field_name = str(field.get_python_name())  2189                 namespace[field_name] = None  2190   2191         # Make the methods.  2192   2193         real_methods = {}  2194         external_names = []  2195   2196         for method in self.class_file.methods:  2197             real_method_name = str(method.get_name())  2198             method_name = str(method.get_python_name())  2199   2200             translator, writer = self.translate_method(method)  2201   2202             # Add external names to the master list.  2203   2204             for external_name in writer.external_names:  2205                 if external_name not in external_names:  2206                     external_names.append(external_name)  2207   2208             # Fix up special class initialisation methods and static methods.  2209   2210             method_is_static = real_method_name != "<init>" and classfile.has_flags(method.access_flags, [classfile.STATIC])  2211             if method_is_static:  2212                 nargs = len(method.get_descriptor()[0])  2213             else:  2214                 nargs = len(method.get_descriptor()[0]) + 1  2215             nlocals = writer.max_locals + 1  2216             flags = 67  2217   2218             # NOTE: Add line number table later.  2219   2220             code = new.code(nargs, nlocals, writer.max_stack_depth, flags, writer.get_output(),  2221                 tuple(writer.get_constants()), tuple(writer.get_names()),  2222                 tuple(self.make_varnames(nlocals, method_is_static)), self.filename, method_name, 0, "")  2223   2224             # NOTE: May need more globals.  2225   2226             fn = new.function(code, global_names)  2227   2228             # Fix up special class initialisation methods and static methods.  2229   2230             if method_is_static:  2231                 fn = staticmethod(fn)  2232   2233             # Remember the real method name and the corresponding methods produced.  2234   2235             if not real_methods.has_key(real_method_name):  2236                 real_methods[real_method_name] = []  2237             real_methods[real_method_name].append((method, fn))  2238   2239             # Add the method to the class's namespace.  2240   2241             namespace[method_name] = fn  2242   2243         # Define superclasses.  2244   2245         bases = self.get_base_classes(global_names)  2246   2247         # Define method dispatchers.  2248   2249         for real_method_name, methods in real_methods.items():  2250             if real_method_name != "<clinit>":  2251                 self.make_method(real_method_name, methods, global_names, namespace)  2252   2253         # Use only the last part of the fully qualified name.  2254   2255         full_class_name = str(self.class_file.this_class.get_python_name())  2256         class_name = full_class_name.split(".")[-1]  2257         cls = new.classobj(class_name, bases, namespace)  2258         global_names[cls.__name__] = cls  2259   2260         return cls, external_names  2261   2262     def get_base_classes(self, global_names):  2263   2264         """  2265         Identify the superclass, then either load it from the given  2266         'global_names' if available, or import the class from its parent module.  2267         Return a tuple containing all base classes (typically a single element  2268         tuple).  2269         """  2270   2271         original_name = str(self.class_file.super_class.get_name())  2272         full_this_class_name = str(self.class_file.this_class.get_python_name())  2273         this_class_name_parts = full_this_class_name.split(".")  2274         this_class_module_name = ".".join(this_class_name_parts[:-1])  2275         full_super_class_name = str(self.class_file.super_class.get_python_name())  2276         super_class_name_parts = full_super_class_name.split(".")  2277         super_class_name = super_class_name_parts[-1]  2278         super_class_module_name = ".".join(super_class_name_parts[:-1])  2279         if super_class_module_name == "":  2280             obj = global_names[super_class_name]  2281         elif super_class_module_name == this_class_module_name:  2282             obj = global_names[super_class_name]  2283         else:  2284             #print "Importing", super_class_module_name, super_class_name  2285             obj = __import__(super_class_module_name, global_names, {}, [])  2286             for super_class_name_part in super_class_name_parts[1:] or [super_class_name]:  2287                 #print "*", obj, super_class_name_part  2288                 obj = getattr(obj, super_class_name_part)  2289         return (obj,)  2290   2291     def make_varnames(self, nlocals, method_is_static=0):  2292   2293         """  2294         A utility method which invents variable names for the given number -  2295         'nlocals' - of local variables in a method. Returns a list of such  2296         variable names.  2297   2298         If the optional 'method_is_static' is set to true, do not use "self" as  2299         the first argument name.  2300         """  2301   2302         if method_is_static:  2303             l = ["cls"]  2304         else:  2305             l = ["self"]  2306         for i in range(1, nlocals):  2307             l.append("_l%s" % i)  2308         return l[:nlocals]  2309   2310 # Test functions, useful for tracing generated bytecode operations.  2311   2312 def _map(*args):  2313     print args  2314     return apply(__builtins__.map, args)  2315   2316 def _isinstance(*args):  2317     print args  2318     return apply(__builtins__.isinstance, args)  2319   2320 if __name__ == "__main__":  2321     import sys  2322     import dis  2323     global_names = globals()  2324     #global_names["isinstance"] = _isinstance  2325     #global_names["map"] = _map  2326     for filename in sys.argv[1:]:  2327         f = open(filename, "rb")  2328         c = classfile.ClassFile(f.read())  2329         translator = ClassTranslator(c)  2330         cls, external_names = translator.process(global_names)  2331   2332 # vim: tabstop=4 expandtab shiftwidth=4