Commits

Antonio Cuni committed 52bbfe7

(in-progress) copy the cli backend from the oo-jit branch

Comments (0)

Files changed (66)

pypy/translator/cli/__init__.py

Empty file added.

pypy/translator/cli/carbonpython.py

+#! /usr/bin/env python
+"""
+Usage:  carbonpython.py <module-name> [dll-name]
+
+Compiles an RPython module into a .NET dll.
+"""
+
+import sys
+import new
+import types
+import os.path
+import inspect
+
+from pypy.translator.driver import TranslationDriver
+from pypy.translator.cli.entrypoint import DllEntryPoint
+
+class DllDef:
+    def __init__(self, name, namespace, functions=[], dontmangle=True, isnetmodule=False):
+        self.name = name
+        self.namespace = namespace
+        self.functions = functions # [(function, annotation), ...]
+        self.isnetmodule = isnetmodule
+        self.driver = TranslationDriver()
+        if dontmangle:
+            self.driver.config.translation.ootype.mangle = False
+        self.driver.setup_library(self)
+
+    def add_function(self, func, inputtypes):
+        self.functions.append((func, inputtypes))
+
+    def get_entrypoint(self, bk):
+        graphs = [bk.getdesc(f).cachedgraph(None) for f, _ in self.functions]
+        return DllEntryPoint(self.name, graphs, self.isnetmodule)
+
+    def compile(self):
+        # add all functions to the appropriate namespace
+        if self.namespace:
+            for func, _ in self.functions:
+                if not hasattr(func, '_namespace_'):
+                    func._namespace_ = self.namespace
+        self.driver.proceed(['compile_cli'])
+
+class export(object):
+    def __new__(self, *args, **kwds):
+        if len(args) == 1 and isinstance(args[0], types.FunctionType):
+            func = args[0]
+            func._inputtypes_ = ()
+            return func
+        return object.__new__(self, *args, **kwds)
+    
+    def __init__(self, *args, **kwds):
+        self.inputtypes = args
+        self.namespace = kwds.pop('namespace', None)
+        if len(kwds) > 0:
+            raise TypeError, "unexpected keyword argument: '%s'" % kwds.keys()[0]
+
+    def __call__(self, func):
+        func._inputtypes_ = self.inputtypes
+        if self.namespace is not None:
+            func._namespace_ = self.namespace
+        return func
+
+def is_exported(obj):
+    return isinstance(obj, (types.FunctionType, types.UnboundMethodType)) \
+           and hasattr(obj, '_inputtypes_')
+
+def collect_entrypoints(dic):
+    entrypoints = []
+    for item in dic.itervalues():
+        if is_exported(item):
+            entrypoints.append((item, item._inputtypes_))
+        elif isinstance(item, types.ClassType) or isinstance(item, type):
+            entrypoints += collect_class_entrypoints(item)
+    return entrypoints
+
+def collect_class_entrypoints(cls):
+    try:
+        __init__ = cls.__init__
+        if not is_exported(__init__):
+            return []
+    except AttributeError:
+        return []
+
+    entrypoints = [(wrap_init(cls, __init__), __init__._inputtypes_)]
+    for item in cls.__dict__.itervalues():
+        if item is not __init__.im_func and is_exported(item):
+            inputtypes = (cls,) + item._inputtypes_
+            entrypoints.append((wrap_method(item), inputtypes))
+    return entrypoints
+
+def getarglist(meth):
+    arglist, starargs, kwargs, defaults = inspect.getargspec(meth)
+    assert starargs is None, '*args not supported yet'
+    assert kwargs is None, '**kwds not supported yet'
+    assert defaults is None, 'default values not supported yet'
+    return arglist
+
+def wrap_init(cls, meth):
+    arglist = getarglist(meth)[1:] # discard self
+    args = ', '.join(arglist)
+    source = 'def __internal__ctor(%s): return %s(%s)' % (
+        args, cls.__name__, args)
+    mydict = {cls.__name__: cls}
+    print source
+    exec source in mydict
+    return mydict['__internal__ctor']
+
+def wrap_method(meth, is_init=False):
+    arglist = getarglist(meth)
+    name = '__internal__%s' % meth.func_name
+    selfvar = arglist[0]
+    args = ', '.join(arglist)
+    params = ', '.join(arglist[1:])
+    source = 'def %s(%s): return %s.%s(%s)' % (
+        name, args, selfvar, meth.func_name, params)
+    mydict = {}
+    print source
+    exec source in mydict
+    return mydict[name]
+
+
+def compile_dll(filename, dllname=None, copy_dll=True):
+    dirname, name = os.path.split(filename)
+    if dllname is None:
+        dllname, _ = os.path.splitext(name)
+    elif dllname.endswith('.dll'):
+        dllname, _ = os.path.splitext(dllname)
+    module = new.module(dllname)
+    namespace = module.__dict__.get('_namespace_', dllname)
+    sys.path.insert(0, dirname)
+    execfile(filename, module.__dict__)
+    sys.path.pop(0)
+
+    dll = DllDef(dllname, namespace)
+    dll.functions = collect_entrypoints(module.__dict__)
+    dll.compile()
+    if copy_dll:
+        dll.driver.copy_cli_dll()
+
+def main(argv):
+    if len(argv) == 2:
+        filename = argv[1]
+        dllname = None
+    elif len(argv) == 3:
+        filename = argv[1]
+        dllname = argv[2]
+    else:
+        print >> sys.stderr, __doc__
+        sys.exit(2)
+
+    if not filename.endswith('.py'):
+        filename += '.py'
+    if not os.path.exists(filename):
+        print >> sys.stderr, "Cannot find file %s" % filename
+        sys.exit(1)
+    compile_dll(filename, dllname)
+
+if __name__ == '__main__':
+    main(sys.argv)
+

pypy/translator/cli/class_.py

+from pypy.rpython.ootypesystem import ootype
+from pypy.translator.cli.node import Node
+from pypy.translator.cli.cts import CTS
+from pypy.translator.oosupport.constant import push_constant
+from pypy.translator.cli.ilgenerator import CLIBaseGenerator
+
+try:
+    set
+except NameError:
+    from sets import Set as set
+
+class Class(Node):
+    def __init__(self, db, INSTANCE, namespace, name):
+        self.db = db
+        self.cts = db.genoo.TypeSystem(db)
+        self.INSTANCE = INSTANCE
+        self.namespace = namespace
+        self.name = name
+
+    def dependencies(self):
+        if not self.is_root(self.INSTANCE):
+            self.db.pending_class(self.INSTANCE._superclass)
+
+    def __hash__(self):
+        return hash(self.INSTANCE)
+
+    def __eq__(self, other):
+        return self.INSTANCE == other.INSTANCE
+
+    def __ne__(self, other):
+        return not self == other
+
+    def is_root(INSTANCE):
+        return INSTANCE._superclass is None
+    is_root = staticmethod(is_root)
+
+    def get_name(self):
+        return self.name
+
+    def __repr__(self):
+        return '<Class %s>' % self.name
+
+    def get_base_class(self):
+        base_class = self.INSTANCE._superclass
+        if self.is_root(base_class):
+            return '[mscorlib]System.Object'
+        else:
+            return self.db.class_name(base_class)
+
+    def is_abstract(self):
+        return False # XXX
+        
+        # if INSTANCE has an abstract method, the class is abstract
+        method_names = set()
+        for m_name, m_meth in self.INSTANCE._methods.iteritems():
+            if not hasattr(m_meth, 'graph'):
+                return True
+            method_names.add(m_name)
+
+        # if superclasses have abstract methods not overriden by
+        # INSTANCE, the class is abstract
+        abstract_method_names = set()
+        cls = self.INSTANCE._superclass
+        while cls is not None:
+            abstract_method_names.update(cls._methods.keys())
+            cls = cls._superclass
+        not_overriden = abstract_method_names.difference(method_names)
+        if not_overriden:
+            return True
+        
+        return False
+
+    def render(self, ilasm):        
+        if self.is_root(self.INSTANCE):
+            return
+
+        self.ilasm = ilasm
+        self.gen = CLIBaseGenerator(self.db, ilasm)
+
+        if self.namespace:
+            ilasm.begin_namespace(self.namespace)
+
+        ilasm.begin_class(self.name, self.get_base_class(), abstract=self.is_abstract())
+        for f_name, (f_type, f_default) in self.INSTANCE._fields.iteritems():
+            cts_type = self.cts.lltype_to_cts(f_type)
+            f_name = self.cts.escape_name(f_name)
+            if cts_type != CTS.types.void:
+                ilasm.field(f_name, cts_type)
+
+        self._ctor()
+        self._toString()
+
+        for m_name, m_meth in self.INSTANCE._methods.iteritems():
+            if hasattr(m_meth, 'graph'):
+                # if the first argument's type is not a supertype of
+                # 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()
+                SELF = args[0].concretetype
+##                if not ootype.isSubclass(self.INSTANCE, SELF):
+##                    continue
+                f = self.db.genoo.Function(self.db, m_meth.graph, m_name, is_method = True)
+                f.render(ilasm)
+            else:
+                # abstract method
+                METH = m_meth._TYPE
+                arglist = [(self.cts.lltype_to_cts(ARG), 'v%d' % i)
+                           for i, ARG in enumerate(METH.ARGS)
+                           if ARG is not ootype.Void]
+                returntype = self.cts.lltype_to_cts(METH.RESULT)
+                ilasm.begin_function(m_name, arglist, returntype, False, 'virtual') #, 'abstract')
+                ilasm.add_comment('abstract method')
+                if isinstance(METH.RESULT, ootype.OOType):
+                    ilasm.opcode('ldnull')
+                else:
+                    push_constant(self.db, METH.RESULT, 0, self.gen)
+                ilasm.opcode('ret')
+                ilasm.end_function()
+
+        ilasm.end_class()
+
+        if self.namespace:
+            ilasm.end_namespace()
+
+    def _ctor(self):
+        self.ilasm.begin_function('.ctor', [], 'void', False, 'specialname', 'rtspecialname', 'instance')
+        self.ilasm.opcode('ldarg.0')
+        self.ilasm.call('instance void %s::.ctor()' % self.get_base_class())
+        # set default values for fields
+        default_values = self.INSTANCE._fields.copy()
+        default_values.update(self.INSTANCE._overridden_defaults)
+        for f_name, (F_TYPE, f_default) in default_values.iteritems():
+            if getattr(F_TYPE, '_is_value_type', False):
+                continue # we can't set it to null
+            INSTANCE_DEF, _ = self.INSTANCE._lookup_field(f_name)
+            cts_type = self.cts.lltype_to_cts(F_TYPE)
+            f_name = self.cts.escape_name(f_name)
+            if cts_type != CTS.types.void:
+                self.ilasm.opcode('ldarg.0')
+                push_constant(self.db, F_TYPE, f_default, self.gen)
+                class_name = self.db.class_name(INSTANCE_DEF)
+                self.ilasm.set_field((cts_type, class_name, f_name))
+
+        self.ilasm.opcode('ret')
+        self.ilasm.end_function()
+
+    def _toString(self):
+        self.ilasm.begin_function('ToString', [], 'string', False, 'virtual', 'instance', 'default')
+        self.ilasm.opcode('ldarg.0')
+        self.ilasm.call('string class [pypylib]pypy.test.Result::InstanceToPython(object)')
+        self.ilasm.ret()
+        self.ilasm.end_function()
+

