[pypy-svn] r34023 - in pypy/dist/pypy/translator: cli js jvm jvm/src jvm/test oosupport

niko at codespeak.net niko at codespeak.net
Wed Nov 1 14:57:44 CET 2006


Author: niko
Date: Wed Nov  1 14:57:43 2006
New Revision: 34023

Modified:
   pypy/dist/pypy/translator/cli/function.py
   pypy/dist/pypy/translator/cli/opcodes.py
   pypy/dist/pypy/translator/js/function.py
   pypy/dist/pypy/translator/jvm/conftest.py
   pypy/dist/pypy/translator/jvm/database.py
   pypy/dist/pypy/translator/jvm/generator.py
   pypy/dist/pypy/translator/jvm/node.py
   pypy/dist/pypy/translator/jvm/opcodes.py
   pypy/dist/pypy/translator/jvm/option.py
   pypy/dist/pypy/translator/jvm/src/PyPy.java
   pypy/dist/pypy/translator/jvm/test/   (props changed)
   pypy/dist/pypy/translator/jvm/test/runtest.py
   pypy/dist/pypy/translator/jvm/typesystem.py
   pypy/dist/pypy/translator/oosupport/function.py
   pypy/dist/pypy/translator/oosupport/metavm.py
Log:
Update JVM handling of class objects.  Add support for casts, new, etc.
Some minor refactoring into oosupport as well.



Modified: pypy/dist/pypy/translator/cli/function.py
==============================================================================
--- pypy/dist/pypy/translator/cli/function.py	(original)
+++ pypy/dist/pypy/translator/cli/function.py	Wed Nov  1 14:57:43 2006
@@ -99,6 +99,10 @@
 
 
     # Generator interface
+
+    def add_comment(self, text):
+        pass
+    
     def function_signature(self, graph, func_name=None):
         return self.cts.graph_to_signature(graph, False, func_name)
 
@@ -138,9 +142,13 @@
         signature, virtual = self.cts.method_signature(obj, name)
         self.ilasm.call_method(signature, virtual)
 
-    def downcast(self, type):
+    def downcast(self, TYPE):
+        type = self.cts.lltype_to_cts(TYPE)
         return self.ilasm.opcode('castclass', type)
 
+    def instantiate(self):
+        self.call_signature('object [pypylib]pypy.runtime.Utils::RuntimeNew(class [mscorlib]System.Type)')
+
     def load(self, v):
         if isinstance(v, flowmodel.Variable):
             if v.name in self.argset:

Modified: pypy/dist/pypy/translator/cli/opcodes.py
==============================================================================
--- pypy/dist/pypy/translator/cli/opcodes.py	(original)
+++ pypy/dist/pypy/translator/cli/opcodes.py	Wed Nov  1 14:57:43 2006
@@ -1,8 +1,8 @@
-from pypy.translator.cli.metavm import  Call, CallMethod, RuntimeNew, \
+from pypy.translator.cli.metavm import  Call, CallMethod, \
      IndirectCall, GetField, SetField, CastTo, OOString, DownCast, NewCustomDict,\
      CastWeakAdrToPtr, MapException, Box, Unbox, GetArrayElem
 from pypy.translator.oosupport.metavm import PushArg, PushAllArgs, StoreResult, InstructionList,\
-    New
+    New, RuntimeNew
 from pypy.translator.cli.cts import WEAKREF
 
 # some useful instruction patterns

Modified: pypy/dist/pypy/translator/js/function.py
==============================================================================
--- pypy/dist/pypy/translator/js/function.py	(original)
+++ pypy/dist/pypy/translator/js/function.py	Wed Nov  1 14:57:43 2006
@@ -368,6 +368,9 @@
 
     # following methods belongs to the Generator interface
 
+    def add_comment(self, text):
+        pass
+    
     def function_signature(self, graph):
         return self.cts.graph_to_signature(graph, False)
 

Modified: pypy/dist/pypy/translator/jvm/conftest.py
==============================================================================
--- pypy/dist/pypy/translator/jvm/conftest.py	(original)
+++ pypy/dist/pypy/translator/jvm/conftest.py	Wed Nov  1 14:57:43 2006
@@ -14,5 +14,7 @@
     Option('--noassemble', action='store_true', dest="noasm", default=False,
            help="don't assemble jasmin files"),
     Option('--package', action='store', dest='package', default='pypy',
-           help='Package to output generated classes into')
+           help='Package to output generated classes into'),
+    Option('--trace', action='store_true', dest='trace', default=False,
+           help='Trace execution of generated code')
     )

Modified: pypy/dist/pypy/translator/jvm/database.py
==============================================================================
--- pypy/dist/pypy/translator/jvm/database.py	(original)
+++ pypy/dist/pypy/translator/jvm/database.py	Wed Nov  1 14:57:43 2006
@@ -18,7 +18,8 @@
         self.genoo = genoo
         
         # Private attributes:
-        self._classes = {} # Maps ootype class objects to node.Class objects
+        self._classes = {} # Maps ootype class objects to node.Class objects,
+                           # and JvmType objects as well
         self._counter = 0  # Used to create unique names
         self._functions = {}      # graph -> jvmgen.Method
 
@@ -61,14 +62,26 @@
         # Create class object if it does not already exist:
         if OOCLASS in self._classes:
             return self._classes[OOCLASS]
+        
+        # Resolve super class first
+        if OOCLASS._superclass:
+            superclsnm = self.lltype_to_cts(OOCLASS._superclass).class_name()
+        else:
+            superclsobj = "java.lang.Object" #?
+
         # TODO --- make package of java class reflect the package of the
         # OO class?
         clsnm = self._pkg(
             self._uniq(OOCLASS._name.replace('.','_')))
-        clsobj = node.Class(clsnm)
+        clsobj = node.Class(clsnm, superclsnm)
 
-        # TODO --- mangle field and method names?  Must be deterministic or
-        # use hashtable to avoid conflicts between classes?
+        # Store the class object for future calls
+        self._classes[OOCLASS] = clsobj
+        self._classes[clsobj.jvm_type()] = clsobj
+
+        # TODO --- mangle field and method names?  Must be
+        # deterministic, or use hashtable to avoid conflicts between
+        # classes?
         
         # Add fields:
         for fieldnm, (FIELDOOTY, fielddef) in OOCLASS._fields.iteritems():
@@ -86,17 +99,24 @@
                 # this class it means that this method this method is
                 # not really used by the class: don't render it, else
                 # there would be a type mismatch.
