javaclass

bytecode.py

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