Пример #1
0
        /// <summary>
        /// Emit a constructor - constructors get created as a static
        /// factory methods, so that that CallNew can just push args
        /// and invoke them
        ///
        ///   fan:
        ///     class Foo { new make(Long a) { ... } }
        ///   .net:
        ///     static Foo make(Long a) { return make_(new Foo(), a) }
        ///     static Foo make_(Foo self, Long a) { ... return self }
        ///
        /// We call the first method "make" the "factory" and the
        /// second method "make_" the "body".  CallNew opcodes are
        /// routed to the ctor factory, and CallCtor opcodes are routed
        /// to the ctor body.
        /// </summary>
        public void emitCtor()
        {
            string ctorName = this.name;

            // both factory and body are static from CLR's perspective
            this.isStatic = true;
            this.isHide   = true;

            // first emit the body with implicit self
            this.name = ctorName + "_";
            this.self = true;
            doEmit();
            PERWAPI.MethodDef make = emitter.methodDef;

            // emit body default parameter wrappers
            emitWrappers();

            // then emit the factory
            this.name = ctorName;
            this.self = false;
            this.ret  = emit.pod.typeRef(emit.type.m_self);
            this.code = null;

            PERWAPI.CILInstructions code = doEmit();
            PERWAPI.Method          ctor = emitter.findMethod(selfName, ".ctor", new string[0], "System.Void");
            code.MethInst(PERWAPI.MethodOp.newobj, ctor);
            code.Inst(PERWAPI.Op.dup);
            pushArgs(code, false, method.m_paramCount);
            code.MethInst(PERWAPI.MethodOp.call, make);
            code.Inst(PERWAPI.Op.ret);

            // emit factory default parameter wrappers
            emitWrappers();
        }
Пример #2
0
        /// <summary>
        /// Emit a mixin router from a class to the mixin body methods.
        /// </summary>
        public void emitMixinRouter(Method m)
        {
            string parent = FanUtil.toDotnetTypeName(m.parent());
            string name   = FanUtil.toDotnetMethodName(m.name());
            string ret    = FanUtil.toDotnetTypeName(m.inheritedReturns());

            string[] parTypes   = new string[] { parent };
            List     pars       = m.@params();
            int      paramCount = pars.sz();

            // find first param with default value
            int firstDefault = paramCount;

            for (int i = 0; i < paramCount; i++)
            {
                if (((Param)pars.get(i)).hasDefault())
                {
                    firstDefault = i; break;
                }
            }

            // generate routers
            for (int i = firstDefault; i <= paramCount; i++)
            {
                string[] myParams     = new string[i];
                string[] myParamNames = new string[i];
                string[] implParams   = new string[i + 1];
                implParams[0] = parent;

                for (int j = 0; j < i; j++)
                {
                    Param  param = (Param)m.@params().get(j);
                    Type   pt    = param.type();
                    string s     = FanUtil.toDotnetTypeName(pt);
                    myParams[j]       = s;
                    myParamNames[j]   = param.name();
                    implParams[j + 1] = s;
                }

                // CLR requires public virtual
                PERWAPI.MethAttr attr = PERWAPI.MethAttr.Public | PERWAPI.MethAttr.Virtual;

                PERWAPI.CILInstructions code = emitter.emitMethod(name, ret, myParamNames, myParams,
                                                                  attr, new string[0], new string[0]);
                code.Inst(PERWAPI.Op.ldarg_0); // push this
                for (int p = 0; p < i; p++)
                {
                    // push args
                    Param param = (Param)m.@params().get(p);
                    FCodeEmit.loadVar(code, FanUtil.toDotnetStackType(param.type()), p + 1);
                }
                PERWAPI.Method meth = emitter.findMethod(parent + "_", name, implParams, ret);
                code.MethInst(PERWAPI.MethodOp.call, meth);
                code.Inst(PERWAPI.Op.ret);
            }
        }
