javaclass

javaclass/bytecode.py

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