pypy/translator/cli/comparer.py

+import types
+from pypy.rpython.ootypesystem import ootype
+from pypy.translator.cli.cts import CTS
+from pypy.translator.cli.node import Node
+
+IEQUALITY_COMPARER = 'class [mscorlib]System.Collections.Generic.IEqualityComparer`1<%s>'
+
+class EqualityComparer(Node):
+    count = 0
+    
+    def __init__(self, db, KEY_TYPE, eq_args, hash_args):
+        self.db = db
+        self.cts = CTS(db)
+        self.KEY_TYPE = KEY_TYPE
+        self.key_type = self.cts.lltype_to_cts(KEY_TYPE)
+        self.eq_args = eq_args
+        self.hash_args = hash_args
+        self.name = 'EqualityComparer_%d' % EqualityComparer.count
+        EqualityComparer.count += 1
+
+    def get_ctor(self):
+        return 'instance void %s::.ctor()' % self.name
+
+    def render(self, ilasm):
+        self.ilasm = ilasm
+        IEqualityComparer = IEQUALITY_COMPARER % self.key_type
+        ilasm.begin_class(self.name, interfaces=[IEqualityComparer])
+        self._ctor()
+        self._method('Equals', [(self.key_type, 'x'), (self.key_type, 'y')],
+                     'bool', self.eq_args)
+        self._method('GetHashCode', [(self.key_type, 'x')], 'int32', self.hash_args)
+        ilasm.end_class()
+
+    def _ctor(self):
+        self.ilasm.begin_function('.ctor', [], 'void', False, 'specialname', 'rtspecialname', 'instance')
+        self.ilasm.opcode('ldarg.0')
+        self.ilasm.call('instance void [mscorlib]System.Object::.ctor()')
+        self.ilasm.opcode('ret')
+        self.ilasm.end_function()
+        
+    def _method(self, name, arglist, return_type, fn_args):
+        self.ilasm.begin_function(name, arglist, return_type, False,
+                                  'final', 'virtual', 'hidebysig', 'newslot',
+                                  'instance', 'default')
+
+        if type(fn_args) == types.FunctionType:
+            assert len(fn_args.self_arg) <= 1
+            if len(fn_args.self_arg) == 1:
+                assert fn_args.graph.getargs()[0].concretetype is ootype.Void
+            self._call_function(fn_args.graph, len(arglist))
+        else:
+            fn, obj, method_name = fn_args
+            # fn is a Constant(StaticMethod)
+            if method_name.value is None:
+                self._call_function(fn.value.graph, len(arglist))
+            else:
+                assert False, 'XXX'
+
+        self.ilasm.end_function()
+
+    def _call_function(self, graph, n_args):
+        self.db.pending_function(graph)
+        for arg in range(1, n_args+1):
+            self.ilasm.opcode('ldarg', arg)
+        signature = self.cts.graph_to_signature(graph)
+        self.ilasm.call(signature)
+        self.ilasm.opcode('ret')

pypy/translator/cli/conftest.py

+import py
+
+Option = py.test.config.Option
+
+option = py.test.config.addoptions\
+         ("pypy-cli options", 
+
+          Option('--source', action="store_true", dest="source", default=False,
+                 help="only generate IL source, don't compile"),
+
+          Option('--wd', action="store_true", dest="wd", default=False,
+                 help="store temporary files in the working directory"),
+
+          Option('--stdout', action="store_true", dest="stdout", default=False,
+                 help="print the generated IL code to stdout, too"),
+
+          Option('--nostop', action="store_true", dest="nostop", default=False,
+                 help="don't stop on warning. The generated IL code could not compile"),
+
+          Option('--nowrap', action="store_true", dest="nowrap", default=False,
+                 help="don't wrap exceptions but let them to flow out of the entry point"),
+
+          Option('--verify', action="store_true", dest="verify", default=False,
+                 help="check that compiled executables are verifiable"),
+
+          Option('--norun', action='store_true', dest="norun", default=False,
+                 help="don't run the compiled executable"),
+
+          Option('--trace', action='store_true', dest='trace', default=False,
+                 help='Trace execution of generated code'),
+          )
+
+
+

pypy/translator/cli/constant.py