Пример #3
0
        //////////////////////////////////////////////////////////////////////////
        // Code Utils
        //////////////////////////////////////////////////////////////////////////

        /// <summary>
        /// Push the specified number of arguments onto the stack.
        /// </summary>
        private void pushArgs(PERWAPI.CILInstructions code, bool self, int count)
        {
            if (self)
            {
                code.Inst(PERWAPI.Op.ldarg_0);
            }
            for (int i = 0; i < count; i++)
            {
                FTypeRef var = emit.pod.typeRef(method.m_vars[i].type);
                FCodeEmit.loadVar(code, var.stackType, self ? i + 1 : i);
            }
        }
Пример #4
0
        protected override void emitType()
        {
            PERWAPI.TypeAttr classAttr = PERWAPI.TypeAttr.Public;
            if (isAbstract)
            {
                classAttr |= PERWAPI.TypeAttr.Abstract;
            }

            emitter.emitClass(baseClassName, className, interfaces, classAttr);

            // generate private static Type $Type; set in clinit
            typeField = emitter.classDef.AddField(
                PERWAPI.FieldAttr.Public | PERWAPI.FieldAttr.Static,
                "$type", emitter.findType("Fan.Sys.Type"));

            // generate type() instance method
            PERWAPI.MethodDef m = emitter.classDef.AddMethod(
                PERWAPI.MethAttr.Public | PERWAPI.MethAttr.Virtual, PERWAPI.ImplAttr.IL,
                "typeof", emitter.findType("Fan.Sys.Type"), new PERWAPI.Param[0]);
            m.AddCallConv(PERWAPI.CallConv.Instance);
            emitter.addToMethodMap(className, "typeof", new string[0], m);

            PERWAPI.CILInstructions code = m.CreateCodeBuffer();
            code.FieldInst(PERWAPI.FieldOp.ldsfld, typeField);
            code.Inst(PERWAPI.Op.ret);

            // generate peer field if native
            if (isNative)
            {
                peerField = emitter.classDef.AddField(PERWAPI.FieldAttr.Public,
                                                      "m_peer", emitter.findType(className + "Peer"));
            }

            // Create ctor emit objects first so we can reference them

            // .ctor
            ctor = emitter.findMethod(selfName, ".ctor", new string[0], "System.Void") as PERWAPI.MethodDef;
            ctor.SetMethAttributes(
                PERWAPI.MethAttr.Public |
                PERWAPI.MethAttr.HideBySig |
                PERWAPI.MethAttr.SpecialRTSpecialName);
            ctor.AddCallConv(PERWAPI.CallConv.Instance);

            // .cctor
            cctor = emitter.findMethod(selfName, ".cctor", new string[0], "System.Void") as PERWAPI.MethodDef;
            cctor.SetMethAttributes(
                PERWAPI.MethAttr.Private |
                PERWAPI.MethAttr.Static |
                PERWAPI.MethAttr.HideBySig |
                PERWAPI.MethAttr.SpecialRTSpecialName);
        }
Пример #5
0
        protected virtual void emitInstanceInit(FMethod m)
        {
            hasInstanceInit = true;
            PERWAPI.CILInstructions code = ctor.CreateCodeBuffer();

            // initalize code to call super
            code.Inst(PERWAPI.Op.ldarg_0);

            // if closure, push FuncType static field
            if (funcType != null)
            {
                code.FieldInst(PERWAPI.FieldOp.ldsfld, typeField);
                PERWAPI.Method baseCtor = emitter.findMethod(baseClassName, ".ctor",
                                                             new string[] { "Fan.Sys.FuncType" }, "System.Void");
                baseCtor.AddCallConv(PERWAPI.CallConv.Instance); // if stub, make sure instance callconv
                code.MethInst(PERWAPI.MethodOp.call, baseCtor);
            }
            else
            {
                PERWAPI.Method baseCtor = emitter.findMethod(baseClassName, ".ctor",
                                                             new string[0], "System.Void");
                baseCtor.AddCallConv(PERWAPI.CallConv.Instance); // if stub, make sure instance callconv
                code.MethInst(PERWAPI.MethodOp.call, baseCtor);
            }

            // make peer
            if (isNative)
            {
                //code.op(ALOAD_0);  // for putfield
                //code.op(DUP);      // for arg to make
                //code.op2(INVOKESTATIC, method(selfName + "Peer.make(L" + className + ";)L" + className + "Peer;"));
                //code.op2(PUTFIELD, peerField.ref());

                code.Inst(PERWAPI.Op.ldarg_0);
                code.Inst(PERWAPI.Op.dup);
                PERWAPI.Method peerMake = emitter.findMethod(className + "Peer", "make",
                                                             new string[] { className }, className + "Peer");
                code.MethInst(PERWAPI.MethodOp.call, peerMake);
                code.FieldInst(PERWAPI.FieldOp.stfld, peerField);
            }

            if (m == null)
            {
                code.Inst(PERWAPI.Op.ret);
            }
            else
            {
                new FCodeEmit(this, m, code).emit();
            }
        }