-                args =  m_meth.graph.getargs()
+                args =  mimpl.graph.getargs()
                 SELF = args[0].concretetype
                 if not ootype.isSubclass(OOCLASS, SELF): continue
                 mobj = self._function_for_graph(
-                    clsobj, mimpl.name, False, mimpl.graph)
+                    clsobj, mname, False, mimpl.graph)
                 clsobj.add_method(mobj)
 
-        self._classes[OOCLASS] = clsobj
+        # currently, we always include a special "dump" method for debugging
+        # purposes
+        dump_method = node.TestDumpMethod(self, OOCLASS, clsobj)
+        clsobj.add_dump_method(dump_method)
+
         self.pending_node(clsobj)
         return clsobj
 
+    def class_obj_for_jvm_type(self, jvmtype):
+        return self._classes[jvmtype]
+
     def pending_function(self, graph):
         """
         This is invoked when a standalone function is to be compiled.
@@ -108,7 +128,7 @@
         if graph in self._functions:
             return self._functions[graph]
         classnm = self._pkg(self._uniq(graph.name))
-        classobj = node.Class(classnm)
+        classobj = node.Class(classnm, 'java.lang.Object')
         funcobj = self._function_for_graph(classobj, "invoke", True, graph)
         classobj.add_method(funcobj)
         self.pending_node(classobj)
@@ -147,8 +167,23 @@
         #   For NOW, we create a new class PER constant.
         #   Clearly this is probably undesirable in the long
         #   term.
-        print "TYPE=" + repr(TYPE)
-        return jvmgen.VoidConst() # TODO
+        return jvmgen.WarnNullConst() # TODO
+
+    # Other
+    
+    _type_printing_methods = {
+        ootype.Signed:jvmgen.PYPYDUMPINT,
+        ootype.Unsigned:jvmgen.PYPYDUMPUINT,
+        ootype.SignedLongLong:jvmgen.PYPYDUMPLONG,
+        ootype.Float:jvmgen.PYPYDUMPDOUBLE,
+        ootype.Bool:jvmgen.PYPYDUMPBOOLEAN,
+        ootype.Class:jvmgen.PYPYDUMPOBJECT,
+        }
+
+    def generate_dump_method_for_ootype(self, OOTYPE):
+        if OOTYPE in self._type_printing_methods:
+            return self._type_printing_methods[OOTYPE]
+        return self.pending_class(OOTYPE).dump_method.method()
 
     # Type translation functions
 

Modified: pypy/dist/pypy/translator/jvm/generator.py
==============================================================================
--- pypy/dist/pypy/translator/jvm/generator.py	(original)
+++ pypy/dist/pypy/translator/jvm/generator.py	Wed Nov  1 14:57:43 2006
@@ -1,7 +1,8 @@
 import os # 
 from pypy.objspace.flow import model as flowmodel
 from pypy.translator.oosupport.metavm import Generator
-from pypy.translator.jvm.typesystem import JvmType
+from pypy.translator.jvm.typesystem import \
+     JvmType, jObject, jPrintStream, jvm_for_class, jVoid
 from pypy.rpython.ootypesystem import ootype
 
 # ___________________________________________________________________________
@@ -46,6 +47,8 @@
                 return self.jvmstr + "_m1", ()
             elif args[0] >= 0 and args[0] <= 5:
                 return self.jvmstr + "_" + str(args[0]), ()
+            else:
+                return "ldc", args # HACK
 
         if self.flags & CONST3: 
             assert len(args) == 1
@@ -132,6 +135,7 @@
 
 # Method invocation
 INVOKESTATIC = Opcode(INVOKE, 'invokestatic')
+INVOKEVIRTUAL = Opcode(INVOKE, 'invokevirtual')
 INVOKESPECIAL = Opcode(INVOKE, 'invokespecial')
 
 # Other opcodes
@@ -148,7 +152,7 @@
 PUTFIELD =  Opcode(FIELD, 'putfield')
 GETSTATIC = Opcode(FIELD, 'getstatic')
 PUTSTATIC = Opcode(FIELD, 'putstatic')
-CHECKCAST = Opcode(NOFLAGS, 'checkcast')
+CHECKCAST = Opcode(CLASSINM, 'checkcast')
 INEG =      Opcode(NOFLAGS, 'ineg')
 IXOR =      Opcode(NOFLAGS, 'ixor')
 IADD =      Opcode(NOFLAGS, 'iadd')
@@ -190,6 +194,7 @@
 NEW =       Opcode(CLASSINM, 'new')
 DUP =       Opcode(NOFLAGS, 'dup')
 POP =       Opcode(NOFLAGS, 'pop')
+INSTANCEOF= Opcode(CLASSINM, 'instanceof')
 # Loading/storing local variables
 LOAD =      OpcodeFamily(CONST3, "load")
 STORE =     OpcodeFamily(CONST3, "store")
@@ -231,6 +236,8 @@
 MATHLABS =              Method('java.lang.Math', 'abs', '(L)L')
 MATHDABS =              Method('java.lang.Math', 'abs', '(D)D')
 MATHFLOOR =             Method('java.lang.Math', 'floor', '(D)D')
+PRINTSTREAMPRINTSTR =   Method('java.io.PrintStream', 'print',
+                               '(Ljava/lang/String;)V', opcode=INVOKEVIRTUAL)
 PYPYUINTCMP =           Method('pypy.PyPy', 'uint_cmp', '(II)I')
 PYPYULONGCMP =          Method('pypy.PyPy', 'ulong', '(LL)I')
 PYPYUINTTODOUBLE =      Method('pypy.PyPy', 'uint_to_double', '(I)D')
@@ -252,12 +259,19 @@
                                '(Ljava/lang/String;)D')
 PYPYSTRTOCHAR =         Method('pypy.PyPy', 'str_to_char',
                                '(Ljava/lang/String;)C')
-PYPYDUMPINT  =          Method('pypy.PyPy', 'dump_int', '(I)V')
-PYPYDUMPUINT  =         Method('pypy.PyPy', 'dump_uint', '(I)V')
-PYPYDUMPLONG  =         Method('pypy.PyPy', 'dump_long', '(L)V')
-PYPYDUMPDOUBLE  =       Method('pypy.PyPy', 'dump_double', '(D)V')
-PYPYDUMPSTRING  =       Method('pypy.PyPy', 'dump_string', '([B)V')
-PYPYDUMPBOOLEAN =       Method('pypy.PyPy', 'dump_boolean', '(Z)V')
+PYPYDUMPINDENTED  =     Method('pypy.PyPy', 'dump_indented',
+                                 '(ILjava/lang/String;)V')
+PYPYDUMPINT  =          Method('pypy.PyPy', 'dump_int', '(II)V')
+PYPYDUMPUINT  =         Method('pypy.PyPy', 'dump_uint', '(II)V')
+PYPYDUMPLONG  =         Method('pypy.PyPy', 'dump_long', '(LI)V')
+PYPYDUMPDOUBLE  =       Method('pypy.PyPy', 'dump_double', '(DI)V')
+PYPYDUMPSTRING  =       Method('pypy.PyPy', 'dump_string', '([BI)V')
+PYPYDUMPBOOLEAN =       Method('pypy.PyPy', 'dump_boolean', '(ZI)V')
+PYPYDUMPOBJECT =        Method('pypy.PyPy', 'dump_object',
+                               '(Ljava/lang/Object;I)V')
+PYPYRUNTIMENEW =        Method('pypy.PyPy', 'RuntimeNew',
+                               '(Ljava/lang/Class;)Ljava/lang/Object;')
+
 
 # ___________________________________________________________________________
 # Fields
@@ -285,6 +299,9 @@
         return "%s/%s %s" % (
             self.class_name.replace('.','/'), self.field_name, self.jtype)
 
+SYSTEMOUT = Field('java.lang.System', 'out', jPrintStream, True)
+SYSTEMERR = Field('java.lang.System', 'err', jPrintStream, True)
+
 # ___________________________________________________________________________
 # Constants
 #
@@ -305,6 +322,15 @@
     def load(self, gen):
         pass
 
+class NullConst(object):
+    def load(self, gen):
+        gen.emit(ACONST_NULL)
+
+class WarnNullConst(NullConst):
+    def load(self, gen):
+        gen.add_comment("   substituting NULL")
+        NullConst.load(self, gen)
+
 class SignedIntConst(Const):
     def __init__(self, value):
         self.value = value
@@ -372,7 +398,13 @@
         self.value = value
     def load(self, gen):
         assert isinstance(self.value, unicode)
-        res = '"' + self.value.encode('utf-8').replace('"', r'\"') + '"'
+        def escape(char):
+            if char == '"': return r'\"'
+            if char == '\n': return r'\n'
+            return char
+        res = ('"' + 
+               "".join(escape(c) for c in self.value.encode('utf-8')) +
+               '"')
         gen.emit(LDC, res)
 
 class ComplexConst(Const):
@@ -396,6 +428,40 @@
         gen.emit(self.methodinfo)
 
 # ___________________________________________________________________________
+# Generator State
+
+class ClassState(object):
+    """ When you invoked begin_class(), one of these objects is allocated
+    and tracks the state as we go through the definition process. """
+    def __init__(self, classnm, superclassnm):
+        self.class_name = classnm
+        self.superclass_name = superclassnm
+    def out(self, arg):
+        self.file.write(arg)
+
+class FunctionState(object):
+    """ When you invoked begin_function(), one of these objects is allocated
+    and tracks the state as we go through the definition process. """
+    def __init__(self):
+        self.next_offset = 0
+        self.local_vars = {}
+        self.instr_counter = 0
+    def add_var(self, jvar, jtype):
+        """ Adds new entry for variable 'jvar', of java type 'jtype' """
+        idx = self.next_offset
+        self.next_offset += jtype.type_width()
+        if jvar:
+            assert jvar not in self.local_vars # never been added before
+            self.local_vars[jvar] = idx
+        return idx
+    def var_offset(self, jvar, jtype):
+        """ Returns offset for variable 'jvar', of java type 'jtype' """
+        if jvar in self.local_vars:
+            return self.local_vars[jvar]
+        return self.add_var(jvar, jtype)
+
+
+# ___________________________________________________________________________
 # Generator
 
 class JVMGenerator(Generator):
@@ -410,6 +476,8 @@
     def __init__(self, db):
         self.db = db
         self.label_counter = 0
+        self.curclass = None
+        self.curfunc = None
 
     # __________________________________________________________________
     # JVM specific methods to be overloaded by a subclass
@@ -417,14 +485,38 @@
     # If the name does not begin with '_', it will be called from
     # outside the generator.
 
-    def begin_class(self, classnm):
+    def begin_class(self, classnm, superclsnm):
         """