+"""
+___________________________________________________________________________
+CLI Constants
+
+This module extends the oosupport/constant.py to be specific to the
+CLI.  Most of the code in this file is in the constant generators, which
+determine how constants are stored and loaded (static fields, lazy
+initialization, etc), but some constant classes have been overloaded or
+extended to allow for special handling.
+
+The CLI implementation is broken into three sections:
+
+* Constant Generators: different generators implementing different
+  techniques for loading constants (Static fields, singleton fields, etc)
+
+* Mixins: mixins are used to add a few CLI-specific methods to each
+  constant class.  Basically, any time I wanted to extend a base class
+  (such as AbstractConst or DictConst), I created a mixin, and then
+  mixed it in to each sub-class of that base-class.
+
+* Subclasses: here are the CLI specific classes.  Eventually, these
+  probably wouldn't need to exist at all (the JVM doesn't have any,
+  for example), or could simply have empty bodies and exist to
+  combine a mixin and the generic base class.  For now, though, they
+  contain the create_pointer() and initialize_data() routines.
+"""
+
+from pypy.translator.oosupport.constant import \
+     push_constant, WeakRefConst, StaticMethodConst, CustomDictConst, \
+     ListConst, ClassConst, InstanceConst, RecordConst, DictConst, \
+     BaseConstantGenerator, AbstractConst, ArrayConst
+from pypy.translator.cli.ilgenerator import CLIBaseGenerator
+from pypy.rpython.ootypesystem import ootype
+from pypy.translator.cli.comparer import EqualityComparer
+from pypy.rpython.lltypesystem import lltype
+from pypy.translator.cli.cts import PYPY_DICT_OF_VOID, WEAKREF
+
+CONST_NAMESPACE = 'pypy.runtime'
+CONST_CLASSNAME = 'Constants'
+CONST_CLASS = '%s.%s' % (CONST_NAMESPACE, CONST_CLASSNAME)
+
+DEBUG_CONST_INIT = False
+DEBUG_CONST_INIT_VERBOSE = False
+SERIALIZE = False
+
+# ______________________________________________________________________
+# Constant Generators
+#
+# Different generators implementing different techniques for loading
+# constants (Static fields, singleton fields, etc)
+
+class CLIBaseConstGenerator(BaseConstantGenerator):
+    """
+    Base of all CLI constant generators.  It implements the oosupport
+    constant generator in terms of the CLI interface.
+    """
+
+    def __init__(self, db):
+        BaseConstantGenerator.__init__(self, db)
+        self.cts = db.genoo.TypeSystem(db)
+
+    def _begin_gen_constants(self, ilasm, all_constants):
+        self.ilasm = ilasm
+        self.begin_class()
+        gen = CLIBaseGenerator(self.db, ilasm)
+        return gen
+
+    def _end_gen_constants(self, gen, numsteps):
+        assert gen.ilasm is self.ilasm
+        self.end_class()
+
+    def begin_class(self):
+        self.ilasm.begin_namespace(CONST_NAMESPACE)
+        self.ilasm.begin_class(CONST_CLASSNAME, beforefieldinit=True)
+
+    def end_class(self):
+        self.ilasm.end_class()
+        self.ilasm.end_namespace()
+
+    def _declare_const(self, gen, const):
+        self.ilasm.field(const.name, const.get_type(), static=True)
+
+    def downcast_constant(self, gen, const, EXPECTED_TYPE):
+        type = self.cts.lltype_to_cts(EXPECTED_TYPE)
+        gen.ilasm.opcode('castclass', type)
+ 
+    def _get_key_for_const(self, value):
+        if isinstance(value, ootype._view) and isinstance(value._inst, ootype._record):
+            return value._inst
+        return BaseConstantGenerator._get_key_for_const(self, value)
+
+    def _create_complex_const(self, value):
+        if isinstance(value, ootype._view) and isinstance(value._inst, ootype._record):
+            self.db.cts.lltype_to_cts(value._inst._TYPE) # record the type of the record
+            return self.record_const(value._inst)
+        else:
+            return BaseConstantGenerator._create_complex_const(self, value)
+
+class FieldConstGenerator(CLIBaseConstGenerator):
+    pass
+
+class StaticFieldConstGenerator(FieldConstGenerator):
+
+    # _________________________________________________________________
+    # OOSupport interface
+    
+    def push_constant(self, gen, const):
+        type_ = const.get_type()
+        gen.ilasm.load_static_constant(type_, CONST_NAMESPACE, CONST_CLASSNAME, const.name)
+        
+    def _push_constant_during_init(self, gen, const):
+        full_name = '%s::%s' % (CONST_CLASS, const.name)
+        gen.ilasm.opcode('ldsfld %s %s' % (const.get_type(), full_name))
+
+    def _store_constant(self, gen, const):
+        type_ = const.get_type()
+        gen.ilasm.store_static_constant(type_, CONST_NAMESPACE, CONST_CLASSNAME, const.name)
+
+    # _________________________________________________________________
+    # CLI interface
+
+    def _declare_step(self, gen, stepnum):
+        gen.ilasm.begin_function(
+            'step%d' % stepnum, [], 'void', False, 'static')
+
+    def _close_step(self, gen, stepnum):
+        gen.ilasm.ret()
+        gen.ilasm.end_function()
+
+    def _end_gen_constants(self, gen, numsteps):
+
+        self.ilasm.begin_function('.cctor', [], 'void', False, 'static',
+                                  'specialname', 'rtspecialname', 'default')
+        self.ilasm.stderr('CONST: initialization starts', DEBUG_CONST_INIT)
+        for i in range(numsteps):
+            self.ilasm.stderr('CONST: step %d of %d' % (i, numsteps),
+                              DEBUG_CONST_INIT)
+            step_name = 'step%d' % i
+            self.ilasm.call('void %s::%s()' % (CONST_CLASS, step_name))
+        self.ilasm.stderr('CONST: initialization completed', DEBUG_CONST_INIT)
+        self.ilasm.ret()
+        self.ilasm.end_function()
+
+        super(StaticFieldConstGenerator, self)._end_gen_constants(
+            gen, numsteps)
+
+class InstanceFieldConstGenerator(FieldConstGenerator):
+    
+    # _________________________________________________________________
+    # OOSupport interface
+    
+    def push_constant(self, gen, const):
+        # load the singleton instance
+        gen.ilasm.opcode('ldsfld class %s %s::Singleton' % (CONST_CLASS, CONST_CLASS))
+        gen.ilasm.opcode('ldfld %s %s::%s' % (const.get_type(), CONST_CLASS, const.name))
+
+    def _push_constant_during_init(self, gen, const):
+        # during initialization, we load the 'this' pointer from our
+        # argument rather than the singleton argument
+        gen.ilasm.opcode('ldarg.0')
+        gen.ilasm.opcode('ldfld %s %s::%s' % (const.get_type(), CONST_CLASS, const.name))
+
+    def _pre_store_constant(self, gen, const):
+        gen.ilasm.opcode('ldarg.0')
+        
+    def _store_constant(self, gen, const):
+        gen.ilasm.set_field((const.get_type(), CONST_CLASS, const.name))
+
+    # _________________________________________________________________
+    # CLI interface
+
+    def _declare_const(self, gen, all_constants):
+        gen.ilasm.field(const.name, const.get_type(), static=False)
+    
+    def _declare_step(self, gen, stepnum):
+        gen.ilasm.begin_function('step%d' % stepnum, [], 'void', False)
+
+    def _close_step(self, gen, stepnum):
+        gen.ilasm.ret()
+        gen.ilasm.end_function()
+
+    def _end_gen_constants(self, gen, numsteps):
+
+        ilasm = gen.ilasm
+
+        ilasm.begin_function('.ctor', [], 'void', False, 'specialname', 'rtspecialname', 'instance')
+        ilasm.opcode('ldarg.0')
+        ilasm.call('instance void object::.ctor()')
+
+        ilasm.opcode('ldarg.0')
+        ilasm.opcode('stsfld class %s %s::Singleton' % (CONST_CLASS, CONST_CLASS))
+        
+        for i in range(numsteps):
+            step_name = 'step%d' % i
+            ilasm.opcode('ldarg.0')
+            ilasm.call('instance void %s::%s()' % (CONST_CLASS, step_name))
+        ilasm.ret()
+        ilasm.end_function()
+
+        # declare&init the Singleton containing the constants
+        ilasm.field('Singleton', 'class %s' % CONST_CLASS, static=True)
+        ilasm.begin_function('.cctor', [], 'void', False, 'static', 'specialname', 'rtspecialname', 'default')
+        if SERIALIZE:
+            self._serialize_ctor()
+        else:
+            self._plain_ctor()
+        ilasm.end_function()
+
+        super(StaticFieldConstGenerator, self)._end_gen_constants(gen, numsteps)
+
+    def _plain_ctor(self):
+        self.ilasm.new('instance void class %s::.ctor()' % CONST_CLASS)
+        self.ilasm.pop()
+        self.ilasm.ret()
+
+    def _serialize_ctor(self):
+        self.ilasm.opcode('ldstr "constants.dat"')
+        self.ilasm.call('object [pypylib]pypy.runtime.Utils::Deserialize(string)')
+        self.ilasm.opcode('dup')
+        self.ilasm.opcode('brfalse initialize')
+        self.ilasm.stderr('Constants deserialized successfully')        
+        self.ilasm.opcode('stsfld class %s %s::Singleton' % (CONST_CLASS, CONST_CLASS))
+        self.ilasm.ret()
+        self.ilasm.label('initialize')
+        self.ilasm.pop()
+        self.ilasm.stderr('Cannot deserialize constants... initialize them!')
+        self.ilasm.new('instance void class %s::.ctor()' % CONST_CLASS)
+        self.ilasm.opcode('ldstr "constants.dat"')
+        self.ilasm.call('void [pypylib]pypy.runtime.Utils::Serialize(object, string)')
+        self.ilasm.ret()
+
+class LazyConstGenerator(StaticFieldConstGenerator):
+    def push_constant(self, ilasm, const):
+        getter_name = '%s::%s' % (CONST_CLASS, 'get_%s' % const.name)
+        ilasm.call('%s %s()' % (const.get_type(), getter_name))
+
+    def _create_pointers(self, gen, all_constants):
+        # overload to do nothing since we handle everything in lazy fashion
+        pass
+
+    def _initialize_data(self, gen, all_constants):
+        # overload to do nothing since we handle everything in lazy fashion
+        pass
+
+    def _declare_const(self, gen, const):
+        # Declare the field
+        super(LazyConstGenerator, self)._declare_const(gen, const)
+
+        # Create the method for accessing the field
+        getter_name = 'get_%s' % const.name
+        type_ = const.get_type()
+        self.ilasm.begin_function(getter_name, [], type_, False, 'static')
+        self.ilasm.load_static_constant(type_, CONST_NAMESPACE, CONST_CLASS, const.name)
+        # if it's already initialized, just return it
+        self.ilasm.opcode('dup')
+        self.ilasm.opcode('brfalse', 'initialize')
+        self.ilasm.opcode('ret')
+        # else, initialize!
+        self.ilasm.label('initialize')
+        self.ilasm.opcode('pop') # discard the null value we know is on the stack
+        const.instantiate(ilasm)
+        self.ilasm.opcode('dup') # two dups because const.init pops the value at the end
+        self.ilasm.opcode('dup')
+        self.ilasm.store_static_constant(type_, CONST_NAMESPACE, CONST_CLASS, const.name)
+        const.init(ilasm)
+        self.ilasm.opcode('ret')
+        self.ilasm.end_function()
+
+# ______________________________________________________________________
+# Mixins
+#
+# Mixins are used to add a few CLI-specific methods to each constant
+# class.  Basically, any time I wanted to extend a base class (such as
+# AbstractConst or DictConst), I created a mixin, and then mixed it in
+# to each sub-class of that base-class.  Kind of awkward.
+
+class CLIBaseConstMixin(object):
+    """ A mix-in with a few extra methods the CLI backend uses """
+    
+    def get_type(self):
+        """ Returns the CLI type for this constant's representation """
+        return self.cts.lltype_to_cts(self.value._TYPE)
+    
+    def push_inline(self, gen, TYPE):
+        """ Overload the oosupport version so that we use the CLI opcode
+        for pushing NULL """
+        assert self.is_null()
+        gen.ilasm.opcode('ldnull')
+
+class CLIDictMixin(CLIBaseConstMixin):
+    def _check_for_void_dict(self, gen):
+        KEYTYPE = self.value._TYPE._KEYTYPE
+        keytype = self.cts.lltype_to_cts(KEYTYPE)
+        keytype_T = self.cts.lltype_to_cts(self.value._TYPE.KEYTYPE_T)
+        VALUETYPE = self.value._TYPE._VALUETYPE
+        valuetype = self.cts.lltype_to_cts(VALUETYPE)
+        valuetype_T = self.cts.lltype_to_cts(self.value._TYPE.VALUETYPE_T)
+        if VALUETYPE is ootype.Void:
+            gen.add_comment('  CLI Dictionary w/ void value')
+            class_name = PYPY_DICT_OF_VOID % keytype
+            for key in self.value._dict:
+                gen.ilasm.opcode('dup')
+                push_constant(self.db, KEYTYPE, key, gen)
+                meth = 'void class %s::ll_set(%s)' % (class_name, keytype_T)
+                gen.ilasm.call_method(meth, False)
+            return True
+        return False
+    
+    def initialize_data(self, constgen, gen):
+        # special case: dict of void, ignore the values
+        if self._check_for_void_dict(gen):
+            return 
+        return super(CLIDictMixin, self).initialize_data(constgen, gen)
+
+# ______________________________________________________________________
+# Constant Classes
+#
+# Here we overload a few methods, and mix in the base classes above.
+# Note that the mix-ins go first so that they overload methods where
+# required.
+#
+# Eventually, these probably wouldn't need to exist at all (the JVM
+# doesn't have any, for example), or could simply have empty bodies
+# and exist to combine a mixin and the generic base class.  For now,
+# though, they contain the create_pointer() and initialize_data()
+# routines.  In order to get rid of them, we would need to implement
+# the generator interface in the CLI.
+
+class CLIRecordConst(CLIBaseConstMixin, RecordConst):
+    def create_pointer(self, gen):
+        self.db.const_count.inc('Record')
+        super(CLIRecordConst, self).create_pointer(gen)
+
+class CLIInstanceConst(CLIBaseConstMixin, InstanceConst):
+    def create_pointer(self, gen):
+        self.db.const_count.inc('Instance')
+        self.db.const_count.inc('Instance', self.OOTYPE())
+        super(CLIInstanceConst, self).create_pointer(gen)
+
+
+class CLIClassConst(CLIBaseConstMixin, ClassConst):
+    def is_inline(self):
+        return True
+
+    def push_inline(self, gen, EXPECTED_TYPE):
+        if not self.is_null():
+            if hasattr(self.value, '_FUNC'):
+                FUNC = self.value._FUNC
+                classname = self.db.record_delegate(FUNC)
+            else:
+                TYPE = self.value._INSTANCE
+                classname = self.db.class_or_record_name(TYPE)
+            gen.ilasm.opcode('ldtoken', classname)
+            gen.ilasm.call('class [mscorlib]System.Type class [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle)')
+            return
+        super(CLIClassConst, self).push_inline(gen, EXPECTED_TYPE)
+
+class CLIListConst(CLIBaseConstMixin, ListConst):
+
+    def _do_not_initialize(self):
+        # Check if it is a list of all zeroes:
+        try:
+            if self.value._list == [0] * len(self.value._list):
+                return True
+        except:
+            pass
+        return super(CLIListConst, self)._do_not_initialize()
+    
+    def create_pointer(self, gen):
+        self.db.const_count.inc('List')
+        self.db.const_count.inc('List', self.value._TYPE.ITEM)
+        self.db.const_count.inc('List', len(self.value._list))
+        super(CLIListConst, self).create_pointer(gen)
+
+
+class CLIArrayConst(CLIBaseConstMixin, ArrayConst):
+
+    def _do_not_initialize(self):
+        # Check if it is an array of all zeroes:
+        try:
+            if self.value._list == [0] * len(self.value._list):
+                return True
+        except:
+            pass
+        return super(CLIArrayConst, self)._do_not_initialize()
+
+    def _setitem(self, SELFTYPE, gen):
+        gen.array_setitem(SELFTYPE)
+
+
+class CLIDictConst(CLIDictMixin, DictConst):
+    def create_pointer(self, gen):
+        self.db.const_count.inc('Dict')
+        self.db.const_count.inc('Dict', self.value._TYPE._KEYTYPE, self.value._TYPE._VALUETYPE)
+        super(CLIDictConst, self).create_pointer(gen)        
+        
+class CLICustomDictConst(CLIDictMixin, CustomDictConst):
+    def record_dependencies(self):
+        if not self.value:
+            return
+        eq = self.value._dict.key_eq
+        hash = self.value._dict.key_hash
+        self.comparer = EqualityComparer(self.db, self.value._TYPE._KEYTYPE, eq, hash)
+        self.db.pending_node(self.comparer)
+        super(CLICustomDictConst, self).record_dependencies()
+
+    def create_pointer(self, gen):
+        assert not self.is_null()
+        gen.ilasm.new(self.comparer.get_ctor())
+        class_name = self.get_type()
+        gen.ilasm.new('instance void %s::.ctor(class '
+                      '[mscorlib]System.Collections.Generic.IEqualityComparer`1<!0>)'
+                  % class_name)
+        self.db.const_count.inc('CustomDict')
+        self.db.const_count.inc('CustomDict', self.value._TYPE._KEYTYPE, self.value._TYPE._VALUETYPE)
+
+class CLIStaticMethodConst(CLIBaseConstMixin, StaticMethodConst):
+    def create_pointer(self, gen):
+        assert not self.is_null()
+        signature = self.cts.graph_to_signature(self.value.graph)
+        gen.ilasm.opcode('ldnull')
+        gen.ilasm.opcode('ldftn', signature)
+        gen.ilasm.new('instance void class %s::.ctor(object, native int)' % self.delegate_type)
+        self.db.const_count.inc('StaticMethod')
+        
+    def initialize_data(self, constgen, gen):
+        return
+
+        
+class CLIWeakRefConst(CLIBaseConstMixin, WeakRefConst):
+    def create_pointer(self, gen):
+        gen.ilasm.new('instance void %s::.ctor()' % self.get_type())
+        self.db.const_count.inc('WeakRef')
+
+    def get_type(self, include_class=True):
+        return 'class ' + WEAKREF
+    
+    def initialize_data(self, constgen, gen):
+        if self.value is not None:
+            push_constant(self.db, self.value._TYPE, self.value, gen)
+            gen.ilasm.call_method('void %s::ll_set(object)' % self.get_type(), True)
+            return True
+    

