/// <summary> /// Declares the data layout of the given type if it was not declared already. /// An LLVM type that corresponds to the declaration is returned. /// </summary> /// <param name="Type">The type to declare.</param> /// <returns>An LLVM type.</returns> public LLVMTypeRef DeclareDataLayout(LLVMType Type) { LLVMTypeRef result; if (!declaredDataLayouts.TryGetValue(Type, out result)) { if (Type.GetIsValueType() || Type.GetIsEnum() || Type.IsRuntimeImplementedDelegate) { // The layout of some types can be computed naively. result = Type.DefineLayout(this); declaredDataLayouts[Type] = result; } else { // Reference types cannot have their layout computed naively, because // they might refer to themselves. To get around this, we first declare // a named struct, then figure out what its layout should look like and // finally fill it out. result = StructCreateNamed(GetGlobalContext(), Type.FullName.ToString()); declaredDataLayouts[Type] = result; var layout = Type.DefineLayout(this); StructSetBody(result, GetStructElementTypes(layout), IsPackedStruct(layout)); } } return(result); }
public ITypeBuilder DeclareType(ITypeSignatureTemplate Template) { var childType = new LLVMType(this, Template); declaredTypes.Add(childType); return(childType); }
private LLVMBasicBlockRef WriteReturnBlock( LLVMType Type, LLVMMethod Implementation, LLVMModuleBuilder Module) { return(WriteReturnBlock(Type.Name.ToString(), Module.DeclareVirtual(Implementation))); }
/// <summary> /// Gets the vtable global for the given type. /// </summary> /// <param name="Type">The type to get the vtable of.</param> /// <returns>A vtable global.</returns> public VTableInstance GetVTable(IType Type) { VTableInstance vtable; if (!declaredVTables.TryGetValue(Type, out vtable)) { if (Type is LLVMType) { vtable = ((LLVMType)Type).DefineVTable(this); } else { vtable = new VTableInstance( LLVMType.DefineVTableGlobal(this, Type, new LLVMValueRef[] { }), new LLVMMethod[] { }); } declaredVTables[Type] = vtable; } return(vtable); }
public LLVMField(LLVMType DeclaringType, IFieldSignatureTemplate Template, int FieldIndex) : base(DeclaringType) { this.templateInstance = new FieldSignatureInstance(Template, this); this.FieldIndex = FieldIndex; }
public LLVMSymbolTypeMember(LLVMType DeclaringType, LLVMAbi Abi) { this.ParentType = DeclaringType; this.abiVal = Abi.AsLazyAbi(); }
public LLVMSymbolTypeMember(LLVMType DeclaringType) { this.ParentType = DeclaringType; this.abiVal = new Lazy <LLVMAbi>(PickLLVMAbi); }
public LLVMMethod(LLVMType DeclaringType, IMethodSignatureTemplate Template, LLVMAbi Abi) : base(DeclaringType, Abi) { this.templateInstance = new MethodSignatureInstance(Template, this); this.allInterfaceImpls = new Lazy <HashSet <LLVMMethod> >(LookupAllInterfaceImpls); }
/// <summary> /// Generates code that runs the given type's static constructors. /// </summary> /// <param name="BasicBlock">The basic block to extend.</param> /// <param name="Type">The type whose static constructors are to be run.</param> /// <returns>A basic block builder.</returns> public BasicBlockBuilder EmitRunStaticConstructors(BasicBlockBuilder BasicBlock, LLVMType Type) { if (Type.StaticConstructors.Count == 0) { return(BasicBlock); } // Get or create the lock triple for the type. A lock triple consists of: // // * A global Boolean flag that tells if all static constructors for // the type have been run. // // * A global Boolean flag that tells if the static constructors for // the type are in the process of being run. // // * A thread-local Boolean flag that tells if the static constructors // for the type are in the process of being run **by the current // thread.** // // * A common metadata node per thread-local variable that is used to // group loads/stores to that variable in an '!invariant.group'. // Tuple <LLVMValueRef, LLVMValueRef, LLVMValueRef, LLVMValueRef> lockQuad; if (!staticConstructorLocks.TryGetValue(Type, out lockQuad)) { string typeName = Type.Namespace.Assembly.Abi.Mangler.Mangle(Type, true); var hasRunGlobal = AddGlobal(module, Int8Type(), typeName + "__has_run_cctor"); hasRunGlobal.SetInitializer(ConstInt(Int8Type(), 0, false)); hasRunGlobal.SetLinkage(LLVMLinkage.LLVMInternalLinkage); var isRunningGlobal = AddGlobal(module, Int8Type(), typeName + "__is_running_cctor"); isRunningGlobal.SetInitializer(ConstInt(Int8Type(), 0, false)); isRunningGlobal.SetLinkage(LLVMLinkage.LLVMInternalLinkage); var isRunningHereGlobal = AddGlobal(module, Int1Type(), typeName + "__is_running_cctor_here"); isRunningHereGlobal.SetInitializer(ConstInt(Int1Type(), 0, false)); isRunningHereGlobal.SetLinkage(LLVMLinkage.LLVMInternalLinkage); isRunningHereGlobal.SetThreadLocal(true); var mdNode = MDNode(new LLVMValueRef[] { MDString(typeName + "__is_running_cctor_here") }); lockQuad = new Tuple <LLVMValueRef, LLVMValueRef, LLVMValueRef, LLVMValueRef>( hasRunGlobal, isRunningGlobal, isRunningHereGlobal, mdNode); staticConstructorLocks[Type] = lockQuad; } // A type's static constructors need to be run *before* any of its static fields // are accessed. Also, we need to ensure that a type's static constructors are // run only *once* in both single-threaded and multi-threaded environments. // // We'll generate something along the lines of this when a type's static // constructors need to be run: // // if (!is_running_cctor_here && !has_run_cctor) // { // while (!Interlocked.CompareExchange(ref is_running_cctor, false, true)) { } // if (!has_run_cctor) // { // cctor(); // has_run_cctor = true; // } // is_running_cctors = false; // } // // Or, using gotos: // // if (is_running_cctors_here) goto after_cctor; // else goto check_has_run_cctor; // // check_has_run_cctor: // is_running_cctors_here = true; // if (has_run_cctor) goto after_cctor; // else goto wait_for_cctor_lock; // // wait_for_cctor_lock: // has_exchanged = Interlocked.CompareExchange(ref is_running_cctos, false, true); // if (has_exchanged) goto maybe_run_cctor; // else goto wait_for_cctor_lock; // // maybe_run_cctor: // if (has_run_cctor) goto reset_lock; // else goto run_cctor; // // run_cctor: // cctor(); // has_run_cctor = true; // goto reset_lock; // // reset_lock: // is_running_cctors = false; // goto after_cctor; // // after_cctor: // ... var hasRunPtr = lockQuad.Item1; var isRunningPtr = lockQuad.Item2; var isRunningHerePtr = lockQuad.Item3; var invariantGroup = lockQuad.Item4; var invariantGroupMdId = GetMDKindID("invariant.group"); var checkHasRunBlock = BasicBlock.CreateChildBlock("check_has_run_cctor"); var waitForLockBlock = BasicBlock.CreateChildBlock("wait_for_cctor_lock"); var maybeRunBlock = BasicBlock.CreateChildBlock("maybe_run_cctor"); var runBlock = BasicBlock.CreateChildBlock("run_cctor"); var resetLockBlock = BasicBlock.CreateChildBlock("reset_lock"); var afterBlock = BasicBlock.CreateChildBlock("after_cctor"); // Implement the entry basic block. BuildCondBr( BasicBlock.Builder, WithMetadata( BuildLoad(BasicBlock.Builder, isRunningHerePtr, "is_running_cctor_here"), invariantGroupMdId, invariantGroup), afterBlock.Block, checkHasRunBlock.Block); // Implement the `check_has_run_cctor` block. WithMetadata( BuildStore(checkHasRunBlock.Builder, ConstInt(Int1Type(), 1, false), isRunningHerePtr), invariantGroupMdId, invariantGroup); BuildCondBr( checkHasRunBlock.Builder, IntToBoolean( checkHasRunBlock.Builder, BuildAtomicLoad(checkHasRunBlock.Builder, hasRunPtr, "has_run_cctor")), afterBlock.Block, waitForLockBlock.Block); // Implement the `wait_for_cctor_lock` block. var cmpxhg = BuildAtomicCmpXchg( waitForLockBlock.Builder, isRunningPtr, ConstInt(Int8Type(), 0, false), ConstInt(Int8Type(), 1, false), LLVMAtomicOrdering.LLVMAtomicOrderingSequentiallyConsistent, LLVMAtomicOrdering.LLVMAtomicOrderingMonotonic, false); cmpxhg.SetValueName("is_running_cctor_cmpxhg"); BuildCondBr( waitForLockBlock.Builder, BuildExtractValue( waitForLockBlock.Builder, cmpxhg, 1, "has_exchanged"), maybeRunBlock.Block, waitForLockBlock.Block); // Implement the `maybe_run_cctor` block. BuildCondBr( maybeRunBlock.Builder, IntToBoolean( maybeRunBlock.Builder, BuildAtomicLoad(maybeRunBlock.Builder, hasRunPtr, "has_run_cctor")), resetLockBlock.Block, runBlock.Block); // Implement the `run_cctor` block. for (int i = 0; i < Type.StaticConstructors.Count; i++) { BuildCall(runBlock.Builder, Declare(Type.StaticConstructors[i]), new LLVMValueRef[] { }, ""); } BuildAtomicStore(runBlock.Builder, ConstInt(Int8Type(), 1, false), hasRunPtr); BuildBr(runBlock.Builder, resetLockBlock.Block); // Implement the `reset_lock` block. BuildAtomicStore(resetLockBlock.Builder, ConstInt(Int8Type(), 0, false), isRunningPtr); BuildBr(resetLockBlock.Builder, afterBlock.Block); return(afterBlock); }
public LLVMProperty(LLVMType ParentType, IPropertySignatureTemplate Template) { this.ParentType = ParentType; this.templateInstance = new PropertySignatureInstance(Template, this); this.declaredAccessors = new List <LLVMAccessor>(); }
/// <summary> /// Registers the given method as the implementation for the given type. /// </summary> /// <param name="Type">The type that implements the method.</param> /// <param name="Method">The implementation method.</param> public void Implement(LLVMType Type, LLVMMethod Method) { impls.Add(Type, Method); }