Пример #6
0
        //////////////////////////////////////////////////////////////////////////
        // Overrides
        //////////////////////////////////////////////////////////////////////////

        protected override void emitInstanceInit(FMethod m)
        {
            hasInstanceInit = true;

            // make peer
            if (isNative)
            {
                throw new System.Exception("No native support for Err subclasses");
            }

            // stub ctor2
            PERWAPI.MethodDef ctor2 = emitter.findMethod(selfName, ".ctor",
                                                         new string[] { "Fan.Sys.Err/Val" }, "System.Void") as PERWAPI.MethodDef;
            ctor2.SetMethAttributes(
                PERWAPI.MethAttr.Public |
                PERWAPI.MethAttr.HideBySig |
                PERWAPI.MethAttr.SpecialRTSpecialName);
            ctor2.AddCallConv(PERWAPI.CallConv.Instance);

            // no arg constructor -> calls this(Err/Val)
            PERWAPI.CILInstructions code = ctor.CreateCodeBuffer();
            code.Inst(PERWAPI.Op.ldarg_0);
            PERWAPI.Method valctor = emitter.findMethod(className + "/Val", ".ctor", new string[0], "System.Void");
            code.MethInst(PERWAPI.MethodOp.newobj, valctor);
            code.MethInst(PERWAPI.MethodOp.call, ctor2);
            code.Inst(PERWAPI.Op.ret);

            // arg constructor with Err$Val (and init implementation)
            code = ctor2.CreateCodeBuffer();
            code.Inst(PERWAPI.Op.ldarg_0);
            code.Inst(PERWAPI.Op.ldarg_1);
            PERWAPI.Method baseCtor = emitter.findMethod(baseClassName, ".ctor",
                                                         new string[] { "Fan.Sys.Err/Val" }, "System.Void");
            baseCtor.AddCallConv(PERWAPI.CallConv.Instance); // if stub, make sure instance callconv
            code.MethInst(PERWAPI.MethodOp.call, baseCtor);
            if (m == null)
            {
                //code.maxLocals = 2;
                //code.maxStack  = 2;
                code.Inst(PERWAPI.Op.ret);
            }
            else
            {
                // e.code.maxLocals++;  // alloc room for Val extra argument
                new FCodeEmit(this, m, code).emit();
            }
        }
Пример #7
0
        private void emitCtor()
        {
            // no arg constructor
            ctor = emitter.findMethod(selfName, ".ctor", new string[0], "System.Void") as PERWAPI.MethodDef;
            ctor.SetMethAttributes(
                PERWAPI.MethAttr.Public |
                PERWAPI.MethAttr.HideBySig |
                PERWAPI.MethAttr.SpecialRTSpecialName);
            ctor.AddCallConv(PERWAPI.CallConv.Instance);

            PERWAPI.CILInstructions code = ctor.CreateCodeBuffer();
            code.Inst(PERWAPI.Op.ldarg_0);
            PERWAPI.Method baseCtor = emitter.findMethod(baseClassName, ".ctor", new string[0], "System.Void");
            baseCtor.AddCallConv(PERWAPI.CallConv.Instance); // if stub, make sure instance callconv
            code.MethInst(PERWAPI.MethodOp.call, baseCtor);
            code.Inst(PERWAPI.Op.ret);
        }
