private ConstructorBuilder EmitFieldOnlyConstructor(TypeBuilder fnTB, Type baseType) { Type[] ctorTypes = CtorTypes(); Type[] altCtorTypes = new Type[ctorTypes.Length - _altCtorDrops]; for (int i = 0; i < altCtorTypes.Length; i++) { altCtorTypes[i] = ctorTypes[i]; } ConstructorBuilder cb = fnTB.DefineConstructor(MethodAttributes.Public, CallingConventions.HasThis, altCtorTypes); CljILGen gen = new CljILGen(cb.GetILGenerator()); //Call full constructor gen.EmitLoadArg(0); // gen.Emit(OpCodes.Ldarg_0); for (int i = 0; i < altCtorTypes.Length; i++) { gen.EmitLoadArg(i + 1); } for (int i = 0; i < _altCtorDrops; i++) { gen.EmitNull(); } gen.Emit(OpCodes.Call, _ctorInfo); gen.Emit(OpCodes.Ret); return(cb); }
private void EmitMetaFunctions(TypeBuilder fnTB) { // IPersistentMap meta() MethodBuilder metaMB = fnTB.DefineMethod("meta", MethodAttributes.Public | MethodAttributes.Virtual | MethodAttributes.ReuseSlot, typeof(IPersistentMap), Type.EmptyTypes); CljILGen gen = new CljILGen(metaMB.GetILGenerator()); if (SupportsMeta) { gen.EmitLoadArg(0); gen.EmitFieldGet(MetaField); } else gen.EmitNull(); gen.Emit(OpCodes.Ret); // IObj withMeta(IPersistentMap) MethodBuilder withMB = fnTB.DefineMethod("withMeta", MethodAttributes.Public | MethodAttributes.Virtual | MethodAttributes.ReuseSlot, typeof(IObj), new Type[] { typeof(IPersistentMap) }); gen = new CljILGen(withMB.GetILGenerator()); if (SupportsMeta) { gen.EmitLoadArg(1); // meta arg foreach (FieldBuilder fb in ClosedOverFields) { gen.EmitLoadArg(0); gen.MaybeEmitVolatileOp(fb); gen.EmitFieldGet(fb); } gen.EmitNew(CtorInfo); } else gen.EmitLoadArg(0); //this gen.Emit(OpCodes.Ret); }
internal void EmitLocal(CljILGen ilg, LocalBinding lb) { Type primType = lb.PrimitiveType; if (Closes.containsKey(lb)) { ilg.Emit(OpCodes.Ldarg_0); // this FieldBuilder fb = ClosedOverFieldsMap[lb]; ilg.MaybeEmitVolatileOp(IsVolatile(lb)); ilg.Emit(OpCodes.Ldfld, fb); if (primType != null) HostExpr.EmitBoxReturn(this, ilg, primType); // TODO: ONCEONLY? } else { if (lb.IsArg) { //int argOffset = IsStatic ? 1 : 0; //ilg.Emit(OpCodes.Ldarg, lb.Index - argOffset); ilg.EmitLoadArg(lb.Index); } else if (lb.IsThis) { ilg.EmitLoadArg(0); } else { ilg.Emit(OpCodes.Ldloc, lb.LocalVar); } if (primType != null) HostExpr.EmitBoxReturn(this, ilg, primType); } }
private ConstructorBuilder EmitConstructorForDefType(TypeBuilder fnTB, Type baseType) { ConstructorBuilder cb = fnTB.DefineConstructor(MethodAttributes.Public, CallingConventions.HasThis, CtorTypes()); CljILGen gen = new CljILGen(cb.GetILGenerator()); GenContext.EmitDebugInfo(gen, SpanMap); // Pass closed-overs to base class ctor gen.EmitLoadArg(0); // gen.Emit(OpCodes.Ldarg_0); int a = 0; for (ISeq s = RT.keys(Closes); s != null; s = s.next(), a++) { //LocalBinding lb = (LocalBinding)s.first(); //FieldBuilder fb = _closedOverFields[a]; //bool isVolatile = IsVolatile(_closedOverFieldsToBindingsMap[fb]); gen.EmitLoadArg(a + 1); // gen.Emit(OpCodes.Ldarg, a + 1); } gen.Emit(OpCodes.Call, BaseClassClosedOverCtor); gen.Emit(OpCodes.Ret); return(cb); }
private void EmitFieldOnlyConstructorWithoutHash(TypeBuilder fnTB) { Type[] ctorTypes = CtorTypes(); Type[] altCtorTypes = new Type[ctorTypes.Length - 2]; for (int i = 0; i < altCtorTypes.Length; i++) { altCtorTypes[i] = ctorTypes[i]; } ConstructorBuilder cb = fnTB.DefineConstructor(MethodAttributes.Public, CallingConventions.HasThis, altCtorTypes); CljILGen gen = new CljILGen(cb.GetILGenerator()); //Call full constructor gen.EmitLoadArg(0); // gen.Emit(OpCodes.Ldarg_0); for (int i = 0; i < altCtorTypes.Length; i++) { gen.EmitLoadArg(i + 1); } gen.Emit(OpCodes.Ldc_I4_0); // __hash gen.Emit(OpCodes.Ldc_I4_0); // __hasheq gen.Emit(OpCodes.Call, CtorInfo); gen.Emit(OpCodes.Ret); }
void EmitSwapThunk(TypeBuilder tb) { MethodBuilder mb = tb.DefineMethod("swapThunk", MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.Virtual, typeof(void), new Type[] { typeof(int), typeof(ILookupThunk) }); CljILGen ilg = new CljILGen(mb.GetILGenerator()); Label endLabel = ilg.DefineLabel(); Label[] labels = new Label[KeywordCallsites.count()]; for (int i = 0; i < KeywordCallsites.count(); i++) { labels[i] = ilg.DefineLabel(); } ilg.EmitLoadArg(1); ilg.Emit(OpCodes.Switch, labels); ilg.Emit(OpCodes.Br, endLabel); for (int i = 0; i < KeywordCallsites.count(); i++) { ilg.MarkLabel(labels[i]); ilg.EmitLoadArg(2); ilg.EmitFieldSet(_thunkFields[i]); ilg.Emit(OpCodes.Br, endLabel); } ilg.MarkLabel(endLabel); ilg.Emit(OpCodes.Ret); }
private void DefineBaseClassClosedOverConstructors(Type super, TypeBuilder tb) { // ctor that takes closed-overs and does nothing if (CtorTypes().Length > 0) { ConstructorBuilder cb = tb.DefineConstructor(MethodAttributes.Public, CallingConventions.HasThis, CtorTypes()); CljILGen ilg = new CljILGen(cb.GetILGenerator()); ilg.EmitLoadArg(0); ilg.Emit(OpCodes.Call, super.GetConstructor(Type.EmptyTypes)); // store closed-overs in their fields int a = 0; for (ISeq s = RT.keys(Closes); s != null; s = s.next(), a++) { FieldBuilder fb = ClosedOverFields[a]; bool isVolatile = IsVolatile(ClosedOverFieldsToBindingsMap[fb]); ilg.EmitLoadArg(0); // gen.Emit(OpCodes.Ldarg_0); ilg.EmitLoadArg(a + 1); // gen.Emit(OpCodes.Ldarg, a + 1); ilg.MaybeEmitVolatileOp(isVolatile); ilg.Emit(OpCodes.Stfld, fb); } ilg.Emit(OpCodes.Ret); if (AltCtorDrops > 0) { Type[] ctorTypes = CtorTypes(); int newLen = ctorTypes.Length - AltCtorDrops; if (newLen > 0) { Type[] altCtorTypes = new Type[newLen]; for (int i = 0; i < altCtorTypes.Length; i++) { altCtorTypes[i] = ctorTypes[i]; } ConstructorBuilder cb2 = tb.DefineConstructor(MethodAttributes.Public, CallingConventions.HasThis, altCtorTypes); CljILGen ilg2 = new CljILGen(cb2.GetILGenerator()); ilg2.EmitLoadArg(0); for (int i = 0; i < newLen; i++) { ilg2.EmitLoadArg(i + 1); } for (int i = 0; i < AltCtorDrops; i++) { ilg2.EmitNull(); } ilg2.Emit(OpCodes.Call, cb); ilg2.Emit(OpCodes.Ret); } } } }
internal void EmitLocal(CljILGen ilg, LocalBinding lb) { Type primType = lb.PrimitiveType; if (Closes.containsKey(lb)) { if (_fnMode == FnMode.Full) { ilg.Emit(OpCodes.Ldarg_0); // this ilg.Emit(OpCodes.Ldfld, _closedOverFieldsMap[lb]); if (primType != null) { HostExpr.EmitBoxReturn(this, ilg, primType); } // TODO: ONCEONLY? } else // FnMode.Light { ilg.Emit(OpCodes.Ldarg_0); // this ilg.Emit(OpCodes.Castclass, typeof(IFnClosure)); ilg.EmitCall(Compiler.Method_IFnClosure_GetClosure); ilg.EmitFieldGet(Compiler.Field_Closure_Locals); ilg.EmitInt(lb.Index); ilg.EmitLoadElement(typeof(Object)); } } else { if (lb.IsArg) { //int argOffset = IsStatic ? 1 : 0; //ilg.Emit(OpCodes.Ldarg, lb.Index - argOffset); ilg.EmitLoadArg(lb.Index); } else if (lb.IsThis) { ilg.EmitLoadArg(0); } else { ilg.Emit(OpCodes.Ldloc, lb.LocalVar); } if (primType != null) { HostExpr.EmitBoxReturn(this, ilg, primType); } } }
private void DoEmitPrimOrStatic(ObjExpr fn, TypeBuilder tb, bool isStatic) { MethodAttributes attribs = isStatic ? MethodAttributes.Static | MethodAttributes.Public : MethodAttributes.ReuseSlot | MethodAttributes.Public | MethodAttributes.Virtual; string methodName = isStatic ? "invokeStatic" : "invokePrim"; MethodBuilder baseMB = tb.DefineMethod(methodName, attribs, GetReturnType(), _argTypes); if (!isStatic) { SetCustomAttributes(baseMB); } CljILGen baseIlg = new CljILGen(baseMB.GetILGenerator()); try { Label loopLabel = baseIlg.DefineLabel(); Var.pushThreadBindings(RT.map(Compiler.LoopLabelVar, loopLabel, Compiler.MethodVar, this)); GenContext.EmitDebugInfo(baseIlg, SpanMap); baseIlg.MarkLabel(loopLabel); EmitBody(Objx, baseIlg, _retType, _body); if (_body.HasNormalExit()) { baseIlg.Emit(OpCodes.Ret); } } finally { Var.popThreadBindings(); } // Generate the regular invoke, calling the static or prim method MethodBuilder regularMB = tb.DefineMethod(GetMethodName(), MethodAttributes.ReuseSlot | MethodAttributes.Public | MethodAttributes.Virtual, typeof(Object), GetArgTypes()); SetCustomAttributes(regularMB); CljILGen regIlg = new CljILGen(regularMB.GetILGenerator()); if (!isStatic) { regIlg.Emit(OpCodes.Ldarg_0); } for (int i = 0; i < _argTypes.Length; i++) { regIlg.EmitLoadArg(i + 1); HostExpr.EmitUnboxArg(fn, regIlg, _argTypes[i]); } regIlg.Emit(OpCodes.Call, baseMB); if (GetReturnType().IsValueType) { regIlg.Emit(OpCodes.Box, GetReturnType()); } regIlg.Emit(OpCodes.Ret); }
private ConstructorBuilder EmitConstructorForNonDefType(TypeBuilder fnTB, Type baseType) { ConstructorBuilder cb = fnTB.DefineConstructor(MethodAttributes.Public, CallingConventions.HasThis, CtorTypes()); CljILGen gen = new CljILGen(cb.GetILGenerator()); GenContext.EmitDebugInfo(gen, SpanMap); //Call base constructor ConstructorInfo baseCtorInfo = baseType.GetConstructor(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public, null, Type.EmptyTypes, null); if (baseCtorInfo == null) { throw new InvalidOperationException("Unable to find default constructor for " + baseType.FullName); } gen.EmitLoadArg(0); gen.Emit(OpCodes.Call, baseCtorInfo); // Store Meta if (SupportsMeta) { gen.EmitLoadArg(0); gen.EmitLoadArg(1); gen.Emit(OpCodes.Castclass, typeof(IPersistentMap)); gen.EmitFieldSet(MetaField); } // store closed-overs in their fields int a = 0; int offset = !SupportsMeta ? 1 : 2; for (ISeq s = RT.keys(Closes); s != null; s = s.next(), a++) { //LocalBinding lb = (LocalBinding)s.first(); FieldBuilder fb = ClosedOverFields[a]; bool isVolatile = IsVolatile(ClosedOverFieldsToBindingsMap[fb]); gen.EmitLoadArg(0); // gen.Emit(OpCodes.Ldarg_0); gen.EmitLoadArg(a + offset); // gen.Emit(OpCodes.Ldarg, a + 1); gen.MaybeEmitVolatileOp(isVolatile); gen.Emit(OpCodes.Stfld, fb); } gen.Emit(OpCodes.Ret); return(cb); }
private ConstructorBuilder EmitNonMetaConstructor(TypeBuilder fnTB, Type baseType) { Type[] ctorTypes = CtorTypes(); Type[] noMetaCtorTypes = new Type[ctorTypes.Length - 1]; for (int i = 1; i < ctorTypes.Length; i++) noMetaCtorTypes[i - 1] = ctorTypes[i]; ConstructorBuilder cb = fnTB.DefineConstructor(MethodAttributes.Public, CallingConventions.HasThis, noMetaCtorTypes); CljILGen gen = new CljILGen(cb.GetILGenerator()); gen.EmitLoadArg(0); gen.EmitNull(); // null meta for (int i = 0; i < noMetaCtorTypes.Length; i++) gen.EmitLoadArg(i + 1); gen.Emit(OpCodes.Call, CtorInfo); gen.Emit(OpCodes.Ret); return cb; }
protected static void EmitHasArityMethod(TypeBuilder tb, IList <int> arities, bool isVariadic, int reqArity) { // TODO: Convert to a Switch instruction MethodBuilder mb = tb.DefineMethod( "HasArity", MethodAttributes.ReuseSlot | MethodAttributes.Public | MethodAttributes.Virtual, typeof(bool), new Type[] { typeof(int) }); CljILGen gen = new CljILGen(mb.GetILGenerator()); Label falseLabel = gen.DefineLabel(); Label trueLabel = gen.DefineLabel(); if (isVariadic) { gen.EmitLoadArg(1); gen.EmitInt(reqArity); gen.Emit(OpCodes.Bge, trueLabel); } if (arities != null) { foreach (int i in arities) { gen.EmitLoadArg(1); gen.EmitInt(i); gen.Emit(OpCodes.Beq, trueLabel); } } gen.MarkLabel(falseLabel); gen.EmitBoolean(false); gen.Emit(OpCodes.Ret); gen.MarkLabel(trueLabel); gen.EmitBoolean(true); gen.Emit(OpCodes.Ret); }
internal void EmitUnboxedLocal(CljILGen ilg, LocalBinding lb) { if (Closes.containsKey(lb)) { ilg.Emit(OpCodes.Ldarg_0); // this FieldBuilder fb = ClosedOverFieldsMap[lb]; ilg.MaybeEmitVolatileOp(IsVolatile(lb)); ilg.Emit(OpCodes.Ldfld, fb); } else if (lb.IsArg) { //int argOffset = IsStatic ? 0 : 1; //ilg.Emit(OpCodes.Ldarg, lb.Index + argOffset); ilg.EmitLoadArg(lb.Index); } else if (lb.IsThis) { ilg.EmitLoadArg(0); } else ilg.Emit(OpCodes.Ldloc, lb.LocalVar); }
internal void EmitUnboxedLocal(CljILGen ilg, LocalBinding lb) { if (Closes.containsKey(lb)) { if (_fnMode == FnMode.Full) { ilg.Emit(OpCodes.Ldarg_0); // this ilg.Emit(OpCodes.Ldfld, _closedOverFieldsMap[lb]); } else { ilg.Emit(OpCodes.Ldarg_0); // this ilg.Emit(OpCodes.Castclass, typeof(IFnClosure)); ilg.EmitCall(Compiler.Method_IFnClosure_GetClosure); ilg.EmitFieldGet(Compiler.Field_Closure_Locals); ilg.EmitInt(lb.Index); ilg.EmitLoadElement(typeof(Object)); if (lb.PrimitiveType != null) { ilg.Emit(OpCodes.Unbox, lb.PrimitiveType); } } } else if (lb.IsArg) { //int argOffset = IsStatic ? 0 : 1; //ilg.Emit(OpCodes.Ldarg, lb.Index + argOffset); ilg.EmitLoadArg(lb.Index); } else if (lb.IsThis) { ilg.EmitLoadArg(0); } else { ilg.Emit(OpCodes.Ldloc, lb.LocalVar); } }
internal void EmitUnboxedLocal(CljILGen ilg, LocalBinding lb) { if (Closes.containsKey(lb)) { if (_fnMode == FnMode.Full) { ilg.Emit(OpCodes.Ldarg_0); // this FieldBuilder fb = _closedOverFieldsMap[lb]; ilg.MaybeEmitVolatileOp(IsVolatile(lb)); ilg.Emit(OpCodes.Ldfld, fb); } else { ilg.Emit(OpCodes.Ldarg_0); // this ilg.Emit(OpCodes.Castclass, typeof(IFnClosure)); ilg.EmitCall(Compiler.Method_IFnClosure_GetClosure); ilg.EmitFieldGet(Compiler.Field_Closure_Locals); ilg.EmitInt(lb.Index); ilg.EmitLoadElement(typeof(Object)); if (lb.PrimitiveType != null) ilg.Emit(OpCodes.Unbox, lb.PrimitiveType); } } else if (lb.IsArg) { //int argOffset = IsStatic ? 0 : 1; //ilg.Emit(OpCodes.Ldarg, lb.Index + argOffset); ilg.EmitLoadArg(lb.Index); } else if (lb.IsThis) { ilg.EmitLoadArg(0); } else ilg.Emit(OpCodes.Ldloc, lb.LocalVar); }
/*** * Current host interop uses reflection, which requires pre-existing classes * Work around this by: * Generate a stub class that has the same interfaces and fields as the class we are generating. * Use it as a type hint for this, and bind the simple name of the class to this stub (in resolve etc) * Unmunge the name (using a magic prefix) on any code gen for classes */ // TODO: Preparse method heads to pick up signatures, implement those methods as abstract or as NotImpelmented so that Reflection can pick up calls during compilation and avoide a callsite. static Type CompileStub(GenContext context, Type super, NewInstanceExpr ret, Type[] interfaces, Object frm) { TypeBuilder tb = context.ModuleBuilder.DefineType(Compiler.CompileStubPrefix + "." + ret.InternalName + RT.nextID(), TypeAttributes.Public | TypeAttributes.Abstract, super, interfaces); tb.DefineDefaultConstructor(MethodAttributes.Public); // instance fields for closed-overs for (ISeq s = RT.keys(ret.Closes); s != null; s = s.next()) { LocalBinding lb = (LocalBinding)s.first(); FieldAttributes access = FieldAttributes.Public; if (!ret.IsMutable(lb)) { access |= FieldAttributes.InitOnly; } Type fieldType = lb.PrimitiveType ?? typeof(Object); if (ret.IsVolatile(lb)) { tb.DefineField(lb.Name, fieldType, new Type[] { typeof(IsVolatile) }, Type.EmptyTypes, access); } else { tb.DefineField(lb.Name, fieldType, access); } } // ctor that takes closed-overs and does nothing if (ret.CtorTypes().Length > 0) { ConstructorBuilder cb = tb.DefineConstructor(MethodAttributes.Public, CallingConventions.HasThis, ret.CtorTypes()); CljILGen ilg = new CljILGen(cb.GetILGenerator()); ilg.EmitLoadArg(0); ilg.Emit(OpCodes.Call, super.GetConstructor(Type.EmptyTypes)); ilg.Emit(OpCodes.Ret); if (ret._altCtorDrops > 0) { Type[] ctorTypes = ret.CtorTypes(); int newLen = ctorTypes.Length - ret._altCtorDrops; if (newLen > 0) { Type[] altCtorTypes = new Type[newLen]; for (int i = 0; i < altCtorTypes.Length; i++) { altCtorTypes[i] = ctorTypes[i]; } ConstructorBuilder cb2 = tb.DefineConstructor(MethodAttributes.Public, CallingConventions.HasThis, altCtorTypes); CljILGen ilg2 = new CljILGen(cb2.GetILGenerator()); ilg2.EmitLoadArg(0); for (int i = 0; i < newLen; i++) { ilg2.EmitLoadArg(i + 1); } for (int i = 0; i < ret._altCtorDrops; i++) { ilg2.EmitNull(); } ilg2.Emit(OpCodes.Call, cb); ilg2.Emit(OpCodes.Ret); } } } Type t = tb.CreateType(); //Compiler.RegisterDuplicateType(t); return(t); }
internal void EmitUnboxedLocal(CljILGen ilg, LocalBinding lb) { if (Closes.containsKey(lb)) { ilg.Emit(OpCodes.Ldarg_0); // this FieldBuilder fb = _closedOverFieldsMap[lb]; ilg.MaybeEmitVolatileOp(IsVolatile(lb)); ilg.Emit(OpCodes.Ldfld, fb); } else if (lb.IsArg) { //int argOffset = IsStatic ? 0 : 1; //ilg.Emit(OpCodes.Ldarg, lb.Index + argOffset); ilg.EmitLoadArg(lb.Index); } else if (lb.IsThis) { ilg.EmitLoadArg(0); } else ilg.Emit(OpCodes.Ldloc, lb.LocalVar); }
void EmitSwapThunk(TypeBuilder tb) { MethodBuilder mb = tb.DefineMethod("swapThunk", MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.Virtual, typeof(void), new Type[] { typeof(int), typeof(ILookupThunk) }); CljILGen ilg = new CljILGen(mb.GetILGenerator()); Label endLabel = ilg.DefineLabel(); Label[] labels = new Label[KeywordCallsites.count()]; for (int i = 0; i < KeywordCallsites.count(); i++) labels[i] = ilg.DefineLabel(); ilg.EmitLoadArg(1); ilg.Emit(OpCodes.Switch, labels); ilg.Emit(OpCodes.Br, endLabel); for (int i = 0; i < KeywordCallsites.count(); i++) { ilg.MarkLabel(labels[i]); ilg.EmitLoadArg(2); ilg.EmitFieldSet(_thunkFields[i]); ilg.Emit(OpCodes.Br, endLabel); } ilg.MarkLabel(endLabel); ilg.Emit(OpCodes.Ret); }
private void EmitMetaFunctions(TypeBuilder fnTB) { // IPersistentMap meta() MethodBuilder metaMB = fnTB.DefineMethod("meta", MethodAttributes.Public | MethodAttributes.Virtual | MethodAttributes.ReuseSlot, typeof(IPersistentMap), Type.EmptyTypes); CljILGen gen = new CljILGen(metaMB.GetILGenerator()); if (SupportsMeta) { gen.EmitLoadArg(0); gen.EmitFieldGet(_metaField); } else gen.EmitNull(); gen.Emit(OpCodes.Ret); // IObj withMeta(IPersistentMap) MethodBuilder withMB = fnTB.DefineMethod("withMeta", MethodAttributes.Public | MethodAttributes.Virtual | MethodAttributes.ReuseSlot, typeof(IObj), new Type[] { typeof(IPersistentMap) }); gen = new CljILGen(withMB.GetILGenerator()); if (SupportsMeta) { gen.EmitLoadArg(1); // meta arg foreach (FieldBuilder fb in _closedOverFields) { gen.EmitLoadArg(0); gen.MaybeEmitVolatileOp(fb); gen.EmitFieldGet(fb); } gen.EmitNew(_ctorInfo); } else gen.EmitLoadArg(0); //this gen.Emit(OpCodes.Ret); }
private ConstructorBuilder EmitConstructor(TypeBuilder fnTB, Type baseType) { ConstructorBuilder cb = fnTB.DefineConstructor(MethodAttributes.Public, CallingConventions.HasThis, CtorTypes()); CljILGen gen = new CljILGen(cb.GetILGenerator()); GenContext.EmitDebugInfo(gen, SpanMap); //Call base constructor ConstructorInfo baseCtorInfo = baseType.GetConstructor(BindingFlags.Instance|BindingFlags.NonPublic|BindingFlags.Public,null,Type.EmptyTypes,null); if (baseCtorInfo == null) throw new InvalidOperationException("Unable to find default constructor for " + baseType.FullName); gen.EmitLoadArg(0); gen.Emit(OpCodes.Call, baseCtorInfo); // Store Meta if (SupportsMeta) { gen.EmitLoadArg(0); gen.EmitLoadArg(1); gen.Emit(OpCodes.Castclass, typeof(IPersistentMap)); gen.EmitFieldSet(_metaField); } // store closed-overs in their fields int a = 0; int offset = !SupportsMeta ? 1 : 2; for (ISeq s = RT.keys(Closes); s != null; s = s.next(), a++) { //LocalBinding lb = (LocalBinding)s.first(); FieldBuilder fb = _closedOverFields[a]; bool isVolatile = IsVolatile(_closedOverFieldsToBindingsMap[fb]); gen.EmitLoadArg(0); // gen.Emit(OpCodes.Ldarg_0); gen.EmitLoadArg(a + offset); // gen.Emit(OpCodes.Ldarg, a + 1); gen.MaybeEmitVolatileOp(isVolatile); gen.Emit(OpCodes.Stfld, fb); } gen.Emit(OpCodes.Ret); return cb; }
private static void CreateSuperCall(TypeBuilder proxyTB, Symbol p, MethodInfo mi) { Type[] paramTypes = CreateTypeArray(mi.GetParameters()); MethodBuilder mb = proxyTB.DefineMethod(p.Name, MethodAttributes.Public, CallingConventions.HasThis, mi.ReturnType, paramTypes); CljILGen gen = new CljILGen(mb.GetILGenerator()); gen.EmitLoadArg(0); // gen.Emit(OpCodes.Ldarg_0); for (int i = 0; i < paramTypes.Length; i++) gen.EmitLoadArg(i + 1); // gen.Emit(OpCodes.Ldarg, i + 1); gen.Emit(OpCodes.Call, mi); // not gen.EmitCall(mi); -- we need call versus callvirt gen.Emit(OpCodes.Ret); }
private void DefineBaseClassClosedOverConstructors(Type super, TypeBuilder tb) { // ctor that takes closed-overs and does nothing if (CtorTypes().Length > 0) { ConstructorBuilder cb = tb.DefineConstructor(MethodAttributes.Public, CallingConventions.HasThis,CtorTypes()); CljILGen ilg = new CljILGen(cb.GetILGenerator()); ilg.EmitLoadArg(0); ilg.Emit(OpCodes.Call, super.GetConstructor(Type.EmptyTypes)); // store closed-overs in their fields int a = 0; for (ISeq s = RT.keys(Closes); s != null; s = s.next(), a++) { FieldBuilder fb = ClosedOverFields[a]; bool isVolatile = IsVolatile(ClosedOverFieldsToBindingsMap[fb]); ilg.EmitLoadArg(0); // gen.Emit(OpCodes.Ldarg_0); ilg.EmitLoadArg(a + 1); // gen.Emit(OpCodes.Ldarg, a + 1); ilg.MaybeEmitVolatileOp(isVolatile); ilg.Emit(OpCodes.Stfld, fb); } ilg.Emit(OpCodes.Ret); if (AltCtorDrops > 0) { Type[] ctorTypes = CtorTypes(); int newLen = ctorTypes.Length - AltCtorDrops; if (newLen > 0) { Type[] altCtorTypes = new Type[newLen]; for (int i = 0; i < altCtorTypes.Length; i++) altCtorTypes[i] = ctorTypes[i]; ConstructorBuilder cb2 = tb.DefineConstructor(MethodAttributes.Public, CallingConventions.HasThis, altCtorTypes); CljILGen ilg2 = new CljILGen(cb2.GetILGenerator()); ilg2.EmitLoadArg(0); for (int i = 0; i < newLen; i++) ilg2.EmitLoadArg(i + 1); for (int i = 0; i < AltCtorDrops; i++) ilg2.EmitNull(); ilg2.Emit(OpCodes.Call, cb); ilg2.Emit(OpCodes.Ret); } } } }
protected override void EmitStatics(TypeBuilder tb) { if (IsDefType) { // getBasis() { MethodBuilder mbg = tb.DefineMethod("getBasis", MethodAttributes.Public | MethodAttributes.Static, typeof(IPersistentVector), Type.EmptyTypes); CljILGen ilg = new CljILGen(mbg.GetILGenerator()); EmitValue(HintedFields, ilg); ilg.Emit(OpCodes.Ret); } if (Fields.count() > HintedFields.count()) { // create(IPersistentMap) MethodBuilder mbc = tb.DefineMethod("create", MethodAttributes.Public | MethodAttributes.Static, tb, new Type[] { typeof(IPersistentMap) }); CljILGen gen = new CljILGen(mbc.GetILGenerator()); LocalBuilder kwLocal = gen.DeclareLocal(typeof(Keyword)); List<LocalBuilder> locals = new List<LocalBuilder>(); for (ISeq s = RT.seq(HintedFields); s != null; s = s.next()) { string bName = ((Symbol)s.first()).Name; Type t = Compiler.TagType(Compiler.TagOf(s.first())); // local_kw = Keyword.intern(bname) // local_i = arg_0.valAt(kw,null) gen.EmitLoadArg(0); gen.EmitString(bName); gen.EmitCall(Compiler.Method_Keyword_intern_string); gen.Emit(OpCodes.Dup); gen.Emit(OpCodes.Stloc, kwLocal.LocalIndex); gen.EmitNull(); gen.EmitCall(Compiler.Method_IPersistentMap_valAt2); LocalBuilder lb = gen.DeclareLocal(t); locals.Add(lb); if (t.IsPrimitive) gen.EmitUnbox(t); gen.Emit(OpCodes.Stloc, lb.LocalIndex); // arg_0 = arg_0.without(local_kw); gen.EmitLoadArg(0); gen.Emit(OpCodes.Ldloc, kwLocal.LocalIndex); gen.EmitCall(Compiler.Method_IPersistentMap_without); gen.EmitStoreArg(0); } foreach (LocalBuilder lb in locals) gen.Emit(OpCodes.Ldloc, lb.LocalIndex); gen.EmitNull(); gen.EmitLoadArg(0); gen.EmitCall(Compiler.Method_RT_seqOrElse); gen.EmitNew(CtorInfo); gen.Emit(OpCodes.Ret); } } }
private void EmitFieldOnlyConstructorWithoutHash(TypeBuilder fnTB) { Type[] ctorTypes = CtorTypes(); Type[] altCtorTypes = new Type[ctorTypes.Length - 2]; for (int i = 0; i < altCtorTypes.Length; i++) altCtorTypes[i] = ctorTypes[i]; ConstructorBuilder cb = fnTB.DefineConstructor(MethodAttributes.Public, CallingConventions.HasThis, altCtorTypes); CljILGen gen = new CljILGen(cb.GetILGenerator()); //Call full constructor gen.EmitLoadArg(0); // gen.Emit(OpCodes.Ldarg_0); for (int i = 0; i < altCtorTypes.Length; i++) gen.EmitLoadArg(i + 1); gen.Emit(OpCodes.Ldc_I4_0); // __hash gen.Emit(OpCodes.Ldc_I4_0); // __hasheq gen.Emit(OpCodes.Call, CtorInfo); gen.Emit(OpCodes.Ret); }
private ConstructorBuilder EmitConstructorForDefType(TypeBuilder fnTB, Type baseType) { ConstructorBuilder cb = fnTB.DefineConstructor(MethodAttributes.Public, CallingConventions.HasThis, CtorTypes()); CljILGen gen = new CljILGen(cb.GetILGenerator()); GenContext.EmitDebugInfo(gen, SpanMap); // Pass closed-overs to base class ctor gen.EmitLoadArg(0); // gen.Emit(OpCodes.Ldarg_0); int a = 0; for (ISeq s = RT.keys(Closes); s != null; s = s.next(), a++) { //LocalBinding lb = (LocalBinding)s.first(); //FieldBuilder fb = _closedOverFields[a]; //bool isVolatile = IsVolatile(_closedOverFieldsToBindingsMap[fb]); gen.EmitLoadArg(a + 1); // gen.Emit(OpCodes.Ldarg, a + 1); } gen.Emit(OpCodes.Call, _baseClassClosedOverCtor); gen.Emit(OpCodes.Ret); return cb; }
protected override void EmitStatics(TypeBuilder tb) { if (IsDefType) { // getBasis() { MethodBuilder mbg = tb.DefineMethod("getBasis", MethodAttributes.Public | MethodAttributes.Static, typeof(IPersistentVector), Type.EmptyTypes); CljILGen ilg = new CljILGen(mbg.GetILGenerator()); EmitValue(HintedFields, ilg); ilg.Emit(OpCodes.Ret); } if (Fields.count() > HintedFields.count()) { // create(IPersistentMap) MethodBuilder mbc = tb.DefineMethod("create", MethodAttributes.Public | MethodAttributes.Static, tb, new Type[] { typeof(IPersistentMap) }); CljILGen gen = new CljILGen(mbc.GetILGenerator()); LocalBuilder kwLocal = gen.DeclareLocal(typeof(Keyword)); List <LocalBuilder> locals = new List <LocalBuilder>(); for (ISeq s = RT.seq(HintedFields); s != null; s = s.next()) { string bName = ((Symbol)s.first()).Name; Type t = Compiler.TagType(Compiler.TagOf(s.first())); // local_kw = Keyword.intern(bname) // local_i = arg_0.valAt(kw,null) gen.EmitLoadArg(0); gen.EmitString(bName); gen.EmitCall(Compiler.Method_Keyword_intern_string); gen.Emit(OpCodes.Dup); gen.Emit(OpCodes.Stloc, kwLocal.LocalIndex); gen.EmitNull(); gen.EmitCall(Compiler.Method_IPersistentMap_valAt2); LocalBuilder lb = gen.DeclareLocal(t); locals.Add(lb); if (t.IsPrimitive) { gen.EmitUnbox(t); } gen.Emit(OpCodes.Stloc, lb.LocalIndex); // arg_0 = arg_0.without(local_kw); gen.EmitLoadArg(0); gen.Emit(OpCodes.Ldloc, kwLocal.LocalIndex); gen.EmitCall(Compiler.Method_IPersistentMap_without); gen.EmitStoreArg(0); } foreach (LocalBuilder lb in locals) { gen.Emit(OpCodes.Ldloc, lb.LocalIndex); } gen.EmitNull(); // __meta gen.EmitLoadArg(0); // __extmap gen.EmitCall(Compiler.Method_RT_seqOrElse); gen.Emit(OpCodes.Ldc_I4_0); // __hash gen.Emit(OpCodes.Ldc_I4_0); // __hasheq gen.EmitNew(CtorInfo); gen.Emit(OpCodes.Ret); } } }
static void DefineCtors(TypeBuilder proxyTB, Type superClass, string initName, string postInitName, ISeq ctors, ISeq ctorTypes, FieldBuilder initFB, FieldBuilder postInitFB, FieldBuilder stateFB, string factoryName) { ISeq s1 = ctors; for (ISeq s = ctorTypes; s != null; s = s.next()) { // TODO: Get rid of this mess by making sure the metadata on the keys of the constructors map gets copied to the constructor-types map. Sigh. IPersistentMap ctorAttributes = GenInterface.ExtractAttributes(RT.meta(((IMapEntry)s1.first()).key())); s1 = s1.next(); IMapEntry me = (IMapEntry)s.first(); ISeq thisParamTypesV = (ISeq)me.key(); ISeq baseParamTypesV = (ISeq)me.val(); Type[] thisParamTypes = CreateTypeArray(thisParamTypesV); Type[] baseParamTypes = CreateTypeArray(baseParamTypesV); BindingFlags flags = BindingFlags.CreateInstance| BindingFlags.NonPublic| BindingFlags.Public| BindingFlags.Instance; ConstructorInfo superCtor = superClass.GetConstructor(flags,null,baseParamTypes,null); if (superCtor == null || superCtor.IsPrivate) throw new InvalidOperationException("Base class constructor missing or private"); ConstructorBuilder cb = proxyTB.DefineConstructor(MethodAttributes.Public, CallingConventions.HasThis, thisParamTypes); GenInterface.SetCustomAttributes(cb, ctorAttributes); CljILGen gen = new CljILGen(cb.GetILGenerator()); Label noInitLabel = gen.DefineLabel(); Label noPostInitLabel = gen.DefineLabel(); Label endPostInitLabel = gen.DefineLabel(); Label endLabel = gen.DefineLabel(); LocalBuilder locSuperArgs = gen.DeclareLocal(typeof(object)); LocalBuilder locInitVal = gen.DeclareLocal(typeof(object)); if (initFB != null) { // init supplied EmitGetVar(gen, initFB); gen.Emit(OpCodes.Dup); gen.Emit(OpCodes.Brfalse_S, noInitLabel); gen.Emit(OpCodes.Castclass, typeof(IFn)); // box init args for (int i = 0; i < thisParamTypes.Length; i++) { gen.EmitLoadArg(i + 1); // gen.Emit(OpCodes.Ldarg, i + 1); if (thisParamTypes[i].IsValueType) gen.Emit(OpCodes.Box,thisParamTypes[i]); } gen.EmitCall(Compiler.Methods_IFn_invoke[thisParamTypes.Length]); // gen.Emit(OpCodes.Call, Compiler.Methods_IFn_invoke[thisParamTypes.Length]); // Expecting: [[super-ctor-args...] state] // store the init return in a local gen.Emit(OpCodes.Dup); gen.Emit(OpCodes.Stloc,locInitVal); // store the first element in a local gen.EmitInt(0); // gen.Emit(OpCodes.Ldc_I4_0); gen.EmitCall(Method_RT_nth); // gen.Emit(OpCodes.Call, Method_RT_nth); gen.Emit(OpCodes.Stloc, locSuperArgs); // Stack this + super-ctor-args + call base-class ctor. gen.EmitLoadArg(0); // gen.Emit(OpCodes.Ldarg_0); for (int i = 0; i < baseParamTypes.Length; i++) { gen.Emit(OpCodes.Ldloc, locSuperArgs); gen.EmitInt(i); // gen.Emit(OpCodes.Ldc_I4, i); gen.EmitCall(Method_RT_nth); // gen.Emit(OpCodes.Call, Method_RT_nth); if (baseParamTypes[i].IsValueType) gen.Emit(OpCodes.Unbox_Any, baseParamTypes[i]); else gen.Emit(OpCodes.Castclass, baseParamTypes[i]); } gen.Emit(OpCodes.Call, superCtor); if (stateFB != null) { gen.EmitLoadArg(0); // gen.Emit(OpCodes.Ldarg_0); gen.Emit(OpCodes.Ldloc, locInitVal); gen.EmitInt(1); // gen.Emit(OpCodes.Ldc_I4_1); gen.EmitCall(Method_RT_nth); // gen.Emit(OpCodes.Call, Method_RT_nth); gen.Emit(OpCodes.Castclass, typeof(object)); gen.EmitFieldSet(stateFB); // gen.Emit(OpCodes.Stfld, stateFB); } gen.Emit(OpCodes.Br_S, endLabel); // No init found gen.MarkLabel(noInitLabel); gen.Emit(OpCodes.Pop); EmitUnsupported(gen, initName); gen.MarkLabel(endLabel); } else // no InitFB supplied. { bool ok = thisParamTypes.Length == baseParamTypes.Length; for (int i = 0; ok && i < thisParamTypes.Length; i++) ok = baseParamTypes[i].IsAssignableFrom(thisParamTypes[i]); if (!ok) throw new InvalidOperationException(":init not specified, but ctor and super ctor args differ"); gen.EmitLoadArg(0); // gen.Emit(OpCodes.Ldarg_0); for ( int i=0; i< thisParamTypes.Length; i++ ) { gen.EmitLoadArg(i + 1); // gen.Emit(OpCodes.Ldarg, i + 1); if (baseParamTypes[i] != thisParamTypes[i]) gen.Emit(OpCodes.Castclass, baseParamTypes[i]); } gen.Emit(OpCodes.Call, superCtor); } if (postInitFB != null) { // post-init supplied EmitGetVar(gen, postInitFB); gen.Emit(OpCodes.Dup); gen.Emit(OpCodes.Brfalse_S, noPostInitLabel); gen.Emit(OpCodes.Castclass, typeof(IFn)); // box init args gen.EmitLoadArg(0); // gen.Emit(OpCodes.Ldarg_0); for (int i = 0; i < thisParamTypes.Length; i++) { gen.EmitLoadArg(i + 1); // gen.Emit(OpCodes.Ldarg, i + 1); if (thisParamTypes[i].IsValueType) gen.Emit(OpCodes.Box, thisParamTypes[i]); gen.Emit(OpCodes.Castclass, thisParamTypes[i]); } gen.EmitCall(Compiler.Methods_IFn_invoke[thisParamTypes.Length + 1]); // gen.Emit(OpCodes.Call, Compiler.Methods_IFn_invoke[thisParamTypes.Length + 1]); gen.Emit(OpCodes.Pop); gen.Emit(OpCodes.Br_S, endPostInitLabel); // no post-init found gen.MarkLabel(noPostInitLabel); gen.Emit(OpCodes.Pop); EmitUnsupported(gen,postInitName + " not defined"); gen.MarkLabel(endPostInitLabel); } gen.Emit(OpCodes.Ret); if (!String.IsNullOrEmpty(factoryName)) { MethodBuilder factoryMB = proxyTB.DefineMethod(factoryName, MethodAttributes.Public | MethodAttributes.Static, CallingConventions.Standard, proxyTB, thisParamTypes); CljILGen genf = new CljILGen(factoryMB.GetILGenerator()); LocalBuilder[] locals = new LocalBuilder[thisParamTypes.Length]; for (int i = 0; i < thisParamTypes.Length; i++) { locals[i] = genf.DeclareLocal(thisParamTypes[i]); genf.EmitLoadArg(i); // genf.Emit(OpCodes.Ldarg, i); genf.Emit(OpCodes.Stloc, locals[i]); } for (int i = 0; i < thisParamTypes.Length; i++) genf.EmitLoadArg(i); // genf.Emit(OpCodes.Ldarg, i); genf.EmitNew(cb); // genf.Emit(OpCodes.Newobj, cb); genf.Emit(OpCodes.Ret); } } }
void EmitProto(RHC rhc, ObjExpr objx, CljILGen ilg) { Label onLabel = ilg.DefineLabel(); Label callLabel = ilg.DefineLabel(); Label endLabel = ilg.DefineLabel(); Var v = ((VarExpr)_fexpr).Var; Expr e = (Expr)_args.nth(0); e.Emit(RHC.Expression, objx, ilg); // target ilg.Emit(OpCodes.Dup); // target, target LocalBuilder targetTemp = ilg.DeclareLocal(typeof(Object)); GenContext.SetLocalName(targetTemp, "target"); ilg.Emit(OpCodes.Stloc, targetTemp); // target ilg.Emit(OpCodes.Call, Compiler.Method_Util_classOf); // class ilg.EmitLoadArg(0); // class, this ilg.EmitFieldGet(objx.CachedTypeField(_siteIndex)); // class, cached-class ilg.Emit(OpCodes.Beq, callLabel); // if (_protocolOn != null) { ilg.Emit(OpCodes.Ldloc, targetTemp); // target ilg.Emit(OpCodes.Isinst, _protocolOn); // null or target ilg.Emit(OpCodes.Ldnull); // (null or target), null ilg.Emit(OpCodes.Cgt_Un); // (0 or 1) ilg.Emit(OpCodes.Brtrue, onLabel); } ilg.Emit(OpCodes.Ldloc, targetTemp); // target ilg.Emit(OpCodes.Call, Compiler.Method_Util_classOf); // class LocalBuilder typeTemp = ilg.DeclareLocal(typeof(Type)); GenContext.SetLocalName(typeTemp, "type"); ilg.Emit(OpCodes.Stloc, typeTemp); // (typeType <= class) ilg.EmitLoadArg(0); // this ilg.Emit(OpCodes.Ldloc, typeTemp); // this, class ilg.EmitFieldSet(objx.CachedTypeField(_siteIndex)); // ilg.MarkLabel(callLabel); objx.EmitVar(ilg, v); // var ilg.Emit(OpCodes.Call, Compiler.Method_Var_getRawRoot); // proto-fn ilg.Emit(OpCodes.Castclass, typeof(AFunction)); ilg.Emit(OpCodes.Ldloc, targetTemp); // proto-fn, target EmitArgsAndCall(1, rhc, objx, ilg); ilg.Emit(OpCodes.Br, endLabel); ilg.MarkLabel(onLabel); ilg.Emit(OpCodes.Ldloc, targetTemp); // target if (_protocolOn != null) { ilg.Emit(OpCodes.Castclass, _protocolOn); MethodExpr.EmitTypedArgs(objx, ilg, _onMethod.GetParameters(), RT.subvec(_args, 1, _args.count())); //if (rhc == RHC.Return) //{ // ObjMethod2 method = (ObjMethod)Compiler.MethodVar.deref(); // method.EmitClearLocals(context); //} ilg.Emit(OpCodes.Callvirt, _onMethod); HostExpr.EmitBoxReturn(objx, ilg, _onMethod.ReturnType); } ilg.MarkLabel(endLabel); }
/*** * Current host interop uses reflection, which requires pre-existing classes * Work around this by: * Generate a stub class that has the same interfaces and fields as the class we are generating. * Use it as a type hint for this, and bind the simple name of the class to this stub (in resolve etc) * Unmunge the name (using a magic prefix) on any code gen for classes */ // TODO: Preparse method heads to pick up signatures, implement those methods as abstract or as NotImpelmented so that Reflection can pick up calls during compilation and avoide a callsite. static Type CompileStub(GenContext context, Type super, NewInstanceExpr ret, Type[] interfaces, Object frm) { //GenContext context = Compiler.CompilerContextVar.get() as GenContext ?? GenContext.CreateWithExternalAssembly("stub" + RT.nextID().ToString(), ".dll", false); //GenContext context = Compiler.IsCompiling ? Compiler.CompilerContextVar.get() as GenContext : GenContext.CreateWithExternalAssembly("stub" + RT.nextID().ToString(), ".dll", false); //context = GenContext.CreateWithExternalAssembly("stub" + RT.nextID().ToString(), ".dll", false); TypeBuilder tb = context.ModuleBuilder.DefineType(Compiler.CompileStubPrefix + "." + ret.InternalName + RT.nextID(), TypeAttributes.Public | TypeAttributes.Abstract, super, interfaces); tb.DefineDefaultConstructor(MethodAttributes.Public); // instance fields for closed-overs for (ISeq s = RT.keys(ret.Closes); s != null; s = s.next()) { LocalBinding lb = (LocalBinding)s.first(); FieldAttributes access = FieldAttributes.Public; // TODO: FIgure out Volatile if (!ret.IsVolatile(lb)) access |= FieldAttributes.InitOnly; if (lb.PrimitiveType != null) tb.DefineField(lb.Name, lb.PrimitiveType, access); else tb.DefineField(lb.Name, typeof(Object), access); } // ctor that takes closed-overs and does nothing if (ret.CtorTypes().Length > 0) { ConstructorBuilder cb = tb.DefineConstructor(MethodAttributes.Public, CallingConventions.HasThis, ret.CtorTypes()); CljILGen ilg = new CljILGen(cb.GetILGenerator()); ilg.EmitLoadArg(0); ilg.Emit(OpCodes.Call, super.GetConstructor(Type.EmptyTypes)); ilg.Emit(OpCodes.Ret); if (ret._altCtorDrops > 0) { Type[] ctorTypes = ret.CtorTypes(); int newLen = ctorTypes.Length - ret._altCtorDrops; if (newLen > 0) { Type[] altCtorTypes = new Type[newLen]; for (int i = 0; i < altCtorTypes.Length; i++) altCtorTypes[i] = ctorTypes[i]; ConstructorBuilder cb2 = tb.DefineConstructor(MethodAttributes.Public, CallingConventions.HasThis, altCtorTypes); CljILGen ilg2 = new CljILGen(cb2.GetILGenerator()); ilg2.EmitLoadArg(0); for (int i = 0; i < newLen; i++) ilg2.EmitLoadArg(i + 1); for (int i = 0; i < ret._altCtorDrops; i++) ilg2.EmitNull(); ilg2.Emit(OpCodes.Call, cb); ilg2.Emit(OpCodes.Ret); } } } Type t = tb.CreateType(); //Compiler.RegisterDuplicateType(t); return t; }
private ConstructorBuilder EmitFieldOnlyConstructor(TypeBuilder fnTB, Type baseType) { Type[] ctorTypes = CtorTypes(); Type[] altCtorTypes = new Type[ctorTypes.Length - _altCtorDrops]; for (int i = 0; i < altCtorTypes.Length; i++) altCtorTypes[i] = ctorTypes[i]; ConstructorBuilder cb = fnTB.DefineConstructor(MethodAttributes.Public, CallingConventions.HasThis, altCtorTypes); CljILGen gen = new CljILGen(cb.GetILGenerator()); //Call full constructor gen.EmitLoadArg(0); // gen.Emit(OpCodes.Ldarg_0); for (int i = 0; i < altCtorTypes.Length; i++) gen.EmitLoadArg(i + 1); for (int i = 0; i < _altCtorDrops; i++) gen.EmitNull(); gen.Emit(OpCodes.Call, _ctorInfo); gen.Emit(OpCodes.Ret); return cb; }
private void DoEmitStatic(ObjExpr fn, TypeBuilder tb) { MethodAttributes attribs = MethodAttributes.Static | MethodAttributes.Public; string methodName = "invokeStatic"; Type returnType = ReturnType; MethodBuilder baseMB = tb.DefineMethod(methodName, attribs, returnType, _argTypes); CljILGen baseIlg = new CljILGen(baseMB.GetILGenerator()); try { Label loopLabel = baseIlg.DefineLabel(); Var.pushThreadBindings(RT.map(Compiler.LoopLabelVar, loopLabel, Compiler.MethodVar, this)); GenContext.EmitDebugInfo(baseIlg, SpanMap); baseIlg.MarkLabel(loopLabel); EmitBody(Objx, baseIlg, _retType, Body); if (Body.HasNormalExit()) baseIlg.Emit(OpCodes.Ret); } finally { Var.popThreadBindings(); } // Generate the regular invoke, calling the static method { MethodBuilder regularMB = tb.DefineMethod(MethodName, MethodAttributes.ReuseSlot | MethodAttributes.Public | MethodAttributes.Virtual, typeof(Object), ArgTypes); SetCustomAttributes(regularMB); CljILGen regIlg = new CljILGen(regularMB.GetILGenerator()); for (int i = 0; i < _argTypes.Length; i++) { regIlg.EmitLoadArg(i + 1); HostExpr.EmitUnboxArg(fn, regIlg, _argTypes[i]); } GenContext.EmitDebugInfo(baseIlg, SpanMap); regIlg.Emit(OpCodes.Call, baseMB); if (ReturnType.IsValueType) regIlg.Emit(OpCodes.Box, ReturnType); regIlg.Emit(OpCodes.Ret); } // Generate primInvoke if prim if (Prim != null) { MethodAttributes primAttribs = MethodAttributes.ReuseSlot | MethodAttributes.Public | MethodAttributes.Virtual; string primMethodName = "invokePrim"; Type primReturnType; if (_retType == typeof(double) || _retType == typeof(long)) primReturnType = ReturnType; else primReturnType = typeof(object); MethodBuilder primMB = tb.DefineMethod(primMethodName, primAttribs, primReturnType, _argTypes); SetCustomAttributes(primMB); CljILGen primIlg = new CljILGen(primMB.GetILGenerator()); for (int i = 0; i < _argTypes.Length; i++) { primIlg.EmitLoadArg(i + 1); //HostExpr.EmitUnboxArg(fn, primIlg, _argTypes[i]); } primIlg.Emit(OpCodes.Call, baseMB); if (Body.HasNormalExit()) primIlg.Emit(OpCodes.Ret); } }
private ConstructorBuilder EmitNonMetaConstructor(TypeBuilder fnTB, Type baseType) { Type[] ctorTypes = CtorTypes(); Type[] noMetaCtorTypes = new Type[ctorTypes.Length - 1]; for (int i = 1; i < ctorTypes.Length; i++) noMetaCtorTypes[i - 1] = ctorTypes[i]; ConstructorBuilder cb = fnTB.DefineConstructor(MethodAttributes.Public, CallingConventions.HasThis, noMetaCtorTypes); CljILGen gen = new CljILGen(cb.GetILGenerator()); gen.EmitLoadArg(0); gen.EmitNull(); // null meta for (int i = 0; i < noMetaCtorTypes.Length; i++) gen.EmitLoadArg(i + 1); gen.Emit(OpCodes.Call, _ctorInfo); gen.Emit(OpCodes.Ret); return cb; }
static void EmitMain(GenContext context, TypeBuilder proxyTB, string mainName, FieldBuilder mainFB) { MethodBuilder cb = proxyTB.DefineMethod("Main",MethodAttributes.Public| MethodAttributes.Static,CallingConventions.Standard,typeof(void),new Type[] { typeof(String[]) }); CljILGen gen = new CljILGen(cb.GetILGenerator()); ; Label noMainLabel = gen.DefineLabel(); Label endLabel = gen.DefineLabel(); EmitGetVar(gen, mainFB); gen.Emit(OpCodes.Dup); gen.Emit(OpCodes.Brfalse_S, noMainLabel); gen.Emit(OpCodes.Castclass, typeof(IFn)); gen.EmitLoadArg(0); // gen.Emit(OpCodes.Ldarg_0); gen.EmitCall(Method_RT_seq); // gen.Emit(OpCodes.Call, Method_RT_seq); gen.EmitCall(Method_IFn_applyTo_Object_ISeq); // gen.Emit(OpCodes.Call, Method_IFn_applyTo_Object_ISeq); gen.Emit(OpCodes.Pop); gen.Emit(OpCodes.Br_S, endLabel); // no main found gen.MarkLabel(noMainLabel); EmitUnsupported(gen, mainName); gen.MarkLabel(endLabel); gen.Emit(OpCodes.Ret); //context.AssyBldr.SetEntryPoint(cb); context.AssemblyBuilder.SetEntryPoint(cb); }
internal void EmitLocal(CljILGen ilg, LocalBinding lb) { Type primType = lb.PrimitiveType; if (Closes.containsKey(lb)) { ilg.Emit(OpCodes.Ldarg_0); // this FieldBuilder fb = _closedOverFieldsMap[lb]; ilg.MaybeEmitVolatileOp(IsVolatile(lb)); ilg.Emit(OpCodes.Ldfld, fb); if (primType != null) HostExpr.EmitBoxReturn(this, ilg, primType); // TODO: ONCEONLY? } else { if (lb.IsArg) { //int argOffset = IsStatic ? 1 : 0; //ilg.Emit(OpCodes.Ldarg, lb.Index - argOffset); ilg.EmitLoadArg(lb.Index); } else if (lb.IsThis) { ilg.EmitLoadArg(0); } else { ilg.Emit(OpCodes.Ldloc, lb.LocalVar); } if (primType != null) HostExpr.EmitBoxReturn(this, ilg, primType); } }
private void DoEmitPrim(ObjExpr fn, TypeBuilder tb) { MethodAttributes attribs = MethodAttributes.ReuseSlot | MethodAttributes.Public | MethodAttributes.Virtual; string methodName = "invokePrim"; Type returnType; if (_retType == typeof(double) || _retType == typeof(long)) { returnType = ReturnType; } else { returnType = typeof(object); } MethodBuilder baseMB = tb.DefineMethod(methodName, attribs, returnType, _argTypes); SetCustomAttributes(baseMB); CljILGen baseIlg = new CljILGen(baseMB.GetILGenerator()); try { Label loopLabel = baseIlg.DefineLabel(); Var.pushThreadBindings(RT.map(Compiler.LoopLabelVar, loopLabel, Compiler.MethodVar, this)); GenContext.EmitDebugInfo(baseIlg, SpanMap); baseIlg.MarkLabel(loopLabel); EmitBody(Objx, baseIlg, _retType, Body); if (Body.HasNormalExit()) { baseIlg.Emit(OpCodes.Ret); } } finally { Var.popThreadBindings(); } // Generate the regular invoke, calling the prim method MethodBuilder regularMB = tb.DefineMethod(MethodName, MethodAttributes.ReuseSlot | MethodAttributes.Public | MethodAttributes.Virtual, typeof(Object), ArgTypes); SetCustomAttributes(regularMB); CljILGen regIlg = new CljILGen(regularMB.GetILGenerator()); regIlg.Emit(OpCodes.Ldarg_0); for (int i = 0; i < _argTypes.Length; i++) { regIlg.EmitLoadArg(i + 1); HostExpr.EmitUnboxArg(fn, regIlg, _argTypes[i]); } regIlg.Emit(OpCodes.Call, baseMB); if (ReturnType.IsValueType) { regIlg.Emit(OpCodes.Box, ReturnType); } regIlg.Emit(OpCodes.Ret); }
protected static void EmitHasArityMethod(TypeBuilder tb, IList<int> arities, bool isVariadic, int reqArity) { // TODO: Convert to a Switch instruction MethodBuilder mb = tb.DefineMethod( "HasArity", MethodAttributes.ReuseSlot | MethodAttributes.Public | MethodAttributes.Virtual, typeof(bool), new Type[] { typeof(int) }); CljILGen gen = new CljILGen(mb.GetILGenerator()); Label falseLabel = gen.DefineLabel(); Label trueLabel = gen.DefineLabel(); if (isVariadic) { gen.EmitLoadArg(1); gen.EmitInt(reqArity); gen.Emit(OpCodes.Bge, trueLabel); } if (arities != null) { foreach (int i in arities) { gen.EmitLoadArg(1); gen.EmitInt(i); gen.Emit(OpCodes.Beq, trueLabel); } } gen.MarkLabel(falseLabel); gen.EmitBoolean(false); gen.Emit(OpCodes.Ret); gen.MarkLabel(trueLabel); gen.EmitBoolean(true); gen.Emit(OpCodes.Ret); }
private static FieldBuilder AddIProxyMethods(TypeBuilder proxyTB) { FieldBuilder fb = proxyTB.DefineField( _methodMapFieldName, typeof(IPersistentMap), FieldAttributes.Private); MethodBuilder initMb = proxyTB.DefineMethod( "__initClojureFnMappings", MethodAttributes.Public|MethodAttributes.Virtual|MethodAttributes.HideBySig, typeof(void), new Type[] { typeof(IPersistentMap) }); CljILGen gen = new CljILGen(initMb.GetILGenerator()); gen.EmitLoadArg(0); // gen.Emit(OpCodes.Ldarg_0); gen.EmitLoadArg(1); // gen.Emit(OpCodes.Ldarg_1); gen.EmitFieldSet(fb); // gen.Emit(OpCodes.Stfld, fb); gen.Emit(OpCodes.Ret); MethodBuilder updateTB = proxyTB.DefineMethod( "__updateClojureFnMappings", MethodAttributes.Public | MethodAttributes.Virtual | MethodAttributes.HideBySig, typeof(void), new Type[] { typeof(IPersistentMap) }); gen = new CljILGen(updateTB.GetILGenerator()); gen.EmitLoadArg(0); // gen.Emit(OpCodes.Ldarg_0); gen.Emit(OpCodes.Dup); gen.EmitFieldGet(fb); // gen.Emit(OpCodes.Ldfld, fb); gen.Emit(OpCodes.Castclass, typeof(IPersistentMap)); gen.EmitLoadArg(1); // gen.Emit(OpCodes.Ldarg_1); gen.EmitCall(Method_IPersistentMap_Cons); //gen.Emit(OpCodes.Call, Method_IPersistentCollection_Cons); gen.EmitFieldSet(fb); // gen.Emit(OpCodes.Stfld, fb); gen.Emit(OpCodes.Ret); MethodBuilder getMb = proxyTB.DefineMethod( "__getClojureFnMappings", MethodAttributes.Public | MethodAttributes.Virtual | MethodAttributes.HideBySig, typeof(IPersistentMap), Type.EmptyTypes); gen = new CljILGen(getMb.GetILGenerator()); gen.EmitLoadArg(0); // gen.Emit(OpCodes.Ldarg_0); gen.EmitFieldGet(fb); // gen.Emit(OpCodes.Ldfld, fb); gen.Emit(OpCodes.Ret); return fb; }
private void DoEmitPrimOrStatic(ObjExpr fn, TypeBuilder tb, bool isStatic) { MethodAttributes attribs = isStatic ? MethodAttributes.Static | MethodAttributes.Public : MethodAttributes.ReuseSlot | MethodAttributes.Public | MethodAttributes.Virtual; string methodName = isStatic ? "invokeStatic" : "invokePrim"; MethodBuilder baseMB = tb.DefineMethod(methodName, attribs, GetReturnType(), _argTypes); if ( ! isStatic ) SetCustomAttributes(baseMB); CljILGen baseIlg = new CljILGen(baseMB.GetILGenerator()); try { Label loopLabel = baseIlg.DefineLabel(); Var.pushThreadBindings(RT.map(Compiler.LoopLabelVar,loopLabel,Compiler.MethodVar,this)); GenContext.EmitDebugInfo(baseIlg, SpanMap); baseIlg.MarkLabel(loopLabel); EmitBody(Objx, baseIlg, _retType, _body); if ( _body.HasNormalExit() ) baseIlg.Emit(OpCodes.Ret); } finally { Var.popThreadBindings(); } // Generate the regular invoke, calling the static or prim method MethodBuilder regularMB = tb.DefineMethod(GetMethodName(), MethodAttributes.ReuseSlot | MethodAttributes.Public | MethodAttributes.Virtual, typeof(Object), GetArgTypes()); SetCustomAttributes(regularMB); CljILGen regIlg = new CljILGen(regularMB.GetILGenerator()); if ( ! isStatic ) regIlg.Emit(OpCodes.Ldarg_0); for(int i = 0; i < _argTypes.Length; i++) { regIlg.EmitLoadArg(i+1); HostExpr.EmitUnboxArg(fn, regIlg, _argTypes[i]); } regIlg.Emit(OpCodes.Call,baseMB); if ( GetReturnType().IsValueType) regIlg.Emit(OpCodes.Box,GetReturnType()); regIlg.Emit(OpCodes.Ret); }
private static void DefineCtor(TypeBuilder proxyTB, ConstructorInfo ctor) { ParameterInfo[] pinfos = ctor.GetParameters(); Type[] paramTypes = new Type[pinfos.Length]; for (int i = 0; i < pinfos.Length; i++) paramTypes[i] = pinfos[i].ParameterType; ConstructorBuilder cb = proxyTB.DefineConstructor(ctor.Attributes, CallingConventions.HasThis, paramTypes); // Call base class ctor on all the args CljILGen gen = new CljILGen(cb.GetILGenerator()); gen.EmitLoadArg(0); // gen.Emit(OpCodes.Ldarg_0); for (int i = 0; i < pinfos.Length; i++) gen.EmitLoadArg(i + 1); // gen.Emit(OpCodes.Ldarg, i + 1); gen.Emit(OpCodes.Call, ctor); gen.Emit(OpCodes.Ret); }
internal void EmitLocal(CljILGen ilg, LocalBinding lb) { Type primType = lb.PrimitiveType; if (Closes.containsKey(lb)) { if (_fnMode == FnMode.Full) { ilg.Emit(OpCodes.Ldarg_0); // this FieldBuilder fb = _closedOverFieldsMap[lb]; ilg.MaybeEmitVolatileOp(IsVolatile(lb)); ilg.Emit(OpCodes.Ldfld, fb); if (primType != null) HostExpr.EmitBoxReturn(this, ilg, primType); // TODO: ONCEONLY? } else // FnMode.Light { ilg.Emit(OpCodes.Ldarg_0); // this ilg.Emit(OpCodes.Castclass, typeof(IFnClosure)); ilg.EmitCall(Compiler.Method_IFnClosure_GetClosure); ilg.EmitFieldGet(Compiler.Field_Closure_Locals); ilg.EmitInt(lb.Index); ilg.EmitLoadElement(typeof(Object)); } } else { if (lb.IsArg) { //int argOffset = IsStatic ? 1 : 0; //ilg.Emit(OpCodes.Ldarg, lb.Index - argOffset); ilg.EmitLoadArg(lb.Index); } else if (lb.IsThis) { ilg.EmitLoadArg(0); } else { ilg.Emit(OpCodes.Ldloc, lb.LocalVar); } if (primType != null) HostExpr.EmitBoxReturn(this, ilg, primType); } }
private static void GenerateProxyMethod( TypeBuilder proxyTB, FieldBuilder mapField, MethodInfo m, HashSet<MethodBuilder> specialMethods) { MethodAttributes attribs = m.Attributes; bool callBaseMethod; if ( (attribs & MethodAttributes.Abstract) == MethodAttributes.Abstract ) { attribs &= ~MethodAttributes.Abstract; callBaseMethod = false; } else { callBaseMethod = true; } attribs &= ~MethodAttributes.NewSlot; attribs |= MethodAttributes.Virtual | MethodAttributes.HideBySig | MethodAttributes.Public; //Console.Write("Generating proxy method {0}(", m.Name); //foreach (ParameterInfo p in m.GetParameters()) // Console.Write("{0}, ", p.ParameterType.FullName); //Console.Write(") "); //Console.WriteLine(attribs.ToString()); MethodBuilder proxym = proxyTB.DefineMethod( m.Name, attribs, m.CallingConvention, m.ReturnType, m.GetParameters().Select<ParameterInfo, Type>(p => p.ParameterType).ToArray<Type>()); if (m.IsSpecialName) specialMethods.Add(proxym); CljILGen gen = new CljILGen(proxym.GetILGenerator()); Label elseLabel = gen.DefineLabel(); Label endLabel = gen.DefineLabel(); //// Print a little message, for debugging purposes //gen.Emit(OpCodes.Ldstr, String.Format("Calling {0} / {1}", proxyTB.FullName, m.ToString())); //gen.Emit(OpCodes.Call, typeof(Console).GetMethod("WriteLine", // new Type[] { typeof(string) })); //gen.Emit(OpCodes.Call, typeof(Console).GetMethod("get_Out")); //gen.Emit(OpCodes.Call, typeof(System.IO.TextWriter).GetMethod("Flush")); // Lookup method name in map gen.EmitLoadArg(0); // gen.Emit(OpCodes.Ldarg_0); gen.EmitFieldGet(mapField); // gen.Emit(OpCodes.Ldfld, mapField); gen.EmitString(m.Name); // gen.Emit(OpCodes.Ldstr, m.Name); gen.EmitCall(Method_RT_get); // gen.Emit(OpCodes.Call, Method_RT_get); gen.Emit(OpCodes.Dup); gen.EmitNull(); // gen.Emit(OpCodes.Ldnull); gen.Emit(OpCodes.Beq_S, elseLabel); // map entry found ParameterInfo[] pinfos = m.GetParameters(); gen.Emit(OpCodes.Castclass, typeof(IFn)); gen.EmitLoadArg(0); // gen.Emit(OpCodes.Ldarg_0); // push implicit 'this' arg. for (int i = 0; i < pinfos.Length; i++) { gen.EmitLoadArg(i + 1); // gen.Emit(OpCodes.Ldarg, i + 1); if (m.GetParameters()[i].ParameterType.IsValueType) gen.Emit(OpCodes.Box,pinfos[i].ParameterType); } int parmCount = pinfos.Length; gen.EmitCall(GetIFnInvokeMethodInfo(parmCount+1)); // gen.Emit(OpCodes.Call, GetIFnInvokeMethodInfo(parmCount + 1)); if (m.ReturnType == typeof(void)) gen.Emit(OpCodes.Pop); else gen.Emit(OpCodes.Unbox_Any, m.ReturnType); gen.Emit(OpCodes.Br_S,endLabel); // map entry not found gen.MarkLabel(elseLabel); gen.Emit(OpCodes.Pop); // get rid of null leftover from the 'get' if ( callBaseMethod ) { gen.EmitLoadArg(0); // gen.Emit(OpCodes.Ldarg_0); for (int i = 0; i < parmCount; i++) gen.EmitLoadArg(i + 1); // gen.Emit(OpCodes.Ldarg, i + 1); gen.Emit(OpCodes.Call, m); // gen.EmitCall(m) improperly emits a callvirt in some cases } else { gen.EmitString(m.Name); // gen.Emit(OpCodes.Ldstr, m.Name); gen.EmitNew(CtorInfo_NotImplementedException_1); // gen.Emit(OpCodes.Newobj, CtorInfo_NotImplementedException_1); gen.Emit(OpCodes.Throw); } gen.MarkLabel(endLabel); gen.Emit(OpCodes.Ret); }
private static void EmitExposers(TypeBuilder proxyTB, Type superClass, IPersistentMap exposesFields) { for ( ISeq s = RT.seq(exposesFields); s != null; s = s.next() ) { IMapEntry me = (IMapEntry)s.first(); Symbol protectedFieldSym = (Symbol)me.key(); IPersistentMap accessMap = (IPersistentMap)me.val(); string fieldName = protectedFieldSym.Name; Symbol getterSym = (Symbol)accessMap.valAt(_getKw, null); Symbol setterSym = (Symbol)accessMap.valAt(_setKW, null); FieldInfo fld = null; if ( getterSym != null || setterSym != null ) fld = superClass.GetField(fieldName, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.FlattenHierarchy | BindingFlags.Static | BindingFlags.Instance); if (getterSym != null) { MethodAttributes attribs = MethodAttributes.Public; if (fld.IsStatic) attribs |= MethodAttributes.Static; MethodBuilder mb = proxyTB.DefineMethod(getterSym.Name, attribs, fld.FieldType, Type.EmptyTypes); CljILGen gen = new CljILGen(mb.GetILGenerator()); //if (fld.IsStatic) // gen.Emit(OpCodes.Ldsfld, fld); //else //{ // gen.Emit(OpCodes.Ldarg_0); // gen.Emit(OpCodes.Ldfld, fld); //} if (!fld.IsStatic) gen.EmitLoadArg(0); gen.MaybeEmitVolatileOp(fld); gen.EmitFieldGet(fld); gen.Emit(OpCodes.Ret); } if (setterSym != null) { MethodAttributes attribs = MethodAttributes.Public; if (fld.IsStatic) attribs |= MethodAttributes.Static; MethodBuilder mb = proxyTB.DefineMethod(setterSym.Name, attribs, typeof(void), new Type[] { fld.FieldType }); CljILGen gen = new CljILGen(mb.GetILGenerator()); if (fld.IsStatic) { gen.Emit(OpCodes.Ldarg_0); //gen.Emit(OpCodes.Stsfld, fld); } else { gen.Emit(OpCodes.Ldarg_0); gen.Emit(OpCodes.Ldarg_1); //gen.Emit(OpCodes.Stfld, fld); } gen.MaybeEmitVolatileOp(fld); gen.EmitFieldSet(fld); gen.Emit(OpCodes.Ret); } } }
void EmitProto(RHC rhc, ObjExpr objx, CljILGen ilg) { Label onLabel = ilg.DefineLabel(); Label callLabel = ilg.DefineLabel(); Label endLabel = ilg.DefineLabel(); Var v = ((VarExpr)_fexpr).Var; Expr e = (Expr)_args.nth(0); e.Emit(RHC.Expression, objx, ilg); // target ilg.Emit(OpCodes.Dup); // target, target LocalBuilder targetTemp = ilg.DeclareLocal(typeof(Object)); GenContext.SetLocalName(targetTemp, "target"); ilg.Emit(OpCodes.Stloc,targetTemp); // target ilg.Emit(OpCodes.Call,Compiler.Method_Util_classOf); // class ilg.EmitLoadArg(0); // class, this ilg.EmitFieldGet(objx.CachedTypeField(_siteIndex)); // class, cached-class ilg.Emit(OpCodes.Beq, callLabel); // if (_protocolOn != null) { ilg.Emit(OpCodes.Ldloc,targetTemp); // target ilg.Emit(OpCodes.Isinst, _protocolOn); // null or target ilg.Emit(OpCodes.Ldnull); // (null or target), null ilg.Emit(OpCodes.Cgt_Un); // (0 or 1) ilg.Emit(OpCodes.Brtrue, onLabel); } ilg.Emit(OpCodes.Ldloc,targetTemp); // target ilg.Emit(OpCodes.Call,Compiler.Method_Util_classOf); // class LocalBuilder typeTemp = ilg.DeclareLocal(typeof(Type)); GenContext.SetLocalName(typeTemp, "type"); ilg.Emit(OpCodes.Stloc,typeTemp); // (typeType <= class) ilg.EmitLoadArg(0); // this ilg.Emit(OpCodes.Ldloc,typeTemp); // this, class ilg.EmitFieldSet(objx.CachedTypeField(_siteIndex)); // ilg.MarkLabel(callLabel); objx.EmitVar(ilg,v); // var ilg.Emit(OpCodes.Call,Compiler.Method_Var_getRawRoot); // proto-fn ilg.Emit(OpCodes.Castclass, typeof(AFunction)); ilg.Emit(OpCodes.Ldloc,targetTemp); // proto-fn, target EmitArgsAndCall(1,rhc,objx,ilg); ilg.Emit(OpCodes.Br,endLabel); ilg.MarkLabel(onLabel); ilg.Emit(OpCodes.Ldloc,targetTemp); // target if ( _protocolOn != null ) { ilg.Emit(OpCodes.Castclass, _protocolOn); MethodExpr.EmitTypedArgs(objx, ilg, _onMethod.GetParameters(), RT.subvec(_args, 1, _args.count())); //if (rhc == RHC.Return) //{ // ObjMethod2 method = (ObjMethod)Compiler.MethodVar.deref(); // method.EmitClearLocals(context); //} ilg.Emit(OpCodes.Callvirt, _onMethod); HostExpr.EmitBoxReturn(objx, ilg, _onMethod.ReturnType); } ilg.MarkLabel(endLabel); }
private static void EmitForwardingMethod(TypeBuilder proxyTB, bool isStatic, FieldBuilder regularFB, FieldBuilder overloadFB, MethodSignature sig, ElseGenDelegate elseGen) { MethodAttributes attributes; CallingConventions conventions; if (isStatic) { attributes = MethodAttributes.Public | MethodAttributes.Static; conventions = CallingConventions.Standard; } else { attributes = MethodAttributes.Public | MethodAttributes.Virtual; conventions = CallingConventions.HasThis; } MethodBuilder mb = proxyTB.DefineMethod(sig.Name, attributes, conventions, sig.ReturnType, sig.ParamTypes); CljILGen gen = new CljILGen(mb.GetILGenerator()); Label foundLabel = gen.DefineLabel(); Label elseLabel = gen.DefineLabel(); Label endLabel = gen.DefineLabel(); if (sig.ParamTypes.Length > 18) elseGen(gen); else { if (overloadFB != null) { EmitGetVar(gen, overloadFB); gen.Emit(OpCodes.Dup); gen.Emit(OpCodes.Brtrue_S, foundLabel); gen.Emit(OpCodes.Pop); } EmitGetVar(gen, regularFB); gen.Emit(OpCodes.Dup); gen.Emit(OpCodes.Brfalse_S, elseLabel); if (overloadFB != null) gen.MarkLabel(foundLabel); gen.Emit(OpCodes.Castclass, typeof(IFn)); if (!isStatic) gen.EmitLoadArg(0); // gen.Emit(OpCodes.Ldarg_0); for (int i = 0; i < sig.ParamTypes.Length; i++) { gen.EmitLoadArg(isStatic ? i : i + 1); // gen.Emit(OpCodes.Ldarg, i + 1); if (sig.ParamTypes[i].IsValueType) gen.Emit(OpCodes.Box, sig.ParamTypes[i]); } gen.EmitCall(Compiler.Methods_IFn_invoke[sig.ParamTypes.Length + (isStatic ? 0 : 1)]); //gen.Emit(OpCodes.Call, Compiler.Methods_IFn_invoke[sig.ParamTypes.Length + (isStatic ? 0 : 1)]); if (sig.ReturnType == typeof(void)) gen.Emit(OpCodes.Pop); else if (sig.ReturnType.IsValueType) gen.Emit(OpCodes.Unbox_Any,sig.ReturnType); gen.Emit(OpCodes.Br_S, endLabel); gen.MarkLabel(elseLabel); gen.Emit(OpCodes.Pop); elseGen(gen); gen.MarkLabel(endLabel); gen.Emit(OpCodes.Ret); } }
static public void EmitDynamicCallPreamble(DynamicExpression dyn, IPersistentMap spanMap, string methodName, Type returnType, IList <ParameterExpression> paramExprs, Type[] paramTypes, CljILGen ilg, out LambdaExpression lambda, out Type delType, out MethodBuilder mbLambda) { Expression call = dyn; GenContext context = Compiler.CompilerContextVar.deref() as GenContext; DynInitHelper.SiteInfo siteInfo; if (context != null && context.DynInitHelper != null) { call = context.DynInitHelper.ReduceDyn(dyn, out siteInfo); } else { throw new InvalidOperationException("Don't know how to handle callsite in this case"); } if (returnType == typeof(void)) { call = Expression.Block(call, Expression.Default(typeof(object))); returnType = typeof(object); } else if (returnType != call.Type) { call = Expression.Convert(call, returnType); } call = GenContext.AddDebugInfo(call, spanMap); delType = Microsoft.Scripting.Generation.Snippets.Shared.DefineDelegate("__interop__", returnType, paramTypes); lambda = Expression.Lambda(delType, call, paramExprs); mbLambda = null; if (context == null) { // light compile Delegate d = lambda.Compile(); int key = RT.nextID(); CacheDelegate(key, d); ilg.EmitInt(key); ilg.Emit(OpCodes.Call, Method_MethodExpr_GetDelegate); ilg.Emit(OpCodes.Castclass, delType); } else { mbLambda = context.TB.DefineMethod(methodName, MethodAttributes.Static | MethodAttributes.Public, CallingConventions.Standard, returnType, paramTypes); //lambda.CompileToMethod(mbLambda); // Now we get to do all this code create by hand. // the primary code is // (loc1 = fb).Target.Invoke(loc1,*args); // if return type if void, pop the value and push a null // if return type does not match the call site, add a conversion CljILGen ilg2 = new CljILGen(mbLambda.GetILGenerator()); ilg2.EmitFieldGet(siteInfo.FieldBuilder); ilg2.Emit(OpCodes.Dup); LocalBuilder siteVar = ilg2.DeclareLocal(siteInfo.DelegateType); ilg2.Emit(OpCodes.Stloc, siteVar); ilg2.EmitFieldGet(siteInfo.SiteType.GetField("Target")); ilg2.Emit(OpCodes.Ldloc, siteVar); for (int i = 0; i < paramExprs.Count; i++) { ilg2.EmitLoadArg(i); } ilg2.EmitCall(siteInfo.DelegateType.GetMethod("Invoke")); if (returnType == typeof(void)) { ilg2.Emit(OpCodes.Pop); ilg2.EmitNull(); } else if (returnType != call.Type) { EmitConvertToType(ilg2, call.Type, returnType, false); } ilg2.Emit(OpCodes.Ret); /* * return Expression.Block( * new[] { site }, * Expression.Call( * Expression.Field( * Expression.Assign(site, access), * cs.GetType().GetField("Target") * ), * node.DelegateType.GetMethod("Invoke"), * ClrExtensions.ArrayInsert(site, node.Arguments) * ) */ } }