Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[NativeAOT-LLVM]: Initial support for IsVirtualVtable calls #1768

Merged
merged 9 commits into from
Feb 10, 2022
Merged
7 changes: 7 additions & 0 deletions src/coreclr/jit/gentree.h
Original file line number Diff line number Diff line change
Expand Up @@ -4749,6 +4749,7 @@ struct GenTreeCall final : public GenTree

#if defined(TARGET_WASM)
CorInfoType gtCorInfoType; // the precise return type used to construct the signature
bool gtHasHiddenArgument;
#endif

CORINFO_CLASS_HANDLE gtRetClsHnd; // The return type handle of the call if it is a struct; always available
Expand Down Expand Up @@ -4813,10 +4814,16 @@ struct GenTreeCall final : public GenTree
GenTreeCall(var_types type) : GenTree(GT_CALL, type)
{
fgArgInfo = nullptr;
#ifdef TARGET_WASM
gtHasHiddenArgument = false;
#endif // TARGET_WAS<
}
#if DEBUGGABLE_GENTREE
GenTreeCall() : GenTree()
{
#ifdef TARGET_WASM
gtHasHiddenArgument = false;
#endif // TARGET_WAS<
}
#endif
};
Expand Down
10 changes: 10 additions & 0 deletions src/coreclr/jit/indirectcalltransformer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -461,6 +461,9 @@ class IndirectCallTransformer
{
fatCall->gtCallArgs = compiler->gtPrependNewCallArg(hiddenArgument, fatCall->gtCallArgs);
}
#ifdef TARGET_WASM
fatCall->gtHasHiddenArgument = true;
#endif // TARGET_WASM
#else
if (fatCall->gtCallArgs == nullptr)
{
Expand Down Expand Up @@ -491,7 +494,14 @@ class IndirectCallTransformer
}

private:
// Wasm stores function pointers as indicies in a function table

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// Wasm stores function pointers as indicies in a function table
// Wasm stores function pointers as indices in a function table.

#if defined(TARGET_WASM32)
const int FAT_POINTER_MASK = 0x80000000;
#elif defined(TARGET_WASM64)
const int FAT_POINTER_MASK = 0x8000000000000000;
#else
const int FAT_POINTER_MASK = 0x2;
#endif // TARGET_WASM

GenTree* fptrAddress;
var_types pointerType;
Expand Down
183 changes: 139 additions & 44 deletions src/coreclr/jit/llvm.cpp

Large diffs are not rendered by default.

