/*** * 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 */ static Type CompileStub(Type super, NewInstanceExpr ret, Type[] interfaces, Object frm) { GenContext context = Compiler.CompilerContextVar.get() as GenContext ?? GenContext.CreateWithExternalAssembly("stub" + RT.nextID().ToString(), ".dll", false); TypeBuilder tb = context.ModuleBuilder.DefineType(Compiler.CompileStubPrefix + "." + ret.InternalName, 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()); ILGen ilg = new ILGen(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); ILGen ilg2 = new ILGen(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 static ObjExpr Build( IPersistentVector interfaceSyms, IPersistentVector fieldSyms, Symbol thisSym, string tagName, Symbol className, Symbol typeTag, ISeq methodForms, Object frm) { NewInstanceExpr ret = new NewInstanceExpr(null); ret._src = frm; ret._name = className.ToString(); ret._classMeta = GenInterface.ExtractAttributes(RT.meta(className)); ret.InternalName = ret.Name; // ret.Name.Replace('.', '/'); // Java: ret.objtype = Type.getObjectType(ret.internalName); if (thisSym != null) { ret._thisName = thisSym.Name; } if (fieldSyms != null) { IPersistentMap fmap = PersistentHashMap.EMPTY; object[] closesvec = new object[2 * fieldSyms.count()]; for (int i = 0; i < fieldSyms.count(); i++) { Symbol sym = (Symbol)fieldSyms.nth(i); LocalBinding lb = new LocalBinding(-1, sym, null, new MethodParamExpr(Compiler.TagType(Compiler.TagOf(sym))), false, false); fmap = fmap.assoc(sym, lb); closesvec[i * 2] = lb; closesvec[i * 2 + 1] = lb; } // Java TODO: inject __meta et al into closes - when? // use array map to preserve ctor order ret._closes = new PersistentArrayMap(closesvec); ret._fields = fmap; for (int i = fieldSyms.count() - 1; i >= 0 && ((Symbol)fieldSyms.nth(i)).Name.StartsWith("__"); --i) { ret._altCtorDrops++; } } // Java TODO: set up volatiles //ret._volatiles = PersistentHashSet.create(RT.seq(RT.get(ret._optionsMap, volatileKey))); IPersistentVector interfaces = PersistentVector.EMPTY; for (ISeq s = RT.seq(interfaceSyms); s != null; s = s.next()) { Type t = (Type)Compiler.Resolve((Symbol)s.first()); if (!t.IsInterface) { throw new ParseException("only interfaces are supported, had: " + t.Name); } interfaces = interfaces.cons(t); } Type superClass = typeof(Object); Dictionary <IPersistentVector, List <MethodInfo> > overrideables; GatherMethods(superClass, RT.seq(interfaces), out overrideables); ret._methodMap = overrideables; //string[] inames = InterfaceNames(interfaces); Type stub = CompileStub(superClass, ret, SeqToTypeArray(interfaces), frm); Symbol thisTag = Symbol.intern(null, stub.FullName); //Symbol stubTag = Symbol.intern(null,stub.FullName); //Symbol thisTag = Symbol.intern(null, tagName); // Needs its own GenContext so it has its own DynInitHelper // Can't reuse Compiler.EvalContext if it is a DefType because we have to use the given name and will get a conflict on redefinition GenContext context = Compiler.CompilerContextVar.get() as GenContext ?? (ret.IsDefType ? GenContext.CreateWithExternalAssembly("deftype" + RT.nextID().ToString(), ".dll", true) : Compiler.EvalContext); GenContext genC = context.WithNewDynInitHelper(ret.InternalName + "__dynInitHelper_" + RT.nextID().ToString()); //genC.FnCompileMode = FnMode.Full; try { Var.pushThreadBindings( RT.map( Compiler.ConstantsVar, PersistentVector.EMPTY, Compiler.ConstantIdsVar, new IdentityHashMap(), Compiler.KeywordsVar, PersistentHashMap.EMPTY, Compiler.VarsVar, PersistentHashMap.EMPTY, Compiler.KeywordCallsitesVar, PersistentVector.EMPTY, Compiler.ProtocolCallsitesVar, PersistentVector.EMPTY, Compiler.VarCallsitesVar, Compiler.EmptyVarCallSites(), Compiler.NoRecurVar, null, Compiler.CompilerContextVar, genC )); if (ret.IsDefType) { Var.pushThreadBindings( RT.map( Compiler.MethodVar, null, Compiler.LocalEnvVar, ret._fields, Compiler.CompileStubSymVar, Symbol.intern(null, tagName), Compiler.CompileStubClassVar, stub )); ret._hintedFields = RT.subvec(fieldSyms, 0, fieldSyms.count() - ret._altCtorDrops); } // now (methodname [args] body)* // TODO: SourceLocation? //ret.line = (Integer)LINE.deref(); IPersistentCollection methods = null; for (ISeq s = methodForms; s != null; s = RT.next(s)) { NewInstanceMethod m = NewInstanceMethod.Parse(ret, (ISeq)RT.first(s), thisTag, overrideables); methods = RT.conj(methods, m); } ret.Methods = methods; ret.Keywords = (IPersistentMap)Compiler.KeywordsVar.deref(); ret.Vars = (IPersistentMap)Compiler.VarsVar.deref(); ret.Constants = (PersistentVector)Compiler.ConstantsVar.deref(); ret._constantsID = RT.nextID(); ret.KeywordCallsites = (IPersistentVector)Compiler.KeywordCallsitesVar.deref(); ret.ProtocolCallsites = (IPersistentVector)Compiler.ProtocolCallsitesVar.deref(); ret.VarCallsites = (IPersistentSet)Compiler.VarCallsitesVar.deref(); } finally { if (ret.IsDefType) { Var.popThreadBindings(); } Var.popThreadBindings(); } // TOD: Really, the first stub here should be 'superclass' but can't handle hostexprs nested in method bodies -- reify method compilation takes place before this sucker is compiled, so can't replace the call. // Might be able to flag stub classes and not try to convert, leading to a dynsite. ret.Compile(stub, stub, interfaces, false, genC); Compiler.RegisterDuplicateType(ret.CompiledType); return(ret); }
internal static ObjExpr Build( IPersistentVector interfaceSyms, IPersistentVector fieldSyms, Symbol thisSym, string tagName, Symbol className, Symbol typeTag, ISeq methodForms, Object frm) { NewInstanceExpr ret = new NewInstanceExpr(null); ret._src = frm; ret._name = className.ToString(); ret._classMeta = GenInterface.ExtractAttributes(RT.meta(className)); ret.InternalName = ret.Name; // ret.Name.Replace('.', '/'); // Java: ret.objtype = Type.getObjectType(ret.internalName); if (thisSym != null) ret._thisName = thisSym.Name; if (fieldSyms != null) { IPersistentMap fmap = PersistentHashMap.EMPTY; object[] closesvec = new object[2 * fieldSyms.count()]; for (int i = 0; i < fieldSyms.count(); i++) { Symbol sym = (Symbol)fieldSyms.nth(i); LocalBinding lb = new LocalBinding(-1, sym, null, new MethodParamExpr(Compiler.TagType(Compiler.TagOf(sym))), false, false); fmap = fmap.assoc(sym, lb); closesvec[i * 2] = lb; closesvec[i * 2 + 1] = lb; } // Java TODO: inject __meta et al into closes - when? // use array map to preserve ctor order ret._closes = new PersistentArrayMap(closesvec); ret._fields = fmap; for (int i = fieldSyms.count() - 1; i >= 0 && ((Symbol)fieldSyms.nth(i)).Name.StartsWith("__"); --i) ret._altCtorDrops++; } // Java TODO: set up volatiles //ret._volatiles = PersistentHashSet.create(RT.seq(RT.get(ret._optionsMap, volatileKey))); IPersistentVector interfaces = PersistentVector.EMPTY; for (ISeq s = RT.seq(interfaceSyms); s != null; s = s.next()) { Type t = (Type)Compiler.Resolve((Symbol)s.first()); if (!t.IsInterface) throw new ArgumentException("only interfaces are supported, had: " + t.Name); interfaces = interfaces.cons(t); } Type superClass = typeof(Object); Dictionary<IPersistentVector, List<MethodInfo>> overrideables; GatherMethods(superClass, RT.seq(interfaces), out overrideables); ret._methodMap = overrideables; //string[] inames = InterfaceNames(interfaces); Type stub = CompileStub(superClass, ret, SeqToTypeArray(interfaces),frm); Symbol thisTag = Symbol.intern(null, stub.FullName); //Symbol stubTag = Symbol.intern(null,stub.FullName); //Symbol thisTag = Symbol.intern(null, tagName); // Needs its own GenContext so it has its own DynInitHelper // Can't reuse Compiler.EvalContext if it is a DefType because we have to use the given name and will get a conflict on redefinition GenContext context = Compiler.COMPILER_CONTEXT.get() as GenContext ?? (ret.IsDefType ? new GenContext("deftype" + RT.nextID().ToString(),".dll",".",true) : Compiler.EvalContext); GenContext genC = context.WithNewDynInitHelper(ret.InternalName + "__dynInitHelper_" + RT.nextID().ToString()); //genC.FnCompileMode = FnMode.Full; try { Var.pushThreadBindings( RT.map( Compiler.CONSTANTS, PersistentVector.EMPTY, Compiler.CONSTANT_IDS, new IdentityHashMap(), Compiler.KEYWORDS, PersistentHashMap.EMPTY, Compiler.VARS, PersistentHashMap.EMPTY, Compiler.KEYWORD_CALLSITES, PersistentVector.EMPTY, Compiler.PROTOCOL_CALLSITES, PersistentVector.EMPTY, Compiler.VAR_CALLSITES, PersistentVector.EMPTY, Compiler.COMPILER_CONTEXT, genC )); if (ret.IsDefType) { Var.pushThreadBindings( RT.map( Compiler.METHOD, null, Compiler.LOCAL_ENV, ret._fields, Compiler.COMPILE_STUB_SYM, Symbol.intern(null, tagName), Compiler.COMPILE_STUB_CLASS, stub )); } // now (methodname [args] body)* // TODO: SourceLocation? //ret.line = (Integer)LINE.deref(); IPersistentCollection methods = null; for (ISeq s = methodForms; s != null; s = RT.next(s)) { NewInstanceMethod m = NewInstanceMethod.Parse(ret, (ISeq)RT.first(s), thisTag, overrideables); methods = RT.conj(methods, m); } ret._methods = methods; ret.Keywords = (IPersistentMap)Compiler.KEYWORDS.deref(); ret.Vars = (IPersistentMap)Compiler.VARS.deref(); ret.Constants = (PersistentVector)Compiler.CONSTANTS.deref(); ret._constantsID = RT.nextID(); ret.KeywordCallsites = (IPersistentVector)Compiler.KEYWORD_CALLSITES.deref(); ret.ProtocolCallsites = (IPersistentVector)Compiler.PROTOCOL_CALLSITES.deref(); ret.VarCallsites = (IPersistentVector)Compiler.VAR_CALLSITES.deref(); } finally { if (ret.IsDefType) Var.popThreadBindings(); Var.popThreadBindings(); } ret.Compile(stub, interfaces, false, genC); Compiler.RegisterDuplicateType(ret.CompiledType); return ret; }
/*** * 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 */ static Type CompileStub(Type super, NewInstanceExpr ret, Type[] interfaces, Object frm) { //GenContext context = Compiler.COMPILER_CONTEXT.get() as GenContext ?? Compiler.EvalContext; //GenContext context = Compiler.COMPILER_CONTEXT.get() as GenContext ?? new GenContext("stub" + RT.nextID().ToString(), ".dll", ".", CompilerMode.Immediate); GenContext context = Compiler.COMPILER_CONTEXT.get() as GenContext ?? new GenContext("stub" + RT.nextID().ToString(), ".dll", ".", false); TypeBuilder tb = context.ModuleBuilder.DefineType(Compiler.COMPILE_STUB_PREFIX + "." + ret.InternalName, 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()); ILGen ilg = new ILGen(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); ILGen ilg2 = new ILGen(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 static ObjExpr Build( IPersistentVector interfaceSyms, IPersistentVector fieldSyms, Symbol thisSym, string tagName, Symbol className, Symbol typeTag, ISeq methodForms, Object frm, IPersistentMap opts) { NewInstanceExpr ret = new NewInstanceExpr(null); ret.Src = frm; ret.Name = className.ToString(); ret.ClassMeta = GenInterface.ExtractAttributes(RT.meta(className)); ret.InternalName = ret.Name; // ret.Name.Replace('.', '/'); // Java: ret.objtype = Type.getObjectType(ret.internalName); ret.Opts = opts; if (thisSym != null) ret.ThisName = thisSym.Name; if (fieldSyms != null) { IPersistentMap fmap = PersistentHashMap.EMPTY; object[] closesvec = new object[2 * fieldSyms.count()]; for (int i = 0; i < fieldSyms.count(); i++) { Symbol sym = (Symbol)fieldSyms.nth(i); LocalBinding lb = new LocalBinding(-1, sym, null, new MethodParamExpr(Compiler.TagType(Compiler.TagOf(sym))), false, false, false); fmap = fmap.assoc(sym, lb); closesvec[i * 2] = lb; closesvec[i * 2 + 1] = lb; } // Java TODO: inject __meta et al into closes - when? // use array map to preserve ctor order ret.Closes = new PersistentArrayMap(closesvec); ret.Fields = fmap; for (int i = fieldSyms.count() - 1; i >= 0 && (((Symbol)fieldSyms.nth(i)).Name.Equals("__meta") || ((Symbol)fieldSyms.nth(i)).Name.Equals("__extmap")); --i) ret.AltCtorDrops++; } // Java TODO: set up volatiles //ret._volatiles = PersistentHashSet.create(RT.seq(RT.get(ret._optionsMap, volatileKey))); IPersistentVector interfaces = PersistentVector.EMPTY; for (ISeq s = RT.seq(interfaceSyms); s != null; s = s.next()) { Type t = (Type)Compiler.Resolve((Symbol)s.first()); if (!t.IsInterface) throw new ParseException("only interfaces are supported, had: " + t.Name); interfaces = interfaces.cons(t); } Type superClass = typeof(Object); Dictionary<IPersistentVector, IList<MethodInfo>> overrideables; Dictionary<IPersistentVector, IList<MethodInfo>> explicits; GatherMethods(superClass, RT.seq(interfaces), out overrideables, out explicits); ret._methodMap = overrideables; GenContext context = Compiler.IsCompiling ? Compiler.CompilerContextVar.get() as GenContext : (ret.IsDefType ? GenContext.CreateWithExternalAssembly("deftype" + RT.nextID().ToString(), ".dll", true) : (Compiler.CompilerContextVar.get() as GenContext ?? Compiler.EvalContext)); GenContext genC = context.WithNewDynInitHelper(ret.InternalName + "__dynInitHelper_" + RT.nextID().ToString()); Type baseClass = ret.CompileBaseClass(genC, superClass, SeqToTypeArray(interfaces), frm); Symbol thisTag = Symbol.intern(null, baseClass.FullName); try { Var.pushThreadBindings( RT.mapUniqueKeys( Compiler.ConstantsVar, PersistentVector.EMPTY, Compiler.ConstantIdsVar, new IdentityHashMap(), Compiler.KeywordsVar, PersistentHashMap.EMPTY, Compiler.VarsVar, PersistentHashMap.EMPTY, Compiler.KeywordCallsitesVar, PersistentVector.EMPTY, Compiler.ProtocolCallsitesVar, PersistentVector.EMPTY, Compiler.VarCallsitesVar, Compiler.EmptyVarCallSites(), Compiler.NoRecurVar, null, Compiler.CompilerContextVar, genC )); if (ret.IsDefType) { Var.pushThreadBindings( RT.mapUniqueKeys( Compiler.MethodVar, null, Compiler.LocalEnvVar, ret.Fields, Compiler.CompileStubSymVar, Symbol.intern(null, tagName), Compiler.CompileStubClassVar, baseClass )); ret.HintedFields = RT.subvec(fieldSyms, 0, fieldSyms.count() - ret.AltCtorDrops); } // now (methodname [args] body)* ret.SpanMap = (IPersistentMap)Compiler.SourceSpanVar.deref(); IPersistentCollection methods = null; for (ISeq s = methodForms; s != null; s = RT.next(s)) { NewInstanceMethod m = NewInstanceMethod.Parse(ret, (ISeq)RT.first(s), thisTag, overrideables, explicits); methods = RT.conj(methods, m); } ret.Methods = methods; ret.Keywords = (IPersistentMap)Compiler.KeywordsVar.deref(); ret.Vars = (IPersistentMap)Compiler.VarsVar.deref(); ret.Constants = (PersistentVector)Compiler.ConstantsVar.deref(); ret.ConstantsID = RT.nextID(); ret.KeywordCallsites = (IPersistentVector)Compiler.KeywordCallsitesVar.deref(); ret.ProtocolCallsites = (IPersistentVector)Compiler.ProtocolCallsitesVar.deref(); ret.VarCallsites = (IPersistentSet)Compiler.VarCallsitesVar.deref(); } finally { if (ret.IsDefType) Var.popThreadBindings(); Var.popThreadBindings(); } // TOD: Really, the first baseclass here should be 'superclass' but can't handle hostexprs nested in method bodies -- reify method compilation takes place before this sucker is compiled, so can't replace the call. // Might be able to flag baseclass classes and not try to convert, leading to a dynsite. ret.Compile(baseClass, baseClass, interfaces, false, genC); Compiler.RegisterDuplicateType(ret.CompiledType); return ret; }
/*** * 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; }