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
path: root/src
diff options
context:
space:
mode:
authorMorgan Brown <morganbr@users.noreply.github.com>2018-08-07 11:21:02 +0300
committerGitHub <noreply@github.com>2018-08-07 11:21:02 +0300
commit914360af01f97f5b49c104c5a0b38ea879849d9f (patch)
treebbe4d5c3faf47b71f1f1c23a2ed19616c31c187e /src
parentbdc6bfbef12b94db9dedef90cb39da88949f61ed (diff)
Optimize WASM arguments and returns (#6181)
Use LLVM arguments and returns where possible (no GC references) instead of passing them on the shadow stack. The argument optimization saves 3% optimized (5% compressed). The return change adds about 0.5% to the uncompressed file, but saves about 6% compressed. They both save size in debug. This also greatly simplifies debugging and reading code. Also includes a fix to the class constructor runner where it was calling cctors with the wrong signature and some test fixes.
Diffstat (limited to 'src')
-rw-r--r--src/Common/src/TypeSystem/Common/MethodDesc.cs25
-rw-r--r--src/ILCompiler.Compiler/src/Compiler/CompilerTypeSystemContext.Mangling.cs19
-rw-r--r--src/ILCompiler.WebAssembly/src/CodeGen/ILToWebAssemblyImporter.cs303
-rw-r--r--src/ILCompiler.WebAssembly/src/CodeGen/WebAssemblyObjectWriter.cs18
-rw-r--r--src/System.Private.CoreLib/src/System/Runtime/CompilerServices/ClassConstructorRunner.NonPortable.cs5
-rw-r--r--src/System.Private.CoreLib/src/System/Runtime/CompilerServices/ClassConstructorRunner.cs2
6 files changed, 288 insertions, 84 deletions
diff --git a/src/Common/src/TypeSystem/Common/MethodDesc.cs b/src/Common/src/TypeSystem/Common/MethodDesc.cs
index 74c48d8eb..7103433b0 100644
--- a/src/Common/src/TypeSystem/Common/MethodDesc.cs
+++ b/src/Common/src/TypeSystem/Common/MethodDesc.cs
@@ -133,7 +133,32 @@ namespace Internal.TypeSystem
return TypeHashingAlgorithms.ComputeMethodSignatureHashCode(_returnType.GetHashCode(), _parameters);
}
+ public SignatureEnumerator GetEnumerator()
+ {
+ return new SignatureEnumerator(this);
+ }
+
public override TypeSystemContext Context => _returnType.Context;
+
+ public struct SignatureEnumerator
+ {
+ private int _index;
+ private MethodSignature _signature;
+
+ public SignatureEnumerator(MethodSignature signature)
+ {
+ _signature = signature;
+ _index = -1;
+ }
+
+ public TypeDesc Current => _signature[_index];
+
+ public bool MoveNext()
+ {
+ _index++;
+ return _index < _signature.Length;
+ }
+ }
}
/// <summary>
diff --git a/src/ILCompiler.Compiler/src/Compiler/CompilerTypeSystemContext.Mangling.cs b/src/ILCompiler.Compiler/src/Compiler/CompilerTypeSystemContext.Mangling.cs
index 720f06114..ace374f04 100644
--- a/src/ILCompiler.Compiler/src/Compiler/CompilerTypeSystemContext.Mangling.cs
+++ b/src/ILCompiler.Compiler/src/Compiler/CompilerTypeSystemContext.Mangling.cs
@@ -47,5 +47,24 @@ namespace ILCompiler
}
}
}
+
+ partial class UnboxingThunk : IPrefixMangledMethod
+ {
+ MethodDesc IPrefixMangledMethod.BaseMethod
+ {
+ get
+ {
+ return _targetMethod;
+ }
+ }
+
+ string IPrefixMangledMethod.Prefix
+ {
+ get
+ {
+ return "unbox";
+ }
+ }
+ }
}
}
diff --git a/src/ILCompiler.WebAssembly/src/CodeGen/ILToWebAssemblyImporter.cs b/src/ILCompiler.WebAssembly/src/CodeGen/ILToWebAssemblyImporter.cs
index eab414bce..19960e6a9 100644
--- a/src/ILCompiler.WebAssembly/src/CodeGen/ILToWebAssemblyImporter.cs
+++ b/src/ILCompiler.WebAssembly/src/CodeGen/ILToWebAssemblyImporter.cs
@@ -45,6 +45,7 @@ namespace Internal.IL
private LLVMBuilderRef _builder;
private readonly LocalVariableDefinition[] _locals;
private readonly LLVMValueRef[] _localSlots;
+ private readonly LLVMValueRef[] _argSlots;
private List<SpilledExpressionEntry> _spilledExpressions = new List<SpilledExpressionEntry>();
private int _pointerSize;
private readonly byte[] _ilBytes;
@@ -53,9 +54,7 @@ namespace Internal.IL
/// Stack of values pushed onto the IL stack: locals, arguments, values, function pointer, ...
/// </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
@@ -94,6 +93,7 @@ namespace Internal.IL
_ilBytes = methodIL.GetILBytes();
_locals = methodIL.GetLocals();
_localSlots = new LLVMValueRef[_locals.Length];
+ _argSlots = new LLVMValueRef[method.Signature.Length];
_signature = method.Signature;
_thisType = method.OwningType;
@@ -103,7 +103,7 @@ namespace Internal.IL
{
_exceptionRegions[i] = new ExceptionRegion() { ILRegion = ilExceptionRegions[i] };
}
- _llvmFunction = GetOrCreateLLVMFunction(mangledName);
+ _llvmFunction = GetOrCreateLLVMFunction(mangledName, method.Signature);
_builder = LLVM.CreateBuilder();
_pointerSize = compilation.NodeFactory.Target.PointerSize;
}
@@ -158,9 +158,36 @@ namespace Internal.IL
LLVMBasicBlockRef prologBlock = LLVM.AppendBasicBlock(_llvmFunction, "Prolog");
LLVM.PositionBuilderAtEnd(_builder, prologBlock);
+ // Copy arguments onto the stack to allow
+ // them to be referenced by address
+ int thisOffset = 0;
+ if (!_signature.IsStatic)
+ {
+ thisOffset = 1;
+ }
+
+ // Keep track of where we are in the llvm signature, starting after the
+ // shadow stack pointer and return adress
+ int signatureIndex = 1;
+ if (NeedsReturnStackSlot(_signature))
+ {
+ signatureIndex++;
+ }
+
+ for (int i = 0; i < _signature.Length; i++)
+ {
+ if (CanStoreTypeOnStack(_signature[i]))
+ {
+ LLVMValueRef argStackSlot = LLVM.BuildAlloca(_builder, GetLLVMTypeForTypeDesc(_signature[i]), $"arg{i + thisOffset}_");
+ LLVM.BuildStore(_builder, LLVM.GetParam(_llvmFunction, (uint)signatureIndex), argStackSlot);
+ _argSlots[i] = argStackSlot;
+ signatureIndex++;
+ }
+ }
+
for (int i = 0; i < _locals.Length; i++)
{
- if (CanStoreTypeOnStack(_locals[i].Type))
+ if (CanStoreLocalOnStack(_locals[i].Type))
{
LLVMValueRef localStackSlot = LLVM.BuildAlloca(_builder, GetLLVMTypeForTypeDesc(_locals[i].Type), $"local{i}_");
_localSlots[i] = localStackSlot;
@@ -172,7 +199,7 @@ namespace Internal.IL
for(int i = 0; i < _locals.Length; i++)
{
LLVMValueRef localAddr = LoadVarAddress(i, LocalVarKind.Local, out TypeDesc localType);
- if(CanStoreTypeOnStack(localType))
+ if(CanStoreLocalOnStack(localType))
{
LLVMTypeRef llvmType = GetLLVMTypeForTypeDesc(localType);
LLVMTypeKind typeKind = LLVM.GetTypeKind(llvmType);
@@ -236,18 +263,18 @@ namespace Internal.IL
LLVM.BuildBr(_builder, block0);
}
- private LLVMValueRef CreateLLVMFunction(string mangledName)
+ private LLVMValueRef CreateLLVMFunction(string mangledName, MethodSignature signature)
{
- return LLVM.AddFunction(Module, mangledName , _universalSignature);
+ return LLVM.AddFunction(Module, mangledName, GetLLVMSignatureForMethod(signature));
}
- private LLVMValueRef GetOrCreateLLVMFunction(string mangledName)
+ private LLVMValueRef GetOrCreateLLVMFunction(string mangledName, MethodSignature signature)
{
LLVMValueRef llvmFunction = LLVM.GetNamedFunction(Module, mangledName);
if(llvmFunction.Pointer == IntPtr.Zero)
{
- return CreateLLVMFunction(mangledName);
+ return CreateLLVMFunction(mangledName, signature);
}
return llvmFunction;
}
@@ -484,7 +511,7 @@ namespace Internal.IL
varCountBase = 1;
}
- GetArgSizeAndOffsetAtIndex(index, out int argSize, out varOffset);
+ GetArgSizeAndOffsetAtIndex(index, out int argSize, out varOffset, out int realArgIndex);
if (!_signature.IsStatic && index == 0)
{
@@ -499,6 +526,13 @@ namespace Internal.IL
type = _signature[index - varCountBase];
}
valueType = GetLLVMTypeForTypeDesc(type);
+
+ // If the argument can be passed as a real argument rather than on the shadow stack,
+ // get its address here
+ if(realArgIndex != -1)
+ {
+ return _argSlots[realArgIndex];
+ }
}
else if (kind == LocalVarKind.Local)
{
@@ -785,7 +819,7 @@ namespace Internal.IL
for (int i = 0; i < _locals.Length; i++)
{
TypeDesc localType = _locals[i].Type;
- if (!CanStoreTypeOnStack(localType))
+ if (!CanStoreLocalOnStack(localType))
{
offset = PadNextOffset(localType, offset);
}
@@ -793,38 +827,56 @@ namespace Internal.IL
return offset.AlignUp(_pointerSize);
}
+ private bool CanStoreLocalOnStack(TypeDesc localType)
+ {
+ // Keep all locals on the shadow stack if there is exception
+ // handling so funclets can access them
+ if (_exceptionRegions.Length == 0)
+ {
+ return CanStoreTypeOnStack(localType);
+ }
+ return false;
+ }
+
/// <summary>
/// Returns true if the type can be stored on the local stack
/// instead of the shadow stack in this method.
/// </summary>
- private bool CanStoreTypeOnStack(TypeDesc localType)
+ private static bool CanStoreTypeOnStack(TypeDesc type)
{
- // Keep all locals on the shadow stack if there is exception
- // handling so funclets can access them
- if (_exceptionRegions.Length == 0)
+ if (type is DefType defType)
{
- if (localType is DefType)
- {
- if (!((DefType)localType).ContainsGCPointers)
- {
- return true;
- }
- }
- else if (localType is PointerType)
+ if (!defType.IsGCPointer && !defType.ContainsGCPointers)
{
return true;
}
}
+ else if (type is PointerType)
+ {
+ return true;
+ }
return false;
}
+ /// <summary>
+ /// Returns true if the method returns a type that must be kept
+ /// on the shadow stack
+ /// </summary>
+ private static bool NeedsReturnStackSlot(MethodSignature signature)
+ {
+ return !signature.ReturnType.IsVoid && !CanStoreTypeOnStack(signature.ReturnType);
+ }
+
private int GetTotalParameterOffset()
{
int offset = 0;
for (int i = 0; i < _signature.Length; i++)
{
- offset = PadNextOffset(_signature[i], offset);
+ if (!CanStoreTypeOnStack(_signature[i]))
+ {
+ offset = PadNextOffset(_signature[i], offset);
+ }
}
if (!_signature.IsStatic)
{
@@ -842,8 +894,10 @@ namespace Internal.IL
return offset.AlignUp(_pointerSize);
}
- private void GetArgSizeAndOffsetAtIndex(int index, out int size, out int offset)
+ private void GetArgSizeAndOffsetAtIndex(int index, out int size, out int offset, out int realArgIndex)
{
+ realArgIndex = -1;
+
int thisSize = 0;
if (!_signature.IsStatic)
{
@@ -863,12 +917,29 @@ namespace Internal.IL
var argType = _signature[index];
size = argType.GetElementSize().AsInt;
+ int potentialRealArgIndex = 0;
+
offset = thisSize;
for (int i = 0; i < index; i++)
{
- offset = PadNextOffset(_signature[i], offset);
+ // We could compact the set of argSlots to only those that we'd keep on the stack, but currently don't
+ potentialRealArgIndex++;
+
+ if (!CanStoreTypeOnStack(_signature[i]))
+ {
+ offset = PadNextOffset(_signature[i], offset);
+ }
+ }
+
+ if (CanStoreTypeOnStack(argType))
+ {
+ realArgIndex = potentialRealArgIndex;
+ offset = -1;
+ }
+ else
+ {
+ offset = PadOffset(argType, offset);
}
- offset = PadOffset(argType, offset);
}
private void GetLocalSizeAndOffsetAtIndex(int index, out int size, out int offset)
@@ -876,7 +947,7 @@ namespace Internal.IL
LocalVariableDefinition local = _locals[index];
size = local.Type.GetElementSize().AsInt;
- if (CanStoreTypeOnStack(local.Type))
+ if (CanStoreLocalOnStack(local.Type))
{
offset = -1;
}
@@ -885,7 +956,7 @@ namespace Internal.IL
offset = 0;
for (int i = 0; i < index; i++)
{
- if (!CanStoreTypeOnStack(_locals[i].Type))
+ if (!CanStoreLocalOnStack(_locals[i].Type))
{
offset = PadNextOffset(_locals[i].Type, offset);
}
@@ -992,14 +1063,25 @@ namespace Internal.IL
private void ImportReturn()
{
- if (_signature.ReturnType != GetWellKnownType(WellKnownType.Void))
+ if (_signature.ReturnType.IsVoid)
{
- StackEntry retVal = _stack.Pop();
- LLVMTypeRef valueType = GetLLVMTypeForTypeDesc(_signature.ReturnType);
- ImportStoreHelper(retVal.ValueAsType(valueType, _builder), valueType, LLVM.GetNextParam(LLVM.GetFirstParam(_llvmFunction)), 0);
+ LLVM.BuildRetVoid(_builder);
+ return;
}
- LLVM.BuildRetVoid(_builder);
+ StackEntry retVal = _stack.Pop();
+ LLVMTypeRef valueType = GetLLVMTypeForTypeDesc(_signature.ReturnType);
+ LLVMValueRef castValue = retVal.ValueAsType(valueType, _builder);
+
+ if (NeedsReturnStackSlot(_signature))
+ {
+ ImportStoreHelper(castValue, valueType, LLVM.GetNextParam(LLVM.GetFirstParam(_llvmFunction)), 0);
+ LLVM.BuildRetVoid(_builder);
+ }
+ else
+ {
+ LLVM.BuildRet(_builder, castValue);
+ }
}
private void ImportCall(ILOpcode opcode, int token)
@@ -1095,7 +1177,7 @@ namespace Internal.IL
callee = delegateInfo.Constructor.Method;
if (callee.Signature.Length == 3)
{
- PushExpression(StackValueKind.NativeInt, "thunk", GetOrCreateLLVMFunction(_compilation.NodeFactory.NameMangler.GetMangledMethodName(delegateInfo.Thunk.Method).ToString()));
+ PushExpression(StackValueKind.NativeInt, "thunk", GetOrCreateLLVMFunction(_compilation.NodeFactory.NameMangler.GetMangledMethodName(delegateInfo.Thunk.Method).ToString(), delegateInfo.Thunk.Method.Signature));
}
}
@@ -1110,7 +1192,7 @@ namespace Internal.IL
if(callee.IsFinal || callee.OwningType.IsSealed())
{
AddMethodReference(callee);
- return GetOrCreateLLVMFunction(calleeName);
+ return GetOrCreateLLVMFunction(calleeName, callee.Signature);
}
if (thisPointer != null && callee.IsVirtual && isCallVirt)
@@ -1155,7 +1237,7 @@ namespace Internal.IL
if (targetMethod != null)
{
AddMethodReference(targetMethod);
- return GetOrCreateLLVMFunction(_compilation.NameMangler.GetMangledMethodName(targetMethod).ToString());
+ return GetOrCreateLLVMFunction(_compilation.NameMangler.GetMangledMethodName(targetMethod).ToString(), callee.Signature);
}
return GetCallableVirtualMethod(thisPointer, callee);
@@ -1163,7 +1245,7 @@ namespace Internal.IL
}
else
{
- return GetOrCreateLLVMFunction(calleeName);
+ return GetOrCreateLLVMFunction(calleeName, callee.Signature);
}
}
@@ -1180,7 +1262,7 @@ namespace Internal.IL
Debug.Assert(method.IsVirtual);
LLVMValueRef slot = GetOrCreateMethodSlot(method);
var pointerSize = method.Context.Target.PointerSize;
- LLVMTypeRef universalSignature = LLVM.FunctionType(LLVM.VoidType(), new LLVMTypeRef[] { LLVM.PointerType(LLVM.Int8Type(), 0), LLVM.PointerType(LLVM.Int8Type(), 0) }, false);
+ LLVMTypeRef llvmSignature = GetLLVMSignatureForMethod(method.Signature);
LLVMValueRef functionPtr;
if (method.OwningType.IsInterface)
{
@@ -1188,11 +1270,11 @@ namespace Internal.IL
var interfaceEEType = new LoadExpressionEntry(StackValueKind.ValueType, "interfaceEEType", GetEETypePointerForTypeDesc(method.OwningType, true), eeTypeDesc);
var eeTypeExpression = new LoadExpressionEntry(StackValueKind.ValueType, "eeType", objectPtr.ValueAsType(LLVM.PointerType(LLVM.Int8Type(), 0), _builder), eeTypeDesc);
var targetEntry = CallRuntime(_compilation.TypeSystemContext, DispatchResolve, "FindInterfaceMethodImplementationTarget", new StackEntry[] { eeTypeExpression, interfaceEEType, new ExpressionEntry(StackValueKind.Int32, "slot", slot, GetWellKnownType(WellKnownType.UInt16)) });
- functionPtr = targetEntry.ValueAsType(LLVM.PointerType(universalSignature, 0), _builder);
+ functionPtr = targetEntry.ValueAsType(LLVM.PointerType(llvmSignature, 0), _builder);
}
else
{
- var rawObjectPtr = CastIfNecessary(objectPtr.ValueAsType(LLVM.PointerType(LLVM.Int8Type(), 0), _builder), LLVM.PointerType(LLVM.PointerType(LLVM.PointerType(universalSignature, 0), 0), 0), objectPtr.Name());
+ var rawObjectPtr = CastIfNecessary(objectPtr.ValueAsType(LLVM.PointerType(LLVM.Int8Type(), 0), _builder), LLVM.PointerType(LLVM.PointerType(LLVM.PointerType(llvmSignature, 0), 0), 0), objectPtr.Name());
var eeType = LLVM.BuildLoad(_builder, rawObjectPtr, "ldEEType");
var slotPtr = LLVM.BuildGEP(_builder, eeType, new LLVMValueRef[] { slot }, "__getslot__");
functionPtr = LLVM.BuildLoad(_builder, slotPtr, "ld__getslot__");
@@ -1201,6 +1283,42 @@ namespace Internal.IL
return functionPtr;
}
+ private LLVMTypeRef GetLLVMSignatureForMethod(MethodSignature signature)
+ {
+ TypeDesc returnType = signature.ReturnType;
+ LLVMTypeRef llvmReturnType;
+ bool returnOnStack = false;
+ if (!NeedsReturnStackSlot(signature))
+ {
+ returnOnStack = true;
+ llvmReturnType = GetLLVMTypeForTypeDesc(returnType);
+ }
+ else
+ {
+ llvmReturnType = LLVM.VoidType();
+ }
+
+ List<LLVMTypeRef> signatureTypes = new List<LLVMTypeRef>();
+ signatureTypes.Add(LLVM.PointerType(LLVM.Int8Type(), 0)); // Shadow stack pointer
+
+ if (!returnOnStack && returnType != GetWellKnownType(WellKnownType.Void))
+ {
+ signatureTypes.Add(LLVM.PointerType(LLVM.Int8Type(), 0));
+ }
+
+ // Intentionally skipping the 'this' pointer since it could always be a GC reference
+ // and thus must be on the shadow stack
+ foreach (TypeDesc type in signature)
+ {
+ if (CanStoreTypeOnStack(type))
+ {
+ signatureTypes.Add(GetLLVMTypeForTypeDesc(type));
+ }
+ }
+
+ return LLVM.FunctionType(llvmReturnType, signatureTypes.ToArray(), false);
+ }
+
private ExpressionEntry AllocateObject(TypeDesc type)
{
MetadataType metadataType = (MetadataType)type;
@@ -1371,10 +1489,12 @@ namespace Internal.IL
var pointerSize = _compilation.NodeFactory.Target.PointerSize;
LLVMValueRef returnAddress;
- LLVMValueRef castReturnAddress;
+ LLVMValueRef castReturnAddress = default;
TypeDesc returnType = signature.ReturnType;
+
+ bool needsReturnSlot = NeedsReturnStackSlot(signature);
SpilledExpressionEntry returnSlot = null;
- if (!returnType.IsVoid)
+ if (needsReturnSlot)
{
int returnIndex = _spilledExpressions.Count;
returnSlot = new SpilledExpressionEntry(GetStackValueKind(returnType), callee?.Name + "_return", returnType, returnIndex, this);
@@ -1382,11 +1502,6 @@ namespace Internal.IL
returnAddress = LoadVarAddress(returnIndex, LocalVarKind.Temp, out TypeDesc unused);
castReturnAddress = LLVM.BuildPointerCast(_builder, returnAddress, LLVM.PointerType(LLVM.Int8Type(), 0), callee?.Name + "_castreturn");
}
- else
- {
- returnAddress = LLVM.ConstNull(LLVM.PointerType(LLVM.Int8Type(), 0));
- castReturnAddress = returnAddress;
- }
int offset = GetTotalParameterOffset() + GetTotalLocalOffset();
LLVMValueRef shadowStack = LLVM.BuildGEP(_builder, LLVM.GetFirstParam(_llvmFunction),
@@ -1394,16 +1509,25 @@ namespace Internal.IL
String.Empty);
var castShadowStack = LLVM.BuildPointerCast(_builder, shadowStack, LLVM.PointerType(LLVM.Int8Type(), 0), "castshadowstack");
- // argument offset
+ List<LLVMValueRef> llvmArgs = new List<LLVMValueRef>();
+ llvmArgs.Add(castShadowStack);
+ if (needsReturnSlot)
+ {
+ llvmArgs.Add(castReturnAddress);
+ }
+
+ // argument offset on the shadow stack
int argOffset = 0;
var instanceAdjustment = signature.IsStatic ? 0 : 1;
for (int index = 0; index < argumentValues.Length; index++)
{
StackEntry toStore = argumentValues[index];
+ bool isThisParameter = false;
TypeDesc argType;
if (index == 0 && !signature.IsStatic)
{
+ isThisParameter = true;
if (opcode == ILOpcode.calli)
argType = toStore.Type;
else if (callee.OwningType.IsValueType)
@@ -1416,14 +1540,24 @@ 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);
+ LLVMValueRef argValue = toStore.ValueAsType(valueType, _builder);
+
+ // Pass arguments as parameters if possible
+ if (!isThisParameter && CanStoreTypeOnStack(argType))
+ {
+ llvmArgs.Add(argValue);
+ }
+ // Otherwise store them on the shadow stack
+ else
+ {
+ // The previous argument might have left this type unaligned, so pad if necessary
+ argOffset = PadOffset(argType, argOffset);
- ImportStoreHelper(toStore.ValueAsType(valueType, _builder), valueType, castShadowStack, (uint)argOffset);
+ ImportStoreHelper(argValue, valueType, castShadowStack, (uint)argOffset);
- argOffset += argType.GetElementSize().AsInt;
+ argOffset += argType.GetElementSize().AsInt;
+ }
}
LLVMValueRef fn;
@@ -1436,14 +1570,18 @@ namespace Internal.IL
fn = LLVMFunctionForMethod(callee, signature.IsStatic ? null : argumentValues[0], opcode == ILOpcode.callvirt);
}
- LLVM.BuildCall(_builder, fn, new LLVMValueRef[] {
- castShadowStack,
- castReturnAddress}, string.Empty);
-
+ LLVMValueRef llvmReturn = LLVM.BuildCall(_builder, fn, llvmArgs.ToArray(), string.Empty);
if (!returnType.IsVoid)
{
- return returnSlot;
+ if (needsReturnSlot)
+ {
+ return returnSlot;
+ }
+ else
+ {
+ return new ExpressionEntry(GetStackValueKind(returnType), callee?.Name + "_return", llvmReturn, returnType);
+ }
}
else
{
@@ -1641,15 +1779,35 @@ namespace Internal.IL
curOffset = PadNextOffset(method.Signature.ReturnType, curOffset);
LLVMValueRef calleeFrame = LLVM.BuildGEP(builder, shadowStack, new LLVMValueRef[] { BuildConstInt32(curOffset) }, "calleeFrame");
+ List<LLVMValueRef> llvmArgs = new List<LLVMValueRef>();
+ llvmArgs.Add(calleeFrame);
+
+ bool needsReturnSlot = NeedsReturnStackSlot(method.Signature);
+
+ if (needsReturnSlot)
+ {
+ // Slot for return value if necessary
+ llvmArgs.Add(shadowStack);
+ }
+
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), $"parameter{i}_"));
- curOffset = PadNextOffset(method.Signature[i], curOffset);
+ LLVMValueRef argValue = LLVM.GetParam(thunkFunc, (uint)i);
+
+ if (CanStoreTypeOnStack(method.Signature[i]))
+ {
+ llvmArgs.Add(argValue);
+ }
+ else
+ {
+ 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, argValue, CastIfNecessary(builder, argAddr, LLVM.PointerType(llvmParams[i], 0), $"parameter{i}_"));
+ curOffset = PadNextOffset(method.Signature[i], curOffset);
+ }
}
- LLVM.BuildCall(builder, managedFunction, new LLVMValueRef[] { calleeFrame, shadowStack }, "");
+ LLVMValueRef llvmReturnValue = LLVM.BuildCall(builder, managedFunction, llvmArgs.ToArray(), "");
if (method.IsNativeCallable)
{
@@ -1657,9 +1815,16 @@ namespace Internal.IL
LLVM.BuildCall(builder, RhpReversePInvokeReturn2, new LLVMValueRef[] { reversePInvokeFrame }, "");
}
- if (method.Signature.ReturnType != compilation.TypeSystemContext.GetWellKnownType(WellKnownType.Void))
+ if (!method.Signature.ReturnType.IsVoid)
{
- LLVM.BuildRet(builder, LLVM.BuildLoad(builder, CastIfNecessary(builder, shadowStack, LLVM.PointerType(GetLLVMTypeForTypeDesc(method.Signature.ReturnType), 0)), "returnValue"));
+ if (needsReturnSlot)
+ {
+ LLVM.BuildRet(builder, LLVM.BuildLoad(builder, CastIfNecessary(builder, shadowStack, LLVM.PointerType(GetLLVMTypeForTypeDesc(method.Signature.ReturnType), 0)), "returnValue"));
+ }
+ else
+ {
+ LLVM.BuildRet(builder, llvmReturnValue);
+ }
}
else
{
@@ -1670,7 +1835,7 @@ 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));
+ HandleCall(null, methodSignature, ILOpcode.calli, ((ExpressionEntry)_stack.Pop()).ValueAsType(LLVM.PointerType(GetLLVMSignatureForMethod(methodSignature), 0), _builder));
}
private void ImportLdFtn(int token, ILOpcode opCode)
@@ -1693,7 +1858,7 @@ namespace Internal.IL
if (targetLLVMFunction.Pointer.Equals(IntPtr.Zero))
{
- targetLLVMFunction = GetOrCreateLLVMFunction(_compilation.NameMangler.GetMangledMethodName(method).ToString());
+ targetLLVMFunction = GetOrCreateLLVMFunction(_compilation.NameMangler.GetMangledMethodName(method).ToString(), method.Signature);
}
var entry = new FunctionPointerEntry("ldftn", method, targetLLVMFunction, GetWellKnownType(WellKnownType.IntPtr), opCode == ILOpcode.ldvirtftn);
diff --git a/src/ILCompiler.WebAssembly/src/CodeGen/WebAssemblyObjectWriter.cs b/src/ILCompiler.WebAssembly/src/CodeGen/WebAssemblyObjectWriter.cs
index cec8c0563..5b819d8a6 100644
--- a/src/ILCompiler.WebAssembly/src/CodeGen/WebAssemblyObjectWriter.cs
+++ b/src/ILCompiler.WebAssembly/src/CodeGen/WebAssemblyObjectWriter.cs
@@ -270,22 +270,18 @@ namespace ILCompiler.DependencyAnalysis
LLVM.BuildStore(builder, castShadowStack, shadowStackTop);
// Pass on main arguments
- var argcSlot = LLVM.BuildPointerCast(builder, shadowStack, LLVM.PointerType(LLVM.Int32Type(), 0), "argcSlot");
- LLVM.BuildStore(builder, LLVM.GetParam(mainFunc, 0), argcSlot);
- var argvSlot = LLVM.BuildGEP(builder, castShadowStack, new LLVMValueRef[] { LLVM.ConstInt(LLVM.Int32Type(), 4, LLVMMisc.False) }, "argvSlot");
- LLVM.BuildStore(builder, LLVM.GetParam(mainFunc, 1), LLVM.BuildPointerCast(builder, argvSlot, LLVM.PointerType(LLVM.PointerType(LLVM.Int8Type(), 0), 0), ""));
+ LLVMValueRef argc = LLVM.GetParam(mainFunc, 0);
+ LLVMValueRef argv = LLVM.GetParam(mainFunc, 1);
- // StartupCodeMain will always return a value whether the user's main does or not
- LLVMValueRef returnValueSlot = LLVM.BuildAlloca(builder, LLVM.Int32Type(), "returnValue");
-
- LLVM.BuildCall(builder, managedMain, new LLVMValueRef[]
+ LLVMValueRef mainReturn = LLVM.BuildCall(builder, managedMain, new LLVMValueRef[]
{
castShadowStack,
- LLVM.BuildPointerCast(builder, returnValueSlot, LLVM.PointerType(LLVM.Int8Type(), 0), String.Empty)
+ argc,
+ argv,
},
- String.Empty);
+ "returnValue");
- LLVM.BuildRet(builder, LLVM.BuildLoad(builder, returnValueSlot, String.Empty));
+ LLVM.BuildRet(builder, mainReturn);
LLVM.SetLinkage(mainFunc, LLVMLinkage.LLVMExternalLinkage);
}
diff --git a/src/System.Private.CoreLib/src/System/Runtime/CompilerServices/ClassConstructorRunner.NonPortable.cs b/src/System.Private.CoreLib/src/System/Runtime/CompilerServices/ClassConstructorRunner.NonPortable.cs
index 4c309ca34..5374478e7 100644
--- a/src/System.Private.CoreLib/src/System/Runtime/CompilerServices/ClassConstructorRunner.NonPortable.cs
+++ b/src/System.Private.CoreLib/src/System/Runtime/CompilerServices/ClassConstructorRunner.NonPortable.cs
@@ -19,10 +19,9 @@ namespace System.Runtime.CompilerServices
{
//=========================================================================================================
// Intrinsic to call the cctor given a pointer to the code (this method's body is ignored and replaced
- // with a calli during compilation). The transform doesn't handle non-generic versions yet (i.e.
- // functions that are void).
+ // with a calli during compilation).
//=========================================================================================================
- private static T Call<T>(System.IntPtr pfn)
+ private static void Call(System.IntPtr pfn)
{
throw NotImplemented.ByDesign;
}
diff --git a/src/System.Private.CoreLib/src/System/Runtime/CompilerServices/ClassConstructorRunner.cs b/src/System.Private.CoreLib/src/System/Runtime/CompilerServices/ClassConstructorRunner.cs
index d8a418e15..a82e434b8 100644
--- a/src/System.Private.CoreLib/src/System/Runtime/CompilerServices/ClassConstructorRunner.cs
+++ b/src/System.Private.CoreLib/src/System/Runtime/CompilerServices/ClassConstructorRunner.cs
@@ -94,7 +94,7 @@ namespace System.Runtime.CompilerServices
{
NoisyLog("Calling cctor, cctor={0}, thread={1}", pfnCctor, currentManagedThreadId);
- Call<int>(pfnCctor);
+ Call(pfnCctor);
// Insert a memory barrier here to order any writes executed as part of static class
// construction above with respect to the initialized flag update we're about to make