/// <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(); }
/// <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); } }
////////////////////////////////////////////////////////////////////////// // 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); } }
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); }
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(); } }
////////////////////////////////////////////////////////////////////////// // 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(); } }
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); }
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(); } }
/// <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(); }
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); }
/// <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); }