Пример #8
0
        internal void emitStaticInit(FMethod m)
        {
            // make sure we add local defs
            if (m != null && m.m_localCount > 0)
            {
                PERWAPI.Local[] locals = new PERWAPI.Local[m.m_vars.Length];
                for (int i = 0; i < locals.Length; i++)
                {
                    string name = m.m_vars[i].name;
                    string type = nname(m.m_vars[i].type);
                    locals[i] = new PERWAPI.Local(name, emitter.findType(type));
                }
                cctor.AddLocals(locals, true);
            }

            hasStaticInit = true;
            PERWAPI.CILInstructions code = cctor.CreateCodeBuffer();

            // set $Type field with type (if we this is a closure,
            // then the FuncType will be the type exposed)
            if (!parent.isMixin())
            {
                Type t = parent;
                if (parent.@base() is FuncType)
                {
                    t = parent.@base();
                }

                code.ldstr(t.signature());
                PERWAPI.Method findType = emitter.findMethod("Fan.Sys.Type", "find",
                                                             new string[] { "System.String" }, "Fan.Sys.Type");
                code.MethInst(PERWAPI.MethodOp.call, findType);
                code.FieldInst(PERWAPI.FieldOp.stsfld, typeField);
            }

            if (m == null)
            {
                code.Inst(PERWAPI.Op.ret);
            }
            else
            {
                new FCodeEmit(this, m, code).emit();
            }
        }
Пример #9
0
        /// <summary>
        /// Emit a native method
        /// <summary>
        public void emitNative()
        {
            // emit an empty method
            this.code = null;

            // emit code which calls the peer
            PERWAPI.CILInstructions code = doEmit();
            if (!emitter.stub)
            {
                if (isStatic)
                {
                    string[] parTypes = new string[paramLen];
                    for (int i = 0; i < paramLen; i++)
                    {
                        parTypes[i] = emit.nname(method.m_vars[i].type);
                    }

                    PERWAPI.Method peerMeth = emitter.findMethod(selfName + "Peer", name, parTypes, ret.nname());
                    pushArgs(code, false, paramLen);
                    code.MethInst(PERWAPI.MethodOp.call, peerMeth);
                }
                else
                {
                    string[] parTypes = new string[paramLen + 1];
                    parTypes[0] = selfName;
                    for (int i = 0; i < paramLen; i++)
                    {
                        parTypes[i + 1] = emit.nname(method.m_vars[i].type);
                    }

                    PERWAPI.Method peerMeth = emitter.findMethod(selfName + "Peer", name, parTypes, ret.nname());
                    peerMeth.AddCallConv(PERWAPI.CallConv.Instance);
                    code.Inst(PERWAPI.Op.ldarg_0);
                    code.FieldInst(PERWAPI.FieldOp.ldfld, emit.peerField);
                    pushArgs(code, true, paramLen);
                    code.MethInst(PERWAPI.MethodOp.call, peerMeth);
                }
            }
            code.Inst(PERWAPI.Op.ret);

            // emit default parameter wrappers
            emitWrappers();
        }