pypy/translator/cli/cts.py

+"""
+Translate between PyPy ootypesystem and .NET Common Type System
+"""
+
+import exceptions
+
+from py.builtin import set
+from pypy.rpython.lltypesystem import lltype
+from pypy.rpython.ootypesystem import ootype
+from pypy.translator.cli.option import getoption
+from pypy.translator.cli import oopspec
+
+from pypy.tool.ansi_print import ansi_log
+import py
+log = py.log.Producer("cli") 
+py.log.setconsumer("cli", ansi_log) 
+
+class CliType(object):
+    def typename(self):
+        raise NotImplementedError
+
+    def __str__(self):
+        return self.typename()
+
+    def __hash__(self):
+        return hash(self.typename())
+
+    def __eq__(self, other):
+        return self.typename() == other.typename()
+
+    def __ne__(self, other):
+        return self.typename() != other.typename()
+
+
+class CliPrimitiveType(CliType):
+    def __init__(self, name):
+        self.name = name
+
+    def typename(self):
+        return self.name
+
+
+class CliReferenceType(CliType):
+    prefix = 'class '
+    
+    def typename(self):
+        return self.prefix + self.classname()
+
+    def classname(self):
+        raise NotImplementedError
+
+class CliClassType(CliReferenceType):
+    def __init__(self, assembly, name):
+        self.assembly = assembly
+        self.name = name
+
+    def classname(self):
+        if self.assembly:
+            return '[%s]%s' % (self.assembly, self.name)
+        else:
+            return self.name
+
+class CliValueType(CliClassType):
+    prefix = 'valuetype '
+
+
+class CliGenericType(CliReferenceType):
+    def __init__(self, assembly, name, numparam):
+        self.assembly = assembly
+        self.name = name
+        self.numparam = numparam
+
+    def classname(self):
+        paramtypes = [self.paramtype(i) for i in range(self.numparam)]
+        thistype = self.specialize(*paramtypes)
+        return thistype.classname()
+
+    def specialize(self, *types):
+        assert len(types) == self.numparam
+        return CliSpecializedType(self, types)
+
+    def paramtype(self, num):
+        assert 0 <= num < self.numparam
+        return CliPrimitiveType('!%d' % num)
+
+class CliSpecializedType(CliReferenceType):
+    def __init__(self, generic_type, arg_types):
+        self.generic_type = generic_type
+        self.arg_types = arg_types
+
+    def classname(self):
+        assembly = self.generic_type.assembly
+        name = self.generic_type.name
+        numparam = self.generic_type.numparam
+        arglist = ', '.join([arg.typename() for arg in self.arg_types])
+        return '[%s]%s`%d<%s>' % (assembly, name, numparam, arglist)
+
+class CliArrayType(CliType):
+
+    def __init__(self, itemtype):
+        self.itemtype = itemtype
+
+    def typename(self):
+        return '%s[]' % self.itemtype.typename()
+
+
+T = CliPrimitiveType
+class types:
+    void =    T('void')
+    int32 =   T('int32')
+    uint32 =  T('unsigned int32')
+    int64 =   T('int64')
+    uint64 =  T('unsigned int64')
+    bool =    T('bool')
+    float64 = T('float64')
+    char =    T('char')
+    string =  T('string')
+
+    weakref = CliClassType('pypylib', 'pypy.runtime.WeakReference')
+    type = CliClassType('mscorlib', 'System.Type')
+    object = CliClassType('mscorlib', 'System.Object')
+    list = CliGenericType('pypylib', 'pypy.runtime.List', 1)
+    list_of_void = CliClassType('pypylib', 'pypy.runtime.ListOfVoid')
+    dict = CliGenericType('pypylib', 'pypy.runtime.Dict', 2)
+    dict_void_void = CliClassType('pypylib', 'pypy.runtime.DictVoidVoid')
+    dict_items_iterator = CliGenericType('pypylib', 'pypy.runtime.DictItemsIterator', 2)
+    string_builder = CliClassType('pypylib', 'pypy.runtime.StringBuilder')
+del T
+
+WEAKREF = types.weakref.classname()
+PYPY_DICT_OF_VOID = '[pypylib]pypy.runtime.DictOfVoid`2<%s, int32>'
+PYPY_DICT_OF_VOID_KEY = '[pypylib]pypy.runtime.DictOfVoidKey`2<int32, %s>'
+
+
+_lltype_to_cts = {
+    ootype.Void: types.void,
+    ootype.Signed: types.int32,    
+    ootype.Unsigned: types.uint32,
+    ootype.SignedLongLong: types.int64,
+    ootype.UnsignedLongLong: types.uint64,
+    ootype.Bool: types.bool,
+    ootype.Float: types.float64,
+    ootype.Char: types.char,
+    ootype.UniChar: types.char,
+    ootype.Class: types.type,
+    ootype.String: types.string,
+    ootype.StringBuilder: types.string_builder,
+    ootype.Unicode: types.string,
+    ootype.UnicodeBuilder: types.string_builder,
+    ootype.WeakReference: types.weakref,
+    ootype.Object: types.object,
+
+    # maps generic types to their ordinal
+    ootype.List.SELFTYPE_T: types.list,
+    ootype.List.ITEMTYPE_T: types.list.paramtype(0),
+    ootype.Dict.SELFTYPE_T: types.dict,
+    ootype.Dict.KEYTYPE_T: types.dict.paramtype(0),
+    ootype.Dict.VALUETYPE_T: types.dict.paramtype(1),
+    ootype.DictItemsIterator.SELFTYPE_T: types.dict_items_iterator,
+    ootype.DictItemsIterator.KEYTYPE_T: types.dict_items_iterator.paramtype(0),
+    ootype.DictItemsIterator.VALUETYPE_T: types.dict_items_iterator.paramtype(1),
+    }
+
+
+def _get_from_dict(d, key, error):
+    try:
+        return d[key]
+    except KeyError:
+        if getoption('nostop'):
+            log.WARNING(error)
+            return key
+        else:
+            assert False, error
+
+class CTS(object):
+
+    ILASM_KEYWORDS = set(["at", "as", "implicitcom", "implicitres",
+    "noappdomain", "noprocess", "nomachine", "extern", "instance",
+    "explicit", "default", "vararg", "unmanaged", "cdecl", "stdcall",
+    "thiscall", "fastcall", "marshal", "in", "out", "opt", "retval",
+    "static", "public", "private", "family", "initonly",
+    "rtspecialname", "specialname", "assembly", "famandassem",
+    "famorassem", "privatescope", "literal", "notserialized", "value",
+    "not_in_gc_heap", "interface", "sealed", "abstract", "auto",
+    "sequential", "ansi", "unicode", "autochar", "bestfit",
+    "charmaperror", "import", "serializable", "nested", "lateinit",
+    "extends", "implements", "final", "virtual", "hidebysig",
+    "newslot", "unmanagedexp", "pinvokeimpl", "nomangle", "ole",
+    "lasterr", "winapi", "native", "il", "cil", "optil", "managed",
+    "forwardref", "runtime", "internalcall", "synchronized",
+    "noinlining", "custom", "fixed", "sysstring", "array", "variant",
+    "currency", "syschar", "void", "bool", "int8", "int16", "int32",
+    "int64", "float32", "float64", "error", "unsigned", "uint",
+    "uint8", "uint16", "uint32", "uint64", "decimal", "date", "bstr",
+    "lpstr", "lpwstr", "lptstr", "objectref", "iunknown", "idispatch",
+    "struct", "safearray", "int", "byvalstr", "tbstr", "lpvoid",
+    "any", "float", "lpstruct", "null", "ptr", "vector", "hresult",
+    "carray", "userdefined", "record", "filetime", "blob", "stream",
+    "storage", "streamed_object", "stored_object", "blob_object",
+    "cf", "clsid", "method", "class", "pinned", "modreq", "modopt",
+    "typedref", "type","refany", "wchar", "char", "fromunmanaged",
+    "callmostderived", "bytearray", "with", "init", "to", "catch",
+    "filter", "finally", "fault", "handler", "tls", "field",
+    "request", "demand", "assert", "deny", "permitonly", "linkcheck",
+    "inheritcheck", "reqmin", "reqopt", "reqrefuse", "prejitgrant",
+    "prejitdeny", "noncasdemand", "noncaslinkdemand",
+    "noncasinheritance", "readonly", "nometadata", "algorithm",
+    "fullorigin", "nan", "inf", "publickey", "enablejittracking",
+    "disablejitoptimizer", "preservesig", "beforefieldinit",
+    "alignment", "nullref", "valuetype", "compilercontrolled",
+    "reqsecobj", "enum", "object", "string", "true", "false", "is",
+    "on", "off", "add", "and", "arglist", "beq", "bge", "bgt", "ble",
+    "blt", "bne", "box", "br", "break", "brfalse", "brnull", "brtrue",
+    "call", "calli", "callvirt", "castclass", "ceq", "cgt",
+    "ckfinite", "clt", "conf", "constrained", "conv", "cpblk",
+    "cpobj", "div", "dup", "endfault", "endfilter", "endfinally",
+    "initblk", "initobj", "isinst", "jmp", "ldarg", "ldarga", "ldc",
+    "ldelem", "ldelema", "ldfld", "ldflda", "ldftn", "ldind", "ldlen",
+    "ldloc", "ldloca", "ldnull", "ldobj", "ldsfld", "ldsflda",
+    "ldstr", "ldtoken", "ldvirtftn", "leave", "localloc", "mkrefany",
+    "mul", "neg", "newarr", "newobj", "nop", "not", "or", "pop",
+    "readonly", "refanytype", "refanyval", "rem", "ret", "rethrow",
+    "shl", "shr", "sizeof", "starg", "stelem", "stfld", "stind",
+    "stloc", "stobj", "stsfld", "sub", "switch", "tail", "throw",
+    "unaligned", "unbox", "volatile", "xor", "ole"])
+    # ole is not a keyword, but mono ilasm fails if you use it as a field/method name
+
+    types = types # for convenience
+
+    def __init__(self, db):
+        self.db = db
+
+    def escape_name(self, name):
+        """Mangle then name if it's a ilasm reserved word"""
+        if name in self.ILASM_KEYWORDS:
+            return "'%s'" % name
+        else:
+            return name
+
+    def lltype_to_cts(self, t):
+        if t is ootype.ROOT:
+            return types.object
+        elif isinstance(t, lltype.Ptr) and isinstance(t.TO, lltype.OpaqueType):
+            return types.object
+        elif isinstance(t, ootype.Instance):
+            if getattr(t, '_is_value_type', False):
+                cls = CliValueType
+            else:
+                cls = CliClassType
+            NATIVE_INSTANCE = t._hints.get('NATIVE_INSTANCE', None)
+            if NATIVE_INSTANCE:
+                return cls(None, NATIVE_INSTANCE._name)
+            else:
+                name = self.db.pending_class(t)
+                return cls(None, name)
+        elif isinstance(t, ootype.Record):
+            name = self.db.pending_record(t)
+            return CliClassType(None, name)
+        elif isinstance(t, ootype.StaticMethod):
+            delegate = self.db.record_delegate(t)
+            return CliClassType(None, delegate)
+        elif isinstance(t, ootype.Array):
+            item_type = self.lltype_to_cts(t.ITEM)
+            if item_type == types.void: # special case: Array of Void
+                return types.list_of_void
+            return CliArrayType(item_type)
+        elif isinstance(t, ootype.List):
+            item_type = self.lltype_to_cts(t.ITEM)
+            if item_type == types.void: # special case: List of Void
+                return types.list_of_void
+            return types.list.specialize(item_type)
+        elif isinstance(t, ootype.Dict):
+            key_type = self.lltype_to_cts(t._KEYTYPE)
+            value_type = self.lltype_to_cts(t._VALUETYPE)
+            if value_type == types.void: # special cases: Dict with voids
+                if key_type == types.void:
+                    return types.dict_void_void
+                else:
+                    # XXX
+                    return CliClassType(None, PYPY_DICT_OF_VOID % key_type)
+            elif key_type == types.void:
+                assert value_type != types.void
+                return CliClassType(None, PYPY_DICT_OF_VOID_KEY % value_type)
+            return types.dict.specialize(key_type, value_type)
+        elif isinstance(t, ootype.DictItemsIterator):
+            key_type = self.lltype_to_cts(t._KEYTYPE)
+            value_type = self.lltype_to_cts(t._VALUETYPE)
+            if key_type == types.void:
+                key_type = types.int32 # placeholder
+            if value_type == types.void:
+                value_type = types.int32 # placeholder
+            return types.dict_items_iterator.specialize(key_type, value_type)
+
+        return _get_from_dict(_lltype_to_cts, t, 'Unknown type %s' % t)
+
+    def llvar_to_cts(self, var):
+        return self.lltype_to_cts(var.concretetype), var.name
+
+    def llconst_to_cts(self, const):
+        return self.lltype_to_cts(const.concretetype), const.value
+
+    def ctor_name(self, t):
+        return 'instance void %s::.ctor()' % self.lltype_to_cts(t)
+
+    def graph_to_signature(self, graph, is_method = False, func_name = None):
+        ret_type, ret_var = self.llvar_to_cts(graph.getreturnvar())
+        func_name = func_name or graph.name
+        func_name = self.escape_name(func_name)
+        namespace = getattr(graph.func, '_namespace_', None)
+        if namespace:
+            func_name = '%s::%s' % (namespace, func_name)
+
+        args = [arg for arg in graph.getargs() if arg.concretetype is not ootype.Void]
+        if is_method:
+            args = args[1:]
+
+        arg_types = [self.lltype_to_cts(arg.concretetype).typename() for arg in args]
+        arg_list = ', '.join(arg_types)
+
+        return '%s %s(%s)' % (ret_type, func_name, arg_list)
+
+    def op_to_signature(self, op, func_name):
+        ret_type, ret_var = self.llvar_to_cts(op.result)
+        func_name = self.escape_name(func_name)
+
+        args = [arg for arg in op.args[1:]
+                    if arg.concretetype is not ootype.Void]
+
+        arg_types = [self.lltype_to_cts(arg.concretetype).typename() for arg in args]
+        arg_list = ', '.join(arg_types)
+
+        return '%s %s(%s)' % (ret_type, func_name, arg_list)
+
+
+    def method_signature(self, TYPE, name_or_desc):
+        # TODO: use callvirt only when strictly necessary
+        if isinstance(TYPE, ootype.Instance):
+            if isinstance(name_or_desc, ootype._overloaded_meth_desc):
+                name = name_or_desc.name
+                METH = name_or_desc.TYPE
+                virtual = True
+            else:
+                name = name_or_desc
+                owner, meth = TYPE._lookup(name)
+                METH = meth._TYPE
+                virtual = getattr(meth, '_virtual', True)
+            class_name = self.db.class_name(TYPE)
+            full_name = 'class %s::%s' % (class_name, self.escape_name(name))
+            returntype = self.lltype_to_cts(METH.RESULT)
+            arg_types = [self.lltype_to_cts(ARG).typename() for ARG in METH.ARGS if ARG is not ootype.Void]
+            arg_list = ', '.join(arg_types)
+            return '%s %s(%s)' % (returntype, full_name, arg_list), virtual
+
+        elif isinstance(TYPE, (ootype.BuiltinType, ootype.StaticMethod)):
+            assert isinstance(name_or_desc, str)
+            name = name_or_desc
+            if isinstance(TYPE, ootype.StaticMethod):
+                METH = TYPE
+            else:
+                METH = oopspec.get_method(TYPE, name)
+            class_name = self.lltype_to_cts(TYPE)
+            if isinstance(TYPE, ootype.Dict):
+                KEY = TYPE._KEYTYPE
+                VALUE = TYPE._VALUETYPE
+                name = name_or_desc
+                if KEY is ootype.Void and VALUE is ootype.Void and name == 'll_get_items_iterator':
+                    # ugly, ugly special case
+                    ret_type = types.dict_items_iterator.specialize(types.int32, types.int32)
+                elif VALUE is ootype.Void and METH.RESULT is ootype.Dict.VALUETYPE_T:
+                    ret_type = types.void
+                else:
+                    ret_type = self.lltype_to_cts(METH.RESULT)
+                    ret_type = dict_of_void_ll_copy_hack(TYPE, ret_type)
+            else:
+                ret_type = self.lltype_to_cts(METH.RESULT)
+            generic_types = getattr(TYPE, '_generic_types', {})
+            arg_types = [self.lltype_to_cts(arg).typename() for arg in METH.ARGS if
+                         arg is not ootype.Void and \
+                         generic_types.get(arg, arg) is not ootype.Void]
+            arg_list = ', '.join(arg_types)
+            return '%s %s::%s(%s)' % (ret_type, class_name, name, arg_list), False
+
+        else:
+            assert False
+
+def dict_of_void_ll_copy_hack(TYPE, ret_type):
+    # XXX: ugly hack to make the ll_copy signature correct when
+    # CustomDict is special-cased to DictOfVoid.
+    if isinstance(TYPE, ootype.CustomDict) and TYPE._VALUETYPE is ootype.Void:
+        return ret_type.typename().replace('Dict`2', 'DictOfVoid`2')
+    else:
+        return ret_type

