From 738accf49d3ae9e4b031a616fccd14405a22b755 Mon Sep 17 00:00:00 2001 From: Milos Kotlar Date: Tue, 5 Aug 2025 20:12:08 +0200 Subject: [PATCH 1/5] Refactor string allocation method to use native-sized integer; add support for CPBLK operation in interpreter; Special-case RuntimeHandle constructors --- .../src/System/String.CoreCLR.cs | 4 +-- src/coreclr/interpreter/compiler.cpp | 29 ++++++++++++++++++- src/coreclr/interpreter/intops.def | 1 + src/coreclr/vm/interpexec.cpp | 9 ++++++ 4 files changed, 40 insertions(+), 3 deletions(-) diff --git a/src/coreclr/System.Private.CoreLib/src/System/String.CoreCLR.cs b/src/coreclr/System.Private.CoreLib/src/System/String.CoreCLR.cs index e66db58ba95f52..248b9a91305d80 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/String.CoreCLR.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/String.CoreCLR.cs @@ -25,10 +25,10 @@ internal static unsafe string StrCns(uint rid, IntPtr scopeHandle) } [MethodImpl(MethodImplOptions.InternalCall)] - internal static extern unsafe string FastAllocateString(MethodTable *pMT, int length); + internal static extern unsafe string FastAllocateString(MethodTable *pMT, nint length); [DebuggerHidden] - internal static unsafe string FastAllocateString(int length) + internal static unsafe string FastAllocateString(nint length) { return FastAllocateString(TypeHandle.TypeHandleOf().AsMethodTable(), length); } diff --git a/src/coreclr/interpreter/compiler.cpp b/src/coreclr/interpreter/compiler.cpp index 2363738a3f725f..2abd341a83b71e 100644 --- a/src/coreclr/interpreter/compiler.cpp +++ b/src/coreclr/interpreter/compiler.cpp @@ -4,6 +4,7 @@ #include "interpreter.h" #include "stackmap.h" +#include "../vm/classnames.h" #include @@ -2833,7 +2834,21 @@ void InterpCompiler::EmitCall(CORINFO_RESOLVED_TOKEN* pConstrainedToken, bool re if (newObjThisArgLocation != INT_MAX) { - ctorType = GetInterpType(m_compHnd->asCorInfoType(resolvedCallToken.hClass)); + const char* className = m_compHnd->getClassNameFromMetadata(resolvedCallToken.hClass, NULL); + CorInfoType corInfoType; + if (!strcmp(className, g_RuntimeMethodHandleInternalName) || + !strcmp(className, g_RuntimeFieldHandleInternalName) || + !strcmp(className, g_RuntimeArgumentHandleName)) + { + corInfoType = CORINFO_TYPE_VALUECLASS; + } + else + { + corInfoType = m_compHnd->asCorInfoType(resolvedCallToken.hClass); + } + + ctorType = GetInterpType(corInfoType); + if (ctorType == InterpTypeVT) { vtsize = m_compHnd->getClassSize(resolvedCallToken.hClass); @@ -5412,6 +5427,18 @@ void InterpCompiler::GenerateCode(CORINFO_METHOD_INFO* methodInfo) m_ip += 5; break; } + case CEE_CPBLK: + CHECK_STACK(3); + if (volatile_) + { + AddIns(INTOP_MEMBAR); + volatile_ = false; + } + AddIns(INTOP_CPBLK); + m_pStackPointer -= 3; + m_pLastNewIns->SetSVars3(m_pStackPointer[0].var, m_pStackPointer[1].var, m_pStackPointer[2].var); + m_ip++; + break; default: { const uint8_t *ip = m_ip - 1; diff --git a/src/coreclr/interpreter/intops.def b/src/coreclr/interpreter/intops.def index 0e1d73769a44fa..0861d0f21fbfa7 100644 --- a/src/coreclr/interpreter/intops.def +++ b/src/coreclr/interpreter/intops.def @@ -390,6 +390,7 @@ OPDEF(INTOP_GENERICLOOKUP, "generic", 4, 1, 1, InterpOpGenericLookup) OPDEF(INTOP_CALL_FINALLY, "call.finally", 2, 0, 0, InterpOpBranch) OPDEF(INTOP_ZEROBLK_IMM, "zeroblk.imm", 3, 0, 1, InterpOpInt) +OPDEF(INTOP_CPBLK, "cpblk", 4, 0, 3, InterpOpNoArgs) OPDEF(INTOP_LOCALLOC, "localloc", 3, 1, 1, InterpOpNoArgs) OPDEF(INTOP_BREAKPOINT, "breakpoint", 1, 0, 0, InterpOpNoArgs) diff --git a/src/coreclr/vm/interpexec.cpp b/src/coreclr/vm/interpexec.cpp index 2fb4f73e4f2a69..b5d3c8b1750159 100644 --- a/src/coreclr/vm/interpexec.cpp +++ b/src/coreclr/vm/interpexec.cpp @@ -2012,6 +2012,15 @@ void InterpExecMethod(InterpreterFrame *pInterpreterFrame, InterpMethodContextFr memset(LOCAL_VAR(ip[1], void*), 0, ip[2]); ip += 3; break; + case INTOP_CPBLK: + { + void* dst = LOCAL_VAR(ip[1], void*); + void* src = LOCAL_VAR(ip[2], void*); + size_t size = LOCAL_VAR(ip[3], size_t); + memcpy(dst, src, size); + ip += 4; + break; + } case INTOP_LOCALLOC: { size_t len = LOCAL_VAR(ip[2], size_t); From 468bbed6045c3af5b9f3262090f886c0bd7aaae9 Mon Sep 17 00:00:00 2001 From: Milos Kotlar Date: Tue, 5 Aug 2025 20:23:32 +0200 Subject: [PATCH 2/5] Add null reference checks before memcpy --- src/coreclr/vm/interpexec.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/coreclr/vm/interpexec.cpp b/src/coreclr/vm/interpexec.cpp index b5d3c8b1750159..80ed0344204875 100644 --- a/src/coreclr/vm/interpexec.cpp +++ b/src/coreclr/vm/interpexec.cpp @@ -2017,7 +2017,10 @@ void InterpExecMethod(InterpreterFrame *pInterpreterFrame, InterpMethodContextFr void* dst = LOCAL_VAR(ip[1], void*); void* src = LOCAL_VAR(ip[2], void*); size_t size = LOCAL_VAR(ip[3], size_t); - memcpy(dst, src, size); + if (size && (!dst || !src)) + COMPlusThrow(kNullReferenceException); + else + memcpy(dst, src, size); ip += 4; break; } From 5ec9b08c9e6072b1d07d6e2ef9f4306943b487f7 Mon Sep 17 00:00:00 2001 From: Milos Kotlar Date: Tue, 5 Aug 2025 20:32:00 +0200 Subject: [PATCH 3/5] Include namespace checks for RuntimeHandle types --- src/coreclr/interpreter/compiler.cpp | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/coreclr/interpreter/compiler.cpp b/src/coreclr/interpreter/compiler.cpp index 2abd341a83b71e..b18cae03e9f71a 100644 --- a/src/coreclr/interpreter/compiler.cpp +++ b/src/coreclr/interpreter/compiler.cpp @@ -2834,11 +2834,14 @@ void InterpCompiler::EmitCall(CORINFO_RESOLVED_TOKEN* pConstrainedToken, bool re if (newObjThisArgLocation != INT_MAX) { - const char* className = m_compHnd->getClassNameFromMetadata(resolvedCallToken.hClass, NULL); + const char* namespaceName = nullptr; + const char* className = m_compHnd->getClassNameFromMetadata(resolvedCallToken.hClass, &namespaceName); CorInfoType corInfoType; - if (!strcmp(className, g_RuntimeMethodHandleInternalName) || - !strcmp(className, g_RuntimeFieldHandleInternalName) || - !strcmp(className, g_RuntimeArgumentHandleName)) + if (namespaceName != NULL && className != NULL && + !strcmp(namespaceName, "System") && + (!strcmp(className, g_RuntimeMethodHandleInternalName) || + !strcmp(className, g_RuntimeFieldHandleInternalName) || + !strcmp(className, g_RuntimeArgumentHandleName))) { corInfoType = CORINFO_TYPE_VALUECLASS; } From 33ce119474504e1a429c394ffcac89daaf43236b Mon Sep 17 00:00:00 2001 From: Milos Kotlar Date: Wed, 6 Aug 2025 11:04:11 +0200 Subject: [PATCH 4/5] Refactor EmitCall method to simplify type handling; replace memcpy with memcpyNoGCRefs for null reference safety --- src/coreclr/interpreter/compiler.cpp | 22 +++------------------- src/coreclr/vm/interpexec.cpp | 2 +- 2 files changed, 4 insertions(+), 20 deletions(-) diff --git a/src/coreclr/interpreter/compiler.cpp b/src/coreclr/interpreter/compiler.cpp index b18cae03e9f71a..50862f5a7240e9 100644 --- a/src/coreclr/interpreter/compiler.cpp +++ b/src/coreclr/interpreter/compiler.cpp @@ -2834,25 +2834,9 @@ void InterpCompiler::EmitCall(CORINFO_RESOLVED_TOKEN* pConstrainedToken, bool re if (newObjThisArgLocation != INT_MAX) { - const char* namespaceName = nullptr; - const char* className = m_compHnd->getClassNameFromMetadata(resolvedCallToken.hClass, &namespaceName); - CorInfoType corInfoType; - if (namespaceName != NULL && className != NULL && - !strcmp(namespaceName, "System") && - (!strcmp(className, g_RuntimeMethodHandleInternalName) || - !strcmp(className, g_RuntimeFieldHandleInternalName) || - !strcmp(className, g_RuntimeArgumentHandleName))) - { - corInfoType = CORINFO_TYPE_VALUECLASS; - } - else - { - corInfoType = m_compHnd->asCorInfoType(resolvedCallToken.hClass); - } - - ctorType = GetInterpType(corInfoType); + ctorType = GetInterpType(m_compHnd->asCorInfoType(resolvedCallToken.hClass)); - if (ctorType == InterpTypeVT) + if (ctorType != InterpTypeO) { vtsize = m_compHnd->getClassSize(resolvedCallToken.hClass); PushTypeVT(resolvedCallToken.hClass, vtsize); @@ -2984,7 +2968,7 @@ void InterpCompiler::EmitCall(CORINFO_RESOLVED_TOKEN* pConstrainedToken, bool re case CORINFO_CALL: if (newObj && !doCallInsteadOfNew) { - if (ctorType == InterpTypeVT) + if (ctorType != InterpTypeO) { // If this is a newobj for a value type, we need to call the constructor // and then copy the value type to the stack. diff --git a/src/coreclr/vm/interpexec.cpp b/src/coreclr/vm/interpexec.cpp index 80ed0344204875..3419a19710d3b3 100644 --- a/src/coreclr/vm/interpexec.cpp +++ b/src/coreclr/vm/interpexec.cpp @@ -2020,7 +2020,7 @@ void InterpExecMethod(InterpreterFrame *pInterpreterFrame, InterpMethodContextFr if (size && (!dst || !src)) COMPlusThrow(kNullReferenceException); else - memcpy(dst, src, size); + memcpyNoGCRefs(dst, src, size); ip += 4; break; } From 1cef773e70e6a8e5f0879bd3eb11c6fd4d4e3495 Mon Sep 17 00:00:00 2001 From: Milos Kotlar Date: Wed, 6 Aug 2025 11:12:00 +0200 Subject: [PATCH 5/5] Remove unnecessary include of classnames.h --- src/coreclr/interpreter/compiler.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/coreclr/interpreter/compiler.cpp b/src/coreclr/interpreter/compiler.cpp index 50862f5a7240e9..c184a263bf1bf5 100644 --- a/src/coreclr/interpreter/compiler.cpp +++ b/src/coreclr/interpreter/compiler.cpp @@ -4,7 +4,6 @@ #include "interpreter.h" #include "stackmap.h" -#include "../vm/classnames.h" #include @@ -2835,7 +2834,6 @@ void InterpCompiler::EmitCall(CORINFO_RESOLVED_TOKEN* pConstrainedToken, bool re if (newObjThisArgLocation != INT_MAX) { ctorType = GetInterpType(m_compHnd->asCorInfoType(resolvedCallToken.hClass)); - if (ctorType != InterpTypeO) { vtsize = m_compHnd->getClassSize(resolvedCallToken.hClass);