javaclass

javaclass/bytecode.py

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