Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
1 change: 1 addition & 0 deletions src/coreclr/inc/corinfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -807,6 +807,7 @@ enum CORINFO_ACCESS_FLAGS
CORINFO_ACCESS_NONNULL = 0x0004, // Instance is guaranteed non-null

CORINFO_ACCESS_LDFTN = 0x0010, // Accessed via ldftn
CORINFO_ACCESS_UNMANAGED_CALLER_MAYBE = 0x0020, // Method might be attributed with UnmanagedCallersOnlyAttribute.

// Field access flags
CORINFO_ACCESS_GET = 0x0100, // Field get (ldfld)
Expand Down
1 change: 1 addition & 0 deletions src/coreclr/tools/Common/JitInterface/CorInfoTypes.cs
Original file line number Diff line number Diff line change
Expand Up @@ -547,6 +547,7 @@ public enum CORINFO_ACCESS_FLAGS
CORINFO_ACCESS_NONNULL = 0x0004, // Instance is guaranteed non-null

CORINFO_ACCESS_LDFTN = 0x0010, // Accessed via ldftn
CORINFO_ACCESS_UNMANAGED_CALLER_MAYBE = 0x0020, // Method might be attributed with UnmanagedCallersOnlyAttribute.

// Field access flags
CORINFO_ACCESS_GET = 0x0100, // Field get (ldfld)
Expand Down
17 changes: 11 additions & 6 deletions src/coreclr/vm/comdelegate.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1277,17 +1277,22 @@ void COMDelegate::BindToMethod(DELEGATEREF *pRefThis,
// We can get virtual delegates closed over null through this code path, so be careful to handle that case (no need to
// virtualize since we're just going to throw NullRefException at invocation time).
// </TODO>
if (pTargetMethod->IsVirtual() &&
*pRefFirstArg != NULL &&
pTargetMethod->GetMethodTable() != (*pRefFirstArg)->GetMethodTable())
if (pTargetMethod->IsVirtual()
&& *pRefFirstArg != NULL
&& pTargetMethod->GetMethodTable() != (*pRefFirstArg)->GetMethodTable())
{
pTargetCode = pTargetMethod->GetMultiCallableAddrOfVirtualizedCode(pRefFirstArg, pTargetMethod->GetMethodTable());
else
}
#ifdef HAS_THISPTR_RETBUF_PRECODE
if (pTargetMethod->IsStatic() && pTargetMethod->HasRetBuffArg() && IsRetBuffPassedAsFirstArg())
else if (pTargetMethod->IsStatic() && pTargetMethod->HasRetBuffArg() && IsRetBuffPassedAsFirstArg())
{
pTargetCode = pTargetMethod->GetLoaderAllocator()->GetFuncPtrStubs()->GetFuncPtrStub(pTargetMethod, PRECODE_THISPTR_RETBUF);
else
}
#endif // HAS_THISPTR_RETBUF_PRECODE
else
{
pTargetCode = pTargetMethod->GetMultiCallableAddrOfCode();
}
_ASSERTE(pTargetCode);

refRealDelegate->SetTarget(*pRefFirstArg);
Expand Down
15 changes: 8 additions & 7 deletions src/coreclr/vm/corhost.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -694,8 +694,9 @@ HRESULT CorHost2::CreateDelegate(
EMPTY_STRING_TO_NULL(wszClassName);
EMPTY_STRING_TO_NULL(wszMethodName);

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

*fnPtr = 0;

if(wszAssemblyName == NULL)
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())
{
*fnPtr = pMD->GetMultiCallableAddrOfCode();
pMD->PrepareForUseAsAFunctionPointer();
*fnPtr = pMD->GetMultiCallableAddrOfCode(CORINFO_ACCESS_UNMANAGED_CALLER_MAYBE);
}
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
20 changes: 20 additions & 0 deletions src/coreclr/vm/dllimport.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6165,6 +6165,26 @@ EXTERN_C void STDCALL GenericPInvokeCalliStubWorker(TransitionBlock * pTransitio
pFrame->Pop(CURRENT_THREAD);
}

EXTERN_C void LookupMethodByName(const char* fullQualifiedTypeName, const char* methodName, MethodDesc** ppMD)
{
CONTRACTL
{
STANDARD_VM_CHECK;
ENTRY_POINT;
}
CONTRACTL_END;

_ASSERTE(fullQualifiedTypeName != nullptr);
_ASSERTE(methodName != nullptr);
_ASSERTE(ppMD != nullptr);

SString fullQualifiedTypeNameUtf8(SString::Utf8, fullQualifiedTypeName);
TypeHandle type = TypeName::GetTypeFromAsmQualifiedName(fullQualifiedTypeNameUtf8.GetUnicode(), /*bThrowIfNotFound*/ TRUE);
_ASSERTE(!type.IsTypeDesc());

*ppMD = MemberLoader::FindMethodByName(type.GetMethodTable(), methodName);
}

namespace
{
//-------------------------------------------------------------------------------------
Expand Down
2 changes: 1 addition & 1 deletion src/coreclr/vm/interpexec.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -293,7 +293,7 @@ void InvokeCalliStub(PCODE ftn, void *cookie, int8_t *pArgs, int8_t *pRet)
pHeader->Invoke(pHeader->Routines, pArgs, pRet, pHeader->TotalStackSize);
}

LPVOID GetCookieForCalliSig(MetaSig metaSig)
void* GetCookieForCalliSig(MetaSig metaSig)
{
STANDARD_VM_CONTRACT;

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

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

extern "C" void LookupMethodByName(const char* fullQualifiedTypeName, const char* methodName, MethodDesc** ppMD);
extern "C" void ExecuteInterpretedMethodFromUnmanaged(MethodDesc* pMD, int8_t* args, size_t argSize, int8_t* ret);

CallStubHeader *CreateNativeToInterpreterCallStub(InterpMethod* pInterpMethod);

#endif
#endif // _INTERPEXEC_H_
10 changes: 5 additions & 5 deletions src/coreclr/vm/jitinterface.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9158,15 +9158,15 @@ void CEEInfo::getFunctionEntryPoint(CORINFO_METHOD_HANDLE ftnHnd,
}
else
{
ret = (void *)ftn->TryGetMultiCallableAddrOfCode(accessFlags);
ret = (void*)ftn->TryGetMultiCallableAddrOfCode((CORINFO_ACCESS_FLAGS)(accessFlags | CORINFO_ACCESS_UNMANAGED_CALLER_MAYBE));

// TryGetMultiCallableAddrOfCode returns NULL if indirect access is desired
if (ret == NULL)
{
// should never get here for EnC methods or if interception via remoting stub is required
_ASSERTE(!ftn->InEnCEnabledModule());

ret = (void *)ftn->GetAddrOfSlot();
ret = (void*)ftn->GetAddrOfSlot();

accessType = IAT_PVALUE;
}
Expand Down Expand Up @@ -9205,7 +9205,7 @@ void CEEInfo::getFunctionFixedEntryPoint(CORINFO_METHOD_HANDLE ftn,
pMD->PrepareForUseAsAFunctionPointer();

pResult->accessType = IAT_VALUE;
pResult->addr = (void*)pMD->GetMultiCallableAddrOfCode();
pResult->addr = (void*)pMD->GetMultiCallableAddrOfCode(CORINFO_ACCESS_UNMANAGED_CALLER_MAYBE);

EE_TO_JIT_TRANSITION();
}
Expand Down Expand Up @@ -11291,7 +11291,7 @@ LPVOID CEEInfo::GetCookieForInterpreterCalliSig(CORINFO_SIG_INFO* szMetaSig)
#ifdef FEATURE_INTERPRETER

// Forward declare the function for mapping MetaSig to a cookie.
LPVOID GetCookieForCalliSig(MetaSig metaSig);
void* GetCookieForCalliSig(MetaSig metaSig);

LPVOID CInterpreterJitInfo::GetCookieForInterpreterCalliSig(CORINFO_SIG_INFO* szMetaSig)
{
Expand Down Expand Up @@ -13936,7 +13936,7 @@ BOOL LoadDynamicInfoEntry(Module *currentModule,
}

MethodEntry:
result = pMD->GetMultiCallableAddrOfCode(CORINFO_ACCESS_ANY);
result = pMD->GetMultiCallableAddrOfCode(CORINFO_ACCESS_UNMANAGED_CALLER_MAYBE);
}
break;

Expand Down
27 changes: 23 additions & 4 deletions src/coreclr/vm/method.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2104,12 +2104,13 @@ PCODE MethodDesc::TryGetMultiCallableAddrOfCode(CORINFO_ACCESS_FLAGS accessFlags
COMPlusThrow(kInvalidOperationException, IDS_EE_CODEEXECUTION_CONTAINSGENERICVAR);
}

#ifdef _DEBUG
if (accessFlags & CORINFO_ACCESS_LDFTN)
{
// Whenever we use LDFTN on shared-generic-code-which-requires-an-extra-parameter
// we need to give out the address of an instantiating stub. This is why we give
// out GetStableEntryPoint() for the IsInstantiatingStub() case: this is
// safe. But first we assert that we only use GetMultiCallableAddrOfCode on
// we need to give out the address of an instantiating stub. This is why we give
// out GetStableEntryPoint() for IsInstantiatingStub() via the IsWrapperStub() case: this is
// safe. But first we assert that we only use GetMultiCallableAddrOfCode on
// the instantiating stubs and not on the shared code itself.
_ASSERTE(!RequiresInstArg());
_ASSERTE(!IsSharedByGenericMethodInstantiations());
Expand All @@ -2118,8 +2119,26 @@ PCODE MethodDesc::TryGetMultiCallableAddrOfCode(CORINFO_ACCESS_FLAGS accessFlags
_ASSERTE((accessFlags & ~CORINFO_ACCESS_LDFTN) == 0);
}

#ifndef FEATURE_PORTABLE_ENTRYPOINTS
// If HasUnmanagedCallersOnlyAttribute() is true, then CORINFO_ACCESS_UNMANAGED_CALLER_MAYBE must be set.
// We only validate this on non portable entrypoints because HasUnmanagedCallersOnlyAttribute()
// is an unnecessary cost, even in non-Release builds, on portable entrypoint platforms.
if (HasUnmanagedCallersOnlyAttribute())
{
_ASSERTE((accessFlags & CORINFO_ACCESS_UNMANAGED_CALLER_MAYBE) != 0);
}
#endif // !FEATURE_PORTABLE_ENTRYPOINTS
#endif // _DEBUG

#ifdef FEATURE_PORTABLE_ENTRYPOINTS
return GetPortableEntryPoint();
PCODE entryPoint = GetPortableEntryPoint();
if (accessFlags & CORINFO_ACCESS_UNMANAGED_CALLER_MAYBE
&& 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<int32_t>& flags, int32_t flagMask)
{
LIMITED_METHOD_CONTRACT;
return (flags.Load() & flagMask) == flagMask;
}

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

// Forward declaration
void* 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<int32_t> _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
Loading
Loading