public void AddMethod(MessageContext ctxt, CST.MethodDef methodDef) { var trace = Parent.Parent; var name = methodDef.QualifiedMemberName(trace.Parent.Env.Global, Parent.Assembly, Type); if (trace.Parent.FirstOccuranceOfMethod(ctxt, name, trace)) Methods.Add(methodDef.MethodSignature); }
public AssemblyTrace(Trace parent, CST.AssemblyDef assembly) { Parent = parent; Assembly = assembly; IncludeAssembly = false; TypeMap = new Map<CST.TypeName, TypeTrace>(); }
private static bool IsUpToDate(CompilerEnvironment env, CST.AssemblyDef assembly, bool complain) { var annot = assembly.Annotations.OfType<CST.AssemblyFileAnnotation>().FirstOrDefault(); if (annot == null) throw new InvalidOperationException("assembly is missing file annotation"); var fn = default(string); var lastCompTime = AssemblyCompiler.LastCompilationTime(env, assembly.Name, out fn); if (lastCompTime.HasValue) { if (annot.LastWriteTime <= lastCompTime.Value) return true; else { if (complain) env.Log (new OutOfDateAssemblyMessage(assembly.Name, annot.CanonicalFileName, fn)); return false; } } else { if (complain) env.Log(new AssemblyNotCompiledMessage(assembly.Name, fn)); return false; } }
public TypeTrace(AssemblyTrace parent, CST.TypeDef type) { Parent = parent; Type = type; IncludeType = false; Methods = new Set<CST.MethodSignature>(); }
public MethodCompiler(TypeDefinitionCompiler parent, JST.NameSupply outerNameSupply, CST.MethodDef methodDef, MethodCompilationMode mode) { env = parent.Env; this.parent = parent; methEnv = parent.TyconEnv.AddSelfTypeBoundArguments().AddMethod(methodDef).AddSelfMethodBoundArguments(); messageCtxt = CST.MessageContextBuilders.Env(methEnv); this.mode = mode; this.outerNameSupply = outerNameSupply; var common = default(JST.NameSupply); switch (mode) { case MethodCompilationMode.SelfContained: common = outerNameSupply; // Will be bound by function passed to root's BindMethod rootId = common.GenSym(); assemblyId = common.GenSym(); typeDefinitionId = common.GenSym(); break; case MethodCompilationMode.DirectBind: common = outerNameSupply.Fork(); // Already bound rootId = parent.RootId; assemblyId = parent.AssemblyId; typeDefinitionId = parent.TypeDefinitionId; break; default: throw new ArgumentOutOfRangeException("mode"); } nameSupply = common.Fork(); simpNameSupply = common.Fork(); }
public string ResolveTypeRefToSlot(CST.TypeRef typeRef) { var assemblyDef = default(CST.AssemblyDef); if (typeRef.QualifiedTypeName.Assembly.PrimTryResolve(env.Global, out assemblyDef)) return AssemblyMappingFor(assemblyDef).ResolveTypeDefinitionToSlot(typeRef.QualifiedTypeName.Type); else throw new InvalidOperationException("invalid type ref"); }
// Collecting mode entry point public AssemblyCompiler(CompilerEnvironment env, CST.AssemblyDef assemblyDef) : this(env) { assmEnv = env.Global.Environment().AddAssembly(assemblyDef); assemblyTrace = null; NameSupply = new JST.NameSupply(Constants.Globals); rootId = NameSupply.GenSym(); assemblyId = NameSupply.GenSym(); }
public string ResolveFieldRefToSlot(CST.FieldRef fieldRef) { var assemblyDef = default(CST.AssemblyDef); var typeDef = default(CST.TypeDef); if (fieldRef.DefiningType.PrimTryResolve(env.Global, out assemblyDef, out typeDef)) return TypeMappingFor(assemblyDef, typeDef).ResolveFieldToSlot(fieldRef.QualifiedMemberName); else throw new InvalidOperationException("invalid field ref"); }
private TypeMapping TypeMappingFor(CST.AssemblyDef assemblyDef, CST.TypeDef typeDef) { var name = typeDef.QualifiedTypeName(env.Global, assemblyDef); var typeMapping = default(TypeMapping); if (!typeMappingCache.TryGetValue(name, out typeMapping)) { typeMapping = new TypeMapping(env, assemblyDef, typeDef); typeMappingCache.Add(name, typeMapping); } return typeMapping; }
private AssemblyMapping AssemblyMappingFor(CST.AssemblyDef assemblyDef) { var name = assemblyDef.Name; var assemblyMapping = default(AssemblyMapping); if (!assemblyMappingCache.TryGetValue(name, out assemblyMapping)) { assemblyMapping = new AssemblyMapping(env, assemblyDef); assemblyMappingCache.Add(name, assemblyMapping); } return assemblyMapping; }
private bool HasFullReflection(CST.AssemblyDef assemblyDef, CST.TypeDef typeDef) { var level = default(ReflectionLevel); env.AttributeHelper.GetValueFromType (assemblyDef, typeDef, env.AttributeHelper.ReflectionAttributeRef, env.AttributeHelper.TheReflectionLevelProperty, true, true, ref level); return level >= ReflectionLevel.Full; }
// NOTE: May be called on invalid definitions public override bool FieldAlwaysUsed(CST.AssemblyDef assemblyDef, CST.TypeDef typeDef, CST.FieldDef fieldDef) { #if false if (env.AttributeHelper.FieldHasAttribute(assemblyDef, typeDef, fieldDef, env.Global.CompilerGeneratedAttributeRef, false)) return false; #endif if (env.AttributeHelper.FieldHasAttribute(assemblyDef, typeDef, fieldDef, env.AttributeHelper.IgnoreAttributeRef, true, true)) return false; if (HasFullReflection(assemblyDef, typeDef)) return true; var isUsed = default(bool); env.AttributeHelper.GetValueFromField(assemblyDef, typeDef, fieldDef, env.AttributeHelper.UsedAttributeRef, env.AttributeHelper.TheIsUsedProperty, true, false, ref isUsed); if (isUsed) return true; return false; }
public bool CouldBeInlinableBasedOnHeaderAlone(CST.AssemblyDef assemblyDef, CST.TypeDef typeDef, CST.MethodDef methodDef) { if (methodDef.IsVirtualOrAbstract || typeDef.Style is CST.InterfaceTypeStyle) // No virtuals or interface methods return false; if (typeDef.Style is CST.MultiDimArrayTypeStyle) // Implemented by runtime return false; if (typeDef.IsAttributeType(env.Global, assemblyDef)) // Don't inline attribute property methods since we invoke them directly when building attributes return false; var level = default(ReflectionLevel); env.AttributeHelper.GetValueFromType (assemblyDef, typeDef, env.AttributeHelper.ReflectionAttributeRef, env.AttributeHelper.TheReflectionLevelProperty, true, true, ref level); if (level >= ReflectionLevel.Full) // No inlining in classes needing full reflection since need to support dynamic invokes return false; // NOTE: Method may be used in a delegate, in which case it's fine to inline but we'll still // need to emit the definition if (assemblyDef.EntryPoint != null && assemblyDef.EntryPoint.QualifiedMemberName.Equals (methodDef.QualifiedMemberName(env.Global, assemblyDef, typeDef))) // Entry points are called directly by startup code return false; return true; }
public override CST.InvalidInfo ImplementableTypeRef(MessageContext ctxt, CST.RootEnvironment rootEnv, CST.TypeRef typeRef) { var s = typeRef.Style(rootEnv); if (s is CST.UnmanagedPointerTypeStyle) { Log(new CST.InvalidTypeRef(ctxt, typeRef, "Unmanaged pointers are not supported")); return new CST.InvalidInfo(CST.MessageContextBuilders.Type(Global, typeRef)); } return null; }
public override CST.InvalidInfo ImplementableInstruction(MessageContext ctxt, CST.AssemblyDef assemblyDef, CST.TypeDef typeDef, CST.MethodDef methodDef, CST.Instruction instruction) { switch (instruction.Flavor) { case CST.InstructionFlavor.Try: { var tryi = (CST.TryInstruction)instruction; if (tryi.Handlers.Any(h => h.Flavor == CST.HandlerFlavor.Filter)) { Log (new CST.InvalidInstruction (ctxt, instruction, "Exception filter blocks are not supported")); return new CST.InvalidInfo(CST.MessageContextBuilders.Instruction(Global, instruction)); } break; } default: break; } return null; }
public override void ImplementableMemberDef(CST.AssemblyDef assemblyDef, CST.TypeDef typeDef, CST.MemberDef memberDef) { var ctxt = CST.MessageContextBuilders.Member(env.Global, assemblyDef, typeDef, memberDef); var s = typeDef.Style; var methodDef = memberDef as CST.MethodDef; if (methodDef == null) return; if (s is CST.DelegateTypeStyle || s is CST.MultiDimArrayTypeStyle) // SPECIAL CASE: Magic delegate and multi-dimensional array methods are // implemented by runtime return; if (env.AttributeHelper.MethodHasAttribute (assemblyDef, typeDef, methodDef, env.AttributeHelper.IgnoreAttributeRef, true, true)) { Log(new CST.InvalidMemberDef(ctxt, "Method is marked as '[Ignore]'")); methodDef.Invalid = new CST.InvalidInfo("Ignored"); } try { if (!(s is CST.InterfaceTypeStyle) && methodDef.MethodStyle != CST.MethodStyle.Abstract && !env.InteropManager.IsImported(assemblyDef, typeDef, methodDef)) { switch (methodDef.CodeFlavor) { case CST.MethodCodeFlavor.Managed: { var instructions = methodDef.Instructions(Global); if (instructions == null || instructions.Body.Count == 0) { Log(new CST.InvalidMemberDef(ctxt, "Method has no body")); methodDef.Invalid = new CST.InvalidInfo("Unimplementable"); } break; } case CST.MethodCodeFlavor.ManagedExtern: Log(new CST.InvalidMemberDef(ctxt, "Method is marked as extern but has no import")); methodDef.Invalid = new CST.InvalidInfo("Unimplementable"); break; case CST.MethodCodeFlavor.Native: Log(new CST.InvalidMemberDef(ctxt, "Method invokes native code")); methodDef.Invalid = new CST.InvalidInfo("Unimplementable"); break; case CST.MethodCodeFlavor.Runtime: Log(new CST.InvalidMemberDef(ctxt, "Method is part of the CLR runtime")); methodDef.Invalid = new CST.InvalidInfo("Unimplementable"); break; case CST.MethodCodeFlavor.ForwardRef: Log(new CST.InvalidMemberDef(ctxt, "Method is a forward reference")); methodDef.Invalid = new CST.InvalidInfo("Unimplementable"); break; default: throw new ArgumentOutOfRangeException(); } } // else: no body to check } catch (DefinitionException) { Log(new CST.InvalidMemberDef(ctxt, "Method contains an interop error")); methodDef.Invalid = new CST.InvalidInfo("Unimplementable"); } }
public override void ImplementableTypeDef(CST.AssemblyDef assemblyDef, CST.TypeDef typeDef) { if (env.AttributeHelper.TypeHasAttribute (assemblyDef, typeDef, env.AttributeHelper.IgnoreAttributeRef, true, true)) { var ctxt = CST.MessageContextBuilders.Type(env.Global, assemblyDef, typeDef); Log(new CST.InvalidTypeDef(ctxt, "Type is marked as '[Ignore]'")); typeDef.Invalid = new CST.InvalidInfo("Ignored"); } }
public override bool IgnoreMethodDefBody(CST.AssemblyDef assemblyDef, CST.TypeDef typeDef, CST.MethodDef methodDef) { return env.AttributeHelper.MethodHasAttribute(assemblyDef, typeDef, methodDef, env.AttributeHelper.InteropGeneratedAttributeRef, false, false); }
public bool IsNoInteropParameter(CST.AssemblyDef assemblyDef, CST.TypeDef typeDef, CST.MethodDef methodDef, int idx) { if (!methodDef.IsStatic && idx == 0) { // We must look for [Runtime] on the method's declaring type, since the CLR does not // allow custom attributes on implicit arguments var isRuntime = default(bool); attributeHelper.GetValueFromType (assemblyDef, typeDef, attributeHelper.RuntimeAttributeRef, attributeHelper.TheIsRuntimeProperty, true, false, ref isRuntime); return isRuntime; } else { var isNoInterop = default(bool); attributeHelper.GetValueFromParameter (assemblyDef, typeDef, methodDef, idx, attributeHelper.NoInteropAttributeRef, attributeHelper.TheIsNoInteropProperty, true, false, ref isNoInterop); return isNoInterop; } }
public override bool IncludeAttributes(CST.AssemblyDef assemblyDef, CST.TypeDef typeDef) { return HasFullReflection(assemblyDef, typeDef); }
public override bool PropogateExtraUsedFromType(CST.AssemblyDef assemblyDef, CST.TypeDef typeDef) { var newUsed = false; var state = env.InteropManager.GetTypeRepresentation(assemblyDef, typeDef).State; if (state == InstanceState.JavaScriptOnly || state == InstanceState.ManagedAndJavaScript) { var typeEnv = Global.Environment().AddAssembly(assemblyDef).AddType(typeDef).AddSelfTypeBoundArguments(); var methodRef = env.InteropManager.DefaultImportingConstructor(typeEnv); if (methodRef != null) { // Default importing constructor is used if its type is used if (ExtraUsedMethod(methodRef.QualifiedMemberName)) newUsed = true; } } return newUsed; }
// NOTE: May be called on invalid definitions public override bool MethodAlwaysUsed(CST.AssemblyDef assemblyDef, CST.TypeDef typeDef, CST.MethodDef methodDef) { if (typeDef.Style is CST.DelegateTypeStyle) // All the magic delegate methods are inlined by the compiler return false; #if false if (env.AttributeHelper.MethodHasAttribute(assemblyDef, typeDef, methodDef, env.Global.CompilerGeneratedAttributeRef, false)) return false; #endif if (env.AttributeHelper.MethodHasAttribute (assemblyDef, typeDef, methodDef, env.AttributeHelper.IgnoreAttributeRef, true, true)) return false; if (typeDef.IsModule && methodDef.IsStatic && methodDef.IsConstructor) return true; if (HasFullReflection(assemblyDef, typeDef)) return true; var isUsed = default(bool); env.AttributeHelper.GetValueFromMethod (assemblyDef, typeDef, methodDef, env.AttributeHelper.UsedAttributeRef, env.AttributeHelper.TheIsUsedProperty, true, false, ref isUsed); if (isUsed) return true; if (env.InteropManager.IsExported(assemblyDef, typeDef, methodDef)) // Exported methods always used return true; return false; }
// NOTE: May be called on invalid definitions public override bool IsAlternateEntryPoint(CST.AssemblyDef assemblyDef, CST.TypeDef typeDef, CST.MethodDef methodDef) { return env.AttributeHelper.MethodHasAttribute (assemblyDef, typeDef, methodDef, env.AttributeHelper.EntryPointAttributeRef, false, false); }
private JST.Expression RecaseMethod(CST.AssemblyDef assemblyDef, CST.TypeDef typeDef, CST.MethodDef methodDef, JST.Expression script) { if (script != null) return script; var casing = default(Casing); attributeHelper.GetValueFromMethod (assemblyDef, typeDef, methodDef, attributeHelper.NamingAttributeRef, attributeHelper.TheMemberNameCasingProperty, true, false, ref casing); return new JST.Identifier(JST.Lexemes.StringToIdentifier(Recase(methodDef.Name, casing))).ToE(); }
public bool IsFactory(CST.AssemblyDef assemblyDef, CST.TypeDef typeDef, CST.MethodDef methodDef) { if (!methodDef.IsStatic && methodDef.IsConstructor) { if (IsImported(assemblyDef, typeDef, methodDef)) { var state = GetTypeRepresentation(assemblyDef, typeDef).State; switch (state) { case InstanceState.ManagedOnly: { // Only imported ctors in [Runtime] types can be factories var isRuntime = default(bool); attributeHelper.GetValueFromType (assemblyDef, typeDef, attributeHelper.RuntimeAttributeRef, attributeHelper.TheIsRuntimeProperty, true, false, ref isRuntime); return isRuntime; } case InstanceState.Merged: return true; case InstanceState.ManagedAndJavaScript: case InstanceState.JavaScriptOnly: // Both managed and unmanaged instances are needed break; default: throw new ArgumentOutOfRangeException(); } if (state == InstanceState.Merged) return IsInlinable(assemblyDef, typeDef, methodDef, state); } // else: not improted } // else: not a ctor return false; }
public bool IsNoInteropResult(CST.AssemblyDef assemblyDef, CST.TypeDef typeDef, CST.MethodDef methodDef) { var isNoInterop = default(bool); attributeHelper.GetValueFromResult (assemblyDef, typeDef, methodDef, attributeHelper.NoInteropAttributeRef, attributeHelper.TheIsNoInteropProperty, true, false, ref isNoInterop); return isNoInterop; }
public override CST.InvalidInfo ImplementableMemberRef(MessageContext ctxt, CST.RootEnvironment rootEnv, CST.MemberRef memberRef) { if (memberRef.DefiningType.Style(rootEnv) is CST.DelegateTypeStyle && memberRef.Name.Equals(".ctor", StringComparison.Ordinal)) // SPECIAL CASE: Delegates are constructed by runtime, so assume .ctor is implementable return null; return null; }
public override bool PropogateExtraUsedFromMember(CST.AssemblyDef assemblyDef, CST.TypeDef typeDef, CST.MemberDef memberDef) { var newUsed = false; var methodDef = memberDef as CST.MethodDef; if (methodDef != null) { if (!methodDef.IsStatic && methodDef.IsConstructor && env.InteropManager.IsImported(assemblyDef, typeDef, methodDef) && !env.InteropManager.IsFactory(assemblyDef, typeDef, methodDef)) { // Imported instance constructor may invoke an 'importing' constructor var polyMethEnv = Global.Environment().AddAssembly(assemblyDef).AddType(typeDef).AddSelfTypeBoundArguments(). AddMethod(methodDef); var methodRef = env.InteropManager.BestImportingConstructor(polyMethEnv); if (methodRef != null) { if (ExtraUsedMethod(methodRef.QualifiedMemberName)) newUsed = true; } } } return newUsed; }
// Take acccount of: // - PassRootAsArgument // - PassInstanceAsArgument // - InlineParamsArray private JST.Expression AppendFinalImport(JST.NameSupply nameSupply, JST.Identifier rootId, CST.AssemblyDef assemblyDef, CST.TypeDef typeDef, CST.MethodDef methodDef, JST.Expression script, ISeq<JST.Statement> body, IImSeq<JST.Expression> arguments) { var isInstanceMethod = !(methodDef.IsStatic || methodDef.IsConstructor); var scriptExpectsRoot = default(bool); attributeHelper.GetValueFromMethod (assemblyDef, typeDef, methodDef, attributeHelper.ImportAttributeRef, attributeHelper.ThePassRootAsArgumentProperty, true, false, ref scriptExpectsRoot); var passInstAsArg = default(bool); attributeHelper.GetValueFromMethod (assemblyDef, typeDef, methodDef, attributeHelper.ImportAttributeRef, attributeHelper.ThePassInstanceAsArgumentProperty, true, false, ref passInstAsArg); var instanceIsThis = isInstanceMethod && !passInstAsArg; var inlineParams = default(bool); attributeHelper.GetValueFromMethod (assemblyDef, typeDef, methodDef, attributeHelper.ImportAttributeRef, attributeHelper.TheInlineParamsArrayProperty, true, false, ref inlineParams); var lastArgIsParamsArray = methodDef.HasParamsArray(rootEnv) && inlineParams; var funcScript = script as JST.FunctionExpression; var nextArg = 0; var instArg = default(JST.Expression); if (instanceIsThis) { // Instance argument will be the first arg to 'call' or 'apply', or the target of a '.' call. instArg = arguments[nextArg++]; if (lastArgIsParamsArray && !instArg.IsDuplicatable) { // Make sure instance argument is evaluated before the remaining arguments var instId = nameSupply.GenSym(); body.Add(JST.Statement.Var(instId, instArg)); instArg = instId.ToE(); } } else { if (lastArgIsParamsArray) instArg = new JST.NullExpression(); } var knownArgs = 0; var call = default(JST.Expression); if (lastArgIsParamsArray) { // We mush build script args at runtime var argsId = nameSupply.GenSym(); body.Add(JST.Statement.Var(argsId, new JST.ArrayLiteral())); if (scriptExpectsRoot) { body.Add(JST.Statement.DotCall(argsId.ToE(), Constants.push, rootId.ToE())); knownArgs++; } while (nextArg < arguments.Count - 1) { body.Add(JST.Statement.DotCall(argsId.ToE(), Constants.push, arguments[nextArg++])); knownArgs++; } var arrArg = arguments[nextArg]; if (!arrArg.IsDuplicatable) { var arrId = nameSupply.GenSym(); body.Add(JST.Statement.Var(arrId, arrArg)); arrArg = arrId.ToE(); } var iId = nameSupply.GenSym(); body.Add (new JST.IfStatement (JST.Expression.IsNotNull(arrArg), new JST.Statements (new JST.ForStatement (new JST.ForVarLoopClause (iId, new JST.NumericLiteral(0), new JST.BinaryExpression (iId.ToE(), JST.BinaryOp.LessThan, JST.Expression.Dot(arrArg, Constants.length)), new JST.UnaryExpression(iId.ToE(), JST.UnaryOp.PostIncrement)), new JST.Statements (JST.Statement.DotCall (argsId.ToE(), Constants.push, new JST.IndexExpression(arrArg, iId.ToE()))))))); if (funcScript != null) { // var args = ...; var x = script; x.apply(this/null, args) var scriptId = nameSupply.GenSym(); body.Add(JST.Statement.Var(scriptId, funcScript)); call = JST.Expression.DotCall(scriptId.ToE(), Constants.apply, instArg, argsId.ToE()); } else { if (instanceIsThis) { // var args = ...; (this.script).apply(this, args); call = JST.Expression.DotCall (JST.Expression.Dot(instArg, JST.Expression.ExplodePath(script)), Constants.apply, instArg, argsId.ToE()); } else { // var args = ...; script.apply(null, args) call = JST.Expression.DotCall(script, Constants.apply, instArg, argsId.ToE()); } } } else { var callArgs = new Seq<JST.Expression>(); if (instanceIsThis && funcScript != null) callArgs.Add(instArg); if (scriptExpectsRoot) { callArgs.Add(rootId.ToE()); knownArgs++; } while (nextArg < arguments.Count) { callArgs.Add(arguments[nextArg++]); knownArgs++; } if (instanceIsThis) { if (funcScript != null) { // var x = script; x.call(this, arg1, ..., argn) var scriptId = nameSupply.GenSym(); body.Add(JST.Statement.Var(scriptId, funcScript)); call = JST.Expression.DotCall(scriptId.ToE(), Constants.call, callArgs); } else // this.script(arg1, ..., angn) call = new JST.CallExpression (JST.Expression.Dot(instArg, JST.Expression.ExplodePath(script)), callArgs); } else // script(arg1, ..., argn) call = new JST.CallExpression(script, callArgs); } if (funcScript != null) { if (funcScript.Parameters.Count < knownArgs) { var ctxt = CST.MessageContextBuilders.Member(env.Global, assemblyDef, typeDef, methodDef); env.Log(new InvalidInteropMessage(ctxt, "script accepts too few arguments")); throw new DefinitionException(); } } return call; }
public bool IsStatic(CST.AssemblyDef assemblyDef, CST.TypeDef typeDef, CST.MethodDef methodDef) { return methodDef.IsStatic || IsFactory(assemblyDef, typeDef, methodDef); }