javaclass

bytecode.py

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