14 changes: 8 additions & 6 deletions src/coreclr/jit/llvm.h
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ extern "C" void registerLlvmCallbacks(void* thisPtr,
const char* dataLayout,
const char* (*getMangledMethodNamePtr)(void*, CORINFO_METHOD_STRUCT_*),
const char* (*getMangledSymbolNamePtr)(void*, void*),
const char* (*getMangledSymbolNameFromHelperTargetPtr)(void*, void*),
const char* (*getTypeName)(void*, CORINFO_CLASS_HANDLE),
const char* (*addCodeReloc)(void*, void*),
const uint32_t (*isRuntimeImport)(void*, CORINFO_METHOD_STRUCT_*),
Expand Down Expand Up @@ -153,15 +154,15 @@ class Llvm
void emitDoNothingCall();
void endImportingBasicBlock(BasicBlock* block);
[[noreturn]] void failFunctionCompilation();
void failUnsupportedCalls(GenTreeCall* callNode, CORINFO_SIG_INFO &calleeSigInfo);
void failUnsupportedCalls(GenTreeCall* callNode, CORINFO_SIG_INFO* calleeSigInfo);
void fillPhis();
llvm::Instruction* getCast(llvm::Value* source, Type* targetType);
void generateProlog();
CorInfoType getCorInfoTypeForArg(CORINFO_SIG_INFO& sigInfo, CORINFO_ARG_LIST_HANDLE& arg, CORINFO_CLASS_HANDLE* clsHnd);
CorInfoType getCorInfoTypeForArg(CORINFO_SIG_INFO* sigInfo, CORINFO_ARG_LIST_HANDLE& arg, CORINFO_CLASS_HANDLE* clsHnd);
llvm::FunctionType* getFunctionType();
llvm::FunctionType* getFunctionTypeForCall(GenTreeCall* callNode);
llvm::FunctionType* getFunctionTypeForCall(GenTreeCall* call);
Value* getGenTreeValue(GenTree* node);
LlvmArgInfo getLlvmArgInfoForArgIx(CORINFO_SIG_INFO& sigInfo, unsigned int lclNum);
LlvmArgInfo getLlvmArgInfoForArgIx(unsigned int lclNum);
llvm::BasicBlock* getLLVMBasicBlockForBlock(BasicBlock* block);
Type* getLlvmTypeForCorInfoType(CorInfoType corInfoType, CORINFO_CLASS_HANDLE classHnd);
Type* getLlvmTypeForParameterType(CORINFO_CLASS_HANDLE classHnd);
Expand All @@ -170,6 +171,7 @@ class Llvm
int getLocalOffsetAtIndex(GenTreeLclVar* lclVar);
Value* getLocalVarAddress(GenTreeLclVar* lclVar);
struct DebugMetadata getOrCreateDebugMetadata(const char* documentFileName);
llvm::Function* getOrCreateLlvmFunction(const char* symbolName, GenTreeCall* call);
Value* getShadowStackForCallee();
unsigned int getSpillOffsetAtIndex(unsigned int index, unsigned int offset);
Value* getSsaLocalForPhi(unsigned lclNum, unsigned ssaNum);
Expand All @@ -181,8 +183,8 @@ class Llvm
void importStoreInd(GenTreeStoreInd* storeIndOp);
Value* localVar(GenTreeLclVar* lclVar);

GenTreeCall::Use* lowerCallReturn(GenTreeCall* callNode, CORINFO_SIG_INFO& calleeSigInfo, GenTreeCall::Use* lastArg);
void lowerCallToShadowStack(GenTreeCall* callNode, CORINFO_SIG_INFO& calleeSigInfo);
GenTreeCall::Use* lowerCallReturn(GenTreeCall* callNode, CORINFO_SIG_INFO* calleeSigInfo, GenTreeCall::Use* lastArg);
void lowerCallToShadowStack(GenTreeCall* callNode, CORINFO_SIG_INFO* calleeSigInfo);
void lowerToShadowStack();

Value* mapGenTreeToValue(GenTree* genTree, Value* valueRef);
Expand Down
23 changes: 21 additions & 2 deletions src/coreclr/jit/ssabuilder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -598,9 +598,28 @@ void SsaBuilder::InsertPhiToRationalIRForm(BasicBlock* block, unsigned lclNum)
GenTree* storeLcl = m_pCompiler->gtNewStoreLclVar(lclNum, phi);

LIR::Range& lirRange = LIR::AsRange(block);
GenTree* firstNode = lirRange.FirstNode();
GenTree* firstNode = lirRange.FirstNode();

// cant insert the storeLcl bewteen phis so find first non-phi node
GenTree* nonPhiNode = nullptr;
for (GenTree* node : lirRange)
{
if (!node->IsPhiNode())
{
nonPhiNode = node;
break;
}
}

lirRange.InsertBefore(firstNode, phi);
lirRange.InsertAfter(phi, storeLcl);
if (nonPhiNode == nullptr)
{
lirRange.InsertAfter(phi, storeLcl);
}
else
{
lirRange.InsertBefore(nonPhiNode, storeLcl);
}

JITDUMP("Added PHI definition for V%02u at start of " FMT_BB ".\n", lclNum, block->bbNum);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -127,9 +127,8 @@ private unsafe void CompileSingleMethod(CorInfoImpl corInfo, LLVMMethodCodeNode
{
if (GetMethodIL(method).GetExceptionRegions().Length == 0)
{
var sig = method.Signature;
// this could be inlined, by the local makes debugging easier
var mangledName = NodeFactory.NameMangler.GetMangledMethodName(method).ToString();
var sig = method.Signature;
corInfo.RegisterLlvmCallbacks((IntPtr)Unsafe.AsPointer(ref corInfo), _outputFile,
Module.Target,
Module.DataLayout);
Expand All @@ -145,7 +144,7 @@ private unsafe void CompileSingleMethod(CorInfoImpl corInfo, LLVMMethodCodeNode

ryuJitMethodCount++;
}
else ILImporter.CompileMethod(this, methodCodeNodeNeedingCode);
else ILImporter.CompileMethod(this, methodCodeNodeNeedingCode);
}
catch (CodeGenerationFailedException)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
using Internal.IL;
using Internal.Text;
using Internal.TypeSystem;
using Internal.TypeSystem.Ecma;

namespace Internal.JitInterface
{
Expand All @@ -25,6 +26,15 @@ public static void addCodeReloc(IntPtr thisHandle, void* handle)
var helperNode = node as ReadyToRunHelperNode;
if (helperNode != null)
{
if (helperNode.Id == ReadyToRunHelperId.VirtualCall)
{
MethodDesc virtualCallTarget = (MethodDesc)helperNode.Target;
_this._codeRelocs.Add(new Relocation(RelocType.IMAGE_REL_BASED_REL32, 0,
_this._compilation.NodeFactory.MethodEntrypoint(virtualCallTarget)));

return;
}

MetadataType target = (MetadataType)helperNode.Target;
switch (helperNode.Id)
{
Expand Down Expand Up @@ -105,6 +115,21 @@ private static byte[] AppendNullByte(byte[] inputArray)
return (byte*)_this.GetPin(sb.UnderlyingArray);
}

[UnmanagedCallersOnly]
public static byte* getSymbolMangledNameFromHelperTarget(IntPtr thisHandle, void* handle)
{
var _this = GetThis(thisHandle);

var node = (ReadyToRunHelperNode)_this.HandleToObject((IntPtr)handle);
var method = node.Target as MethodDesc;

// Abstract methods must require a lookup so no point passing the abstract name back
if (method.IsAbstract || method.IsVirtual) return null;

Utf8StringBuilder sb = new Utf8StringBuilder();
return (byte*)_this.GetPin(AppendNullByte(_this._compilation.NameMangler.GetMangledMethodName(method).UnderlyingArray));
}

// IL backend does not use the mangled name. The unmangled name is easier to read.
[UnmanagedCallersOnly]
public static byte* getTypeName(IntPtr thisHandle, CORINFO_CLASS_STRUCT_* structHnd)
Expand All @@ -120,7 +145,6 @@ private static byte[] AppendNullByte(byte[] inputArray)
return (byte*)_this.GetPin(sb.UnderlyingArray);
}


[UnmanagedCallersOnly]
public static uint isRuntimeImport(IntPtr thisHandle, CORINFO_METHOD_STRUCT_* ftn)
{
Expand Down Expand Up @@ -267,6 +291,7 @@ public static CorInfoTypeWithMod getParameterType(IntPtr thisHandle, CORINFO_CLA
private extern static void registerLlvmCallbacks(IntPtr thisHandle, byte* outputFileName, byte* triple, byte* dataLayout,
delegate* unmanaged<IntPtr, CORINFO_METHOD_STRUCT_*, byte*> getMangedMethodNamePtr,
delegate* unmanaged<IntPtr, void*, byte*> getSymbolMangledName,
delegate* unmanaged<IntPtr, void*, byte*> getSymbolMangledNameFromHelperTarget,
delegate* unmanaged<IntPtr, CORINFO_CLASS_STRUCT_*, byte*> getTypeName,
delegate* unmanaged<IntPtr, void*, void> addCodeReloc,
delegate* unmanaged<IntPtr, CORINFO_METHOD_STRUCT_*, uint> isRuntimeImport,
Expand All @@ -286,6 +311,7 @@ public void RegisterLlvmCallbacks(IntPtr corInfoPtr, string outputFileName, stri
(byte*)GetPin(StringToUTF8(dataLayout)),
&getMangledMethodName,
&getSymbolMangledName,
&getSymbolMangledNameFromHelperTarget,
&getTypeName,
&addCodeReloc,
&isRuntimeImport,
Expand Down
2 changes: 1 addition & 1 deletion src/coreclr/tools/aot/ILCompiler/ILCompiler.csproj
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<AssemblyName>ilc</AssemblyName>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
Expand Down
1 change: 0 additions & 1 deletion src/tests/Common/dirs.proj
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,6 @@
<ItemGroup Condition="'$(TestBuildMode)' == 'nativeaot' and '$(TargetArchitecture)' == 'wasm'">
<DisabledProjects Include="$(TestRoot)nativeaot\SmokeTests\BasicThreading\BasicThreading.csproj" />
<DisabledProjects Include="$(TestRoot)nativeaot\SmokeTests\HardwareIntrinsics\*.csproj" />
<DisabledProjects Include="$(TestRoot)nativeaot\SmokeTests\Delegates\Delegates.csproj" />
<DisabledProjects Include="$(TestRoot)nativeaot\SmokeTests\DynamicGenerics\DynamicGenerics.csproj" />
<DisabledProjects Include="$(TestRoot)nativeaot\SmokeTests\PInvoke\PInvoke.csproj" />
<DisabledProjects Include="$(TestRoot)nativeaot\SmokeTests\SharedLibrary\SharedLibrary.csproj" />
Expand Down