pypy/translator/cli/database.py

+import operator
+import string
+from pypy.translator.cli.function import Function, log
+from pypy.translator.cli.class_ import Class
+from pypy.translator.cli.record import Record
+from pypy.translator.cli.delegate import Delegate
+from pypy.translator.cli.comparer import EqualityComparer
+from pypy.translator.cli.node import Node
+from pypy.translator.cli.support import string_literal, Counter
+from pypy.rpython.ootypesystem import ootype
+from pypy.rpython.ootypesystem.module import ll_os
+from pypy.translator.cli.opcodes import opcodes
+from pypy.translator.cli import dotnet
+from pypy.rlib.objectmodel import CDefinedIntSymbolic
+from pypy.translator.oosupport.database import Database as OODatabase
+
+try:
+    set
+except NameError:
+    from sets import Set as set
+
+BUILTIN_RECORDS = {
+    ootype.Record({"item0": ootype.Signed, "item1": ootype.Signed}):
+    '[pypylib]pypy.runtime.Record_Signed_Signed',
+    
+    ootype.Record({"item0": ootype.Float, "item1": ootype.Signed}):
+    '[pypylib]pypy.runtime.Record_Float_Signed',
+    
+    ootype.Record({"item0": ootype.Float, "item1": ootype.Float}):
+    '[pypylib]pypy.runtime.Record_Float_Float',
+
+    ootype.Record({"item0": ootype.String, "item1": ootype.String}):
+    '[pypylib]pypy.runtime.Record_String_String',
+
+    ll_os.STAT_RESULT: '[pypylib]pypy.runtime.Record_Stat_Result',
+    }
+
+class LowLevelDatabase(OODatabase):
+    def __init__(self, genoo):
+        OODatabase.__init__(self, genoo)
+        self.classes = {} # INSTANCE --> class_name
+        self.classnames = set() # (namespace, name)
+        self.recordnames = {} # RECORD --> name
+        self.functions = {} # graph --> function_name
+        self.methods = {} # graph --> method_name
+        self.consts = {}  # value --> AbstractConst
+        self.delegates = {} # StaticMethod --> type_name
+        self.const_count = Counter() # store statistics about constants
+
+    def next_count(self):
+        return self.unique()
+
+    def _default_record_name(self, RECORD):
+        trans = string.maketrans('[]<>(), :', '_________')
+        name = ['Record']
+        # XXX: refactor this: we need a proper way to ensure unique names
+        for f_name, (FIELD_TYPE, f_default) in RECORD._fields.iteritems():
+            type_name = FIELD_TYPE._short_name().translate(trans)
+            name.append(f_name)
+            name.append(type_name)
+            
+        return '__'.join(name)
+
+    def _default_class_name(self, INSTANCE):
+        parts = INSTANCE._name.rsplit('.', 1)
+        if len(parts) == 2:
+            return parts
+        else:
+            return None, parts[0]
+
+    def pending_function(self, graph, functype=None):
+        if functype is None:
+            function = self.genoo.Function(self, graph)
+        else:
+            function = functype(self, graph)
+        self.pending_node(function)
+        return function.get_name()
+
+    def pending_class(self, INSTANCE):
+        try:
+            return self.classes[INSTANCE]
+        except KeyError:
+            pass
+        
+        if isinstance(INSTANCE, dotnet.NativeInstance):
+            self.classes[INSTANCE] = INSTANCE._name
+            return INSTANCE._name
+        else:
+            namespace, name = self._default_class_name(INSTANCE)
+            name = self.get_unique_class_name(namespace, name)
+            if namespace is None:
+                full_name = name
+            else:
+                full_name = '%s.%s' % (namespace, name)
+            self.classes[INSTANCE] = full_name
+            cls = Class(self, INSTANCE, namespace, name)
+            self.pending_node(cls)
+            return full_name
+
+    def pending_record(self, RECORD):
+        try:
+            return BUILTIN_RECORDS[RECORD]
+        except KeyError:
+            pass
+        try:
+            return self.recordnames[RECORD]
+        except KeyError:
+            pass
+        name = self._default_record_name(RECORD)
+        name = self.get_unique_class_name(None, name)
+        self.recordnames[RECORD] = name
+        r = Record(self, RECORD, name)
+        self.pending_node(r)
+        return name
+
+    def record_function(self, graph, name):
+        self.functions[graph] = name
+
+    def graph_name(self, graph):
+        # XXX: graph name are not guaranteed to be unique
+        return self.functions.get(graph, None)
+
+    def get_unique_class_name(self, namespace, name):
+        base_name = name
+        i = 0
+        while (namespace, name) in self.classnames:
+            name = '%s_%d' % (base_name, i)
+            i+= 1
+        self.classnames.add((namespace, name))            
+        return name
+
+    def class_or_record_name(self, TYPE):
+        if TYPE is not ootype.ROOT and isinstance(TYPE, ootype.Instance):
+            return self.class_name(TYPE)
+        elif isinstance(TYPE, ootype.Record):
+            return self.get_record_name(TYPE)
+        elif isinstance(TYPE, ootype.OOType):
+            return self.cts.lltype_to_cts(TYPE)
+        else:
+            assert False
+
+    def class_name(self, INSTANCE):
+        try:
+            NATIVE_INSTANCE = INSTANCE._hints['NATIVE_INSTANCE']
+            return NATIVE_INSTANCE._name
+        except KeyError:
+            return self.classes[INSTANCE]
+
+    def get_record_name(self, RECORD):
+        try:
+            return BUILTIN_RECORDS[RECORD]
+        except KeyError:
+            return self.recordnames[RECORD]
+
+    def record_delegate(self, TYPE):
+        try:
+            return self.delegates[TYPE]
+        except KeyError:
+            name = 'StaticMethod__%d' % len(self.delegates)
+            self.delegates[TYPE] = name
+            self.pending_node(Delegate(self, TYPE, name))
+            return name