Пример #10
0
        private PERWAPI.CILInstructions doEmit(string[] localNames, string[] localTypes)
        {
            int paramCount = paramLen;

            if (self)
            {
                paramCount++;
            }

            string[] parNames = new string[paramCount];
            string[] parTypes = new string[paramCount];
            for (int i = 0; i < paramCount; i++)
            {
                int z = i;
                if (self)
                {
                    z--;
                }

                if (self && i == 0)
                {
                    parNames[0] = "self";
                    parTypes[0] = selfName;
                }
                else
                {
                    parNames[i] = method.m_vars[z].name;
                    parTypes[i] = emit.nname(method.m_vars[z].type);
                }
            }

            if (localNames == null)
            {
                localNames = new string[method.m_localCount];
                localTypes = new string[method.m_localCount];
                for (int i = 0; i < method.m_localCount; i++)
                {
                    int z = i + paramCount;
                    if (self)
                    {
                        z--;
                    }

                    localNames[i] = method.m_vars[z].name;
                    localTypes[i] = emit.nname(method.m_vars[z].type);
                }
            }

            /*
             * PERWAPI.MethAttr attr;
             * if (isPrivate) attr = PERWAPI.MethAttr.Public; //PERWAPI.MethAttr.Private;
             * else if (isInternal) attr = PERWAPI.MethAttr.Assembly;
             * else attr = PERWAPI.MethAttr.Public;
             */
            PERWAPI.MethAttr attr = isInternal
        ? PERWAPI.MethAttr.Assembly
        : PERWAPI.MethAttr.Public;

            if (isStatic)
            {
                attr |= PERWAPI.MethAttr.Static;
            }
            if (isAbstract)
            {
                attr |= PERWAPI.MethAttr.Abstract;
            }
            if (isVirtual)
            {
                attr |= PERWAPI.MethAttr.Virtual;
            }
            if (isOverride)
            {
                attr |= PERWAPI.MethAttr.Virtual;
            }
            if (isHide)
            {
                attr |= PERWAPI.MethAttr.HideBySig;
            }

            PERWAPI.CILInstructions code = emitter.emitMethod(name, ret.nname(), parNames, parTypes, attr,
                                                              localNames, localTypes);
            if (this.code != null)
            {
                new FCodeEmit(emit, method, code).emit();
            }

            return(code);
        }
Пример #11
0
        /// <summary>
        /// Emit wrapper.
        /// </summary>
        private void emitWrapper(PERWAPI.MethodDef main, int paramLen)
        {
            // use explicit param count, and clear code
            this.paramLen = paramLen;
            this.code     = null;
            int numArgs = isStatic && !self ? paramLen : paramLen + 1;

            // TODO - this code probably isn't quite right, since it looks
            // like we generate local variables even when they might not be
            // used.  Doesn't hurt anything, but is probably more efficient
            // if we could determine that from the fcode.

            // define our locals
            int numLocals = method.m_paramCount - paramLen;

            string[] localNames = new string[numLocals];
            string[] localTypes = new string[numLocals];
            for (int i = paramLen; i < method.m_paramCount; i++)
            {
                localNames[i - paramLen] = method.m_vars[i].name;
                localTypes[i - paramLen] = emit.nname(method.m_vars[i].type);
            }

            // emit code
            PERWAPI.CILInstructions code = doEmit(localNames, localTypes);

            // push arguments passed thru
            pushArgs(code, !(isStatic && !self), paramLen);

            // emit default arguments
            FCodeEmit.Reg[] regs      = FCodeEmit.initRegs(emit.pod, isStatic, method.m_vars);
            int             maxLocals = method.maxLocals();
            int             maxStack  = 16; // TODO - add additional default expr stack height

            for (int i = paramLen; i < method.m_paramCount; i++)
            {
                FCodeEmit ce = new FCodeEmit(emit, method.m_vars[i].def, code, regs, emit.pod.typeRef(method.m_ret));
                ce.paramCount = numArgs;
                ce.vars       = method.m_vars;
                ce.isStatic   = isStatic;
// TODO - is this correct?
                ce.emit(false); // don't emit debug s cope for wrappers
                maxStack = System.Math.Max(maxStack, 2 + i + 8);
            }
            // TODO
            //code.maxLocals = maxLocals;
            //code.maxStack  = maxStack;

            // call master implementation
            if (isStatic)
            {
                code.MethInst(PERWAPI.MethodOp.call, main);
            }
            else
            {
                code.MethInst(PERWAPI.MethodOp.callvirt, main);
            }

            // return
            code.Inst(PERWAPI.Op.ret);
        }