Skip to content
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion src/coreclr/hosts/corerun/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -74,13 +74,17 @@ else()
-sMAXIMUM_MEMORY=2147483648
-sALLOW_MEMORY_GROWTH=1
-sSTACK_SIZE=5MB
-sWASM_BIGINT=1
-sEXPORTED_RUNTIME_METHODS=cwrap,ccall,HEAP8,HEAPU8,HEAP16,HEAPU16,HEAP32,HEAPU32,HEAP64,HEAPU64,HEAPF32,HEAPF64,safeSetTimeout,maybeExit,exitJS,abort,lengthBytesUTF8,UTF8ToString,stringToUTF8Array
-sEXPORTED_FUNCTIONS=_main,_GetDotNetRuntimeContractDescriptor
-sENVIRONMENT=node,shell,web
-Wl,-error-limit=0)

if (CORERUN_IN_BROWSER)
# Node.js doesn't have good support for WASM_BIGINT
# so it only is added when running in the browser.
target_link_options(corerun PRIVATE
-sWASM_BIGINT=1)

# Include the virtual file system data for the
# browser scenario.
set(WASM_PRELOAD_DIR "${CMAKE_INSTALL_PREFIX}/IL")
Expand Down
8 changes: 2 additions & 6 deletions src/coreclr/interpreter/compiler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3940,19 +3940,15 @@ void InterpCompiler::EmitCall(CORINFO_RESOLVED_TOKEN* pConstrainedToken, bool re
bool isDelegateInvoke = false;
bool isJmp = (*m_ip == CEE_JMP);

CORINFO_RESOLVED_TOKEN resolvedCallToken;
CORINFO_CALL_INFO callInfo;
CORINFO_RESOLVED_TOKEN resolvedCallToken{};
CORINFO_CALL_INFO callInfo{};
bool doCallInsteadOfNew = false;

int callIFunctionPointerVar = -1;
void* calliCookie = NULL;

if (isCalli)
{
// Suppress uninitialized use warning.
memset(&resolvedCallToken, 0, sizeof(resolvedCallToken));
memset(&callInfo, 0, sizeof(callInfo));

resolvedCallToken.token = token;
resolvedCallToken.tokenContext = METHOD_BEING_COMPILED_CONTEXT();
resolvedCallToken.tokenScope = m_methodInfo->scope;
Expand Down
13 changes: 7 additions & 6 deletions src/coreclr/vm/corhost.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -696,7 +696,8 @@ HRESULT CorHost2::CreateDelegate(

if (fnPtr == 0)
return E_POINTER;
*fnPtr = 0;

*fnPtr = NULL;

if(wszAssemblyName == NULL)
return E_INVALIDARG;
Expand All @@ -714,10 +715,6 @@ HRESULT CorHost2::CreateDelegate(
HRESULT hr = S_OK;
BEGIN_EXTERNAL_ENTRYPOINT(&hr);

#ifdef FEATURE_PORTABLE_ENTRYPOINTS
hr = E_NOTIMPL;

#else // !FEATURE_PORTABLE_ENTRYPOINTS
GCX_COOP_THREAD_EXISTS(GET_THREAD());

MAKE_UTF8PTR_FROMWIDE(szClassName, wszClassName);
Expand Down Expand Up @@ -754,15 +751,19 @@ HRESULT CorHost2::CreateDelegate(

if (pMD->HasUnmanagedCallersOnlyAttribute())
{
pMD->PrepareForUseAsAFunctionPointer();
*fnPtr = pMD->GetMultiCallableAddrOfCode();
}
else
{
#ifdef FEATURE_PORTABLE_ENTRYPOINTS
ThrowHR(COR_E_NOTSUPPORTED);
#else // !FEATURE_PORTABLE_ENTRYPOINTS
UMEntryThunkData* pUMEntryThunk = pMD->GetLoaderAllocator()->GetUMEntryThunkCache()->GetUMEntryThunk(pMD);
*fnPtr = (INT_PTR)pUMEntryThunk->GetCode();
#endif // FEATURE_PORTABLE_ENTRYPOINTS
}
}
#endif // FEATURE_PORTABLE_ENTRYPOINTS

END_EXTERNAL_ENTRYPOINT;

Expand Down
4 changes: 3 additions & 1 deletion src/coreclr/vm/interpexec.h
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,8 @@ struct ExceptionClauseArgs

void InterpExecMethod(InterpreterFrame *pInterpreterFrame, InterpMethodContextFrame *pFrame, InterpThreadContext *pThreadContext, ExceptionClauseArgs *pExceptionClauseArgs = NULL);

extern "C" void ExecuteInterpretedMethodFromUnmanaged(MethodDesc* pMD, int8_t* args, size_t argSize, int8_t* ret);

CallStubHeader *CreateNativeToInterpreterCallStub(InterpMethod* pInterpMethod);

#endif
#endif // _INTERPEXEC_H_
6 changes: 5 additions & 1 deletion src/coreclr/vm/method.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2119,7 +2119,11 @@ PCODE MethodDesc::TryGetMultiCallableAddrOfCode(CORINFO_ACCESS_FLAGS accessFlags
}

#ifdef FEATURE_PORTABLE_ENTRYPOINTS
return GetPortableEntryPoint();
PCODE entryPoint = GetPortableEntryPoint();
if (PortableEntryPoint::ToPortableEntryPoint(entryPoint)->HasUnmanagedCallersOnlyAttribute())
entryPoint = (PCODE)PortableEntryPoint::GetActualCode(entryPoint);

return entryPoint;

#else // !FEATURE_PORTABLE_ENTRYPOINTS
if (RequiresStableEntryPoint() && !HasStableEntryPoint())
Expand Down
60 changes: 52 additions & 8 deletions src/coreclr/vm/precode_portable.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,14 @@ void PortableEntryPoint::SetInterpreterData(PCODE addr, PCODE interpreterData)
portableEntryPoint->_pInterpreterData = (void*)PCODEToPINSTR(interpreterData);
}

#ifdef _DEBUG
bool PortableEntryPoint::IsValid() const
{
LIMITED_METHOD_CONTRACT;
return _canary == CANARY_VALUE;
}
#endif // _DEBUG

PortableEntryPoint* PortableEntryPoint::ToPortableEntryPoint(PCODE addr)
{
LIMITED_METHOD_CONTRACT;
Expand All @@ -86,21 +94,14 @@ PortableEntryPoint* PortableEntryPoint::ToPortableEntryPoint(PCODE addr)
return portableEntryPoint;
}

#ifdef _DEBUG
bool PortableEntryPoint::IsValid() const
{
LIMITED_METHOD_CONTRACT;
return _canary == CANARY_VALUE;
}
#endif // _DEBUG

void PortableEntryPoint::Init(MethodDesc* pMD)
{
LIMITED_METHOD_CONTRACT;
_ASSERTE(pMD != NULL);
_pActualCode = NULL;
_pMD = pMD;
_pInterpreterData = NULL;
_flags = kNone;
INDEBUG(_canary = CANARY_VALUE);
}

Expand All @@ -111,9 +112,52 @@ void PortableEntryPoint::Init(void* nativeEntryPoint)
_pActualCode = nativeEntryPoint;
_pMD = NULL;
_pInterpreterData = NULL;
_flags = kNone;
INDEBUG(_canary = CANARY_VALUE);
}

namespace
{
bool HasFlags(Volatile<LONG>& flags, LONG flagMask)
{
LIMITED_METHOD_CONTRACT;
return (flags.Load() & flagMask) == flagMask;
}

void SetFlags(Volatile<LONG>& flags, LONG flagMask)
{
LIMITED_METHOD_CONTRACT;
::InterlockedOr(flags.GetPointer(), flagMask);
}
}

// Forward declaration
LPVOID GetUnmanagedCallersOnlyThunk(MethodDesc* pMD);

bool PortableEntryPoint::HasUnmanagedCallersOnlyAttribute()
{
LIMITED_METHOD_CONTRACT;
_ASSERTE(IsValid());

if (HasFlags(_flags, kUnmanagedCallersOnly_Checked | kUnmanagedCallersOnly_Has))
return true;

if (HasFlags(_flags, kUnmanagedCallersOnly_Checked))
return false;

// First time check, do the full check
if (_pMD == nullptr || !_pMD->HasUnmanagedCallersOnlyAttribute())
{
SetFlags(_flags, kUnmanagedCallersOnly_Checked);
return false;
}

_pActualCode = GetUnmanagedCallersOnlyThunk(_pMD);
SetFlags(_flags, kUnmanagedCallersOnly_Checked | kUnmanagedCallersOnly_Has);

return true;
}

InterleavedLoaderHeapConfig s_stubPrecodeHeapConfig;

Precode* Precode::Allocate(PrecodeType t, MethodDesc* pMD,
Expand Down
17 changes: 14 additions & 3 deletions src/coreclr/vm/precode_portable.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,25 +21,36 @@ class PortableEntryPoint final
static void* GetInterpreterData(PCODE addr);
static void SetInterpreterData(PCODE addr, PCODE interpreterData);

private: // static
static PortableEntryPoint* ToPortableEntryPoint(PCODE addr);

private:
Volatile<void*> _pActualCode;
MethodDesc* _pMD;
void* _pInterpreterData;

enum PortableEntryPointFlag
{
kNone = 0,
kUnmanagedCallersOnly_Has = 0x1,
kUnmanagedCallersOnly_Checked = 0x2,
};
Volatile<LONG> _flags;

// We keep the canary value last to ensure a stable ABI across build flavors
INDEBUG(size_t _canary);

#ifdef _DEBUG
bool IsValid() const;
#endif // _DEBUG

public: // static
static PortableEntryPoint* ToPortableEntryPoint(PCODE addr);

public:
void Init(MethodDesc* pMD);
void Init(void* nativeEntryPoint);

// Check if the entry point represents a method with the UnmanagedCallersOnly attribute
bool HasUnmanagedCallersOnlyAttribute();

// Query methods for entry point state.
bool HasInterpreterCode() const
{
Expand Down
24 changes: 17 additions & 7 deletions src/coreclr/vm/prestub.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2056,18 +2056,28 @@ extern "C" void* STDCALL ExecuteInterpretedMethod(TransitionBlock* pTransitionBl
return frames.interpMethodContextFrame.pRetVal;
}

extern "C" void* STDCALL ExecuteInterpretedMethodWithArgs(TransitionBlock* pTransitionBlock, TADDR byteCodeAddr, int8_t* pArgs, size_t size, void* retBuff)
extern "C" void ExecuteInterpretedMethodFromUnmanaged(MethodDesc* pMD, int8_t* args, size_t argSize, int8_t* ret)
{
// copy the arguments to the stack
if (size > 0 && pArgs != nullptr)
_ASSERTE(pMD != NULL);

InterpByteCodeStart* targetIp = pMD->GetInterpreterCode();
if (targetIp == NULL)
{
InterpThreadContext *threadContext = GetInterpThreadContext();
int8_t *sp = threadContext->pStackPointer;
GCX_PREEMP();
(void)pMD->DoPrestub(NULL /* MethodTable */, CallerGCMode::Coop);
targetIp = pMD->GetInterpreterCode();
}

memcpy(sp, pArgs, size);
// Copy arguments to the stack
if (argSize > 0 && args != nullptr)
{
InterpThreadContext *threadContext = GetInterpThreadContext();
int8_t* sp = threadContext->pStackPointer;
memcpy(sp, args, argSize);
}

return ExecuteInterpretedMethod(pTransitionBlock, byteCodeAddr, retBuff);
TransitionBlock dummy{};
(void)ExecuteInterpretedMethod(&dummy, (TADDR)targetIp, ret);
}
#endif // FEATURE_INTERPRETER

Expand Down
16 changes: 4 additions & 12 deletions src/coreclr/vm/wasm/calldescrworkerwasm.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,11 @@

#include <interpexec.h>

extern "C" void* STDCALL ExecuteInterpretedMethodWithArgs(TransitionBlock* pTransitionBlock, TADDR byteCodeAddr, int8_t* pArgs, size_t size, void* retBuff);

extern "C" void STDCALL CallDescrWorkerInternal(CallDescrData* pCallDescrData)
{
MethodDesc* pMethod = PortableEntryPoint::GetMethodDesc(pCallDescrData->pTarget);
InterpByteCodeStart* targetIp = pMethod->GetInterpreterCode();
if (targetIp == NULL)
{
GCX_PREEMP();
(void)pMethod->DoPrestub(NULL /* MethodTable */, CallerGCMode::Coop);
targetIp = pMethod->GetInterpreterCode();
}
_ASSERTE(pCallDescrData != NULL);
_ASSERTE(pCallDescrData->pTarget != (PCODE)NULL);

TransitionBlock dummy{};
ExecuteInterpretedMethodWithArgs(&dummy, (TADDR)targetIp, (int8_t*)pCallDescrData->pSrc, pCallDescrData->nArgsSize, pCallDescrData->returnValue);
MethodDesc* pMethod = PortableEntryPoint::GetMethodDesc(pCallDescrData->pTarget);
ExecuteInterpretedMethodFromUnmanaged(pMethod, (int8_t*)pCallDescrData->pSrc, pCallDescrData->nArgsSize, (int8_t*)pCallDescrData->returnValue);
}
27 changes: 27 additions & 0 deletions src/coreclr/vm/wasm/callhelpers.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -735,3 +735,30 @@ const StringToWasmSigThunk g_wasmThunks[] = {
};

const size_t g_wasmThunksCount = sizeof(g_wasmThunks) / sizeof(g_wasmThunks[0]);

// Define reverse thunks here

// Entry point for interpreted method execution from unmanaged code
class MethodDesc;
extern "C" void ExecuteInterpretedMethodFromUnmanaged(MethodDesc* pMD, int8_t* args, size_t argSize, int8_t* ret);

// static MethodDesc* MD_MyAssembly_MyType_MyMethod_I32_I32_RetI32 = nullptr;
// static int Call_MyAssembly_MyType_MyMethod_I32_I32_RetI32(int a, int b)
// {
// int64_t args[2] =
// {
// (int64_t)a,
// (int64_t)b
// };

// int result;
// ExecuteInterpretedMethodFromUnmanaged(MD_MyAssembly_MyType_MyMethod_I32_I32_RetI32, (int8_t*)args, sizeof(args), (int8_t*)&result);
// return result;
// }

extern const ReverseThunkMapEntry g_ReverseThunks[] =
{
/// { 0xee78b850, { &MD_MyAssembly_MyType_MyMethod_I32_I32_RetI32, (void*)&Call_MyAssembly_MyType_MyMethod_I32_I32_RetI32 } },
};

const size_t g_ReverseThunksCount = sizeof(g_ReverseThunks) / sizeof(g_ReverseThunks[0]);
21 changes: 18 additions & 3 deletions src/coreclr/vm/wasm/callhelpers.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@
// The .NET Foundation licenses this file to you under the MIT license.
//

#ifndef __callhelpers_h__
#define __callhelpers_h__
#ifndef __WASM_CALLHELPERS_HPP__
#define __WASM_CALLHELPERS_HPP__

struct StringToWasmSigThunk
{
Expand All @@ -14,4 +14,19 @@ struct StringToWasmSigThunk
extern const StringToWasmSigThunk g_wasmThunks[];
extern const size_t g_wasmThunksCount;

#endif // __callhelpers_h__
struct ReverseThunkMapValue
{
MethodDesc** Target;
void* EntryPoint;
};

struct ReverseThunkMapEntry
{
ULONG key;
ReverseThunkMapValue value;
};

extern const ReverseThunkMapEntry g_ReverseThunks[];
extern const size_t g_ReverseThunksCount;

#endif // __WASM_CALLHELPERS_HPP__
Loading
Loading