pypy/translator/cli/delegate.py

+from pypy.rpython.ootypesystem import ootype
+from pypy.translator.cli.cts import CTS
+from pypy.translator.cli.node import Node
+
+class Delegate(Node):
+    def __init__(self, db, TYPE, name):
+        self.cts = CTS(db)        
+        self.TYPE = TYPE
+        self.name = name
+
+    def __eq__(self, other):
+        return self.TYPE == other.TYPE
+
+    def __ne__(self, other):
+        return not self == other
+
+    def __hash__(self):
+        return hash(self.TYPE)
+
+    def get_name(self):
+        return self.name
+
+    def dependencies(self):
+        # record we know about result and argument types
+        self.cts.lltype_to_cts(self.TYPE.RESULT)
+        for ARG in self.TYPE.ARGS:
+            self.cts.lltype_to_cts(ARG)
+
+
+    def render(self, ilasm):
+        TYPE = self.TYPE
+        ilasm.begin_class(self.name, '[mscorlib]System.MulticastDelegate', sealed=True)
+        ilasm.begin_function('.ctor',
+                             [('object', "'object'"), ('native int', "'method'")],
+                             'void',
+                             False,
+                             'hidebysig', 'specialname', 'rtspecialname', 'instance', 'default',
+                             runtime=True)
+        ilasm.end_function()
+
+        resulttype = self.cts.lltype_to_cts(TYPE.RESULT)
+        arglist = [(self.cts.lltype_to_cts(ARG), '') for ARG in TYPE.ARGS if ARG is not ootype.Void]
+        ilasm.begin_function('Invoke', arglist, resulttype, False,
+                             'virtual', 'hidebysig', 'instance', 'default',
+                             runtime=True)
+        ilasm.end_function()
+        ilasm.end_class()

pypy/translator/cli/dotnet.py

