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>2018-01-13 15:48:48 +0300
committerGitHub <noreply@github.com>2018-01-13 15:48:48 +0300
commite32aeceee788a18bb4ced99e629ce8acfcec53b2 (patch)
treea476d154b9c197169c749104a29562d69974299a /src/ILCompiler.WebAssembly
parentc91a527a15ee429b776e57d1930c5841c66e1dcf (diff)
Implement WebAssembly delegates (#5143)
* Implement WebAssembly delegates and fix other minor codegen issues.
Diffstat (limited to 'src/ILCompiler.WebAssembly')
-rw-r--r--src/ILCompiler.WebAssembly/src/CodeGen/EvaluationStack.cs28
-rw-r--r--src/ILCompiler.WebAssembly/src/CodeGen/ILToWebAssemblyImporter.cs157
2 files changed, 144 insertions, 41 deletions
diff --git a/src/ILCompiler.WebAssembly/src/CodeGen/EvaluationStack.cs b/src/ILCompiler.WebAssembly/src/CodeGen/EvaluationStack.cs
index c218dd440..bdc2b4564 100644
--- a/src/ILCompiler.WebAssembly/src/CodeGen/EvaluationStack.cs
+++ b/src/ILCompiler.WebAssembly/src/CodeGen/EvaluationStack.cs
@@ -484,20 +484,44 @@ namespace Internal.IL
}
/// <summary>
+ /// Represents the result of a ldftn or ldvirtftn
+ /// </summary>
+ internal class FunctionPointerEntry : ExpressionEntry
+ {
+ /// <summary>
+ /// True if the function pointer was loaded as a virtual function pointer
+ /// </summary>
+ public bool IsVirtual { get; }
+
+ public MethodDesc Method { get; }
+
+ public FunctionPointerEntry(string name, MethodDesc method, LLVMValueRef llvmValue, TypeDesc type, bool isVirtual) : base(StackValueKind.NativeInt, name, llvmValue, type)
+ {
+ Method = method;
+ IsVirtual = isVirtual;
+ }
+
+ public override StackEntry Duplicate()
+ {
+ return new FunctionPointerEntry(Name, Method, RawLLVMValue, Type, IsVirtual);
+ }
+ }
+
+ /// <summary>
/// Entry representing some token (either of TypeDesc, MethodDesc or FieldDesc) along with its string representation
/// </summary>
internal class LdTokenEntry<T> : ExpressionEntry
{
public T LdToken { get; }
- public LdTokenEntry(StackValueKind kind, string name, T token, TypeDesc type = null) : base(kind, name, default(LLVMValueRef), type)
+ public LdTokenEntry(StackValueKind kind, string name, T token, LLVMValueRef llvmValue, TypeDesc type = null) : base(kind, name, llvmValue, type)
{
LdToken = token;
}
public override StackEntry Duplicate()
{
- return new LdTokenEntry<T>(Kind, Name, LdToken, Type);
+ return new LdTokenEntry<T>(Kind, Name, LdToken, RawLLVMValue, Type);
}
protected override LLVMValueRef ValueAsTypeInternal(LLVMTypeRef type, LLVMBuilderRef builder, bool signExtend)
diff --git a/src/ILCompiler.WebAssembly/src/CodeGen/ILToWebAssemblyImporter.cs b/src/ILCompiler.WebAssembly/src/CodeGen/ILToWebAssemblyImporter.cs
index 71da8d50a..44a04b8d1 100644
--- a/src/ILCompiler.WebAssembly/src/CodeGen/ILToWebAssemblyImporter.cs
+++ b/src/ILCompiler.WebAssembly/src/CodeGen/ILToWebAssemblyImporter.cs
@@ -52,6 +52,8 @@ namespace Internal.IL
/// </summary>
private EvaluationStack<StackEntry> _stack = new EvaluationStack<StackEntry>(0);
+ LLVMTypeRef _universalSignature = LLVM.FunctionType(LLVM.VoidType(), new LLVMTypeRef[] { LLVM.PointerType(LLVM.Int8Type(), 0), LLVM.PointerType(LLVM.Int8Type(), 0) }, false);
+
private class BasicBlock
{
// Common fields
@@ -156,8 +158,7 @@ namespace Internal.IL
private LLVMValueRef CreateLLVMFunction(string mangledName)
{
- LLVMTypeRef universalSignature = LLVM.FunctionType(LLVM.VoidType(), new LLVMTypeRef[] { LLVM.PointerType(LLVM.Int8Type(), 0), LLVM.PointerType(LLVM.Int8Type(), 0) }, false);
- return LLVM.AddFunction(Module, mangledName , universalSignature);
+ return LLVM.AddFunction(Module, mangledName , _universalSignature);
}
private LLVMValueRef GetOrCreateLLVMFunction(string mangledName)
@@ -563,6 +564,15 @@ namespace Internal.IL
{
throw new NotImplementedException($"trying to cast {toStoreKind} to {valueTypeKind}");
}
+ else if (toStoreKind == LLVMTypeKind.LLVMFloatTypeKind && valueTypeKind == LLVMTypeKind.LLVMDoubleTypeKind)
+ {
+ typedToStore = LLVM.BuildFPExt(builder, source, valueType, "FloatToDouble");
+ }
+
+ else if (toStoreKind == LLVMTypeKind.LLVMDoubleTypeKind && valueTypeKind == LLVMTypeKind.LLVMFloatTypeKind)
+ {
+ typedToStore = LLVM.BuildFPTrunc(builder, source, valueType, "DoubleToFloat");
+ }
else if (toStoreKind != valueTypeKind && toStoreKind != LLVMTypeKind.LLVMIntegerTypeKind && valueTypeKind != LLVMTypeKind.LLVMIntegerTypeKind)
{
throw new NotImplementedException($"trying to cast {toStoreKind} to {valueTypeKind}");
@@ -827,17 +837,19 @@ namespace Internal.IL
{
throw new NotImplementedException();
}
- if (opcode == ILOpcode.callvirt && callee.IsAbstract)
- {
- throw new NotImplementedException();
- }
- if (callee.OwningType.IsDelegate)
+ if (opcode == ILOpcode.newobj && callee.OwningType.IsDelegate)
{
- throw new NotImplementedException();
+ FunctionPointerEntry functionPointer = ((FunctionPointerEntry)_stack.Peek());
+ DelegateCreationInfo delegateInfo = _compilation.GetDelegateCtor(callee.OwningType, functionPointer.Method, functionPointer.IsVirtual);
+ callee = delegateInfo.Constructor.Method;
+ if (callee.Signature.Length == 3)
+ {
+ PushExpression(StackValueKind.NativeInt, "thunk", GetOrCreateLLVMFunction(_compilation.NodeFactory.NameMangler.GetMangledMethodName(delegateInfo.Thunk.Method).ToString()));
+ }
}
- HandleCall(callee, opcode);
+ HandleCall(callee, callee.Signature, opcode);
}
private LLVMValueRef LLVMFunctionForMethod(MethodDesc callee, StackEntry thisPointer, bool isCallVirt)
@@ -850,11 +862,11 @@ namespace Internal.IL
throw new NotImplementedException();
if (!_compilation.HasFixedSlotVTable(callee.OwningType))
- _dependencies.Add(_compilation.NodeFactory.VirtualMethodUse(callee));
+ AddVirtualMethodReference(callee);
//TODO: needs runtime support for DispatchByInterface
if (callee.OwningType.IsInterface)
- throw new NotImplementedException();
+ throw new NotImplementedException("Interface call");
return GetCallableVirtualMethod(thisPointer.ValueAsType(LLVM.PointerType(LLVM.Int8Type(), 0), _builder), callee);
}
@@ -863,7 +875,7 @@ namespace Internal.IL
return GetOrCreateLLVMFunction(calleeName);
}
}
-
+
private LLVMValueRef GetOrCreateMethodSlot(MethodDesc method)
{
var vtableSlotSymbol = _compilation.NodeFactory.VTableSlot(method);
@@ -970,32 +982,49 @@ namespace Internal.IL
return false;
}
- private void HandleCall(MethodDesc callee, ILOpcode opcode = ILOpcode.call)
- {
- AddMethodReference(callee);
- int offset = GetTotalParameterOffset() + GetTotalLocalOffset() + callee.Signature.ReturnType.GetElementSize().AsInt;
+ private void HandleCall(MethodDesc callee, MethodSignature signature, ILOpcode opcode = ILOpcode.call, LLVMValueRef calliTarget = default(LLVMValueRef))
+ {
+ if (callee != null && !callee.IsAbstract)
+ {
+ AddMethodReference(callee);
+ }
+
+ int offset = GetTotalParameterOffset() + GetTotalLocalOffset();
+
+ LLVMValueRef returnAddress;
+ LLVMValueRef castReturnAddress;
+ if (signature.ReturnType != GetWellKnownType(WellKnownType.Void))
+ {
+ offset += signature.ReturnType.GetElementSize().AsInt;
+
+ int returnOffset = GetTotalParameterOffset() + GetTotalLocalOffset();
+ returnAddress = LLVM.BuildGEP(_builder, LLVM.GetFirstParam(_llvmFunction),
+ new LLVMValueRef[] { LLVM.ConstInt(LLVM.Int32Type(), (uint)returnOffset, LLVMMisc.False) },
+ String.Empty);
+ castReturnAddress = LLVM.BuildPointerCast(_builder, returnAddress, LLVM.PointerType(LLVM.Int8Type(), 0), "castreturnaddress");
+ }
+ else
+ {
+ returnAddress = LLVM.ConstNull(LLVM.PointerType(LLVM.Int8Type(), 0));
+ castReturnAddress = returnAddress;
+ }
LLVMValueRef shadowStack = LLVM.BuildGEP(_builder, LLVM.GetFirstParam(_llvmFunction),
new LLVMValueRef[] { LLVM.ConstInt(LLVM.Int32Type(), (uint)offset, LLVMMisc.False) },
String.Empty);
var castShadowStack = LLVM.BuildPointerCast(_builder, shadowStack, LLVM.PointerType(LLVM.Int8Type(), 0), "castshadowstack");
- int returnOffset = GetTotalParameterOffset() + GetTotalLocalOffset();
- var returnAddress = LLVM.BuildGEP(_builder, LLVM.GetFirstParam(_llvmFunction),
- new LLVMValueRef[] { LLVM.ConstInt(LLVM.Int32Type(), (uint)returnOffset, LLVMMisc.False) },
- String.Empty);
- var castReturnAddress = LLVM.BuildPointerCast(_builder, returnAddress, LLVM.PointerType(LLVM.Int8Type(), 0), "castreturnaddress");
// argument offset
uint argOffset = 0;
int instanceAdjustment = 0;
- if (!callee.Signature.IsStatic)
+ if (!signature.IsStatic)
{
instanceAdjustment = 1;
}
// The last argument is the top of the stack. We need to reverse them and store starting at the first argument
- StackEntry[] argumentValues = new StackEntry[callee.Signature.Length + instanceAdjustment];
+ StackEntry[] argumentValues = new StackEntry[signature.Length + instanceAdjustment];
for(int i = 0; i < argumentValues.Length; i++)
{
@@ -1007,16 +1036,18 @@ namespace Internal.IL
StackEntry toStore = argumentValues[index];
TypeDesc argType;
- if (index == 0 && !callee.Signature.IsStatic)
+ if (index == 0 && !signature.IsStatic)
{
- if(callee.OwningType.IsValueType)
+ if (opcode == ILOpcode.calli)
+ argType = toStore.Type;
+ else if (callee.OwningType.IsValueType)
argType = callee.OwningType.MakeByRefType();
else
argType = callee.OwningType;
}
else
{
- argType = callee.Signature[index - instanceAdjustment];
+ argType = signature[index - instanceAdjustment];
}
LLVMTypeRef valueType = GetLLVMTypeForTypeDesc(argType);
@@ -1026,17 +1057,26 @@ namespace Internal.IL
argOffset += (uint)argType.GetElementSize().AsInt;
}
- LLVMValueRef fn = LLVMFunctionForMethod(callee, callee.Signature.IsStatic ? null : argumentValues[0], opcode == ILOpcode.callvirt);
+ LLVMValueRef fn;
+ if (opcode == ILOpcode.calli)
+ {
+ fn = calliTarget;
+ }
+ else
+ {
+ fn = LLVMFunctionForMethod(callee, signature.IsStatic ? null : argumentValues[0], opcode == ILOpcode.callvirt);
+ }
+
LLVM.BuildCall(_builder, fn, new LLVMValueRef[] {
castShadowStack,
castReturnAddress}, string.Empty);
- if (!callee.Signature.ReturnType.IsVoid)
+ if (!signature.ReturnType.IsVoid)
{
- LLVMTypeRef returnLLVMType = GetLLVMTypeForTypeDesc(callee.Signature.ReturnType);
+ LLVMTypeRef returnLLVMType = GetLLVMTypeForTypeDesc(signature.ReturnType);
LLVMValueRef returnLLVMPointer = LLVM.BuildPointerCast(_builder, returnAddress, LLVM.PointerType(returnLLVMType, 0), "castreturnpointer");
- PushLoadExpression(GetStackValueKind(callee.Signature.ReturnType), String.Empty, returnLLVMPointer, callee.Signature.ReturnType);
+ PushLoadExpression(GetStackValueKind(signature.ReturnType), String.Empty, returnLLVMPointer, signature.ReturnType);
}
}
@@ -1045,6 +1085,11 @@ namespace Internal.IL
_dependencies.Add(_compilation.NodeFactory.MethodEntrypoint(method));
}
+ private void AddVirtualMethodReference(MethodDesc method)
+ {
+ _dependencies.Add(_compilation.NodeFactory.VirtualMethodUse(method));
+ }
+
private void ImportRawPInvoke(MethodDesc method)
{
LLVMValueRef nativeFunc = LLVM.GetNamedFunction(Module, method.Name);
@@ -1146,10 +1191,35 @@ namespace Internal.IL
private void ImportCalli(int token)
{
+ MethodSignature methodSignature = (MethodSignature)_methodIL.GetObject(token);
+ HandleCall(null, methodSignature, ILOpcode.calli, ((ExpressionEntry)_stack.Pop()).ValueAsType(LLVM.PointerType(_universalSignature, 0), _builder));
}
private void ImportLdFtn(int token, ILOpcode opCode)
{
+ MethodDesc method = (MethodDesc)_methodIL.GetObject(token);
+ LLVMValueRef targetLLVMFunction = default(LLVMValueRef);
+ if (opCode == ILOpcode.ldvirtftn)
+ {
+ StackEntry thisPointer = _stack.Pop();
+ if (method.IsVirtual)
+ {
+ targetLLVMFunction = LLVMFunctionForMethod(method, thisPointer, true);
+ AddVirtualMethodReference(method);
+ }
+ }
+ else
+ {
+ AddMethodReference(method);
+ }
+
+ if (targetLLVMFunction.Pointer.Equals(IntPtr.Zero))
+ {
+ targetLLVMFunction = GetOrCreateLLVMFunction(_compilation.NameMangler.GetMangledMethodName(method).ToString());
+ }
+
+ var entry = new FunctionPointerEntry("ldftn", method, targetLLVMFunction, GetWellKnownType(WellKnownType.IntPtr), opCode == ILOpcode.ldvirtftn);
+ _stack.Push(entry);
}
private void ImportLoadInt(long value, StackValueKind kind)
@@ -1339,10 +1409,14 @@ namespace Internal.IL
var pointer = _stack.Pop();
Debug.Assert(pointer is ExpressionEntry || pointer is ConstantEntry);
var expressionPointer = pointer as ExpressionEntry;
- TypeDesc pointerElementType = pointer.Type.GetParameterType();
- LLVMValueRef rawValue = expressionPointer?.RawLLVMValue ?? LLVM.ConstNull(GetLLVMTypeForTypeDesc(pointerElementType));
+ if(type == null)
+ {
+ type = GetWellKnownType(WellKnownType.Object).MakeByRefType();
+ }
+
+ LLVMValueRef pointerElementType = pointer.ValueAsType(type.MakePointerType(), _builder);
_stack.Push(new LoadExpressionEntry(type != null ? GetStackValueKind(type) : StackValueKind.ByRef, "ldind",
- rawValue, pointer.Type.GetParameterType()));
+ pointerElementType, type.MakePointerType()));
}
private void ImportStoreIndirect(int token)
@@ -1603,6 +1677,8 @@ namespace Internal.IL
{
StackEntry value = _stack.Pop();
LLVMValueRef convertedValue;
+ TypeDesc destType = GetWellKnownType(wellKnownType);
+
//conv.u for a pointer should change to a int8*
if (wellKnownType == WellKnownType.UIntPtr)
{
@@ -1612,14 +1688,14 @@ namespace Internal.IL
}
else
{
- convertedValue = value.ValueAsType(GetWellKnownType(wellKnownType), _builder);
+ convertedValue = value.ValueAsType(destType, _builder);
}
}
else
{
- convertedValue = value.ValueAsType(GetWellKnownType(wellKnownType), _builder);
+ convertedValue = value.ValueAsType(destType, _builder);
}
- PushExpression(value.Kind, "conv", convertedValue, value.Type);
+ PushExpression(GetStackValueKind(destType), "conv", convertedValue, destType);
}
private void ImportUnaryOperation(ILOpcode opCode)
@@ -1739,13 +1815,13 @@ namespace Internal.IL
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);
+ HandleCall(helper, helper.Signature);
name = ldtokenValue.ToString();
}
else if (ldtokenValue is FieldDesc)
{
ldtokenKind = WellKnownType.RuntimeFieldHandle;
- value = new LdTokenEntry<FieldDesc>(StackValueKind.ValueType, null, (FieldDesc)ldtokenValue, GetWellKnownType(ldtokenKind));
+ value = new LdTokenEntry<FieldDesc>(StackValueKind.ValueType, null, (FieldDesc)ldtokenValue, LLVM.ConstInt(LLVM.Int32Type(), 0, LLVMMisc.False), GetWellKnownType(ldtokenKind));
_stack.Push(value);
}
else if (ldtokenValue is MethodDesc)
@@ -1781,6 +1857,9 @@ namespace Internal.IL
private void ImportSizeOf(int token)
{
+ TypeDesc type = (TypeDesc)_methodIL.GetObject(token);
+ int size = type.GetElementSize().AsInt;
+ PushExpression(StackValueKind.Int32, "sizeof", LLVM.ConstInt(LLVM.Int32Type(), (ulong)size, LLVMMisc.False), GetWellKnownType(WellKnownType.Int32));
}
private void ImportRefAnyType()
@@ -2061,7 +2140,7 @@ namespace Internal.IL
{
MetadataType helperType = context.SystemModule.GetKnownType("System.Runtime", "RuntimeExports");
MethodDesc helperMethod = helperType.GetKnownMethod(methodName, null);
- HandleCall(helperMethod);
+ HandleCall(helperMethod, helperMethod.Signature);
}
private StackEntry NewSpillSlot(StackEntry entry)