Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/mono/corert.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMorgan Brown <morganbr@users.noreply.github.com>2017-12-27 13:49:39 +0300
committerGitHub <noreply@github.com>2017-12-27 13:49:39 +0300
commit843f6ab3477eeb36f221d502e5ceaa780ac6c503 (patch)
treee873274e06d1c2dabd8a63bc9fe1892399fd59f0 /src/ILCompiler.WebAssembly
parent82fe1d0f3827d1c272ddd9eeeca07d53dc69cb07 (diff)
Link WebAssembly runtime (#5141)
* Changes to hook up the portable runtime and bootstrapper. Includes implementing allocation using RhpNewFast as well as some floating point codegen fixes required to make the new code compile. Removes usage of buggy dladdr API in WebAssembly, fixes order of conditional branch expressions, which fixes printing when C# optimizations are enabled, adds debug and release flags to emcc, updates WebAssembly documentation to reflect the new build flavor and linking steps. Adds thunks for RuntimeExport methods to fix linker errors for missing runtime exports.
Diffstat (limited to 'src/ILCompiler.WebAssembly')
-rw-r--r--src/ILCompiler.WebAssembly/src/CodeGen/ILToWebAssemblyImporter.cs228
-rw-r--r--src/ILCompiler.WebAssembly/src/CodeGen/ILToWebAssemblyImporter_Statics.cs6
-rw-r--r--src/ILCompiler.WebAssembly/src/CodeGen/WebAssemblyObjectWriter.cs18
3 files changed, 204 insertions, 48 deletions
diff --git a/src/ILCompiler.WebAssembly/src/CodeGen/ILToWebAssemblyImporter.cs b/src/ILCompiler.WebAssembly/src/CodeGen/ILToWebAssemblyImporter.cs
index d91017d75..420d12f2e 100644
--- a/src/ILCompiler.WebAssembly/src/CodeGen/ILToWebAssemblyImporter.cs
+++ b/src/ILCompiler.WebAssembly/src/CodeGen/ILToWebAssemblyImporter.cs
@@ -12,6 +12,7 @@ using LLVMSharp;
using ILCompiler.CodeGen;
using ILCompiler.DependencyAnalysis;
using ILCompiler.DependencyAnalysisFramework;
+using Internal.TypeSystem.Ecma;
namespace Internal.IL
{
@@ -125,6 +126,14 @@ namespace Internal.IL
LLVM.BuildRetVoid(_builder);
throw;
}
+ finally
+ {
+ // Generate thunk for runtime exports
+ if (_method.IsRuntimeExport)
+ {
+ EmitNativeToManagedThunk(_compilation, _method, ((EcmaMethod)_method).GetRuntimeExportName(), _llvmFunction);
+ }
+ }
}
private void GenerateProlog()
@@ -346,23 +355,33 @@ namespace Internal.IL
private static LLVMValueRef CastIntValue(LLVMBuilderRef builder, LLVMValueRef value, LLVMTypeRef type, bool signExtend)
{
+ LLVMTypeKind typeKind = LLVM.TypeOf(value).TypeKind;
if (LLVM.TypeOf(value).Pointer == type.Pointer)
{
return value;
}
- else if (LLVM.TypeOf(value).TypeKind == LLVMTypeKind.LLVMPointerTypeKind)
+ else if (typeKind == LLVMTypeKind.LLVMPointerTypeKind)
{
return LLVM.BuildPtrToInt(builder, value, type, "intcast");
}
+ else if (typeKind == LLVMTypeKind.LLVMFloatTypeKind || typeKind == LLVMTypeKind.LLVMDoubleTypeKind)
+ {
+ if (signExtend)
+ {
+ return LLVM.BuildFPToSI(builder, value, type, "fptosi");
+ }
+ else
+ {
+ return LLVM.BuildFPToUI(builder, value, type, "fptoui");
+ }
+ }
else if (signExtend && type.GetIntTypeWidth() > LLVM.TypeOf(value).GetIntTypeWidth())
{
return LLVM.BuildSExtOrBitCast(builder, value, type, "SExtOrBitCast");
}
else
{
- if (LLVM.TypeOf(value).TypeKind != LLVMTypeKind.LLVMIntegerTypeKind)
- throw new NotImplementedException();
-
+ Debug.Assert(typeKind == LLVMTypeKind.LLVMIntegerTypeKind);
return LLVM.BuildIntCast(builder, value, type, "intcast");
}
}
@@ -882,13 +901,11 @@ namespace Internal.IL
objectSize += type.Context.Target.PointerSize;
}
- LLVMValueRef allocatedMemory = LLVM.BuildMalloc(_builder, LLVM.ArrayType(LLVM.Int8Type(), (uint)objectSize), "newobj");
- LLVMValueRef castMemory = LLVM.BuildPointerCast(_builder, allocatedMemory, LLVM.PointerType(LLVM.Int8Type(), 0), "castnewobj");
- ImportCallMemset(castMemory, 0, objectSize);
- LLVMValueRef eeTypePointer = GetEETypeForTypeDesc(type);
- LLVMValueRef objectHeaderPtr = LLVM.BuildPointerCast(_builder, allocatedMemory, LLVM.PointerType(LLVM.TypeOf(eeTypePointer), 0), "objectHeaderPtr");
- LLVM.BuildStore(_builder, eeTypePointer, objectHeaderPtr);
- return new ExpressionEntry(StackValueKind.ObjRef, "newobj", castMemory, type);
+ LLVMValueRef eeTypePointer = GetEETypeForTypeDesc(type, true);
+ var rhpNewFastSig = LLVM.FunctionType(LLVMTypeRef.PointerType(LLVMTypeRef.Int8Type(), 0), new LLVMTypeRef[] { LLVM.TypeOf(eeTypePointer) }, false);
+ var rhpNewFast = GetOrCreateLLVMFunction("RhpNewFast", rhpNewFastSig);
+ LLVMValueRef allocatedMemory = LLVM.BuildCall(_builder, rhpNewFast, new LLVMValueRef[] { eeTypePointer }, "newobj");
+ return new ExpressionEntry(StackValueKind.ObjRef, "newobj", allocatedMemory, type);
}
private static LLVMValueRef BuildConstInt1(int number)
@@ -907,14 +924,21 @@ namespace Internal.IL
return LLVM.ConstInt(LLVM.Int32Type(), (ulong)number, LLVMMisc.False);
}
- private LLVMValueRef GetEETypeForTypeDesc(TypeDesc target)
+ private LLVMValueRef GetEETypeForTypeDesc(TypeDesc target, bool constructed)
{
- ISymbolNode node = _compilation.NodeFactory.ConstructedTypeSymbol(target);
+ ISymbolNode node;
+ if (constructed)
+ {
+ node = _compilation.NodeFactory.ConstructedTypeSymbol(target);
+ }
+ else
+ {
+ node = _compilation.NodeFactory.NecessaryTypeSymbol(target);
+ }
LLVMValueRef eeTypePointer = LoadAddressOfSymbolNode(node);
_dependencies.Add(node);
- var eeTypePtrType = _compilation.TypeSystemContext.SystemModule.GetKnownType("System", "EETypePtr");
- var ptrPtrType = LLVM.PointerType(GetLLVMTypeForTypeDesc(eeTypePtrType), 0);
- return LLVM.BuildPointerCast(_builder, eeTypePointer, ptrPtrType, "castEETypePtr");
+
+ return eeTypePointer;
}
/// <summary>
@@ -1056,13 +1080,70 @@ namespace Internal.IL
arguments[arguments.Length - i - 1] = _stack.Pop().ValueAsType(GetLLVMTypeForTypeDesc(signatureType), _builder);
}
- //dont name the return value if the function returns void, its invalid
+ // Save the top of the shadow stack in case the callee reverse P/Invokes
+ LLVMValueRef stackFrameSize = BuildConstInt32(GetTotalParameterOffset() + GetTotalLocalOffset());
+ LLVM.BuildStore(_builder, LLVM.BuildGEP(_builder, LLVM.GetFirstParam(_llvmFunction), new LLVMValueRef[] { stackFrameSize }, "shadowStackTop"),
+ LLVM.GetNamedGlobal(Module, "t_pShadowStackTop"));
+
+ // Don't name the return value if the function returns void, it's invalid
var returnValue = LLVM.BuildCall(_builder, nativeFunc, arguments, !method.Signature.ReturnType.IsVoid ? "call" : string.Empty);
if(!method.Signature.ReturnType.IsVoid)
PushExpression(GetStackValueKind(method.Signature.ReturnType), "retval", returnValue, method.Signature.ReturnType);
}
+ static LLVMValueRef s_shadowStackTop = default(LLVMValueRef);
+ LLVMValueRef ShadowStackTop
+ {
+ get
+ {
+ if (s_shadowStackTop.Pointer.Equals(IntPtr.Zero))
+ {
+ s_shadowStackTop = LLVM.AddGlobal(Module, LLVM.PointerType(LLVM.Int8Type(), 0), "t_pShadowStackTop");
+ LLVM.SetLinkage(s_shadowStackTop, LLVMLinkage.LLVMInternalLinkage);
+ LLVM.SetInitializer(s_shadowStackTop, LLVM.ConstPointerNull(LLVM.PointerType(LLVM.Int8Type(), 0)));
+ LLVM.SetThreadLocal(s_shadowStackTop, LLVMMisc.True);
+ }
+ return s_shadowStackTop;
+ }
+ }
+
+ private void EmitNativeToManagedThunk(WebAssemblyCodegenCompilation compilation, MethodDesc method, string nativeName, LLVMValueRef managedFunction)
+ {
+ LLVMTypeRef[] llvmParams = new LLVMTypeRef[method.Signature.Length];
+ for (int i = 0; i < llvmParams.Length; i++)
+ {
+ llvmParams[i] = GetLLVMTypeForTypeDesc(method.Signature[i]);
+ }
+
+ LLVMTypeRef thunkSig = LLVM.FunctionType(GetLLVMTypeForTypeDesc(method.Signature.ReturnType), llvmParams, false);
+ LLVMValueRef thunkFunc = LLVM.AddFunction(compilation.Module, nativeName, thunkSig);
+ LLVMBasicBlockRef block = LLVM.AppendBasicBlock(thunkFunc, "Block0");
+ LLVMBuilderRef builder = LLVM.CreateBuilder();
+ LLVM.PositionBuilderAtEnd(builder, block);
+
+ LLVMValueRef shadowStack = LLVM.BuildLoad(builder, ShadowStackTop, "");
+
+ int curOffset = 0;
+ for (int i = 0; i < llvmParams.Length; i++)
+ {
+ 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 += method.Signature[i].GetElementSize().AsInt;
+ }
+
+ 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 }, "");
+ 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)), ""));
+ }
+ else
+ {
+ LLVM.BuildRetVoid(builder);
+ }
+ }
+
private void ImportCalli(int token)
{
}
@@ -1143,13 +1224,10 @@ namespace Internal.IL
kind = op2.Kind;
}
- LLVMValueRef left = op1.ValueForStackKind(kind, _builder, false);
- LLVMValueRef right = op2.ValueForStackKind(kind, _builder, false);
- if (kind == StackValueKind.Float)
- {
- throw new NotSupportedException();
- }
- else
+ LLVMValueRef right = op1.ValueForStackKind(kind, _builder, false);
+ LLVMValueRef left = op2.ValueForStackKind(kind, _builder, false);
+
+ if (kind != StackValueKind.Float)
{
switch (opcode)
{
@@ -1187,6 +1265,44 @@ namespace Internal.IL
throw new NotSupportedException(); // unreachable
}
}
+ else
+ {
+ switch (opcode)
+ {
+ case ILOpcode.beq:
+ condition = LLVM.BuildFCmp(_builder, LLVMRealPredicate.LLVMRealOEQ, left, right, "beq");
+ break;
+ case ILOpcode.bge:
+ condition = LLVM.BuildFCmp(_builder, LLVMRealPredicate.LLVMRealOGE, left, right, "bge");
+ break;
+ case ILOpcode.bgt:
+ condition = LLVM.BuildFCmp(_builder, LLVMRealPredicate.LLVMRealOGT, left, right, "bgt");
+ break;
+ case ILOpcode.ble:
+ condition = LLVM.BuildFCmp(_builder, LLVMRealPredicate.LLVMRealOLE, left, right, "ble");
+ break;
+ case ILOpcode.blt:
+ condition = LLVM.BuildFCmp(_builder, LLVMRealPredicate.LLVMRealOLT, left, right, "blt");
+ break;
+ case ILOpcode.bne_un:
+ condition = LLVM.BuildFCmp(_builder, LLVMRealPredicate.LLVMRealONE, left, right, "bne_un");
+ break;
+ case ILOpcode.bge_un:
+ condition = LLVM.BuildFCmp(_builder, LLVMRealPredicate.LLVMRealUGE, left, right, "bge_un");
+ break;
+ case ILOpcode.bgt_un:
+ condition = LLVM.BuildFCmp(_builder, LLVMRealPredicate.LLVMRealUGT, left, right, "bgt_un");
+ break;
+ case ILOpcode.ble_un:
+ condition = LLVM.BuildFCmp(_builder, LLVMRealPredicate.LLVMRealULE, left, right, "ble_un");
+ break;
+ case ILOpcode.blt_un:
+ condition = LLVM.BuildFCmp(_builder, LLVMRealPredicate.LLVMRealULT, left, right, "blt_un");
+ break;
+ default:
+ throw new NotSupportedException(); // unreachable
+ }
+ }
}
//TODO: why did this happen only during an optimized build of [System.Private.CoreLib]System.Threading.Lock.ReleaseContended
if (target.StartOffset == 0)
@@ -1433,25 +1549,51 @@ namespace Internal.IL
LLVMValueRef typeSaneOp1 = op1.ValueForStackKind(kind, _builder, true);
LLVMValueRef typeSaneOp2 = op2.ValueForStackKind(kind, _builder, true);
- switch (opcode)
+ if (kind != StackValueKind.Float)
{
- case ILOpcode.ceq:
- result = LLVM.BuildICmp(_builder, LLVMIntPredicate.LLVMIntEQ, typeSaneOp2, typeSaneOp1, "ceq");
- break;
- case ILOpcode.cgt:
- result = LLVM.BuildICmp(_builder, LLVMIntPredicate.LLVMIntSGT, typeSaneOp2, typeSaneOp1, "cgt");
- break;
- case ILOpcode.clt:
- result = LLVM.BuildICmp(_builder, LLVMIntPredicate.LLVMIntSLT, typeSaneOp2, typeSaneOp1, "clt");
- break;
- case ILOpcode.cgt_un:
- result = LLVM.BuildICmp(_builder, LLVMIntPredicate.LLVMIntUGT, typeSaneOp2, typeSaneOp1, "cgt_un");
- break;
- case ILOpcode.clt_un:
- result = LLVM.BuildICmp(_builder, LLVMIntPredicate.LLVMIntULT, typeSaneOp2, typeSaneOp1, "clt_un");
- break;
- default:
- throw new NotSupportedException(); // unreachable
+ switch (opcode)
+ {
+ case ILOpcode.ceq:
+ result = LLVM.BuildICmp(_builder, LLVMIntPredicate.LLVMIntEQ, typeSaneOp2, typeSaneOp1, "ceq");
+ break;
+ case ILOpcode.cgt:
+ result = LLVM.BuildICmp(_builder, LLVMIntPredicate.LLVMIntSGT, typeSaneOp2, typeSaneOp1, "cgt");
+ break;
+ case ILOpcode.clt:
+ result = LLVM.BuildICmp(_builder, LLVMIntPredicate.LLVMIntSLT, typeSaneOp2, typeSaneOp1, "clt");
+ break;
+ case ILOpcode.cgt_un:
+ result = LLVM.BuildICmp(_builder, LLVMIntPredicate.LLVMIntUGT, typeSaneOp2, typeSaneOp1, "cgt_un");
+ break;
+ case ILOpcode.clt_un:
+ result = LLVM.BuildICmp(_builder, LLVMIntPredicate.LLVMIntULT, typeSaneOp2, typeSaneOp1, "clt_un");
+ break;
+ default:
+ throw new NotSupportedException(); // unreachable
+ }
+ }
+ else
+ {
+ switch (opcode)
+ {
+ case ILOpcode.ceq:
+ result = LLVM.BuildFCmp(_builder, LLVMRealPredicate.LLVMRealOEQ, typeSaneOp2, typeSaneOp1, "ceq");
+ break;
+ case ILOpcode.cgt:
+ result = LLVM.BuildFCmp(_builder, LLVMRealPredicate.LLVMRealOGT, typeSaneOp2, typeSaneOp1, "cgt");
+ break;
+ case ILOpcode.clt:
+ result = LLVM.BuildFCmp(_builder, LLVMRealPredicate.LLVMRealOLT, typeSaneOp2, typeSaneOp1, "clt");
+ break;
+ case ILOpcode.cgt_un:
+ result = LLVM.BuildFCmp(_builder, LLVMRealPredicate.LLVMRealUGT, typeSaneOp2, typeSaneOp1, "cgt_un");
+ break;
+ case ILOpcode.clt_un:
+ result = LLVM.BuildFCmp(_builder, LLVMRealPredicate.LLVMRealULT, typeSaneOp2, typeSaneOp1, "clt_un");
+ break;
+ default:
+ throw new NotSupportedException(); // unreachable
+ }
}
PushExpression(StackValueKind.Int32, "cmpop", result, GetWellKnownType(WellKnownType.SByte));
@@ -1568,7 +1710,7 @@ namespace Internal.IL
if (ldtokenValue is TypeDesc)
{
ldtokenKind = WellKnownType.RuntimeTypeHandle;
- PushExpression(StackValueKind.ByRef, "ldtoken", GetEETypeForTypeDesc(ldtokenValue as TypeDesc), _compilation.TypeSystemContext.SystemModule.GetKnownType("System", "EETypePtr"));
+ PushExpression(StackValueKind.ByRef, "ldtoken", GetEETypeForTypeDesc(ldtokenValue as TypeDesc, false), _compilation.TypeSystemContext.SystemModule.GetKnownType("System", "EETypePtr"));
MethodDesc helper = _compilation.TypeSystemContext.GetHelperEntryPoint("LdTokenHelpers", "GetRuntimeTypeHandle");
AddMethodReference(helper);
HandleCall(helper);
diff --git a/src/ILCompiler.WebAssembly/src/CodeGen/ILToWebAssemblyImporter_Statics.cs b/src/ILCompiler.WebAssembly/src/CodeGen/ILToWebAssemblyImporter_Statics.cs
index 3a5f48117..002e5e916 100644
--- a/src/ILCompiler.WebAssembly/src/CodeGen/ILToWebAssemblyImporter_Statics.cs
+++ b/src/ILCompiler.WebAssembly/src/CodeGen/ILToWebAssemblyImporter_Statics.cs
@@ -10,7 +10,7 @@ using Internal.TypeSystem;
using Internal.TypeSystem.Ecma;
using ILCompiler;
-using ILCompiler.Compiler.CppCodeGen;
+using ILCompiler.CodeGen;
using ILCompiler.DependencyAnalysis;
using LLVMSharp;
@@ -54,7 +54,7 @@ namespace Internal.IL
// TODO: We should use the startup node to generate StartupCodeMain and avoid special casing here
if (methodCodeNodeNeedingCode.Method.Signature.IsStatic && methodCodeNodeNeedingCode.Method.Name == "Main")
{
- mangledName = "Main";
+ mangledName = "StartupCodeMain";
}
else
{
@@ -83,6 +83,7 @@ namespace Internal.IL
ilImporter.SetParameterNames(parameters);*/
ilImporter.Import();
+
methodCodeNodeNeedingCode.CompilationCompleted = true;
}
catch (Exception e)
@@ -101,6 +102,7 @@ namespace Internal.IL
static LLVMValueRef TrapFunction = default(LLVMValueRef);
static LLVMValueRef DoNothingFunction = default(LLVMValueRef);
+
private static IEnumerable<string> GetParameterNamesForMethod(MethodDesc method)
{
// TODO: The uses of this method need revision. The right way to get to this info is from
diff --git a/src/ILCompiler.WebAssembly/src/CodeGen/WebAssemblyObjectWriter.cs b/src/ILCompiler.WebAssembly/src/CodeGen/WebAssemblyObjectWriter.cs
index 5d41270f4..9cb9b26d5 100644
--- a/src/ILCompiler.WebAssembly/src/CodeGen/WebAssemblyObjectWriter.cs
+++ b/src/ILCompiler.WebAssembly/src/CodeGen/WebAssemblyObjectWriter.cs
@@ -228,15 +228,27 @@ namespace ILCompiler.DependencyAnalysis
private void EmitNativeMain()
{
+ LLVMValueRef shadowStackTop = LLVM.GetNamedGlobal(Module, "t_pShadowStackTop");
+
LLVMBuilderRef builder = LLVM.CreateBuilder();
- var mainSignature = LLVM.FunctionType(LLVM.Int32Type(), new LLVMTypeRef[0], false);
- var mainFunc = LLVM.AddFunction(Module, "main", mainSignature);
+ var mainSignature = LLVM.FunctionType(LLVM.Int32Type(), new LLVMTypeRef[] { LLVM.Int32Type(), LLVM.PointerType(LLVM.Int8Type(), 0) }, false);
+ var mainFunc = LLVM.AddFunction(Module, "__managed__Main", mainSignature);
var mainEntryBlock = LLVM.AppendBasicBlock(mainFunc, "entry");
LLVM.PositionBuilderAtEnd(builder, mainEntryBlock);
- LLVMValueRef managedMain = LLVM.GetNamedFunction(Module, "Main");
+ LLVMValueRef managedMain = LLVM.GetNamedFunction(Module, "StartupCodeMain");
+ if (managedMain.Pointer == IntPtr.Zero)
+ {
+ throw new Exception("Main not found");
+ }
+
+ 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));
+ LLVM.BuildCall(builder, RhpReversePInvoke2, new LLVMValueRef[] { reversePinvokeFrame }, "");
var shadowStack = LLVM.BuildMalloc(builder, LLVM.ArrayType(LLVM.Int8Type(), 1000000), String.Empty);
var castShadowStack = LLVM.BuildPointerCast(builder, shadowStack, LLVM.PointerType(LLVM.Int8Type(), 0), String.Empty);
+ LLVM.BuildStore(builder, castShadowStack, shadowStackTop);
LLVM.BuildCall(builder, managedMain, new LLVMValueRef[]
{
castShadowStack,