+import types
+
+from pypy.tool.pairtype import pair, pairtype
+from pypy.annotation.model import SomeObject, SomeInstance, SomeOOInstance, SomeInteger, s_None,\
+     s_ImpossibleValue, lltype_to_annotation, annotation_to_lltype, SomeChar, SomeString, SomeOOStaticMeth
+from pypy.annotation.unaryop import immutablevalue
+from pypy.annotation.binaryop import _make_none_union
+from pypy.annotation import model as annmodel
+from pypy.rlib.rarithmetic import r_uint, r_longlong, r_ulonglong
+from pypy.rpython.error import TyperError
+from pypy.rpython.extregistry import ExtRegistryEntry
+from pypy.rpython.rmodel import Repr
+from pypy.rpython.rint import IntegerRepr
+from pypy.rpython.ootypesystem.rootype import OOInstanceRepr
+from pypy.rpython.ootypesystem import ootype
+from pypy.rpython.ootypesystem.ootype import meth, overload, Meth, StaticMethod
+from pypy.translator.cli.support import PythonNet
+
+## Annotation model
+
+class SomeCliClass(SomeObject):
+    def getattr(self, s_attr):
+        assert self.is_constant()
+        assert s_attr.is_constant()
+        cliclass = self.const
+        attrname = s_attr.const
+        if attrname in cliclass._static_fields:
+            TYPE = cliclass._static_fields[attrname]
+            return OverloadingResolver.lltype_to_annotation(TYPE)
+        elif attrname in cliclass._static_methods:
+            return SomeCliStaticMethod(cliclass, attrname)
+        else:
+            return s_ImpossibleValue
+
+    def setattr(self, s_attr, s_value):
+        assert self.is_constant()
+        assert s_attr.is_constant
+        cliclass = self.const
+        attrname = s_attr.const
+        if attrname not in cliclass._static_fields:
+            return s_ImpossibleValue
+        # XXX: check types?
+
+    def simple_call(self, *s_args):
+        assert self.is_constant()
+        return SomeOOInstance(self.const._INSTANCE)
+
+    def rtyper_makerepr(self, rtyper):
+        return CliClassRepr(self.const)
+
+    def rtyper_makekey(self):
+        return self.__class__, self.const
+
+
+class SomeCliStaticMethod(SomeObject):
+    def __init__(self, cli_class, meth_name):
+        self.cli_class = cli_class
+        self.meth_name = meth_name
+
+    def simple_call(self, *args_s):
+        return self.cli_class._ann_static_method(self.meth_name, args_s)
+
+    def rtyper_makerepr(self, rtyper):
+        return CliStaticMethodRepr(self.cli_class, self.meth_name)
+
+    def rtyper_makekey(self):
+        return self.__class__, self.cli_class, self.meth_name
+
+class __extend__(SomeOOInstance):
+
+    def simple_call(self, *s_args):
+        from pypy.translator.cli.query import get_cli_class
+        DELEGATE = get_cli_class('System.Delegate')._INSTANCE
+        if ootype.isSubclass(self.ootype, DELEGATE):
+            s_invoke = self.getattr(immutablevalue('Invoke'))
+            return s_invoke.simple_call(*s_args)
+        else:
+            # cannot call a non-delegate
+            return SomeObject.simple_call(self, *s_args)
+
+class __extend__(pairtype(SomeOOInstance, SomeInteger)):
+    def getitem((ooinst, index)):
+        if ooinst.ootype._isArray:
+            return SomeOOInstance(ooinst.ootype._ELEMENT)
+        return s_ImpossibleValue
+
+    def setitem((ooinst, index), s_value):
+        if ooinst.ootype._isArray:
+            if s_value is annmodel.s_None:
+                return s_None
+            ELEMENT = ooinst.ootype._ELEMENT
+            VALUE = s_value.ootype
+            assert ootype.isSubclass(VALUE, ELEMENT)
+            return s_None
+        return s_ImpossibleValue
+
+
+## Rtyper model
+
+class CliClassRepr(Repr):
+    lowleveltype = ootype.Void
+
+    def __init__(self, cli_class):
+        self.cli_class = cli_class
+
+    def rtype_getattr(self, hop):
+        attrname = hop.args_v[1].value
+        if attrname in self.cli_class._static_methods:
+            return hop.inputconst(ootype.Void, self.cli_class)
+        else:
+            assert attrname in self.cli_class._static_fields
+            TYPE = self.cli_class._static_fields[attrname]
+            c_class = hop.inputarg(hop.args_r[0], arg=0)
+            c_name = hop.inputconst(ootype.Void, attrname)
+            return hop.genop("cli_getstaticfield", [c_class, c_name], resulttype=hop.r_result.lowleveltype)
+
+    def rtype_setattr(self, hop):
+        attrname = hop.args_v[1].value
+        assert attrname in self.cli_class._static_fields
+        c_class = hop.inputarg(hop.args_r[0], arg=0)
+        c_name = hop.inputconst(ootype.Void, attrname)
+        v_value = hop.inputarg(hop.args_r[2], arg=2)
+        return hop.genop("cli_setstaticfield", [c_class, c_name, v_value], resulttype=hop.r_result.lowleveltype)
+
+    def rtype_simple_call(self, hop):
+        # TODO: resolve constructor overloading
+        INSTANCE = hop.args_r[0].cli_class._INSTANCE
+        cINST = hop.inputconst(ootype.Void, INSTANCE)
+        vlist = hop.inputargs(*hop.args_r)[1:] # discard the first argument
+        hop.exception_is_here()
+        return hop.genop("new", [cINST]+vlist, resulttype=hop.r_result.lowleveltype)
+
+class CliStaticMethodRepr(Repr):
+    lowleveltype = ootype.Void
+
+    def __init__(self, cli_class, meth_name):
+        self.cli_class = cli_class
+        self.meth_name = meth_name
+
+    def _build_desc(self, args_v):
+        ARGS = tuple([v.concretetype for v in args_v])
+        return self.cli_class._lookup(self.meth_name, ARGS)
+
+    def rtype_simple_call(self, hop):
+        vlist = []
+        for i, repr in enumerate(hop.args_r[1:]):
+            vlist.append(hop.inputarg(repr, i+1))
+        resulttype = hop.r_result.lowleveltype
+        desc = self._build_desc(vlist)
+        cDesc = hop.inputconst(ootype.Void, desc)
+        return hop.genop("direct_call", [cDesc] + vlist, resulttype=resulttype)
+
+
+class __extend__(pairtype(OOInstanceRepr, IntegerRepr)):
+
+    def rtype_getitem((r_inst, r_int), hop):
+        if not r_inst.lowleveltype._isArray:
+            raise TyperError("getitem() on a non-array instance")
+        v_array, v_index = hop.inputargs(r_inst, ootype.Signed)
+        hop.exception_is_here()
+        return hop.genop('cli_getelem', [v_array, v_index], hop.r_result.lowleveltype)
+
+    def rtype_setitem((r_inst, r_int), hop):
+        if not r_inst.lowleveltype._isArray:
+            raise TyperError("setitem() on a non-array instance")
+        vlist = hop.inputargs(*hop.args_r)
+        hop.exception_is_here()
+        return hop.genop('cli_setelem', vlist, hop.r_result.lowleveltype)
+
+
+class __extend__(OOInstanceRepr):
+
+    def rtype_len(self, hop):
+        if not self.lowleveltype._isArray:
+            raise TypeError("len() on a non-array instance")
+        vlist = hop.inputargs(*hop.args_r)
+        hop.exception_cannot_occur()
+        return hop.genop('cli_arraylength', vlist, hop.r_result.lowleveltype)
+
+    def rtype_simple_call(self, hop):
+        TYPE = self.lowleveltype
+        _, meth = TYPE._lookup('Invoke')
+        assert isinstance(meth, ootype._overloaded_meth)
+        ARGS = tuple([repr.lowleveltype for repr in hop.args_r[1:]])
+        desc = meth._get_desc('Invoke', ARGS)
+        cname = hop.inputconst(ootype.Void, desc)
+        vlist = hop.inputargs(self, *hop.args_r[1:])
+        hop.exception_is_here()
+        return hop.genop("oosend", [cname]+vlist,
+                         resulttype = hop.r_result.lowleveltype)
+
+
+## OOType model
+
+class OverloadingResolver(ootype.OverloadingResolver):
+
+    def _can_convert_from_to(self, ARG1, ARG2):
+        if ARG1 is ootype.Void and isinstance(ARG2, NativeInstance):
+            return True # ARG1 could be None, that is always convertible to a NativeInstance
+        else:
+            return ootype.OverloadingResolver._can_convert_from_to(self, ARG1, ARG2)
+
+    def annotation_to_lltype(cls, ann):
+        if isinstance(ann, SomeChar):
+            return ootype.Char
+        elif isinstance(ann, SomeString):
+            return ootype.String
+        else:
+            return annotation_to_lltype(ann)
+    annotation_to_lltype = classmethod(annotation_to_lltype)
+
+    def lltype_to_annotation(cls, TYPE):
+        if isinstance(TYPE, NativeInstance):
+            return SomeOOInstance(TYPE)
+        elif TYPE is ootype.Char:
+            return SomeChar()
+        elif TYPE is ootype.String:
+            return SomeString(can_be_None=True)
+        else:
+            return lltype_to_annotation(TYPE)
+    lltype_to_annotation = classmethod(lltype_to_annotation)
+
+
+class _static_meth(object):
+
+    def __init__(self, TYPE):
+        self._TYPE = TYPE
+
+    def _set_attrs(self, cls, name):
+        self._cls = cls
+        self._name = name
+
+    def _get_desc(self, ARGS):
+        #assert ARGS == self._TYPE.ARGS
+        return self
+
+
+class _overloaded_static_meth(object):
+    def __init__(self, *overloadings, **attrs):
+        resolver = attrs.pop('resolver', OverloadingResolver)
+        assert not attrs
+        self._resolver = resolver(overloadings)
+
+    def _set_attrs(self, cls, name):
+        for meth in self._resolver.overloadings:
+            meth._set_attrs(cls, name)
+
+    def _get_desc(self, ARGS):
+        meth = self._resolver.resolve(ARGS)
+        assert isinstance(meth, _static_meth)
+        return meth._get_desc(ARGS)
+
+
+class NativeInstance(ootype.Instance):
+    def __init__(self, assembly, namespace, name, superclass,
+                 fields={}, methods={}, _is_root=False, _hints = {}):
+        fullname = '%s%s.%s' % (assembly, namespace, name)
+        self._namespace = namespace
+        self._classname = name
+        self._is_value_type = False
+        ootype.Instance.__init__(self, fullname, superclass, fields, methods, _is_root, _hints)
+
+
+## RPython interface definition
+
+class CliClass(object):
+    def __init__(self, INSTANCE, static_methods, static_fields):
+        self._name = INSTANCE._name
+        self._INSTANCE = INSTANCE
+        self._static_methods = {}
+        self._static_fields = {}
+        self._add_methods(static_methods)
+
+    def __repr__(self):
+        return '<%s>' % (self,)
+
+    def __str__(self):
+        return '%s(%s)' % (self.__class__.__name__, self._INSTANCE._name)
+
+    def _add_methods(self, methods):
+        self._static_methods.update(methods)
+        for name, meth in methods.iteritems():
+            meth._set_attrs(self, name)
+
+    def _add_static_fields(self, fields):
+        self._static_fields.update(fields)
+
+    def _lookup(self, meth_name, ARGS):
+        meth = self._static_methods[meth_name]
+        return meth._get_desc(ARGS)
+
+    def _ann_static_method(self, meth_name, args_s):
+        meth = self._static_methods[meth_name]
+        return meth._resolver.annotate(args_s)
+
+    def _load_class(self):
+        names = self._INSTANCE._namespace.split('.')
+        names.append(self._INSTANCE._classname)
+        obj = PythonNet
+        for name in names:
+            obj = getattr(obj, name)
+        self._PythonNet_class = obj
+
+    def __getattr__(self, attr):
+        if attr in self._static_methods or attr in self._static_fields:
+            self._load_class()
+            return getattr(self._PythonNet_class, attr)
+        else:
+            raise AttributeError, attr
+
+    def __call__(self, *args):
+        self._load_class()
+        return self._PythonNet_class(*args)
+
+
+class Entry(ExtRegistryEntry):
+    _type_ = CliClass
+
+    def compute_annotation(self):
+        return SomeCliClass()
+
+    def compute_result_annotation(self):
+        return SomeOOInstance(self.instance._INSTANCE)
+
+
+BOXABLE_TYPES = [ootype.Signed, ootype.Unsigned, ootype.SignedLongLong,
+                 ootype.UnsignedLongLong, ootype.Bool, ootype.Float,
+                 ootype.Char, ootype.String]
+
+class BoxedSpace:
+    objects = {}
+    index = 0
+    def put(cls, obj):
+        index = cls.index
+        cls.objects[index] = obj
+        cls.index += 1
+        return index
+    put = classmethod(put)
+
+    def get(cls, index):
+        return cls.objects[index]
+    get = classmethod(get)
+
+def box(x):
+    t = type(x)
+    if t is int:
+        return CLR.System.Int32(x)
+    elif t is r_uint:
+        return CLR.System.UInt32(x)
+    elif t is r_longlong:
+        return CLR.System.Int64(x)
+    elif t is r_ulonglong:
+        return CLR.System.UInt64(x)
+    elif t is bool:
+        return CLR.System.Boolean(x)
+    elif t is float:
+        return CLR.System.Double(x)
+    elif t is str or t is unicode:
+        if len(x) == 1:
+            return CLR.System.Char(x)
+        else:
+            return CLR.System.String(x)
+    elif isinstance(x, ootype._class):
+        if hasattr(x, '_FUNC'):
+            TYPE = x._FUNC
+            assert isinstance(TYPE, ootype.StaticMethod)
+            return typeof(TYPE)
+        elif x is ootype.nullruntimeclass:
+            return None
+        else:
+            name = x._INSTANCE._assembly_qualified_name
+            t = CLR.System.Type.GetType(name)
+            assert t is not None
+            return t
+    elif isinstance(x, PythonNet.System.Object):
+        return x
+    elif x is None:
+        return None
+    else:
+        # cast RPython instances to System.Object is trivial when
+        # translated but not when interpreting, because Python for
+        # .NET doesn't support passing aribrary Python objects to
+        # .NET. To solve, we store them in the BoxedSpace, then we
+        # return an opaque objects, which will be used by unbox to
+        # retrieve the original RPython instance.
+        index = BoxedSpace.put(x)
+        res = PythonNet.pypy.test.ObjectWrapper(index)
+        return res
+
+def unbox(x, TYPE):
+    if isinstance(x, PythonNet.pypy.test.ObjectWrapper):
+        x = BoxedSpace.get(x.index)
+
+    if isinstance(TYPE, (type, types.ClassType)):
+        # we need to check the TYPE and return None if it fails
+        if isinstance(x, TYPE):
+            return x
+        else:
+            return None
+
+    if isinstance(TYPE, ootype.OOType) and TYPE is not ootype.String and not isinstance(TYPE, ootype.StaticMethod):
+        try:
+            return ootype.enforce(TYPE, x)
+        except TypeError:
+            return None
+
+    # TODO: do the typechecking also in the other cases
+
+    # this is a workaround against a pythonnet limitation: you can't
+    # directly get the, e.g., python int from the System.Int32 object:
+    # a simple way to do this is to put it into an ArrayList and
+    # retrieve the value.
+    tmp = PythonNet.System.Collections.ArrayList()
+    tmp.Add(x)
+    return tmp[0]
+
+
+class Entry(ExtRegistryEntry):
+    _about_ = box
+
+    def compute_result_annotation(self, x_s):
+        can_be_None = getattr(x_s, 'can_be_None', False)
+        return SomeOOInstance(CLR.System.Object._INSTANCE, can_be_None=can_be_None)
+
+    def specialize_call(self, hop):
+        v_obj, = hop.inputargs(*hop.args_r)
+
+        hop.exception_cannot_occur()
+        TYPE = v_obj.concretetype
+        if (TYPE is ootype.String or isinstance(TYPE, (ootype.OOType, NativeInstance))):
+            return hop.genop('ooupcast', [v_obj], hop.r_result.lowleveltype)
+        else:
+            if TYPE not in BOXABLE_TYPES:
+                raise TyperError, "Can't box values of type %s" % v_obj.concretetype
+            return hop.genop('clibox', [v_obj], hop.r_result.lowleveltype)
+
+
+class Entry(ExtRegistryEntry):
+    _about_ = unbox
+
+    def compute_result_annotation(self, x_s, type_s):
+        assert isinstance(x_s, SomeOOInstance)
+        assert isinstance(x_s.ootype, NativeInstance)
+        assert type_s.is_constant()
+        TYPE = type_s.const
+        if isinstance(TYPE, (type, types.ClassType)):
+            # it's a user-defined class, so we return SomeInstance
+            # can_be_None == True because it can always return None, if it fails
+            classdef = self.bookkeeper.getuniqueclassdef(TYPE)
+            return SomeInstance(classdef, can_be_None=True)
+        elif TYPE in BOXABLE_TYPES:
+            return OverloadingResolver.lltype_to_annotation(TYPE)
+        elif isinstance(TYPE, ootype.StaticMethod):
+            return SomeOOStaticMeth(TYPE)
+        elif isinstance(TYPE, ootype.OOType):
+            return SomeOOInstance(TYPE)
+        else:
+            assert False
+            
+
+    def specialize_call(self, hop):
+        assert hop.args_s[1].is_constant()
+        TYPE = hop.args_s[1].const
+        v_obj = hop.inputarg(hop.args_r[0], arg=0)
+        if TYPE is ootype.String or isinstance(TYPE, (type, types.ClassType)) or isinstance(TYPE, ootype.OOType):
+            return hop.genop('oodowncast', [v_obj], hop.r_result.lowleveltype)
+        else:
+            c_type = hop.inputconst(ootype.Void, TYPE)
+            return hop.genop('cliunbox', [v_obj, c_type], hop.r_result.lowleveltype)
+
+
+
+native_exc_cache = {}
+def NativeException(cliClass):
+    try:
+        return native_exc_cache[cliClass._name]
+    except KeyError:
+        res = _create_NativeException(cliClass)
+        native_exc_cache[cliClass._name] = res
+        return res
+
+def _create_NativeException(cliClass):
+    from pypy.translator.cli.support import getattr_ex
+    TYPE = cliClass._INSTANCE
+    if PythonNet.__name__ in ('CLR', 'clr'):
+        # we are using pythonnet -- use the .NET class
+        name = '%s.%s' % (TYPE._namespace, TYPE._classname)
+        res = getattr_ex(PythonNet, name)
+    else:
+        # we are not using pythonnet -- create a fake class
+        res = types.ClassType(TYPE._classname, (Exception,), {})
+    res._rpython_hints = {'NATIVE_INSTANCE': TYPE}
+    return res
+
+def native_exc(exc):
+    return exc
+
+class Entry(ExtRegistryEntry):
+    _about_ = native_exc
+
+    def compute_result_annotation(self, exc_s):
+        assert isinstance(exc_s, SomeInstance)
+        cls = exc_s.classdef.classdesc.pyobj
+        assert issubclass(cls, Exception)
+        NATIVE_INSTANCE = cls._rpython_hints['NATIVE_INSTANCE']
+        return SomeOOInstance(NATIVE_INSTANCE)
+
+    def specialize_call(self, hop):
+        v_obj, = hop.inputargs(*hop.args_r)
+        return hop.genop('same_as', [v_obj], hop.r_result.lowleveltype)
+
+def new_array(type, length):
+    # PythonNet doesn't provide a straightforward way to create arrays,
+    # let's use reflection instead
+
+    # hack to produce the array type name from the member type name
+    typename = type._INSTANCE._assembly_qualified_name
+    parts = typename.split(',')
+    parts[0] = parts[0] + '[]'
+    typename = ','.join(parts)
+    t = PythonNet.System.Type.GetType(typename)
+    ctor = t.GetConstructors()[0]
+    return ctor.Invoke([length])
+
+def init_array(type, *args):
+    array = new_array(type, len(args))
+    for i, arg in enumerate(args):
+        array[i] = arg
+    return array
+
+class Entry(ExtRegistryEntry):
+    _about_ = new_array
+
+    def compute_result_annotation(self, type_s, length_s):
+        from pypy.translator.cli.query import get_cli_class
+        assert type_s.is_constant()
+        assert isinstance(length_s, SomeInteger)
+        TYPE = type_s.const._INSTANCE
+        fullname = '%s.%s[]' % (TYPE._namespace, TYPE._classname)
+        cliArray = get_cli_class(fullname)
+        return SomeOOInstance(cliArray._INSTANCE)
+
+    def specialize_call(self, hop):
+        c_type, v_length = hop.inputargs(*hop.args_r)
+        hop.exception_cannot_occur()
+        return hop.genop('cli_newarray', [c_type, v_length], hop.r_result.lowleveltype)
+
+