+        Begins a class declaration.  Overall flow of class declaration
+        looks like:
+
+        begin_class()
+        [add_field()]
+        emit_constructor()
+        [begin_function()...end_function()]
+        end_class()
+
+        Where items in brackets may appear anywhere from 0 to inf times.
+        
         classnm --- full Java name of the class (i.e., "java.lang.String")
+        superclassnm --- full Java name of the super class
         """
-        unimplemented
+        assert not self.curclass
+        self.curclass = ClassState(classnm, superclsnm)
+        self._begin_class()
 
     def end_class(self):
-        unimplemented
+        self._end_class()
+        self.curclass = None
+        self.curfunc = None
+
+    def _begin_class(self):
+        """ Main implementation of begin_class """
+        raise NotImplementedError
+
+    def _end_class(self):
+        """ Main implementation of end_class """
+        raise NotImplementedError    
 
     def add_field(self, fobj):
         """
@@ -432,13 +524,29 @@
         """
         unimplemented
 
+    def emit_constructor(self):
+        """
+        Emits the constructor for this class, which merely invokes the
+        parent constructor.
+        
+        superclsnm --- same Java name of super class as from begin_class
+        """
+        jtype = jvm_for_class(self.curclass.class_name)
+        self.begin_function("<init>", [], [jtype], jVoid)
+        self.load_jvm_var(jtype, 0)
+        jmethod = Method(self.curclass.superclass_name, "<init>", "()V",
+                         opcode=INVOKESPECIAL)
+        jmethod.invoke(self)
+        self.return_val(jVoid)
+        self.end_function()
+
     def begin_function(self, funcname, argvars, argtypes, rettype,
                        static=False):
         """
         funcname --- name of the function
         argvars --- list of objects passed to load() that represent arguments;
                     should be in order, or () if load() will not be used
-        argtypes --- JvmType for each argument
+        argtypes --- JvmType for each argument [INCLUDING this]
         rettype --- JvmType for the return value
         static --- keyword, if true then a static func is generated
 
@@ -448,13 +556,12 @@
         # Compute the indicates of each argument in the local variables
         # for the function.  Note that some arguments take up two slots
         # depending on their type [this is compute by type_width()]
-        self.next_offset = 0
-        self.local_vars = {}
+        assert not self.curfunc
+        self.curfunc = FunctionState()
         for idx, ty in enumerate(argtypes):
