diff options
author | Morgan Brown <morganbr@users.noreply.github.com> | 2018-03-06 15:15:09 +0300 |
---|---|---|
committer | GitHub <noreply@github.com> | 2018-03-06 15:15:09 +0300 |
commit | 19116562388ed45b336321456079fc7c398556fc (patch) | |
tree | bb027294e397853d1db5852090881de0b1034088 /src/ILCompiler.WebAssembly | |
parent | 40b2afa6ba669c28aeffdd5a8d544220b2312232 (diff) |
Static constructors for WebAssembly (#5425)
* Implement static constructor triggering. Also includes several bug fixes found in the process:
* Don't make the ClassConstructorRunner depend on module intialization
* Moves non-GC statics and thread statics from globals to the type's data regions. GC statics can't be moved until we can call InitializeModules on startup.
* Devirtualizing interface calls to structs in order to be able to compile the class constructor runner.
* Add a prolog block before Block0 to allow branching to Block0, which happens in retail builds
* Correct use of unreachable in traps and at the end of finally blocks to fix more retail build problems
* Stop reusing spill slots when a spilled value is spilled again. This avoids cases where the spills feeding into a block don't use the same slot
* Enable thunks for NativeCallable methods and call RhpReversePInvoke for them
* Fix alignment for cases where a small type is followed by a larger one
* Workaround for Emscripten atomics bug
Diffstat (limited to 'src/ILCompiler.WebAssembly')
-rw-r--r-- | src/ILCompiler.WebAssembly/src/CodeGen/ILToWebAssemblyImporter.cs | 257 | ||||
-rw-r--r-- | src/ILCompiler.WebAssembly/src/CodeGen/WebAssemblyObjectWriter.cs | 8 |
2 files changed, 203 insertions, 62 deletions
diff --git a/src/ILCompiler.WebAssembly/src/CodeGen/ILToWebAssemblyImporter.cs b/src/ILCompiler.WebAssembly/src/CodeGen/ILToWebAssemblyImporter.cs index 8b0936d1e..b4859b849 100644 --- a/src/ILCompiler.WebAssembly/src/CodeGen/ILToWebAssemblyImporter.cs +++ b/src/ILCompiler.WebAssembly/src/CodeGen/ILToWebAssemblyImporter.cs @@ -110,6 +110,8 @@ namespace Internal.IL { FindBasicBlocks(); + GenerateProlog(); + try { ImportBasicBlocks(); @@ -130,39 +132,53 @@ namespace Internal.IL LLVM.PositionBuilderAtEnd(_builder, trapBlock); EmitTrapCall(); - LLVM.BuildRetVoid(_builder); throw; } finally { // Generate thunk for runtime exports - if (_method.IsRuntimeExport) + if (_method.IsRuntimeExport || _method.IsNativeCallable) { - EmitNativeToManagedThunk(_compilation, _method, ((EcmaMethod)_method).GetRuntimeExportName(), _llvmFunction); + EcmaMethod ecmaMethod = ((EcmaMethod)_method); + string exportName = ecmaMethod.IsRuntimeExport ? ecmaMethod.GetRuntimeExportName() : ecmaMethod.GetNativeCallableExportName(); + EmitNativeToManagedThunk(_compilation, _method, exportName, _llvmFunction); } } } private void GenerateProlog() { - if (!_methodIL.IsInitLocals) - { - return; - } + LLVMBasicBlockRef prologBlock = LLVM.AppendBasicBlock(_llvmFunction, "Prolog"); + LLVM.PositionBuilderAtEnd(_builder, prologBlock); - int totalLocalSize = 0; - foreach(LocalVariableDefinition local in _locals) + if (_methodIL.IsInitLocals) { - totalLocalSize = PadNextOffset(local.Type, totalLocalSize); + int totalLocalSize = 0; + foreach (LocalVariableDefinition local in _locals) + { + totalLocalSize = PadNextOffset(local.Type, totalLocalSize); + } + + var sp = LLVM.GetFirstParam(_llvmFunction); + int paramOffset = GetTotalParameterOffset(); + for (int i = 0; i < totalLocalSize; i++) + { + var stackOffset = LLVM.BuildGEP(_builder, sp, new LLVMValueRef[] { LLVM.ConstInt(LLVM.Int32Type(), (ulong)(paramOffset + i), LLVMMisc.False) }, String.Empty); + LLVM.BuildStore(_builder, LLVM.ConstInt(LLVM.Int8Type(), 0, LLVMMisc.False), stackOffset); + } } - var sp = LLVM.GetFirstParam(_llvmFunction); - int paramOffset = GetTotalParameterOffset(); - for (int i = 0; i < totalLocalSize; i++) + MetadataType metadataType = (MetadataType)_thisType; + if (!metadataType.IsBeforeFieldInit) { - var stackOffset = LLVM.BuildGEP(_builder, sp, new LLVMValueRef[] { LLVM.ConstInt(LLVM.Int32Type(), (ulong)(paramOffset + i), LLVMMisc.False) }, String.Empty); - LLVM.BuildStore(_builder, LLVM.ConstInt(LLVM.Int8Type(), 0, LLVMMisc.False), stackOffset); + if (!_method.IsStaticConstructor && _method.Signature.IsStatic || _method.IsConstructor || (_thisType.IsValueType && !_method.Signature.IsStatic)) + { + TriggerCctor(metadataType); + } } + + LLVMBasicBlockRef block0 = GetLLVMBasicBlockForBlock(_basicBlocks[0]); + LLVM.BuildBr(_builder, block0); } private LLVMValueRef CreateLLVMFunction(string mangledName) @@ -278,19 +294,9 @@ namespace Internal.IL } } - bool isFirstBlock = false; - if(_curBasicBlock.Equals(default(LLVMBasicBlockRef))) - { - isFirstBlock = true; - } _curBasicBlock = GetLLVMBasicBlockForBlock(basicBlock); LLVM.PositionBuilderAtEnd(_builder, _curBasicBlock); - - if(isFirstBlock) - { - GenerateProlog(); - } } private void EndImportingBasicBlock(BasicBlock basicBlock) @@ -305,10 +311,6 @@ namespace Internal.IL LLVM.BuildBr(_builder, GetLLVMBasicBlockForBlock(_basicBlocks[_currentOffset])); } - else - { - LLVM.BuildRet(_builder, default(LLVMValueRef)); - } } } @@ -749,6 +751,7 @@ namespace Internal.IL { offset = PadNextOffset(_signature[i], offset); } + offset = PadOffset(argType, offset); } private void GetLocalSizeAndOffsetAtIndex(int index, out int size, out int offset) @@ -761,6 +764,7 @@ namespace Internal.IL { offset = PadNextOffset(_locals[i].Type, offset); } + offset = PadOffset(local.Type, offset); } private void GetSpillSizeAndOffsetAtIndex(int index, out int size, out int offset) @@ -773,6 +777,7 @@ namespace Internal.IL { offset = PadNextOffset(_spilledExpressions[i].Type, offset); } + offset = PadOffset(spill.Type, offset); } public int PadNextOffset(TypeDesc type, int atOffset) @@ -810,7 +815,7 @@ namespace Internal.IL { TypeDesc type; LLVMValueRef typedLoadLocation = LoadVarAddress(index, argument ? LocalVarKind.Argument : LocalVarKind.Local, out type); - _stack.Push(new AddressExpressionEntry(StackValueKind.ByRef, "ldloca", typedLoadLocation, type.MakePointerType())); + _stack.Push(new AddressExpressionEntry(StackValueKind.ByRef, "ldloca", typedLoadLocation, type.MakeByRefType())); } private void ImportDup() @@ -959,9 +964,46 @@ namespace Internal.IL if (!_compilation.HasFixedSlotVTable(callee.OwningType)) AddVirtualMethodReference(callee); - //TODO: needs runtime support for DispatchByInterface + bool isValueTypeCall = false; + TypeDesc thisType = thisPointer.Type; + TypeFlags category = thisType.Category; + MethodDesc targetMethod = null; + TypeDesc parameterType = null; + + if (category == TypeFlags.ByRef) + { + parameterType = ((ByRefType)thisType).ParameterType; + if (parameterType.IsValueType) + { + isValueTypeCall = true; + } + } if (callee.OwningType.IsInterface) - throw new NotImplementedException("Interface call"); + { + // For value types, devirtualize the call + if (isValueTypeCall) + { + targetMethod = parameterType.ResolveInterfaceMethodTarget(callee); + } + else + { + //TODO: needs runtime support for DispatchByInterface + throw new NotImplementedException("Interface call"); + } + } + else + { + if (isValueTypeCall) + { + targetMethod = parameterType.FindVirtualFunctionTargetMethodOnObjectType(callee); + } + } + + if (targetMethod != null) + { + AddMethodReference(targetMethod); + return GetOrCreateLLVMFunction(_compilation.NameMangler.GetMangledMethodName(targetMethod).ToString()); + } return GetCallableVirtualMethod(thisPointer.ValueAsType(LLVM.PointerType(LLVM.Int8Type(), 0), _builder), callee); } @@ -1204,11 +1246,14 @@ namespace Internal.IL argType = signature[index - instanceAdjustment]; } + // The previous argument might have left this type unaligned, so pad if necessary + argOffset = PadOffset(argType, argOffset); + LLVMTypeRef valueType = GetLLVMTypeForTypeDesc(argType); ImportStoreHelper(toStore.ValueAsType(valueType, _builder), valueType, castShadowStack, (uint)argOffset); - argOffset = PadNextOffset(argType, argOffset); + argOffset += argType.GetElementSize().AsInt; } LLVMValueRef fn; @@ -1382,25 +1427,61 @@ namespace Internal.IL LLVMTypeRef thunkSig = LLVM.FunctionType(GetLLVMTypeForTypeDesc(method.Signature.ReturnType), llvmParams, false); LLVMValueRef thunkFunc = LLVM.AddFunction(compilation.Module, nativeName, thunkSig); - LLVMBasicBlockRef block = LLVM.AppendBasicBlock(thunkFunc, "Block0"); + LLVMBasicBlockRef shadowStackSetupBlock = LLVM.AppendBasicBlock(thunkFunc, "ShadowStackSetupBlock"); + LLVMBasicBlockRef allocateShadowStackBlock = LLVM.AppendBasicBlock(thunkFunc, "allocateShadowStackBlock"); + LLVMBasicBlockRef managedCallBlock = LLVM.AppendBasicBlock(thunkFunc, "ManagedCallBlock"); + LLVMBuilderRef builder = LLVM.CreateBuilder(); - LLVM.PositionBuilderAtEnd(builder, block); + LLVM.PositionBuilderAtEnd(builder, shadowStackSetupBlock); - LLVMValueRef shadowStack = LLVM.BuildLoad(builder, ShadowStackTop, ""); + // Allocate shadow stack if it's null + LLVMValueRef shadowStackPtr = LLVM.BuildAlloca(builder, LLVM.PointerType(LLVM.Int8Type(), 0), "ShadowStackPtr"); + LLVMValueRef savedShadowStack = LLVM.BuildLoad(builder, ShadowStackTop, "SavedShadowStack"); + LLVM.BuildStore(builder, savedShadowStack, shadowStackPtr); + LLVMValueRef shadowStackNull = LLVM.BuildICmp(builder, LLVMIntPredicate.LLVMIntEQ, savedShadowStack, LLVM.ConstPointerNull(LLVM.PointerType(LLVM.Int8Type(), 0)), "ShadowStackNull"); + LLVM.BuildCondBr(builder, shadowStackNull, allocateShadowStackBlock, managedCallBlock); + LLVM.PositionBuilderAtEnd(builder, allocateShadowStackBlock); + + LLVMValueRef newShadowStack = LLVM.BuildArrayMalloc(builder, LLVM.Int8Type(), BuildConstInt32(1000000), "NewShadowStack"); + LLVM.BuildStore(builder, newShadowStack, shadowStackPtr); + LLVM.BuildBr(builder, managedCallBlock); + + LLVM.PositionBuilderAtEnd(builder, managedCallBlock); + LLVMTypeRef reversePInvokeFrameType = LLVM.StructType(new LLVMTypeRef[] { LLVM.PointerType(LLVM.Int8Type(), 0), LLVM.PointerType(LLVM.Int8Type(), 0) }, false); + LLVMValueRef reversePInvokeFrame = default(LLVMValueRef); + LLVMTypeRef reversePInvokeFunctionType = LLVM.FunctionType(LLVM.VoidType(), new LLVMTypeRef[] { LLVM.PointerType(reversePInvokeFrameType, 0) }, false); + if (method.IsNativeCallable) + { + reversePInvokeFrame = LLVM.BuildAlloca(builder, reversePInvokeFrameType, "ReversePInvokeFrame"); + LLVMValueRef RhpReversePInvoke2 = GetOrCreateLLVMFunction("RhpReversePInvoke2", reversePInvokeFunctionType); + LLVM.BuildCall(builder, RhpReversePInvoke2, new LLVMValueRef[] { reversePInvokeFrame }, ""); + } + + LLVMValueRef shadowStack = LLVM.BuildLoad(builder, shadowStackPtr, "ShadowStack"); int curOffset = 0; + curOffset = PadNextOffset(method.Signature.ReturnType, curOffset); + LLVMValueRef calleeFrame = LLVM.BuildGEP(builder, shadowStack, new LLVMValueRef[] { BuildConstInt32(curOffset) }, "calleeFrame"); + for (int i = 0; i < llvmParams.Length; i++) { + curOffset = PadOffset(method.Signature[i], curOffset); LLVMValueRef argAddr = LLVM.BuildGEP(builder, shadowStack, new LLVMValueRef[] { LLVM.ConstInt(LLVM.Int32Type(), (ulong)curOffset, LLVMMisc.False) }, "arg" + i); LLVM.BuildStore(builder, LLVM.GetParam(thunkFunc, (uint)i), CastIfNecessary(builder, argAddr, LLVM.PointerType(llvmParams[i], 0))); curOffset = PadNextOffset(method.Signature[i], curOffset); } - LLVMValueRef retAddr = LLVM.BuildGEP(builder, shadowStack, new LLVMValueRef[] { LLVM.ConstInt(LLVM.Int32Type(), (ulong)curOffset, LLVMMisc.False) }, "retAddr"); - LLVM.BuildCall(builder, managedFunction, new LLVMValueRef[] { shadowStack, retAddr }, ""); + LLVM.BuildCall(builder, managedFunction, new LLVMValueRef[] { calleeFrame, shadowStack }, ""); + + if (method.IsNativeCallable) + { + LLVMValueRef RhpReversePInvokeReturn2 = GetOrCreateLLVMFunction("RhpReversePInvokeReturn2", reversePInvokeFunctionType); + LLVM.BuildCall(builder, RhpReversePInvokeReturn2, new LLVMValueRef[] { reversePInvokeFrame }, ""); + } + if (method.Signature.ReturnType != compilation.TypeSystemContext.GetWellKnownType(WellKnownType.Void)) { - LLVM.BuildRet(builder, LLVM.BuildLoad(builder, CastIfNecessary(builder, retAddr, LLVM.PointerType(GetLLVMTypeForTypeDesc(method.Signature.ReturnType), 0)), "")); + LLVM.BuildRet(builder, LLVM.BuildLoad(builder, CastIfNecessary(builder, shadowStack, LLVM.PointerType(GetLLVMTypeForTypeDesc(method.Signature.ReturnType), 0)), "")); } else { @@ -1470,9 +1551,6 @@ namespace Internal.IL if (opcode == ILOpcode.br) { ImportFallthrough(target); - //TODO: why does this illegal branch happen in System.Reflection.MemberFilter.ctor - if (target.StartOffset == 0) - throw new InvalidProgramException(); LLVM.BuildBr(_builder, GetLLVMBasicBlockForBlock(target)); } else @@ -1593,9 +1671,6 @@ namespace Internal.IL } } } - //TODO: why did this happen only during an optimized build of [System.Private.CoreLib]System.Threading.Lock.ReleaseContended - if (target.StartOffset == 0) - throw new NotImplementedException("cant branch to entry basic block"); ImportFallthrough(target); ImportFallthrough(fallthrough); @@ -1630,7 +1705,7 @@ namespace Internal.IL var expressionPointer = pointer as ExpressionEntry; if(type == null) { - type = GetWellKnownType(WellKnownType.Object).MakeByRefType(); + type = GetWellKnownType(WellKnownType.Object); } LLVMValueRef pointerElementType = pointer.ValueAsType(type.MakePointerType(), _builder); @@ -1827,6 +1902,7 @@ namespace Internal.IL if(enumCleanTargetType != null && targetType.IsPrimitive) { if(enumCleanTargetType.IsWellKnownType(WellKnownType.Byte) || + enumCleanTargetType.IsWellKnownType(WellKnownType.Char) || enumCleanTargetType.IsWellKnownType(WellKnownType.UInt16) || enumCleanTargetType.IsWellKnownType(WellKnownType.UInt32) || enumCleanTargetType.IsWellKnownType(WellKnownType.UInt64) || @@ -2186,7 +2262,49 @@ namespace Internal.IL if (!isStatic) _stack.Pop(); - return WebAssemblyObjectWriter.EmitGlobal(Module, field, _compilation.NameMangler); + ISymbolNode node; + MetadataType owningType = (MetadataType)field.OwningType; + LLVMValueRef staticBase; + int fieldOffset = field.Offset.AsInt; + + // TODO: We need the right thread static per thread + if (field.IsThreadStatic) + { + node = _compilation.NodeFactory.TypeThreadStaticsSymbol(owningType); + staticBase = LoadAddressOfSymbolNode(node); + } + + else if (field.HasGCStaticBase) + { + node = _compilation.NodeFactory.TypeGCStaticsSymbol(owningType); + + // We can't use GCStatics in the data section until we can successfully call + // InitializeModules on startup, so stick with globals for now + //LLVMValueRef basePtrPtr = LoadAddressOfSymbolNode(node); + //staticBase = LLVM.BuildLoad(_builder, LLVM.BuildLoad(_builder, LLVM.BuildPointerCast(_builder, basePtrPtr, LLVM.PointerType(LLVM.PointerType(LLVM.PointerType(LLVM.Int8Type(), 0), 0), 0), "castBasePtrPtr"), "basePtr"), "base"); + staticBase = WebAssemblyObjectWriter.EmitGlobal(Module, field, _compilation.NameMangler); + fieldOffset = 0; + } + else + { + node = _compilation.NodeFactory.TypeNonGCStaticsSymbol(owningType); + staticBase = LoadAddressOfSymbolNode(node); + } + + _dependencies.Add(node); + + // Run static constructor if necessary + // If the type is non-BeforeFieldInit, this is handled before calling any methods on it + if (owningType.IsBeforeFieldInit || (!owningType.IsBeforeFieldInit && owningType != _thisType)) + { + TriggerCctor(owningType); + } + + LLVMValueRef castStaticBase = LLVM.BuildPointerCast(_builder, staticBase, LLVM.PointerType(LLVM.Int8Type(), 0), owningType.Name + "_statics"); + LLVMValueRef fieldAddr = LLVM.BuildGEP(_builder, castStaticBase, new LLVMValueRef[] { BuildConstInt32(fieldOffset) }, field.Name + "_addr"); + + + return fieldAddr; } else { @@ -2194,6 +2312,27 @@ namespace Internal.IL } } + /// <summary> + /// Triggers a static constructor check and call for types that have them + /// </summary> + private void TriggerCctor(MetadataType type) + { + if (_compilation.TypeSystemContext.HasLazyStaticConstructor(type)) + { + ISymbolNode classConstructionContextSymbol = _compilation.NodeFactory.TypeNonGCStaticsSymbol(type); + _dependencies.Add(classConstructionContextSymbol); + LLVMValueRef firstNonGcStatic = LoadAddressOfSymbolNode(classConstructionContextSymbol); + + // TODO: Codegen could check whether it has already run rather than calling into EnsureClassConstructorRun + // but we'd have to figure out how to manage the additional basic blocks + LLVMValueRef classConstructionContextPtr = LLVM.BuildGEP(_builder, firstNonGcStatic, new LLVMValueRef[] { BuildConstInt32(-2) }, "classConstructionContext"); + StackEntry classConstructionContext = new AddressExpressionEntry(StackValueKind.NativeInt, "classConstructionContext", classConstructionContextPtr, GetWellKnownType(WellKnownType.IntPtr)); + MetadataType helperType = _compilation.TypeSystemContext.SystemModule.GetKnownType("System.Runtime.CompilerServices", "ClassConstructorRunner"); + MethodDesc helperMethod = helperType.GetKnownMethod("EnsureClassConstructorRun", null); + HandleCall(helperMethod, helperMethod.Signature, new StackEntry[] { classConstructionContext }); + } + } + private void ImportLoadField(int token, bool isStatic) { FieldDesc field = (FieldDesc)_methodIL.GetObject(token); @@ -2205,7 +2344,7 @@ namespace Internal.IL { FieldDesc field = (FieldDesc)_methodIL.GetObject(token); LLVMValueRef fieldAddress = GetFieldAddress(field, isStatic); - _stack.Push(new AddressExpressionEntry(StackValueKind.ByRef, "ldflda", fieldAddress, field.FieldType.MakePointerType())); + _stack.Push(new AddressExpressionEntry(StackValueKind.ByRef, "ldflda", fieldAddress, field.FieldType.MakeByRefType())); } private void ImportStoreField(int token, bool isStatic) @@ -2372,6 +2511,9 @@ namespace Internal.IL private void ImportEndFinally() { + // These are currently unreachable since we can't get into finally blocks. + // We'll need to change this once we have other finally block handling. + LLVM.BuildUnreachable(_builder); } private void ImportFallthrough(BasicBlock next) @@ -2418,9 +2560,6 @@ namespace Internal.IL if (entry == null) throw new InvalidProgramException(); - if (currentEntry is SpilledExpressionEntry) - continue; //this is already a sharable value - StoreTemp(entry.LocalIndex, currentEntry.ValueAsType(entry.Type, _builder)); } } @@ -2453,16 +2592,11 @@ namespace Internal.IL private StackEntry NewSpillSlot(StackEntry entry) { - if (entry is SpilledExpressionEntry) - return entry; - else - { - var entryType = entry.Type ?? GetWellKnownType(WellKnownType.Object); //type is required here, currently the only time entry.Type is null is if someone has pushed a null literal - var entryIndex = _spilledExpressions.Count; - var newEntry = new SpilledExpressionEntry(entry.Kind, entry is ExpressionEntry ? ((ExpressionEntry)entry).Name : "spilled" + entryIndex, entryType, entryIndex, this); - _spilledExpressions.Add(newEntry); - return newEntry; - } + var entryType = entry.Type ?? GetWellKnownType(WellKnownType.Object); //type is required here, currently the only time entry.Type is null is if someone has pushed a null literal + var entryIndex = _spilledExpressions.Count; + var newEntry = new SpilledExpressionEntry(entry.Kind, entry is ExpressionEntry ? ((ExpressionEntry)entry).Name : "spilled" + entryIndex, entryType, entryIndex, this); + _spilledExpressions.Add(newEntry); + return newEntry; } private StackEntry TakeAddressOf(StackEntry entry) @@ -2535,6 +2669,7 @@ namespace Internal.IL TrapFunction = LLVM.AddFunction(Module, "llvm.trap", LLVM.FunctionType(LLVM.VoidType(), Array.Empty<LLVMTypeRef>(), false)); } LLVM.BuildCall(_builder, TrapFunction, Array.Empty<LLVMValueRef>(), string.Empty); + LLVM.BuildUnreachable(_builder); } private void EmitDoNothingCall() diff --git a/src/ILCompiler.WebAssembly/src/CodeGen/WebAssemblyObjectWriter.cs b/src/ILCompiler.WebAssembly/src/CodeGen/WebAssemblyObjectWriter.cs index 8808a2e02..29a6a26cd 100644 --- a/src/ILCompiler.WebAssembly/src/CodeGen/WebAssemblyObjectWriter.cs +++ b/src/ILCompiler.WebAssembly/src/CodeGen/WebAssemblyObjectWriter.cs @@ -243,7 +243,13 @@ namespace ILCompiler.DependencyAnalysis LLVMTypeRef reversePInvokeFrameType = LLVM.StructType(new LLVMTypeRef[] { LLVM.PointerType(LLVM.Int8Type(), 0), LLVM.PointerType(LLVM.Int8Type(), 0) }, false); LLVMValueRef reversePinvokeFrame = LLVM.BuildAlloca(builder, reversePInvokeFrameType, "ReversePInvokeFrame"); - LLVMValueRef RhpReversePInvoke2 = LLVM.AddFunction(Module, "RhpReversePInvoke2", LLVM.FunctionType(LLVM.VoidType(), new LLVMTypeRef[] { LLVM.PointerType(reversePInvokeFrameType, 0) }, false)); + LLVMValueRef RhpReversePInvoke2 = LLVM.GetNamedFunction(Module, "RhpReversePInvoke2"); + + if (RhpReversePInvoke2.Pointer == IntPtr.Zero) + { + RhpReversePInvoke2 = LLVM.AddFunction(Module, "RhpReversePInvoke2", LLVM.FunctionType(LLVM.VoidType(), new LLVMTypeRef[] { LLVM.PointerType(reversePInvokeFrameType, 0) }, false)); + } + LLVM.BuildCall(builder, RhpReversePInvoke2, new LLVMValueRef[] { reversePinvokeFrame }, ""); var shadowStack = LLVM.BuildMalloc(builder, LLVM.ArrayType(LLVM.Int8Type(), 1000000), String.Empty); |