Beispiel #1
0
        /// <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);
        }
Beispiel #3
0
 private LLVMBasicBlockRef WriteReturnBlock(
     LLVMType Type,
     LLVMMethod Implementation,
     LLVMModuleBuilder Module)
 {
     return(WriteReturnBlock(Type.Name.ToString(), Module.DeclareVirtual(Implementation)));
 }
Beispiel #4
0
        /// <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);
        }
Beispiel #5
0
 public LLVMField(LLVMType DeclaringType, IFieldSignatureTemplate Template, int FieldIndex)
     : base(DeclaringType)
 {
     this.templateInstance = new FieldSignatureInstance(Template, this);
     this.FieldIndex       = FieldIndex;
 }
Beispiel #6
0
 public LLVMSymbolTypeMember(LLVMType DeclaringType, LLVMAbi Abi)
 {
     this.ParentType = DeclaringType;
     this.abiVal     = Abi.AsLazyAbi();
 }
Beispiel #7
0
 public LLVMSymbolTypeMember(LLVMType DeclaringType)
 {
     this.ParentType = DeclaringType;
     this.abiVal     = new Lazy <LLVMAbi>(PickLLVMAbi);
 }
Beispiel #8
0
 public LLVMMethod(LLVMType DeclaringType, IMethodSignatureTemplate Template, LLVMAbi Abi)
     : base(DeclaringType, Abi)
 {
     this.templateInstance  = new MethodSignatureInstance(Template, this);
     this.allInterfaceImpls = new Lazy <HashSet <LLVMMethod> >(LookupAllInterfaceImpls);
 }
Beispiel #9
0
        /// <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);
        }
Beispiel #10
0
 public LLVMProperty(LLVMType ParentType, IPropertySignatureTemplate Template)
 {
     this.ParentType        = ParentType;
     this.templateInstance  = new PropertySignatureInstance(Template, this);
     this.declaredAccessors = new List <LLVMAccessor>();
 }
Beispiel #11
0
 /// <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);
 }