javaclass

bytecode.py

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