-            if idx < len(argvars):
-                var = argvars[idx]
-                self.local_vars[var] = self.next_offset
-            self.next_offset += ty.type_width()
+            if idx < len(argvars): var = argvars[idx]
+            else: var = None
+            self.curfunc.add_var(var, ty)
         # Prepare a map for the local variable indices we will add
         # Let the subclass do the rest of the work; note that it does
         # not need to know the argvars parameter, so don't pass it
@@ -469,8 +576,7 @@
 
     def end_function(self):
         self._end_function()
-        del self.next_offset
-        del self.local_vars
+        self.curfunc = None
 
     def _end_function(self):
         unimplemented
@@ -488,17 +594,24 @@
         """ Returns a value from top of stack of the JvmType 'vartype' """
         self._instr(RETURN.for_type(vartype))
 
+    def load_string(self, str):
+        uni = str.decode('utf-8')
+        UnicodeConst(uni).load(self)
+
     def load_jvm_var(self, vartype, varidx):
         """ Loads from jvm slot #varidx, which is expected to hold a value of
         type vartype """
+        assert varidx < self.curfunc.next_offset
         opc = LOAD.for_type(vartype)
-        print "load_jvm_jar: vartype=%s varidx=%s opc=%s" % (
-            repr(vartype), repr(varidx), repr(opc))
+        self.add_comment("     load_jvm_jar: vartype=%s varidx=%s" % (
+            repr(vartype), repr(varidx)))
         self._instr(opc, varidx)
 
     def store_jvm_var(self, vartype, varidx):
         """ Loads from jvm slot #varidx, which is expected to hold a value of
         type vartype """
+        self.add_comment("     store_jvm_jar: vartype=%s varidx=%s" % (
+            repr(vartype), repr(varidx)))
         self._instr(STORE.for_type(vartype), varidx)
 
     def load_from_array(self, elemtype):
@@ -531,6 +644,11 @@
         if mark:
             self.mark(res)
         return res
+
+    def load_this_ptr(self):
+        """ Convenience method.  Be sure you only call it from a
+        virtual method, not static methods. """
+        self.load_jvm_var(jObject, 0)
     
     # __________________________________________________________________
     # Exception Handling
@@ -604,17 +722,11 @@
         jty = self.db.lltype_to_cts(v.concretetype)
         # Determine index in stack frame slots:
         #   note that arguments and locals can be treated the same here
-        if v in self.local_vars:
-            idx = self.local_vars[v]
-        else:
-            idx = self.local_vars[v] = self.next_offset
-            self.next_offset += jty.type_width()
-        return jty, idx
+        return jty, self.curfunc.var_offset(v, jty)
         
     def load(self, value):
         if isinstance(value, flowmodel.Variable):
             jty, idx = self._var_data(value)
-            print "load_jvm_var: jty=%s idx=%s" % (repr(jty), repr(idx))
             return self.load_jvm_var(jty, idx)
 
         if isinstance(value, flowmodel.Constant):
@@ -624,6 +736,10 @@
                         repr(value.concretetype) + " v=" + repr(value))
 
     def store(self, v):
+        # Ignore Void values
+        if v.concretetype is ootype.Void:
+            return
+        
         if isinstance(v, flowmodel.Variable):
             jty, idx = self._var_data(v)
             return self.store_jvm_var(jty, idx)
@@ -631,6 +747,9 @@
 
     def set_field(self, CONCRETETYPE, fieldname):
         if fieldname == "meta":
+            # temporary hack
+            self.add_comment("      WARNING: emulating meta for now")
+            self.emit(POP)
             self.emit(POP)
         else:
             clsobj = self.db.pending_class(CONCRETETYPE)
@@ -639,6 +758,7 @@
 
     def get_field(self, CONCRETETYPE, fieldname):
         if fieldname == 'meta':
+            self.add_comment("      WARNING: emulating meta for now")
             self.emit(POP)
             self.emit(ACONST_NULL)
         else:
@@ -646,8 +766,13 @@
             fieldobj = clsobj.lookup_field(fieldname)
             fieldobj.load(self)
 
-    def downcast(self, type):
-        self._instr(CHECKCAST, type)
+    def downcast(self, TYPE):
+        jtype = self.db.lltype_to_cts(TYPE)
+        self._instr(CHECKCAST, jtype)
+        
+    def instanceof(self, TYPE):
+        jtype = self.db.lltype_to_cts(TYPE)
+        self._instr(INSTANCEOF, jtype)
 
     def branch_unconditionally(self, target_label):
         self._instr(GOTO, target_label)
@@ -662,6 +787,11 @@
         mthd = self.db.pending_function(graph)
         mthd.invoke(self)
 
+    def call_method(self, OOCLASS, method_name):
+        clsobj = self.db.pending_class(OOCLASS)
+        mthd = clsobj.lookup_method(method_name)
+        mthd.invoke(self)
+
     def call_primitive(self, graph):
         raise NotImplementedError
 
@@ -671,6 +801,9 @@
         self.emit(NEW, clsobj.jvm_type())
         self.emit(DUP)
         self.emit(ctor)
+        
+    def instantiate(self):
+        self.emit(PYPYRUNTIMENEW)
 
     # __________________________________________________________________
     # Methods invoked directly by strings in jvm/opcode.py
@@ -713,6 +846,9 @@
         self._instr(ICONST, 1)
         self.mark(endlbl)
 
+    is_null = lambda self: self._compare_op(IFNULL)
+    is_not_null = lambda self: self._compare_op(IFNOTNULL)
+
     logical_not = lambda self: self._compare_op(IFEQ)
     equals_zero = logical_not
     not_equals_zero = lambda self: self._compare_op(IFNE)
@@ -774,74 +910,60 @@
         JVMGenerator.__init__(self, db)
         self.outdir = outdir
 
-    def add_comment(self, comment):
-        self.out.write("  ; %s\n" % comment)
-
-    def begin_class(self, classnm):
+    def _begin_class(self):
         """
         classnm --- full Java name of the class (i.e., "java.lang.String")
         """
+
+        iclassnm = self.curclass.class_name.replace('.', '/')
+        isuper = self.curclass.superclass_name.replace('.', '/')
         
-        iclassnm = classnm.replace('.', '/')
         jfile = "%s/%s.j" % (self.outdir, iclassnm)
 
         try:
             jdir = jfile[:jfile.rindex('/')]
             os.makedirs(jdir)
         except OSError: pass
-        self.out = open(jfile, 'w')
+        self.curclass.file = open(jfile, 'w')
 
         # Write the JasminXT header
