public TypeTrace(AssemblyTrace parent, CST.TypeDef type) { Parent = parent; Type = type; IncludeType = false; Methods = new Set<CST.MethodSignature>(); }
// NOTE: May be called on invalid definitions public override bool TypeAlwaysUsed(CST.AssemblyDef assemblyDef, CST.TypeDef typeDef) { #if false if (env.AttributeHelper.TypeHasAttribute (assemblyDef, typeDef, env.Global.CompilerGeneratedAttributeRef, false)) { return(false); } #endif if (env.AttributeHelper.TypeHasAttribute (assemblyDef, typeDef, env.AttributeHelper.IgnoreAttributeRef, true, true)) { return(false); } if (typeDef.IsModule) { return(true); } if (HasFullReflection(assemblyDef, typeDef)) { return(true); } var isUsed = default(bool); env.AttributeHelper.GetValueFromType (assemblyDef, typeDef, env.AttributeHelper.UsedTypeAttributeRef, env.AttributeHelper.TheIsUsedProperty, true, false, ref isUsed); var isUsedType = default(bool); env.AttributeHelper.GetValueFromType (assemblyDef, typeDef, env.AttributeHelper.UsedAttributeRef, env.AttributeHelper.TheIsUsedProperty, true, false, ref isUsedType); if (isUsed || isUsedType) { return(true); } return(false); }
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); }
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 void AddMethod(MessageContext ctxt, CST.TypeDef typeDef, CST.MethodDef methodDef) { var typeTrace = ResolveTypeTrace(typeDef); typeTrace.AddMethod(ctxt, methodDef); }
public TypeMapping(CompilerEnvironment env, CST.AssemblyDef assemblyDef, CST.TypeDef typeDef) { ctxt = CST.MessageContextBuilders.Type(env.Global, assemblyDef, typeDef); this.env = env; this.assemblyDef = assemblyDef; this.typeDef = typeDef; // Method slots appear as field names in type structures and directory names on disk. // Thus we use lower-case identifiers. methodSlots = new SlotAllocation<CST.QualifiedMemberName> (env.DebugMode, NameFlavor.LowercaseIdentifier, FriendlyMemberName); // Field slots appear in object annd type structuers, but always prefixed by 'S' or 'F'. // Thus we use arbitrary identifiers. fieldSlots = new SlotAllocation<CST.QualifiedMemberName> (env.DebugMode, NameFlavor.Identifier, FriendlyMemberName); // Similarly for event slots, but prefixed by 'E'. eventSlots = new SlotAllocation<CST.QualifiedMemberName> (env.DebugMode, NameFlavor.Identifier, FriendlyMemberName); // Similarly for property slots (needed only by reflection), but prefixed by 'R' propSlots = new SlotAllocation<CST.QualifiedMemberName> (env.DebugMode, NameFlavor.Identifier, FriendlyMemberName); AddNames(env, assemblyDef, typeDef, methodSlots, fieldSlots, eventSlots, propSlots); // Defer till ask for string slot stringSlots = null; }
public void AddType(MessageContext ctxt, CST.TypeDef typeDef) { var typeTrace = ResolveTypeTrace(typeDef); typeTrace.AddType(ctxt); }
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 string ResolveStringToSlot(CST.AssemblyDef assemblyDef, CST.TypeDef typeDef, string str) { return(TypeMappingFor(assemblyDef, typeDef).ResolveStringToSlot(str)); }
public bool IsInlinable(CST.AssemblyDef assemblyDef, CST.TypeDef typeDef, CST.MethodDef methodDef) { var s = MethodBodySize(methodDef.QualifiedMemberName(env.Global, assemblyDef, typeDef)); return(s >= 0 && s <= env.InlineThreshold); }
public string ResolvePropertyDefToSlot(CST.AssemblyDef assemblyDef, CST.TypeDef typeDef, CST.PropertyDef propDef) { return(TypeMappingFor(assemblyDef, typeDef).ResolvePropertyToSlot (propDef.QualifiedMemberName(env.Global, assemblyDef, typeDef))); }
public void AddType(MessageContext ctxt, CST.AssemblyDef assemblyDef, CST.TypeDef typeDef) { var assemblyTrace = ResolveAssemblyTrace(assemblyDef);; assemblyTrace.AddType(ctxt, typeDef); }
public IEnumerable <KeyValuePair <string, string> > AllStringSlots(CST.AssemblyDef assemblyDef, CST.TypeDef typeDef) { return(TypeMappingFor(assemblyDef, typeDef).AllStringSlots()); }
public override bool IncludeAttributes(CST.AssemblyDef assemblyDef, CST.TypeDef typeDef) { return(HasFullReflection(assemblyDef, typeDef)); }
// 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)); }
public string ResolveFieldDefToSlot(CST.AssemblyDef assemblyDef, CST.TypeDef typeDef, CST.FieldDef fieldDef) { return(TypeMappingFor(assemblyDef, typeDef).ResolveFieldToSlot (fieldDef.QualifiedMemberName(env.Global, assemblyDef, typeDef))); }
public string ResolveTypeDefToSlot(CST.AssemblyDef assemblyDef, CST.TypeDef typeDef) { return(AssemblyMappingFor(assemblyDef).ResolveTypeDefinitionToSlot(typeDef.EffectiveName(env.Global))); }
private static void AddNames( CompilerEnvironment env, CST.AssemblyDef assemblyDef, CST.TypeDef typeDef, SlotAllocation <CST.QualifiedMemberName> methodSlots, SlotAllocation <CST.QualifiedMemberName> fieldSlots, SlotAllocation <CST.QualifiedMemberName> eventSlots, SlotAllocation <CST.QualifiedMemberName> propSlots) { // Allocate slots for any base type so that this type's slots won't collide with them. // NOTE: Not strictly necessary for methods, since only virtual methods of supertype may find their // way into derived type, but seems easiest to just allocate them all. // NOTE: Interface method slots need only be unique within their interface type since the type // id is included in the final slot name. if (typeDef.Extends != null) { var extAssemblyDef = default(CST.AssemblyDef); var extTypeDef = default(CST.TypeDef); if (typeDef.Extends.PrimTryResolve(env.Global, out extAssemblyDef, out extTypeDef)) { AddNames(env, extAssemblyDef, extTypeDef, methodSlots, fieldSlots, eventSlots, propSlots); } } // Members are already in canonical order foreach (var memberDef in typeDef.Members.Where(m => m.IsUsed && m.Invalid == null)) { var name = memberDef.QualifiedMemberName(env.Global, assemblyDef, typeDef); switch (memberDef.Flavor) { case CST.MemberDefFlavor.Field: { fieldSlots.Add(name); break; } case CST.MemberDefFlavor.Event: { eventSlots.Add(name); break; } case CST.MemberDefFlavor.Method: { methodSlots.Add(name); break; } case CST.MemberDefFlavor.Property: { propSlots.Add(name); break; } default: throw new ArgumentOutOfRangeException(); } } return; }
public void AddMethod(MessageContext ctxt, CST.AssemblyDef assemblyDef, CST.TypeDef typeDef, CST.MethodDef methodDef) { var assemblyTrace = ResolveAssemblyTrace(assemblyDef); assemblyTrace.AddMethod(ctxt, typeDef, methodDef); }
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); }
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 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"); } }
// See also: InteropManager::IsInlinable private bool PrimIsInlinable(CST.AssemblyDef assemblyDef, CST.TypeDef typeDef, CST.MethodDef methodDef) { if (!CouldBeInlinableBasedOnHeaderAlone(assemblyDef, typeDef, methodDef)) { return(false); } if (methodDef.IsRecursive) { // No recursive methods return(false); } if (methodDef.IsConstructor) { // No instance constructors (since we can't enline NewExpressions yet), and // no static constructors (since we can't inline calls emitted in assembly Initialize) return(false); } if (env.InteropManager.IsImported(assemblyDef, typeDef, methodDef) || env.InteropManager.IsExported(assemblyDef, typeDef, methodDef)) { // No imported methods (we inline separately), and // no exported methods (we need the definition around to be able to export it) return(false); } if (methodDef.MethodBody == null || methodDef.MethodBody.Instructions.Length == 0) { // No empty methods or imported methods return(false); } var numReturns = 0; var instructions = methodDef.Instructions(env.Global); if (!instructions.IsInlinable(ref numReturns) || numReturns != 1) { // Non-inlinable instructions return(false); } var code = instructions.Body[instructions.Body.Count - 1].Code; if (code != CST.InstructionCode.Ret && code != CST.InstructionCode.RetVal) { // Last instruction is not return return(false); } // NOTE: Even though instructions have a single return, it is still possible the translated statatements // won't have a unique result, so unfortunately we need to check that below var isInline = default(bool); var overrideInline = env.AttributeHelper.GetValueFromMethod (assemblyDef, typeDef, methodDef, env.AttributeHelper.InlineAttributeRef, env.AttributeHelper.TheIsInlinedProperty, true, false, ref isInline); if (overrideInline && !isInline) { // User has supressed inlining return(false); } if (!overrideInline && instructions.Size > env.InlineThreshold) { // Method too large return(false); } var methEnv = env.Global.Environment().AddAssembly(assemblyDef).AddType(typeDef).AddSelfTypeBoundArguments(). AddMethod(methodDef).AddSelfMethodBoundArguments(); var cstmethod = CST.CSTMethod.Translate(methEnv, new JST.NameSupply(), null); var body = new Seq <CST.Statement>(); var retres = cstmethod.Body.ToReturnResult(body); if (retres.Status != CST.ReturnStatus.One) { // More than one return return(false); } return(true); }
public string ResolveEventDefToSlot(CST.AssemblyDef assemblyDef, CST.TypeDef typeDef, CST.EventDef eventDef) { return(TypeMappingFor(assemblyDef, typeDef).ResolveEventToSlot (eventDef.QualifiedMemberName(env.Global, assemblyDef, typeDef))); }