public void LivenReg(SsaRegister reg, CppBuilder builder) { if (!IsRegScopable(reg)) return; AddReg(reg); }
public CppAssignabilityResolver(CppBuilder builder, CfgNodeCompiler.CommonTypeLookup commonTypes, CLRTypeDefRow inClass, CLRMethodDefRow inMethod) { m_builder = builder; m_commonTypes = commonTypes; m_inClass = inClass; m_inMethod = inMethod; }
public static VType.ValTypeEnum ValTypeForTypeSpec(CppBuilder cppBuilder, CLRTypeSpec typeSpec) { if (typeSpec is CLRTypeSpecClass) { CppClass cls = cppBuilder.GetCachedClass(typeSpec); if (cls.IsValueType) return VType.ValTypeEnum.ValueValue; return VType.ValTypeEnum.ReferenceValue; } else if (typeSpec is CLRTypeSpecGenericInstantiation) { CLRTypeSpecGenericInstantiation giSpec = (CLRTypeSpecGenericInstantiation)typeSpec; CppClass cls = cppBuilder.GetCachedClass(new CLRTypeSpecClass(giSpec.GenericType.TypeDef)); if (cls.IsValueType) return VType.ValTypeEnum.ValueValue; return VType.ValTypeEnum.ReferenceValue; } else if (typeSpec is CLRTypeSpecSZArray) { return VType.ValTypeEnum.ReferenceValue; } else if (typeSpec is CLRTypeSpecComplexArray) { return VType.ValTypeEnum.ReferenceValue; } else if (typeSpec is CLRTypeSpecVarOrMVar) { // Generic parameters are always treated like value types even if they're provably ref types return VType.ValTypeEnum.ValueValue; } else throw new ArgumentException(); }
public CppRegisterAllocator(CppBuilder builder) { m_registers = new List<VReg>(); m_ssaID = 1; m_cfgNodeIDs = new Dictionary<CfgNode, int>(); m_builder = builder; m_staticInitTokens = new List<CLR.CLRTypeSpec>(); }
public CfgNodeCompiler(CfgNode cfgNode) { m_cppBuilder = cfgNode.CfgBuilder.CppBuilder; m_commonTypeLookup = new CommonTypeLookup(m_cppBuilder); m_cfgNode = cfgNode; m_ehRegion = cfgNode.CfgBuilder.Region; m_escapePaths = new SortedSet<uint>(); m_temporaries = cfgNode.CfgBuilder.Temporaries; }
public VReg(CppBuilder builder, string prefix, VType vType, int slot, UsageEnum usage) { VType = vType; Slot = slot; Usage = usage; m_isAlive = false; DetermineTraceability(builder); m_basicName = prefix + slot.ToString(); m_slotName = m_basicName; }
static void Main(string[] args) { CLR.CLRAssemblyCollection assemblies = new CLR.CLRAssemblyCollection(); string exportDir = args[0]; string stubDir = args[1]; Dictionary<CLR.CLRAssembly, string> pdbPaths = new Dictionary<CLR.CLRAssembly, string>(); for (int assmIndex = 2; assmIndex < args.Length; assmIndex++) { string path = args[assmIndex]; Console.WriteLine("Loading assembly " + path); CLR.CLRAssembly clrAssembly; using (System.IO.FileStream fs = new System.IO.FileStream(path, System.IO.FileMode.Open, System.IO.FileAccess.Read)) { StreamParser parser = new StreamParser(fs, false); CLR.CLRAssembly assembly = new CLR.CLRAssembly(parser); string pdbPath = path.Substring(0, path.Length - 3) + "pdb"; if (System.IO.File.Exists(pdbPath)) pdbPaths.Add(assembly, pdbPath); assemblies.Add(assembly); } } Console.WriteLine("Resolving..."); assemblies.ResolveAll(); Console.WriteLine("Exporting..."); CppExport.CppBuilder builder = new CppExport.CppBuilder(exportDir + "\\", stubDir + "\\", assemblies, pdbPaths); Console.WriteLine("Done"); /* Console.WriteLine("Compacting..."); TCLR.TCLRAssemblyBuilder builder = new TCLR.TCLRAssemblyBuilder(); builder.ImportAssembly(clrAssembly, false); string tclrAssemblyPath = path; if (tclrAssemblyPath.EndsWith(".dll")) tclrAssemblyPath = tclrAssemblyPath.Substring(0, tclrAssemblyPath.Length - 4); tclrAssemblyPath += ".cca"; Console.WriteLine("Writing Clarity compact assembly " + tclrAssemblyPath); using (System.IO.FileStream fs = new System.IO.FileStream(tclrAssemblyPath, System.IO.FileMode.Create, System.IO.FileAccess.Write)) { builder.Export(fs); } */ }
public CppRegionEmitter(CppBuilder builder, ExceptionHandlingRegion region, CppRegisterAllocator regAllocator, IDictionary<VReg, Clarity.Rpa.HighLocal> localLookup) { m_localLookup = localLookup; m_region = region; m_builder = builder; m_regAllocator = regAllocator; m_nodesToEmittedNodes = new Dictionary<CfgNode, HighCfgNodeHandle>(); m_nodeOutlines = new Dictionary<CfgNode, CppCfgNodeOutline>(); m_ssaToEmittedSsa = new Dictionary<SsaRegister, HighSsaRegister>(); m_translatedOutboundEdges = new Dictionary<CfgOutboundEdge, CppTranslatedOutboundEdge>(); m_pendingNodes = new Queue<CfgNode>(); InternHighCfgNode(region.RootCfgNode); }
public CppMidCompiler(CppBuilder builder, CppClass cls, CppMethod method, ExceptionHandlingRegion mainRegion, string frameVarName, VReg[] args, VReg[] locals, VReg[] temporaries) { m_builder = builder; m_cls = cls; m_method = method; m_mainRegion = mainRegion; m_args = args; m_locals = locals; m_temporaries = temporaries; m_frameVarName = frameVarName; m_instructionStream = new MemoryStream(); m_instructionWriter = new StreamWriter(m_instructionStream); m_regAllocator = new CppRegisterAllocator(builder); }
public CfgBuilder(ExceptionHandlingRegion region, CppBuilder builder, CppClass cls, CppMethod method, VReg[] args, VReg[] locals, IList<VReg> temporaries) { m_builder = builder; m_cls = cls; m_method = method; m_args = args; m_locals = locals; m_temporaries = temporaries; m_instrs = method.MethodDef.Method.Instructions; m_inClass = cls.TypeDef; m_inMethod = method.MethodDef; m_region = region; m_startInstr = (int)region.StartInstr; m_endInstr = (int)region.EndInstr; m_ehClusters = region.Clusters; LocateBranchTargets(); ConstructCfg(); CreateSuccessionGraph(); }
public void ResolveInherit(CppBuilder builder, CppClass parentClass, IEnumerable<CLRTypeSpec> interfaces, CLRTypeSpec parentTypeSpec) { // There are a LOT of tricky slotting cases here. // See TestNewSlotImplementation, TestSlotDivergence, and TestImplementNonVirtual for some sample cases. // // Roughly how this works: // 1.) Override vtable slots based on matching: // - If a method is ReuseSlot, then it overrides a slot no matter what // - If a method is NewSlot, then it creates a slot // 2.) Implement MethodImpls and interfaces as cross-slot thunks // // Two notable complications with this: // // In Clarity, we only implement the specified interface once in a given class's heirarchy, but // reimplemented interfaces need to emit new mappings because the reimplementation can change how the // interface is implemented. For example, if a parent class implements an interface method by match, // and then a derived class hides that method with a newslot and reimplements the interface, then the // interface must link to the newslot method. // // This is further complicated by the II.12.2 dispatch rules, which have errors. // // We might be able to optimize this a bit if we can detect that a method reimplementation is the // same as the one that already exists. // // The second complication is that Roslyn sometimes emits useless but apparently legal .override // directives that "override" a parent class implementation with the same method that already overrides // it from reuseslot matching. ParentTypeSpec = parentTypeSpec; if (parentClass != null) { m_allVtableSlots.AddRange(parentClass.m_allVtableSlots); List<CppVtableSlot> parentOverrideVisibleSlots = new List<CppVtableSlot>(parentClass.m_overrideVisibleVtableSlots); foreach (CppMethod method in m_methods) { if (method.Virtual) { if (method.CreatesSlot != null) RemoveOverrides(parentOverrideVisibleSlots, method.CreatesSlot); if (method.Overrides) { List<int> overrideIndexes = FindOverrideIndexes(parentOverrideVisibleSlots, method.Name, method.MethodSignature); if (overrideIndexes.Count != 1) throw new ParseFailedException("Method did not override exactly one slot"); method.ReplacesStandardSlot = parentOverrideVisibleSlots[overrideIndexes[0]]; } } } if (m_newImplementationVisibleVtableSlots.Count != 0) throw new Exception(); foreach (CppMethod method in m_methods) { if (method.Virtual && method.MethodDef.MemberAccess == CLRMethodDefRow.MethodMemberAccess.Public) { if (method.Overrides) m_newImplementationVisibleVtableSlots.Add(method.ReplacesStandardSlot); else m_newImplementationVisibleVtableSlots.Add(method.CreatesSlot); } } m_overrideVisibleVtableSlots.AddRange(parentOverrideVisibleSlots); } if (parentClass != null) { // Remove already-implemented interfaces from this class's set, but keep reimplementations // to resolve them again List<CLRTypeSpec> dedupedInterfaces = new List<CLRTypeSpec>(); List<CLRTypeSpec> reimplementedInterfaces = new List<CLRTypeSpec>(); List<CLRTypeSpec> allInheritedInterfaces = new List<CLRTypeSpec>(); allInheritedInterfaces.AddRange(parentClass.m_newlyImplementedInterfaces); allInheritedInterfaces.AddRange(parentClass.m_inheritedImplementedInterfaces); foreach (CLRTypeSpec ifc in m_newlyImplementedInterfaces) { if (allInheritedInterfaces.Contains(ifc)) reimplementedInterfaces.Add(ifc); else dedupedInterfaces.Add(ifc); } m_newlyImplementedInterfaces = dedupedInterfaces; m_reimplementedInterfaces = reimplementedInterfaces; m_inheritedFields.AddRange(parentClass.m_inheritedFields); m_inheritedFields.AddRange(parentClass.m_fields); m_inheritedImplementedInterfaces = allInheritedInterfaces; m_inheritedPassiveIfcConversions.AddRange(parentClass.m_passiveIfcConversions); m_inheritedPassiveIfcConversions.AddRange(parentClass.m_inheritedPassiveIfcConversions); IsValueType = (parentClass.FullName == "System.ValueType" && this.FullName != "System.Enum") || parentClass.FullName == "System.Enum"; IsEnum = parentClass.FullName == "System.Enum"; IsMulticastDelegate = (parentClass.FullName == "System.MulticastDelegate"); IsDelegate = IsMulticastDelegate || (parentClass.FullName == "System.Delegate" && this.FullName != "System.MulticastDelegate"); HaveInheritedStaticFields = (parentClass.HaveInheritedStaticFields || parentClass.HaveNewStaticFields); if (IsDelegate) { foreach (CppMethod method in m_methods) { if (method.Name == "Invoke") { DelegateSignature = method.MethodSignature; break; } } if (DelegateSignature == null) throw new ParseFailedException("Malformed delegate"); } } }
public void CheckInterfaceLegality(CppBuilder cppBuilder) { if (this.TypeDef.IsSealed) return; foreach (CLRTypeSpec ifcType in m_newlyImplementedInterfaces) { CppClass ifcClass = cppBuilder.GetCachedClass(ifcType); if (ifcClass.HaveAnyGenericMethods) throw new Exception(this.TypeDef.TypeNamespace + "." + this.TypeDef.TypeName + " must be sealed because it implements " + ifcType.ToString() + ", which contains virtual generic methods."); } }
// IMPORTANT: This must match "type declaration order" in the spec. // Clarity doesn't implement TDO itself, it depends on the new interfaces list being in TDO. public void AddExplicitInterface(CppBuilder builder, CLRTypeSpec ifcTypeSpec) { CppClass ifcType = builder.GetCachedClass(ifcTypeSpec); // CS0695 guarantees that type substitution will never result in multiple interfaces // resolving to the same passive conversion, so this strategy should be OK m_explicitInterfaces.Add(ifcTypeSpec); // NOTE: This function is called BEFORE inheritance resolution, which may remove some newly implemented // interfaces and convert them to reimplemented. foreach (CLRTypeSpec ifc in ifcType.m_newlyImplementedInterfaces) AddExplicitInterface(builder, ifc); // Only add each explicit interface once foreach (CLRTypeSpec ifc in m_newlyImplementedInterfaces) if (ifc.Equals(ifcTypeSpec)) return; // Unique, add it m_newlyImplementedInterfaces.Add(ifcTypeSpec); }
public CommonTypeLookup(CppBuilder builder) { CLRAssemblyCollection assm = builder.Assemblies; I = assm.InternVagueType(new CLRSigTypeSimple(CLRSigType.ElementType.I)); I8 = assm.InternVagueType(new CLRSigTypeSimple(CLRSigType.ElementType.I1)); I16 = assm.InternVagueType(new CLRSigTypeSimple(CLRSigType.ElementType.I2)); I32 = assm.InternVagueType(new CLRSigTypeSimple(CLRSigType.ElementType.I4)); I64 = assm.InternVagueType(new CLRSigTypeSimple(CLRSigType.ElementType.I8)); U = assm.InternVagueType(new CLRSigTypeSimple(CLRSigType.ElementType.U)); U8 = assm.InternVagueType(new CLRSigTypeSimple(CLRSigType.ElementType.U1)); U16 = assm.InternVagueType(new CLRSigTypeSimple(CLRSigType.ElementType.U2)); U32 = assm.InternVagueType(new CLRSigTypeSimple(CLRSigType.ElementType.U4)); U64 = assm.InternVagueType(new CLRSigTypeSimple(CLRSigType.ElementType.U8)); F32 = assm.InternVagueType(new CLRSigTypeSimple(CLRSigType.ElementType.R4)); F64 = assm.InternVagueType(new CLRSigTypeSimple(CLRSigType.ElementType.R8)); Object = assm.InternVagueType(new CLRSigTypeSimple(CLRSigType.ElementType.OBJECT)); String = assm.InternVagueType(new CLRSigTypeSimple(CLRSigType.ElementType.STRING)); Char = assm.InternVagueType(new CLRSigTypeSimple(CLRSigType.ElementType.CHAR)); Boolean = assm.InternVagueType(new CLRSigTypeSimple(CLRSigType.ElementType.BOOLEAN)); Array = assm.InternVagueType(new CLRSigTypeSimple(CLRSigType.ElementType.ARRAY)); ValueType = assm.InternVagueType(new CLRSigTypeSimple(CLRSigType.ElementType.VALUETYPE)); }
private void DetermineTraceability(CppBuilder builder) { switch (this.VType.ValType) { case VType.ValTypeEnum.ValueValue: m_traceability = builder.GetCachedTraceability(this.VType.TypeSpec); break; case VType.ValTypeEnum.ReferenceValue: case VType.ValTypeEnum.ManagedPtr: m_traceability = CppTraceabilityEnum.DefinitelyTraced; break; default: throw new ArgumentException(); } }
public static void WriteMethodCode(Clarity.Rpa.HighFileBuilder fileBuilder, BinaryWriter writer, CppBuilder builder, CppClass cls, CppMethod method) { List<VReg> args = new List<VReg>(); if (!method.Static) { CppClass thisClass = builder.GetCachedClass(method.DeclaredInClassSpec); CLRTypeSpec thisTypeSpec = method.DeclaredInClassSpec; VType vt = new VType(thisClass.IsValueType ? VType.ValTypeEnum.ManagedPtr : VType.ValTypeEnum.ReferenceValue, thisTypeSpec); args.Add(new VReg(builder, "bThis", vt, args.Count, VReg.UsageEnum.Argument)); } foreach (CLRMethodSignatureInstanceParam param in method.MethodSignature.ParamTypes) { CLRTypeSpec spec = param.Type; VType vt; switch (param.TypeOfType) { case CLRSigParamOrRetType.TypeOfTypeEnum.ByRef: vt = new VType(VType.ValTypeEnum.ManagedPtr, spec); break; case CLRSigParamOrRetType.TypeOfTypeEnum.Value: vt = new VType(ValTypeForTypeSpec(builder, spec), spec); break; default: throw new ArgumentException(); } args.Add(new VReg(builder, "bParam", vt, args.Count, VReg.UsageEnum.Argument)); } List<VReg> locals = new List<VReg>(); CLRSigLocalVarSig localVarSig = method.MethodDef.Method.LocalVarSig; if (localVarSig != null) { foreach (CLRSigLocalVar localVar in localVarSig.LocalVars) { if (localVar.Constraints != null && localVar.Constraints.Length > 0) throw new NotSupportedException("Local var constraints are not supported"); if (localVar.CustomMods != null && localVar.CustomMods.Length > 0) throw new NotSupportedException("Local var custom mods are not supported"); CLRTypeSpec localTypeSpec = builder.Assemblies.InternVagueType(localVar.Type); VReg vreg = null; switch (localVar.VarKind) { case CLRSigLocalVar.LocalVarKind.ByRef: vreg = new VReg(builder, "bLocal", new VType(VType.ValTypeEnum.ManagedPtr, localTypeSpec), locals.Count, VReg.UsageEnum.Local); break; case CLRSigLocalVar.LocalVarKind.Default: vreg = new VReg(builder, "bLocal", new VType(CppCilExporter.ValTypeForTypeSpec(builder, localTypeSpec), localTypeSpec), locals.Count, VReg.UsageEnum.Local); break; default: throw new NotImplementedException(); } locals.Add(vreg); } } foreach (VReg vReg in locals) vReg.Liven(); foreach (VReg vReg in args) vReg.Liven(); List<VReg> temporaries = new List<VReg>(); ExceptionHandlingRegion mainRegion = new ExceptionHandlingRegion(null, builder, method, 0, (uint)method.MethodDef.Method.Instructions.Length - 1, null); { CfgBuilder cfgBuilder = new CfgBuilder(mainRegion, builder, cls, method, args.ToArray(), locals.ToArray(), temporaries); mainRegion.RootCfgNode = cfgBuilder.RootNode; } CppMidCompiler midCompiler = new CppMidCompiler(builder, cls, method, mainRegion, "bTLFrame", args.ToArray(), locals.ToArray(), temporaries.ToArray()); midCompiler.EmitAll(fileBuilder, writer); //MidCompile(builder, cls, method, mainRegion, args.ToArray(), locals.ToArray(), writer.BaseStream); foreach (VReg vReg in locals) { if (!vReg.IsAlive || vReg.IsZombie) throw new Exception("Internal error: local vreg was killed"); } foreach (VReg vReg in args) { if (!vReg.IsAlive || vReg.IsZombie) throw new Exception("Internal error: arg vreg was killed"); } }