-        #self.out.write(".bytecode XX\n")
-        #self.out.write(".source \n")
-        self.out.write(".class public %s\n" % iclassnm)
-
-        # FIX: custom super class
-        self.out.write(".super java/lang/Object\n")
-        self.constructor_emitted = False
+        self.curclass.out(".class public %s\n" % iclassnm)
+        self.curclass.out(".super %s\n" % isuper)
         
-    def end_class(self):
-        self._emit_constructor()
-        self.out.close()
-        self.out = None
+    def _end_class(self):
+        self.curclass.file.close()
 
     def close(self):
-        assert self.out is None, "Unended class"
+        assert self.curclass is None
+
+    def add_comment(self, comment):
+        self.curclass.out("  ; %s\n" % comment)
 
     def add_field(self, fobj):
-        self.out.write('.field public %s %s\n' % (
+        self.curclass.out('.field public %s %s\n' % (
             fobj.field_name, fobj.jtype))
 
-    def _emit_constructor(self):
-        if not self.constructor_emitted:
-            self.out.write(".method public <init>()V\n")
-            self.out.write("    aload_0\n")
-            self.out.write("    invokespecial java/lang/Object/<init>()V\n")
-            self.out.write("    return\n")
-            self.out.write(".end method\n")
-            self.constructor_emitted = True
-            
     def _begin_function(self, funcname, argtypes, rettype, static):
 
-        self._emit_constructor()
+        if not static: argtypes = argtypes[1:]
 
         # Throws clause?  Only use RuntimeExceptions?
         kw = ['public']
         if static: kw.append('static')
-        self.out.write('.method %s %s(%s)%s\n' % (
+        self.curclass.out('.method %s %s(%s)%s\n' % (
             " ".join(kw), funcname,
             "".join(argtypes), rettype))
 
     def _end_function(self):
-        self.out.write('.limit stack 100\n') # HACK, track max offset
-        self.out.write('.limit locals %d\n' % self.next_offset)
-        self.out.write('.end method\n')
+        self.curclass.out('.limit stack 100\n') # HACK, track max offset
+        self.curclass.out('.limit locals %d\n' % self.curfunc.next_offset)
+        self.curclass.out('.end method\n')
 
     def mark(self, lbl):
         """ Marks the point that a label indicates. """
         _, lblnum, lbldesc = lbl
         assert _ == "Label"
-        self.out.write('  %s_%s:\n' % (lbldesc, lblnum))
+        self.curclass.out('  %s_%s:\n' % (lbldesc, lblnum))
 
     def _instr(self, opcode, *args):
         jvmstr, args = opcode.specialize_opcode(args)
@@ -853,10 +975,12 @@
         if opcode.flags & (INVOKE|FIELD):
             assert len(args) == 1
             args = (args[0].jasmin_syntax(),)
-        self.out.write('    %s %s\n' % (
-            jvmstr, " ".join([str(s) for s in args])))
+        instr_text = '    %s %s' % (jvmstr, " ".join([str(s) for s in args]))
+        self.curclass.out('    %-60s ; %d\n' % (
+            instr_text, self.curfunc.instr_counter))
+        self.curfunc.instr_counter+=1
 
     def try_catch_region(self, excclsty, trystartlbl, tryendlbl, catchlbl):
-        self.out.write('  .catch %s from %s to %s using %s\n' % (
+        self.curclass.out('  .catch %s from %s to %s using %s\n' % (
             excclsty.int_class_name(), trystartlbl, tryendlbl, catchlbl))
                        

Modified: pypy/dist/pypy/translator/jvm/node.py
==============================================================================
--- pypy/dist/pypy/translator/jvm/node.py	(original)
+++ pypy/dist/pypy/translator/jvm/node.py	Wed Nov  1 14:57:43 2006
@@ -8,8 +8,9 @@
 from pypy.rpython.ootypesystem import ootype
 from pypy.translator.jvm.typesystem import \
      jString, jStringArray, jVoid, jThrowable
-from pypy.translator.jvm.typesystem import jvm_for_class, jvm_method_desc
+from pypy.translator.jvm.typesystem import jvm_for_class, jvm_method_desc, jInt
 from pypy.translator.jvm.opcodes import opcodes
+from pypy.translator.jvm.option import getoption
 from pypy.translator.oosupport.function import Function as OOFunction
 import pypy.translator.jvm.generator as jvmgen
 
@@ -60,16 +61,8 @@
         ootype.Char:jvmgen.PYPYSTRTOCHAR
         }
 
-    _type_printing_methods = {
-        ootype.Signed:jvmgen.PYPYDUMPINT,
-        ootype.Unsigned:jvmgen.PYPYDUMPUINT,
-        ootype.SignedLongLong:jvmgen.PYPYDUMPLONG,
-        ootype.Float:jvmgen.PYPYDUMPDOUBLE,
-        ootype.Bool:jvmgen.PYPYDUMPBOOLEAN,
-        }
-
     def render(self, gen):
-        gen.begin_class('pypy.Main')
+        gen.begin_class('pypy.Main', 'java.lang.Object')
         gen.begin_function(
             'main', (), [jStringArray], jVoid, static=True)
 
@@ -97,10 +90,10 @@
 
         # Print result?
         if self.print_result:
-            resootype = self.graph.getreturnvar().concretetype
-            resjtype = self.db.lltype_to_cts(resootype)
-            meth = self._type_printing_methods[resootype]
-            gen.emit(meth)
+            gen.emit(jvmgen.ICONST, 0)
+            RESOOTYPE = self.graph.getreturnvar().concretetype
+            dumpmethod = self.db.generate_dump_method_for_ootype(RESOOTYPE)
+            dumpmethod.invoke(gen)
 
         # And finish up
         gen.return_val(jVoid)
@@ -131,9 +124,13 @@
 
     def method(self):
         """ Returns a jvmgen.Method that can invoke this function """
-        if not self.is_method: opcode = jvmgen.INVOKESTATIC
-        else: opcode = jvmgen.INVOKEVIRTUAL
-        mdesc = jvm_method_desc(self.jargtypes, self.jrettype)
+        if not self.is_method:
+            opcode = jvmgen.INVOKESTATIC
+            startidx = 0
+        else:
+            opcode = jvmgen.INVOKEVIRTUAL
+            startidx = 1
+        mdesc = jvm_method_desc(self.jargtypes[startidx:], self.jrettype)
         return jvmgen.Method(self.classnm, self.name, mdesc, opcode=opcode)
 
     def begin_render(self):
@@ -196,15 +193,14 @@
         self.ilasm.load(exc)
         self.ilasm.throw()
 
-    def _setup_link(self, link):
-        target = link.target
-        for to_load, to_store in zip(link.args, target.inputargs):
-            if to_load.concretetype is not ootype.Void:
-                self.ilasm.load(to_load)
-                self.ilasm.store(to_store)
-
     def _render_op(self, op):
         self.generator.add_comment(str(op))
+        
+        if getoption('trace'):
+            jvmgen.SYSTEMERR.load(self.generator)
+            self.generator.load_string(str(op) + "\n")
+            jvmgen.PRINTSTREAMPRINTSTR.invoke(self.generator)
+            
         OOFunction._render_op(self, op)
 
 class Class(Node):
@@ -212,15 +208,16 @@
     """ Represents a class to be emitted.  Note that currently, classes
     are emitted all in one shot, not piecemeal. """
 
-    def __init__(self, name):
+    def __init__(self, name, supername):
         """
-        'name' should be a fully qualified Java class name like
+        'name' and 'super_name' should be fully qualified Java class names like
         "java.lang.String"
         """
-        self.name = name        # public attribute
-        self.fields = []
-        self.methods = []
+        self.name = name             # public attribute
+        self.super_name = supername  # public attribute
+        self.fields = {}
         self.rendered = False
+        self.methods = {}
 
     def jvm_type(self):
         return jvm_for_class(self.name)
@@ -229,29 +226,104 @@
         """ Creates a new field accessed via the jvmgen.Field
         descriptor 'fieldobj'.  Must be called before render()."""
         assert not self.rendered and isinstance(fieldobj, jvmgen.Field)
-        self.fields.append(fieldobj)
+        self.fields[fieldobj.field_name] = fieldobj
 
     def lookup_field(self, fieldnm):
-        for f in self.fields:
-            if f.field_name == fieldnm: return f
-        assert False, "No field named '%s' found" % fieldnm
+        """ Given a field name, returns a jvmgen.Field object """
+        return self.fields[fieldnm]
+
+    def lookup_method(self, methodnm):
+        """ Given the method name, returns a jvmgen.Method object """
+        return self.methods[methodnm].method()
 
     def add_method(self, func):
         """ Creates a new method in this class, represented by the
         Function object 'func'.  Must be called before render();
         intended to be invoked by the database.  Note that some of these
         'methods' may actually represent static functions. """
-        self.methods.append(func)
+        self.methods[func.name] = func
 
+    def add_dump_method(self, dm):
+        self.dump_method = dm # public attribute for reading
+        self.add_method(dm)
+        
     def render(self, gen):
         self.rendered = True
-        gen.begin_class(self.name)
+        gen.begin_class(self.name, self.super_name)
 
-        for field in self.fields:
+        for field in self.fields.values():
             gen.add_field(field)
 
-        for method in self.methods:
+        gen.emit_constructor()
+
+        for method in self.methods.values():
             method.render(gen)
         
         gen.end_class()
 
+class TestDumpMethod(object):
+
+    def __init__(self, db, OOCLASS, clsobj):
+        self.db = db
+        self.OOCLASS = OOCLASS
+        self.clsobj = clsobj
+        self.name = "_pypy_dump"
+        self.jargtypes = [clsobj.jvm_type(), jInt]
+        self.jrettype = jVoid
+
+    def method(self):
+        """ Returns a jvmgen.Method that can invoke this function """
+        mdesc = jvm_method_desc(self.jargtypes[1:], self.jrettype)
+        return jvmgen.Method(self.clsobj.name, self.name, mdesc,
+                             opcode=jvmgen.INVOKEVIRTUAL)
+
+    def render(self, gen):
+        clsobj = self.clsobj
+
+        gen.begin_function(
+            self.name, (), self.jargtypes, self.jrettype, static=False)
+
+        def genprint(str, unoffset=0):
+            gen.load_jvm_var(jInt, 1)
+            if unoffset:
+                gen.emit(jvmgen.ICONST, unoffset)
+                gen.emit(jvmgen.ISUB)
+            gen.load_string(str)
+            jvmgen.PYPYDUMPINDENTED.invoke(gen)
+
+        # Start the dump
+        genprint("InstanceWrapper([")
+
+        # Increment the indent
+        gen.load_jvm_var(jInt, 1)
+        gen.emit(jvmgen.ICONST, 2)
+        gen.emit(jvmgen.IADD)
+        gen.store_jvm_var(jInt, 1)
+
+        for fieldnm, (FIELDOOTY, fielddef) in self.OOCLASS._fields.iteritems():
+
+            if FIELDOOTY is ootype.Void: continue
+
+            genprint("(")
+            genprint(fieldnm+",")
+
+            print "fieldnm=%r fieldty=%r" % (fieldnm, FIELDOOTY)
+
+            # Print the value of the field:
+            gen.load_this_ptr()
+            fieldobj = clsobj.lookup_field(fieldnm)
+            fieldobj.load(gen)
+            gen.load_jvm_var(jInt, 1)
+            dumpmethod = self.db.generate_dump_method_for_ootype(FIELDOOTY)
+            gen.emit(dumpmethod)
+
+            genprint(")")
+
+        # Decrement indent and dump close
+        genprint("])", 2)
+
+        gen.emit(jvmgen.RETURN.for_type(jVoid))
+
+        gen.end_function()
+        
+        

Modified: pypy/dist/pypy/translator/jvm/opcodes.py
==============================================================================
--- pypy/dist/pypy/translator/jvm/opcodes.py	(original)
+++ pypy/dist/pypy/translator/jvm/opcodes.py	Wed Nov  1 14:57:43 2006
@@ -7,7 +7,7 @@
 
 from pypy.translator.oosupport.metavm import \
      PushArg, PushAllArgs, StoreResult, InstructionList, New, DoNothing, Call,\
-     SetField, GetField
+     SetField, GetField, CallMethod, DownCast, RuntimeNew
 import pypy.translator.jvm.generator as jvmgen
 
 def _check_zer(op):
@@ -23,14 +23,14 @@
 opcodes = {
     # __________ object oriented operations __________
     'new':                      [New, StoreResult],
-    #'runtimenew':               [RuntimeNew],
+    'runtimenew':               [RuntimeNew, StoreResult],
     'oosetfield':               [SetField],
     'oogetfield':               [GetField, StoreResult],
-    #'oosend':                   [CallMethod],
-    #'ooupcast':                 DoNothing,
-    #'oodowncast':               [DownCast],
-    #'oois':                     'ceq',
-    #'oononnull':                [PushAllArgs, 'ldnull', 'ceq']+Not,
+    'oosend':                   [CallMethod, StoreResult],
+    'ooupcast':                 DoNothing,
+    'oodowncast':               [DownCast,StoreResult],
+    'oois':                     'is_null',
+    'oononnull':                'is_not_null',
     #'instanceof':               [CastTo, 'ldnull', 'cgt.un'],
     #'subclassof':               [PushAllArgs, 'call bool [pypylib]pypy.runtime.Utils::SubclassOf(class [mscorlib]System.Type, class[mscorlib]System.Type)'],
     #'ooidentityhash':           [PushAllArgs, 'callvirt instance int32 object::GetHashCode()'],
@@ -41,7 +41,7 @@
     #
     'same_as':                  DoNothing,
     #'hint':                     [PushArg(0), StoreResult],
-    'direct_call':              [Call],
+    'direct_call':              [Call, StoreResult],
     #'indirect_call':            [IndirectCall],
     #
     #'cast_ptr_to_weakadr':      [PushAllArgs, 'newobj instance void class %s::.ctor(object)' % WEAKREF],

Modified: pypy/dist/pypy/translator/jvm/option.py
==============================================================================
--- pypy/dist/pypy/translator/jvm/option.py	(original)
+++ pypy/dist/pypy/translator/jvm/option.py	Wed Nov  1 14:57:43 2006
@@ -8,7 +8,8 @@
     'noasm':False,
     'package':'pypy',
     'wd':False,
-    'norun':False
+    'norun':False,
+    'trace':False
     }
 
 def getoption(name):

Modified: pypy/dist/pypy/translator/jvm/src/PyPy.java
==============================================================================
--- pypy/dist/pypy/translator/jvm/src/PyPy.java	(original)
+++ pypy/dist/pypy/translator/jvm/src/PyPy.java	Wed Nov  1 14:57:43 2006
@@ -185,45 +185,69 @@
 
     // Used in testing:
 
-    public static void dump_int(int i) {
-        System.out.println(i);
+    public static void dump_indented(int indent, String text) {
+        for (int i = 0; i < indent; i++)
+            System.out.print(" ");
+        System.out.println(text);
     }
 
-    public static void dump_uint(int i) {
+    public static void dump_int(int i, int indent) {
+        dump_indented(indent, Integer.toString(i));
+    }
+
+    public static void dump_uint(int i, int indent) {
         if (i >= 0)
-            System.out.println(i);
+            dump_indented(indent, Integer.toString(i));
         else {
             int loword = i & 0xFFFF;
             int hiword = i >>> 16;
             long res = loword + (hiword*0xFFFF);
-            System.out.println(res);
+            dump_indented(indent, Long.toString(res));
         }
     }
 
-    public static void dump_boolean(boolean l) {
+    public static void dump_boolean(boolean l, int indent) {
         if (l)
-            System.out.println("True");
+            dump_indented(indent, "True");
         else
-            System.out.println("False");
+            dump_indented(indent, "False");
     }
 
-    public static void dump_long(long l) {
-        System.out.println(l);
+    public static void dump_long(long l, int indent) {
+        dump_indented(indent, Long.toString(l));
     }
 
-    public static void dump_double(double d) {
-        System.out.println(d);
+    public static void dump_double(double d, int indent) {
+        dump_indented(indent, Double.toString(d));
     }
 
-    public static void dump_string(char[] b) {
-        System.out.print('"');
+    public static void dump_string(char[] b, int indent) {
+        StringBuffer sb = new StringBuffer();
+        sb.append('"');
         for (char c : b) {
             if (c == '"') 
-                System.out.print("\\\"");
-            System.out.print(c);
+                sb.append("\\\"");
+            else
+                sb.append(c);
+        }
+        sb.append('"');
+        dump_indented(indent, sb.toString());
+    }
+
+    public static void dump_object(Object o, int indent) {
+        dump_indented(indent, o.toString());
+    }
+
+    // ----------------------------------------------------------------------
+    // Type Manipulation Routines
+
+    public static Object RuntimeNew(Class c) {
+        // all classes in our system have constructors w/ no arguments
+        try {
+            return c.getConstructor().newInstance();
+        } catch (Exception exc) {
+            throw new RuntimeException("Unexpected", exc);
         }
-        System.out.print('"');
-        System.out.println();
     }
 
     // ----------------------------------------------------------------------

Modified: pypy/dist/pypy/translator/jvm/test/runtest.py
==============================================================================
--- pypy/dist/pypy/translator/jvm/test/runtest.py	(original)
+++ pypy/dist/pypy/translator/jvm/test/runtest.py	Wed Nov  1 14:57:43 2006
@@ -40,6 +40,14 @@
     def __repr__(self):
         return 'ExceptionWrapper(%s)' % repr(self.class_name)
 
+class InstanceWrapper:
+    def __init__(self, fields):
+        # fields is a list of (name, value) tuples
+        self.fields = fields
+
+    def __repr__(self):
+        return 'InstanceWrapper(%s)' % repr(self.fields)
+
 # CLI could-be duplicate
 class JvmGeneratedSourceWrapper(object):
     def __init__(self, gensrc):

Modified: pypy/dist/pypy/translator/jvm/typesystem.py
==============================================================================
--- pypy/dist/pypy/translator/jvm/typesystem.py	(original)
+++ pypy/dist/pypy/translator/jvm/typesystem.py	Wed Nov  1 14:57:43 2006
@@ -48,9 +48,13 @@
         return not self.is_scalar()
     def is_array(self):
         return self[0] == '['
+    def class_name(self):
+        """ Converts a descriptor like Ljava/lang/Object; to
+        full class name java.lang.Object """
+        return self.int_class_name().replace('/','.')
     def int_class_name(self):
         """ Converts a descriptor like Ljava/lang/Object; to
-        java/lang/Object """
+        internal class name java/lang/Object """
         assert self[0] == 'L' and self[-1] == ';'
         return self[1:-1]
     def type_width(self):
@@ -93,6 +97,7 @@
 jIterator = jvm_for_class('java.util.Iterator')
 jClass = jvm_for_class('java.lang.Class')
 jStringBuilder = jvm_for_class('java.lang.StringBuilder')
+jPrintStream = jvm_for_class('java.io.PrintStream')
 
 # Map from OOType to an internal JVM type descriptor
 #  only handles the simple cases

Modified: pypy/dist/pypy/translator/oosupport/function.py
==============================================================================
--- pypy/dist/pypy/translator/oosupport/function.py	(original)
+++ pypy/dist/pypy/translator/oosupport/function.py	Wed Nov  1 14:57:43 2006
@@ -158,9 +158,12 @@
                 self.generator.branch_conditionally(link.exitcase, target_label)
 
     def _setup_link(self, link):
+        self.generator.add_comment("Setup link")
         target = link.target
         for to_load, to_store in zip(link.args, target.inputargs):
             if to_load.concretetype is not Void:
+                self.generator.add_comment("  to_load=%r to_store=%r" % (
+                    to_load, to_store))
                 self.generator.load(to_load)
                 self.generator.store(to_store)
 

Modified: pypy/dist/pypy/translator/oosupport/metavm.py
==============================================================================
--- pypy/dist/pypy/translator/oosupport/metavm.py	(original)
+++ pypy/dist/pypy/translator/oosupport/metavm.py	Wed Nov  1 14:57:43 2006
@@ -15,6 +15,19 @@
 from pypy.rpython.ootypesystem.bltregistry import ExternalType
 
 class Generator(object):
+    
+    def add_comment(self, text):
+        """
+        Called w/in a function w/ a text string that could be
+        usefully added to the output.
+        """
+        pass
+
+    def dup(self, TYPE):
+        """ Duplicates the top of the stack, which is of the given TYPE.
+
+        Stack: val, ... -> val, val, ..."""
+        raise NotImplementedError
 
     def emit(self, instr, *args):
         """
@@ -49,7 +62,7 @@
         
         Stack: value, item, ... -> ...
         """
-        pass
+        raise NotImplementedError
 
     def get_field(self, CONCRETETYPE, fieldname):
         """
@@ -60,15 +73,35 @@
 
         Stack: item, ... -> ...
         """
-        pass
+        raise NotImplementedError
 
-    def downcast(self, type):
+    def downcast(self, TYPE):
         """
         Casts the object on the top of the stack to be of the specified
-        type.  Assumed to raise an exception on failure.
+        ootype.  Assumed to raise an exception on failure.
         
         Stack: obj, ... -> obj, ...
         """
+        raise NotImplementedError
+        
+
+    def instantiate(self):
+        """
+        Instantiates an instance of the Class object that is on top of
+        the stack.  Class objects refers to an object representing a
+        class.  Used to implement RuntimeNew.
+
+        Stack: class_obj, ... -> instance_obj, ...
+        """
+        raise NotImplementedError
+
+    def instanceof(self, TYPE):
+        """
+        Determines whether the object on the top of the stack is an
+        instance of TYPE (an ootype).
+        
+        Stack: obj, ... -> boolean, ...
+        """
         pass
 
     def branch_unconditionally(self, target_label):
@@ -85,13 +118,20 @@
         raise NotImplementedError
 
     def call_graph(self, graph):
-        """ Invokes the method corresponding to the given graph.  The
+        """ Invokes the function corresponding to the given graph.  The
         arguments to the graph have already been pushed in order
         (i.e., first argument pushed first, etc).  Pushes the return
         value.
 
         Stack: argN...arg2, arg1, arg0, ... -> ret, ... """
-        raise NotImplementedError        
+        raise NotImplementedError
+
+    def call_method(self, OOCLASS, method_name):
+        """ Invokes the given method on the object on the stack.  The
+        this ptr and all arguments have already been pushed.
+
+        Stack: argN, arg2, arg1, this, ... -> ret, ... """
+        raise NotImplementedError
 
     def call_primitive(self, graph):
         """ Like call_graph, but it has been suggested that the method be
@@ -106,6 +146,9 @@
         Stack: ... -> newobj, ... """
         raise NotImplementedError
 
+    def push_null(self):
+        raise NotImplementedError
+
 class InstructionList(list):
     def render(self, generator, op):
         for instr in self:
@@ -182,9 +225,16 @@
     result on top of the stack. """
     def render(self, generator, op):
         RESULTTYPE = op.result.concretetype
-        resulttype = generator.cts.lltype_to_cts(RESULTTYPE)
         generator.load(op.args[0])
-        generator.downcast(resulttype)
+        generator.downcast(RESULTTYPE)
+
+class _InstanceOf(MicroInstruction):
+    """ Push the argument op.args[0] and cast it to the desired type, leaving
+    result on top of the stack. """
+    def render(self, generator, op):
+        RESULTTYPE = op.result.concretetype
+        generator.load(op.args[0])
+        generator.instanceof(RESULTTYPE)
 
 # There are three distinct possibilities where we need to map call differently:
 # 1. Object is marked with rpython_hints as a builtin, so every attribut access
@@ -292,37 +342,23 @@
             else:
                 generator.call_graph(graph)
         else:
-            self._render_method(generator, method_name, op.args[1:])
-
-    def _render_method(self, generator, method_name, args):
-        this = args[0]
-        for arg in args: # push parameters
-            generator.load(arg)
-
-        # XXX: very hackish, need refactoring
-        if this.concretetype is ootype.String:
-            # special case for string: don't use methods, but plain functions
-            METH = this.concretetype._METHODS[method_name]
-            cts = generator.cts
-            ret_type = cts.lltype_to_cts(METH.RESULT)
-            arg_types = [cts.lltype_to_cts(arg) for arg in METH.ARGS if arg is not ootype.Void]
-            arg_types.insert(0, cts.lltype_to_cts(ootype.String))
-            arg_list = ', '.join(arg_types)
-            signature = '%s %s::%s(%s)' % (ret_type, STRING_HELPER_CLASS, method_name, arg_list)
-            generator.call_signature(signature)
-        else:
+            this = op.args[1]
             generator.call_method(this.concretetype, method_name)
             
-            # special case: DictItemsIterator(XXX,
-            # Void).ll_current_value needs to return an int32 because
-            # we can't use 'void' as a parameter of a Generic. This
-            # means that after the call to ll_current_value there will
-            # be a value on the stack, and we need to explicitly pop
-            # it.
-            if isinstance(this.concretetype, ootype.DictItemsIterator) and \
-               this.concretetype._VALUETYPE is ootype.Void and \
-               method_name == 'll_current_value':
-                generator.ilasm.pop()
+class _CallMethod(MicroInstruction):
+    def render(self, generator, op):
+        method = op.args[0] # a FlowConstant string...
+        this = op.args[1]
+        for arg in op.args[1:]:
+            generator.load(arg)
+        generator.call_method(this.concretetype, method.value)
+
+class _RuntimeNew(MicroInstruction):
+    def render(self, generator, op):
+        generator.load(op.args[0])
+        generator.instantiate()
+        generator.downcast(op.result.concretetype)
+
 
 New = _New()
 
@@ -333,3 +369,5 @@
 DownCast = _DownCast()
 DoNothing = _DoNothing()
 Call = _Call()
+CallMethod = _CallMethod()
+RuntimeNew = _RuntimeNew()



More information about the Pypy-commit mailing list