diff --git a/docs/design/coreclr/botr/corelib.md b/docs/design/coreclr/botr/corelib.md
index 9662dc3f4e20ff..1dd2fc60d4bb08 100644
--- a/docs/design/coreclr/botr/corelib.md
+++ b/docs/design/coreclr/botr/corelib.md
@@ -42,8 +42,6 @@ The CLR provides a [`mscorlib` binder](https://github.com/dotnet/runtime/blob/ma
Two techniques exist for calling into the CLR from managed code. FCall allows you to call directly into the CLR code, and provides a lot of flexibility in terms of manipulating objects, though it is easy to cause GC holes by not tracking object references correctly. QCall also allows you to call into the CLR via the P/Invoke, but is much harder to accidentally mis-use. FCalls are identified in managed code as extern methods with the [`MethodImplOptions.InternalCall`](https://learn.microsoft.com/dotnet/api/system.runtime.compilerservices.methodimploptions) bit set. QCalls are marked `static extern` methods similar to regular P/Invokes, but are directed toward a library called `"QCall"`.
-There is a small variant of FCall called HCall (for Helper call) for implementing JIT helpers. The HCall is intended for doing things like accessing multi-dimensional array elements, range checks, etc. The only difference between HCall and FCall is that HCall methods won't show up in an exception stack trace.
-
### Choosing between FCall, QCall, P/Invoke, and writing in managed code
First, remember that you should be writing as much as possible in managed code. You avoid a raft of potential GC hole issues, you get a better debugging experience, and the code is often simpler.
@@ -54,7 +52,7 @@ If the only reason you're defining a FCall method is to call a native method, yo
If you still need to implement a feature inside the runtime, consider if there is a way to reduce the frequency of transitioning to native code. Can you write the common case in managed and only call into native for some rare corner cases? You're usually best off keeping as much as possible in managed code.
-QCalls are the preferred mechanism going forward. You should only use FCalls when you are "forced" to. This happens when there is common "short path" through the code that is important to optimize. This short path should not be more than a few hundred instructions, cannot allocate GC memory, take locks or throw exceptions (`GC_NOTRIGGER`, `NOTHROWS`). In all other circumstances (and especially when you enter a FCall and then simply erect HelperMethodFrame), you should be using QCall.
+QCalls are the preferred mechanism going forward. You should only use FCalls when you are "forced" to. This happens when there is common "short path" through the code that is important to optimize. This short path should not be more than a few hundred instructions, cannot allocate GC memory, take locks or throw exceptions (`GC_NOTRIGGER`, `NOTHROWS`). In all other circumstances, you should be using QCall.
FCalls were specifically designed for short paths of code that must be optimized. They allowed explicit control over when erecting a frame was done. However, it is error prone and not worth the complexity for many APIs. QCalls are essentially P/Invokes into the CLR. In the event the performance of an FCall is required consider creating a QCall and marking it with [`SuppressGCTransitionAttribute`](https://learn.microsoft.com/dotnet/api/system.runtime.interopservices.suppressgctransitionattribute).
@@ -64,8 +62,6 @@ As a result, QCalls give you some advantageous marshaling for `SafeHandle`s auto
QCalls are very much like a normal P/Invoke from CoreLib to CLR. Unlike FCalls, QCalls will marshal all arguments as unmanaged types like a normal P/Invoke. QCall also switch to preemptive GC mode like a normal P/Invoke. These two features should make QCalls easier to write reliably compared to FCalls. QCalls are not prone to GC holes and GC starvation bugs that are common with FCalls.
-QCalls perform better than FCalls that erect a `HelperMethodFrame`. The overhead is about 1.4x less compared to FCall w/ `HelperMethodFrame` overhead on x86 and x64.
-
The preferred types for QCall arguments are primitive types that are efficiently handled by the P/Invoke marshaler (`INT32`, `LPCWSTR`, `BOOL`). Notice that `BOOL` is the correct boolean flavor for QCall arguments. On the other hand, `CLR_BOOL` is the correct boolean flavor for FCall arguments.
The pointers to common unmanaged EE structures should be wrapped into handle types. This is to make the managed implementation type safe and avoid falling into unsafe C# everywhere. See AssemblyHandle in [vm\qcall.h][qcall] for an example.
@@ -164,7 +160,7 @@ extern "C" BOOL QCALLTYPE Foo_BarInternal(int flags, LPCWSTR wszString, QCall::S
## FCall functional behavior
-FCalls allow more flexibility in terms of passing object references around, but with higher code complexity and more opportunities to make mistakes. Additionally, FCall methods must either erect a helper method frame along their common code paths, or for any FCall of non-trivial length, explicitly poll for whether a garbage collection must occur. Failing to do so will lead to starvation issues if managed code repeatedly calls the FCall method in a tight loop, because FCalls execute while the thread only allows the GC to run in a cooperative manner.
+FCalls allow more flexibility in terms of passing object references around, but with higher code complexity and more opportunities to make mistakes. Additionally, for any FCall of non-trivial length, explicitly poll for whether a garbage collection must occur. Failing to do so will lead to starvation issues if managed code repeatedly calls the FCall method in a tight loop, because FCalls execute while the thread only allows the GC to run in a cooperative manner.
FCalls require a lot of boilerplate code, too much to describe here. Refer to [fcall.h][fcall] for details.
@@ -176,8 +172,6 @@ A more complete discussion on GC holes can be found in the [CLR Code Guide](../.
Object references passed as parameters to FCall methods are not GC-protected, meaning that if a GC occurs, those references will point to the old location in memory of an object, not the new location. For this reason, FCalls usually follow the discipline of accepting something like `StringObject*` as their parameter type, then explicitly converting that to a `STRINGREF` before doing operations that may trigger a GC. If you expect to use an object reference later, you must GC protect object references before triggering a GC.
-All GC heap allocations within an FCall method must happen within a helper method frame. If you allocate memory on the GC heap, the GC may collect dead objects and move objects around in unpredictable ways, with some low probability. For this reason, you must manually report any object references in your method to the GC, so that if a garbage collection occurs, your object reference will be updated to refer to the new location in memory. Any pointers into managed objects (like arrays or Strings) within your code will not be updated automatically, and must be re-fetched after any operation that may allocate memory and before your first usage. Reporting a reference can be done via the `GCPROTECT_*` macros or as parameters when erecting a helper method frame.
-
Failing to properly report an `OBJECTREF` or to update an interior pointer is commonly referred to as a "GC hole", because the `OBJECTREF` class will do some validation that it points to a valid object every time you dereference it in Debug and Checked builds. When an `OBJECTREF` pointing to an invalid object is dereferenced, an assert will trigger saying something like "Detected an invalid object reference. Possible GC hole?". This assert is unfortunately easy to hit when writing "manually managed" code.
Note that QCall's programming model is restrictive to sidestep GC holes by forcing you to pass in the address of an object reference on the stack. This guarantees that the object reference is GC protected by the JIT's reporting logic, and that the actual object reference will not move because it is not allocated in the GC heap. QCall is our recommended approach, precisely because it makes GC holes harder to write.
@@ -188,8 +182,6 @@ The managed stack walker needs to be able to find its way from FCalls. It is rel
Complex constructs like stack allocated objects with destructors or exception handling in the FCall implementation may confuse the epilog walker. This can lead to GC holes or crashes during stack walking. There is no comprehensive list of what constructs should be avoided to prevent this class of bugs. An FCall implementation that is fine one day may break with the next C++ compiler update. We depend on stress runs and code coverage to find bugs in this area.
-Setting a breakpoint inside an FCall implementation may confuse the epilog walker. It leads to an "Invalid breakpoint in a helpermethod frame epilog" assert inside [vm\i386\gmsx86.cpp](https://github.com/dotnet/runtime/blob/main/src/coreclr/vm/i386/gmsx86.cpp).
-
### FCall example – managed
Here's a real-world example from the `String` class:
@@ -218,29 +210,18 @@ The FCall entrypoint has to be registered in tables in [vm\ecalllist.h][ecalllis
[ecalllist]: https://github.com/dotnet/runtime/blob/main/src/coreclr/vm/ecalllist.h
-This method is an instance method in managed code, with the "this" parameter passed as the first argument. We use `StringObject*` as the argument type, then copy it into a `STRINGREF` so we get some error checking when we use it.
+This example shows an FCall method that takes a managed object (`Object*`) as a raw pointer. These raw inputs are considered "unsafe" and must be validated or converted if they’re used in a GC-sensitive context.
```C++
-FCIMPL1(Object*, AppDomainNative::IsStringInterned, StringObject* pStringUNSAFE)
+FCIMPL1(FC_BOOL_RET, ExceptionNative::IsImmutableAgileException, Object* pExceptionUNSAFE)
{
FCALL_CONTRACT;
- STRINGREF refString = ObjectToSTRINGREF(pStringUNSAFE);
- STRINGREF* prefRetVal = NULL;
-
- HELPER_METHOD_FRAME_BEGIN_RET_1(refString);
-
- if (refString == NULL)
- COMPlusThrow(kArgumentNullException, W("ArgumentNull_String"));
-
- prefRetVal = GetAppDomain()->IsStringInterned(&refString);
-
- HELPER_METHOD_FRAME_END();
+ ASSERT(pExceptionUNSAFE != NULL);
- if (prefRetVal == NULL)
- return NULL;
+ OBJECTREF pException = (OBJECTREF) pExceptionUNSAFE;
- return OBJECTREFToObject(*prefRetVal);
+ FC_RETURN_BOOL(CLRException::IsPreallocatedExceptionObject(pException));
}
FCIMPLEND
```
diff --git a/docs/design/coreclr/botr/exceptions.md b/docs/design/coreclr/botr/exceptions.md
index 1fc3029df64caf..835ca9f0e03606 100644
--- a/docs/design/coreclr/botr/exceptions.md
+++ b/docs/design/coreclr/botr/exceptions.md
@@ -255,9 +255,9 @@ This is the "fcall", "jit helper", and so forth. The typical way that the runtim
On the other hand, if an fcall function can do anything that might throw a CLR internal exception (one of the C++ exceptions), that exception must not be allowed to leak back out to managed code. To handle this case, the CLR has the UnwindAndContinueHandler (UACH), which is a set of code to catch the C++ EH exceptions, and re-raise them as managed exceptions.
-Any runtime function that is called from managed code, and might throw a C++ EH exception, must wrap the throwing code in INSTALL_UNWIND_AND_CONTINUE_HANDLER / UNINSTALL_UNWIND_AND_CONTINUE_HANDLER. Installing a HELPER_METHOD_FRAME will automatically install the UACH. There is a non-trivial amount of overhead to installing a UACH, so they shouldn't be used everywhere. One technique that is used in performance critical code is to run without a UACH, and install one just before throwing an exception.
+Any runtime function that is called from managed code, and might throw a C++ EH exception, must wrap the throwing code in INSTALL_UNWIND_AND_CONTINUE_HANDLER / UNINSTALL_UNWIND_AND_CONTINUE_HANDLER. There is a non-trivial amount of overhead to installing a UACH, so they shouldn't be used everywhere. One technique that is used in performance critical code is to run without a UACH, and install one just before throwing an exception.
-When a C++ exception is thrown, and there is a missing UACH, the typical failure will be a Contract Violation of "GC_TRIGGERS called in a GC_NOTRIGGER region" in CPFH_RealFirstPassHandler. To fix these, look for managed to runtime transitions, and check for INSTALL_UNWIND_AND_CONTINUE_HANDLER or HELPER_METHOD_FRAME_BEGIN_XXX.
+When a C++ exception is thrown, and there is a missing UACH, the typical failure will be a Contract Violation of "GC_TRIGGERS called in a GC_NOTRIGGER region" in CPFH_RealFirstPassHandler. To fix these, look for managed to runtime transitions, and check for INSTALL_UNWIND_AND_CONTINUE_HANDLER.
Runtime code into managed code
------------------------------
diff --git a/docs/design/coreclr/botr/guide-for-porting.md b/docs/design/coreclr/botr/guide-for-porting.md
index 15b4e4c65d32c0..500d95394266a0 100644
--- a/docs/design/coreclr/botr/guide-for-porting.md
+++ b/docs/design/coreclr/botr/guide-for-porting.md
@@ -340,27 +340,22 @@ Here is an annotated list of the stubs implemented for Unix on Arm64.
calls. Necessary for all applications as this is how the main method is
called.
- 2. `LazyMachStateCaptureState`/`HelperMethodFrameRestoreState` – Needed to
- support a GC occurring with an FCALL or HCALL on the stack. (Incorrect
- implementations will cause unpredictable crashes during or after garbage
- collection)
-
- 3. `NDirectImportThunk` – Needed to support saving off a set of arguments to
+ 2. `NDirectImportThunk` – Needed to support saving off a set of arguments to
a p/invoke so that the runtime can find the actual target. Also uses one
of the secret arguments (Used by all p/invoke methods)
- 4. `PrecodeFixupThunk` – Needed to convert the secret argument from a
+ 3. `PrecodeFixupThunk` – Needed to convert the secret argument from a
FixupPrecode\* to a MethodDesc\*. This function exists to reduce the
code size of FixupPrecodes as there are (Used by many managed methods)
- 5. `ThePreStub` - Needed to support saving off a set of arguments to the
+ 4. `ThePreStub` - Needed to support saving off a set of arguments to the
stack so that the runtime can find or jit the right target method.
(Needed for any jitted method to execute Used by all managed methods)
- 6. `ThePreStubPatch` – Exists to provide a reliable spot for the managed
+ 5. `ThePreStubPatch` – Exists to provide a reliable spot for the managed
debugger to put a breakpoint.
- 7. GC Write Barriers – These are used to provide the GC with information
+ 6. GC Write Barriers – These are used to provide the GC with information
about what memory is being updated. The existing implementations of
these are all complex, and there are a number of controls where the
runtime can adjust to tweak the behavior of the barrier in various ways.
@@ -373,40 +368,40 @@ Here is an annotated list of the stubs implemented for Unix on Arm64.
FEATURE_USE_SOFTWARE_WRITE_WATCH_FOR_GC_HEAP can be implemented as
performance needs require.
- 8. `ComCallPreStub`/ `COMToCLRDispatchHelper` /`GenericComCallStub` - not
+ 7. `ComCallPreStub`/ `COMToCLRDispatchHelper` /`GenericComCallStub` - not
necessary for non-Windows platforms at this time
- 9. `TheUMEntryPrestub`/ `UMThunkStub` - used to enter the runtime from
+ 8. `TheUMEntryPrestub`/ `UMThunkStub` - used to enter the runtime from
non-managed code through entrypoints generated from the
Marshal.GetFunctionPointerForDelegate api.
- 10. `OnHijackTripThread` - needed for thread suspension to support GC + other
+ 9. `OnHijackTripThread` - needed for thread suspension to support GC + other
suspension requiring events. This is typically not needed for very early
stage bringup of the product, but will be needed for any decent size
application
- 11. `CallEHFunclet` – Used to call catch, finally and fault funclets. Behavior
+ 10. `CallEHFunclet` – Used to call catch, finally and fault funclets. Behavior
is specific to exactly how funclets are implemented.
- 12. `CallEHFilterFunclet` – Used to call filter funclets. Behavior is specific
+ 11. `CallEHFilterFunclet` – Used to call filter funclets. Behavior is specific
to exactly how funclets are implemented.
- 13. `ResolveWorkerChainLookupAsmStub`/ `ResolveWorkerAsmStub` Used for virtual
+ 12. `ResolveWorkerChainLookupAsmStub`/ `ResolveWorkerAsmStub` Used for virtual
stub dispatch (virtual call support for interface, and some virtual
methods). These work in tandem with the logic in virtualcallstubcpu.h to
implement the logic described in [Virtual Stub Dispatch](virtual-stub-dispatch.md)
- 14. `ProfileEnter`/ `ProfileLeave`/ `ProfileTailcall` – Used to call function
+ 13. `ProfileEnter`/ `ProfileLeave`/ `ProfileTailcall` – Used to call function
entry/exit profile functions acquired through the ICorProfiler
interface. Used in VERY rare circumstances. It is reasonable to wait to
implement these until the final stages of productization. Most profilers
do not use this functionality.
- 15. `JIT_PInvokeBegin`/`JIT_PInvokeEnd` – Leave/enter the managed runtime state. Necessary
+ 14. `JIT_PInvokeBegin`/`JIT_PInvokeEnd` – Leave/enter the managed runtime state. Necessary
for ReadyToRun pre-compiled pinvoke calls, so that they do not cause GC
starvation
- 16. `VarargPInvokeStub`/ `GenericPInvokeCalliHelper` Used to support calli
+ 15. `VarargPInvokeStub`/ `GenericPInvokeCalliHelper` Used to support calli
pinvokes. It is expected that C\# 8.0 will increase use of this feature.
Today use of this feature on Unix requires hand-written IL. On Windows
this feature is commonly used by C++/CLI
diff --git a/docs/design/datacontracts/StackWalk.md b/docs/design/datacontracts/StackWalk.md
index e30cc0a013302e..143a2f89435f56 100644
--- a/docs/design/datacontracts/StackWalk.md
+++ b/docs/design/datacontracts/StackWalk.md
@@ -293,10 +293,6 @@ HijackFrames carry a IP (ReturnAddress) and a pointer to `HijackArgs`. All platf
TailCallFrames are only used on Windows x86 which is not yet supported in the cDAC and therefore not implemented.
-#### HelperMethodFrame
-
-HelperMethodFrames are on the way to being removed. They are not currently supported in the cDAC.
-
### APIs
The majority of the contract's complexity is the stack walking algorithm (detailed above) implemented as part of `CreateStackWalk`.
diff --git a/src/coreclr/debug/daccess/dacdbiimpl.cpp b/src/coreclr/debug/daccess/dacdbiimpl.cpp
index 16abe8d2826d1b..05f2f7f7ca3cfc 100644
--- a/src/coreclr/debug/daccess/dacdbiimpl.cpp
+++ b/src/coreclr/debug/daccess/dacdbiimpl.cpp
@@ -1,15 +1,12 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
+
//*****************************************************************************
// File: DacDbiImpl.cpp
-//
-
//
// Implement DAC/DBI interface
-//
//*****************************************************************************
-
#include "stdafx.h"
#include "dacdbiinterface.h"
@@ -5640,7 +5637,7 @@ void DacDbiInterfaceImpl::GetContext(VMPTR_Thread vmThread, DT_CONTEXT * pContex
// Going through thread Frames and looking for first (deepest one) one that
// that has context available for stackwalking (SP and PC)
- // For example: RedirectedThreadFrame, InlinedCallFrame, HelperMethodFrame, CLRToCOMMethodFrame
+ // For example: RedirectedThreadFrame, InlinedCallFrame, DynamicHelperFrame, CLRToCOMMethodFrame
Frame *frame = pThread->GetFrame();
while (frame != NULL && frame != FRAME_TOP)
{
diff --git a/src/coreclr/debug/di/shimremotedatatarget.cpp b/src/coreclr/debug/di/shimremotedatatarget.cpp
index 674d325560ff52..72c46f594c73de 100644
--- a/src/coreclr/debug/di/shimremotedatatarget.cpp
+++ b/src/coreclr/debug/di/shimremotedatatarget.cpp
@@ -371,5 +371,5 @@ ShimRemoteDataTarget::ContinueStatusChanged(
HRESULT STDMETHODCALLTYPE
ShimRemoteDataTarget::VirtualUnwind(DWORD threadId, ULONG32 contextSize, PBYTE context)
{
- return m_pTransport->VirtualUnwind(threadId, contextSize, context);
+ return E_NOTIMPL;
}
diff --git a/src/coreclr/debug/ee/controller.cpp b/src/coreclr/debug/ee/controller.cpp
index fc5204bb3cffea..4927e96b7b399c 100644
--- a/src/coreclr/debug/ee/controller.cpp
+++ b/src/coreclr/debug/ee/controller.cpp
@@ -6625,8 +6625,7 @@ void DebuggerStepper::TrapStepOut(ControllerStackInfo *info, bool fForceTraditio
m_reason = STEP_EXIT;
break;
}
- else if (info->m_activeFrame.frame->GetFrameType() == Frame::TYPE_SECURITY &&
- info->m_activeFrame.frame->GetInterception() == Frame::INTERCEPTION_NONE)
+ else if (info->m_activeFrame.frame->GetInterception() == Frame::INTERCEPTION_NONE)
{
// If we're stepping out of something that was protected by (declarative) security,
// the security subsystem may leave a frame on the stack to cache it's computation.
@@ -8706,24 +8705,20 @@ void DebuggerUserBreakpoint::HandleDebugBreak(Thread * pThread)
}
}
-
DebuggerUserBreakpoint::DebuggerUserBreakpoint(Thread *thread)
: DebuggerStepper(thread, (CorDebugUnmappedStop) (STOP_ALL & ~STOP_UNMANAGED), INTERCEPT_ALL, NULL)
{
// Setup a step out from the current frame (which we know is
// unmanaged, actually...)
-
- // This happens to be safe, but it's a very special case (so we have a special case ticket)
- // This is called while we're live (so no filter context) and from the fcall,
- // and we pushed a HelperMethodFrame to protect us. We also happen to know that we have
- // done anything illegal or dangerous since then.
+ // Initiate a step-out from Debug.Break() if the current frame allows it.
+ // This is now safe because the entry point uses QCall or dynamic transition,
+ // so no special frame setup is required.
StackTraceTicket ticket(this);
StepOut(LEAF_MOST_FRAME, ticket);
}
-
// Is this frame interesting?
// Use this to skip all code in the namespace "Debugger.Diagnostics"
bool DebuggerUserBreakpoint::IsInterestingFrame(FrameInfo * pFrame)
diff --git a/src/coreclr/debug/ee/frameinfo.cpp b/src/coreclr/debug/ee/frameinfo.cpp
index bd4866eaa96661..f4d88f7a462f5e 100644
--- a/src/coreclr/debug/ee/frameinfo.cpp
+++ b/src/coreclr/debug/ee/frameinfo.cpp
@@ -1671,7 +1671,6 @@ StackWalkAction DebuggerWalkStackProc(CrawlFrame *pCF, void *data)
{
case Frame::TYPE_ENTRY: // We now ignore entry + exit frames.
case Frame::TYPE_EXIT:
- case Frame::TYPE_HELPER_METHOD_FRAME:
case Frame::TYPE_INTERNAL:
/* If we have a specific interception type, use it. However, if this
@@ -1694,8 +1693,7 @@ StackWalkAction DebuggerWalkStackProc(CrawlFrame *pCF, void *data)
break;
case Frame::TYPE_INTERCEPTION:
- case Frame::TYPE_SECURITY: // Security is a sub-type of interception
- LOG((LF_CORDB, LL_INFO100000, "DWSP: Frame type is TYPE_INTERCEPTION/TYPE_SECURITY.\n"));
+ LOG((LF_CORDB, LL_INFO100000, "DWSP: Frame type is TYPE_INTERCEPTION.\n"));
d->info.managed = true;
d->info.internal = true;
use = true;
@@ -1703,22 +1701,14 @@ StackWalkAction DebuggerWalkStackProc(CrawlFrame *pCF, void *data)
case Frame::TYPE_CALL:
LOG((LF_CORDB, LL_INFO100000, "DWSP: Frame type is TYPE_CALL.\n"));
- // In V4, StubDispatchFrame is only used on 64-bit (and PPC?) but not on x86. x86 uses a
- // different code path which sets up a HelperMethodFrame instead. In V4.5, x86 and ARM
- // both use the 64-bit code path and they set up a StubDispatchFrame as well. This causes
- // a problem in the debugger stackwalker (see Dev11 Issue 13229) since the two frame types
- // are treated differently. More specifically, a StubDispatchFrame causes the debugger
- // stackwalk to make an invalid callback, i.e. a callback which is not for a managed method,
- // an explicit frame, or a chain.
+
+ // StubDispatchFrame is used during virtual stub dispatch and appears temporarily on the stack
+ // across architectures like x64, x86, and ARM. It exists for a short duration while dispatching
+ // a virtual call through a stub, making its presence rare during a typical debugger stack walk.
//
- // Ideally we would just change the StubDispatchFrame to behave like a HMF, but it's
- // too big of a change for an in-place release. For now I'm just making surgical fixes in
- // the debugger stackwalker. This may introduce behavioural changes in on X64, but the
- // chance of that is really small. StubDispatchFrame is only used in the virtual stub
- // disptch code path. It stays on the stack in a small time window and it's not likely to
- // be on the stack while some managed methods closer to the leaf are on the stack. There is
- // only one scenario I know of, and that's the repro for Dev11 13229, but that's for x86 only.
- // The jitted code on X64 behaves differently.
+ // In the debugger, we avoid treating StubDispatchFrame as a managed or inspectable frame.
+ // It doesn't represent a managed method, explicit frame, or chain, and attempting to interpret
+ // it as such may lead to invalid callbacks or incorrect debugger behavior.
//
// Note that there is a corresponding change in DacDbiInterfaceImpl::GetInternalFrameType().
if (frame->GetFrameIdentifier() == FrameIdentifier::StubDispatchFrame)
diff --git a/src/coreclr/debug/inc/dbgtransportsession.h b/src/coreclr/debug/inc/dbgtransportsession.h
index 28f677fdabe014..3bc9521e9c5251 100644
--- a/src/coreclr/debug/inc/dbgtransportsession.h
+++ b/src/coreclr/debug/inc/dbgtransportsession.h
@@ -421,7 +421,6 @@ class DbgTransportSession
// Read and write memory on the LS from the RS.
HRESULT ReadMemory(PBYTE pbRemoteAddress, PBYTE pbBuffer, SIZE_T cbBuffer);
HRESULT WriteMemory(PBYTE pbRemoteAddress, PBYTE pbBuffer, SIZE_T cbBuffer);
- HRESULT VirtualUnwind(DWORD threadId, ULONG32 contextSize, PBYTE context);
// Read and write the debugger control block on the LS from the RS.
HRESULT GetDCB(DebuggerIPCControlBlock *pDCB);
@@ -468,7 +467,6 @@ class DbgTransportSession
// Misc management operations.
MT_ReadMemory, // RS <-> LS : RS wants to read LS memory block (or LS is replying to such a request)
MT_WriteMemory, // RS <-> LS : RS wants to write LS memory block (or LS is replying to such a request)
- MT_VirtualUnwind, // RS <-> LS : RS wants to LS unwind a stack frame (or LS is replying to such a request)
MT_GetDCB, // RS <-> LS : RS wants to read LS DCB (or LS is replying to such a request)
MT_SetDCB, // RS <-> LS : RS wants to write LS DCB (or LS is replying to such a request)
MT_GetAppDomainCB, // RS <-> LS : RS wants to read LS AppDomainCB (or LS is replying to such a request)
@@ -589,7 +587,6 @@ class DbgTransportSession
LONG m_cSentEvent;
LONG m_cSentReadMemory;
LONG m_cSentWriteMemory;
- LONG m_cSentVirtualUnwind;
LONG m_cSentGetDCB;
LONG m_cSentSetDCB;
LONG m_cSentGetAppDomainCB;
@@ -604,7 +601,6 @@ class DbgTransportSession
LONG m_cReceivedEvent;
LONG m_cReceivedReadMemory;
LONG m_cReceivedWriteMemory;
- LONG m_cReceivedVirtualUnwind;
LONG m_cReceivedGetDCB;
LONG m_cReceivedSetDCB;
LONG m_cReceivedGetAppDomainCB;
diff --git a/src/coreclr/debug/shared/dbgtransportsession.cpp b/src/coreclr/debug/shared/dbgtransportsession.cpp
index 010cb3fa38bb04..f2547ffc8aefcf 100644
--- a/src/coreclr/debug/shared/dbgtransportsession.cpp
+++ b/src/coreclr/debug/shared/dbgtransportsession.cpp
@@ -526,16 +526,6 @@ HRESULT DbgTransportSession::WriteMemory(PBYTE pbRemoteAddress, PBYTE pbBuffer,
return sMessage.m_sHeader.TypeSpecificData.MemoryAccess.m_hrResult;
}
-HRESULT DbgTransportSession::VirtualUnwind(DWORD threadId, ULONG32 contextSize, PBYTE context)
-{
- DbgTransportLog(LC_Requests, "Sending 'VirtualUnwind'");
- DBG_TRANSPORT_INC_STAT(SentVirtualUnwind);
-
- Message sMessage;
- sMessage.Init(MT_VirtualUnwind, context, contextSize, context, contextSize);
- return SendRequestMessageAndWait(&sMessage);
-}
-
// Read and write the debugger control block on the LS from the RS.
HRESULT DbgTransportSession::GetDCB(DebuggerIPCControlBlock *pDCB)
{
@@ -957,7 +947,6 @@ void DbgTransportSession::FlushSendQueue(DWORD dwLastProcessedId)
MessageType eType = pMsg->m_sHeader.m_eType;
if (eType != MT_ReadMemory &&
eType != MT_WriteMemory &&
- eType != MT_VirtualUnwind &&
eType != MT_GetDCB &&
eType != MT_SetDCB &&
eType != MT_GetAppDomainCB)
@@ -1953,33 +1942,6 @@ void DbgTransportSession::TransportWorker()
#endif // RIGHT_SIDE_COMPILE
break;
- case MT_VirtualUnwind:
-#ifdef RIGHT_SIDE_COMPILE
- if (!ProcessReply(&sReceiveHeader))
- HANDLE_TRANSIENT_ERROR();
-#else // RIGHT_SIDE_COMPILE
- if (sReceiveHeader.m_cbDataBlock != (DWORD)sizeof(frameContext))
- {
- _ASSERTE(!"Inconsistent VirtualUnwind request");
- HANDLE_CRITICAL_ERROR();
- }
-
- if (!ReceiveBlock((PBYTE)&frameContext, sizeof(frameContext)))
- {
- HANDLE_TRANSIENT_ERROR();
- }
-
- if (!PAL_VirtualUnwind(&frameContext, NULL))
- {
- HANDLE_TRANSIENT_ERROR();
- }
-
- fReplyRequired = true;
- pbOptReplyData = (PBYTE)&frameContext;
- cbOptReplyData = sizeof(frameContext);
-#endif // RIGHT_SIDE_COMPILE
- break;
-
case MT_GetDCB:
#ifdef RIGHT_SIDE_COMPILE
if (!ProcessReply(&sReceiveHeader))
@@ -2125,7 +2087,6 @@ void DbgTransportSession::TransportWorker()
#ifdef RIGHT_SIDE_COMPILE
case MT_ReadMemory:
case MT_WriteMemory:
- case MT_VirtualUnwind:
case MT_GetDCB:
case MT_SetDCB:
case MT_GetAppDomainCB:
@@ -2135,7 +2096,6 @@ void DbgTransportSession::TransportWorker()
#else // RIGHT_SIDE_COMPILE
case MT_ReadMemory:
case MT_WriteMemory:
- case MT_VirtualUnwind:
case MT_GetDCB:
case MT_SetDCB:
case MT_GetAppDomainCB:
@@ -2537,8 +2497,6 @@ const char *DbgTransportSession::MessageName(MessageType eType)
return "ReadMemory";
case MT_WriteMemory:
return "WriteMemory";
- case MT_VirtualUnwind:
- return "VirtualUnwind";
case MT_GetDCB:
return "GetDCB";
case MT_SetDCB:
@@ -2595,10 +2553,6 @@ void DbgTransportSession::DbgTransportLogMessageReceived(MessageHeader *pHeader)
(DWORD)pHeader->TypeSpecificData.MemoryAccess.m_cbLeftSideBuffer);
DBG_TRANSPORT_INC_STAT(ReceivedWriteMemory);
return;
- case MT_VirtualUnwind:
- DbgTransportLog(LC_Requests, "Received 'VirtualUnwind' reply");
- DBG_TRANSPORT_INC_STAT(ReceivedVirtualUnwind);
- return;
case MT_GetDCB:
DbgTransportLog(LC_Requests, "Received 'GetDCB' reply");
DBG_TRANSPORT_INC_STAT(ReceivedGetDCB);
@@ -2624,10 +2578,6 @@ void DbgTransportSession::DbgTransportLogMessageReceived(MessageHeader *pHeader)
(DWORD)pHeader->TypeSpecificData.MemoryAccess.m_cbLeftSideBuffer);
DBG_TRANSPORT_INC_STAT(ReceivedWriteMemory);
return;
- case MT_VirtualUnwind:
- DbgTransportLog(LC_Requests, "Received 'VirtualUnwind'");
- DBG_TRANSPORT_INC_STAT(ReceivedVirtualUnwind);
- return;
case MT_GetDCB:
DbgTransportLog(LC_Requests, "Received 'GetDCB'");
DBG_TRANSPORT_INC_STAT(ReceivedGetDCB);
diff --git a/src/coreclr/inc/debugreturn.h b/src/coreclr/inc/debugreturn.h
index 86b606efdfb596..93bd5b6c8078b6 100644
--- a/src/coreclr/inc/debugreturn.h
+++ b/src/coreclr/inc/debugreturn.h
@@ -54,7 +54,6 @@ class __YouCannotUseAReturnStatementHere {
// If you got here, and you're wondering what you did wrong -- you're using
// a return statement where it's not allowed. Likely, it's inside one of:
// GCPROTECT_BEGIN ... GCPROTECT_END
- // HELPER_METHOD_FRAME_BEGIN ... HELPER_METHOD_FRAME_END
//
static int safe_to_return() {return 0;};
public:
diff --git a/src/coreclr/inc/stacktrace.h b/src/coreclr/inc/stacktrace.h
index b843eee74baf00..0df8da9d907d95 100644
--- a/src/coreclr/inc/stacktrace.h
+++ b/src/coreclr/inc/stacktrace.h
@@ -63,16 +63,6 @@ void MagicDeinit(void);
******************************************************************** robch */
void GetStringFromStackLevels(UINT ifrStart, UINT cfrTotal, _Out_writes_(cchMaxAssertStackLevelStringLen * cfrTotal) CHAR *pszString, struct _CONTEXT * pContext = NULL);
-/****************************************************************************
-* GetStringFromAddr *
-*-------------------*
-* Description:
-* Builds a string from an address in the format:
-*
-* 0x
: ! + 0x
-******************************************************************** robch */
-void GetStringFromAddr(DWORD_PTR dwAddr, _Out_writes_(cchMaxAssertStackLevelStringLen) LPSTR szString);
-
#if defined(HOST_X86) && !defined(TARGET_UNIX)
/****************************************************************************
* ClrCaptureContext *
diff --git a/src/coreclr/utilcode/stacktrace.cpp b/src/coreclr/utilcode/stacktrace.cpp
index 33bf7ed41a694a..323e1a90425d58 100644
--- a/src/coreclr/utilcode/stacktrace.cpp
+++ b/src/coreclr/utilcode/stacktrace.cpp
@@ -1,8 +1,5 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
-//-----------------------------------------------------------------------------
-
-//-----------------------------------------------------------------------------
#include "stdafx.h"
@@ -896,36 +893,6 @@ CONTEXT * pContext // @parm Context to start the stack trace at; null for curre
}
#endif // !defined(DACCESS_COMPILE)
-/****************************************************************************
-* GetStringFromAddr *
-*-------------------*
-* Description:
-* Returns a string from an address.
-****************************************************************************/
-void GetStringFromAddr
-(
-DWORD_PTR dwAddr,
-_Out_writes_(cchMaxAssertStackLevelStringLen) LPSTR szString // Place to put string.
- // Buffer must hold at least cchMaxAssertStackLevelStringLen.
-)
-{
- STATIC_CONTRACT_NOTHROW;
- STATIC_CONTRACT_GC_NOTRIGGER;
-
- LOCAL_ASSERT(szString);
-
- SYM_INFO si;
- FillSymbolInfo(&si, dwAddr);
-
- sprintf_s(szString,
- cchMaxAssertStackLevelStringLen,
- "%s! %s + 0x%p (0x%p)",
- (si.achModule[0]) ? si.achModule : "",
- (si.achSymbol[0]) ? si.achSymbol : "",
- (void*)si.dwOffset,
- (void*)dwAddr);
-}
-
/****************************************************************************
* MagicDeinit *
*-------------*
diff --git a/src/coreclr/vm/CMakeLists.txt b/src/coreclr/vm/CMakeLists.txt
index e2799dcdb48d1e..b9a272765a8090 100644
--- a/src/coreclr/vm/CMakeLists.txt
+++ b/src/coreclr/vm/CMakeLists.txt
@@ -674,7 +674,6 @@ elseif(CLR_CMAKE_TARGET_ARCH_I386)
${ARCH_SOURCES_DIR}/AllocSlow.asm
${ARCH_SOURCES_DIR}/asmhelpers.asm
${ARCH_SOURCES_DIR}/ehhelpers.asm
- ${ARCH_SOURCES_DIR}/gmsasm.asm
${ARCH_SOURCES_DIR}/jithelp.asm
${ARCH_SOURCES_DIR}/PInvokeStubs.asm
${ARCH_SOURCES_DIR}/thunktemplates.asm
@@ -740,7 +739,6 @@ else(CLR_CMAKE_TARGET_WIN32)
${ARCH_SOURCES_DIR}/ehhelpers.S
${ARCH_SOURCES_DIR}/asmhelpers.S
${ARCH_SOURCES_DIR}/jithelp.S
- ${ARCH_SOURCES_DIR}/gmsasm.S
${ARCH_SOURCES_DIR}/pinvokestubs.S
${ARCH_SOURCES_DIR}/umthunkstub.S
${ARCH_SOURCES_DIR}/thunktemplates.S
@@ -801,7 +799,6 @@ if(CLR_CMAKE_TARGET_ARCH_AMD64)
set(VM_SOURCES_DAC_AND_WKS_ARCH
${ARCH_SOURCES_DIR}/cgenamd64.cpp
${ARCH_SOURCES_DIR}/excepamd64.cpp
- ${ARCH_SOURCES_DIR}/gmsamd64.cpp
${ARCH_SOURCES_DIR}/stublinkeramd64.cpp
)
@@ -809,7 +806,6 @@ if(CLR_CMAKE_TARGET_ARCH_AMD64)
${ARCH_SOURCES_DIR}/asmconstants.h
${ARCH_SOURCES_DIR}/cgencpu.h
${ARCH_SOURCES_DIR}/excepcpu.h
- ${ARCH_SOURCES_DIR}/gmscpu.h
${ARCH_SOURCES_DIR}/stublinkeramd64.h
)
@@ -827,14 +823,12 @@ elseif(CLR_CMAKE_TARGET_ARCH_I386)
set(VM_SOURCES_DAC_AND_WKS_ARCH
${ARCH_SOURCES_DIR}/cgenx86.cpp
${ARCH_SOURCES_DIR}/excepx86.cpp
- ${ARCH_SOURCES_DIR}/gmsx86.cpp
${ARCH_SOURCES_DIR}/stublinkerx86.cpp
)
set(VM_HEADERS_DAC_AND_WKS_ARCH
${ARCH_SOURCES_DIR}/cgencpu.h
${ARCH_SOURCES_DIR}/excepcpu.h
- ${ARCH_SOURCES_DIR}/gmscpu.h
${ARCH_SOURCES_DIR}/stublinkerx86.h
)
diff --git a/src/coreclr/vm/FrameTypes.h b/src/coreclr/vm/FrameTypes.h
index b4ef6891a5d8f3..4033d882efd8b5 100644
--- a/src/coreclr/vm/FrameTypes.h
+++ b/src/coreclr/vm/FrameTypes.h
@@ -18,11 +18,6 @@ FRAME_TYPE_NAME(SoftwareExceptionFrame)
#ifdef DEBUGGING_SUPPORTED
FRAME_TYPE_NAME(FuncEvalFrame)
#endif // DEBUGGING_SUPPORTED
-FRAME_TYPE_NAME(HelperMethodFrame)
-FRAME_TYPE_NAME(HelperMethodFrame_1OBJ)
-FRAME_TYPE_NAME(HelperMethodFrame_2OBJ)
-FRAME_TYPE_NAME(HelperMethodFrame_3OBJ)
-FRAME_TYPE_NAME(HelperMethodFrame_PROTECTOBJ)
#ifdef FEATURE_COMINTEROP
FRAME_TYPE_NAME(ComMethodFrame)
FRAME_TYPE_NAME(CLRToCOMMethodFrame)
diff --git a/src/coreclr/vm/amd64/AsmHelpers.asm b/src/coreclr/vm/amd64/AsmHelpers.asm
index 23440f18b9cf36..f06d64ec1ef30f 100644
--- a/src/coreclr/vm/amd64/AsmHelpers.asm
+++ b/src/coreclr/vm/amd64/AsmHelpers.asm
@@ -18,60 +18,6 @@ endif
extern g_pPollGC:QWORD
extern g_TrapReturningThreads:DWORD
-; EXTERN_C int __fastcall HelperMethodFrameRestoreState(
-; INDEBUG_COMMA(HelperMethodFrame *pFrame)
-; MachState *pState
-; )
-LEAF_ENTRY HelperMethodFrameRestoreState, _TEXT
-
-ifdef _DEBUG
- mov rcx, rdx
-endif
-
- ; Check if the MachState is valid
- xor eax, eax
- cmp qword ptr [rcx + OFFSETOF__MachState___pRetAddr], rax
- jne @F
- REPRET
-@@:
-
- ;
- ; If a preserved register were pushed onto the stack between
- ; the managed caller and the H_M_F, m_pReg will point to its
- ; location on the stack and it would have been updated on the
- ; stack by the GC already and it will be popped back into the
- ; appropriate register when the appropriate epilog is run.
- ;
- ; Otherwise, the register is preserved across all the code
- ; in this HCALL or FCALL, so we need to update those registers
- ; here because the GC will have updated our copies in the
- ; frame.
- ;
- ; So, if m_pReg points into the MachState, we need to update
- ; the register here. That's what this macro does.
- ;
-RestoreReg macro reg, regnum
- lea rax, [rcx + OFFSETOF__MachState__m_Capture + 8 * regnum]
- mov rdx, [rcx + OFFSETOF__MachState__m_Ptrs + 8 * regnum]
- cmp rax, rdx
- cmove reg, [rax]
- endm
-
- ; regnum has to match ENUM_CALLEE_SAVED_REGISTERS macro
- RestoreReg Rdi, 0
- RestoreReg Rsi, 1
- RestoreReg Rbx, 2
- RestoreReg Rbp, 3
- RestoreReg R12, 4
- RestoreReg R13, 5
- RestoreReg R14, 6
- RestoreReg R15, 7
-
- xor eax, eax
- ret
-
-LEAF_END HelperMethodFrameRestoreState, _TEXT
-
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;; NDirectImportThunk
diff --git a/src/coreclr/vm/amd64/asmconstants.h b/src/coreclr/vm/amd64/asmconstants.h
index 299eb1af7c6229..845584ad7aefcd 100644
--- a/src/coreclr/vm/amd64/asmconstants.h
+++ b/src/coreclr/vm/amd64/asmconstants.h
@@ -163,7 +163,7 @@ ASMCONSTANTS_C_ASSERT(OFFSETOF__GenericDictionaryDynamicHelperStubData__HandleAr
#define OFFSETOF__InstantiatedMethodDesc__m_pPerInstInfo DBG_FRE(0x40, 0x18)
ASMCONSTANTS_C_ASSERT(OFFSETOF__InstantiatedMethodDesc__m_pPerInstInfo
== offsetof(InstantiatedMethodDesc, m_pPerInstInfo));
-
+
#define OFFSETOF__MethodTable__m_dwFlags 0x00
ASMCONSTANTS_C_ASSERT(OFFSETOF__MethodTable__m_dwFlags
@@ -244,54 +244,19 @@ ASMCONSTANTS_C_ASSERT(OFFSETOF__DynamicStaticsInfo__m_pNonGCStatics
ASMCONSTANTS_C_ASSERT(OFFSETOF__DynamicStaticsInfo__m_pGCStatics
== offsetof(DynamicStaticsInfo, m_pGCStatics));
-
-// MachState offsets (AMD64\gmscpu.h)
-
-#define OFFSETOF__MachState__m_Rip 0x00
-ASMCONSTANTS_C_ASSERT(OFFSETOF__MachState__m_Rip
- == offsetof(MachState, m_Rip));
-
-#define OFFSETOF__MachState__m_Rsp 0x08
-ASMCONSTANTS_C_ASSERT(OFFSETOF__MachState__m_Rsp
- == offsetof(MachState, m_Rsp));
-
-#define OFFSETOF__MachState__m_Capture 0x10
-ASMCONSTANTS_C_ASSERT(OFFSETOF__MachState__m_Capture
- == offsetof(MachState, m_Capture));
-
-#ifdef UNIX_AMD64_ABI
-#define OFFSETOF__MachState__m_Ptrs 0x40
-#define OFFSETOF__MachState___pRetAddr 0x70
-#define OFFSETOF__LazyMachState__m_CaptureRip 0xA8
-#define OFFSETOF__LazyMachState__m_CaptureRsp 0xB0
-#else
-#define OFFSETOF__MachState__m_Ptrs 0x50
-#define OFFSETOF__MachState___pRetAddr 0x90
-#define OFFSETOF__LazyMachState__m_CaptureRip 0x98
-#define OFFSETOF__LazyMachState__m_CaptureRsp 0xA0
-#endif
-ASMCONSTANTS_C_ASSERT(OFFSETOF__MachState__m_Ptrs
- == offsetof(MachState, m_Ptrs));
-ASMCONSTANTS_C_ASSERT(OFFSETOF__MachState___pRetAddr
- == offsetof(MachState, _pRetAddr));
-ASMCONSTANTS_C_ASSERT(OFFSETOF__LazyMachState__m_CaptureRip
- == offsetof(LazyMachState, m_CaptureRip));
-ASMCONSTANTS_C_ASSERT(OFFSETOF__LazyMachState__m_CaptureRsp
- == offsetof(LazyMachState, m_CaptureRsp));
-
#define OFFSETOF__VASigCookie__pNDirectILStub 0x8
ASMCONSTANTS_C_ASSERT(OFFSETOF__VASigCookie__pNDirectILStub
== offsetof(VASigCookie, pNDirectILStub));
#if defined(UNIX_AMD64_ABI) && !defined(HOST_WINDOWS)
// Expression is too complicated, is currently:
-// (8*6 + 4*2 + 2*6 + 4 + 8*6 + 8*16 + 8 +
-// /*XMM_SAVE_AREA32*/(2*2 + 1*2 + 2 + 4 + 2*2 + 4 + 2*2 + 4*2 + 16*8 + 16*16 + 1*96) + 26*16 + 8 + 8*5 +
-// /*XSTATE*/ + 8 + 8 +
-// /*XSTATE_AVX*/ 16*16 +
-// /*XSTATE_AVX512_KMASK*/ 8*8 +
-// /*XSTATE_AVX512_ZMM_H*/ 32*16 +
-// /*XSTATE_AVX512_ZMM*/ 64*16 +
+// (8*6 + 4*2 + 2*6 + 4 + 8*6 + 8*16 + 8 +
+// /*XMM_SAVE_AREA32*/(2*2 + 1*2 + 2 + 4 + 2*2 + 4 + 2*2 + 4*2 + 16*8 + 16*16 + 1*96) + 26*16 + 8 + 8*5 +
+// /*XSTATE*/ + 8 + 8 +
+// /*XSTATE_AVX*/ 16*16 +
+// /*XSTATE_AVX512_KMASK*/ 8*8 +
+// /*XSTATE_AVX512_ZMM_H*/ 32*16 +
+// /*XSTATE_AVX512_ZMM*/ 64*16 +
// /*XSTATE_APX*/ 8*16)
#define SIZEOF__CONTEXT (3232)
#else
diff --git a/src/coreclr/vm/amd64/cgenamd64.cpp b/src/coreclr/vm/amd64/cgenamd64.cpp
index a97b9439236080..7fa9d44d1baa6b 100644
--- a/src/coreclr/vm/amd64/cgenamd64.cpp
+++ b/src/coreclr/vm/amd64/cgenamd64.cpp
@@ -1,8 +1,7 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
-//
+
// Various helper routines for generating AMD64 assembly code.
-//
// Precompiled Header
@@ -142,93 +141,6 @@ void InlinedCallFrame::UpdateRegDisplay_Impl(const PREGDISPLAY pRD, bool updateF
LOG((LF_GCROOTS, LL_INFO100000, "STACKWALK InlinedCallFrame::UpdateRegDisplay_Impl(rip:%p, rsp:%p)\n", pRD->ControlPC, pRD->SP));
}
-void HelperMethodFrame::UpdateRegDisplay_Impl(const PREGDISPLAY pRD, bool updateFloats)
-{
- CONTRACTL
- {
- NOTHROW;
- GC_NOTRIGGER;
- MODE_ANY;
- PRECONDITION(m_MachState._pRetAddr == PTR_TADDR(&m_MachState.m_Rip));
- SUPPORTS_DAC;
- }
- CONTRACTL_END;
-
-#ifndef DACCESS_COMPILE
- if (updateFloats)
- {
- UpdateFloatingPointRegisters(pRD);
- _ASSERTE(pRD->pCurrentContext->Rip == m_MachState.m_Rip);
- }
-#endif // DACCESS_COMPILE
-
- pRD->IsCallerContextValid = FALSE;
- pRD->IsCallerSPValid = FALSE; // Don't add usage of this field. This is only temporary.
-
- //
- // Copy the saved state from the frame to the current context.
- //
-
- LOG((LF_GCROOTS, LL_INFO100000, "STACKWALK HelperMethodFrame::UpdateRegDisplay cached ip:%p, sp:%p\n", m_MachState.m_Rip, m_MachState.m_Rsp));
-
-#if defined(DACCESS_COMPILE)
- // For DAC, we may get here when the HMF is still uninitialized.
- // So we may need to unwind here.
- if (!m_MachState.isValid())
- {
- // This allocation throws on OOM.
- MachState* pUnwoundState = (MachState*)DacAllocHostOnlyInstance(sizeof(*pUnwoundState), true);
-
- EnsureInit(pUnwoundState);
-
- pRD->pCurrentContext->Rip = pRD->ControlPC = pUnwoundState->m_Rip;
- pRD->pCurrentContext->Rsp = pRD->SP = pUnwoundState->m_Rsp;
-
-#define CALLEE_SAVED_REGISTER(regname) pRD->pCurrentContext->regname = pUnwoundState->m_Capture.regname;
- ENUM_CALLEE_SAVED_REGISTERS();
-#undef CALLEE_SAVED_REGISTER
-
-#define CALLEE_SAVED_REGISTER(regname) pRD->pCurrentContextPointers->regname = &pRD->pCurrentContext->regname;
- ENUM_CALLEE_SAVED_REGISTERS();
-#undef CALLEE_SAVED_REGISTER
-
- ClearRegDisplayArgumentAndScratchRegisters(pRD);
-
- return;
- }
-#endif // DACCESS_COMPILE
-
- pRD->pCurrentContext->Rip = pRD->ControlPC = m_MachState.m_Rip;
- pRD->pCurrentContext->Rsp = pRD->SP = m_MachState.m_Rsp;
-
-#ifdef TARGET_UNIX
-
-#define CALLEE_SAVED_REGISTER(regname) pRD->pCurrentContext->regname = (m_MachState.m_Ptrs.p##regname != NULL) ? \
- *m_MachState.m_Ptrs.p##regname : m_MachState.m_Unwound.regname;
- ENUM_CALLEE_SAVED_REGISTERS();
-#undef CALLEE_SAVED_REGISTER
-
-#else // TARGET_UNIX
-
-#define CALLEE_SAVED_REGISTER(regname) pRD->pCurrentContext->regname = *m_MachState.m_Ptrs.p##regname;
- ENUM_CALLEE_SAVED_REGISTERS();
-#undef CALLEE_SAVED_REGISTER
-
-#endif // TARGET_UNIX
-
-#define CALLEE_SAVED_REGISTER(regname) pRD->pCurrentContextPointers->regname = (DWORD64 *)(TADDR *)m_MachState.m_Ptrs.p##regname;
- ENUM_CALLEE_SAVED_REGISTERS();
-#undef CALLEE_SAVED_REGISTER
-
- //
- // Clear all knowledge of scratch registers. We're skipping to any
- // arbitrary point on the stack, and frames aren't required to preserve or
- // keep track of these anyways.
- //
-
- ClearRegDisplayArgumentAndScratchRegisters(pRD);
-}
-
void FaultingExceptionFrame::UpdateRegDisplay_Impl(const PREGDISPLAY pRD, bool updateFloats)
{
LIMITED_METHOD_DAC_CONTRACT;
diff --git a/src/coreclr/vm/amd64/getstate.S b/src/coreclr/vm/amd64/getstate.S
index 04d9ab707d5979..f693f6071155b6 100644
--- a/src/coreclr/vm/amd64/getstate.S
+++ b/src/coreclr/vm/amd64/getstate.S
@@ -20,25 +20,3 @@ LEAF_ENTRY GetCurrentIP, _TEXT
ret
LEAF_END GetCurrentIP, _TEXT
-
-
-// EXTERN_C void LazyMachStateCaptureState(struct LazyMachState *pState)
-LEAF_ENTRY LazyMachStateCaptureState, _TEXT
-
- mov rdx, [rsp] // get the return address
-
- mov [rdi + OFFSETOF__MachState__m_Capture + 0*8], r12
- mov [rdi + OFFSETOF__MachState__m_Capture + 1*8], r13
- mov [rdi + OFFSETOF__MachState__m_Capture + 2*8], r14
- mov [rdi + OFFSETOF__MachState__m_Capture + 3*8], r15
- mov [rdi + OFFSETOF__MachState__m_Capture + 4*8], rbx
- mov [rdi + OFFSETOF__MachState__m_Capture + 5*8], rbp
-
- mov qword ptr [rdi + OFFSETOF__MachState___pRetAddr], 0
-
- mov [rdi + OFFSETOF__LazyMachState__m_CaptureRip], rdx
- mov [rdi + OFFSETOF__LazyMachState__m_CaptureRsp], rsp
-
- ret
-
-LEAF_END LazyMachStateCaptureState, _TEXT
diff --git a/src/coreclr/vm/amd64/getstate.asm b/src/coreclr/vm/amd64/getstate.asm
index 4831b758b9ddb8..7033b7bf0c3d66 100644
--- a/src/coreclr/vm/amd64/getstate.asm
+++ b/src/coreclr/vm/amd64/getstate.asm
@@ -50,29 +50,4 @@ LEAF_ENTRY get_cycle_count, _TEXT
ret
LEAF_END get_cycle_count, _TEXT
-
-; EXTERN_C void LazyMachStateCaptureState(struct LazyMachState *pState)
-LEAF_ENTRY LazyMachStateCaptureState, _TEXT
-
- mov rdx, [rsp] ; get the return address
-
- mov [rcx + OFFSETOF__MachState__m_Capture + 0*8], rdi
- mov [rcx + OFFSETOF__MachState__m_Capture + 1*8], rsi
- mov [rcx + OFFSETOF__MachState__m_Capture + 2*8], rbx
- mov [rcx + OFFSETOF__MachState__m_Capture + 3*8], rbp
- mov [rcx + OFFSETOF__MachState__m_Capture + 4*8], r12
- mov [rcx + OFFSETOF__MachState__m_Capture + 5*8], r13
- mov [rcx + OFFSETOF__MachState__m_Capture + 6*8], r14
- mov [rcx + OFFSETOF__MachState__m_Capture + 7*8], r15
-
- mov qword ptr [rcx + OFFSETOF__MachState___pRetAddr], 0
-
- mov [rcx + OFFSETOF__LazyMachState__m_CaptureRip], rdx
- mov [rcx + OFFSETOF__LazyMachState__m_CaptureRsp], rsp
-
- ret
-
-LEAF_END LazyMachStateCaptureState, _TEXT
-
-
end
diff --git a/src/coreclr/vm/amd64/gmsamd64.cpp b/src/coreclr/vm/amd64/gmsamd64.cpp
deleted file mode 100644
index 8af5247d07c334..00000000000000
--- a/src/coreclr/vm/amd64/gmsamd64.cpp
+++ /dev/null
@@ -1,130 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-
-/**************************************************************/
-/* gmsAMD64.cpp */
-/**************************************************************/
-
-#include "common.h"
-#include "gmscpu.h"
-
-void LazyMachState::unwindLazyState(LazyMachState* baseState,
- MachState* unwoundState,
- DWORD threadId,
- int funCallDepth /* = 1 */)
-{
- CONTRACTL
- {
- NOTHROW;
- GC_NOTRIGGER;
- SUPPORTS_DAC;
- }
- CONTRACTL_END;
-
- CONTEXT ctx;
- KNONVOLATILE_CONTEXT_POINTERS nonVolRegPtrs;
-
- ctx.ContextFlags = 0; // Read by PAL_VirtualUnwind.
-
- ctx.Rip = baseState->m_CaptureRip;
- ctx.Rsp = baseState->m_CaptureRsp + 8; // +8 for return addr pushed before calling LazyMachStateCaptureState
-
-#define CALLEE_SAVED_REGISTER(regname) ctx.regname = unwoundState->m_Capture.regname = baseState->m_Capture.regname;
- ENUM_CALLEE_SAVED_REGISTERS();
-#undef CALLEE_SAVED_REGISTER
-
-#if !defined(DACCESS_COMPILE)
-
- // For DAC, if we get here, it means that the LazyMachState is uninitialized and we have to unwind it.
- // The API we use to unwind in DAC is StackWalk64(), which does not support the context pointers.
-#define CALLEE_SAVED_REGISTER(regname) nonVolRegPtrs.regname = (PDWORD64)&unwoundState->m_Capture.regname;
- ENUM_CALLEE_SAVED_REGISTERS();
-#undef CALLEE_SAVED_REGISTER
-
-#endif // !DACCESS_COMPILE
-
- LOG((LF_GCROOTS, LL_INFO100000, "STACKWALK LazyMachState::unwindLazyState(ip:%p,sp:%p)\n", baseState->m_CaptureRip, baseState->m_CaptureRsp));
-
- PCODE pvControlPc;
-
- do
- {
-
-#ifndef TARGET_UNIX
- pvControlPc = Thread::VirtualUnwindCallFrame(&ctx, &nonVolRegPtrs);
-#else // !TARGET_UNIX
-
-#if defined(DACCESS_COMPILE)
- HRESULT hr = DacVirtualUnwind(threadId, &ctx, &nonVolRegPtrs);
- if (FAILED(hr))
- {
- DacError(hr);
- }
-#else
- BOOL success = PAL_VirtualUnwind(&ctx, &nonVolRegPtrs);
- if (!success)
- {
- _ASSERTE(!"unwindLazyState: Unwinding failed");
- EEPOLICY_HANDLE_FATAL_ERROR(COR_E_EXECUTIONENGINE);
- }
-#endif // DACCESS_COMPILE
-
- pvControlPc = GetIP(&ctx);
-#endif // !TARGET_UNIX
-
- if (funCallDepth > 0)
- {
- --funCallDepth;
- if (funCallDepth == 0)
- break;
- }
- else
- {
- // Determine whether given IP resides in JITted code. (It returns nonzero in that case.)
- // Use it now to see if we've unwound to managed code yet.
- BOOL fIsManagedCode = ExecutionManager::IsManagedCode(pvControlPc);
-
- if (fIsManagedCode)
- break;
- }
- }
- while(TRUE);
-
- //
- // Update unwoundState so that HelperMethodFrameRestoreState knows which
- // registers have been potentially modified.
- //
-
- unwoundState->m_Rip = ctx.Rip;
- unwoundState->m_Rsp = ctx.Rsp;
-
- // For DAC, the return value of this function may be used after unwoundState goes out of scope. so we cannot do
- // "unwoundState->_pRetAddr = PTR_TADDR(&unwoundState->m_Rip)".
- unwoundState->_pRetAddr = PTR_TADDR(unwoundState->m_Rsp - 8);
-
-#ifdef TARGET_UNIX
-#define CALLEE_SAVED_REGISTER(regname) unwoundState->m_Unwound.regname = ctx.regname;
- ENUM_CALLEE_SAVED_REGISTERS();
-#undef CALLEE_SAVED_REGISTER
-#endif
-
-#if defined(DACCESS_COMPILE)
-
- // For DAC, we have to update the registers directly, since we don't have context pointers.
-#define CALLEE_SAVED_REGISTER(regname) unwoundState->m_Capture.regname = ctx.regname;
- ENUM_CALLEE_SAVED_REGISTERS();
-#undef CALLEE_SAVED_REGISTER
-
- // Since we don't have context pointers in this case, just assing them to NULL.
-#define CALLEE_SAVED_REGISTER(regname) unwoundState->m_Ptrs.p##regname = NULL;
- ENUM_CALLEE_SAVED_REGISTERS();
-#undef CALLEE_SAVED_REGISTER
-
-#else // !DACCESS_COMPILE
-
-#define CALLEE_SAVED_REGISTER(regname) unwoundState->m_Ptrs.p##regname = PTR_TADDR(nonVolRegPtrs.regname);
- ENUM_CALLEE_SAVED_REGISTERS();
-#undef CALLEE_SAVED_REGISTER
-
-#endif // DACCESS_COMPILE
-}
diff --git a/src/coreclr/vm/amd64/gmscpu.h b/src/coreclr/vm/amd64/gmscpu.h
deleted file mode 100644
index 411f1cf0c71b88..00000000000000
--- a/src/coreclr/vm/amd64/gmscpu.h
+++ /dev/null
@@ -1,184 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-
-/**************************************************************/
-/* gmscpu.h */
-/**************************************************************/
-/* HelperFrame is defines 'GET_STATE(machState)' macro, which
- figures out what the state of the machine will be when the
- current method returns. It then stores the state in the
- JIT_machState structure. */
-
-/**************************************************************/
-
-#ifndef __gmsAMD64_h__
-#define __gmsAMD64_h__
-
-#ifdef _DEBUG
-class HelperMethodFrame;
-struct MachState;
-EXTERN_C MachState* __stdcall HelperMethodFrameConfirmState(HelperMethodFrame* frame, void* esiVal, void* ediVal, void* ebxVal, void* ebpVal);
-#endif // _DEBUG
-
-// A MachState indicates the register state of the processor at some point in time (usually
-// just before or after a call is made). It can be made one of two ways. Either explicitly
-// (when you for some reason know the values of all the registers), or implicitly using the
-// GET_STATE macros.
-
-typedef DPTR(struct MachState) PTR_MachState;
-struct MachState
-{
- MachState()
- {
- LIMITED_METHOD_DAC_CONTRACT;
- INDEBUG(memset((void*)this, 0xCC, sizeof(MachState));)
- }
-
- bool isValid() { LIMITED_METHOD_DAC_CONTRACT; _ASSERTE(dac_cast(_pRetAddr) != INVALID_POINTER_CC); return(_pRetAddr != nullptr); }
- TADDR* pRetAddr() { LIMITED_METHOD_DAC_CONTRACT; _ASSERTE(isValid()); return(_pRetAddr); }
- TADDR GetRetAddr() { LIMITED_METHOD_DAC_CONTRACT; _ASSERTE(isValid()); return *_pRetAddr; }
-#ifndef DACCESS_COMPILE
- void SetRetAddr(TADDR* addr) { _ASSERTE(isValid()); _pRetAddr = addr; }
-#endif
-
- friend class HelperMethodFrame;
- friend class CheckAsmOffsets;
- friend struct LazyMachState;
-#ifdef _DEBUG
- friend MachState* __stdcall HelperMethodFrameConfirmState(HelperMethodFrame* frame, void* esiVal, void* ediVal, void* ebxVal, void* ebpVal);
-#endif
-
-protected:
- PCODE m_Rip;
- TADDR m_Rsp;
-
- //
- // These "capture" fields are READ ONLY once initialized by
- // LazyMachStateCaptureState because we are racing to update
- // the MachState when we do a stackwalk so, we must not update
- // any state used to initialize the unwind from the captured
- // state to the managed caller.
- //
- // Note also, that these fields need to be in the base struct
- // because the context pointers below may point up to these
- // fields.
- //
- CalleeSavedRegisters m_Capture;
-
- // context pointers for preserved registers
- CalleeSavedRegistersPointers m_Ptrs;
-
- PTR_TADDR _pRetAddr;
-
-#ifdef TARGET_UNIX
- // On PAL, we don't always have the context pointers available due to
- // a limitation of an unwinding library. In such case, preserve
- // the unwound values.
- CalleeSavedRegisters m_Unwound;
-#endif
-};
-
-/********************************************************************/
-/* This allows you to defer the computation of the Machine state
- until later. Note that we don't reuse slots, because we want
- this to be threadsafe without locks */
-
-EXTERN_C void LazyMachStateCaptureState(struct LazyMachState *pState);
-
-typedef DPTR(struct LazyMachState) PTR_LazyMachState;
-struct LazyMachState : public MachState
-{
- // compute the machine state of the processor as it will exist just
- // after the return after at most'funCallDepth' number of functions.
- // if 'testFtn' is non-NULL, the return address is tested at each
- // return instruction encountered. If this test returns non-NULL,
- // then stack walking stops (thus you can walk up to the point that the
- // return address matches some criteria
-
- // Normally this is called with funCallDepth=1 and testFtn = 0 so that
- // it returns the state of the processor after the function that called 'captureState()'
- void setLazyStateFromUnwind(MachState* copy);
- static void unwindLazyState(LazyMachState* baseState,
- MachState* lazyState,
- DWORD threadId,
- int funCallDepth = 1);
-
- friend class HelperMethodFrame;
- friend class CheckAsmOffsets;
-
- //
- // These "capture" fields are READ ONLY once initialized by
- // LazyMachStateCaptureState because we are racing to update
- // the MachState when we do a stackwalk so, we must not update
- // any state used to initialize the unwind from the captured
- // state to the managed caller.
- //
- ULONG64 m_CaptureRip;
- ULONG64 m_CaptureRsp;
-};
-
-inline void LazyMachState::setLazyStateFromUnwind(MachState* copy)
-{
- LIMITED_METHOD_CONTRACT;
-
-#if defined(DACCESS_COMPILE)
- // This function cannot be called in DAC because DAC cannot update target memory.
- DacError(E_FAIL);
- return;
-
-#else // !DACCESS_COMPILE
- this->m_Rip = copy->m_Rip;
- this->m_Rsp = copy->m_Rsp;
-
-#ifdef TARGET_UNIX
- this->m_Unwound = copy->m_Unwound;
-#endif
-
- // Capture* has already been set, so there is no need to touch it
-
- // loop over the nonvolatile context pointers and make
- // sure to properly copy interior pointers into the
- // new struct
-
- PULONG64* pSrc = (PULONG64 *)©->m_Ptrs;
- PULONG64* pDst = (PULONG64 *)&this->m_Ptrs;
-
- const PULONG64 LowerBoundDst = (PULONG64) this;
- const PULONG64 LowerBoundSrc = (PULONG64) copy;
-
- const PULONG64 UpperBoundSrc = (PULONG64) ((BYTE*)LowerBoundSrc + sizeof(*copy));
-
- for (int i = 0; i < NUM_CALLEE_SAVED_REGISTERS; i++)
- {
- PULONG64 valueSrc = *pSrc++;
-
- if ((LowerBoundSrc <= valueSrc) && (valueSrc < UpperBoundSrc))
- {
- // make any pointer interior to 'src' interior to 'dst'
- valueSrc = (PULONG64)((BYTE*)valueSrc - (BYTE*)LowerBoundSrc + (BYTE*)LowerBoundDst);
- }
-
- *pDst++ = valueSrc;
- }
-
- // this has to be last because we depend on write ordering to
- // synchronize the race implicit in updating this struct
- VolatileStore(&_pRetAddr, (PTR_TADDR)(TADDR)&m_Rip);
-
-#endif // !DACCESS_COMPILE
-}
-
-// Do the initial capture of the machine state. This is meant to be
-// as light weight as possible, as we may never need the state that
-// we capture. Thus to complete the process you need to call
-// 'getMachState()', which finishes the process
-EXTERN_C void LazyMachStateCaptureState(struct LazyMachState *pState);
-
-// CAPTURE_STATE captures just enough register state so that the state of the
-// processor can be deterined just after the routine that has CAPTURE_STATE in
-// it returns.
-
-#define CAPTURE_STATE(machState, ret) \
- LazyMachStateCaptureState(machState)
-
-#endif // __gmsAMD64_h__
diff --git a/src/coreclr/vm/amd64/unixasmhelpers.S b/src/coreclr/vm/amd64/unixasmhelpers.S
index 35f765e940164b..cc864816bf03c8 100644
--- a/src/coreclr/vm/amd64/unixasmhelpers.S
+++ b/src/coreclr/vm/amd64/unixasmhelpers.S
@@ -5,57 +5,6 @@
#include "unixasmmacros.inc"
#include "asmconstants.h"
-// EXTERN_C int __fastcall HelperMethodFrameRestoreState(
-// INDEBUG_COMMA(HelperMethodFrame *pFrame)
-// MachState *pState
-// )
-LEAF_ENTRY HelperMethodFrameRestoreState, _TEXT
-
-#ifdef _DEBUG
- mov rdi, rsi
-#endif
-
- // Check if the MachState is valid
- xor eax, eax
- cmp qword ptr [rdi + OFFSETOF__MachState___pRetAddr], rax
- jne DoRestore
- REPRET
-DoRestore:
-
- //
- // If a preserved register were pushed onto the stack between
- // the managed caller and the H_M_F, m_pReg will point to its
- // location on the stack and it would have been updated on the
- // stack by the GC already and it will be popped back into the
- // appropriate register when the appropriate epilog is run.
- //
- // Otherwise, the register is preserved across all the code
- // in this HCALL or FCALL, so we need to update those registers
- // here because the GC will have updated our copies in the
- // frame.
- //
- // So, if m_pReg points into the MachState, we need to update
- // the register here. That's what this macro does.
- //
-#define RestoreReg(reg, regnum) \
- lea rax, [rdi + OFFSETOF__MachState__m_Capture + 8 * regnum]; \
- mov rdx, [rdi + OFFSETOF__MachState__m_Ptrs + 8 * regnum]; \
- cmp rax, rdx; \
- cmove reg, [rax];
-
- // regnum has to match ENUM_CALLEE_SAVED_REGISTERS macro
- RestoreReg(R12, 0)
- RestoreReg(R13, 1)
- RestoreReg(R14, 2)
- RestoreReg(R15, 3)
- RestoreReg(Rbx, 4)
- RestoreReg(Rbp, 5)
-
- xor eax, eax
- ret
-
-LEAF_END HelperMethodFrameRestoreState, _TEXT
-
//////////////////////////////////////////////////////////////////////////
//
// NDirectImportThunk
@@ -108,7 +57,7 @@ NESTED_ENTRY NDirectImportThunk, _TEXT, NoHandler
POP_ARGUMENT_REGISTERS
jmp r10
-
+
NESTED_END NDirectImportThunk, _TEXT
//------------------------------------------------
diff --git a/src/coreclr/vm/arm/asmconstants.h b/src/coreclr/vm/arm/asmconstants.h
index 8e72ae93d6f85d..47efe69e5f9cf4 100644
--- a/src/coreclr/vm/arm/asmconstants.h
+++ b/src/coreclr/vm/arm/asmconstants.h
@@ -41,27 +41,6 @@ ASMCONSTANTS_C_ASSERT(ThisPtrRetBufPrecodeData__Target == offsetof(ThisPtrRetBuf
#define REDIRECTSTUB_SP_OFFSET_CONTEXT 0
-
-// Offset of the array containing the address of captured registers in MachState
-#define MachState__captureR4_R11 0x0
-ASMCONSTANTS_C_ASSERT(MachState__captureR4_R11 == offsetof(MachState, captureR4_R11))
-
-// Offset of the array containing the address of preserved registers in MachState
-#define MachState___R4_R11 0x20
-ASMCONSTANTS_C_ASSERT(MachState___R4_R11 == offsetof(MachState, _R4_R11))
-
-#define MachState__isValid 0x48
-ASMCONSTANTS_C_ASSERT(MachState__isValid == offsetof(MachState, _isValid))
-
-#define LazyMachState_captureR4_R11 MachState__captureR4_R11
-ASMCONSTANTS_C_ASSERT(LazyMachState_captureR4_R11 == offsetof(LazyMachState, captureR4_R11))
-
-#define LazyMachState_captureSp (MachState__isValid+4)
-ASMCONSTANTS_C_ASSERT(LazyMachState_captureSp == offsetof(LazyMachState, captureSp))
-
-#define LazyMachState_captureIp (LazyMachState_captureSp+4)
-ASMCONSTANTS_C_ASSERT(LazyMachState_captureIp == offsetof(LazyMachState, captureIp))
-
#define OFFSETOF__MethodTable__m_dwFlags 0x00
ASMCONSTANTS_C_ASSERT(OFFSETOF__MethodTable__m_dwFlags == offsetof(MethodTable, m_dwFlags));
diff --git a/src/coreclr/vm/arm/asmhelpers.S b/src/coreclr/vm/arm/asmhelpers.S
index 62ba0ac90e8fd6..bf655df04704d6 100644
--- a/src/coreclr/vm/arm/asmhelpers.S
+++ b/src/coreclr/vm/arm/asmhelpers.S
@@ -135,23 +135,6 @@ CallDescrWorkerInternalReturnAddressOffset:
// ------------------------------------------------------------------
-// void LazyMachStateCaptureState(struct LazyMachState *pState)//
- LEAF_ENTRY LazyMachStateCaptureState, _TEXT
-
- // marks that this is not yet valid
- mov r1, #0
- str r1, [r0, #MachState__isValid]
-
- str lr, [r0, #LazyMachState_captureIp]
- str sp, [r0, #LazyMachState_captureSp]
-
- add r1, r0, #LazyMachState_captureR4_R11
- stm r1, {r4-r11}
-
- mov pc, lr
-
- LEAF_END LazyMachStateCaptureState, _TEXT
-
//
// r12 = UMEntryThunk*
//
@@ -260,46 +243,6 @@ ThePreStubPatchLabel:
NESTED_END ResolveWorkerChainLookupAsmStub, _TEXT
- //
- // If a preserved register were pushed onto the stack between
- // the managed caller and the H_M_F, _R4_R11 will point to its
- // location on the stack and it would have been updated on the
- // stack by the GC already and it will be popped back into the
- // appropriate register when the appropriate epilog is run.
- //
- // Otherwise, the register is preserved across all the code
- // in this HCALL or FCALL, so we need to update those registers
- // here because the GC will have updated our copies in the
- // frame.
- //
- // So, if _R4_R11 points into the MachState, we need to update
- // the register here. That's what this macro does.
- //
-
- .macro RestoreRegMS regIndex, reg
-
- // Incoming:
- //
- // R0 = address of MachState
- //
- // $regIndex: Index of the register (R4-R11). For R4, index is 4.
- // For R5, index is 5, and so on.
- //
- // $reg: Register name (e.g. R4, R5, etc)
- //
- // Get the address of the specified captured register from machine state
- add r2, r0, #(MachState__captureR4_R11 + ((\regIndex-4)*4))
-
- // Get the address of the specified preserved register from machine state
- ldr r3, [r0, #(MachState___R4_R11 + ((\regIndex-4)*4))]
-
- cmp r2, r3
- bne 0f
- ldr \reg, [r2]
-0:
-
- .endm
-
#ifdef PROFILING_SUPPORTED
//
@@ -334,7 +277,7 @@ LEAF_END JIT_ProfilerEnterLeaveTailcallStub, _TEXT
NESTED_ENTRY \helper\()Naked, _TEXT, NoHandler
PROLOG_PUSH "{r0,r3,r9,r12}"
- // for the 5 arguments that do not need popped plus 4 bytes of alignment
+ // for the 5 arguments that do not need popped plus 4 bytes of alignment
alloc_stack 6*4
// push fp regs
@@ -362,7 +305,7 @@ NESTED_ENTRY \helper\()Naked, _TEXT, NoHandler
// clear hiddenArg
movw r2, #0
str r2, [sp, PROFILE_PLATFORM_SPECIFIC_DATA__hiddenArg]
-
+
// set the flag to indicate what hook this is
movw r2, \flags
str r2, [sp, PROFILE_PLATFORM_SPECIFIC_DATA__flags]
@@ -390,38 +333,6 @@ GenerateProfileHelper ProfileTailcall, PROFILE_TAILCALL
#endif
-// EXTERN_C int __fastcall HelperMethodFrameRestoreState(
-// INDEBUG_COMMA(HelperMethodFrame *pFrame)
-// MachState *pState
-// )
- LEAF_ENTRY HelperMethodFrameRestoreState, _TEXT
-
-#ifdef _DEBUG
- mov r0, r1
-#endif
-
- // If machine state is invalid, then simply exit
- ldr r1, [r0, #MachState__isValid]
- cmp r1, #0
- beq LOCAL_LABEL(Done)
-
- RestoreRegMS 4, R4
- RestoreRegMS 5, R5
- RestoreRegMS 6, R6
- RestoreRegMS 7, R7
- RestoreRegMS 8, R8
- RestoreRegMS 9, R9
- RestoreRegMS 10, R10
- RestoreRegMS 11, R11
-LOCAL_LABEL(Done):
- // Its imperative that the return value of HelperMethodFrameRestoreState is zero
- // as it is used in the state machine to loop until it becomes zero.
- // Refer to HELPER_METHOD_FRAME_END macro for details.
- mov r0,#0
- bx lr
-
- LEAF_END HelperMethodFrameRestoreState, _TEXT
-
#if 0
// ------------------------------------------------------------------
// Macro to generate Redirection Stubs
diff --git a/src/coreclr/vm/arm/gmscpu.h b/src/coreclr/vm/arm/gmscpu.h
deleted file mode 100644
index 42641889ad9e37..00000000000000
--- a/src/coreclr/vm/arm/gmscpu.h
+++ /dev/null
@@ -1,173 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-
-/**************************************************************/
-/* gmscpu.h */
-/**************************************************************/
-/* HelperFrame is defines 'GET_STATE(machState)' macro, which
- figures out what the state of the machine will be when the
- current method returns. It then stores the state in the
- JIT_machState structure. */
-
-/**************************************************************/
-
-#ifndef __gmscpu_h__
-#define __gmscpu_h__
-
-#define __gmscpu_h__
-
-#ifdef _DEBUG
-class HelperMethodFrame;
-struct MachState;
-EXTERN_C MachState* __stdcall HelperMethodFrameConfirmState(HelperMethodFrame* frame, void* esiVal, void* ediVal, void* ebxVal, void* ebpVal);
-#endif
-
- // A MachState indicates the register state of the processor at some point in time (usually
- // just before or after a call is made). It can be made one of two ways. Either explicitly
- // (when you for some reason know the values of all the registers), or implicitly using the
- // GET_STATE macros.
-
-typedef DPTR(struct MachState) PTR_MachState;
-struct MachState {
-
- BOOL isValid() { LIMITED_METHOD_DAC_CONTRACT; return _isValid; }
- TADDR GetRetAddr() { LIMITED_METHOD_DAC_CONTRACT; return _pc; }
-
- friend class HelperMethodFrame;
- friend class CheckAsmOffsets;
- friend struct LazyMachState;
-
-
-protected:
- // The simplest way to understand the relationship between capturedR4_R11 (registers
- // representing the captured state) and _R4_R11 (pointers to registers representing
- // preserved state) is as follows:
- //
- // 1) LazyMachState::unwindLazyState is invoked by HelperMethodFrame to initialize the captured
- // state. It then performs an unwind and copies the register pointers to _R4_R11.
- //
- // 2) HelperMethodFrame::UpdateRegdisplay is invoked by our StackWalker that initializes
- // the regdisplay with the updated register state.
- //
- // 3) HelperMethodFrameRestoreState is invoked when the HMF state machine exits and it
- // restores the values of unmodified registers.
-
- TADDR captureR4_R11[8]; // Registers R4..R11 at the time of capture
-
- PTR_DWORD _R4_R11[8]; // Preserved registers
-
- TADDR _pc; // program counter after the function returns
- TADDR _sp; // stack pointer after the function returns
-
- BOOL _isValid;
-};
-
-/********************************************************************/
-/* This allows you to defer the computation of the Machine state
- until later. Note that we don't reuse slots, because we want
- this to be threadsafe without locks */
-
-struct LazyMachState : public MachState {
- // compute the machine state of the processor as it will exist just
- // after the return after at most'funCallDepth' number of functions.
- // if 'testFtn' is non-NULL, the return address is tested at each
- // return instruction encountered. If this test returns non-NULL,
- // then stack walking stops (thus you can walk up to the point that the
- // return address matches some criteria
-
- // Normally this is called with funCallDepth=1 and testFtn = 0 so that
- // it returns the state of the processor after the function that called 'captureState()'
- void setLazyStateFromUnwind(MachState* copy);
- static void unwindLazyState(LazyMachState* baseState,
- MachState* lazyState,
- DWORD threadId,
- int funCallDepth = 1);
-
- friend class HelperMethodFrame;
- friend class CheckAsmOffsets;
-private:
- TADDR captureSp; // Stack pointer at the time of capture
- TADDR captureIp; // Instruction pointer at the time of capture
-};
-
-// R4 - R11
-#define NUM_NONVOLATILE_CONTEXT_POINTERS 8
-
-inline void LazyMachState::setLazyStateFromUnwind(MachState* copy)
-{
- LIMITED_METHOD_CONTRACT;
-
-#if defined(DACCESS_COMPILE)
- // This function cannot be called in DAC because DAC cannot update target memory.
- DacError(E_FAIL);
- return;
-
-#else // !DACCESS_COMPILE
- this->_pc = copy->_pc;
- this->_sp = copy->_sp;
-
- // Capture* has already been set, so there is no need to touch it.
- // This was setup in LazyMachState::unwindLazyState just before we
- // called into the OS for unwind.
-
- // Prepare to loop over the nonvolatile context pointers for and
- // make sure to properly copy interior pointers into the new struct.
-
- PDWORD* pSrc = ©->_R4_R11[0];
- PDWORD* pDst = &this->_R4_R11[0];
-
- const PDWORD LowerBoundDst = (PDWORD) this;
- const PDWORD LowerBoundSrc = (PDWORD) copy;
-
- // Calculate the upperbound till which we need to loop (i.e. the highest address till
- // which we have saved non-volatile pointers).
- const PDWORD UpperBoundSrc = (PDWORD) (((BYTE*)LowerBoundSrc) + offsetof(LazyMachState, _pc));
-
-#ifdef _DEBUG
- int count = 0;
-#endif // _DEBUG
-
- while (((PDWORD)pSrc) < UpperBoundSrc)
- {
-#ifdef _DEBUG
- count++;
-#endif // _DEBUG
-
- PDWORD valueSrc = *pSrc++;
-
- // If any non-volatile register pointer is pointing to the corresponding register field
- // in the MachState, then make the corresponding pointer in "this" MachState point
- // to the corresponding field.
- if ((LowerBoundSrc <= valueSrc) && (valueSrc < UpperBoundSrc))
- {
- valueSrc = (PDWORD)((BYTE*)valueSrc - (BYTE*)LowerBoundSrc + (BYTE*)LowerBoundDst);
- }
-
- *pDst++ = valueSrc;
- }
-
- CONSISTENCY_CHECK_MSGF(count == NUM_NONVOLATILE_CONTEXT_POINTERS, ("count != NUM_NONVOLATILE_CONTEXT_POINTERS, actually = %d", count));
-
- // this has to be last because we depend on write ordering to
- // synchronize the race implicit in updating this struct
- VolatileStore(&_isValid, TRUE);
-
-#endif // !DACCESS_COMPILE
-
-}
-typedef DPTR(LazyMachState) PTR_LazyMachState;
-
-// Do the initial capture of the machine state. This is meant to be
-// as light weight as possible, as we may never need the state that
-// we capture. Thus to complete the process you need to call
-// 'getMachState()', which finishes the process
-EXTERN_C void LazyMachStateCaptureState(struct LazyMachState *pState);
-
-// CAPTURE_STATE captures just enough register state so that the state of the
-// processor can be deterined just after the routine that has CAPTURE_STATE in
-// it returns.
-
-#define CAPTURE_STATE(machState, ret) \
- LazyMachStateCaptureState(machState)
-
-#endif
diff --git a/src/coreclr/vm/arm/stubs.cpp b/src/coreclr/vm/arm/stubs.cpp
index 9a91389cc830ea..da16361ddc3f8c 100644
--- a/src/coreclr/vm/arm/stubs.cpp
+++ b/src/coreclr/vm/arm/stubs.cpp
@@ -555,210 +555,8 @@ void FlushWriteBarrierInstructionCache()
FlushInstructionCache(GetCurrentProcess(), pbAlteredRange, cbAlteredRange);
}
-
#endif // !DACCESS_COMPILE
-void LazyMachState::unwindLazyState(LazyMachState* baseState,
- MachState* unwoundstate,
- DWORD threadId,
- int funCallDepth)
-{
- T_CONTEXT ctx;
- T_KNONVOLATILE_CONTEXT_POINTERS nonVolRegPtrs;
-
- ctx.ContextFlags = 0; // Read by PAL_VirtualUnwind.
-
- ctx.Pc = baseState->captureIp;
- ctx.Sp = baseState->captureSp;
-
- ctx.R4 = unwoundstate->captureR4_R11[0] = baseState->captureR4_R11[0];
- ctx.R5 = unwoundstate->captureR4_R11[1] = baseState->captureR4_R11[1];
- ctx.R6 = unwoundstate->captureR4_R11[2] = baseState->captureR4_R11[2];
- ctx.R7 = unwoundstate->captureR4_R11[3] = baseState->captureR4_R11[3];
- ctx.R8 = unwoundstate->captureR4_R11[4] = baseState->captureR4_R11[4];
- ctx.R9 = unwoundstate->captureR4_R11[5] = baseState->captureR4_R11[5];
- ctx.R10 = unwoundstate->captureR4_R11[6] = baseState->captureR4_R11[6];
- ctx.R11 = unwoundstate->captureR4_R11[7] = baseState->captureR4_R11[7];
-
-#if !defined(DACCESS_COMPILE)
- // For DAC, if we get here, it means that the LazyMachState is uninitialized and we have to unwind it.
- // The API we use to unwind in DAC is StackWalk64(), which does not support the context pointers.
- //
- // Restore the integer registers to KNONVOLATILE_CONTEXT_POINTERS to be used for unwinding.
- nonVolRegPtrs.R4 = &unwoundstate->captureR4_R11[0];
- nonVolRegPtrs.R5 = &unwoundstate->captureR4_R11[1];
- nonVolRegPtrs.R6 = &unwoundstate->captureR4_R11[2];
- nonVolRegPtrs.R7 = &unwoundstate->captureR4_R11[3];
- nonVolRegPtrs.R8 = &unwoundstate->captureR4_R11[4];
- nonVolRegPtrs.R9 = &unwoundstate->captureR4_R11[5];
- nonVolRegPtrs.R10 = &unwoundstate->captureR4_R11[6];
- nonVolRegPtrs.R11 = &unwoundstate->captureR4_R11[7];
-#endif // DACCESS_COMPILE
-
- LOG((LF_GCROOTS, LL_INFO100000, "STACKWALK LazyMachState::unwindLazyState(ip:%p,sp:%p)\n", baseState->captureIp, baseState->captureSp));
-
- PCODE pvControlPc;
-
- do
- {
-#ifdef DACCESS_COMPILE
- HRESULT hr = DacVirtualUnwind(threadId, &ctx, &nonVolRegPtrs);
- if (FAILED(hr))
- {
- DacError(hr);
- }
-#else // DACCESS_COMPILE
- BOOL success = PAL_VirtualUnwind(&ctx, &nonVolRegPtrs);
- if (!success)
- {
- _ASSERTE(!"unwindLazyState: Unwinding failed");
- EEPOLICY_HANDLE_FATAL_ERROR(COR_E_EXECUTIONENGINE);
- }
-#endif // DACCESS_COMPILE
- pvControlPc = GetIP(&ctx);
- if (funCallDepth > 0)
- {
- --funCallDepth;
- if (funCallDepth == 0)
- break;
- }
- else
- {
- // Determine whether given IP resides in JITted code. (It returns nonzero in that case.)
- // Use it now to see if we've unwound to managed code yet.
- BOOL fIsManagedCode = ExecutionManager::IsManagedCode(pvControlPc);
-
- if (fIsManagedCode)
- break;
- }
- }
- while(TRUE);
-
- //
- // Update unwoundState so that HelperMethodFrameRestoreState knows which
- // registers have been potentially modified.
- //
-
- unwoundstate->_pc = ctx.Pc;
- unwoundstate->_sp = ctx.Sp;
-
-#ifdef DACCESS_COMPILE
- // For DAC builds, we update the registers directly since we dont have context pointers
- unwoundstate->captureR4_R11[0] = ctx.R4;
- unwoundstate->captureR4_R11[1] = ctx.R5;
- unwoundstate->captureR4_R11[2] = ctx.R6;
- unwoundstate->captureR4_R11[3] = ctx.R7;
- unwoundstate->captureR4_R11[4] = ctx.R8;
- unwoundstate->captureR4_R11[5] = ctx.R9;
- unwoundstate->captureR4_R11[6] = ctx.R10;
- unwoundstate->captureR4_R11[7] = ctx.R11;
-#else // !DACCESS_COMPILE
- // For non-DAC builds, update the register state from context pointers
- unwoundstate->_R4_R11[0] = (PDWORD)nonVolRegPtrs.R4;
- unwoundstate->_R4_R11[1] = (PDWORD)nonVolRegPtrs.R5;
- unwoundstate->_R4_R11[2] = (PDWORD)nonVolRegPtrs.R6;
- unwoundstate->_R4_R11[3] = (PDWORD)nonVolRegPtrs.R7;
- unwoundstate->_R4_R11[4] = (PDWORD)nonVolRegPtrs.R8;
- unwoundstate->_R4_R11[5] = (PDWORD)nonVolRegPtrs.R9;
- unwoundstate->_R4_R11[6] = (PDWORD)nonVolRegPtrs.R10;
- unwoundstate->_R4_R11[7] = (PDWORD)nonVolRegPtrs.R11;
-#endif // DACCESS_COMPILE
-
- unwoundstate->_isValid = true;
-}
-
-void HelperMethodFrame::UpdateRegDisplay_Impl(const PREGDISPLAY pRD, bool updateFloats)
-{
- CONTRACTL
- {
- NOTHROW;
- GC_NOTRIGGER;
- MODE_ANY;
- SUPPORTS_DAC;
- }
- CONTRACTL_END;
-
-#ifndef DACCESS_COMPILE
- if (updateFloats)
- {
- UpdateFloatingPointRegisters(pRD);
- _ASSERTE(pRD->pCurrentContext->Pc == GetReturnAddress());
- }
-#endif // DACCESS_COMPILE
-
- pRD->IsCallerContextValid = FALSE;
- pRD->IsCallerSPValid = FALSE; // Don't add usage of this field. This is only temporary.
-
- //
- // Copy the saved state from the frame to the current context.
- //
-
- LOG((LF_GCROOTS, LL_INFO100000, "STACKWALK HelperMethodFrame::UpdateRegDisplay cached ip:%p, sp:%p\n", m_MachState._pc, m_MachState._sp));
-
- #if defined(DACCESS_COMPILE)
- // For DAC, we may get here when the HMF is still uninitialized.
- // So we may need to unwind here.
- if (!m_MachState.isValid())
- {
- // This allocation throws on OOM.
- MachState* pUnwoundState = (MachState*)DacAllocHostOnlyInstance(sizeof(*pUnwoundState), true);
-
- EnsureInit(pUnwoundState);
-
- pRD->pCurrentContext->Pc = pRD->ControlPC = pUnwoundState->_pc;
- pRD->pCurrentContext->Sp = pRD->SP = pUnwoundState->_sp;
-
- pRD->pCurrentContext->R4 = (DWORD)(pUnwoundState->captureR4_R11[0]);
- pRD->pCurrentContext->R5 = (DWORD)(pUnwoundState->captureR4_R11[1]);
- pRD->pCurrentContext->R6 = (DWORD)(pUnwoundState->captureR4_R11[2]);
- pRD->pCurrentContext->R7 = (DWORD)(pUnwoundState->captureR4_R11[3]);
- pRD->pCurrentContext->R8 = (DWORD)(pUnwoundState->captureR4_R11[4]);
- pRD->pCurrentContext->R9 = (DWORD)(pUnwoundState->captureR4_R11[5]);
- pRD->pCurrentContext->R10 = (DWORD)(pUnwoundState->captureR4_R11[6]);
- pRD->pCurrentContext->R11 = (DWORD)(pUnwoundState->captureR4_R11[7]);
-
- pRD->pCurrentContextPointers->R4 = &pRD->pCurrentContext->R4;
- pRD->pCurrentContextPointers->R5 = &pRD->pCurrentContext->R5;
- pRD->pCurrentContextPointers->R6 = &pRD->pCurrentContext->R6;
- pRD->pCurrentContextPointers->R7 = &pRD->pCurrentContext->R7;
- pRD->pCurrentContextPointers->R8 = &pRD->pCurrentContext->R8;
- pRD->pCurrentContextPointers->R9 = &pRD->pCurrentContext->R9;
- pRD->pCurrentContextPointers->R10 = &pRD->pCurrentContext->R10;
- pRD->pCurrentContextPointers->R11 = &pRD->pCurrentContext->R11;
- pRD->pCurrentContextPointers->Lr = &pRD->pCurrentContext->Lr;
-
- return;
- }
-#endif // DACCESS_COMPILE
-
- // reset pContext; it's only valid for active (top-most) frame
- pRD->pContext = NULL;
- pRD->ControlPC = GetReturnAddress();
- pRD->SP = (DWORD)(size_t)m_MachState._sp;
-
- pRD->pCurrentContext->Pc = pRD->ControlPC;
- pRD->pCurrentContext->Sp = pRD->SP;
-
- pRD->pCurrentContext->R4 = *m_MachState._R4_R11[0];
- pRD->pCurrentContext->R5 = *m_MachState._R4_R11[1];
- pRD->pCurrentContext->R6 = *m_MachState._R4_R11[2];
- pRD->pCurrentContext->R7 = *m_MachState._R4_R11[3];
- pRD->pCurrentContext->R8 = *m_MachState._R4_R11[4];
- pRD->pCurrentContext->R9 = *m_MachState._R4_R11[5];
- pRD->pCurrentContext->R10 = *m_MachState._R4_R11[6];
- pRD->pCurrentContext->R11 = *m_MachState._R4_R11[7];
-
- pRD->pCurrentContextPointers->R4 = m_MachState._R4_R11[0];
- pRD->pCurrentContextPointers->R5 = m_MachState._R4_R11[1];
- pRD->pCurrentContextPointers->R6 = m_MachState._R4_R11[2];
- pRD->pCurrentContextPointers->R7 = m_MachState._R4_R11[3];
- pRD->pCurrentContextPointers->R8 = m_MachState._R4_R11[4];
- pRD->pCurrentContextPointers->R9 = m_MachState._R4_R11[5];
- pRD->pCurrentContextPointers->R10 = m_MachState._R4_R11[6];
- pRD->pCurrentContextPointers->R11 = m_MachState._R4_R11[7];
- pRD->pCurrentContextPointers->Lr = NULL;
-}
-
#ifndef DACCESS_COMPILE
/*
diff --git a/src/coreclr/vm/arm64/asmconstants.h b/src/coreclr/vm/arm64/asmconstants.h
index 0711dc779f8b9c..fb262a617e8bba 100644
--- a/src/coreclr/vm/arm64/asmconstants.h
+++ b/src/coreclr/vm/arm64/asmconstants.h
@@ -88,31 +88,6 @@ ASMCONSTANTS_C_ASSERT(CallDescrData__pTarget == offsetof(CallDescrD
ASMCONSTANTS_C_ASSERT(CallDescrData__pRetBuffArg == offsetof(CallDescrData, pRetBuffArg))
ASMCONSTANTS_C_ASSERT(CallDescrData__returnValue == offsetof(CallDescrData, returnValue))
-
-// Offset of the array containing the address of captured registers in MachState
-#define MachState__captureX19_X29 0x0
-ASMCONSTANTS_C_ASSERT(MachState__captureX19_X29 == offsetof(MachState, captureX19_X29))
-
-// Offset of the array containing the address of preserved registers in MachState
-#define MachState__ptrX19_X29 0x58
-ASMCONSTANTS_C_ASSERT(MachState__ptrX19_X29 == offsetof(MachState, ptrX19_X29))
-
-#define MachState__isValid 0xc0
-ASMCONSTANTS_C_ASSERT(MachState__isValid == offsetof(MachState, _isValid))
-
-#define LazyMachState_captureX19_X29 MachState__captureX19_X29
-ASMCONSTANTS_C_ASSERT(LazyMachState_captureX19_X29 == offsetof(LazyMachState, captureX19_X29))
-
-#ifdef __APPLE__
-#define LazyMachState_captureSp (MachState__isValid+8+88) // padding for alignment
-#else // __APPLE__
-#define LazyMachState_captureSp (MachState__isValid+8) // padding for alignment
-#endif // __APPLE
-ASMCONSTANTS_C_ASSERT(LazyMachState_captureSp == offsetof(LazyMachState, captureSp))
-
-#define LazyMachState_captureIp (LazyMachState_captureSp+8)
-ASMCONSTANTS_C_ASSERT(LazyMachState_captureIp == offsetof(LazyMachState, captureIp))
-
#define VASigCookie__pNDirectILStub 0x8
ASMCONSTANTS_C_ASSERT(VASigCookie__pNDirectILStub == offsetof(VASigCookie, pNDirectILStub))
diff --git a/src/coreclr/vm/arm64/asmhelpers.S b/src/coreclr/vm/arm64/asmhelpers.S
index 074b0bff19f1b0..394f75b80f1eca 100644
--- a/src/coreclr/vm/arm64/asmhelpers.S
+++ b/src/coreclr/vm/arm64/asmhelpers.S
@@ -30,106 +30,6 @@ LEAF_END GetDataCacheZeroIDReg, _TEXT
ret lr
LEAF_END GetSveLengthFromOS, _TEXT
-//-----------------------------------------------------------------------------
-// This routine captures the machine state. It is used by helper method frame
-//-----------------------------------------------------------------------------
-//void LazyMachStateCaptureState(struct LazyMachState *pState)//
-LEAF_ENTRY LazyMachStateCaptureState, _TEXT
- // marks that this is not yet valid
- mov w1, #0
- str w1, [x0, #MachState__isValid]
-
- str lr, [x0, #LazyMachState_captureIp]
-
- // str instruction does not save sp register directly so move to temp register
- mov x1, sp
- str x1, [x0, #LazyMachState_captureSp]
-
- // save non-volatile registers that can contain object references
- add x1, x0, #LazyMachState_captureX19_X29
- stp x19, x20, [x1, #(16*0)]
- stp x21, x22, [x1, #(16*1)]
- stp x23, x24, [x1, #(16*2)]
- stp x25, x26, [x1, #(16*3)]
- stp x27, x28, [x1, #(16*4)]
- str x29, [x1, #(16*5)]
-
- ret lr
-LEAF_END LazyMachStateCaptureState, _TEXT
-
-//
-// If a preserved register were pushed onto the stack between
-// the managed caller and the H_M_F, ptrX19_X29 will point to its
-// location on the stack and it would have been updated on the
-// stack by the GC already and it will be popped back into the
-// appropriate register when the appropriate epilog is run.
-//
-// Otherwise, the register is preserved across all the code
-// in this HCALL or FCALL, so we need to update those registers
-// here because the GC will have updated our copies in the
-// frame.
-//
-// So, if ptrX19_X29 points into the MachState, we need to update
-// the register here. That's what this macro does.
-//
-.macro RestoreRegMS regIndex, reg
- // Incoming:
- //
- // x0 = address of MachState
- //
- // $regIndex: Index of the register (x19-x28). For x19, index is 19.
- //For x20, index is 20, and so on.
- //
- // $reg: Register name (e.g. x19, x20, etc)
- //
- // Get the address of the specified captured register from machine state
- add x2, x0, #(MachState__captureX19_X29 + ((\regIndex-19)*8))
-
- // Get the content of specified preserved register pointer from machine state
- ldr x3, [x0, #(MachState__ptrX19_X29 + ((\regIndex-19)*8))]
-
- cmp x2, x3
- bne LOCAL_LABEL(NoRestore_\reg)
- ldr \reg, [x2]
-LOCAL_LABEL(NoRestore_\reg):
-
-.endm
-
-// EXTERN_C int __fastcall HelperMethodFrameRestoreState(
-// INDEBUG_COMMA(HelperMethodFrame *pFrame)
-// MachState *pState
-// )
-LEAF_ENTRY HelperMethodFrameRestoreState, _TEXT
-
- #ifdef _DEBUG
- mov x0, x1
- #endif
-
- // If machine state is invalid, then simply exit
- ldr w1, [x0, #MachState__isValid]
- cmp w1, #0
- beq LOCAL_LABEL(Done)
-
- RestoreRegMS 19, X19
- RestoreRegMS 20, X20
- RestoreRegMS 21, X21
- RestoreRegMS 22, X22
- RestoreRegMS 23, X23
- RestoreRegMS 24, X24
- RestoreRegMS 25, X25
- RestoreRegMS 26, X26
- RestoreRegMS 27, X27
- RestoreRegMS 28, X28
- RestoreRegMS 29, X29
-LOCAL_LABEL(Done):
- // Its imperative that the return value of HelperMethodFrameRestoreState is zero
- // as it is used in the state machine to loop until it becomes zero.
- // Refer to HELPER_METHOD_FRAME_END macro for details.
- mov x0,#0
- ret lr
-
-LEAF_END HelperMethodFrameRestoreState, _TEXT
-
// ------------------------------------------------------------------
// The call in ndirect import precode points to this function.
NESTED_ENTRY NDirectImportThunk, _TEXT, NoHandler
diff --git a/src/coreclr/vm/arm64/asmhelpers.asm b/src/coreclr/vm/arm64/asmhelpers.asm
index bd206f32940ba3..815e2c8face8e0 100644
--- a/src/coreclr/vm/arm64/asmhelpers.asm
+++ b/src/coreclr/vm/arm64/asmhelpers.asm
@@ -93,110 +93,6 @@
ret lr
LEAF_END
-;;-----------------------------------------------------------------------------
-;; This routine captures the machine state. It is used by helper method frame
-;;-----------------------------------------------------------------------------
-;;void LazyMachStateCaptureState(struct LazyMachState *pState);
- LEAF_ENTRY LazyMachStateCaptureState
- ;; marks that this is not yet valid
- mov w1, #0
- str w1, [x0, #MachState__isValid]
-
- str lr, [x0, #LazyMachState_captureIp]
-
- ;; str instruction does not save sp register directly so move to temp register
- mov x1, sp
- str x1, [x0, #LazyMachState_captureSp]
-
- ;; save non-volatile registers that can contain object references
- add x1, x0, #LazyMachState_captureX19_X29
- stp x19, x20, [x1, #(16*0)]
- stp x21, x22, [x1, #(16*1)]
- stp x23, x24, [x1, #(16*2)]
- stp x25, x26, [x1, #(16*3)]
- stp x27, x28, [x1, #(16*4)]
- str x29, [x1, #(16*5)]
-
- ret lr
- LEAF_END
-
- ;
- ; If a preserved register were pushed onto the stack between
- ; the managed caller and the H_M_F, ptrX19_X29 will point to its
- ; location on the stack and it would have been updated on the
- ; stack by the GC already and it will be popped back into the
- ; appropriate register when the appropriate epilog is run.
- ;
- ; Otherwise, the register is preserved across all the code
- ; in this HCALL or FCALL, so we need to update those registers
- ; here because the GC will have updated our copies in the
- ; frame.
- ;
- ; So, if ptrX19_X29 points into the MachState, we need to update
- ; the register here. That's what this macro does.
- ;
-
- MACRO
- RestoreRegMS $regIndex, $reg
-
- ; Incoming:
- ;
- ; x0 = address of MachState
- ;
- ; $regIndex: Index of the register (x19-x29). For x19, index is 19.
- ; For x20, index is 20, and so on.
- ;
- ; $reg: Register name (e.g. x19, x20, etc)
- ;
- ; Get the address of the specified captured register from machine state
- add x2, x0, #(MachState__captureX19_X29 + (($regIndex-19)*8))
-
- ; Get the content of specified preserved register pointer from machine state
- ldr x3, [x0, #(MachState__ptrX19_X29 + (($regIndex-19)*8))]
-
- cmp x2, x3
- bne %FT0
- ldr $reg, [x2]
-0
-
- MEND
-
-; EXTERN_C int __fastcall HelperMethodFrameRestoreState(
-; INDEBUG_COMMA(HelperMethodFrame *pFrame)
-; MachState *pState
-; )
- LEAF_ENTRY HelperMethodFrameRestoreState
-
-#ifdef _DEBUG
- mov x0, x1
-#endif
-
- ; If machine state is invalid, then simply exit
- ldr w1, [x0, #MachState__isValid]
- cmp w1, #0
- beq Done
-
- RestoreRegMS 19, X19
- RestoreRegMS 20, X20
- RestoreRegMS 21, X21
- RestoreRegMS 22, X22
- RestoreRegMS 23, X23
- RestoreRegMS 24, X24
- RestoreRegMS 25, X25
- RestoreRegMS 26, X26
- RestoreRegMS 27, X27
- RestoreRegMS 28, X28
- RestoreRegMS 29, X29
-
-Done
- ; Its imperative that the return value of HelperMethodFrameRestoreState is zero
- ; as it is used in the state machine to loop until it becomes zero.
- ; Refer to HELPER_METHOD_FRAME_END macro for details.
- mov x0,#0
- ret lr
-
- LEAF_END
-
; ------------------------------------------------------------------
; The call in ndirect import precode points to this function.
NESTED_ENTRY NDirectImportThunk
diff --git a/src/coreclr/vm/arm64/gmscpu.h b/src/coreclr/vm/arm64/gmscpu.h
deleted file mode 100644
index f33230702afc5f..00000000000000
--- a/src/coreclr/vm/arm64/gmscpu.h
+++ /dev/null
@@ -1,109 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-
-/**************************************************************/
-/* gmscpu.h */
-/**************************************************************/
-/* HelperFrame is defines 'GET_STATE(machState)' macro, which
- figures out what the state of the machine will be when the
- current method returns. It then stores the state in the
- JIT_machState structure. */
-
-/**************************************************************/
-
-#ifndef __gmscpu_h__
-#define __gmscpu_h__
-
-#define __gmscpu_h__
-
-// X19 - X29
-#define NUM_NONVOLATILE_CONTEXT_POINTERS 11
-
-struct MachState {
- ULONG64 captureX19_X29[NUM_NONVOLATILE_CONTEXT_POINTERS]; // preserved registers
- PTR_ULONG64 ptrX19_X29[NUM_NONVOLATILE_CONTEXT_POINTERS]; // pointers to preserved registers
- TADDR _pc; // program counter after the function returns
- TADDR _sp; // stack pointer after the function returns
- BOOL _isValid;
-#ifdef __APPLE__
- // libunwind on macOS doesn't support context pointers and we cannot modify the captureX19_X29,
- // so we store the unwound values in a separate array.
- ULONG64 unwoundX19_X29[NUM_NONVOLATILE_CONTEXT_POINTERS]; // preserved registers
-#endif // __APPLE__
-
- BOOL isValid() { LIMITED_METHOD_DAC_CONTRACT; return _isValid; }
- TADDR GetRetAddr() { LIMITED_METHOD_DAC_CONTRACT; return _pc; }
-};
-
-struct LazyMachState : public MachState{
-
- TADDR captureSp; // Stack pointer at the time of capture
- TADDR captureIp; // Instruction pointer at the time of capture
-
- void setLazyStateFromUnwind(MachState* copy);
- static void unwindLazyState(LazyMachState* baseState,
- MachState* lazyState,
- DWORD threadId,
- int funCallDepth = 1);
-};
-
-inline void LazyMachState::setLazyStateFromUnwind(MachState* copy)
-{
-#if defined(DACCESS_COMPILE)
- // This function cannot be called in DAC because DAC cannot update target memory.
- DacError(E_FAIL);
- return;
-
-#else // !DACCESS_COMPILE
-
- _sp = copy->_sp;
- _pc = copy->_pc;
-
-#ifdef __APPLE__
- memcpy(unwoundX19_X29, copy->unwoundX19_X29, sizeof(unwoundX19_X29));
-#endif // __APPLE__
-
- // Capture* has already been set, so there is no need to touch it
-
- // loop over the nonvolatile context pointers and make
- // sure to properly copy interior pointers into the
- // new struct
-
- PULONG64* pSrc = (PULONG64 *)©->ptrX19_X29;
- PULONG64* pDst = (PULONG64 *)&this->ptrX19_X29;
-
- const PULONG64 LowerBoundDst = (PULONG64) this;
- const PULONG64 LowerBoundSrc = (PULONG64) copy;
-
- const PULONG64 UpperBoundSrc = (PULONG64) ((BYTE*)LowerBoundSrc + sizeof(*copy));
-
- for (int i = 0; i < NUM_NONVOLATILE_CONTEXT_POINTERS; i++)
- {
- PULONG64 valueSrc = *pSrc++;
-
- if ((LowerBoundSrc <= valueSrc) && (valueSrc < UpperBoundSrc))
- {
- // make any pointer interior to 'src' interior to 'dst'
- valueSrc = (PULONG64)((BYTE*)valueSrc - (BYTE*)LowerBoundSrc + (BYTE*)LowerBoundDst);
- }
-
- *pDst++ = valueSrc;
- }
-
-
- // this has to be last because we depend on write ordering to
- // synchronize the race implicit in updating this struct
- VolatileStore(&_isValid, TRUE);
-#endif // DACCESS_COMPILE
-}
-
-// Do the initial capture of the machine state. This is meant to be
-// as light weight as possible, as we may never need the state that
-// we capture.
-EXTERN_C void LazyMachStateCaptureState(struct LazyMachState *pState);
-
-#define CAPTURE_STATE(machState, ret) \
- LazyMachStateCaptureState(machState)
-
-
-#endif
diff --git a/src/coreclr/vm/arm64/stubs.cpp b/src/coreclr/vm/arm64/stubs.cpp
index a06955d24a7012..9071e914091bcf 100644
--- a/src/coreclr/vm/arm64/stubs.cpp
+++ b/src/coreclr/vm/arm64/stubs.cpp
@@ -1,8 +1,6 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
-//
-// File: stubs.cpp
-//
+
// This file contains stub functions for unimplemented features need to
// run on the ARM64 platform.
@@ -278,269 +276,6 @@ void ClearRegDisplayArgumentAndScratchRegisters(REGDISPLAY * pRD)
pRD->volatileCurrContextPointers.X[i] = NULL;
}
-void LazyMachState::unwindLazyState(LazyMachState* baseState,
- MachState* unwoundstate,
- DWORD threadId,
- int funCallDepth)
-{
- T_CONTEXT context;
- T_KNONVOLATILE_CONTEXT_POINTERS nonVolContextPtrs;
-
- context.ContextFlags = 0; // Read by PAL_VirtualUnwind.
-
- context.X19 = unwoundstate->captureX19_X29[0] = baseState->captureX19_X29[0];
- context.X20 = unwoundstate->captureX19_X29[1] = baseState->captureX19_X29[1];
- context.X21 = unwoundstate->captureX19_X29[2] = baseState->captureX19_X29[2];
- context.X22 = unwoundstate->captureX19_X29[3] = baseState->captureX19_X29[3];
- context.X23 = unwoundstate->captureX19_X29[4] = baseState->captureX19_X29[4];
- context.X24 = unwoundstate->captureX19_X29[5] = baseState->captureX19_X29[5];
- context.X25 = unwoundstate->captureX19_X29[6] = baseState->captureX19_X29[6];
- context.X26 = unwoundstate->captureX19_X29[7] = baseState->captureX19_X29[7];
- context.X27 = unwoundstate->captureX19_X29[8] = baseState->captureX19_X29[8];
- context.X28 = unwoundstate->captureX19_X29[9] = baseState->captureX19_X29[9];
- context.Fp = unwoundstate->captureX19_X29[10] = baseState->captureX19_X29[10];
- context.Lr = 0; // Filled by the unwinder
-
- context.Sp = baseState->captureSp;
- context.Pc = baseState->captureIp;
-
-#if !defined(DACCESS_COMPILE)
- // For DAC, if we get here, it means that the LazyMachState is uninitialized and we have to unwind it.
- // The API we use to unwind in DAC is StackWalk64(), which does not support the context pointers.
- //
- // Restore the integer registers to KNONVOLATILE_CONTEXT_POINTERS to be used for unwinding.
- nonVolContextPtrs.X19 = &unwoundstate->captureX19_X29[0];
- nonVolContextPtrs.X20 = &unwoundstate->captureX19_X29[1];
- nonVolContextPtrs.X21 = &unwoundstate->captureX19_X29[2];
- nonVolContextPtrs.X22 = &unwoundstate->captureX19_X29[3];
- nonVolContextPtrs.X23 = &unwoundstate->captureX19_X29[4];
- nonVolContextPtrs.X24 = &unwoundstate->captureX19_X29[5];
- nonVolContextPtrs.X25 = &unwoundstate->captureX19_X29[6];
- nonVolContextPtrs.X26 = &unwoundstate->captureX19_X29[7];
- nonVolContextPtrs.X27 = &unwoundstate->captureX19_X29[8];
- nonVolContextPtrs.X28 = &unwoundstate->captureX19_X29[9];
- nonVolContextPtrs.Fp = &unwoundstate->captureX19_X29[10];
- nonVolContextPtrs.Lr = 0; // Filled by the unwinder
-
-#endif // DACCESS_COMPILE
-
- LOG((LF_GCROOTS, LL_INFO100000, "STACKWALK LazyMachState::unwindLazyState(ip:%p,sp:%p)\n", baseState->captureIp, baseState->captureSp));
-
- PCODE pvControlPc;
-
- do {
-
-#ifndef TARGET_UNIX
- pvControlPc = Thread::VirtualUnwindCallFrame(&context, &nonVolContextPtrs);
-#else // !TARGET_UNIX
-#ifdef DACCESS_COMPILE
- HRESULT hr = DacVirtualUnwind(threadId, &context, &nonVolContextPtrs);
- if (FAILED(hr))
- {
- DacError(hr);
- }
-#else // DACCESS_COMPILE
- BOOL success = PAL_VirtualUnwind(&context, &nonVolContextPtrs);
- if (!success)
- {
- _ASSERTE(!"unwindLazyState: Unwinding failed");
- EEPOLICY_HANDLE_FATAL_ERROR(COR_E_EXECUTIONENGINE);
- }
-#endif // DACCESS_COMPILE
- pvControlPc = GetIP(&context);
-#endif // !TARGET_UNIX
-
- if (funCallDepth > 0)
- {
- funCallDepth--;
- if (funCallDepth == 0)
- break;
- }
- else
- {
- // Determine whether given IP resides in JITted code. (It returns nonzero in that case.)
- // Use it now to see if we've unwound to managed code yet.
- BOOL fIsManagedCode = ExecutionManager::IsManagedCode(pvControlPc);
-
- if (fIsManagedCode)
- break;
-
- }
- } while (true);
-
-#ifdef __APPLE__
- unwoundstate->unwoundX19_X29[0] = context.X19;
- unwoundstate->unwoundX19_X29[1] = context.X20;
- unwoundstate->unwoundX19_X29[2] = context.X21;
- unwoundstate->unwoundX19_X29[3] = context.X22;
- unwoundstate->unwoundX19_X29[4] = context.X23;
- unwoundstate->unwoundX19_X29[5] = context.X24;
- unwoundstate->unwoundX19_X29[6] = context.X25;
- unwoundstate->unwoundX19_X29[7] = context.X26;
- unwoundstate->unwoundX19_X29[8] = context.X27;
- unwoundstate->unwoundX19_X29[9] = context.X28;
- unwoundstate->unwoundX19_X29[10] = context.Fp;
-#endif // __APPLE__
-
-#ifdef DACCESS_COMPILE
- // For DAC builds, we update the registers directly since we dont have context pointers
- unwoundstate->captureX19_X29[0] = context.X19;
- unwoundstate->captureX19_X29[1] = context.X20;
- unwoundstate->captureX19_X29[2] = context.X21;
- unwoundstate->captureX19_X29[3] = context.X22;
- unwoundstate->captureX19_X29[4] = context.X23;
- unwoundstate->captureX19_X29[5] = context.X24;
- unwoundstate->captureX19_X29[6] = context.X25;
- unwoundstate->captureX19_X29[7] = context.X26;
- unwoundstate->captureX19_X29[8] = context.X27;
- unwoundstate->captureX19_X29[9] = context.X28;
- unwoundstate->captureX19_X29[10] = context.Fp;
-#else // !DACCESS_COMPILE
- // For non-DAC builds, update the register state from context pointers
- unwoundstate->ptrX19_X29[0] = nonVolContextPtrs.X19;
- unwoundstate->ptrX19_X29[1] = nonVolContextPtrs.X20;
- unwoundstate->ptrX19_X29[2] = nonVolContextPtrs.X21;
- unwoundstate->ptrX19_X29[3] = nonVolContextPtrs.X22;
- unwoundstate->ptrX19_X29[4] = nonVolContextPtrs.X23;
- unwoundstate->ptrX19_X29[5] = nonVolContextPtrs.X24;
- unwoundstate->ptrX19_X29[6] = nonVolContextPtrs.X25;
- unwoundstate->ptrX19_X29[7] = nonVolContextPtrs.X26;
- unwoundstate->ptrX19_X29[8] = nonVolContextPtrs.X27;
- unwoundstate->ptrX19_X29[9] = nonVolContextPtrs.X28;
- unwoundstate->ptrX19_X29[10] = nonVolContextPtrs.Fp;
-#endif // DACCESS_COMPILE
-
- unwoundstate->_pc = context.Pc;
- unwoundstate->_sp = context.Sp;
-
- unwoundstate->_isValid = TRUE;
-}
-
-void HelperMethodFrame::UpdateRegDisplay_Impl(const PREGDISPLAY pRD, bool updateFloats)
-{
- CONTRACTL
- {
- NOTHROW;
- GC_NOTRIGGER;
- MODE_ANY;
- SUPPORTS_DAC;
- }
- CONTRACTL_END;
-
-#ifndef DACCESS_COMPILE
- if (updateFloats)
- {
- UpdateFloatingPointRegisters(pRD);
- _ASSERTE(pRD->pCurrentContext->Pc == GetReturnAddress());
- }
-#endif // DACCESS_COMPILE
-
- pRD->IsCallerContextValid = FALSE;
- pRD->IsCallerSPValid = FALSE; // Don't add usage of this field. This is only temporary.
-
- //
- // Copy the saved state from the frame to the current context.
- //
-
- LOG((LF_GCROOTS, LL_INFO100000, "STACKWALK HelperMethodFrame::UpdateRegDisplay cached ip:%p, sp:%p\n", m_MachState._pc, m_MachState._sp));
-
- #if defined(DACCESS_COMPILE)
- // For DAC, we may get here when the HMF is still uninitialized.
- // So we may need to unwind here.
- if (!m_MachState.isValid())
- {
- // This allocation throws on OOM.
- MachState* pUnwoundState = (MachState*)DacAllocHostOnlyInstance(sizeof(*pUnwoundState), true);
-
- EnsureInit(pUnwoundState);
-
- pRD->pCurrentContext->Pc = pRD->ControlPC = pUnwoundState->_pc;
- pRD->pCurrentContext->Sp = pRD->SP = pUnwoundState->_sp;
-
- pRD->pCurrentContext->X19 = (DWORD64)(pUnwoundState->captureX19_X29[0]);
- pRD->pCurrentContext->X20 = (DWORD64)(pUnwoundState->captureX19_X29[1]);
- pRD->pCurrentContext->X21 = (DWORD64)(pUnwoundState->captureX19_X29[2]);
- pRD->pCurrentContext->X22 = (DWORD64)(pUnwoundState->captureX19_X29[3]);
- pRD->pCurrentContext->X23 = (DWORD64)(pUnwoundState->captureX19_X29[4]);
- pRD->pCurrentContext->X24 = (DWORD64)(pUnwoundState->captureX19_X29[5]);
- pRD->pCurrentContext->X25 = (DWORD64)(pUnwoundState->captureX19_X29[6]);
- pRD->pCurrentContext->X26 = (DWORD64)(pUnwoundState->captureX19_X29[7]);
- pRD->pCurrentContext->X27 = (DWORD64)(pUnwoundState->captureX19_X29[8]);
- pRD->pCurrentContext->X28 = (DWORD64)(pUnwoundState->captureX19_X29[9]);
- pRD->pCurrentContext->Fp = (DWORD64)(pUnwoundState->captureX19_X29[10]);
- pRD->pCurrentContext->Lr = 0; // Unwind again to get Caller's PC
-
- pRD->pCurrentContextPointers->X19 = &pRD->pCurrentContext->X19;
- pRD->pCurrentContextPointers->X20 = &pRD->pCurrentContext->X20;
- pRD->pCurrentContextPointers->X21 = &pRD->pCurrentContext->X21;
- pRD->pCurrentContextPointers->X22 = &pRD->pCurrentContext->X22;
- pRD->pCurrentContextPointers->X23 = &pRD->pCurrentContext->X23;
- pRD->pCurrentContextPointers->X24 = &pRD->pCurrentContext->X24;
- pRD->pCurrentContextPointers->X25 = &pRD->pCurrentContext->X25;
- pRD->pCurrentContextPointers->X26 = &pRD->pCurrentContext->X26;
- pRD->pCurrentContextPointers->X27 = &pRD->pCurrentContext->X27;
- pRD->pCurrentContextPointers->X28 = &pRD->pCurrentContext->X28;
- pRD->pCurrentContextPointers->Fp = &pRD->pCurrentContext->Fp;
- pRD->pCurrentContextPointers->Lr = &pRD->pCurrentContext->Lr;
-
- return;
- }
-#endif // DACCESS_COMPILE
-
- // reset pContext; it's only valid for active (top-most) frame
- pRD->pContext = NULL;
- pRD->ControlPC = GetReturnAddress(); // m_MachState._pc;
- pRD->SP = (DWORD64)(size_t)m_MachState._sp;
-
- pRD->pCurrentContext->Pc = pRD->ControlPC;
- pRD->pCurrentContext->Sp = pRD->SP;
-
-#ifdef __APPLE__
- pRD->pCurrentContext->X19 = (DWORD64)(m_MachState.unwoundX19_X29[0]);
- pRD->pCurrentContext->X20 = (DWORD64)(m_MachState.unwoundX19_X29[1]);
- pRD->pCurrentContext->X21 = (DWORD64)(m_MachState.unwoundX19_X29[2]);
- pRD->pCurrentContext->X22 = (DWORD64)(m_MachState.unwoundX19_X29[3]);
- pRD->pCurrentContext->X23 = (DWORD64)(m_MachState.unwoundX19_X29[4]);
- pRD->pCurrentContext->X24 = (DWORD64)(m_MachState.unwoundX19_X29[5]);
- pRD->pCurrentContext->X25 = (DWORD64)(m_MachState.unwoundX19_X29[6]);
- pRD->pCurrentContext->X26 = (DWORD64)(m_MachState.unwoundX19_X29[7]);
- pRD->pCurrentContext->X27 = (DWORD64)(m_MachState.unwoundX19_X29[8]);
- pRD->pCurrentContext->X28 = (DWORD64)(m_MachState.unwoundX19_X29[9]);
- pRD->pCurrentContext->Fp = (DWORD64)(m_MachState.unwoundX19_X29[10]);
- pRD->pCurrentContext->Lr = 0; // Unwind again to get Caller's PC
-#else // __APPLE__
- pRD->pCurrentContext->X19 = *m_MachState.ptrX19_X29[0];
- pRD->pCurrentContext->X20 = *m_MachState.ptrX19_X29[1];
- pRD->pCurrentContext->X21 = *m_MachState.ptrX19_X29[2];
- pRD->pCurrentContext->X22 = *m_MachState.ptrX19_X29[3];
- pRD->pCurrentContext->X23 = *m_MachState.ptrX19_X29[4];
- pRD->pCurrentContext->X24 = *m_MachState.ptrX19_X29[5];
- pRD->pCurrentContext->X25 = *m_MachState.ptrX19_X29[6];
- pRD->pCurrentContext->X26 = *m_MachState.ptrX19_X29[7];
- pRD->pCurrentContext->X27 = *m_MachState.ptrX19_X29[8];
- pRD->pCurrentContext->X28 = *m_MachState.ptrX19_X29[9];
- pRD->pCurrentContext->Fp = *m_MachState.ptrX19_X29[10];
- pRD->pCurrentContext->Lr = 0; // Unwind again to get Caller's PC
-#endif // __APPLE__
-
-#if !defined(DACCESS_COMPILE)
- pRD->pCurrentContextPointers->X19 = m_MachState.ptrX19_X29[0];
- pRD->pCurrentContextPointers->X20 = m_MachState.ptrX19_X29[1];
- pRD->pCurrentContextPointers->X21 = m_MachState.ptrX19_X29[2];
- pRD->pCurrentContextPointers->X22 = m_MachState.ptrX19_X29[3];
- pRD->pCurrentContextPointers->X23 = m_MachState.ptrX19_X29[4];
- pRD->pCurrentContextPointers->X24 = m_MachState.ptrX19_X29[5];
- pRD->pCurrentContextPointers->X25 = m_MachState.ptrX19_X29[6];
- pRD->pCurrentContextPointers->X26 = m_MachState.ptrX19_X29[7];
- pRD->pCurrentContextPointers->X27 = m_MachState.ptrX19_X29[8];
- pRD->pCurrentContextPointers->X28 = m_MachState.ptrX19_X29[9];
- pRD->pCurrentContextPointers->Fp = m_MachState.ptrX19_X29[10];
- pRD->pCurrentContextPointers->Lr = 0; // Unwind again to get Caller's PC
-#endif
-
- ClearRegDisplayArgumentAndScratchRegisters(pRD);
-}
-
void UpdateRegDisplayFromCalleeSavedRegisters(REGDISPLAY * pRD, CalleeSavedRegisters * pCalleeSaved)
{
LIMITED_METHOD_CONTRACT;
@@ -573,7 +308,6 @@ void UpdateRegDisplayFromCalleeSavedRegisters(REGDISPLAY * pRD, CalleeSavedRegis
pContextPointers->Lr = (PDWORD64)&pCalleeSaved->x30;
}
-
void TransitionFrame::UpdateRegDisplay_Impl(const PREGDISPLAY pRD, bool updateFloats)
{
#ifndef DACCESS_COMPILE
@@ -605,8 +339,6 @@ void TransitionFrame::UpdateRegDisplay_Impl(const PREGDISPLAY pRD, bool updateFl
LOG((LF_GCROOTS, LL_INFO100000, "STACKWALK TransitionFrame::UpdateRegDisplay_Impl(pc:%p, sp:%p)\n", pRD->ControlPC, pRD->SP));
}
-
-
void FaultingExceptionFrame::UpdateRegDisplay_Impl(const PREGDISPLAY pRD, bool updateFloats)
{
LIMITED_METHOD_DAC_CONTRACT;
@@ -892,7 +624,7 @@ AdjustContextForVirtualStub(
#ifdef FEATURE_CACHED_INTERFACE_DISPATCH
if (VirtualCallStubManager::isCachedInterfaceDispatchStubAVLocation(f_IP))
{
- isVirtualStubNullCheck = true;
+ isVirtualStubNullCheck = true;
}
#endif // FEATURE_CACHED_INTERFACE_DISPATCH
#ifdef FEATURE_VIRTUAL_STUB_DISPATCH
diff --git a/src/coreclr/vm/common.h b/src/coreclr/vm/common.h
index 3d4ff5e9610065..d4be1f1f00d4a6 100644
--- a/src/coreclr/vm/common.h
+++ b/src/coreclr/vm/common.h
@@ -1,12 +1,10 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
+
//
// common.h - precompiled headers include for the CLR Execution Engine
//
-//
-
-
#ifndef _common_h_
#define _common_h_
@@ -289,7 +287,6 @@ namespace Loader
#include "synch.h"
#include "regdisp.h"
#include "stackframe.h"
-#include "gms.h"
#include "fcall.h"
#include "syncblk.h"
#include "gcdesc.h"
diff --git a/src/coreclr/vm/comutilnative.cpp b/src/coreclr/vm/comutilnative.cpp
index 58764432a16893..8b94eb98ddd22c 100644
--- a/src/coreclr/vm/comutilnative.cpp
+++ b/src/coreclr/vm/comutilnative.cpp
@@ -578,8 +578,6 @@ FCIMPL0(INT64, GCInterface::GetTotalPauseDuration)
{
FCALL_CONTRACT;
- FC_GC_POLL_NOT_NEEDED();
-
return GCHeapUtilities::GetGCHeap()->GetTotalPauseDuration();
}
FCIMPLEND
@@ -588,8 +586,6 @@ FCIMPL2(void, GCInterface::GetMemoryInfo, Object* objUNSAFE, int kind)
{
FCALL_CONTRACT;
- FC_GC_POLL_NOT_NEEDED();
-
GCMEMORYINFODATAREF objGCMemoryInfo = (GCMEMORYINFODATAREF)(ObjectToOBJECTREF (objUNSAFE));
UINT64* genInfoRaw = (UINT64*)&(objGCMemoryInfo->generationInfo0);
@@ -620,8 +616,6 @@ FCIMPL0(UINT32, GCInterface::GetMemoryLoad)
{
FCALL_CONTRACT;
- FC_GC_POLL_NOT_NEEDED();
-
int result = (INT32)GCHeapUtilities::GetGCHeap()->GetMemoryLoad();
return result;
}
@@ -631,8 +625,6 @@ FCIMPL0(int, GCInterface::GetGcLatencyMode)
{
FCALL_CONTRACT;
- FC_GC_POLL_NOT_NEEDED();
-
int result = (INT32)GCHeapUtilities::GetGCHeap()->GetGcLatencyMode();
return result;
}
@@ -642,8 +634,6 @@ FCIMPL1(int, GCInterface::SetGcLatencyMode, int newLatencyMode)
{
FCALL_CONTRACT;
- FC_GC_POLL_NOT_NEEDED();
-
return GCHeapUtilities::GetGCHeap()->SetGcLatencyMode(newLatencyMode);
}
FCIMPLEND
@@ -652,8 +642,6 @@ FCIMPL0(int, GCInterface::GetLOHCompactionMode)
{
FCALL_CONTRACT;
- FC_GC_POLL_NOT_NEEDED();
-
int result = (INT32)GCHeapUtilities::GetGCHeap()->GetLOHCompactionMode();
return result;
}
@@ -663,8 +651,6 @@ FCIMPL1(void, GCInterface::SetLOHCompactionMode, int newLOHCompactionyMode)
{
FCALL_CONTRACT;
- FC_GC_POLL_NOT_NEEDED();
-
GCHeapUtilities::GetGCHeap()->SetLOHCompactionMode(newLOHCompactionyMode);
}
FCIMPLEND
@@ -674,8 +660,6 @@ FCIMPL2(FC_BOOL_RET, GCInterface::RegisterForFullGCNotification, UINT32 gen2Perc
{
FCALL_CONTRACT;
- FC_GC_POLL_NOT_NEEDED();
-
FC_RETURN_BOOL(GCHeapUtilities::GetGCHeap()->RegisterForFullGCNotification(gen2Percentage, lohPercentage));
}
FCIMPLEND
@@ -684,7 +668,6 @@ FCIMPL0(FC_BOOL_RET, GCInterface::CancelFullGCNotification)
{
FCALL_CONTRACT;
- FC_GC_POLL_NOT_NEEDED();
FC_RETURN_BOOL(GCHeapUtilities::GetGCHeap()->CancelFullGCNotification());
}
FCIMPLEND
diff --git a/src/coreclr/vm/ecall.cpp b/src/coreclr/vm/ecall.cpp
index ca48e537c0aab4..84745cde7c341f 100644
--- a/src/coreclr/vm/ecall.cpp
+++ b/src/coreclr/vm/ecall.cpp
@@ -98,9 +98,6 @@ void ECall::PopulateManagedStringConstructors()
static CrstStatic gFCallLock;
-// This variable is used to force the compiler not to tailcall a function.
-RAW_KEYWORD(volatile) int FC_NO_TAILCALL;
-
#endif // !DACCESS_COMPILE
// To provide a quick check, this is the lowest and highest
@@ -530,11 +527,6 @@ void ECall::Init()
CONTRACTL_END;
gFCallLock.Init(CrstFCall);
-
- // It is important to do an explicit increment here instead of just in-place initialization
- // so that the global optimizer cannot figure out the value and remove the side-effect that
- // we depend on in FC_INNER_RETURN macros and other places
- FC_NO_TAILCALL++;
}
#endif // !DACCESS_COMPILE
diff --git a/src/coreclr/vm/exceptmacros.h b/src/coreclr/vm/exceptmacros.h
index 959d326324671b..aa8e0956f58527 100644
--- a/src/coreclr/vm/exceptmacros.h
+++ b/src/coreclr/vm/exceptmacros.h
@@ -384,16 +384,6 @@ VOID DECLSPEC_NORETURN DispatchManagedException(PAL_SEHException& ex, bool isHar
/* The purpose of the INSTALL_UNWIND_AND_CONTINUE_HANDLER is to translate an exception to a managed */ \
/* exception before it hits managed code. */
-// Optimized version for helper method frame. Avoids redundant GetThread() calls.
-#define INSTALL_UNWIND_AND_CONTINUE_HANDLER_FOR_HMF(pHelperFrame) \
- { \
- Exception* __pUnCException = NULL; \
- Frame* __pUnCEntryFrame = (pHelperFrame); \
- bool __fExceptionCaught = false; \
- SCAN_EHMARKER(); \
- if (true) PAL_CPP_TRY { \
- SCAN_EHMARKER_TRY();
-
#define UNINSTALL_UNWIND_AND_CONTINUE_HANDLER_EX(nativeRethrow) \
SCAN_EHMARKER_END_TRY(); \
} \
diff --git a/src/coreclr/vm/fcall.cpp b/src/coreclr/vm/fcall.cpp
index 0da0fc6a63e2a7..74ea17bd310f65 100644
--- a/src/coreclr/vm/fcall.cpp
+++ b/src/coreclr/vm/fcall.cpp
@@ -1,17 +1,11 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
-// FCALL.CPP
-//
-
-//
-
#include "common.h"
#include "vars.hpp"
#include "fcall.h"
#include "excep.h"
#include "frames.h"
-#include "gms.h"
#include "ecall.h"
#include "eeconfig.h"
@@ -57,188 +51,4 @@ DEBUG_NOINLINE ForbidGC::~ForbidGC()
m_pThread->EndNoTriggerGC();
}
-/**************************************************************************************/
-DEBUG_NOINLINE FCallCheck::FCallCheck(const char *szFile, int lineNum) : ForbidGC(szFile, lineNum)
-{
- SCAN_SCOPE_BEGIN;
- STATIC_CONTRACT_GC_NOTRIGGER;
- STATIC_CONTRACT_MODE_COOPERATIVE;
-
-#ifdef _DEBUG
- unbreakableLockCount = m_pThread->GetUnbreakableLockCount();
-#endif
- didGCPoll = false;
- notNeeded = false;
- startTicks = getCycleCount();
-}
-
-/**************************************************************************************/
-DEBUG_NOINLINE FCallCheck::~FCallCheck()
-{
- SCAN_SCOPE_END;
-
- // Confirm that we don't starve the GC or thread-abort.
- // Basically every control flow path through an FCALL must
- // to a poll. If you hit the assert below, you can fix it by
- //
- // If you erect a HELPER_METHOD_FRAME, you can
- //
- // Call HELPER_METHOD_POLL()
- // or use HELPER_METHOD_FRAME_END_POLL
-
- _ASSERTE(unbreakableLockCount == m_pThread->GetUnbreakableLockCount() ||
- (!m_pThread->HasUnbreakableLock() && !m_pThread->HasThreadStateNC(Thread::TSNC_OwnsSpinLock)));
-
- if (notNeeded) {
-
- /* TODO, we want to actually measure the time to make certain we are not too far off
-
- unsigned delta = unsigned(getCycleCount() - startTicks);
- */
- }
- else if (!didGCPoll) {
- // TODO turn this on!!! _ASSERTE(!"FCALL without a GC poll in it somewhere!");
- }
-
-}
-
-
-#if defined(TARGET_AMD64)
-
-
-FCallTransitionState::FCallTransitionState ()
-{
- WRAPPER_NO_CONTRACT;
-
- m_pThread = GetThread();
- m_pPreviousHelperMethodFrameCallerList = m_pThread->m_pHelperMethodFrameCallerList;
- m_pThread->m_pHelperMethodFrameCallerList = NULL;
-}
-
-
-FCallTransitionState::~FCallTransitionState ()
-{
- WRAPPER_NO_CONTRACT;
-
- m_pThread->m_pHelperMethodFrameCallerList = m_pPreviousHelperMethodFrameCallerList;
-}
-
-
-PermitHelperMethodFrameState::PermitHelperMethodFrameState ()
-{
- WRAPPER_NO_CONTRACT;
-
- m_pThread = GetThread();
- CONSISTENCY_CHECK_MSG((HelperMethodFrameCallerList*)-1 != m_pThread->m_pHelperMethodFrameCallerList,
- "fcall entry point is missing a FCALL_TRANSITION_BEGIN or a FCIMPL\n");
-
- m_ListEntry.pCaller = m_pThread->m_pHelperMethodFrameCallerList;
- m_pThread->m_pHelperMethodFrameCallerList = &m_ListEntry;
-}
-
-
-PermitHelperMethodFrameState::~PermitHelperMethodFrameState ()
-{
- WRAPPER_NO_CONTRACT;
-
- m_pThread->m_pHelperMethodFrameCallerList = m_ListEntry.pCaller;
-}
-
-
-VOID PermitHelperMethodFrameState::CheckHelperMethodFramePermitted ()
-{
- CONTRACTL {
- NOTHROW;
- GC_NOTRIGGER;
- DEBUG_ONLY;
- } CONTRACTL_END;
-
- //
- // Get current context and unwind to caller
- //
-
- CONTEXT ctx;
-
- ClrCaptureContext(&ctx);
- Thread::VirtualUnwindCallFrame(&ctx);
-
- //
- // Make sure each unmanaged frame used PERMIT_HELPER_METHOD_FRAME_BEGIN.
- // If we hit NULL before we reach managed code, then the caller of the
- // fcall was not managed.
- //
-
- Thread *pThread = GetThread();
- HelperMethodFrameCallerList *pList = pThread->m_pHelperMethodFrameCallerList;
- PCODE CurrentIP;
- TADDR CurrentSP;
-
- do
- {
- CurrentSP = GetSP(&ctx);
- CurrentIP = GetIP(&ctx);
-
- Thread::VirtualUnwindCallFrame(&ctx);
-
- TADDR CallerSP = GetSP(&ctx);
-
- unsigned nAssociatedListEntries = 0;
-
- while ( (SIZE_T)pList >= (SIZE_T)CurrentSP
- && (SIZE_T)pList < (SIZE_T)CallerSP)
- {
- nAssociatedListEntries++;
- pList = pList->pCaller;
- }
-
- if (!nAssociatedListEntries)
- {
- char szFunction[cchMaxAssertStackLevelStringLen];
- GetStringFromAddr((DWORD_PTR)CurrentIP, szFunction);
-
- CONSISTENCY_CHECK_MSGF(false, ("Unmanaged caller %s at sp %p/ip %p is missing a "
- "PERMIT_HELPER_METHOD_FRAME_BEGIN, or this function "
- "is calling an fcall entry point that is missing a "
- "FCALL_TRANSITION_BEGIN or a FCIMPL\n", szFunction, CurrentSP, CurrentIP));
- }
- }
- while (pList && !ExecutionManager::IsManagedCode(GetIP(&ctx)));
-
- //
- // We should have exhausted the list. If not, the list was not reset at
- // the transition from managed code.
- //
-
- if (pList)
- {
- char szFunction[cchMaxAssertStackLevelStringLen];
- GetStringFromAddr((DWORD_PTR)CurrentIP, szFunction);
-
- CONSISTENCY_CHECK_MSGF(false, ("fcall entry point %s at sp %p/ip %p is missing a "
- "FCALL_TRANSITION_BEGIN or a FCIMPL\n", szFunction, CurrentSP, CurrentIP));
- }
-}
-
-
-CompletedFCallTransitionState::CompletedFCallTransitionState ()
-{
- WRAPPER_NO_CONTRACT;
-
- Thread *pThread = GetThread();
- m_pLastHelperMethodFrameCallerList = pThread->m_pHelperMethodFrameCallerList;
- pThread->m_pHelperMethodFrameCallerList = (HelperMethodFrameCallerList*)-1;
-}
-
-
-CompletedFCallTransitionState::~CompletedFCallTransitionState ()
-{
- WRAPPER_NO_CONTRACT;
-
- Thread *pThread = GetThread();
- pThread->m_pHelperMethodFrameCallerList = m_pLastHelperMethodFrameCallerList;
-}
-
-
-#endif // TARGET_AMD64
-
#endif // ENABLE_CONTRACTS
diff --git a/src/coreclr/vm/fcall.h b/src/coreclr/vm/fcall.h
index efa2749d56d221..e3f1637ebbfca7 100644
--- a/src/coreclr/vm/fcall.h
+++ b/src/coreclr/vm/fcall.h
@@ -1,91 +1,13 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
-// FCall.H
-//
-
-//
-// FCall is a high-performance alternative to ECall. Unlike ECall, FCall
-// methods do not necessarily create a frame. Jitted code calls directly
-// to the FCall entry point. It is possible to do operations that need
-// to have a frame within an FCall, you need to manually set up the frame
-// before you do such operations.
-
-// It is illegal to cause a GC or EH to happen in an FCALL before setting
-// up a frame. To prevent accidentally violating this rule, FCALLs turn
-// on BEGINGCFORBID, which ensures that these things can't happen in a
-// checked build without causing an ASSERTE. Once you set up a frame,
-// this state is turned off as long as the frame is active, and then is
-// turned on again when the frame is torn down. This mechanism should
-// be sufficient to ensure that the rules are followed.
-
-// In general you set up a frame by using the following macros
-
-// HELPER_METHOD_FRAME_BEGIN_RET*() // Use If the FCALL has a return value
-// HELPER_METHOD_FRAME_BEGIN*() // Use If FCALL does not return a value
-// HELPER_METHOD_FRAME_END*()
-// These macros introduce a scope which is protected by an HelperMethodFrame.
-// In this scope you can do EH or GC. There are rules associated with
-// their use. In particular
+// FCall is a high-performance call into unmanaged runtime code from managed code.
+// The managed code calls the FCall entry point directly.
-// 1) These macros can only be used in the body of a FCALL (that is
-// something using the FCIMPL* or HCIMPL* macros for their decaration.
-
-// 2) You may not perform a 'return' within this scope..
+// Causing GC or EH in an FCALL is illegal. QCalls should be used instead.
// Compile time errors occur if you try to violate either of these rules.
-// The frame that is set up does NOT protect any GC variables (in particular the
-// arguments of the FCALL. Thus you need to do an explicit GCPROTECT once the
-// frame is established if you need to protect an argument. There are flavors
-// of HELPER_METHOD_FRAME that protect a certain number of GC variables. For
-// example
-
-// HELPER_METHOD_FRAME_BEGIN_RET_2(arg1, arg2)
-
-// will protect the GC variables arg1, and arg2 as well as erecting the frame.
-
-// Another invariant that you must be aware of is the need to poll to see if
-// a GC is needed by some other thread. Unless the FCALL is VERY short,
-// every code path through the FCALL must do such a poll. The important
-// thing here is that a poll will cause a GC, and thus you can only do it
-// when all you GC variables are protected. To make things easier
-// HELPER_METHOD_FRAMES that protect things automatically do this poll.
-// If you don't need to protect anything HELPER_METHOD_FRAME_BEGIN_0
-// will also do the poll.
-
-// Sometimes it is convenient to do the poll a the end of the frame, you
-// can use HELPER_METHOD_FRAME_BEGIN_NOPOLL and HELPER_METHOD_FRAME_END_POLL
-// to do the poll at the end. If somewhere in the middle is the best
-// place you can do that too with HELPER_METHOD_POLL()
-
-// Finally if your method is VERY small, you can get away without a poll,
-// you have to use FC_GC_POLL_NOT_NEEDED to mark this.
-// Use sparingly!
-
-// It is possible to set up the frame as the first operation in the FCALL and
-// tear it down as the last operation before returning. This works and is
-// reasonably efficient (as good as an ECall), however, if it is the case that
-// you can defer the setup of the frame to an unlikely code path (exception path)
-// that is much better.
-
-// If you defer setup of the frame, all codepaths leading to the frame setup
-// must be wrapped with PERMIT_HELPER_METHOD_FRAME_BEGIN/END. These block
-// certain compiler optimizations that interfere with the delayed frame setup.
-// These macros are automatically included in the HCIMPL, FCIMPL, and frame
-// setup macros.
-
-// TODO: we should have a way of doing a trial allocation (an allocation that
-// will fail if it would cause a GC). That way even FCALLs that need to allocate
-// would not necessarily need to set up a frame.
-
-// It is common to only need to set up a frame in order to throw an exception.
-// While this can be done by doing
-
-// HELPER_METHOD_FRAME_BEGIN() // Use if FCALL does not return a value
-// COMPlusThrow(execpt);
-// HELPER_METHOD_FRAME_END()
-
// Since FCALLS have to conform to the EE calling conventions and not to C
// calling conventions, FCALLS, need to be declared using special macros (FCIMPL*)
// that implement the correct calling conventions. There are variants of these
@@ -126,31 +48,6 @@
// UINT64) and floating-point values (i.e. FLOAT or DOUBLE). For example, FCDECL3_IVI
// must be used for FCalls that take 3 arguments and 2nd argument is INT64 and
// FDECL2_VV must be used for FCalls that take 2 arguments where both are FLOAT.
-//
-// - You may use structs for protecting multiple OBJECTREF's simultaneously.
-// In these cases, you must use a variant of a helper method frame with PROTECT
-// in the name, to ensure all the OBJECTREF's in the struct get protected.
-// Also, initialize all the OBJECTREF's first. Like this:
-//
-// FCIMPL4(Object*, COMNlsInfo::nativeChangeCaseString, LocaleIDObject* localeUNSAFE,
-// INT_PTR pNativeTextInfo, StringObject* pStringUNSAFE, FC_BOOL_ARG bIsToUpper)
-// {
-// [ignoring CONTRACT for now]
-// struct _gc
-// {
-// STRINGREF pResult;
-// STRINGREF pString;
-// LOCALEIDREF pLocale;
-// } gc;
-// gc.pResult = NULL;
-// gc.pString = ObjectToSTRINGREF(pStringUNSAFE);
-// gc.pLocale = (LOCALEIDREF)ObjectToOBJECTREF(localeUNSAFE);
-//
-// HELPER_METHOD_FRAME_BEGIN_RET_PROTECT(gc)
-//
-// If you forgot the PROTECT part, the macro will only protect the first OBJECTREF,
-// introducing a subtle GC hole in your code. Fortunately, we now issue a
-// compile-time error if you forget.
// How FCall works:
// ----------------
@@ -161,150 +58,9 @@
#ifndef __FCall_h__
#define __FCall_h__
-#include "gms.h"
#include "runtimeexceptionkind.h"
#include "debugreturn.h"
-//==============================================================================================
-// These macros defeat compiler optimizations that might mix nonvolatile
-// register loads and stores with other code in the function body. This
-// creates problems for the frame setup code, which assumes that any
-// nonvolatiles that are saved at the point of the frame setup will be
-// re-loaded when the frame is popped.
-//
-// Currently this is only known to be an issue on AMD64. It's uncertain
-// whether it is an issue on x86.
-//==============================================================================================
-
-#if defined(TARGET_AMD64) && !defined(TARGET_UNIX)
-
-//
-// On AMD64 this is accomplished by including a setjmp anywhere in a function.
-// Doesn't matter whether it is reachable or not, and in fact in optimized
-// builds the setjmp is removed altogether.
-//
-#include
-
-#ifdef _DEBUG
-//
-// Linked list of unmanaged methods preceding a HelperMethodFrame push. This
-// is linked onto the current Thread. Each list entry is stack-allocated so it
-// can be associated with an unmanaged frame. Each unmanaged frame needs to be
-// associated with at least one list entry.
-//
-struct HelperMethodFrameCallerList
-{
- HelperMethodFrameCallerList *pCaller;
-};
-#endif // _DEBUG
-
-//
-// Resets the Thread state at a new managed -> fcall transition.
-//
-class FCallTransitionState
-{
-public:
-
- FCallTransitionState () NOT_DEBUG({ LIMITED_METHOD_CONTRACT; });
- ~FCallTransitionState () NOT_DEBUG({ LIMITED_METHOD_CONTRACT; });
-
-#ifdef _DEBUG
-private:
- Thread *m_pThread;
- HelperMethodFrameCallerList *m_pPreviousHelperMethodFrameCallerList;
-#endif // _DEBUG
-};
-
-//
-// Pushes/pops state for each caller.
-//
-class PermitHelperMethodFrameState
-{
-public:
-
- PermitHelperMethodFrameState () NOT_DEBUG({ LIMITED_METHOD_CONTRACT; });
- ~PermitHelperMethodFrameState () NOT_DEBUG({ LIMITED_METHOD_CONTRACT; });
-
- static VOID CheckHelperMethodFramePermitted () NOT_DEBUG({ LIMITED_METHOD_CONTRACT; });
-
-#ifdef _DEBUG
-private:
- Thread *m_pThread;
- HelperMethodFrameCallerList m_ListEntry;
-#endif // _DEBUG
-};
-
-//
-// Resets the Thread state after the HelperMethodFrame is pushed. At this
-// point, the HelperMethodFrame is capable of unwinding to the managed code,
-// so we can reset the Thread state for any nested fcalls.
-//
-class CompletedFCallTransitionState
-{
-public:
-
- CompletedFCallTransitionState () NOT_DEBUG({ LIMITED_METHOD_CONTRACT; });
- ~CompletedFCallTransitionState () NOT_DEBUG({ LIMITED_METHOD_CONTRACT; });
-
-#ifdef _DEBUG
-private:
-
- HelperMethodFrameCallerList *m_pLastHelperMethodFrameCallerList;
-#endif // _DEBUG
-};
-
-// These macros are used to narrowly suppress
-// warning 4611 - interaction between 'function' and C++ object destruction is non-portable
-// See usage of setjmp() and inclusion of setjmp.h for reasoning behind usage.
-#ifdef _MSC_VER
-#define DISABLE_4611() \
- _Pragma("warning(push)") \
- _Pragma("warning(disable:4611)")
-
-#define RESET_4611() \
- _Pragma("warning(pop)")
-#else
-#define DISABLE_4611()
-#define RESET_4611()
-#endif // _MSC_VER
-
-#define PERMIT_HELPER_METHOD_FRAME_BEGIN() \
- if (1) \
- { \
- PermitHelperMethodFrameState ___PermitHelperMethodFrameState;
-
-#define PERMIT_HELPER_METHOD_FRAME_END() \
- } \
- else \
- { \
- jmp_buf ___jmpbuf; \
- DISABLE_4611() \
- setjmp(___jmpbuf); \
- RESET_4611() \
- __assume(0); \
- }
-
-#define FCALL_TRANSITION_BEGIN() \
- FCallTransitionState ___FCallTransitionState; \
- PERMIT_HELPER_METHOD_FRAME_BEGIN();
-
-#define FCALL_TRANSITION_END() \
- PERMIT_HELPER_METHOD_FRAME_END();
-
-#define CHECK_HELPER_METHOD_FRAME_PERMITTED() \
- PermitHelperMethodFrameState::CheckHelperMethodFramePermitted(); \
- CompletedFCallTransitionState ___CompletedFCallTransitionState;
-
-#else // unsupported processor
-
-#define PERMIT_HELPER_METHOD_FRAME_BEGIN()
-#define PERMIT_HELPER_METHOD_FRAME_END()
-#define FCALL_TRANSITION_BEGIN()
-#define FCALL_TRANSITION_END()
-#define CHECK_HELPER_METHOD_FRAME_PERMITTED()
-
-#endif // unsupported processor
-
//==============================================================================================
// FDECLn: A set of macros for generating header declarations for FC targets.
// Use FIMPLn for the actual body.
@@ -313,11 +69,9 @@ class CompletedFCallTransitionState
// Note: on the x86, these defs reverse all but the first two arguments
// (IL stack calling convention is reversed from __fastcall.)
-
// Calling convention for varargs
#define F_CALL_VA_CONV __cdecl
-
#ifdef TARGET_X86
// Choose the appropriate calling convention for FCALL helpers on the basis of the JIT calling convention
@@ -408,28 +162,6 @@ class CompletedFCallTransitionState
#endif // !SWIZZLE_REGARG_ORDER
-#if 0
-//
-// don't use something like this... directly calling an FCALL from within the runtime breaks stackwalking because
-// the FCALL reverse mapping only gets established in ECall::GetFCallImpl and that codepath is circumvented by
-// directly calling and FCALL
-// See below for usage of FC_CALL_INNER (used in SecurityStackWalk::Check presently)
-//
-#define FCCALL0(funcname) funcname()
-#define FCCALL1(funcname, a1) funcname(a1)
-#define FCCALL2(funcname, a1, a2) funcname(a1, a2)
-#define FCCALL3(funcname, a1, a2, a3) funcname(a1, a2, a3)
-#define FCCALL4(funcname, a1, a2, a3, a4) funcname(a1, a2, a4, a3)
-#define FCCALL5(funcname, a1, a2, a3, a4, a5) funcname(a1, a2, a5, a4, a3)
-#define FCCALL6(funcname, a1, a2, a3, a4, a5, a6) funcname(a1, a2, a6, a5, a4, a3)
-#define FCCALL7(funcname, a1, a2, a3, a4, a5, a6, a7) funcname(a1, a2, a7, a6, a5, a4, a3)
-#define FCCALL8(funcname, a1, a2, a3, a4, a5, a6, a7, a8) funcname(a1, a2, a8, a7, a6, a5, a4, a3)
-#define FCCALL9(funcname, a1, a2, a3, a4, a5, a6, a7, a8, a9) funcname(a1, a2, a9, a8, a7, a6, a5, a4, a3)
-#define FCCALL10(funcname, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10) funcname(a1, a2, a10, a9, a8, a7, a6, a5, a4, a3)
-#define FCCALL11(funcname, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11) funcname(a1, a2, a11, a10, a9, a8, a7, a6, a5, a4, a3)
-#define FCCALL12(funcname, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12) funcname(a1, a2, a12, a11, a10, a9, a8, a7, a6, a5, a4, a3)
-#endif // 0
-
#else // !SWIZZLE_STKARG_ORDER
#define FCDECL0(rettype, funcname) rettype F_CALL_CONV funcname()
@@ -464,264 +196,6 @@ class CompletedFCallTransitionState
#endif // !SWIZZLE_STKARG_ORDER
-#define HELPER_FRAME_DECL(x) HelperMethodFrame_##x##OBJ __helperframe
-
-// use the capture state machinery if the architecture has one
-//
-// For a normal build we create a loop (see explanation on RestoreState below)
-// We don't want a loop here for PREFAST since that causes
-// warning 263: Using _alloca in a loop
-// And we can't use DEBUG_OK_TO_RETURN for PREFAST because the PREFAST version
-// requires that you already be in a DEBUG_ASSURE_NO_RETURN_BEGIN scope
-
-#define HelperMethodFrame_0OBJ HelperMethodFrame
-#define HELPER_FRAME_ARGS(attribs) __me, attribs
-#define FORLAZYMACHSTATE(x) x
-#define FORLAZYMACHSTATE_BEGINLOOP(x) x do
-#define FORLAZYMACHSTATE_ENDLOOP(x) while(x)
-
-// BEGIN: before gcpoll
-//FCallGCCanTriggerNoDtor __fcallGcCanTrigger;
-//__fcallGcCanTrigger.Enter();
-
-// END: after gcpoll
-//__fcallGcCanTrigger.Leave(__FUNCTION__, __FILE__, __LINE__);
-
-#define HELPER_METHOD_FRAME_BEGIN_EX_BODY(ret, helperFrame, gcpoll, allowGC) \
- FORLAZYMACHSTATE_BEGINLOOP(int alwaysZero = 0;) \
- { \
- INDEBUG(static BOOL __haveCheckedRestoreState = FALSE;) \
- PERMIT_HELPER_METHOD_FRAME_BEGIN(); \
- CHECK_HELPER_METHOD_FRAME_PERMITTED(); \
- helperFrame; \
- FORLAZYMACHSTATE(CAPTURE_STATE(__helperframe.MachineState(), ret);) \
- INDEBUG(__helperframe.SetAddrOfHaveCheckedRestoreState(&__haveCheckedRestoreState)); \
- DEBUG_ASSURE_NO_RETURN_BEGIN(HELPER_METHOD_FRAME); \
- INCONTRACT(FCallGCCanTrigger::Enter());
-
-#define HELPER_METHOD_FRAME_BEGIN_EX(ret, helperFrame, gcpoll, allowGC) \
- HELPER_METHOD_FRAME_BEGIN_EX_BODY(ret, helperFrame, gcpoll, allowGC) \
- /* TODO TURN THIS ON!!! */ \
- /* gcpoll; */ \
- __helperframe.Push(); \
- INSTALL_MANAGED_EXCEPTION_DISPATCHER; \
- MAKE_CURRENT_THREAD_AVAILABLE_EX(__helperframe.GetThread()); \
- INSTALL_UNWIND_AND_CONTINUE_HANDLER_FOR_HMF(&__helperframe);
-
-#define HELPER_METHOD_FRAME_BEGIN_EX_NOTHROW(ret, helperFrame, gcpoll, allowGC, probeFailExpr) \
- HELPER_METHOD_FRAME_BEGIN_EX_BODY(ret, helperFrame, gcpoll, allowGC) \
- __helperframe.Push(); \
- MAKE_CURRENT_THREAD_AVAILABLE_EX(__helperframe.GetThread()); \
- /* TODO TURN THIS ON!!! */ \
- /* gcpoll; */
-
-// The while(__helperframe.RestoreState() needs a bit of explanation.
-// The issue is ensuring that the same machine state (which registers saved)
-// exists when the machine state is probed (when the frame is created, and
-// when it is actually used (when the frame is popped. We do this by creating
-// a flow of control from use to def. Note that 'RestoreState' always returns false
-// we never actually loop, but the compiler does not know that, and thus
-// will be forced to make the keep the state of register spills the same at
-// the two locations.
-
-#define HELPER_METHOD_FRAME_END_EX_BODY(gcpoll,allowGC) \
- /* TODO TURN THIS ON!!! */ \
- /* gcpoll; */ \
- DEBUG_ASSURE_NO_RETURN_END(HELPER_METHOD_FRAME); \
- INCONTRACT(FCallGCCanTrigger::Leave(__FUNCTION__, __FILE__, __LINE__)); \
- FORLAZYMACHSTATE(alwaysZero = \
- HelperMethodFrameRestoreState(INDEBUG_COMMA(&__helperframe) \
- __helperframe.MachineState());) \
- PERMIT_HELPER_METHOD_FRAME_END() \
- } FORLAZYMACHSTATE_ENDLOOP(alwaysZero);
-
-#define HELPER_METHOD_FRAME_END_EX(gcpoll,allowGC) \
- UNINSTALL_UNWIND_AND_CONTINUE_HANDLER; \
- UNINSTALL_MANAGED_EXCEPTION_DISPATCHER; \
- __helperframe.Pop(); \
- HELPER_METHOD_FRAME_END_EX_BODY(gcpoll,allowGC);
-
-#define HELPER_METHOD_FRAME_END_EX_NOTHROW(gcpoll,allowGC) \
- __helperframe.Pop(); \
- HELPER_METHOD_FRAME_END_EX_BODY(gcpoll,allowGC);
-
-#define HELPER_METHOD_FRAME_BEGIN_ATTRIB(attribs) \
- HELPER_METHOD_FRAME_BEGIN_EX( \
- return, \
- HELPER_FRAME_DECL(0)(HELPER_FRAME_ARGS(attribs)), \
- HELPER_METHOD_POLL(),TRUE)
-
-#define HELPER_METHOD_FRAME_BEGIN_0() \
- HELPER_METHOD_FRAME_BEGIN_ATTRIB(Frame::FRAME_ATTR_NONE)
-
-#define HELPER_METHOD_FRAME_BEGIN_ATTRIB_NOPOLL(attribs) \
- HELPER_METHOD_FRAME_BEGIN_EX( \
- return, \
- HELPER_FRAME_DECL(0)(HELPER_FRAME_ARGS(attribs)), \
- {},FALSE)
-
-#define HELPER_METHOD_FRAME_BEGIN_NOPOLL() HELPER_METHOD_FRAME_BEGIN_ATTRIB_NOPOLL(Frame::FRAME_ATTR_NONE)
-
-#define HELPER_METHOD_FRAME_BEGIN_ATTRIB_1(attribs, arg1) \
- static_assert(sizeof(arg1) == sizeof(OBJECTREF), "GC protecting structs of multiple OBJECTREFs requires a PROTECT variant of the HELPER METHOD FRAME macro");\
- HELPER_METHOD_FRAME_BEGIN_EX( \
- return, \
- HELPER_FRAME_DECL(1)(HELPER_FRAME_ARGS(attribs), \
- (OBJECTREF*) &arg1), \
- HELPER_METHOD_POLL(),TRUE)
-
-#define HELPER_METHOD_FRAME_BEGIN_1(arg1) HELPER_METHOD_FRAME_BEGIN_ATTRIB_1(Frame::FRAME_ATTR_NONE, arg1)
-
-#define HELPER_METHOD_FRAME_BEGIN_ATTRIB_2(attribs, arg1, arg2) \
- static_assert(sizeof(arg1) == sizeof(OBJECTREF), "GC protecting structs of multiple OBJECTREFs requires a PROTECT variant of the HELPER METHOD FRAME macro");\
- static_assert(sizeof(arg2) == sizeof(OBJECTREF), "GC protecting structs of multiple OBJECTREFs requires a PROTECT variant of the HELPER METHOD FRAME macro");\
- HELPER_METHOD_FRAME_BEGIN_EX( \
- return, \
- HELPER_FRAME_DECL(2)(HELPER_FRAME_ARGS(attribs), \
- (OBJECTREF*) &arg1, (OBJECTREF*) &arg2), \
- HELPER_METHOD_POLL(),TRUE)
-
-#define HELPER_METHOD_FRAME_BEGIN_2(arg1, arg2) HELPER_METHOD_FRAME_BEGIN_ATTRIB_2(Frame::FRAME_ATTR_NONE, arg1, arg2)
-
-#define HELPER_METHOD_FRAME_BEGIN_ATTRIB_3(attribs, arg1, arg2, arg3) \
- static_assert(sizeof(arg1) == sizeof(OBJECTREF), "GC protecting structs of multiple OBJECTREFs requires a PROTECT variant of the HELPER METHOD FRAME macro");\
- static_assert(sizeof(arg2) == sizeof(OBJECTREF), "GC protecting structs of multiple OBJECTREFs requires a PROTECT variant of the HELPER METHOD FRAME macro");\
- static_assert(sizeof(arg3) == sizeof(OBJECTREF), "GC protecting structs of multiple OBJECTREFs requires a PROTECT variant of the HELPER METHOD FRAME macro");\
- HELPER_METHOD_FRAME_BEGIN_EX( \
- return, \
- HELPER_FRAME_DECL(3)(HELPER_FRAME_ARGS(attribs), \
- (OBJECTREF*) &arg1, (OBJECTREF*) &arg2, (OBJECTREF*) &arg3), \
- HELPER_METHOD_POLL(),TRUE)
-
-#define HELPER_METHOD_FRAME_BEGIN_3(arg1, arg2, arg3) HELPER_METHOD_FRAME_BEGIN_ATTRIB_3(Frame::FRAME_ATTR_NONE, arg1, arg2, arg3)
-
-#define HELPER_METHOD_FRAME_BEGIN_PROTECT(gc) \
- HELPER_METHOD_FRAME_BEGIN_EX( \
- return, \
- HELPER_FRAME_DECL(PROTECT)(HELPER_FRAME_ARGS(Frame::FRAME_ATTR_NONE), \
- (OBJECTREF*)&(gc), sizeof(gc)/sizeof(OBJECTREF)), \
- HELPER_METHOD_POLL(),TRUE)
-
-#define HELPER_METHOD_FRAME_BEGIN_RET_ATTRIB_NOPOLL(attribs) \
- HELPER_METHOD_FRAME_BEGIN_EX( \
- return 0, \
- HELPER_FRAME_DECL(0)(HELPER_FRAME_ARGS(attribs)), \
- {},FALSE)
-
-#define HELPER_METHOD_FRAME_BEGIN_RET_VC_ATTRIB_NOPOLL(attribs) \
- HELPER_METHOD_FRAME_BEGIN_EX( \
- FC_RETURN_VC(), \
- HELPER_FRAME_DECL(0)(HELPER_FRAME_ARGS(attribs)), \
- {},FALSE)
-
-#define HELPER_METHOD_FRAME_BEGIN_RET_ATTRIB(attribs) \
- HELPER_METHOD_FRAME_BEGIN_EX( \
- return 0, \
- HELPER_FRAME_DECL(0)(HELPER_FRAME_ARGS(attribs)), \
- HELPER_METHOD_POLL(),TRUE)
-
-#define HELPER_METHOD_FRAME_BEGIN_RET_0() \
- HELPER_METHOD_FRAME_BEGIN_RET_ATTRIB(Frame::FRAME_ATTR_NONE)
-
-#define HELPER_METHOD_FRAME_BEGIN_RET_VC_0() \
- HELPER_METHOD_FRAME_BEGIN_EX( \
- FC_RETURN_VC(), \
- HELPER_FRAME_DECL(0)(HELPER_FRAME_ARGS(Frame::FRAME_ATTR_NONE)), \
- HELPER_METHOD_POLL(),TRUE)
-
-#define HELPER_METHOD_FRAME_BEGIN_RET_ATTRIB_1(attribs, arg1) \
- static_assert(sizeof(arg1) == sizeof(OBJECTREF), "GC protecting structs of multiple OBJECTREFs requires a PROTECT variant of the HELPER METHOD FRAME macro");\
- HELPER_METHOD_FRAME_BEGIN_EX( \
- return 0, \
- HELPER_FRAME_DECL(1)(HELPER_FRAME_ARGS(attribs), \
- (OBJECTREF*) &arg1), \
- HELPER_METHOD_POLL(),TRUE)
-
-#define HELPER_METHOD_FRAME_BEGIN_RET_NOTHROW_1(probeFailExpr, arg1) \
- static_assert(sizeof(arg1) == sizeof(OBJECTREF), "GC protecting structs of multiple OBJECTREFs requires a PROTECT variant of the HELPER METHOD FRAME macro");\
- HELPER_METHOD_FRAME_BEGIN_EX_NOTHROW( \
- return 0, \
- HELPER_FRAME_DECL(1)(HELPER_FRAME_ARGS(Frame::FRAME_ATTR_NO_THREAD_ABORT), \
- (OBJECTREF*) &arg1), \
- HELPER_METHOD_POLL(), TRUE, probeFailExpr)
-
-#define HELPER_METHOD_FRAME_BEGIN_RET_VC_ATTRIB_1(attribs, arg1) \
- static_assert(sizeof(arg1) == sizeof(OBJECTREF), "GC protecting structs of multiple OBJECTREFs requires a PROTECT variant of the HELPER METHOD FRAME macro");\
- HELPER_METHOD_FRAME_BEGIN_EX( \
- FC_RETURN_VC(), \
- HELPER_FRAME_DECL(1)(HELPER_FRAME_ARGS(attribs), \
- (OBJECTREF*) &arg1), \
- HELPER_METHOD_POLL(),TRUE)
-
-#define HELPER_METHOD_FRAME_BEGIN_RET_ATTRIB_2(attribs, arg1, arg2) \
- static_assert(sizeof(arg1) == sizeof(OBJECTREF), "GC protecting structs of multiple OBJECTREFs requires a PROTECT variant of the HELPER METHOD FRAME macro");\
- static_assert(sizeof(arg2) == sizeof(OBJECTREF), "GC protecting structs of multiple OBJECTREFs requires a PROTECT variant of the HELPER METHOD FRAME macro");\
- HELPER_METHOD_FRAME_BEGIN_EX( \
- return 0, \
- HELPER_FRAME_DECL(2)(HELPER_FRAME_ARGS(attribs), \
- (OBJECTREF*) &arg1, (OBJECTREF*) &arg2), \
- HELPER_METHOD_POLL(),TRUE)
-
-#define HELPER_METHOD_FRAME_BEGIN_RET_VC_ATTRIB_2(attribs, arg1, arg2) \
- static_assert(sizeof(arg1) == sizeof(OBJECTREF), "GC protecting structs of multiple OBJECTREFs requires a PROTECT variant of the HELPER METHOD FRAME macro");\
- static_assert(sizeof(arg2) == sizeof(OBJECTREF), "GC protecting structs of multiple OBJECTREFs requires a PROTECT variant of the HELPER METHOD FRAME macro");\
- HELPER_METHOD_FRAME_BEGIN_EX( \
- FC_RETURN_VC(), \
- HELPER_FRAME_DECL(2)(HELPER_FRAME_ARGS(attribs), \
- (OBJECTREF*) &arg1, (OBJECTREF*) &arg2), \
- HELPER_METHOD_POLL(),TRUE)
-
-#define HELPER_METHOD_FRAME_BEGIN_RET_ATTRIB_PROTECT(attribs, gc) \
- HELPER_METHOD_FRAME_BEGIN_EX( \
- return 0, \
- HELPER_FRAME_DECL(PROTECT)(HELPER_FRAME_ARGS(attribs), \
- (OBJECTREF*)&(gc), sizeof(gc)/sizeof(OBJECTREF)), \
- HELPER_METHOD_POLL(),TRUE)
-
-#define HELPER_METHOD_FRAME_BEGIN_RET_VC_NOPOLL() \
- HELPER_METHOD_FRAME_BEGIN_RET_VC_ATTRIB_NOPOLL(Frame::FRAME_ATTR_NONE)
-
-#define HELPER_METHOD_FRAME_BEGIN_RET_NOPOLL() \
- HELPER_METHOD_FRAME_BEGIN_RET_ATTRIB_NOPOLL(Frame::FRAME_ATTR_NONE)
-
-#define HELPER_METHOD_FRAME_BEGIN_RET_1(arg1) \
- static_assert(sizeof(arg1) == sizeof(OBJECTREF), "GC protecting structs of multiple OBJECTREFs requires a PROTECT variant of the HELPER METHOD FRAME macro");\
- HELPER_METHOD_FRAME_BEGIN_RET_ATTRIB_1(Frame::FRAME_ATTR_NONE, arg1)
-
-#define HELPER_METHOD_FRAME_BEGIN_RET_VC_1(arg1) \
- static_assert(sizeof(arg1) == sizeof(OBJECTREF), "GC protecting structs of multiple OBJECTREFs requires a PROTECT variant of the HELPER METHOD FRAME macro");\
- HELPER_METHOD_FRAME_BEGIN_RET_VC_ATTRIB_1(Frame::FRAME_ATTR_NONE, arg1)
-
-#define HELPER_METHOD_FRAME_BEGIN_RET_2(arg1, arg2) \
- static_assert(sizeof(arg1) == sizeof(OBJECTREF), "GC protecting structs of multiple OBJECTREFs requires a PROTECT variant of the HELPER METHOD FRAME macro");\
- static_assert(sizeof(arg2) == sizeof(OBJECTREF), "GC protecting structs of multiple OBJECTREFs requires a PROTECT variant of the HELPER METHOD FRAME macro");\
- HELPER_METHOD_FRAME_BEGIN_RET_ATTRIB_2(Frame::FRAME_ATTR_NONE, arg1, arg2)
-
-#define HELPER_METHOD_FRAME_BEGIN_RET_VC_2(arg1, arg2) \
- static_assert(sizeof(arg1) == sizeof(OBJECTREF), "GC protecting structs of multiple OBJECTREFs requires a PROTECT variant of the HELPER METHOD FRAME macro");\
- static_assert(sizeof(arg2) == sizeof(OBJECTREF), "GC protecting structs of multiple OBJECTREFs requires a PROTECT variant of the HELPER METHOD FRAME macro");\
- HELPER_METHOD_FRAME_BEGIN_RET_VC_ATTRIB_2(Frame::FRAME_ATTR_NONE, arg1, arg2)
-
-#define HELPER_METHOD_FRAME_BEGIN_RET_PROTECT(gc) \
- HELPER_METHOD_FRAME_BEGIN_RET_ATTRIB_PROTECT(Frame::FRAME_ATTR_NONE, gc)
-
-
-#define HELPER_METHOD_FRAME_END() HELPER_METHOD_FRAME_END_EX({},FALSE)
-#define HELPER_METHOD_FRAME_END_POLL() HELPER_METHOD_FRAME_END_EX(HELPER_METHOD_POLL(),TRUE)
-#define HELPER_METHOD_FRAME_END_NOTHROW()HELPER_METHOD_FRAME_END_EX_NOTHROW({},FALSE)
-
-// This is the fastest way to do a GC poll if you have already erected a HelperMethodFrame
-#define HELPER_METHOD_POLL() { __helperframe.Poll(); INCONTRACT(__fCallCheck.SetDidPoll()); }
-
-// The HelperMethodFrame knows how to get its return address. Let other code get at it, too.
-// (Uses comma operator to call EnsureInit & discard result.
-#define HELPER_METHOD_FRAME_GET_RETURN_ADDRESS() \
- ( static_cast( (__helperframe.EnsureInit(NULL)), (__helperframe.MachineState()->GetRetAddr()) ) )
-
- // Very short routines, or routines that are guaranteed to force GC or EH
- // don't need to poll the GC. USE VERY SPARINGLY!!!
-#define FC_GC_POLL_NOT_NEEDED() INCONTRACT(__fCallCheck.SetNotNeeded())
-
#if defined(ENABLE_CONTRACTS)
#define FC_CAN_TRIGGER_GC() FCallGCCanTrigger::Enter()
#define FC_CAN_TRIGGER_GC_END() FCallGCCanTrigger::Leave(__FUNCTION__, __FILE__, __LINE__)
@@ -729,7 +203,7 @@ class CompletedFCallTransitionState
#define FC_CAN_TRIGGER_GC_HAVE_THREAD(thread) FCallGCCanTrigger::Enter(thread)
#define FC_CAN_TRIGGER_GC_HAVE_THREADEND(thread) FCallGCCanTrigger::Leave(thread, __FUNCTION__, __FILE__, __LINE__)
- // turns on forbidGC for the lifetime of the instance
+// turns on forbidGC for the lifetime of the instance
class ForbidGC {
protected:
Thread *m_pThread;
@@ -738,26 +212,6 @@ class ForbidGC {
~ForbidGC();
};
- // this little helper class checks to make certain
- // 1) ForbidGC is set throughout the routine.
- // 2) Sometime during the routine, a GC poll is done
-
-class FCallCheck : public ForbidGC {
-public:
- FCallCheck(const char *szFile, int lineNum);
- ~FCallCheck();
- void SetDidPoll() {LIMITED_METHOD_CONTRACT; didGCPoll = true; }
- void SetNotNeeded() {LIMITED_METHOD_CONTRACT; notNeeded = true; }
-
-private:
-#ifdef _DEBUG
- DWORD unbreakableLockCount;
-#endif
- bool didGCPoll; // GC poll was done
- bool notNeeded; // GC poll not needed
- uint64_t startTicks; // tick count at beginning of FCall
-};
-
// FC_COMMON_PROLOG is used for both FCalls and HCalls
#define FC_COMMON_PROLOG(target, assertFn) \
/* The following line has to be first. We do not want to trash last error */ \
@@ -768,77 +222,18 @@ class FCallCheck : public ForbidGC {
Thread *_pThread = GetThread(); \
Thread::ObjectRefFlush(_pThread); \
} \
- FCallCheck __fCallCheck(__FILE__, __LINE__); \
- FCALL_TRANSITION_BEGIN(); \
+ ForbidGC __fCallCheck(__FILE__, __LINE__); \
::SetLastError(__lastError); \
void FCallAssert(void*& cache, void* target);
void HCallAssert(void*& cache, void* target);
#else
-#define FC_COMMON_PROLOG(target, assertFn) FCALL_TRANSITION_BEGIN()
+#define FC_COMMON_PROLOG(target, assertFn)
#define FC_CAN_TRIGGER_GC()
#define FC_CAN_TRIGGER_GC_END()
#endif // ENABLE_CONTRACTS
-// #FC_INNER
-// Macros that allows fcall to be split into two function to avoid the helper frame overhead on common fast
-// codepaths.
-//
-// The helper routine needs to know the name of the routine that called it so that it can look up the name of
-// the managed routine this code is associted with (for managed stack traces). This is passed with the
-// FC_INNER_PROLOG macro.
-//
-// The helper can set up a HELPER_METHOD_FRAME, but should pass the
-// Frame::FRAME_ATTR_EXACT_DEPTH|Frame::FRAME_ATTR_CAPTURE_DEPTH_2 which indicates the exact number of
-// unwinds to do to get back to managed code. Currently we only support depth 2 which means that the
-// HELPER_METHOD_FRAME needs to be set up in the function directly called by the FCALL. The helper should
-// use the NOINLINE macro to prevent the compiler from inlining it into the FCALL (which would obviously
-// mess up the unwind count).
-//
-// The other invariant that needs to hold is that the epilog walker needs to be able to get from the call to
-// the helper routine to the end of the FCALL using trivial heurisitics. The easiest (and only supported)
-// way of doing this is to place your helper right before a return (eg at the end of the method). Generally
-// this is not a problem at all, since the FCALL itself will pick off some common case and then tail-call to
-// the helper for everything else. You must use the code:FC_INNER_RETURN macros to do the call, to ensure
-// that the C++ compiler does not tail-call optimize the call to the inner function and mess up the stack
-// depth.
-//
-// see code:ObjectNative::GetClass for an example
-//
-#define FC_INNER_PROLOG(outerfuncname) \
- LPVOID __me; \
- __me = GetEEFuncEntryPointMacro(outerfuncname); \
- FC_CAN_TRIGGER_GC(); \
- INCONTRACT(FCallCheck __fCallCheck(__FILE__, __LINE__));
-
-// This variant should be used for inner fcall functions that have the
-// __me value passed as an argument to the function. This allows
-// inner functions to be shared across multiple fcalls.
-#define FC_INNER_PROLOG_NO_ME_SETUP() \
- FC_CAN_TRIGGER_GC(); \
- INCONTRACT(FCallCheck __fCallCheck(__FILE__, __LINE__));
-
-#define FC_INNER_EPILOG() \
- FC_CAN_TRIGGER_GC_END();
-
-// If you are using FC_INNER, and you are tail calling to the helper method (a common case), then you need
-// to use the FC_INNER_RETURN macros (there is one for methods that return a value and another if the
-// function returns void). This macro's purpose is to inhibit any tail calll optimization the C++ compiler
-// might do, which would otherwise confuse the epilog walker.
-//
-// * See #FC_INNER for more
-extern RAW_KEYWORD(volatile) int FC_NO_TAILCALL;
-#define FC_INNER_RETURN(type, expr) \
- type __retVal = expr; \
- while (0 == FC_NO_TAILCALL) { }; /* side effect the compile can't remove */ \
- return(__retVal);
-
-#define FC_INNER_RETURN_VOID(stmt) \
- stmt; \
- while (0 == FC_NO_TAILCALL) { }; /* side effect the compile can't remove */ \
- return;
-
//==============================================================================================
// FIMPLn: A set of macros for generating the proto for the actual
// implementation (use FDECLN for header protos.)
@@ -1023,15 +418,12 @@ struct FCSigCheck {
// Use this to terminte an FCIMPLEND.
//==============================================================================================
-#define FCIMPL_EPILOG() FCALL_TRANSITION_END()
-
-#define FCIMPLEND FCIMPL_EPILOG(); }
+#define FCIMPLEND }
#define HCIMPL_PROLOG(funcname) LPVOID __me; __me = 0; FC_COMMON_PROLOG(funcname, HCallAssert)
- // HCIMPL macros are just like their FCIMPL counterparts, however
- // they do not remember the function they come from. Thus they will not
- // show up in a stack trace. This is what you want for JIT helpers and the like
+// HCIMPL macros are used to implement JIT helpers. The only difference is that
+// HCIMPL methods are not mapped to a managed method in CoreLib in ecalllist.h.
#ifdef SWIZZLE_STKARG_ORDER
#ifdef SWIZZLE_REGARG_ORDER
@@ -1043,23 +435,11 @@ struct FCSigCheck {
#define HCIMPL2(rettype, funcname, a1, a2) rettype F_CALL_CONV funcname(int /* EAX */, a2, a1) { HCIMPL_PROLOG(funcname)
#define HCIMPL2_RAW(rettype, funcname, a1, a2) rettype F_CALL_CONV funcname(int /* EAX */, a2, a1) {
#define HCIMPL2_VV(rettype, funcname, a1, a2) rettype F_CALL_CONV funcname(int /* EAX */, int /* EDX */, int /* ECX */, a2, a1) { HCIMPL_PROLOG(funcname)
-#define HCIMPL2_IV(rettype, funcname, a1, a2) rettype F_CALL_CONV funcname(int /* EAX */, int /* EDX */, a1, a2) { HCIMPL_PROLOG(funcname)
#define HCIMPL3(rettype, funcname, a1, a2, a3) rettype F_CALL_CONV funcname(int /* EAX */, a2, a1, a3) { HCIMPL_PROLOG(funcname)
#define HCIMPL3_RAW(rettype, funcname, a1, a2, a3) rettype F_CALL_CONV funcname(int /* EAX */, a2, a1, a3) {
-#define HCIMPL4(rettype, funcname, a1, a2, a3, a4) rettype F_CALL_CONV funcname(int /* EAX */, a2, a1, a4, a3) { HCIMPL_PROLOG(funcname)
-#define HCIMPL5(rettype, funcname, a1, a2, a3, a4, a5) rettype F_CALL_CONV funcname(int /* EAX */, a2, a1, a5, a4, a3) { HCIMPL_PROLOG(funcname)
-#define HCCALL0(funcname) funcname()
#define HCCALL1(funcname, a1) funcname(0, 0, a1)
-#define HCCALL1_V(funcname, a1) funcname(0, 0, 0, a1)
-#define HCCALL2(funcname, a1, a2) funcname(0, a2, a1)
-#define HCCALL2_VV(funcname, a1, a2) funcname(0, 0, 0, a2, a1)
-#define HCCALL3(funcname, a1, a2, a3) funcname(0, a2, a1, a3)
-#define HCCALL4(funcname, a1, a2, a3, a4) funcname(0, a2, a1, a4, a3)
-#define HCCALL5(funcname, a1, a2, a3, a4, a5) funcname(0, a2, a1, a5, a4, a3)
#define HCCALL1_PTR(rettype, funcptr, a1) rettype (F_CALL_CONV * funcptr)(int /* EAX */, int /* EDX */, a1)
-#define HCCALL2_PTR(rettype, funcptr, a1, a2) rettype (F_CALL_CONV * funcptr)(int /* EAX */, a2, a1)
-#define HCCALL2_VV_PTR(rettype, funcptr, a1, a2) rettype (F_CALL_CONV * funcptr)(int /* EAX */, int /* EDX */, int /* ECX */, a2, a1)
#else // SWIZZLE_REGARG_ORDER
#define HCIMPL0(rettype, funcname) rettype F_CALL_CONV funcname() { HCIMPL_PROLOG(funcname)
@@ -1069,23 +449,11 @@ struct FCSigCheck {
#define HCIMPL2(rettype, funcname, a1, a2) rettype F_CALL_CONV funcname(a1, a2) { HCIMPL_PROLOG(funcname)
#define HCIMPL2_RAW(rettype, funcname, a1, a2) rettype F_CALL_CONV funcname(a1, a2) {
#define HCIMPL2_VV(rettype, funcname, a1, a2) rettype F_CALL_CONV funcname(a2, a1) { HCIMPL_PROLOG(funcname)
-#define HCIMPL2_IV(rettype, funcname, a1, a2) rettype F_CALL_CONV funcname(a1, a2) { HCIMPL_PROLOG(funcname)
#define HCIMPL3(rettype, funcname, a1, a2, a3) rettype F_CALL_CONV funcname(a1, a2, a3) { HCIMPL_PROLOG(funcname)
#define HCIMPL3_RAW(rettype, funcname, a1, a2, a3) rettype F_CALL_CONV funcname(a1, a2, a3) {
-#define HCIMPL4(rettype, funcname, a1, a2, a3, a4) rettype F_CALL_CONV funcname(a1, a2, a4, a3) { HCIMPL_PROLOG(funcname)
-#define HCIMPL5(rettype, funcname, a1, a2, a3, a4, a5) rettype F_CALL_CONV funcname(a1, a2, a5, a4, a3) { HCIMPL_PROLOG(funcname)
-#define HCCALL0(funcname) funcname()
#define HCCALL1(funcname, a1) funcname(a1)
-#define HCCALL1_V(funcname, a1) funcname(a1)
-#define HCCALL2(funcname, a1, a2) funcname(a1, a2)
-#define HCCALL2_VV(funcname, a1, a2) funcname(a1, a2)
-#define HCCALL3(funcname, a1, a2, a3) funcname(a1, a2, a3)
-#define HCCALL4(funcname, a1, a2, a3, a4) funcname(a1, a2, a4, a3)
-#define HCCALL5(funcname, a1, a2, a3, a4, a5) funcname(a1, a2, a5, a4, a3)
#define HCCALL1_PTR(rettype, funcptr, a1) rettype (F_CALL_CONV * (funcptr))(a1)
-#define HCCALL2_PTR(rettype, funcptr, a1, a2) rettype (F_CALL_CONV * (funcptr))(a1, a2)
-#define HCCALL2_VV_PTR(rettype, funcptr, a1, a2) rettype (F_CALL_CONV * (funcptr))(a1, a2)
#endif // !SWIZZLE_REGARG_ORDER
#else // SWIZZLE_STKARG_ORDER
@@ -1096,29 +464,16 @@ struct FCSigCheck {
#define HCIMPL2(rettype, funcname, a1, a2) rettype F_CALL_CONV funcname(a1, a2) { HCIMPL_PROLOG(funcname)
#define HCIMPL2_RAW(rettype, funcname, a1, a2) rettype F_CALL_CONV funcname(a1, a2) {
#define HCIMPL2_VV(rettype, funcname, a1, a2) rettype F_CALL_CONV funcname(a1, a2) { HCIMPL_PROLOG(funcname)
-#define HCIMPL2_IV(rettype, funcname, a1, a2) rettype F_CALL_CONV funcname(a1, a2) { HCIMPL_PROLOG(funcname)
#define HCIMPL3(rettype, funcname, a1, a2, a3) rettype F_CALL_CONV funcname(a1, a2, a3) { HCIMPL_PROLOG(funcname)
#define HCIMPL3_RAW(rettype, funcname, a1, a2, a3) rettype F_CALL_CONV funcname(a1, a2, a3) {
-#define HCIMPL4(rettype, funcname, a1, a2, a3, a4) rettype F_CALL_CONV funcname(a1, a2, a3, a4) { HCIMPL_PROLOG(funcname)
-#define HCIMPL5(rettype, funcname, a1, a2, a3, a4, a5) rettype F_CALL_CONV funcname(a1, a2, a3, a4, a5) { HCIMPL_PROLOG(funcname)
-#define HCCALL0(funcname) funcname()
#define HCCALL1(funcname, a1) funcname(a1)
-#define HCCALL1_V(funcname, a1) funcname(a1)
-#define HCCALL2(funcname, a1, a2) funcname(a1, a2)
-#define HCCALL2_VV(funcname, a1, a2) funcname(a1, a2)
-#define HCCALL3(funcname, a1, a2, a3) funcname(a1, a2, a3)
-#define HCCALL4(funcname, a1, a2, a3, a4) funcname(a1, a2, a3, a4)
-#define HCCALL5(funcname, a1, a2, a3, a4, a5) funcname(a1, a2, a3, a4, a5)
#define HCCALL1_PTR(rettype, funcptr, a1) rettype (F_CALL_CONV * (funcptr))(a1)
-#define HCCALL2_PTR(rettype, funcptr, a1, a2) rettype (F_CALL_CONV * (funcptr))(a1, a2)
-#define HCCALL2_VV_PTR(rettype, funcptr, a1, a2) rettype (F_CALL_CONV * (funcptr))(a1, a2)
#endif // !SWIZZLE_STKARG_ORDER
-#define HCIMPLEND_RAW }
-#define HCIMPLEND FCALL_TRANSITION_END(); }
-
+#define HCIMPLEND_RAW }
+#define HCIMPLEND }
// The managed calling convention expects returned small types (e.g. bool) to be
// widened to 32-bit on return. The C/C++ calling convention does not guarantee returned
@@ -1144,7 +499,6 @@ typedef INT32 FC_BOOL_RET;
#define FC_RETURN_BOOL(x) do { return !!(x); } while(0)
-
// Small primitive return values are artificially widened in managed calling convention
typedef UINT32 FC_CHAR_RET;
typedef INT32 FC_INT8_RET;
@@ -1162,9 +516,6 @@ typedef INT32 FC_BOOL_ARG;
// The parameter of the FCUnique macro is an arbitrary 32-bit random non-zero number.
#define FCUnique(unique) { Volatile u = (unique); while (u.LoadWithoutBarrier() == 0) { }; }
-
-
-
// FCALL contracts come in two forms:
//
// Short form that should be used if the FCALL contract does not have any extras like preconditions, failure injection. Example:
@@ -1183,8 +534,6 @@ typedef INT32 FC_BOOL_ARG;
// PRECONDITION(CheckPointer(p));
// } CONTRACTL_END;
// ...
-
-
//
// FCALL_CHECK defines the actual contract conditions required for FCALLs
//
@@ -1198,8 +547,6 @@ typedef INT32 FC_BOOL_ARG;
//
// #define FCALL_CONTRACT CONTRACTL { FCALL_CHECK; } CONTRACTL_END;
//
-// Since there is very little value in having runtime contracts in FCalls, FCALL_CONTRACT is defined as static contract only for performance reasons.
-//
#define FCALL_CONTRACT \
STATIC_CONTRACT_THROWS; \
/* FCALLS are a special case contract wise, they are "NOTRIGGER, unless you setup a frame" */ \
diff --git a/src/coreclr/vm/frames.cpp b/src/coreclr/vm/frames.cpp
index a6b281437a8d8e..6db1ce122e890d 100644
--- a/src/coreclr/vm/frames.cpp
+++ b/src/coreclr/vm/frames.cpp
@@ -1,8 +1,5 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
-// FRAMES.CPP
-
-
#include "common.h"
#include "log.h"
@@ -19,7 +16,6 @@
#include "dllimportcallback.h"
#include "stackwalk.h"
#include "dbginterface.h"
-#include "gms.h"
#include "eeconfig.h"
#include "ecall.h"
#include "clsload.hpp"
@@ -1842,215 +1838,6 @@ void ComMethodFrame::DoSecondPassHandlerCleanup(Frame * pCurFrame)
#endif // FEATURE_COMINTEROP
-#ifndef DACCESS_COMPILE
-
-#if defined(_MSC_VER) && defined(TARGET_X86)
-#pragma optimize("y", on) // Small critical routines, don't put in EBP frame
-#endif
-
-// Initialization of HelperMethodFrame.
-void HelperMethodFrame::Push()
-{
- CONTRACTL {
- if (m_Attribs & FRAME_ATTR_NO_THREAD_ABORT) NOTHROW; else THROWS;
- GC_TRIGGERS;
- MODE_COOPERATIVE;
- } CONTRACTL_END;
-
- //
- // Finish initialization
- //
-
- _ASSERTE(!m_MachState.isValid());
-
- Thread * pThread = ::GetThread();
- m_pThread = pThread;
-
- // Push the frame
- Frame::Push(pThread);
-
- if (!pThread->HasThreadStateOpportunistic(Thread::TS_AbortRequested))
- return;
-
- // Outline the slow path for better perf
- PushSlowHelper();
-}
-
-void HelperMethodFrame::Pop()
-{
- CONTRACTL {
- if (m_Attribs & FRAME_ATTR_NO_THREAD_ABORT) NOTHROW; else THROWS;
- GC_TRIGGERS;
- MODE_COOPERATIVE;
- } CONTRACTL_END;
-
- Thread * pThread = m_pThread;
-
- if ((m_Attribs & FRAME_ATTR_NO_THREAD_ABORT) || !pThread->HasThreadStateOpportunistic(Thread::TS_AbortInitiated))
- {
- Frame::Pop(pThread);
- return;
- }
-
- // Outline the slow path for better perf
- PopSlowHelper();
-}
-
-#if defined(_MSC_VER) && defined(TARGET_X86)
-#pragma optimize("", on) // Go back to command line default optimizations
-#endif
-
-NOINLINE void HelperMethodFrame::PushSlowHelper()
-{
- CONTRACTL {
- if (m_Attribs & FRAME_ATTR_NO_THREAD_ABORT) NOTHROW; else THROWS;
- GC_TRIGGERS;
- MODE_COOPERATIVE;
- } CONTRACTL_END;
-
- if (!(m_Attribs & FRAME_ATTR_NO_THREAD_ABORT))
- {
- if (m_pThread->IsAbortRequested())
- {
- m_pThread->HandleThreadAbort();
- }
-
- }
-}
-
-NOINLINE void HelperMethodFrame::PopSlowHelper()
-{
- CONTRACTL {
- THROWS;
- GC_TRIGGERS;
- MODE_COOPERATIVE;
- } CONTRACTL_END;
-
- m_pThread->HandleThreadAbort();
- Frame::Pop(m_pThread);
-}
-
-#endif // #ifndef DACCESS_COMPILE
-
-MethodDesc* HelperMethodFrame::GetFunction_Impl()
-{
- WRAPPER_NO_CONTRACT;
-
-#ifndef DACCESS_COMPILE
- EnsureInit(NULL);
- return m_pMD;
-#else
- if (m_MachState.isValid())
- {
- return m_pMD;
- }
- else
- {
- return ECall::MapTargetBackToMethod(m_FCallEntry);
- }
-#endif
-}
-
-//---------------------------------------------------------------------------------------
-//
-// Ensures the HelperMethodFrame gets initialized, if not already.
-//
-// Arguments:
-// * unwindState - [out] DAC builds use this to return the unwound machine state.
-//
-// Return Value:
-// Normally, the function always returns TRUE meaning the initialization succeeded.
-//
-//
-
-BOOL HelperMethodFrame::EnsureInit(MachState * unwindState)
-{
- CONTRACTL {
- NOTHROW;
- GC_NOTRIGGER;
- SUPPORTS_DAC;
- } CONTRACTL_END;
-
- if (m_MachState.isValid())
- {
- return TRUE;
- }
-
- _ASSERTE(m_Attribs != 0xCCCCCCCC);
-
-#ifndef DACCESS_COMPILE
- m_pMD = ECall::MapTargetBackToMethod(m_FCallEntry);
-
- // if this is an FCall, we should find it
- _ASSERTE(m_FCallEntry == 0 || m_pMD != 0);
-#endif
-
- // Because TRUE FCalls can be called from via reflection, com-interop, etc.,
- // we can't rely on the fact that we are called from jitted code to find the
- // caller of the FCALL. Thus FCalls must erect the frame directly in the
- // FCall. For JIT helpers, however, we can rely on this, and so they can
- // be sneakier and defer the HelperMethodFrame setup to a called worker method.
-
- // Work with a copy so that we only write the values once.
- // this avoids race conditions.
- LazyMachState* lazy = &m_MachState;
- DWORD threadId = m_pThread->GetOSThreadId();
- MachState unwound;
-
- if (m_FCallEntry == 0 &&
- !(m_Attribs & Frame::FRAME_ATTR_EXACT_DEPTH)) // Jit Helper
- {
- LazyMachState::unwindLazyState(
- lazy,
- &unwound,
- threadId,
- 0);
-
-#if !defined(DACCESS_COMPILE)
- if (!unwound.isValid())
- {
- // This only happens if LazyMachState::unwindLazyState had to abort as a
- // result of failing to take a reader lock (because we told it not to yield,
- // but the writer lock was already held). Since we've not yet updated
- // m_MachState, this HelperMethodFrame will still be considered not fully
- // initialized (so a future call into EnsureInit() will attempt to complete
- // initialization again).
- //
- // Note that, in DAC builds, the contract with LazyMachState::unwindLazyState
- // is a bit different, and it's expected that LazyMachState::unwindLazyState
- // will commonly return an unwound state with _pRetAddr==NULL (which counts
- // as an "invalid" MachState). So have DAC builds deliberately fall through
- // rather than aborting when unwound is invalid.
- return FALSE;
- }
-#endif // !defined(DACCESS_COMPILE)
- }
- else if ((m_Attribs & Frame::FRAME_ATTR_CAPTURE_DEPTH_2) != 0)
- {
- // explicitly told depth
- LazyMachState::unwindLazyState(lazy, &unwound, threadId, 2);
- }
- else
- {
- // True FCall
- LazyMachState::unwindLazyState(lazy, &unwound, threadId, 1);
- }
-
- _ASSERTE(unwound.isValid());
-
-#if !defined(DACCESS_COMPILE)
- lazy->setLazyStateFromUnwind(&unwound);
-#else // DACCESS_COMPILE
- if (unwindState)
- {
- *unwindState = unwound;
- }
-#endif // DACCESS_COMPILE
-
- return TRUE;
-}
-
-
#ifndef DACCESS_COMPILE
VOID InlinedCallFrame::Init()
diff --git a/src/coreclr/vm/frames.h b/src/coreclr/vm/frames.h
index 1057152ab6bf11..2336fd578c7efc 100644
--- a/src/coreclr/vm/frames.h
+++ b/src/coreclr/vm/frames.h
@@ -49,24 +49,11 @@
// | a JIT'ted caller, the calling method keeps
// | this frame linked throughout its activation.
// |
-// +-HelperMethodFrame - frame used allow stack crawling inside jit helpers and fcalls
-// | |
-// + +-HelperMethodFrame_1OBJ- reports additional object references
-// | |
-// + +-HelperMethodFrame_2OBJ- reports additional object references
-// | |
-// + +-HelperMethodFrame_3OBJ- reports additional object references
-// | |
-// + +-HelperMethodFrame_PROTECTOBJ - reports additional object references
-// |
// +-TransitionFrame - this abstract frame represents a transition from
// | | one or more nested frameless method calls
// | | to either a EE runtime helper function or
// | | a framed method.
// | |
-// | +-MulticastFrame - this frame protects arguments to a MulticastDelegate
-// | Invoke() call while calling each subscriber.
-// |
// | +-FramedMethodFrame - this abstract frame represents a call to a method
// | | that generates a full-fledged frame.
// | |
@@ -194,7 +181,6 @@ obtained from function pointers):
#include "method.hpp"
#include "stackwalk.h"
#include "stubmgr.h"
-#include "gms.h"
#include "threads.h"
#include "callingconvention.h"
@@ -325,9 +311,6 @@ class Frame
FRAME_ATTR_EXCEPTION = 1, // This frame caused an exception
FRAME_ATTR_FAULTED = 4, // Exception caused by Win32 fault
FRAME_ATTR_RESUMABLE = 8, // We may resume from this frame
- FRAME_ATTR_CAPTURE_DEPTH_2 = 0x10, // This is a helperMethodFrame and the capture occurred at depth 2
- FRAME_ATTR_EXACT_DEPTH = 0x20, // This is a helperMethodFrame and a jit helper, but only crawl to the given depth
- FRAME_ATTR_NO_THREAD_ABORT = 0x40, // This is a helperMethodFrame that should not trigger thread aborts on entry
};
unsigned GetFrameAttribs_Impl()
{
@@ -430,7 +413,6 @@ class Frame
// Debugger support
//------------------------------------------------------------------------
-
public:
// Get the type of transition.
// M-->U, U-->M
@@ -445,16 +427,10 @@ class Frame
TYPE_INTERNAL,
TYPE_ENTRY,
TYPE_EXIT,
- TYPE_CONTEXT_CROSS,
TYPE_INTERCEPTION,
- TYPE_SECURITY,
TYPE_CALL,
TYPE_FUNC_EVAL,
- // HMFs and derived classes should use this so the profiling API knows it needs
- // to ensure HMF-specific lazy initialization gets done w/out re-entering to the host.
- TYPE_HELPER_METHOD_FRAME,
-
TYPE_COUNT
};
@@ -1194,424 +1170,6 @@ struct cdac_data
typedef DPTR(FuncEvalFrame) PTR_FuncEvalFrame;
#endif // DEBUGGING_SUPPORTED
-//----------------------------------------------------------------------------------------------
-// A HelperMethodFrame is created by jit helper (Modified slightly it could be used
-// for native routines). This frame just does the callee saved register fixup.
-// It does NOT protect arguments; you must use GCPROTECT or one of the HelperMethodFrame
-// subclases. (see JitInterface for sample use, YOU CAN'T RETURN WHILE IN THE PROTECTED STATE!)
-//----------------------------------------------------------------------------------------------
-
-typedef DPTR(class HelperMethodFrame) PTR_HelperMethodFrame;
-
-class HelperMethodFrame : public Frame
-{
-public:
-#ifndef DACCESS_COMPILE
- // Lazy initialization of HelperMethodFrame. Need to
- // call EnsureInit to complete initialization
- // If this is an FCall, the first param is the entry point for the FCALL.
- // The MethodDesc will be looked up form this (lazily), and this method
- // will be used in stack reporting, if this is not an FCall pass a 0
- FORCEINLINE HelperMethodFrame(void* fCallFtnEntry, unsigned attribs = 0, FrameIdentifier frameIdentifier = FrameIdentifier::HelperMethodFrame) : Frame(frameIdentifier)
- {
- WRAPPER_NO_CONTRACT;
- // Most of the initialization is actually done in HelperMethodFrame::Push()
- INDEBUG(memset(&m_Attribs, 0xCC, sizeof(HelperMethodFrame) - offsetof(HelperMethodFrame, m_Attribs));)
- m_Attribs = attribs;
- m_FCallEntry = (TADDR)fCallFtnEntry;
- }
-#endif // DACCESS_COMPILE
-
- int GetFrameType_Impl()
- {
- LIMITED_METHOD_DAC_CONTRACT;
- return TYPE_HELPER_METHOD_FRAME;
- };
-
- PCODE GetReturnAddress_Impl()
- {
- LIMITED_METHOD_DAC_CONTRACT;
-
- if (!m_MachState.isValid())
- {
-#if defined(DACCESS_COMPILE)
- MachState unwoundState;
- EnsureInit(&unwoundState);
- return unwoundState.GetRetAddr();
-#else // !DACCESS_COMPILE
- _ASSERTE(!"HMF's should always be initialized in the non-DAC world.");
- return 0;
-
-#endif // !DACCESS_COMPILE
- }
-
- return m_MachState.GetRetAddr();
- }
-
- MethodDesc* GetFunction_Impl();
-
- BOOL NeedsUpdateRegDisplay_Impl()
- {
- return TRUE;
- }
-
- void UpdateRegDisplay_Impl(const PREGDISPLAY, bool updateFloats = false);
-
- Interception GetInterception_Impl()
- {
- WRAPPER_NO_CONTRACT;
- LIMITED_METHOD_DAC_CONTRACT;
- if (GetFrameAttribs() & FRAME_ATTR_EXCEPTION)
- return(INTERCEPTION_EXCEPTION);
- return(INTERCEPTION_NONE);
- }
-
- ETransitionType GetTransitionType_Impl()
- {
- LIMITED_METHOD_DAC_CONTRACT;
- return TT_InternalCall;
- }
-
-#ifdef _DEBUG
- void SetAddrOfHaveCheckedRestoreState(BOOL* pDoneCheck)
- {
- m_pDoneCheck = pDoneCheck;
- }
-
- BOOL HaveDoneConfirmStateCheck()
- {
- LIMITED_METHOD_CONTRACT;
- _ASSERTE(m_pDoneCheck != NULL);
- return *m_pDoneCheck;
- }
-
- void SetHaveDoneConfirmStateCheck()
- {
- LIMITED_METHOD_CONTRACT;
- _ASSERTE(m_pDoneCheck != NULL);
- *m_pDoneCheck = TRUE;
- }
-#endif
-
- unsigned GetFrameAttribs_Impl()
- {
- LIMITED_METHOD_DAC_CONTRACT;
- return(m_Attribs);
- }
-
-#ifdef DACCESS_COMPILE
- void EnumMemoryRegions_Impl(CLRDataEnumMemoryFlags flags)
- {
- WRAPPER_NO_CONTRACT;
- Frame::EnumMemoryRegions_Impl(flags);
- }
-#endif
-
-#ifndef DACCESS_COMPILE
- void Push();
- void Pop();
-
- FORCEINLINE void Poll()
- {
- WRAPPER_NO_CONTRACT;
- if (m_pThread->CatchAtSafePoint())
- CommonTripThread();
- }
-#endif // DACCESS_COMPILE
-
- BOOL EnsureInit(struct MachState* unwindState);
-
- LazyMachState * MachineState() {
- LIMITED_METHOD_CONTRACT;
- return &m_MachState;
- }
-
- Thread * GetThread() {
- LIMITED_METHOD_CONTRACT;
- return m_pThread;
- }
-
-private:
- // Slow paths of Push/Pop are factored into a separate functions for better perf.
- NOINLINE void PushSlowHelper();
- NOINLINE void PopSlowHelper();
-
-protected:
- PTR_MethodDesc m_pMD;
- unsigned m_Attribs;
- INDEBUG(BOOL* m_pDoneCheck;)
- PTR_Thread m_pThread;
- TADDR m_FCallEntry; // used to determine our identity for stack traces
-
- LazyMachState m_MachState; // pRetAddr points to the return address and the stack arguments
-};
-
-// Restores registers saved in m_MachState
-EXTERN_C int __fastcall HelperMethodFrameRestoreState(
- INDEBUG_COMMA(HelperMethodFrame *pFrame)
- MachState *pState
- );
-
-
-// workhorse for our promotion efforts
-inline void DoPromote(promote_func *fn, ScanContext* sc, OBJECTREF *address, BOOL interior)
-{
- WRAPPER_NO_CONTRACT;
-
- // We use OBJECTREF_TO_UNCHECKED_OBJECTREF since address may be an interior pointer
- LOG((LF_GC, INFO3,
- " Promoting pointer argument at" FMT_ADDR "from" FMT_ADDR "to ",
- DBG_ADDR(address), DBG_ADDR(OBJECTREF_TO_UNCHECKED_OBJECTREF(*address)) ));
-
- if (interior)
- PromoteCarefully(fn, PTR_PTR_Object(address), sc);
- else
- (*fn) (PTR_PTR_Object(address), sc, 0);
-
- LOG((LF_GC, INFO3, " " FMT_ADDR "\n", DBG_ADDR(OBJECTREF_TO_UNCHECKED_OBJECTREF(*address)) ));
-}
-
-
-//-----------------------------------------------------------------------------
-// a HelplerMethodFrames that also report additional object references
-//-----------------------------------------------------------------------------
-
-typedef DPTR(class HelperMethodFrame_1OBJ) PTR_HelperMethodFrame_1OBJ;
-
-class HelperMethodFrame_1OBJ : public HelperMethodFrame
-{
-public:
-#if !defined(DACCESS_COMPILE)
- HelperMethodFrame_1OBJ(void* fCallFtnEntry, unsigned attribs, OBJECTREF* aGCPtr1)
- : HelperMethodFrame(fCallFtnEntry, attribs, FrameIdentifier::HelperMethodFrame_1OBJ)
- {
- LIMITED_METHOD_CONTRACT;
- gcPtrs[0] = aGCPtr1;
- INDEBUG(Thread::ObjectRefProtected(aGCPtr1);)
- INDEBUG((*aGCPtr1).Validate ();)
- }
-#endif
-
- void SetProtectedObject(PTR_OBJECTREF objPtr)
- {
- LIMITED_METHOD_CONTRACT;
- gcPtrs[0] = objPtr;
- INDEBUG(Thread::ObjectRefProtected(objPtr);)
- }
-
- void GcScanRoots_Impl(promote_func *fn, ScanContext* sc)
- {
- WRAPPER_NO_CONTRACT;
- DoPromote(fn, sc, gcPtrs[0], FALSE);
- HelperMethodFrame::GcScanRoots_Impl(fn, sc);
- }
-
-#ifdef _DEBUG
-#ifndef DACCESS_COMPILE
- void Pop()
- {
- WRAPPER_NO_CONTRACT;
- HelperMethodFrame::Pop();
- Thread::ObjectRefNew(gcPtrs[0]);
- }
-#endif // DACCESS_COMPILE
-
- BOOL Protects_Impl(OBJECTREF *ppORef)
- {
- LIMITED_METHOD_CONTRACT;
- return (ppORef == gcPtrs[0]) ? TRUE : FALSE;
- }
-
-#endif
-
-private:
- PTR_OBJECTREF gcPtrs[1];
-};
-
-
-//-----------------------------------------------------------------------------
-// HelperMethodFrame_2OBJ
-//-----------------------------------------------------------------------------
-
-typedef DPTR(class HelperMethodFrame_2OBJ) PTR_HelperMethodFrame_2OBJ;
-
-class HelperMethodFrame_2OBJ : public HelperMethodFrame
-{
-public:
-#if !defined(DACCESS_COMPILE)
- HelperMethodFrame_2OBJ(
- void* fCallFtnEntry,
- unsigned attribs,
- OBJECTREF* aGCPtr1,
- OBJECTREF* aGCPtr2)
- : HelperMethodFrame(fCallFtnEntry, attribs, FrameIdentifier::HelperMethodFrame_2OBJ)
- {
- LIMITED_METHOD_CONTRACT;
- gcPtrs[0] = aGCPtr1;
- gcPtrs[1] = aGCPtr2;
- INDEBUG(Thread::ObjectRefProtected(aGCPtr1);)
- INDEBUG(Thread::ObjectRefProtected(aGCPtr2);)
- INDEBUG((*aGCPtr1).Validate ();)
- INDEBUG((*aGCPtr2).Validate ();)
- }
-#endif
-
- void GcScanRoots_Impl(promote_func *fn, ScanContext* sc)
- {
- WRAPPER_NO_CONTRACT;
- DoPromote(fn, sc, gcPtrs[0], FALSE);
- DoPromote(fn, sc, gcPtrs[1], FALSE);
- HelperMethodFrame::GcScanRoots_Impl(fn, sc);
- }
-
-#ifdef _DEBUG
-#ifndef DACCESS_COMPILE
- void Pop()
- {
- WRAPPER_NO_CONTRACT;
- HelperMethodFrame::Pop();
- Thread::ObjectRefNew(gcPtrs[0]);
- Thread::ObjectRefNew(gcPtrs[1]);
- }
-#endif // DACCESS_COMPILE
-
- BOOL Protects_Impl(OBJECTREF *ppORef)
- {
- LIMITED_METHOD_CONTRACT;
- return (ppORef == gcPtrs[0] || ppORef == gcPtrs[1]) ? TRUE : FALSE;
- }
-#endif
-
-private:
- PTR_OBJECTREF gcPtrs[2];
-};
-
-//-----------------------------------------------------------------------------
-// HelperMethodFrame_3OBJ
-//-----------------------------------------------------------------------------
-
-typedef DPTR(class HelperMethodFrame_3OBJ) PTR_HelperMethodFrame_3OBJ;
-
-class HelperMethodFrame_3OBJ : public HelperMethodFrame
-{
-public:
-#if !defined(DACCESS_COMPILE)
- HelperMethodFrame_3OBJ(
- void* fCallFtnEntry,
- unsigned attribs,
- OBJECTREF* aGCPtr1,
- OBJECTREF* aGCPtr2,
- OBJECTREF* aGCPtr3)
- : HelperMethodFrame(fCallFtnEntry, attribs, FrameIdentifier::HelperMethodFrame_3OBJ)
- {
- LIMITED_METHOD_CONTRACT;
- gcPtrs[0] = aGCPtr1;
- gcPtrs[1] = aGCPtr2;
- gcPtrs[2] = aGCPtr3;
- INDEBUG(Thread::ObjectRefProtected(aGCPtr1);)
- INDEBUG(Thread::ObjectRefProtected(aGCPtr2);)
- INDEBUG(Thread::ObjectRefProtected(aGCPtr3);)
- INDEBUG((*aGCPtr1).Validate();)
- INDEBUG((*aGCPtr2).Validate();)
- INDEBUG((*aGCPtr3).Validate();)
- }
-#endif
-
- void GcScanRoots_Impl(promote_func *fn, ScanContext* sc)
- {
- WRAPPER_NO_CONTRACT;
- DoPromote(fn, sc, gcPtrs[0], FALSE);
- DoPromote(fn, sc, gcPtrs[1], FALSE);
- DoPromote(fn, sc, gcPtrs[2], FALSE);
- HelperMethodFrame::GcScanRoots_Impl(fn, sc);
- }
-
-#ifdef _DEBUG
-#ifndef DACCESS_COMPILE
- void Pop()
- {
- WRAPPER_NO_CONTRACT;
- HelperMethodFrame::Pop();
- Thread::ObjectRefNew(gcPtrs[0]);
- Thread::ObjectRefNew(gcPtrs[1]);
- Thread::ObjectRefNew(gcPtrs[2]);
- }
-#endif // DACCESS_COMPILE
-
- BOOL Protects_Impl(OBJECTREF *ppORef)
- {
- LIMITED_METHOD_CONTRACT;
- return (ppORef == gcPtrs[0] || ppORef == gcPtrs[1] || ppORef == gcPtrs[2]) ? TRUE : FALSE;
- }
-#endif
-
-private:
- PTR_OBJECTREF gcPtrs[3];
-};
-
-
-//-----------------------------------------------------------------------------
-// HelperMethodFrame_PROTECTOBJ
-//-----------------------------------------------------------------------------
-
-typedef DPTR(class HelperMethodFrame_PROTECTOBJ) PTR_HelperMethodFrame_PROTECTOBJ;
-
-class HelperMethodFrame_PROTECTOBJ : public HelperMethodFrame
-{
-public:
-#if !defined(DACCESS_COMPILE)
- HelperMethodFrame_PROTECTOBJ(void* fCallFtnEntry, unsigned attribs, OBJECTREF* pObjRefs, int numObjRefs)
- : HelperMethodFrame(fCallFtnEntry, attribs, FrameIdentifier::HelperMethodFrame_PROTECTOBJ)
- {
- LIMITED_METHOD_CONTRACT;
- m_pObjRefs = pObjRefs;
- m_numObjRefs = numObjRefs;
-#ifdef _DEBUG
- for (UINT i = 0; i < m_numObjRefs; i++) {
- Thread::ObjectRefProtected(&m_pObjRefs[i]);
- m_pObjRefs[i].Validate();
- }
-#endif
- }
-#endif
-
- void GcScanRoots_Impl(promote_func *fn, ScanContext* sc)
- {
- WRAPPER_NO_CONTRACT;
- for (UINT i = 0; i < m_numObjRefs; i++) {
- DoPromote(fn, sc, &m_pObjRefs[i], FALSE);
- }
- HelperMethodFrame::GcScanRoots_Impl(fn, sc);
- }
-
-#ifdef _DEBUG
-#ifndef DACCESS_COMPILE
- void Pop()
- {
- WRAPPER_NO_CONTRACT;
- HelperMethodFrame::Pop();
- for (UINT i = 0; i < m_numObjRefs; i++) {
- Thread::ObjectRefNew(&m_pObjRefs[i]);
- }
- }
-#endif // DACCESS_COMPILE
-
- BOOL Protects_Impl(OBJECTREF *ppORef)
- {
- LIMITED_METHOD_CONTRACT;
- for (UINT i = 0; i < m_numObjRefs; i++) {
- if (ppORef == &m_pObjRefs[i])
- return TRUE;
- }
- return FALSE;
- }
-#endif
-
-private:
- PTR_OBJECTREF m_pObjRefs;
- UINT m_numObjRefs;
-};
-
class FramedMethodFrame : public TransitionFrame
{
TADDR m_pTransitionBlock;
@@ -3006,8 +2564,7 @@ class InterpreterFrame : public FramedMethodFrame
// a compiler error if you forget to code a maching GCPROTECT_END.
//
// - If you are GCPROTECTing something, it means you are expecting a GC to occur.
-// So we assert that GC is not forbidden. If you hit this assert, you probably need
-// a HELPER_METHOD_FRAME to protect the region that can cause the GC.
+// So we assert that GC is not forbidden.
//------------------------------------------------------------------------
#ifndef DACCESS_COMPILE
diff --git a/src/coreclr/vm/gccover.cpp b/src/coreclr/vm/gccover.cpp
index b029140d88a97c..1e7ce22a79f924 100644
--- a/src/coreclr/vm/gccover.cpp
+++ b/src/coreclr/vm/gccover.cpp
@@ -20,7 +20,6 @@
#pragma warning(disable:4663)
#include "eeconfig.h"
-#include "gms.h"
#include "utsem.h"
#include "gccover.h"
#include "virtualcallstub.h"
@@ -1331,7 +1330,7 @@ BOOL OnGcCoverageInterrupt(PCONTEXT regs)
RemoveGcCoverageInterrupt(instrPtr, savedInstrPtr, gcCover, offset);
return TRUE;
}
-
+
// The thread is in preemptive mode. Normally, it should not be able to trigger GC.
// Besides the GC may be already happening and scanning our stack.
if (!pThread->PreemptiveGCDisabled())
diff --git a/src/coreclr/vm/gchelpers.cpp b/src/coreclr/vm/gchelpers.cpp
index 909ae0fec8ecd9..e30e936d760f87 100644
--- a/src/coreclr/vm/gchelpers.cpp
+++ b/src/coreclr/vm/gchelpers.cpp
@@ -1456,8 +1456,6 @@ extern "C" HCIMPL2_RAW(VOID, JIT_CheckedWriteBarrier, Object **dst, Object *ref)
}
#endif // FEATURE_COUNT_GC_WRITE_BARRIERS
- // no HELPER_METHOD_FRAME because we are MODE_COOPERATIVE, GC_NOTRIGGER
-
VolatileStore(dst, ref);
// if the dst is outside of the heap (unboxed value classes) then we
@@ -1523,7 +1521,6 @@ extern "C" HCIMPL2_RAW(VOID, JIT_WriteBarrier, Object **dst, Object *ref)
#ifdef FEATURE_COUNT_GC_WRITE_BARRIERS
IncUncheckedBarrierCount();
#endif
- // no HELPER_METHOD_FRAME because we are MODE_COOPERATIVE, GC_NOTRIGGER
VolatileStore(dst, ref);
@@ -1582,8 +1579,6 @@ extern "C" HCIMPL2_RAW(VOID, JIT_WriteBarrierEnsureNonHeapTarget, Object **dst,
assert(!GCHeapUtilities::GetGCHeap()->IsHeapPointer((void*)dst));
- // no HELPER_METHOD_FRAME because we are MODE_COOPERATIVE, GC_NOTRIGGER
-
// not a release store because NonHeap.
*dst = ref;
}
diff --git a/src/coreclr/vm/gms.h b/src/coreclr/vm/gms.h
deleted file mode 100644
index be26cdf1be2147..00000000000000
--- a/src/coreclr/vm/gms.h
+++ /dev/null
@@ -1,5 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-
-
-#include "gmscpu.h"
diff --git a/src/coreclr/vm/i386/asmconstants.h b/src/coreclr/vm/i386/asmconstants.h
index a85d6f79e95239..82887f9ad9fa61 100644
--- a/src/coreclr/vm/i386/asmconstants.h
+++ b/src/coreclr/vm/i386/asmconstants.h
@@ -104,51 +104,6 @@ ASMCONSTANTS_C_ASSERT(EHContext_Esp == offsetof(EHContext,Esp))
ASMCONSTANTS_C_ASSERT(EHContext_Eip == offsetof(EHContext,Eip))
#endif // FEATURE_EH_FUNCLETS
-
-// from clr/src/fjit/helperframe.h
-#define SIZEOF_MachState 40
-ASMCONSTANTS_C_ASSERT(SIZEOF_MachState == sizeof(MachState))
-
-#define MachState__pEdi 0
-ASMCONSTANTS_C_ASSERT(MachState__pEdi == offsetof(MachState, _pEdi))
-
-#define MachState__edi 4
-ASMCONSTANTS_C_ASSERT(MachState__edi == offsetof(MachState, _edi))
-
-#define MachState__pEsi 8
-ASMCONSTANTS_C_ASSERT(MachState__pEsi == offsetof(MachState, _pEsi))
-
-#define MachState__esi 12
-ASMCONSTANTS_C_ASSERT(MachState__esi == offsetof(MachState, _esi))
-
-#define MachState__pEbx 16
-ASMCONSTANTS_C_ASSERT(MachState__pEbx == offsetof(MachState, _pEbx))
-
-#define MachState__ebx 20
-ASMCONSTANTS_C_ASSERT(MachState__ebx == offsetof(MachState, _ebx))
-
-#define MachState__pEbp 24
-ASMCONSTANTS_C_ASSERT(MachState__pEbp == offsetof(MachState, _pEbp))
-
-#define MachState__ebp 28
-ASMCONSTANTS_C_ASSERT(MachState__ebp == offsetof(MachState, _ebp))
-
-#define MachState__esp 32
-ASMCONSTANTS_C_ASSERT(MachState__esp == offsetof(MachState, _esp))
-
-#define MachState__pRetAddr 36
-ASMCONSTANTS_C_ASSERT(MachState__pRetAddr == offsetof(MachState, _pRetAddr))
-
-#define LazyMachState_captureEbp 40
-ASMCONSTANTS_C_ASSERT(LazyMachState_captureEbp == offsetof(LazyMachState, captureEbp))
-
-#define LazyMachState_captureEsp 44
-ASMCONSTANTS_C_ASSERT(LazyMachState_captureEsp == offsetof(LazyMachState, captureEsp))
-
-#define LazyMachState_captureEip 48
-ASMCONSTANTS_C_ASSERT(LazyMachState_captureEip == offsetof(LazyMachState, captureEip))
-
-
#define VASigCookie__StubOffset 4
ASMCONSTANTS_C_ASSERT(VASigCookie__StubOffset == offsetof(VASigCookie, pNDirectILStub))
diff --git a/src/coreclr/vm/i386/asmhelpers.S b/src/coreclr/vm/i386/asmhelpers.S
index ca2803e80bdf63..b77d482fe2d670 100644
--- a/src/coreclr/vm/i386/asmhelpers.S
+++ b/src/coreclr/vm/i386/asmhelpers.S
@@ -178,9 +178,9 @@ LOCAL_LABEL(donestack):
LOCAL_LABEL(CallDescrWorkerInternalReturnAddress):
#ifdef _DEBUG
- nop // This is a tag that we use in an assert. Fcalls expect to
- // be called from Jitted code or from certain blessed call sites like
- // this one. (See HelperMethodFrame::EnsureInit)
+ nop // Debug-only tag used in asserts.
+ // FCalls expect to be called from Jitted code or specific approved call sites,
+ // like this one.
#endif
// Save FP return value if necessary
@@ -221,83 +221,6 @@ PATCH_LABEL CallDescrWorkerInternalReturnAddressOffset
NESTED_END CallDescrWorkerInternal, _TEXT
-#ifdef _DEBUG
-// int __fastcall HelperMethodFrameRestoreState(HelperMethodFrame*, struct MachState *)
-LEAF_ENTRY HelperMethodFrameRestoreState, _TEXT
- mov eax, edx // eax = MachState*
-#else // _DEBUG
-// int __fastcall HelperMethodFrameRestoreState(struct MachState *)
-LEAF_ENTRY HelperMethodFrameRestoreState, _TEXT
- mov eax, ecx // eax = MachState*
-#endif // _DEBUG
- // restore the registers from the m_MachState structure. Note that
- // we only do this for register that where not saved on the stack
- // at the time the machine state snapshot was taken.
-
- cmp dword ptr [eax+MachState__pRetAddr], 0
-
-#ifdef _DEBUG
- jnz LOCAL_LABEL(noConfirm)
-
- mov eax, ebp
-
- // Create a minimal EBP-frame (for clean stack trace under debugger)
- PROLOG_BEG
- PROLOG_END
-
- // Call HelperMethodFrameConfirmState (with stack alignment padding)
- #define STACK_ALIGN_PADDING 4
- sub esp, STACK_ALIGN_PADDING
- push eax // eax = ebp
- push ebx
- push edi
- push esi
- push ecx // HelperFrame*
- CHECK_STACK_ALIGNMENT
- call C_FUNC(HelperMethodFrameConfirmState)
- add esp, STACK_ALIGN_PADDING
- #undef STACK_ALIGN_PADDING
-
- // Restore EBP
- EPILOG_BEG
- EPILOG_END
-
- // on return, eax = MachState*
- cmp DWORD PTR [eax + MachState__pRetAddr], 0
-LOCAL_LABEL(noConfirm):
-#endif // _DEBUG
-
- jz LOCAL_LABEL(doRet)
-
- lea edx, [eax + MachState__esi] // Did we have to spill ESI
- cmp [eax + MachState__pEsi], edx
- jnz LOCAL_LABEL(SkipESI)
- mov esi, [edx] // Then restore it
-
-LOCAL_LABEL(SkipESI):
- lea edx, [eax + MachState__edi] // Did we have to spill EDI
- cmp [eax + MachState__pEdi], edx
- jnz LOCAL_LABEL(SkipEDI)
- mov edi, [edx] // Then restore it
-
-LOCAL_LABEL(SkipEDI):
- lea edx, [eax + MachState__ebx] // Did we have to spill EBX
- cmp [eax + MachState__pEbx], edx
- jnz LOCAL_LABEL(SkipEBX)
- mov ebx, [edx] // Then restore it
-
-LOCAL_LABEL(SkipEBX):
- lea edx, [eax + MachState__ebp] // Did we have to spill EBP
- cmp [eax + MachState__pEbp], edx
- jnz LOCAL_LABEL(SkipEBP)
- mov ebp, [edx] // Then restore it
-
-LOCAL_LABEL(SkipEBP):
-LOCAL_LABEL(doRet):
- xor eax, eax
- ret
-LEAF_END HelperMethodFrameRestoreState, _TEXT
-
#ifdef FEATURE_HIJACK
// A JITted method's return address was hijacked to return to us here.
diff --git a/src/coreclr/vm/i386/asmhelpers.asm b/src/coreclr/vm/i386/asmhelpers.asm
index 88c801b35cc2f3..77d5bd32439551 100644
--- a/src/coreclr/vm/i386/asmhelpers.asm
+++ b/src/coreclr/vm/i386/asmhelpers.asm
@@ -27,9 +27,6 @@ EXTERN g_pThrowDivideByZeroException:DWORD
EXTERN g_pThrowOverflowException:DWORD
EXTERN __imp__RtlUnwind@16:DWORD
-ifdef _DEBUG
-EXTERN _HelperMethodFrameConfirmState@20:PROC
-endif
ifdef FEATURE_HIJACK
EXTERN _OnHijackWorker@4:PROC
endif ;FEATURE_HIJACK
@@ -502,9 +499,9 @@ donestack:
CallDescrWorkerInternalReturnAddress:
ifdef _DEBUG
- nop ; This is a tag that we use in an assert. Fcalls expect to
- ; be called from Jitted code or from certain blessed call sites like
- ; this one. (See HelperMethodFrame::EnsureInit)
+ nop ; Debug-only tag used in asserts.
+ ; FCalls expect to be called from Jitted code or specific approved call sites,
+ ; like this one.
endif
; Save FP return value if necessary
@@ -541,66 +538,6 @@ _CallDescrWorkerInternalReturnAddressOffset:
CallDescrWorkerInternal endp
-ifdef _DEBUG
-; int __fastcall HelperMethodFrameRestoreState(HelperMethodFrame*, struct MachState *)
-FASTCALL_FUNC HelperMethodFrameRestoreState,8
- mov eax, edx ; eax = MachState*
-else
-; int __fastcall HelperMethodFrameRestoreState(struct MachState *)
-FASTCALL_FUNC HelperMethodFrameRestoreState,4
- mov eax, ecx ; eax = MachState*
-endif
- ; restore the registers from the m_MachState structure. Note that
- ; we only do this for register that where not saved on the stack
- ; at the time the machine state snapshot was taken.
-
- cmp [eax+MachState__pRetAddr], 0
-
-ifdef _DEBUG
- jnz noConfirm
- push ebp
- push ebx
- push edi
- push esi
- push ecx ; HelperFrame*
- call _HelperMethodFrameConfirmState@20
- ; on return, eax = MachState*
- cmp [eax+MachState__pRetAddr], 0
-noConfirm:
-endif
-
- jz doRet
-
- lea edx, [eax+MachState__esi] ; Did we have to spill ESI
- cmp [eax+MachState__pEsi], edx
- jnz SkipESI
- mov esi, [edx] ; Then restore it
-SkipESI:
-
- lea edx, [eax+MachState__edi] ; Did we have to spill EDI
- cmp [eax+MachState__pEdi], edx
- jnz SkipEDI
- mov edi, [edx] ; Then restore it
-SkipEDI:
-
- lea edx, [eax+MachState__ebx] ; Did we have to spill EBX
- cmp [eax+MachState__pEbx], edx
- jnz SkipEBX
- mov ebx, [edx] ; Then restore it
-SkipEBX:
-
- lea edx, [eax+MachState__ebp] ; Did we have to spill EBP
- cmp [eax+MachState__pEbp], edx
- jnz SkipEBP
- mov ebp, [edx] ; Then restore it
-SkipEBP:
-
-doRet:
- xor eax, eax
- retn
-FASTCALL_ENDFUNC HelperMethodFrameRestoreState
-
-
ifdef FEATURE_HIJACK
; A JITted method's return address was hijacked to return to us here.
@@ -1785,7 +1722,7 @@ ifdef CHAIN_LOOKUP
;==========================================================================
_ResolveWorkerChainLookupAsmStub@0 proc public
; this is the part of the stack that is present as we enter this function:
-
+
ChainLookup__token equ 00h
ChainLookup__indirect_addr equ 04h
ChainLookup__caller_ret_addr equ 08h
diff --git a/src/coreclr/vm/i386/cgenx86.cpp b/src/coreclr/vm/i386/cgenx86.cpp
index ad536bdd9ca3f2..e242668963dcd9 100644
--- a/src/coreclr/vm/i386/cgenx86.cpp
+++ b/src/coreclr/vm/i386/cgenx86.cpp
@@ -1,10 +1,8 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
+
// CGENX86.CPP -
-//
// Various helper routines for generating x86 assembly code.
-//
-//
// Precompiled Header
@@ -209,181 +207,6 @@ void TransitionFrame::UpdateRegDisplayHelper(const PREGDISPLAY pRD, UINT cbStack
RETURN;
}
-void HelperMethodFrame::UpdateRegDisplay_Impl(const PREGDISPLAY pRD, bool updateFloats)
-{
- CONTRACT_VOID
- {
- NOTHROW;
- GC_NOTRIGGER;
- MODE_ANY;
- PRECONDITION(m_MachState.isValid()); // EnsureInit has been called
- SUPPORTS_DAC;
- }
- CONTRACT_END;
-
- ENABLE_FORBID_GC_LOADER_USE_IN_THIS_SCOPE();
-
- LOG((LF_GCROOTS, LL_INFO100000, "STACKWALK HelperMethodFrame::UpdateRegDisplay cached ip:%p, sp:%p\n", m_MachState.GetRetAddr(), m_MachState.esp()));
-
-#ifdef FEATURE_EH_FUNCLETS
-
- pRD->IsCallerContextValid = FALSE;
- pRD->IsCallerSPValid = FALSE; // Don't add usage of this field. This is only temporary.
-
-#ifdef DACCESS_COMPILE
- // For DAC, we may get here when the HMF is still uninitialized.
- // So we may need to unwind here.
- if (!m_MachState.isValid())
- {
- // This allocation throws on OOM.
- MachState* pUnwoundState = (MachState*)DacAllocHostOnlyInstance(sizeof(*pUnwoundState), true);
-
- EnsureInit(pUnwoundState);
-
- SetRegdisplayPCTAddr(pRD, dac_cast(pUnwoundState->pRetAddr()));
- pRD->pCurrentContext->Esp = pRD->SP = pUnwoundState->esp();
-
- // Do not use pUnwoundState->p##regname() here because it returns NULL in this case
- pRD->pCurrentContext->Edi = pUnwoundState->_edi;
- pRD->pCurrentContext->Esi = pUnwoundState->_esi;
- pRD->pCurrentContext->Ebx = pUnwoundState->_ebx;
- pRD->pCurrentContext->Ebp = pUnwoundState->_ebp;
-
-#define CALLEE_SAVED_REGISTER(regname) pRD->pCurrentContextPointers->regname = (DWORD*) pUnwoundState->p##regname();
- ENUM_CALLEE_SAVED_REGISTERS();
-#undef CALLEE_SAVED_REGISTER
-
- ClearRegDisplayArgumentAndScratchRegisters(pRD);
-
- return;
- }
-#endif // DACCESS_COMPILE
-
- SetRegdisplayPCTAddr(pRD, dac_cast(m_MachState.pRetAddr()));
- pRD->pCurrentContext->Esp = pRD->SP = (DWORD) m_MachState.esp();
-
-#define CALLEE_SAVED_REGISTER(regname) pRD->pCurrentContext->regname = *((DWORD*) m_MachState.p##regname());
- ENUM_CALLEE_SAVED_REGISTERS();
-#undef CALLEE_SAVED_REGISTER
-
-#define CALLEE_SAVED_REGISTER(regname) pRD->pCurrentContextPointers->regname = (DWORD*) m_MachState.p##regname();
- ENUM_CALLEE_SAVED_REGISTERS();
-#undef CALLEE_SAVED_REGISTER
-
- //
- // Clear all knowledge of scratch registers. We're skipping to any
- // arbitrary point on the stack, and frames aren't required to preserve or
- // keep track of these anyways.
- //
-
- ClearRegDisplayArgumentAndScratchRegisters(pRD);
-
-#else // FEATURE_EH_FUNCLETS
-
- // reset pContext; it's only valid for active (top-most) frame
- pRD->pContext = NULL;
-
-#ifdef DACCESS_COMPILE
-
- //
- // In the dac case we may have gotten here
- // without the frame being initialized, so
- // try and initialize on the fly.
- //
-
- if (!m_MachState.isValid())
- {
- MachState unwindState;
-
- EnsureInit(&unwindState);
- SetRegdisplayPCTAddr(pRD, dac_cast(unwindState.pRetAddr()));
- pRD->SP = unwindState._esp;
-
- // Get some special host instance memory
- // so we have a place to point to.
- // This host memory has no target address
- // and so won't be looked up or used for
- // anything else.
- MachState* thisState = (MachState*)
- DacAllocHostOnlyInstance(sizeof(*thisState), true);
-
- thisState->_edi = unwindState._edi;
- pRD->pEdi = (DWORD *)&thisState->_edi;
- thisState->_esi = unwindState._esi;
- pRD->pEsi = (DWORD *)&thisState->_esi;
- thisState->_ebx = unwindState._ebx;
- pRD->pEbx = (DWORD *)&thisState->_ebx;
- thisState->_ebp = unwindState._ebp;
- pRD->pEbp = (DWORD *)&thisState->_ebp;
-
- // EnsureInit always sets m_RegArgs to zero
- // in the real code. I'm not sure exactly
- // what should happen in the on-the-fly case,
- // but go with what would happen from an EnsureInit.
-
- RETURN;
- }
-
-#endif // #ifdef DACCESS_COMPILE
-
- // DACCESS: The MachState pointers are kept as PTR_TADDR so
- // the host pointers here refer to the appropriate size and
- // these casts are not a problem.
- pRD->pEdi = (DWORD*) m_MachState.pEdi();
- pRD->pEsi = (DWORD*) m_MachState.pEsi();
- pRD->pEbx = (DWORD*) m_MachState.pEbx();
- pRD->pEbp = (DWORD*) m_MachState.pEbp();
-
- SetRegdisplayPCTAddr(pRD, dac_cast(m_MachState.pRetAddr()));
- pRD->SP = (DWORD) m_MachState.esp();
-
-#endif // FEATURE_EH_FUNCLETS
-
- RETURN;
-}
-
-#ifdef _DEBUG_IMPL
-// Confirm that if the machine state was not initialized, then
-// any unspilled callee saved registers did not change
-EXTERN_C MachState* STDCALL HelperMethodFrameConfirmState(HelperMethodFrame* frame, void* esiVal, void* ediVal, void* ebxVal, void* ebpVal)
- {
- CONTRACTL
- {
- NOTHROW;
- GC_NOTRIGGER;
- MODE_ANY;
- DEBUG_ONLY;
- }
- CONTRACTL_END;
-
- MachState* state = frame->MachineState();
-
- // if we've already executed this check once for this helper method frame then
- // we don't do the check again because it is very expensive.
- if (frame->HaveDoneConfirmStateCheck())
- {
- return state;
- }
-
- // probe to avoid a kazillion violations in the code that follows.
- BEGIN_DEBUG_ONLY_CODE;
- if (!state->isValid())
- {
- frame->EnsureInit(NULL);
- _ASSERTE(state->_pEsi != &state->_esi || state->_esi == (TADDR)esiVal);
- _ASSERTE(state->_pEdi != &state->_edi || state->_edi == (TADDR)ediVal);
- _ASSERTE(state->_pEbx != &state->_ebx || state->_ebx == (TADDR)ebxVal);
- _ASSERTE(state->_pEbp != &state->_ebp || state->_ebp == (TADDR)ebpVal);
- }
- END_DEBUG_ONLY_CODE;
-
- // set that we have executed this check once for this helper method frame.
- frame->SetHaveDoneConfirmStateCheck();
-
- return state;
-}
-#endif
-
void ExternalMethodFrame::UpdateRegDisplay_Impl(const PREGDISPLAY pRD, bool updateFloats)
{
CONTRACT_VOID
diff --git a/src/coreclr/vm/i386/excepx86.cpp b/src/coreclr/vm/i386/excepx86.cpp
index 7b24c632ad4cb1..a320a198235bc4 100644
--- a/src/coreclr/vm/i386/excepx86.cpp
+++ b/src/coreclr/vm/i386/excepx86.cpp
@@ -2068,7 +2068,7 @@ StackWalkAction COMPlusThrowCallback( // SWA value
if (pData->pPrevExceptionRecord) {
// FCALLS have an extra SEH record in debug because of the desctructor
// associated with ForbidGC checking. This is benign, so just ignore it.
- if (pFrame) _ASSERTE(pData->pPrevExceptionRecord < pFrame || pFrame->GetFrameIdentifier() == FrameIdentifier::HelperMethodFrame);
+ if (pFrame) _ASSERTE(pData->pPrevExceptionRecord < pFrame);
if (pCf->IsFrameless()) _ASSERTE((ULONG_PTR)pData->pPrevExceptionRecord <= GetRegdisplaySP(pCf->GetRegisterSet()));
}
}
diff --git a/src/coreclr/vm/i386/gmsasm.S b/src/coreclr/vm/i386/gmsasm.S
deleted file mode 100644
index 30871cdf5f08a2..00000000000000
--- a/src/coreclr/vm/i386/gmsasm.S
+++ /dev/null
@@ -1,27 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-
-.intel_syntax noprefix
-#include "unixasmmacros.inc"
-#include "asmconstants.h"
-
-// int __fastcall LazyMachStateCaptureState(struct LazyMachState *pState);
-LEAF_ENTRY LazyMachStateCaptureState, _TEXT
- // marks that this is not yet valid
- mov dword ptr [ecx+MachState__pRetAddr], 0
-
- // remember register values
- mov [ecx+MachState__edi], edi
- mov [ecx+MachState__esi], esi
- mov [ecx+MachState__ebx], ebx
- mov [ecx+LazyMachState_captureEbp], ebp
- mov [ecx+LazyMachState_captureEsp], esp
-
- // capture return address
- mov eax, [esp]
- mov dword ptr [ecx+LazyMachState_captureEip], eax
-
- // return 0
- xor eax, eax
- ret
-LEAF_END LazyMachStateCaptureState, _TEXT
diff --git a/src/coreclr/vm/i386/gmsasm.asm b/src/coreclr/vm/i386/gmsasm.asm
deleted file mode 100644
index 5870fb04fc8478..00000000000000
--- a/src/coreclr/vm/i386/gmsasm.asm
+++ /dev/null
@@ -1,31 +0,0 @@
-; Licensed to the .NET Foundation under one or more agreements.
-; The .NET Foundation licenses this file to you under the MIT license.
-
-;
-; *** NOTE: If you make changes to this file, propagate the changes to
-; gmsasm.s in this directory
-
- .586
- .model flat
-
-include asmconstants.inc
-
- option casemap:none
- .code
-
-; int __fastcall LazyMachStateCaptureState(struct LazyMachState *pState);
-@LazyMachStateCaptureState@4 proc public
- mov [ecx+MachState__pRetAddr], 0 ; marks that this is not yet valid
- mov [ecx+MachState__edi], edi ; remember register values
- mov [ecx+MachState__esi], esi
- mov [ecx+MachState__ebx], ebx
- mov [ecx+LazyMachState_captureEbp], ebp
- mov [ecx+LazyMachState_captureEsp], esp
-
- mov eax, [esp] ; capture return address
- mov [ecx+LazyMachState_captureEip], eax
- xor eax, eax
- retn
-@LazyMachStateCaptureState@4 endp
-
-end
diff --git a/src/coreclr/vm/i386/gmscpu.h b/src/coreclr/vm/i386/gmscpu.h
deleted file mode 100644
index 9dd91f42caf1c6..00000000000000
--- a/src/coreclr/vm/i386/gmscpu.h
+++ /dev/null
@@ -1,138 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-
-/**************************************************************/
-/* gmscpu.h */
-/**************************************************************/
-/* HelperFrame is defines 'GET_STATE(machState)' macro, which
- figures out what the state of the machine will be when the
- current method returns. It then stores the state in the
- JIT_machState structure. */
-
-/**************************************************************/
-
-#ifndef __gmsx86_h__
-#define __gmsx86_h__
-
-#define __gmsx86_h__
-
-#ifdef _DEBUG
-class HelperMethodFrame;
-struct MachState;
-EXTERN_C MachState* STDCALL HelperMethodFrameConfirmState(HelperMethodFrame* frame, void* esiVal, void* ediVal, void* ebxVal, void* ebpVal);
-#endif
-
- // A MachState indicates the register state of the processor at some point in time (usually
- // just before or after a call is made). It can be made one of two ways. Either explicitly
- // (when you for some reason know the values of all the registers), or implicitly using the
- // GET_STATE macros.
-
-typedef DPTR(struct MachState) PTR_MachState;
-struct MachState {
-
- MachState()
- {
- LIMITED_METHOD_DAC_CONTRACT;
- INDEBUG(memset(this, 0xCC, sizeof(MachState));)
- }
-
- bool isValid() { LIMITED_METHOD_DAC_CONTRACT; _ASSERTE(dac_cast(_pRetAddr) != INVALID_POINTER_CC); return(_pRetAddr != 0); }
- TADDR* pEdi() { LIMITED_METHOD_DAC_CONTRACT; _ASSERTE(dac_cast(_pEdi) != INVALID_POINTER_CC); return(_pEdi); }
- TADDR* pEsi() { LIMITED_METHOD_DAC_CONTRACT; _ASSERTE(dac_cast(_pEsi) != INVALID_POINTER_CC); return(_pEsi); }
- TADDR* pEbx() { LIMITED_METHOD_DAC_CONTRACT; _ASSERTE(dac_cast(_pEbx) != INVALID_POINTER_CC); return(_pEbx); }
- TADDR* pEbp() { LIMITED_METHOD_DAC_CONTRACT; _ASSERTE(dac_cast(_pEbp) != INVALID_POINTER_CC); return(_pEbp); }
- TADDR esp() { LIMITED_METHOD_DAC_CONTRACT; _ASSERTE(isValid()); return(_esp); }
- PTR_TADDR pRetAddr() { LIMITED_METHOD_DAC_CONTRACT; _ASSERTE(isValid()); return(_pRetAddr); }
- TADDR GetRetAddr() { LIMITED_METHOD_DAC_CONTRACT; _ASSERTE(isValid()); return *_pRetAddr; }
-#ifndef DACCESS_COMPILE
- void SetRetAddr(TADDR* addr) { LIMITED_METHOD_CONTRACT; _ASSERTE(isValid()); _pRetAddr = addr; }
-#endif
-
- friend class HelperMethodFrame;
- friend class CheckAsmOffsets;
- friend struct LazyMachState;
-#ifdef _DEBUG
- friend MachState* STDCALL HelperMethodFrameConfirmState(HelperMethodFrame* frame, void* esiVal, void* ediVal, void* ebxVal, void* ebpVal);
-#endif
-
-
-protected:
- // Note the fields are laid out to make generating a
- // MachState structure from assembly code very easy
-
- // The state of all the callee saved registers.
- // If the register has been spill to the stack p
- // points at this location, otherwise it points
- // at the field field itself
- PTR_TADDR _pEdi;
- TADDR _edi;
- PTR_TADDR _pEsi;
- TADDR _esi;
- PTR_TADDR _pEbx;
- TADDR _ebx;
- PTR_TADDR _pEbp;
- TADDR _ebp;
-
- TADDR _esp; // stack pointer after the function returns
- PTR_TADDR _pRetAddr; // The address of the stored IP address (points into the stack)
-};
-
-/********************************************************************/
-/* This allows you to defer the computation of the Machine state
- until later. Note that we don't reuse slots, because we want
- this to be threadsafe without locks */
-
-struct LazyMachState;
-typedef DPTR(LazyMachState) PTR_LazyMachState;
-struct LazyMachState : public MachState {
- // compute the machine state of the processor as it will exist just
- // after the return after at most'funCallDepth' number of functions.
- // if 'testFtn' is non-NULL, the return address is tested at each
- // return instruction encountered. If this test returns non-NULL,
- // then stack walking stops (thus you can walk up to the point that the
- // return address matches some criteria
-
- // Normally this is called with funCallDepth=1 and testFtn = 0 so that
- // it returns the state of the processor after the function that called 'captureState()'
- void setLazyStateFromUnwind(MachState* copy);
- static void unwindLazyState(LazyMachState* baseState,
- MachState* lazyState,
- DWORD threadId,
- int funCallDepth = 1);
-
- friend class HelperMethodFrame;
- friend class CheckAsmOffsets;
-private:
- TADDR captureEbp; // Ebp at the time of capture
- TADDR captureEsp; // Esp at the time of capture
- TADDR captureEip; // Eip at the time of capture
-};
-
-inline void LazyMachState::setLazyStateFromUnwind(MachState* copy)
-{
- // _pRetAddr has to be the last thing updated when we make the copy (because its
- // is the _pRetAddr becoming non-zero that flips this from invalid to valid.
- // we assert that it is the last field in the struct.
- static_assert_no_msg(offsetof(MachState, _pRetAddr) + sizeof(_pRetAddr) == sizeof(MachState));
-
- memcpy(this, copy, offsetof(MachState, _pRetAddr));
-
- // this has to be last
- VolatileStore((TADDR*)&_pRetAddr, dac_cast(copy->_pRetAddr));
-}
-
-// Do the initial capture of the machine state. This is meant to be
-// as light weight as possible, as we may never need the state that
-// we capture. Thus to complete the process you need to call
-// 'getMachState()', which finishes the process
-EXTERN_C int __fastcall LazyMachStateCaptureState(struct LazyMachState *pState);
-
-// CAPTURE_STATE captures just enough register state so that the state of the
-// processor can be deterined just after the routine that has CAPTURE_STATE in
-// it returns.
-
-// Note that the return is never taken, it is there for epilog walking
-#define CAPTURE_STATE(machState, ret) \
- if (LazyMachStateCaptureState(machState)) ret
-
-#endif
diff --git a/src/coreclr/vm/i386/gmsx86.cpp b/src/coreclr/vm/i386/gmsx86.cpp
deleted file mode 100644
index 1a08bf310e51a2..00000000000000
--- a/src/coreclr/vm/i386/gmsx86.cpp
+++ /dev/null
@@ -1,1351 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-
-/**************************************************************/
-/* gmsx86.cpp */
-/**************************************************************/
-
-#include "common.h"
-#include "gmscpu.h"
-
-#ifdef TARGET_UNIX
-#define USE_EXTERNAL_UNWINDER
-#endif
-
-#ifndef USE_EXTERNAL_UNWINDER
-/***************************************************************/
-/* setMachState figures out what the state of the CPU will be
- when the function that calls 'setMachState' returns. It stores
- this information in 'frame'
-
- setMachState works by simulating the execution of the
- instructions starting at the instruction following the
- call to 'setMachState' and continuing until a return instruction
- is simulated. To avoid having to process arbitrary code, the
- call to 'setMachState' should be called as follows
-
- if (machState.setMachState != 0) return;
-
- setMachState is guaranteed to return 0 (so the return
- statement will never be executed), but the expression above
- ensures that there is a 'quick' path to epilog
- of the function. This ensures that setMachState will only
- have to parse a limited number of X86 instructions. */
-
-
-/***************************************************************/
-#ifndef POISONC
-#define POISONC ((sizeof(int *) == 4)?0xCCCCCCCCU:UI64(0xCCCCCCCCCCCCCCCC))
-#endif
-
-/***************************************************************/
-/* the 'zeroFtn and 'recursiveFtn' are only here to determine
- if if mscorwks itself has been instrumented by a profiler
- that intercepts calls or epilogs of functions. (the
- callsInstrumented and epilogInstrumented functions). */
-
-#if !defined(DACCESS_COMPILE)
-
-#ifdef _MSC_VER
-#pragma optimize("gsy", on ) // optimize to ensure that code generation does not have junk in it
-#endif // _MSC_VER
-#pragma warning(disable:4717)
-
-static int __stdcall zeroFtn() {
- return 0;
-}
-
-#ifdef __clang__
-#pragma clang diagnostic push
-#pragma clang diagnostic ignored "-Winfinite-recursion"
-#endif
-
-static int __stdcall recursiveFtn() {
- return recursiveFtn()+1;
-}
-
-#ifdef __clang__
-#pragma clang diagnostic pop
-#endif
-
-#ifdef _MSC_VER
-#pragma optimize("", on )
-#endif // _MSC_VER
-
-
-/* Has mscorwks been instrumented so that calls are morphed into push XXXX call */
-static bool callsInstrumented() {
- // Does the recursive function begin with push XXXX call
- PTR_BYTE ptr = PTR_BYTE(recursiveFtn);
-
- return (ptr[0] == 0x68 && ptr[5] == 0xe8); // PUSH XXXX, call
-}
-
-/* Has mscorwks been instrumented so function prolog and epilogs are replaced with
- jmp [XXXX] */
-
-static bool epilogInstrumented() {
-
- PTR_BYTE ptr = PTR_BYTE(zeroFtn);
- if (ptr[0] == 0xe8) // call (prolog instrumentation)
- ptr += 5;
- if (ptr[0] == 0x33 && ptr[1] == 0xc0) // xor eax eax
- ptr += 2;
- return (ptr[0] == 0xeb || ptr[0] == 0xe9); // jmp
-}
-
-#else
-
- // Note that we have the callsInstrumeted and epilogInstrumented
- // functions so that the looser heuristics used for instrumented code
- // can't foul up an instrumented mscorwks. For simplicity sake we
- // don't bother with this in the DAC, which means that the DAC could
- // be misled more frequently than mscorwks itself, but I still think
- // it will not be misled in any real scenario
-static bool callsInstrumented() { LIMITED_METHOD_DAC_CONTRACT; return true; }
-static bool epilogInstrumented() { LIMITED_METHOD_DAC_CONTRACT; return true; }
-
-#endif // !defined(DACCESS_COMPILE)
-
-/***************************************************************/
-/* returns true if a call to 'ip' should be entered by the
- epilog walker. Bascically we are looking for things that look
- like __SEH_epilog. In particular we look for things that
- pops a register before doing a push. If we see something
- that we don't recognise, we dont consider it a epilog helper
- and return false.
-*/
-
-static bool shouldEnterCall(PTR_BYTE ip) {
- SUPPORTS_DAC;
-
- int datasize; // helper variable for decoding of address modes
- int mod; // helper variable for decoding of mod r/m
- int rm; // helper variable for decoding of mod r/m
-
- int pushes = 0;
-
- // we should start unbalanced pops within 48 instrs. If not, it is not a special epilog function
- // the only reason we need as many instructions as we have below is because coreclr
- // gets instrumented for profiling, code coverage, BBT etc, and we want these things to
- // just work.
- for (int i = 0; i < 48; i++) {
- switch(*ip) {
- case 0xF2: // repne
- case 0xF3: // repe
- case 0x90: // nop
- ip++;
- break;
-
- case 0x68: // push 0xXXXXXXXX
- ip += 5;
-
- // For office profiler. They morph tail calls into push TARGET; jmp helper
- // so if you see
- //
- // push XXXX
- // jmp xxxx
- //
- // and we notice that coreclr has been instrumented and
- // xxxx starts with a JMP [] then do what you would do for jmp XXXX
- if (*ip == 0xE9 && callsInstrumented()) { // jmp helper
- PTR_BYTE tmpIp = ip + 5;
- PTR_BYTE target = tmpIp + (int32_t)*((PTR_TADDR)(PTR_TO_TADDR(tmpIp) - 4));
- if (target[0] == 0xFF && target[1] == 0x25) { // jmp [xxxx] (to external dll)
- ip = PTR_BYTE(*((PTR_TADDR)(PTR_TO_TADDR(ip) - 4)));
- }
- }
- else {
- pushes++;
- }
- break;
-
- case 0x50: // push EAX
- case 0x51: // push ECX
- case 0x52: // push EDX
- case 0x53: // push EBX
- case 0x55: // push EBP
- case 0x56: // push ESI
- case 0x57: // push EDI
- pushes++;
- ip++;
- break;
-
- case 0xE8: // call
- ip += 5;
- pushes = 0; // This assumes that all of the previous pushes are arguments to this call
- break;
-
- case 0xFF:
- if (ip[1] != 0x15) // call [XXXX] is OK (prolog of epilog helper is intrumented)
- return false; // but everything else is not OK.
- ip += 6;
- pushes = 0; // This assumes that all of the previous pushes are arguments to this call
- break;
-
- case 0x9C: // pushfd
- case 0x9D: // popfd
- // a pushfd can never be an argument, so we model a pair of
- // these instruction as not changing the stack so that a call
- // that occurs between them does not consume the value of pushfd
- ip++;
- break;
-
- case 0x5D: // pop EBP
- case 0x5E: // pop ESI
- case 0x5F: // pop EDI
- case 0x5B: // pop EBX
- case 0x58: // pop EAX
- case 0x59: // pop ECX
- case 0x5A: // pop EDX
- if (pushes <= 0) {
- // We now have more pops than pushes. This is our indication
- // that we are in an EH_epilog function so we return true.
- // This is the only way to exit this method with a retval of true.
- return true;
- }
- --pushes;
- ip++;
- break;
-
- case 0xA1: // MOV EAX, [XXXX]
- ip += 5;
- break;
-
- case 0xC6: // MOV r/m8, imm8
- datasize = 1;
- goto decodeRM;
-
- case 0x89: // MOV r/m, reg
- if (ip[1] == 0xE5) // MOV EBP, ESP
- return false;
- if (ip[1] == 0xEC) // MOV ESP, EBP
- return false;
- goto move;
-
- case 0x8B: // MOV reg, r/m
- if (ip[1] == 0xE5) // MOV ESP, EBP
- return false;
- if (ip[1] == 0xEC) // MOV EBP, ESP
- return false;
- goto move;
-
- case 0x88: // MOV reg, r/m (BYTE)
- case 0x8A: // MOV r/m, reg (BYTE)
-
- case 0x31: // XOR
- case 0x32: // XOR
- case 0x33: // XOR
-
- move:
- datasize = 0;
-
- decodeRM:
- // Note that we don't want to read from ip[] after
- // we do ANY incrementing of ip
-
- mod = (ip[1] & 0xC0) >> 6;
- if (mod != 3) {
- rm = (ip[1] & 0x07);
- if (mod == 0) { // (mod == 0)
- if (rm == 5)
- ip += 4; // disp32
- else if (rm == 4)
- ip += 1; // [reg*K+reg]
- // otherwise [reg]
-
- }
- else if (mod == 1) { // (mod == 1)
- ip += 1; // for disp8
- if (rm == 4)
- ip += 1; // [reg*K+reg+disp8]
- // otherwise [reg+disp8]
- }
- else { // (mod == 2)
- ip += 4; // for disp32
- if (rm == 4)
- ip += 1; // [reg*K+reg+disp32]
- // otherwise [reg+disp32]
- }
- }
-
- ip += 2;
- ip += datasize;
- break;
-
- case 0x64: // FS: prefix
- ip++;
- break;
-
- case 0xEB: // jmp
- ip += (int8_t) ip[1] + 2;
- break;
-
- case 0xE9: // jmp
- ip += (int32_t)*PTR_DWORD(PTR_TO_TADDR(ip) + 1) + 5;
- break;
-
- case 0xF7: // test r/m32, imm32
- // Magellan code coverage build
- if ( (ip[1] & 0x38) == 0x00)
- {
- datasize = 4;
- goto decodeRM;
- }
- else
- {
- return false;
- }
- break;
-
- case 0x75: // jnz
- // Magellan code coverage build
- // We always follow forward jump to avoid possible looping.
- {
- PTR_BYTE tmpIp = ip + (TADDR)(int8_t) ip[1] + 2;
- if (tmpIp > ip) {
- ip = tmpIp; // follow forwards jump
- }
- else {
- return false; // backwards jump implies not EH_epilog function
- }
- }
- break;
-
- case 0xC2: // ret
- case 0xC3: // ret n
- default:
- return false;
- }
- }
-
- return false;
-}
-
-/***************************************************************/
-// A fundamental requirement of managed code is that we need to be able to enumerate all GC references on the
-// stack at GC time. To do this we need to be able to 'crawl' the stack. We know how to do this in JIT
-// compiled code (it generates additional information like the frame size etc), but we don't know how to do
-// this for unmanaged code. For PINVOKE calls, we leave a pointer to the transition boundary between managed
-// and unmanaged code and we simply ignore the lower part of the stack. However setting up this transition is
-// a bit expensive (1-2 dozen instructions), and while that is acceptable for PINVOKE, it is not acceptable
-// for high volume calls, like NEW, CAST, WriterBarrier, Stack field fetch and others.
-//
-// To get around this, for transitions into the runtime (which we call FCALLS), we DEFER setting up the
-// boundary variables (what we call the transition frame), until we actually need it (we will do an operation
-// that might cause a GC). This allow us to handle the common case (where we might find the thing in a cache,
-// or be service the 'new' from a allocation quantum), and only pay the cost of setting up the transition
-// frame when it will actually be used.
-//
-// The problem is that in order to set up a transition frame we need to be able to find ALL REGISTERS AT THE
-// TIME THE TRANSITION TO UNMANAGED CODE WAS MADE (because we might need to update them if they have GC
-// references). Because we have executed ordinary C++ code (which might spill the registers to the stack at
-// any time), we have a problem. LazyMachState is our 'solution' to this problem. We take advantage of the
-// fact that the C++ code MUST RESTORE the register before returning. Thus we simulate the execution from the
-// current location to the return and 'watch' where the registers got restored from. This is what
-// unwindLazyState does (determine what the registers would be IF you had never executed and unmanaged C++
-// code).
-//
-// By design, this code does not handle all X86 instructions, but only those instructions needed in an
-// epilog. If you get a failure because of a missing instruction, it MAY simply be because the compiler
-// changed and now emits a new instruction in the epilog, but it MAY also be because the unwinder is
-// 'confused' and is trying to follow a code path that is NOT AN EPILOG, and in this case adding
-// instructions to 'fix' it is inappropriate.
-//
-void LazyMachState::unwindLazyState(LazyMachState* baseState,
- MachState* lazyState,
- DWORD threadId,
- int funCallDepth /* = 1 */)
-{
- CONTRACTL {
- NOTHROW;
- GC_NOTRIGGER;
- SUPPORTS_DAC;
- } CONTRACTL_END;
-
- lazyState->_edi = baseState->_edi;
- lazyState->_esi = baseState->_esi;
- lazyState->_ebx = baseState->_ebx;
- lazyState->_ebp = baseState->captureEbp;
-#ifndef DACCESS_COMPILE
- lazyState->_pEdi = &baseState->_edi;
- lazyState->_pEsi = &baseState->_esi;
- lazyState->_pEbx = &baseState->_ebx;
- lazyState->_pEbp = &baseState->_ebp;
-#endif
-
- // We have captured the state of the registers as they exist in 'captureState'
- // we need to simulate execution from the return address captured in 'captureState
- // until we return from the caller of captureState.
-
- PTR_BYTE ip = PTR_BYTE(baseState->captureEip);
- PTR_TADDR ESP = PTR_TADDR(baseState->captureEsp);
- ESP++; // pop captureState's return address
-
-
- // VC now has small helper calls that it uses in epilogs. We need to walk into these
- // helpers if we are to decode the stack properly. After we walk the helper we need
- // to return and continue walking the epiliog. This variable remembers were to return to
- PTR_BYTE epilogCallRet = PTR_BYTE((TADDR)0);
-
- // The very first conditional jump that we are going to encounter is
- // the one testing for the return value of LazyMachStateCaptureState.
- // The non-zero path is the one directly leading to a return statement.
- // This variable keeps track of whether we are still looking for that
- // first conditional jump.
- BOOL bFirstCondJmp = TRUE;
-
- // The general strategy is that we always try to plough forward:
- // we follow a conditional jump if and only if it is a forward jump.
- // However, in fcall functions that set up a HELPER_METHOD_FRAME in
- // more than one place, gcc will have both of them share the same
- // epilog - and the second one may actually be a backward jump.
- // This can lead us to loop in a destructor code loop. To protect
- // against this, we remember the ip of the last conditional jump
- // we followed, and if we encounter it again, we take the other branch.
- PTR_BYTE lastCondJmpIp = PTR_BYTE((TADDR)0);
-
- int datasize; // helper variable for decoding of address modes
- int mod; // helper variable for decoding of mod r/m
- int rm; // helper variable for decoding of mod r/m
-
-#ifdef _DEBUG
- int count = 0;
- const DWORD cInstructions = 1000;
- PTR_BYTE *instructionBytes = (PTR_BYTE*)alloca(cInstructions * sizeof(PTR_BYTE));
- memset(instructionBytes, 0, cInstructions * sizeof(PTR_BYTE));
-#endif
- bool bset16bit=false;
- bool b16bit=false;
- for(;;)
- {
- _ASSERTE(count++ < 1000); // we should never walk more than 1000 instructions!
- b16bit=bset16bit;
- bset16bit=false;
-
-#ifndef DACCESS_COMPILE
- again:
-#endif
-#ifdef _DEBUG
- instructionBytes[count-1] = ip;
-#endif
- switch(*ip)
- {
-
- case 0x64: // FS: prefix
- bset16bit=b16bit; // In case we have just seen a 0x66 prefix
- goto incIp1;
-
- case 0x66:
- bset16bit=true; // Remember that we saw the 0x66 prefix [16-bit datasize override]
- goto incIp1;
-
- case 0x50: // push EAX
- case 0x51: // push ECX
- case 0x52: // push EDX
- case 0x53: // push EBX
- case 0x55: // push EBP
- case 0x56: // push ESI
- case 0x57: // push EDI
- case 0x9C: // pushfd
- --ESP;
- case 0x40: // inc EAX
- case 0x41: // inc ECX
- case 0x42: // inc EDX
- case 0x43: // inc EBX
- case 0x46: // inc ESI
- case 0x47: // inc EDI
- goto incIp1;
-
- case 0x58: // pop EAX
- case 0x59: // pop ECX
- case 0x5A: // pop EDX
- case 0x9D: // popfd
- ESP++;
- // FALL THROUGH
-
- case 0x90: // nop
- incIp1:
- ip++;
- break;
-
- case 0x5B: // pop EBX
- lazyState->_pEbx = ESP;
- lazyState->_ebx = *ESP++;
- goto incIp1;
- case 0x5D: // pop EBP
- lazyState->_pEbp = ESP;
- lazyState->_ebp = *ESP++;
- goto incIp1;
- case 0x5E: // pop ESI
- lazyState->_pEsi = ESP;
- lazyState->_esi = *ESP++;
- goto incIp1;
- case 0x5F: // pop EDI
- lazyState->_pEdi = ESP;
- lazyState->_edi = *ESP++;
- goto incIp1;
-
- case 0xEB: // jmp
- ip += (int8_t) ip[1] + 2;
- break;
-
- case 0x72: // jb for gcc.
- {
- PTR_BYTE tmpIp = ip + (int)(int8_t)ip[1] + 2;
- if (tmpIp > ip)
- ip = tmpIp;
- else
- ip += 2;
- }
- break;
-
- case 0xE8: // call
- ip += 5;
- if (epilogCallRet == 0)
- {
- PTR_BYTE target = ip + (int32_t)*PTR_DWORD(PTR_TO_TADDR(ip) - 4); // calculate target
-
- if (shouldEnterCall(target))
- {
- epilogCallRet = ip; // remember our return address
- --ESP; // simulate pushing the return address
- ip = target;
- }
- }
- break;
-
- case 0xE9: // jmp
- {
- PTR_BYTE tmpIp = ip
- + ((int32_t)*dac_cast(ip + 1) + 5);
- ip = tmpIp;
- }
- break;
-
- case 0x0f: // follow non-zero jumps:
- if (ip[1] >= 0x90 && ip[1] <= 0x9f) {
- if ((ip[2] & 0xC0) != 0xC0) // set reg
- goto badOpcode;
- ip += 3;
- break;
- }
- else if ((ip[1] & 0xf0) == 0x40) { //cmov mod/rm
- ++ip;
- datasize = 0;
- goto decodeRM;
- }
- else if (ip[1] >= 0x10 && ip[1] <= 0x17) { // movups, movlps, movhps, unpcklpd, unpckhpd
- ++ip;
- datasize = 0;
- goto decodeRM;
- }
- else if (ip[1] == 0x1f) { // nop (multi-byte)
- ++ip;
- datasize = 0;
- goto decodeRM;
- }
- else if (ip[1] == 0x57) { // xorps
- ++ip;
- datasize = 0;
- goto decodeRM;
- }
- else if (ip[1] == 0xb6 || ip[1] == 0xb7) { //movzx reg, r/m8
- ++ip;
- datasize = 0;
- goto decodeRM;
- }
- else if (ip[1] == 0xbf) { //movsx reg, r/m16
- ++ip;
- datasize = 0;
- goto decodeRM;
- }
- else if (ip[1] == 0xd6 || ip[1] == 0x7e) { // movq
- ++ip;
- datasize = 0;
- goto decodeRM;
- }
- else if (bFirstCondJmp) {
- bFirstCondJmp = FALSE;
- if (ip[1] == 0x85) // jne
- ip += (int32_t)*dac_cast(ip + 2) + 6;
- else if (ip[1] >= 0x80 && ip[1] <= 0x8F) // jcc
- ip += 6;
- else
- goto badOpcode;
- }
- else {
- if ((ip[1] >= 0x80) && (ip[1] <= 0x8F)) {
- PTR_BYTE tmpIp = ip + (int32_t)*dac_cast(ip + 2) + 6;
-
- if ((tmpIp > ip) == (lastCondJmpIp != ip)) {
- lastCondJmpIp = ip;
- ip = tmpIp;
- }
- else {
- lastCondJmpIp = ip;
- ip += 6;
- }
- }
- else
- goto badOpcode;
- }
- break;
-
- // This is here because VC seems to not always optimize
- // away a test for a literal constant
- case 0x6A: // push 0xXX
- ip += 2;
- --ESP;
- break;
-
- case 0x68: // push 0xXXXXXXXX
- if ((ip[5] == 0xFF) && (ip[6] == 0x15)) {
- ip += 11; //
- }
- else {
- ip += 5;
-
- // For office profiler. They morph calls into push TARGET; call helper
- // so if you see
- //
- // push XXXX
- // call xxxx
- //
- // and we notice that mscorwks has been instrumented and
- // xxxx starts with a JMP [] then do what you would do for call XXXX
- if ((*ip & 0xFE) == 0xE8 && callsInstrumented()) { // It is a call or a jump (E8 or E9)
- PTR_BYTE tmpIp = ip + 5;
- PTR_BYTE target = tmpIp + (int32_t)*PTR_DWORD(PTR_TO_TADDR(tmpIp) - 4);
- if (target[0] == 0xFF && target[1] == 0x25) { // jmp [xxxx] (to external dll)
- target = PTR_BYTE(*PTR_TADDR(PTR_TO_TADDR(ip) - 4));
- if (*ip == 0xE9) { // Do logic for jmp
- ip = target;
- }
- else if (shouldEnterCall(target)) { // Do logic for calls
- epilogCallRet = ip; // remember our return address
- --ESP; // simulate pushing the return address
- ip = target;
- }
- }
- }
- }
- break;
-
- case 0x74: // jz
- if (bFirstCondJmp) {
- bFirstCondJmp = FALSE;
- ip += 2; // follow the non-zero path
- break;
- }
- goto condJumpDisp8;
-
- case 0x75: // jnz
- // Except the first jump, we always follow forward jump to avoid possible looping.
- //
- if (bFirstCondJmp) {
- bFirstCondJmp = FALSE;
- ip += (int8_t) ip[1] + 2; // follow the non-zero path
- break;
- }
- goto condJumpDisp8;
-
- case 0x77: // ja
- case 0x78: // js
- case 0x79: // jns
- case 0x7d: // jge
- case 0x7c: // jl
- goto condJumpDisp8;
-
- condJumpDisp8:
- {
- PTR_BYTE tmpIp = ip + (TADDR)(int8_t) ip[1] + 2;
- if ((tmpIp > ip) == (lastCondJmpIp != ip)) {
- lastCondJmpIp = ip;
- ip = tmpIp;
- }
- else {
- lastCondJmpIp = ip;
- ip += 2;
- }
- }
- break;
-
- case 0x84:
- case 0x85:
- mod = (ip[1] & 0xC0) >> 6;
- if (mod != 3) // test reg1, reg2
- goto badOpcode;
- ip += 2;
- break;
-
- case 0x34: // XOR AL, imm8
- ip += 2;
- break;
-
- case 0x31:
- case 0x32:
- case 0x33:
-#ifdef __GNUC__
- //there are lots of special workarounds for XOR for msvc. For GnuC
- //just do the normal Mod/rm stuff.
- datasize = 0;
- goto decodeRM;
-#else
- mod = (ip[1] & 0xC0) >> 6;
- if (mod == 3)
- {
- // XOR reg1, reg2
-
- // VC generates this sequence in some code:
- // xor reg, reg
- // test reg reg
- // je
- // This is just an unconditional branch, so jump to it
- if ((ip[1] & 7) == ((ip[1] >> 3) & 7)) { // reg1 == reg2?
- if (ip[2] == 0x85 && ip[3] == ip[1]) { // TEST reg, reg
- if (ip[4] == 0x74) {
- ip += (int8_t) ip[5] + 6; // follow the non-zero path
- break;
- }
- _ASSERTE(ip[4] != 0x0f || ((ip[5] & 0xF0)!=0x80)); // If this goes off, we need the big jumps
- }
- else
- {
- if (ip[2]==0x74)
- {
- ip += (int8_t) ip[3] + 4;
- break;
- }
- _ASSERTE(ip[2] != 0x0f || ((ip[3] & 0xF0)!=0x80)); // If this goes off, we need the big jumps
- }
- }
- ip += 2;
- }
- else if (mod == 1)
- {
- // XOR reg1, [reg+offs8]
- // Used by the /GS flag for call to __security_check_cookie()
- // Should only be XOR ECX,[EBP+4]
- _ASSERTE((((ip[1] >> 3) & 0x7) == 0x1) && ((ip[1] & 0x7) == 0x5) && (ip[2] == 4));
- ip += 3;
- }
- else if (mod == 2)
- {
- // XOR reg1, [reg+offs32]
- // Should not happen but may occur with __security_check_cookie()
- _ASSERTE(!"Unexpected XOR reg1, [reg+offs32]");
- ip += 6;
- }
- else // (mod == 0)
- {
- // XOR reg1, [reg]
- goto badOpcode;
- }
- break;
-#endif
-
- case 0x05:
- // added to handle gcc 3.3 generated code
- // add %reg, constant
- ip += 5;
- break;
-
- case 0xFF:
- if ( (ip[1] & 0x38) == 0x30)
- {
- // opcode generated by Vulcan/BBT instrumentation
- // search for push dword ptr[esp]; push imm32; call disp32 and if found ignore it
- if ((ip[1] == 0x34) && (ip[2] == 0x24) && // push dword ptr[esp] (length 3 bytes)
- (ip[3] == 0x68) && // push imm32 (length 5 bytes)
- (ip[8] == 0xe8)) // call disp32 (length 5 bytes)
- {
- // found the magic seq emitted by Vulcan instrumentation
- ip += 13; // (3+5+5)
- break;
- }
-
- --ESP; // push r/m
- datasize = 0;
- goto decodeRM;
- }
- else if ( (ip[1] & 0x38) == 0x10)
- {
- // added to handle gcc 3.3 generated code
- // This is a call *(%eax) generated by gcc for destructor calls.
- // We can safely skip over the call
- datasize = 0;
- goto decodeRM;
- }
- else if (ip[1] == 0xe0)
- {
- goto badOpcode;
-#if 0
- // Handles jmp *%eax from gcc
- datasize = 0;
- goto decodeRM;
-#endif
- }
- else if (ip[1] == 0x25 && epilogInstrumented()) // is it jmp [XXXX]
- {
- // this is a office profiler epilog (this jmp is acting as a return instruction)
- PTR_BYTE epilogHelper = PTR_BYTE(*PTR_TADDR(*PTR_TADDR(PTR_TO_TADDR(ip) + 2)));
-
- ip = PTR_BYTE(*ESP);
- lazyState->_pRetAddr = ESP++;
-
- if (epilogHelper[0] != 0x6A) // push
- goto badOpcode;
- unsigned disp = *PTR_BYTE(PTR_TO_TADDR(epilogHelper) + 1) * 4;
- ESP = PTR_TADDR(PTR_TO_TADDR(ESP) + disp); // pop args
- goto ret_with_epilogHelperCheck;
-
- }
- else
- {
- goto badOpcode;
- }
- break;
-
- case 0x39: // comp r/m, reg
- case 0x3B: // comp reg, r/m
- datasize = 0;
- goto decodeRM;
-
- case 0xA1: // MOV EAX, [XXXX]
- ip += 5;
- break;
-
- case 0x89: // MOV r/m, reg
- if (ip[1] == 0xEC) // MOV ESP, EBP
- goto mov_esp_ebp;
- if (ip[1] == 0xDC) // MOV ESP, EBX
- goto mov_esp_ebx;
- // FALL THROUGH
-
- case 0x18: // SBB r/m8, r8
- case 0x19: // SBB r/m[16|32], r[16|32]
- case 0x1A: // SBB r8, r/m8
- case 0x1B: // SBB r[16|32], r/m[16|32]
-
- case 0x88: // MOV reg, r/m (BYTE)
- case 0x8A: // MOV r/m, reg (BYTE)
-
- move:
- datasize = 0;
-
- decodeRM:
- // Note that we don't want to read from ip[]
- // after we do ANY incrementing of ip
-
- mod = (ip[1] & 0xC0) >> 6;
- if (mod != 3) {
- rm = (ip[1] & 0x07);
- if (mod == 0) { // (mod == 0)
- if (rm == 5) // has disp32?
- ip += 4; // [disp32]
- else if (rm == 4) // has SIB byte?
- ip += 1; // [reg*K+reg]
- }
- else if (mod == 1) { // (mod == 1)
- if (rm == 4) // has SIB byte?
- ip += 1; // [reg*K+reg+disp8]
- ip += 1; // for disp8
- }
- else { // (mod == 2)
- if (rm == 4) // has SIB byte?
- ip += 1; // [reg*K+reg+disp32]
- ip += 4; // for disp32
- }
- }
- ip += 2; // opcode and Mod R/M byte
- ip += datasize;
- break;
-
- case 0x80: // OP r/m8,
- datasize = 1;
- goto decodeRM;
-
- case 0x81: // OP r/m32,
- if (!b16bit && ip[1] == 0xC4) { // ADD ESP,
- ESP = dac_cast(dac_cast(ESP) +
- (int32_t)*dac_cast(ip + 2));
- ip += 6;
- break;
- } else if (!b16bit && ip[1] == 0xC5) { // ADD EBP,
- lazyState->_ebp += (int32_t)*dac_cast(ip + 2);
- ip += 6;
- break;
- }
-
- datasize = b16bit?2:4;
- goto decodeRM;
-
- case 0x24: // AND AL, imm8
- ip += 2;
- break;
-
- case 0x01: // ADD mod/rm
- case 0x03:
- case 0x11: // ADC mod/rm
- case 0x13:
- case 0x21: // AND mod/rm
- case 0x29: // SUB mod/rm
- case 0x2B:
- datasize = 0;
- goto decodeRM;
- case 0x83: // OP r/m32,
- if (ip[1] == 0xC4) { // ADD ESP,
- ESP = dac_cast(dac_cast(ESP) + (int8_t)ip[2]);
- ip += 3;
- break;
- }
- if (ip[1] == 0xec) { // SUB ESP,
- ESP = PTR_TADDR(PTR_TO_TADDR(ESP) - (int8_t)ip[2]);
- ip += 3;
- break;
- }
- if (ip[1] == 0xe4) { // AND ESP,
- ESP = PTR_TADDR(PTR_TO_TADDR(ESP) & (int8_t)ip[2]);
- ip += 3;
- break;
- }
- if (ip[1] == 0xc5) { // ADD EBP,
- lazyState->_ebp += (int8_t)ip[2];
- ip += 3;
- break;
- }
-
- datasize = 1;
- goto decodeRM;
-
- case 0x8B: // MOV reg, r/m
- if (ip[1] == 0xE5) { // MOV ESP, EBP
- mov_esp_ebp:
- ESP = PTR_TADDR(lazyState->_ebp);
- ip += 2;
- break;
- }
-
- if (ip[1] == 0xE3) { // MOV ESP, EBX
- mov_esp_ebx:
- ESP = PTR_TADDR(lazyState->_ebx);
- ip += 2;
- break;
- }
-
- if ((ip[1] & 0xc7) == 0x4 && ip[2] == 0x24) // move reg, [esp]
- {
- if ( ip[1] == 0x1C ) { // MOV EBX, [ESP]
- lazyState->_pEbx = ESP;
- lazyState->_ebx = *lazyState->_pEbx;
- }
- else if ( ip[1] == 0x34 ) { // MOV ESI, [ESP]
- lazyState->_pEsi = ESP;
- lazyState->_esi = *lazyState->_pEsi;
- }
- else if ( ip[1] == 0x3C ) { // MOV EDI, [ESP]
- lazyState->_pEdi = ESP;
- lazyState->_edi = *lazyState->_pEdi;
- }
- else if ( ip[1] == 0x24 /*ESP*/ || ip[1] == 0x2C /*EBP*/)
- goto badOpcode;
-
- ip += 3;
- break;
- }
-
- if ((ip[1] & 0xc7) == 0x44 && ip[2] == 0x24) // move reg, [esp+imm8]
- {
- if ( ip[1] == 0x5C ) { // MOV EBX, [ESP+XX]
- lazyState->_pEbx = PTR_TADDR(PTR_TO_TADDR(ESP) + (int8_t)ip[3]);
- lazyState->_ebx = *lazyState->_pEbx ;
- }
- else if ( ip[1] == 0x74 ) { // MOV ESI, [ESP+XX]
- lazyState->_pEsi = PTR_TADDR(PTR_TO_TADDR(ESP) + (int8_t)ip[3]);
- lazyState->_esi = *lazyState->_pEsi;
- }
- else if ( ip[1] == 0x7C ) { // MOV EDI, [ESP+XX]
- lazyState->_pEdi = PTR_TADDR(PTR_TO_TADDR(ESP) + (int8_t)ip[3]);
- lazyState->_edi = *lazyState->_pEdi;
- }
- else if ( ip[1] == 0x64 /*ESP*/ || ip[1] == 0x6C /*EBP*/)
- goto badOpcode;
-
- ip += 4;
- break;
- }
-
- if ((ip[1] & 0xC7) == 0x45) { // MOV reg, [EBP + imm8]
- // gcc sometimes restores callee-preserved registers
- // via 'mov reg, [ebp-xx]' instead of 'pop reg'
- if ( ip[1] == 0x5D ) { // MOV EBX, [EBP+XX]
- lazyState->_pEbx = PTR_TADDR(lazyState->_ebp + (int8_t)ip[2]);
- lazyState->_ebx = *lazyState->_pEbx ;
- }
- else if ( ip[1] == 0x75 ) { // MOV ESI, [EBP+XX]
- lazyState->_pEsi = PTR_TADDR(lazyState->_ebp + (int8_t)ip[2]);
- lazyState->_esi = *lazyState->_pEsi;
- }
- else if ( ip[1] == 0x7D ) { // MOV EDI, [EBP+XX]
- lazyState->_pEdi = PTR_TADDR(lazyState->_ebp + (int8_t)ip[2]);
- lazyState->_edi = *lazyState->_pEdi;
- }
- else if ( ip[1] == 0x65 /*ESP*/ || ip[1] == 0x6D /*EBP*/)
- goto badOpcode;
-
- // We don't track the values of EAX,ECX,EDX
-
- ip += 3; // MOV reg, [reg + imm8]
- break;
- }
-
- if ((ip[1] & 0xC7) == 0x85) { // MOV reg, [EBP+imm32]
- // gcc sometimes restores callee-preserved registers
- // via 'mov reg, [ebp-xx]' instead of 'pop reg'
- if ( ip[1] == 0xDD ) { // MOV EBX, [EBP+XXXXXXXX]
- lazyState->_pEbx = PTR_TADDR(lazyState->_ebp + (int32_t)*dac_cast(ip + 2));
- lazyState->_ebx = *lazyState->_pEbx ;
- }
- else if ( ip[1] == 0xF5 ) { // MOV ESI, [EBP+XXXXXXXX]
- lazyState->_pEsi = PTR_TADDR(lazyState->_ebp + (int32_t)*dac_cast(ip + 2));
- lazyState->_esi = *lazyState->_pEsi;
- }
- else if ( ip[1] == 0xFD ) { // MOV EDI, [EBP+XXXXXXXX]
- lazyState->_pEdi = PTR_TADDR(lazyState->_ebp + (int32_t)*dac_cast(ip + 2));
- lazyState->_edi = *lazyState->_pEdi;
- }
- else if ( ip[1] == 0xE5 /*ESP*/ || ip[1] == 0xED /*EBP*/)
- goto badOpcode; // Add more registers
-
- // We don't track the values of EAX,ECX,EDX
-
- ip += 6; // MOV reg, [reg + imm32]
- break;
- }
- goto move;
-
- case 0x8D: // LEA
- if ((ip[1] & 0x38) == 0x20) { // Don't allow ESP to be updated
- if (ip[1] == 0xA5) // LEA ESP, [EBP+XXXX]
- ESP = PTR_TADDR(lazyState->_ebp + (int32_t)*dac_cast(ip + 2));
- else if (ip[1] == 0x65) // LEA ESP, [EBP+XX]
- ESP = PTR_TADDR(lazyState->_ebp + (int8_t) ip[2]);
- else if (ip[1] == 0x24 && ip[2] == 0x24) // LEA ESP, [ESP]
- ;
- else if (ip[1] == 0xa4 && ip[2] == 0x24 && *((DWORD *)(&ip[3])) == 0) // Another form of: LEA ESP, [ESP]
- ;
- else if (ip[1] == 0x64 && ip[2] == 0x24 && ip[3] == 0) // Yet another form of: LEA ESP, [ESP] (8 bit offset)
- ;
- else
- {
- goto badOpcode;
- }
- }
-
- datasize = 0;
- goto decodeRM;
-
- case 0xB0: // MOV AL, imm8
- ip += 2;
- break;
- case 0xB8: // MOV EAX, imm32
- case 0xB9: // MOV ECX, imm32
- case 0xBA: // MOV EDX, imm32
- case 0xBB: // MOV EBX, imm32
- case 0xBE: // MOV ESI, imm32
- case 0xBF: // MOV EDI, imm32
- if(b16bit)
- ip += 3;
- else
- ip += 5;
- break;
-
- case 0xC2: // ret N
- {
- uint16_t disp = *dac_cast(ip + 1);
- ip = PTR_BYTE(*ESP);
- lazyState->_pRetAddr = ESP++;
- _ASSERTE(disp < 64); // sanity check (although strictly speaking not impossible)
- ESP = dac_cast(dac_cast(ESP) + disp); // pop args
- goto ret;
- }
- case 0xC3: // ret
- ip = PTR_BYTE(*ESP);
- lazyState->_pRetAddr = ESP++;
-
- ret_with_epilogHelperCheck:
- if (epilogCallRet != 0) { // we are returning from a special epilog helper
- ip = epilogCallRet;
- epilogCallRet = 0;
- break; // this does not count toward funCallDepth
- }
- ret:
- if (funCallDepth > 0)
- {
- --funCallDepth;
- if (funCallDepth == 0)
- goto done;
- }
- else
- {
- // Determine whether given IP resides in JITted code. (It returns nonzero in that case.)
- // Use it now to see if we've unwound to managed code yet.
- BOOL fIsManagedCode = ExecutionManager::IsManagedCode(*lazyState->pRetAddr());
-
- if (fIsManagedCode)
- goto done;
- }
-
- bFirstCondJmp = TRUE;
- break;
-
- case 0xC6: // MOV r/m8, imm8
- datasize = 1;
- goto decodeRM;
-
- case 0xC7: // MOV r/m32, imm32
- datasize = b16bit?2:4;
- goto decodeRM;
-
- case 0xC9: // leave
- ESP = PTR_TADDR(lazyState->_ebp);
- lazyState->_pEbp = ESP;
- lazyState->_ebp = *ESP++;
- ip++;
- break;
-
-#ifndef DACCESS_COMPILE
- case 0xCC:
- if (minipal_is_native_debugger_present())
- {
- OutputDebugStringA("CLR: Invalid breakpoint in a helpermethod frame epilog\n");
- DebugBreak();
- goto again;
- }
-
- *((volatile int*) 0) = 1; // If you get at this error, it is because yout
- // set a breakpoint in a helpermethod frame epilog
- // you can't do that unfortunately. Just move it
- // into the interior of the method to fix it
- goto done;
-#endif //!DACCESS_COMPILE
-
- case 0xD0: // shl REG16, 1
- case 0xD1: // shl REG32, 1
- if (0xE4 == ip[1] || 0xE5 == ip[1]) // shl, ESP, 1 or shl EBP, 1
- goto badOpcode; // Doesn't look like valid code
- ip += 2;
- break;
-
- case 0xC1: // shl REG32, imm8
- if (0xE4 == ip[1] || 0xE5 == ip[1]) // shl, ESP, imm8 or shl EBP, imm8
- goto badOpcode; // Doesn't look like valid code
- ip += 3;
- break;
-
- case 0xD9: // single prefix
- if (0xEE == ip[1])
- {
- ip += 2; // FLDZ
- break;
- }
- //
- // INTENTIONAL FALL THRU
- //
- case 0xDD: // double prefix
- if ((ip[1] & 0xC0) != 0xC0)
- {
- datasize = 0; // floatop r/m
- goto decodeRM;
- }
- else
- {
- goto badOpcode;
- }
- break;
-
- case 0xf2: // repne prefix
- case 0xF3: // rep prefix
- ip += 1;
- break;
-
- case 0xA4: // MOVS byte
- case 0xA5: // MOVS word/dword
- ip += 1;
- break;
-
- case 0xA8: //test AL, imm8
- ip += 2;
- break;
- case 0xA9: //test EAX, imm32
- ip += 5;
- break;
- case 0xF6:
- if ( (ip[1] & 0x38) == 0x00) // TEST r/m8, imm8
- {
- datasize = 1;
- goto decodeRM;
- }
- else
- {
- goto badOpcode;
- }
- break;
-
- case 0xF7:
- if ( (ip[1] & 0x38) == 0x00) // TEST r/m32, imm32
- {
- datasize = b16bit?2:4;
- goto decodeRM;
- }
- else if ((ip[1] & 0xC8) == 0xC8) //neg reg
- {
- ip += 2;
- break;
- }
- else if ((ip[1] & 0x30) == 0x30) //div eax by mod/rm
- {
- datasize = 0;
- goto decodeRM;
- }
- else
- {
- goto badOpcode;
- }
- break;
-
-#ifdef __GNUC__
- case 0x2e:
- // Group 2 instruction prefix.
- if (ip[1] == 0x0f && ip[2] == 0x1f)
- {
- // Although not the recommended multi-byte sequence for 9-byte
- // nops (the suggestion is to use 0x66 as the prefix), this shows
- // up in GCC-optimized code.
- ip += 2;
- datasize = 0;
- goto decodeRM;
- }
- else
- {
- goto badOpcode;
- }
- break;
-#endif // __GNUC__
-
- default:
- badOpcode:
- _ASSERTE(!"Bad opcode");
- // FIX what to do here?
-#ifndef DACCESS_COMPILE
- *((volatile PTR_BYTE*) 0) = ip; // cause an access violation (Free Build assert)
-#else
- DacNotImpl();
-#endif
- goto done;
- }
- }
-done:
- _ASSERTE(epilogCallRet == 0);
-
- // At this point the fields in 'frame' coorespond exactly to the register
- // state when the helper returns to its caller.
- lazyState->_esp = dac_cast(ESP);
-}
-
-#else // !USE_EXTERNAL_UNWINDER
-
-void LazyMachState::unwindLazyState(LazyMachState* baseState,
- MachState* lazyState,
- DWORD threadId,
- int funCallDepth /* = 1 */)
-{
- CONTRACTL {
- NOTHROW;
- GC_NOTRIGGER;
- SUPPORTS_DAC;
- } CONTRACTL_END;
-
- CONTEXT ctx;
- KNONVOLATILE_CONTEXT_POINTERS nonVolRegPtrs;
-
- ctx.ContextFlags = 0; // Read by PAL_VirtualUnwind.
-
- ctx.Eip = baseState->captureEip;
- ctx.Esp = baseState->captureEsp;
- ctx.Ebp = baseState->captureEbp;
-
- ctx.Edi = lazyState->_edi = baseState->_edi;
- ctx.Esi = lazyState->_esi = baseState->_esi;
- ctx.Ebx = lazyState->_ebx = baseState->_ebx;
-
- nonVolRegPtrs.Edi = &(baseState->_edi);
- nonVolRegPtrs.Esi = &(baseState->_esi);
- nonVolRegPtrs.Ebx = &(baseState->_ebx);
- nonVolRegPtrs.Ebp = &(baseState->_ebp);
-
- PCODE pvControlPc;
-
- LOG((LF_GCROOTS, LL_INFO100000, "STACKWALK LazyMachState::unwindLazyState(ip:%p,bp:%p,sp:%p)\n", baseState->captureEip, baseState->captureEbp, baseState->captureEsp));
-
- do
- {
-#ifdef DACCESS_COMPILE
- HRESULT hr = DacVirtualUnwind(threadId, &ctx, &nonVolRegPtrs);
- if (FAILED(hr))
- {
- DacError(hr);
- }
-#else
- BOOL success = PAL_VirtualUnwind(&ctx, &nonVolRegPtrs);
- if (!success)
- {
- _ASSERTE(!"unwindLazyState: Unwinding failed");
- EEPOLICY_HANDLE_FATAL_ERROR(COR_E_EXECUTIONENGINE);
- }
-#endif // DACCESS_COMPILE
-
- pvControlPc = GetIP(&ctx);
-
- _ASSERTE(pvControlPc != 0);
-
- if (funCallDepth > 0)
- {
- --funCallDepth;
- if (funCallDepth == 0)
- break;
- }
- else
- {
- // Determine whether given IP resides in JITted code. (It returns nonzero in that case.)
- // Use it now to see if we've unwound to managed code yet.
- BOOL fIsManagedCode = ExecutionManager::IsManagedCode(pvControlPc);
-
- if (fIsManagedCode)
- break;
- }
- }
- while(TRUE);
-
- lazyState->_esp = ctx.Esp;
- lazyState->_pRetAddr = PTR_TADDR(lazyState->_esp - 4);
-
- lazyState->_edi = ctx.Edi;
- lazyState->_esi = ctx.Esi;
- lazyState->_ebx = ctx.Ebx;
- lazyState->_ebp = ctx.Ebp;
-
-#ifdef DACCESS_COMPILE
- lazyState->_pEdi = NULL;
- lazyState->_pEsi = NULL;
- lazyState->_pEbx = NULL;
- lazyState->_pEbp = NULL;
-#else // DACCESS_COMPILE
- lazyState->_pEdi = nonVolRegPtrs.Edi;
- lazyState->_pEsi = nonVolRegPtrs.Esi;
- lazyState->_pEbx = nonVolRegPtrs.Ebx;
- lazyState->_pEbp = nonVolRegPtrs.Ebp;
-#endif // DACCESS_COMPILE
-}
-#endif // !USE_EXTERNAL_UNWINDER
diff --git a/src/coreclr/vm/jithelpers.cpp b/src/coreclr/vm/jithelpers.cpp
index 7f3360bdc31e68..33faa25c094869 100644
--- a/src/coreclr/vm/jithelpers.cpp
+++ b/src/coreclr/vm/jithelpers.cpp
@@ -858,8 +858,6 @@ HCIMPL1(void, IL_Throw, Object* obj)
/* Make no assumptions about the current machine state */
ResetCurrentContext();
- FC_GC_POLL_NOT_NEEDED(); // throws always open up for GC
-
OBJECTREF oref = ObjectToOBJECTREF(obj);
Thread *pThread = GetThread();
@@ -960,8 +958,6 @@ HCIMPL0(void, IL_Rethrow)
{
FCALL_CONTRACT;
- FC_GC_POLL_NOT_NEEDED(); // throws always open up for GC
-
Thread *pThread = GetThread();
SoftwareExceptionFrame exceptionFrame;
@@ -1015,13 +1011,11 @@ HCIMPL1(void, IL_ThrowExact, Object* obj)
/* Make no assumptions about the current machine state */
ResetCurrentContext();
- FC_GC_POLL_NOT_NEEDED(); // throws always open up for GC
-
OBJECTREF oref = ObjectToOBJECTREF(obj);
GetThread()->GetExceptionState()->SetRaisingForeignException();
Thread *pThread = GetThread();
-
+
SoftwareExceptionFrame exceptionFrame;
#ifdef TARGET_X86
exceptionFrame.UpdateContextFromTransitionBlock(transitionBlock);
@@ -1322,8 +1316,6 @@ FCIMPL0(INT32, JIT_GetCurrentManagedThreadId)
{
FCALL_CONTRACT;
- FC_GC_POLL_NOT_NEEDED();
-
Thread * pThread = GetThread();
return pThread->GetThreadId();
}
@@ -2005,7 +1997,6 @@ FORCEINLINE static bool CheckSample(T* pIndex, size_t* sampleIndex)
HCIMPL2(void, JIT_ValueProfile32, intptr_t val, ICorJitInfo::ValueHistogram32* valueProfile)
{
FCALL_CONTRACT;
- FC_GC_POLL_NOT_NEEDED();
size_t sampleIndex;
if (!CheckSample(&valueProfile->Count, &sampleIndex))
@@ -2025,7 +2016,6 @@ HCIMPLEND
HCIMPL2(void, JIT_ValueProfile64, intptr_t val, ICorJitInfo::ValueHistogram64* valueProfile)
{
FCALL_CONTRACT;
- FC_GC_POLL_NOT_NEEDED();
size_t sampleIndex;
if (!CheckSample(&valueProfile->Count, &sampleIndex))
@@ -2045,7 +2035,6 @@ HCIMPLEND
HCIMPL2(void, JIT_ClassProfile32, Object *obj, ICorJitInfo::HandleHistogram32* classProfile)
{
FCALL_CONTRACT;
- FC_GC_POLL_NOT_NEEDED();
OBJECTREF objRef = ObjectToOBJECTREF(obj);
VALIDATEOBJECTREF(objRef);
@@ -2080,7 +2069,6 @@ HCIMPLEND
HCIMPL2(void, JIT_ClassProfile64, Object *obj, ICorJitInfo::HandleHistogram64* classProfile)
{
FCALL_CONTRACT;
- FC_GC_POLL_NOT_NEEDED();
OBJECTREF objRef = ObjectToOBJECTREF(obj);
VALIDATEOBJECTREF(objRef);
@@ -2110,7 +2098,6 @@ HCIMPLEND
HCIMPL2(void, JIT_DelegateProfile32, Object *obj, ICorJitInfo::HandleHistogram32* methodProfile)
{
FCALL_CONTRACT;
- FC_GC_POLL_NOT_NEEDED();
OBJECTREF objRef = ObjectToOBJECTREF(obj);
VALIDATEOBJECTREF(objRef);
@@ -2157,7 +2144,6 @@ HCIMPLEND
HCIMPL2(void, JIT_DelegateProfile64, Object *obj, ICorJitInfo::HandleHistogram64* methodProfile)
{
FCALL_CONTRACT;
- FC_GC_POLL_NOT_NEEDED();
OBJECTREF objRef = ObjectToOBJECTREF(obj);
VALIDATEOBJECTREF(objRef);
@@ -2203,7 +2189,6 @@ HCIMPLEND
HCIMPL3(void, JIT_VTableProfile32, Object* obj, CORINFO_METHOD_HANDLE baseMethod, ICorJitInfo::HandleHistogram32* methodProfile)
{
FCALL_CONTRACT;
- FC_GC_POLL_NOT_NEEDED();
OBJECTREF objRef = ObjectToOBJECTREF(obj);
VALIDATEOBJECTREF(objRef);
@@ -2252,7 +2237,6 @@ HCIMPLEND
HCIMPL3(void, JIT_VTableProfile64, Object* obj, CORINFO_METHOD_HANDLE baseMethod, ICorJitInfo::HandleHistogram64* methodProfile)
{
FCALL_CONTRACT;
- FC_GC_POLL_NOT_NEEDED();
OBJECTREF objRef = ObjectToOBJECTREF(obj);
VALIDATEOBJECTREF(objRef);
@@ -2308,7 +2292,6 @@ HCIMPLEND
HCIMPL1(void, JIT_CountProfile32, volatile LONG* pCounter)
{
FCALL_CONTRACT;
- FC_GC_POLL_NOT_NEEDED();
LONG count = *pCounter;
LONG delta = 1;
@@ -2335,7 +2318,6 @@ HCIMPLEND
HCIMPL1(void, JIT_CountProfile64, volatile LONG64* pCounter)
{
FCALL_CONTRACT;
- FC_GC_POLL_NOT_NEEDED();
LONG64 count = *pCounter;
LONG64 delta = 1;
@@ -2452,11 +2434,9 @@ NOINLINE static void JIT_ReversePInvokeEnterRare2(ReversePInvokeFrame* frame, vo
// The following JIT_ReversePInvoke helpers are special.
// They handle setting up Reverse P/Invoke calls and transitioning back to unmanaged code.
-// As a result, we may not have a thread in JIT_ReversePInvokeEnter and we will be in the wrong GC mode for the HCALL prolog.
-// Additionally, we set up and tear down SEH handlers when we're on x86, so we can't use dynamic contracts anyway.
-// As a result, we specially decorate this method to have the correct calling convention
-// and argument ordering for an HCALL, but we don't use the HCALL macros and contracts
-// since this method doesn't follow the contracts.
+// We may not have a managed thread set up in JIT_ReversePInvokeEnter, and the GC mode may be incorrect.
+// On x86, SEH handlers are set up and torn down explicitly, so we avoid using dynamic contracts.
+// This method uses the correct calling convention and argument layout manually, without relying on standard macros or contracts.
HCIMPL3_RAW(void, JIT_ReversePInvokeEnterTrackTransitions, ReversePInvokeFrame* frame, CORINFO_METHOD_HANDLE handle, void* secretArg)
{
_ASSERTE(frame != NULL && handle != NULL);
diff --git a/src/coreclr/vm/loongarch64/asmconstants.h b/src/coreclr/vm/loongarch64/asmconstants.h
index b4db363e9dc60c..bd030820c814c8 100644
--- a/src/coreclr/vm/loongarch64/asmconstants.h
+++ b/src/coreclr/vm/loongarch64/asmconstants.h
@@ -90,27 +90,6 @@ ASMCONSTANTS_C_ASSERT(CallDescrData__returnValue == offsetof(CallDescrD
#define FpStruct__BothFloat 0b10
ASMCONSTANTS_C_ASSERT(FpStruct__BothFloat == (int)FpStruct::BothFloat)
-
-// Offset of the array containing the address of captured registers in MachState
-#define MachState__captureCalleeSavedRegisters 0x0
-ASMCONSTANTS_C_ASSERT(MachState__captureCalleeSavedRegisters == offsetof(MachState, captureCalleeSavedRegisters))
-
-// Offset of the array containing the address of preserved registers in MachState
-#define MachState__ptrCalleeSavedRegisters 0x50
-ASMCONSTANTS_C_ASSERT(MachState__ptrCalleeSavedRegisters == offsetof(MachState, ptrCalleeSavedRegisters))
-
-#define MachState__isValid 0xb0
-ASMCONSTANTS_C_ASSERT(MachState__isValid == offsetof(MachState, _isValid))
-
-#define LazyMachState_captureCalleeSavedRegisters MachState__captureCalleeSavedRegisters
-ASMCONSTANTS_C_ASSERT(LazyMachState_captureCalleeSavedRegisters == offsetof(LazyMachState, captureCalleeSavedRegisters))
-
-#define LazyMachState_captureSp (MachState__isValid+8) // padding for alignment
-ASMCONSTANTS_C_ASSERT(LazyMachState_captureSp == offsetof(LazyMachState, captureSp))
-
-#define LazyMachState_captureIp (LazyMachState_captureSp+8)
-ASMCONSTANTS_C_ASSERT(LazyMachState_captureIp == offsetof(LazyMachState, captureIp))
-
#define VASigCookie__pNDirectILStub 0x8
ASMCONSTANTS_C_ASSERT(VASigCookie__pNDirectILStub == offsetof(VASigCookie, pNDirectILStub))
diff --git a/src/coreclr/vm/loongarch64/asmhelpers.S b/src/coreclr/vm/loongarch64/asmhelpers.S
index 91b5c9432ce1e1..f07811481291f2 100644
--- a/src/coreclr/vm/loongarch64/asmhelpers.S
+++ b/src/coreclr/vm/loongarch64/asmhelpers.S
@@ -345,45 +345,6 @@ LEAF_ENTRY JIT_PatchedCodeLast, _TEXT
jirl $r0, $ra, 0
LEAF_END JIT_PatchedCodeLast, _TEXT
-
-//
-// If a preserved register were pushed onto the stack between
-// the managed caller and the H_M_F, ptrS0_S8 will point to its
-// location on the stack and it would have been updated on the
-// stack by the GC already and it will be popped back into the
-// appropriate register when the appropriate epilog is run.
-//
-// Otherwise, the register is preserved across all the code
-// in this HCALL or FCALL, so we need to update those registers
-// here because the GC will have updated our copies in the
-// frame.
-//
-// So, if ptrS0_S8 points into the MachState, we need to update
-// the register here. That's what this macro does.
-//
-.macro RestoreRegMS regIndex, reg
- // Incoming:
- //
- // $a0 = address of MachState
- //
- // $regIndex: Index of the register (s0-s8). For s0, index is 23.
- //For s1, index is 24, and so on.
- //
- // $reg: Register name (e.g. s0, s1, etc)
- //
- // Get the address of the specified captured register from machine state
- addi.d $a2, $a0,(MachState__captureCalleeSavedRegisters + ((\regIndex-23)*8))
-
- //// Get the content of specified preserved register pointer from machine state
- ld.d $a3, $a0, (MachState__ptrCalleeSavedRegisters + ((\regIndex-23)*8))
-
- bne $a2, $a3, LOCAL_LABEL(NoRestore_\reg)
-
- ld.d $\reg, $a2, 0
-LOCAL_LABEL(NoRestore_\reg):
-
-.endm
-
NESTED_ENTRY ThePreStub, _TEXT, NoHandler
PROLOG_WITH_TRANSITION_BLOCK
@@ -397,67 +358,6 @@ NESTED_ENTRY ThePreStub, _TEXT, NoHandler
EPILOG_BRANCH_REG $t4
NESTED_END ThePreStub, _TEXT
-// ------------------------------------------------------------------
-// EXTERN_C int __fastcall HelperMethodFrameRestoreState(
-// INDEBUG_COMMA(HelperMethodFrame *pFrame)
-// MachState *pState
-// )
-LEAF_ENTRY HelperMethodFrameRestoreState, _TEXT
-#ifdef _DEBUG
- ori $a0, $a1, 0
-#endif
-
- // If machine state is invalid, then simply exit
- ld.w $a1, $a0, MachState__isValid
- beq $a1, $zero, LOCAL_LABEL(Done)
-
- RestoreRegMS 23, s0
- RestoreRegMS 24, s1
- RestoreRegMS 25, s2
- RestoreRegMS 26, s3
- RestoreRegMS 27, s4
- RestoreRegMS 28, s5
- RestoreRegMS 29, s6
- RestoreRegMS 30, s7
- RestoreRegMS 31, s8
- RestoreRegMS 32, fp //NOTE: here 32 is not the real fp register number.
-LOCAL_LABEL(Done):
- // Its imperative that the return value of HelperMethodFrameRestoreState is zero
- // as it is used in the state machine to loop until it becomes zero.
- // Refer to HELPER_METHOD_FRAME_END macro for details.
- ori $a0, $zero, 0
- jirl $r0, $ra, 0
-LEAF_END HelperMethodFrameRestoreState, _TEXT
-
-//-----------------------------------------------------------------------------
-// This routine captures the machine state. It is used by helper method frame
-//-----------------------------------------------------------------------------
-//void LazyMachStateCaptureState(struct LazyMachState *pState)//
-LEAF_ENTRY LazyMachStateCaptureState, _TEXT
- // marks that this is not yet valid
- st.w $zero, $a0, MachState__isValid
-
- st.d $ra, $a0, LazyMachState_captureIp
-
- // save $sp register.
- st.d $sp, $a0, LazyMachState_captureSp
-
- // save non-volatile registers that can contain object references
- addi.d $a1, $a0, LazyMachState_captureCalleeSavedRegisters
- st.d $s0, $a1, 0
- st.d $s1, $a1, 8
- st.d $s2, $a1, 16
- st.d $s3, $a1, 24
- st.d $s4, $a1, 32
- st.d $s5, $a1, 40
- st.d $s6, $a1, 48
- st.d $s7, $a1, 56
- st.d $s8, $a1, 64
- st.d $fp, $a1, 72
-
- jirl $r0, $ra, 0
-LEAF_END LazyMachStateCaptureState, _TEXT
-
// ------------------------------------------------------------------
// The call in ndirect import precode points to this function.
NESTED_ENTRY NDirectImportThunk, _TEXT, NoHandler
diff --git a/src/coreclr/vm/loongarch64/gmscpu.h b/src/coreclr/vm/loongarch64/gmscpu.h
deleted file mode 100644
index 2b3fcf986fbbaf..00000000000000
--- a/src/coreclr/vm/loongarch64/gmscpu.h
+++ /dev/null
@@ -1,101 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-
-/**************************************************************/
-/* gmscpu.h */
-/**************************************************************/
-/* HelperFrame is defines 'GET_STATE(machState)' macro, which
- figures out what the state of the machine will be when the
- current method returns. It then stores the state in the
- JIT_machState structure. */
-
-/**************************************************************/
-
-#ifndef __gmscpu_h__
-#define __gmscpu_h__
-
-#define __gmscpu_h__
-
-// S0 - S8, FP
-#define NUM_CALLEESAVED_REGISTERS 10
-
-struct MachState {
- ULONG64 captureCalleeSavedRegisters[NUM_CALLEESAVED_REGISTERS]; // preserved registers
- PTR_ULONG64 ptrCalleeSavedRegisters[NUM_CALLEESAVED_REGISTERS]; // pointers to preserved registers
- TADDR _pc; // program counter after the function returns
- TADDR _sp; // stack pointer after the function returns
- BOOL _isValid;
-
- BOOL isValid() { LIMITED_METHOD_DAC_CONTRACT; return _isValid; }
- TADDR GetRetAddr() { LIMITED_METHOD_DAC_CONTRACT; return _pc; }
-};
-
-struct LazyMachState : public MachState{
-
- TADDR captureSp; // Stack pointer at the time of capture
- TADDR captureIp; // Instruction pointer at the time of capture
-
- void setLazyStateFromUnwind(MachState* copy);
- static void unwindLazyState(LazyMachState* baseState,
- MachState* lazyState,
- DWORD threadId,
- int funCallDepth = 1);
-};
-
-inline void LazyMachState::setLazyStateFromUnwind(MachState* copy)
-{
-#if defined(DACCESS_COMPILE)
- // This function cannot be called in DAC because DAC cannot update target memory.
- DacError(E_FAIL);
- return;
-
-#else // !DACCESS_COMPILE
-
- _sp = copy->_sp;
- _pc = copy->_pc;
-
- // Capture* has already been set, so there is no need to touch it
-
- // loop over the nonvolatile context pointers and make
- // sure to properly copy interior pointers into the
- // new struct
-
- PULONG64* pSrc = (PULONG64 *)©->ptrCalleeSavedRegisters;
- PULONG64* pDst = (PULONG64 *)&this->ptrCalleeSavedRegisters;
-
- const PULONG64 LowerBoundDst = (PULONG64) this;
- const PULONG64 LowerBoundSrc = (PULONG64) copy;
-
- const PULONG64 UpperBoundSrc = (PULONG64) ((BYTE*)LowerBoundSrc + sizeof(*copy));
-
- for (int i = 0; i < NUM_CALLEESAVED_REGISTERS; i++)
- {
- PULONG64 valueSrc = *pSrc++;
-
- if ((LowerBoundSrc <= valueSrc) && (valueSrc < UpperBoundSrc))
- {
- // make any pointer interior to 'src' interior to 'dst'
- valueSrc = (PULONG64)((BYTE*)valueSrc - (BYTE*)LowerBoundSrc + (BYTE*)LowerBoundDst);
- }
-
- *pDst++ = valueSrc;
- captureCalleeSavedRegisters[i] = copy->captureCalleeSavedRegisters[i];
- }
-
-
- // this has to be last because we depend on write ordering to
- // synchronize the race implicit in updating this struct
- VolatileStore(&_isValid, TRUE);
-#endif // DACCESS_COMPILE
-}
-
-// Do the initial capture of the machine state. This is meant to be
-// as light weight as possible, as we may never need the state that
-// we capture.
-EXTERN_C void LazyMachStateCaptureState(struct LazyMachState *pState);
-
-#define CAPTURE_STATE(machState, ret) \
- LazyMachStateCaptureState(machState)
-
-
-#endif
diff --git a/src/coreclr/vm/loongarch64/stubs.cpp b/src/coreclr/vm/loongarch64/stubs.cpp
index 8513abf0e09f7a..08e0688b534e70 100644
--- a/src/coreclr/vm/loongarch64/stubs.cpp
+++ b/src/coreclr/vm/loongarch64/stubs.cpp
@@ -300,256 +300,6 @@ void ClearRegDisplayArgumentAndScratchRegisters(REGDISPLAY * pRD)
pRD->volatileCurrContextPointers.X0 = NULL;
}
-void LazyMachState::unwindLazyState(LazyMachState* baseState,
- MachState* unwoundstate,
- DWORD threadId,
- int funCallDepth)
-{
- T_CONTEXT context;
- T_KNONVOLATILE_CONTEXT_POINTERS nonVolContextPtrs;
-
- context.ContextFlags = 0; // Read by PAL_VirtualUnwind.
-
- context.S0 = unwoundstate->captureCalleeSavedRegisters[0] = baseState->captureCalleeSavedRegisters[0];
- context.S1 = unwoundstate->captureCalleeSavedRegisters[1] = baseState->captureCalleeSavedRegisters[1];
- context.S2 = unwoundstate->captureCalleeSavedRegisters[2] = baseState->captureCalleeSavedRegisters[2];
- context.S3 = unwoundstate->captureCalleeSavedRegisters[3] = baseState->captureCalleeSavedRegisters[3];
- context.S4 = unwoundstate->captureCalleeSavedRegisters[4] = baseState->captureCalleeSavedRegisters[4];
- context.S5 = unwoundstate->captureCalleeSavedRegisters[5] = baseState->captureCalleeSavedRegisters[5];
- context.S6 = unwoundstate->captureCalleeSavedRegisters[6] = baseState->captureCalleeSavedRegisters[6];
- context.S7 = unwoundstate->captureCalleeSavedRegisters[7] = baseState->captureCalleeSavedRegisters[7];
- context.S8 = unwoundstate->captureCalleeSavedRegisters[8] = baseState->captureCalleeSavedRegisters[8];
- context.Fp = unwoundstate->captureCalleeSavedRegisters[9] = baseState->captureCalleeSavedRegisters[9];
- context.Ra = 0; // Filled by the unwinder
-
- context.Sp = baseState->captureSp;
- context.Pc = baseState->captureIp;
-
-#if !defined(DACCESS_COMPILE)
- // For DAC, if we get here, it means that the LazyMachState is uninitialized and we have to unwind it.
- // The API we use to unwind in DAC is StackWalk64(), which does not support the context pointers.
- //
- // Restore the integer registers to KNONVOLATILE_CONTEXT_POINTERS to be used for unwinding.
- nonVolContextPtrs.S0 = &unwoundstate->captureCalleeSavedRegisters[0];
- nonVolContextPtrs.S1 = &unwoundstate->captureCalleeSavedRegisters[1];
- nonVolContextPtrs.S2 = &unwoundstate->captureCalleeSavedRegisters[2];
- nonVolContextPtrs.S3 = &unwoundstate->captureCalleeSavedRegisters[3];
- nonVolContextPtrs.S4 = &unwoundstate->captureCalleeSavedRegisters[4];
- nonVolContextPtrs.S5 = &unwoundstate->captureCalleeSavedRegisters[5];
- nonVolContextPtrs.S6 = &unwoundstate->captureCalleeSavedRegisters[6];
- nonVolContextPtrs.S7 = &unwoundstate->captureCalleeSavedRegisters[7];
- nonVolContextPtrs.S8 = &unwoundstate->captureCalleeSavedRegisters[8];
- nonVolContextPtrs.Fp = &unwoundstate->captureCalleeSavedRegisters[9];
- nonVolContextPtrs.Ra = 0; // Filled by the unwinder
-
-#endif // DACCESS_COMPILE
-
- LOG((LF_GCROOTS, LL_INFO100000, "STACKWALK LazyMachState::unwindLazyState(ip:%p,sp:%p)\n", baseState->captureIp, baseState->captureSp));
-
- PCODE pvControlPc;
-
- do {
-
-#ifndef TARGET_UNIX
- pvControlPc = Thread::VirtualUnwindCallFrame(&context, &nonVolContextPtrs);
-#else // !TARGET_UNIX
-#ifdef DACCESS_COMPILE
- HRESULT hr = DacVirtualUnwind(threadId, &context, &nonVolContextPtrs);
- if (FAILED(hr))
- {
- DacError(hr);
- }
-#else // DACCESS_COMPILE
- BOOL success = PAL_VirtualUnwind(&context, &nonVolContextPtrs);
- if (!success)
- {
- _ASSERTE(!"unwindLazyState: Unwinding failed");
- EEPOLICY_HANDLE_FATAL_ERROR(COR_E_EXECUTIONENGINE);
- }
-#endif // DACCESS_COMPILE
- pvControlPc = GetIP(&context);
-#endif // !TARGET_UNIX
-
- if (funCallDepth > 0)
- {
- funCallDepth--;
- if (funCallDepth == 0)
- break;
- }
- else
- {
- // Determine whether given IP resides in JITted code. (It returns nonzero in that case.)
- // Use it now to see if we've unwound to managed code yet.
- BOOL fIsManagedCode = ExecutionManager::IsManagedCode(pvControlPc);
-
- if (fIsManagedCode)
- break;
-
- }
- } while (true);
-
-#ifdef TARGET_UNIX
- unwoundstate->captureCalleeSavedRegisters[0] = context.S0;
- unwoundstate->captureCalleeSavedRegisters[1] = context.S1;
- unwoundstate->captureCalleeSavedRegisters[2] = context.S2;
- unwoundstate->captureCalleeSavedRegisters[3] = context.S3;
- unwoundstate->captureCalleeSavedRegisters[4] = context.S4;
- unwoundstate->captureCalleeSavedRegisters[5] = context.S5;
- unwoundstate->captureCalleeSavedRegisters[6] = context.S6;
- unwoundstate->captureCalleeSavedRegisters[7] = context.S7;
- unwoundstate->captureCalleeSavedRegisters[8] = context.S8;
- unwoundstate->captureCalleeSavedRegisters[9] = context.Fp;
-#endif
-
-#ifdef DACCESS_COMPILE
- // For DAC builds, we update the registers directly since we dont have context pointers
- unwoundstate->captureCalleeSavedRegisters[0] = context.S0;
- unwoundstate->captureCalleeSavedRegisters[1] = context.S1;
- unwoundstate->captureCalleeSavedRegisters[2] = context.S2;
- unwoundstate->captureCalleeSavedRegisters[3] = context.S3;
- unwoundstate->captureCalleeSavedRegisters[4] = context.S4;
- unwoundstate->captureCalleeSavedRegisters[5] = context.S5;
- unwoundstate->captureCalleeSavedRegisters[6] = context.S6;
- unwoundstate->captureCalleeSavedRegisters[7] = context.S7;
- unwoundstate->captureCalleeSavedRegisters[8] = context.S8;
- unwoundstate->captureCalleeSavedRegisters[9] = context.Fp;
-#else // !DACCESS_COMPILE
- // For non-DAC builds, update the register state from context pointers
- unwoundstate->ptrCalleeSavedRegisters[0] = nonVolContextPtrs.S0;
- unwoundstate->ptrCalleeSavedRegisters[1] = nonVolContextPtrs.S1;
- unwoundstate->ptrCalleeSavedRegisters[2] = nonVolContextPtrs.S2;
- unwoundstate->ptrCalleeSavedRegisters[3] = nonVolContextPtrs.S3;
- unwoundstate->ptrCalleeSavedRegisters[4] = nonVolContextPtrs.S4;
- unwoundstate->ptrCalleeSavedRegisters[5] = nonVolContextPtrs.S5;
- unwoundstate->ptrCalleeSavedRegisters[6] = nonVolContextPtrs.S6;
- unwoundstate->ptrCalleeSavedRegisters[7] = nonVolContextPtrs.S7;
- unwoundstate->ptrCalleeSavedRegisters[8] = nonVolContextPtrs.S8;
- unwoundstate->ptrCalleeSavedRegisters[9] = nonVolContextPtrs.Fp;
-#endif // DACCESS_COMPILE
-
- unwoundstate->_pc = context.Pc;
- unwoundstate->_sp = context.Sp;
-
- unwoundstate->_isValid = TRUE;
-}
-
-void HelperMethodFrame::UpdateRegDisplay_Impl(const PREGDISPLAY pRD, bool updateFloats)
-{
- CONTRACTL
- {
- NOTHROW;
- GC_NOTRIGGER;
- MODE_ANY;
- SUPPORTS_DAC;
- }
- CONTRACTL_END;
-
-#ifndef DACCESS_COMPILE
- if (updateFloats)
- {
- UpdateFloatingPointRegisters(pRD);
- _ASSERTE(pRD->pCurrentContext->Pc == GetReturnAddress());
- }
-#endif // DACCESS_COMPILE
-
- pRD->IsCallerContextValid = FALSE;
- pRD->IsCallerSPValid = FALSE; // Don't add usage of this field. This is only temporary.
-
- //
- // Copy the saved state from the frame to the current context.
- //
-
- LOG((LF_GCROOTS, LL_INFO100000, "STACKWALK HelperMethodFrame::UpdateRegDisplay cached ip:%p, sp:%p\n", m_MachState._pc, m_MachState._sp));
-
- #if defined(DACCESS_COMPILE)
- // For DAC, we may get here when the HMF is still uninitialized.
- // So we may need to unwind here.
- if (!m_MachState.isValid())
- {
- // This allocation throws on OOM.
- MachState* pUnwoundState = (MachState*)DacAllocHostOnlyInstance(sizeof(*pUnwoundState), true);
-
- EnsureInit(pUnwoundState);
-
- pRD->pCurrentContext->Pc = pRD->ControlPC = pUnwoundState->_pc;
- pRD->pCurrentContext->Sp = pRD->SP = pUnwoundState->_sp;
- pRD->pCurrentContext->S0 = (DWORD64)(pUnwoundState->captureCalleeSavedRegisters[0]);
- pRD->pCurrentContext->S1 = (DWORD64)(pUnwoundState->captureCalleeSavedRegisters[1]);
- pRD->pCurrentContext->S2 = (DWORD64)(pUnwoundState->captureCalleeSavedRegisters[2]);
- pRD->pCurrentContext->S3 = (DWORD64)(pUnwoundState->captureCalleeSavedRegisters[3]);
- pRD->pCurrentContext->S4 = (DWORD64)(pUnwoundState->captureCalleeSavedRegisters[4]);
- pRD->pCurrentContext->S5 = (DWORD64)(pUnwoundState->captureCalleeSavedRegisters[5]);
- pRD->pCurrentContext->S6 = (DWORD64)(pUnwoundState->captureCalleeSavedRegisters[6]);
- pRD->pCurrentContext->S7 = (DWORD64)(pUnwoundState->captureCalleeSavedRegisters[7]);
- pRD->pCurrentContext->S8 = (DWORD64)(pUnwoundState->captureCalleeSavedRegisters[8]);
- pRD->pCurrentContext->Fp = (DWORD64)(pUnwoundState->captureCalleeSavedRegisters[9]);
- pRD->pCurrentContext->Ra = 0; // Unwind again to get Caller's PC
-
- pRD->pCurrentContextPointers->S0 = pUnwoundState->ptrCalleeSavedRegisters[0];
- pRD->pCurrentContextPointers->S1 = pUnwoundState->ptrCalleeSavedRegisters[1];
- pRD->pCurrentContextPointers->S2 = pUnwoundState->ptrCalleeSavedRegisters[2];
- pRD->pCurrentContextPointers->S3 = pUnwoundState->ptrCalleeSavedRegisters[3];
- pRD->pCurrentContextPointers->S4 = pUnwoundState->ptrCalleeSavedRegisters[4];
- pRD->pCurrentContextPointers->S5 = pUnwoundState->ptrCalleeSavedRegisters[5];
- pRD->pCurrentContextPointers->S6 = pUnwoundState->ptrCalleeSavedRegisters[6];
- pRD->pCurrentContextPointers->S7 = pUnwoundState->ptrCalleeSavedRegisters[7];
- pRD->pCurrentContextPointers->S8 = pUnwoundState->ptrCalleeSavedRegisters[8];
- pRD->pCurrentContextPointers->Fp = pUnwoundState->ptrCalleeSavedRegisters[9];
- pRD->pCurrentContextPointers->Ra = NULL;
- return;
- }
-#endif // DACCESS_COMPILE
-
- // reset pContext; it's only valid for active (top-most) frame
- pRD->pContext = NULL;
- pRD->ControlPC = GetReturnAddress(); // m_MachState._pc;
- pRD->SP = (DWORD64)(size_t)m_MachState._sp;
-
- pRD->pCurrentContext->Pc = pRD->ControlPC;
- pRD->pCurrentContext->Sp = pRD->SP;
-
-#ifdef TARGET_UNIX
- pRD->pCurrentContext->S0 = m_MachState.ptrCalleeSavedRegisters[0] ? *m_MachState.ptrCalleeSavedRegisters[0] : m_MachState.captureCalleeSavedRegisters[0];
- pRD->pCurrentContext->S1 = m_MachState.ptrCalleeSavedRegisters[1] ? *m_MachState.ptrCalleeSavedRegisters[1] : m_MachState.captureCalleeSavedRegisters[1];
- pRD->pCurrentContext->S2 = m_MachState.ptrCalleeSavedRegisters[2] ? *m_MachState.ptrCalleeSavedRegisters[2] : m_MachState.captureCalleeSavedRegisters[2];
- pRD->pCurrentContext->S3 = m_MachState.ptrCalleeSavedRegisters[3] ? *m_MachState.ptrCalleeSavedRegisters[3] : m_MachState.captureCalleeSavedRegisters[3];
- pRD->pCurrentContext->S4 = m_MachState.ptrCalleeSavedRegisters[4] ? *m_MachState.ptrCalleeSavedRegisters[4] : m_MachState.captureCalleeSavedRegisters[4];
- pRD->pCurrentContext->S5 = m_MachState.ptrCalleeSavedRegisters[5] ? *m_MachState.ptrCalleeSavedRegisters[5] : m_MachState.captureCalleeSavedRegisters[5];
- pRD->pCurrentContext->S6 = m_MachState.ptrCalleeSavedRegisters[6] ? *m_MachState.ptrCalleeSavedRegisters[6] : m_MachState.captureCalleeSavedRegisters[6];
- pRD->pCurrentContext->S7 = m_MachState.ptrCalleeSavedRegisters[7] ? *m_MachState.ptrCalleeSavedRegisters[7] : m_MachState.captureCalleeSavedRegisters[7];
- pRD->pCurrentContext->S8 = m_MachState.ptrCalleeSavedRegisters[8] ? *m_MachState.ptrCalleeSavedRegisters[8] : m_MachState.captureCalleeSavedRegisters[8];
- pRD->pCurrentContext->Fp = m_MachState.ptrCalleeSavedRegisters[9] ? *m_MachState.ptrCalleeSavedRegisters[9] : m_MachState.captureCalleeSavedRegisters[9];
- pRD->pCurrentContext->Ra = 0; // Unwind again to get Caller's PC
-#else // TARGET_UNIX
- pRD->pCurrentContext->S0 = *m_MachState.ptrCalleeSavedRegisters[0];
- pRD->pCurrentContext->S1 = *m_MachState.ptrCalleeSavedRegisters[1];
- pRD->pCurrentContext->S2 = *m_MachState.ptrCalleeSavedRegisters[2];
- pRD->pCurrentContext->S3 = *m_MachState.ptrCalleeSavedRegisters[3];
- pRD->pCurrentContext->S4 = *m_MachState.ptrCalleeSavedRegisters[4];
- pRD->pCurrentContext->S5 = *m_MachState.ptrCalleeSavedRegisters[5];
- pRD->pCurrentContext->S6 = *m_MachState.ptrCalleeSavedRegisters[6];
- pRD->pCurrentContext->S7 = *m_MachState.ptrCalleeSavedRegisters[7];
- pRD->pCurrentContext->S8 = *m_MachState.ptrCalleeSavedRegisters[8];
- pRD->pCurrentContext->Fp = *m_MachState.ptrCalleeSavedRegisters[9];
- pRD->pCurrentContext->Ra = 0; // Unwind again to get Caller's PC
-#endif
-
-#if !defined(DACCESS_COMPILE)
- pRD->pCurrentContextPointers->S0 = m_MachState.ptrCalleeSavedRegisters[0];
- pRD->pCurrentContextPointers->S1 = m_MachState.ptrCalleeSavedRegisters[1];
- pRD->pCurrentContextPointers->S2 = m_MachState.ptrCalleeSavedRegisters[2];
- pRD->pCurrentContextPointers->S3 = m_MachState.ptrCalleeSavedRegisters[3];
- pRD->pCurrentContextPointers->S4 = m_MachState.ptrCalleeSavedRegisters[4];
- pRD->pCurrentContextPointers->S5 = m_MachState.ptrCalleeSavedRegisters[5];
- pRD->pCurrentContextPointers->S6 = m_MachState.ptrCalleeSavedRegisters[6];
- pRD->pCurrentContextPointers->S7 = m_MachState.ptrCalleeSavedRegisters[7];
- pRD->pCurrentContextPointers->S8 = m_MachState.ptrCalleeSavedRegisters[8];
- pRD->pCurrentContextPointers->Fp = m_MachState.ptrCalleeSavedRegisters[9];
- pRD->pCurrentContextPointers->Ra = NULL; // Unwind again to get Caller's PC
-#endif
- ClearRegDisplayArgumentAndScratchRegisters(pRD);
-}
-
void UpdateRegDisplayFromCalleeSavedRegisters(REGDISPLAY * pRD, CalleeSavedRegisters * pCalleeSaved)
{
LIMITED_METHOD_CONTRACT;
diff --git a/src/coreclr/vm/proftoeeinterfaceimpl.cpp b/src/coreclr/vm/proftoeeinterfaceimpl.cpp
index f1428f3fd64c32..ea42d1ab468e7a 100644
--- a/src/coreclr/vm/proftoeeinterfaceimpl.cpp
+++ b/src/coreclr/vm/proftoeeinterfaceimpl.cpp
@@ -8164,55 +8164,6 @@ StackWalkAction ProfilerStackWalkCallback(CrawlFrame *pCf, PROFILER_STACK_WALK_D
#ifdef TARGET_X86
-//---------------------------------------------------------------------------------------
-// Normally, calling GetFunction() on the frame is sufficient to ensure
-// HelperMethodFrames are initialized. However, sometimes we need to be able to specify
-// that we should not enter the host while initializing, so we need to initialize such
-// frames more directly. This small helper function directly forces the initialization,
-// and ensures we don't enter the host as a result if we're executing in an asynchronous
-// call (i.e., hijacked thread)
-//
-// Arguments:
-// pFrame - Frame to initialize.
-//
-// Return Value:
-// TRUE iff pFrame was successfully initialized (or was already initialized). If
-// pFrame is not a HelperMethodFrame (or derived type), this returns TRUE
-// immediately. FALSE indicates we tried to initialize w/out entering the host, and
-// had to abort as a result when a reader lock was needed but unavailable.
-//
-
-static BOOL EnsureFrameInitialized(Frame * pFrame)
-{
- CONTRACTL
- {
- NOTHROW;
- GC_NOTRIGGER;
- SUPPORTS_DAC;
- }
- CONTRACTL_END;
-
- if (pFrame->GetFrameType() != Frame::TYPE_HELPER_METHOD_FRAME)
- {
- // This frame is not a HelperMethodFrame or a frame derived from
- // HelperMethodFrame, so HMF-specific lazy initialization is not an issue.
- return TRUE;
- }
-
- HelperMethodFrame * pHMF = dac_cast(pFrame);
-
- if (pHMF->EnsureInit(
- NULL // unwindState
- ) != NULL)
- {
- // EnsureInit() succeeded and found the return address
- return TRUE;
- }
-
- // No return address was found
- return FALSE;
-}
-
//---------------------------------------------------------------------------------------
//
// Implements the COR_PRF_SNAPSHOT_X86_OPTIMIZED algorithm called by DoStackSnapshot.
@@ -8361,14 +8312,6 @@ HRESULT ProfToEEInterfaceImpl::ProfilerEbpWalker(
goto Loop;
}
-
- // This should be the first call we make to the Frame, as it will
- // ensure we force lazy initialize of HelperMethodFrames
- if (!EnsureFrameInitialized(pFrameCur))
- {
- return CORPROF_E_ASYNCHRONOUS_UNSAFE;
- }
-
// This frame is only useful if it gives us an actual return address,
// and is situated on the stack at or below our current ESP (stack
// grows up)
@@ -10730,7 +10673,6 @@ GCX_COOP_THREAD_EXISTS(GET_THREAD());
HCIMPL_PROLOG(ProfileEnter)
{
FCALL_CONTRACT;
- FC_GC_POLL_NOT_NEEDED(); // we pulse GC mode, so we are doing a poll
if (GetThreadNULLOk() == NULL)
{
@@ -10910,8 +10852,6 @@ HCIMPL_PROLOG(ProfileLeave)
{
FCALL_CONTRACT;
- FC_GC_POLL_NOT_NEEDED(); // we pulse GC mode, so we are doing a poll
-
#ifdef PROFILING_SUPPORTED
#ifdef PROF_TEST_ONLY_FORCE_ELT
@@ -11037,8 +10977,6 @@ HCIMPL2(EXTERN_C void, ProfileTailcall, UINT_PTR clientData, void * platformSpec
{
FCALL_CONTRACT;
- FC_GC_POLL_NOT_NEEDED(); // we pulse GC mode, so we are doing a poll
-
#ifdef PROFILING_SUPPORTED
#ifdef PROF_TEST_ONLY_FORCE_ELT
diff --git a/src/coreclr/vm/qcall.h b/src/coreclr/vm/qcall.h
index 45312c880acf0f..3eb31c7fbaaab0 100644
--- a/src/coreclr/vm/qcall.h
+++ b/src/coreclr/vm/qcall.h
@@ -20,12 +20,6 @@
// GC mode like a normal P/Invoke. These two features should make QCalls easier to write reliably compared to FCalls.
// QCalls are not prone to GC holes and GC starvation bugs that are common with FCalls.
//
-// QCalls perform better compared to FCalls w/ HelperMethodFrame. The QCall overhead is about 1.4x less compared to
-// FCall w/ HelperMethodFrame overhead on x86. The performance is about the same on x64. However, the implementation
-// of P/Invoke marshaling on x64 is not tuned for performance yet. The QCalls should become significantly faster compared
-// to FCalls w/ HelperMethodFrame on x64 as we do performance tuning of P/Invoke marshaling on x64.
-//
-//
// The preferred type of QCall arguments is primitive types that efficiently handled by the P/Invoke marshaler (INT32, LPCWSTR, BOOL).
// (Notice that BOOL is the correct boolean flavor for QCall arguments. FC_BOOL_ARG is the correct boolean flavor for FCall arguments.)
//
diff --git a/src/coreclr/vm/riscv64/asmconstants.h b/src/coreclr/vm/riscv64/asmconstants.h
index c62c697d6d9f07..d933a33898ab41 100644
--- a/src/coreclr/vm/riscv64/asmconstants.h
+++ b/src/coreclr/vm/riscv64/asmconstants.h
@@ -85,27 +85,6 @@ ASMCONSTANTS_C_ASSERT(CallDescrData__returnValue == offsetof(CallDescrD
#define FpStruct__BothFloat 0b10
ASMCONSTANTS_C_ASSERT(FpStruct__BothFloat == (int)FpStruct::BothFloat)
-
-// Offset of the array containing the address of captured registers in MachState
-#define MachState__captureCalleeSavedRegisters 0x0
-ASMCONSTANTS_C_ASSERT(MachState__captureCalleeSavedRegisters == offsetof(MachState, captureCalleeSavedRegisters))
-
-// Offset of the array containing the address of preserved registers in MachState
-#define MachState__ptrCalleeSavedRegisters 0x70
-ASMCONSTANTS_C_ASSERT(MachState__ptrCalleeSavedRegisters == offsetof(MachState, ptrCalleeSavedRegisters))
-
-#define MachState__isValid 0xf0
-ASMCONSTANTS_C_ASSERT(MachState__isValid == offsetof(MachState, _isValid))
-
-#define LazyMachState_captureCalleeSavedRegisters MachState__captureCalleeSavedRegisters
-ASMCONSTANTS_C_ASSERT(LazyMachState_captureCalleeSavedRegisters == offsetof(LazyMachState, captureCalleeSavedRegisters))
-
-#define LazyMachState_captureSp (MachState__isValid+8) // padding for alignment
-ASMCONSTANTS_C_ASSERT(LazyMachState_captureSp == offsetof(LazyMachState, captureSp))
-
-#define LazyMachState_captureIp (LazyMachState_captureSp+8)
-ASMCONSTANTS_C_ASSERT(LazyMachState_captureIp == offsetof(LazyMachState, captureIp))
-
#define VASigCookie__pNDirectILStub 0x8
ASMCONSTANTS_C_ASSERT(VASigCookie__pNDirectILStub == offsetof(VASigCookie, pNDirectILStub))
diff --git a/src/coreclr/vm/riscv64/asmhelpers.S b/src/coreclr/vm/riscv64/asmhelpers.S
index d524ee9c2667cd..479706eb117b4f 100644
--- a/src/coreclr/vm/riscv64/asmhelpers.S
+++ b/src/coreclr/vm/riscv64/asmhelpers.S
@@ -304,45 +304,6 @@ LEAF_ENTRY JIT_PatchedCodeLast, _TEXT
ret
LEAF_END JIT_PatchedCodeLast, _TEXT
-
-//
-// If a preserved register were pushed onto the stack between
-// the managed caller and the H_M_F, ptrS0_S8 will point to its
-// location on the stack and it would have been updated on the
-// stack by the GC already and it will be popped back into the
-// appropriate register when the appropriate epilog is run.
-//
-// Otherwise, the register is preserved across all the code
-// in this HCALL or FCALL, so we need to update those registers
-// here because the GC will have updated our copies in the
-// frame.
-//
-// So, if ptrS0_S8 points into the MachState, we need to update
-// the register here. That's what this macro does.
-//
-.macro RestoreRegMS idx, reg
- // Incoming:
- //
- // a0 = address of MachState
- //
- // idx: Index of the callee register
- // s0/fp: 0, s1: 1, s3-s11: 4-11, gp: 12 tp: 13
- //
- // reg: Register name (e.g. s0, s1, etc)
- //
- // Get the address of the specified captured register from machine state
- addi a2, a0, (MachState__captureCalleeSavedRegisters + (\idx * 8))
-
- //// Get the content of specified preserved register pointer from machine state
- ld a3, (MachState__ptrCalleeSavedRegisters + (\idx * 8))(a0)
-
- bne a2, a3, LOCAL_LABEL(NoRestore_\reg)
-
- ld \reg, 0(a2)
-LOCAL_LABEL(NoRestore_\reg):
-
-.endm
-
NESTED_ENTRY ThePreStub, _TEXT, NoHandler
PROLOG_WITH_TRANSITION_BLOCK
@@ -356,79 +317,6 @@ NESTED_ENTRY ThePreStub, _TEXT, NoHandler
EPILOG_BRANCH_REG t4
NESTED_END ThePreStub, _TEXT
-// ------------------------------------------------------------------
-
-// EXTERN_C int __fastcall HelperMethodFrameRestoreState(
-// INDEBUG_COMMA(HelperMethodFrame *pFrame)
-// MachState *pState
-// )
-LEAF_ENTRY HelperMethodFrameRestoreState, _TEXT
-#ifdef _DEBUG
- addi a0, a1, 0
-#endif
-
- // If machine state is invalid, then simply exit
- lw a1, MachState__isValid(a0)
- beq a1, zero, LOCAL_LABEL(Done)
-
- // manually assign index
- // s0/fp: 0, s1: 1, s3-s11: 4-11, gp: 12 tp: 13
- RestoreRegMS 0, s0
- RestoreRegMS 1, s1
- RestoreRegMS 2, s2
- RestoreRegMS 3, s3
- RestoreRegMS 4, s4
- RestoreRegMS 5, s5
- RestoreRegMS 6, s6
- RestoreRegMS 7, s7
- RestoreRegMS 8, s8
- RestoreRegMS 9, s9
- RestoreRegMS 10, s10
- RestoreRegMS 11, s11
- RestoreRegMS 12, gp
- RestoreRegMS 13, tp
-LOCAL_LABEL(Done):
- // Its imperative that the return value of HelperMethodFrameRestoreState is zero
- // as it is used in the state machine to loop until it becomes zero.
- // Refer to HELPER_METHOD_FRAME_END macro for details.
- addi a0, zero, 0
- ret
-LEAF_END HelperMethodFrameRestoreState, _TEXT
-
-//-----------------------------------------------------------------------------
-// This routine captures the machine state. It is used by helper method frame
-//-----------------------------------------------------------------------------
-//void LazyMachStateCaptureState(struct LazyMachState *pState)//
-LEAF_ENTRY LazyMachStateCaptureState, _TEXT
- // marks that this is not yet valid
- sw zero, (MachState__isValid)(a0)
-
- sd ra, (LazyMachState_captureIp)(a0)
-
- // save sp register.
- sd sp, (LazyMachState_captureSp)(a0)
-
- // save non-volatile registers that can contain object references
- addi a1, a0, LazyMachState_captureCalleeSavedRegisters
-
- sd s0, 0(a1)
- sd s1, 8(a1)
- sd s2, 16(a1)
- sd s3, 24(a1)
- sd s4, 32(a1)
- sd s5, 40(a1)
- sd s6, 48(a1)
- sd s7, 56(a1)
- sd s8, 64(a1)
- sd s9, 72(a1)
- sd s10, 80(a1)
- sd s11, 88(a1)
- sd gp, 96(a1)
- sd tp, 104(a1)
-
- ret
-LEAF_END LazyMachStateCaptureState, _TEXT
-
// ------------------------------------------------------------------
// The call in ndirect import precode points to this function.
NESTED_ENTRY NDirectImportThunk, _TEXT, NoHandler
diff --git a/src/coreclr/vm/riscv64/gmscpu.h b/src/coreclr/vm/riscv64/gmscpu.h
deleted file mode 100644
index 9330e81e773c53..00000000000000
--- a/src/coreclr/vm/riscv64/gmscpu.h
+++ /dev/null
@@ -1,101 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-
-/**************************************************************/
-/* gmscpu.h */
-/**************************************************************/
-/* HelperFrame is defines 'GET_STATE(machState)' macro, which
- figures out what the state of the machine will be when the
- current method returns. It then stores the state in the
- JIT_machState structure. */
-
-/**************************************************************/
-
-#ifndef __gmscpu_h__
-#define __gmscpu_h__
-
-#define __gmscpu_h__
-
-// CalleeSaveRegisters
-#define NUM_NONVOLATILE_CONTEXT_POINTERS 14
-
-struct MachState {
- ULONG64 captureCalleeSavedRegisters[NUM_NONVOLATILE_CONTEXT_POINTERS]; // preserved registers
- PTR_ULONG64 ptrCalleeSavedRegisters[NUM_NONVOLATILE_CONTEXT_POINTERS]; // pointers to preserved registers
- TADDR _pc; // program counter after the function returns
- TADDR _sp; // stack pointer after the function returns
- BOOL _isValid;
-
- BOOL isValid() { LIMITED_METHOD_DAC_CONTRACT; return _isValid; }
- TADDR GetRetAddr() { LIMITED_METHOD_DAC_CONTRACT; return _pc; }
-};
-
-struct LazyMachState : public MachState{
-
- TADDR captureSp; // Stack pointer at the time of capture
- TADDR captureIp; // Instruction pointer at the time of capture
-
- void setLazyStateFromUnwind(MachState* copy);
- static void unwindLazyState(LazyMachState* baseState,
- MachState* lazyState,
- DWORD threadId,
- int funCallDepth = 1);
-};
-
-inline void LazyMachState::setLazyStateFromUnwind(MachState* copy)
-{
-#if defined(DACCESS_COMPILE)
- // This function cannot be called in DAC because DAC cannot update target memory.
- DacError(E_FAIL);
- return;
-
-#else // !DACCESS_COMPILE
-
- _sp = copy->_sp;
- _pc = copy->_pc;
-
- // Capture* has already been set, so there is no need to touch it
-
- // loop over the nonvolatile context pointers and make
- // sure to properly copy interior pointers into the
- // new struct
-
- PULONG64* pSrc = (PULONG64 *)©->ptrCalleeSavedRegisters;
- PULONG64* pDst = (PULONG64 *)&this->ptrCalleeSavedRegisters;
-
- const PULONG64 LowerBoundDst = (PULONG64) this;
- const PULONG64 LowerBoundSrc = (PULONG64) copy;
-
- const PULONG64 UpperBoundSrc = (PULONG64) ((BYTE*)LowerBoundSrc + sizeof(*copy));
-
- for (int i = 0; i < NUM_NONVOLATILE_CONTEXT_POINTERS; i++)
- {
- PULONG64 valueSrc = *pSrc++;
-
- if ((LowerBoundSrc <= valueSrc) && (valueSrc < UpperBoundSrc))
- {
- // make any pointer interior to 'src' interior to 'dst'
- valueSrc = (PULONG64)((BYTE*)valueSrc - (BYTE*)LowerBoundSrc + (BYTE*)LowerBoundDst);
- }
-
- *pDst++ = valueSrc;
- captureCalleeSavedRegisters[i] = copy->captureCalleeSavedRegisters[i];
- }
-
-
- // this has to be last because we depend on write ordering to
- // synchronize the race implicit in updating this struct
- VolatileStore(&_isValid, TRUE);
-#endif // DACCESS_COMPILE
-}
-
-// Do the initial capture of the machine state. This is meant to be
-// as light weight as possible, as we may never need the state that
-// we capture.
-EXTERN_C void LazyMachStateCaptureState(struct LazyMachState *pState);
-
-#define CAPTURE_STATE(machState, ret) \
- LazyMachStateCaptureState(machState)
-
-
-#endif
diff --git a/src/coreclr/vm/riscv64/stubs.cpp b/src/coreclr/vm/riscv64/stubs.cpp
index 8a4e95473bfd1a..0acf47f0201c80 100644
--- a/src/coreclr/vm/riscv64/stubs.cpp
+++ b/src/coreclr/vm/riscv64/stubs.cpp
@@ -180,296 +180,6 @@ void ClearRegDisplayArgumentAndScratchRegisters(REGDISPLAY * pRD)
pRD->volatileCurrContextPointers.T6 = NULL;
}
-void LazyMachState::unwindLazyState(LazyMachState* baseState,
- MachState* unwoundstate,
- DWORD threadId,
- int funCallDepth)
-{
- T_CONTEXT context;
- T_KNONVOLATILE_CONTEXT_POINTERS nonVolContextPtrs;
-
- context.ContextFlags = 0; // Read by PAL_VirtualUnwind.
-
- context.Fp = unwoundstate->captureCalleeSavedRegisters[0] = baseState->captureCalleeSavedRegisters[0];
- context.S1 = unwoundstate->captureCalleeSavedRegisters[1] = baseState->captureCalleeSavedRegisters[1];
- context.S2 = unwoundstate->captureCalleeSavedRegisters[2] = baseState->captureCalleeSavedRegisters[2];
- context.S3 = unwoundstate->captureCalleeSavedRegisters[3] = baseState->captureCalleeSavedRegisters[3];
- context.S4 = unwoundstate->captureCalleeSavedRegisters[4] = baseState->captureCalleeSavedRegisters[4];
- context.S5 = unwoundstate->captureCalleeSavedRegisters[5] = baseState->captureCalleeSavedRegisters[5];
- context.S6 = unwoundstate->captureCalleeSavedRegisters[6] = baseState->captureCalleeSavedRegisters[6];
- context.S7 = unwoundstate->captureCalleeSavedRegisters[7] = baseState->captureCalleeSavedRegisters[7];
- context.S8 = unwoundstate->captureCalleeSavedRegisters[8] = baseState->captureCalleeSavedRegisters[8];
- context.S9 = unwoundstate->captureCalleeSavedRegisters[9] = baseState->captureCalleeSavedRegisters[9];
- context.S10 = unwoundstate->captureCalleeSavedRegisters[10] = baseState->captureCalleeSavedRegisters[10];
- context.S11 = unwoundstate->captureCalleeSavedRegisters[11] = baseState->captureCalleeSavedRegisters[11];
- context.Gp = unwoundstate->captureCalleeSavedRegisters[12] = baseState->captureCalleeSavedRegisters[12];
- context.Tp = unwoundstate->captureCalleeSavedRegisters[13] = baseState->captureCalleeSavedRegisters[13];
- context.Ra = 0; // Filled by the unwinder
-
- context.Sp = baseState->captureSp;
- context.Pc = baseState->captureIp;
-
-#if !defined(DACCESS_COMPILE)
- // For DAC, if we get here, it means that the LazyMachState is uninitialized and we have to unwind it.
- // The API we use to unwind in DAC is StackWalk64(), which does not support the context pointers.
- //
- // Restore the integer registers to KNONVOLATILE_CONTEXT_POINTERS to be used for unwinding.
- nonVolContextPtrs.Fp = &unwoundstate->captureCalleeSavedRegisters[0];
- nonVolContextPtrs.S1 = &unwoundstate->captureCalleeSavedRegisters[1];
- nonVolContextPtrs.S2 = &unwoundstate->captureCalleeSavedRegisters[2];
- nonVolContextPtrs.S3 = &unwoundstate->captureCalleeSavedRegisters[3];
- nonVolContextPtrs.S4 = &unwoundstate->captureCalleeSavedRegisters[4];
- nonVolContextPtrs.S5 = &unwoundstate->captureCalleeSavedRegisters[5];
- nonVolContextPtrs.S6 = &unwoundstate->captureCalleeSavedRegisters[6];
- nonVolContextPtrs.S7 = &unwoundstate->captureCalleeSavedRegisters[7];
- nonVolContextPtrs.S8 = &unwoundstate->captureCalleeSavedRegisters[8];
- nonVolContextPtrs.S9 = &unwoundstate->captureCalleeSavedRegisters[9];
- nonVolContextPtrs.S10 = &unwoundstate->captureCalleeSavedRegisters[10];
- nonVolContextPtrs.S11 = &unwoundstate->captureCalleeSavedRegisters[11];
- nonVolContextPtrs.Gp = &unwoundstate->captureCalleeSavedRegisters[12];
- nonVolContextPtrs.Tp = &unwoundstate->captureCalleeSavedRegisters[13];
- nonVolContextPtrs.Ra = 0; // Filled by the unwinder
-
-#endif // DACCESS_COMPILE
-
- LOG((LF_GCROOTS, LL_INFO100000, "STACKWALK LazyMachState::unwindLazyState(ip:%p,sp:%p)\n", baseState->captureIp, baseState->captureSp));
-
- PCODE pvControlPc;
-
- do {
-
-#ifndef TARGET_UNIX
- pvControlPc = Thread::VirtualUnwindCallFrame(&context, &nonVolContextPtrs);
-#else // !TARGET_UNIX
-#ifdef DACCESS_COMPILE
- HRESULT hr = DacVirtualUnwind(threadId, &context, &nonVolContextPtrs);
- if (FAILED(hr))
- {
- DacError(hr);
- }
-#else // DACCESS_COMPILE
- BOOL success = PAL_VirtualUnwind(&context, &nonVolContextPtrs);
- if (!success)
- {
- _ASSERTE(!"unwindLazyState: Unwinding failed");
- EEPOLICY_HANDLE_FATAL_ERROR(COR_E_EXECUTIONENGINE);
- }
-#endif // DACCESS_COMPILE
- pvControlPc = GetIP(&context);
-#endif // !TARGET_UNIX
-
- if (funCallDepth > 0)
- {
- funCallDepth--;
- if (funCallDepth == 0)
- break;
- }
- else
- {
- // Determine whether given IP resides in JITted code. (It returns nonzero in that case.)
- // Use it now to see if we've unwound to managed code yet.
- BOOL fIsManagedCode = ExecutionManager::IsManagedCode(pvControlPc);
-
- if (fIsManagedCode)
- break;
-
- }
- } while (true);
-
-#ifdef TARGET_UNIX
- unwoundstate->captureCalleeSavedRegisters[0] = context.Fp;
- unwoundstate->captureCalleeSavedRegisters[1] = context.S1;
- unwoundstate->captureCalleeSavedRegisters[2] = context.S2;
- unwoundstate->captureCalleeSavedRegisters[3] = context.S3;
- unwoundstate->captureCalleeSavedRegisters[4] = context.S4;
- unwoundstate->captureCalleeSavedRegisters[5] = context.S5;
- unwoundstate->captureCalleeSavedRegisters[6] = context.S6;
- unwoundstate->captureCalleeSavedRegisters[7] = context.S7;
- unwoundstate->captureCalleeSavedRegisters[8] = context.S8;
- unwoundstate->captureCalleeSavedRegisters[9] = context.S9;
- unwoundstate->captureCalleeSavedRegisters[10] = context.S10;
- unwoundstate->captureCalleeSavedRegisters[11] = context.S11;
- unwoundstate->captureCalleeSavedRegisters[12] = context.Gp;
- unwoundstate->captureCalleeSavedRegisters[13] = context.Tp;
-#endif
-
-#ifdef DACCESS_COMPILE
- // For DAC builds, we update the registers directly since we dont have context pointers
- unwoundstate->captureCalleeSavedRegisters[0] = context.Fp;
- unwoundstate->captureCalleeSavedRegisters[1] = context.S1;
- unwoundstate->captureCalleeSavedRegisters[2] = context.S2;
- unwoundstate->captureCalleeSavedRegisters[3] = context.S3;
- unwoundstate->captureCalleeSavedRegisters[4] = context.S4;
- unwoundstate->captureCalleeSavedRegisters[5] = context.S5;
- unwoundstate->captureCalleeSavedRegisters[6] = context.S6;
- unwoundstate->captureCalleeSavedRegisters[7] = context.S7;
- unwoundstate->captureCalleeSavedRegisters[8] = context.S8;
- unwoundstate->captureCalleeSavedRegisters[9] = context.S9;
- unwoundstate->captureCalleeSavedRegisters[10] = context.S10;
- unwoundstate->captureCalleeSavedRegisters[11] = context.S11;
- unwoundstate->captureCalleeSavedRegisters[12] = context.Gp;
- unwoundstate->captureCalleeSavedRegisters[13] = context.Tp;
-#else // !DACCESS_COMPILE
- // For non-DAC builds, update the register state from context pointers
- unwoundstate->ptrCalleeSavedRegisters[0] = nonVolContextPtrs.Fp;
- unwoundstate->ptrCalleeSavedRegisters[1] = nonVolContextPtrs.S1;
- unwoundstate->ptrCalleeSavedRegisters[2] = nonVolContextPtrs.S2;
- unwoundstate->ptrCalleeSavedRegisters[3] = nonVolContextPtrs.S3;
- unwoundstate->ptrCalleeSavedRegisters[4] = nonVolContextPtrs.S4;
- unwoundstate->ptrCalleeSavedRegisters[5] = nonVolContextPtrs.S5;
- unwoundstate->ptrCalleeSavedRegisters[6] = nonVolContextPtrs.S6;
- unwoundstate->ptrCalleeSavedRegisters[7] = nonVolContextPtrs.S7;
- unwoundstate->ptrCalleeSavedRegisters[8] = nonVolContextPtrs.S8;
- unwoundstate->ptrCalleeSavedRegisters[9] = nonVolContextPtrs.S9;
- unwoundstate->ptrCalleeSavedRegisters[10] = nonVolContextPtrs.S10;
- unwoundstate->ptrCalleeSavedRegisters[11] = nonVolContextPtrs.S11;
- unwoundstate->ptrCalleeSavedRegisters[12] = nonVolContextPtrs.Gp;
- unwoundstate->ptrCalleeSavedRegisters[13] = nonVolContextPtrs.Tp;
-#endif // DACCESS_COMPILE
-
- unwoundstate->_pc = context.Pc;
- unwoundstate->_sp = context.Sp;
-
- unwoundstate->_isValid = TRUE;
-}
-
-void HelperMethodFrame::UpdateRegDisplay_Impl(const PREGDISPLAY pRD, bool updateFloats)
-{
- CONTRACTL
- {
- NOTHROW;
- GC_NOTRIGGER;
- MODE_ANY;
- SUPPORTS_DAC;
- }
- CONTRACTL_END;
-
-#ifndef DACCESS_COMPILE
- if (updateFloats)
- {
- UpdateFloatingPointRegisters(pRD);
- _ASSERTE(pRD->pCurrentContext->Pc == GetReturnAddress());
- }
-#endif // DACCESS_COMPILE
-
- pRD->IsCallerContextValid = FALSE;
- pRD->IsCallerSPValid = FALSE; // Don't add usage of this field. This is only temporary.
-
- //
- // Copy the saved state from the frame to the current context.
- //
-
- LOG((LF_GCROOTS, LL_INFO100000, "STACKWALK HelperMethodFrame::UpdateRegDisplay cached ip:%p, sp:%p\n", m_MachState._pc, m_MachState._sp));
-
- #if defined(DACCESS_COMPILE)
- // For DAC, we may get here when the HMF is still uninitialized.
- // So we may need to unwind here.
- if (!m_MachState.isValid())
- {
- // This allocation throws on OOM.
- MachState* pUnwoundState = (MachState*)DacAllocHostOnlyInstance(sizeof(*pUnwoundState), true);
-
- EnsureInit(pUnwoundState);
-
- pRD->pCurrentContext->Pc = pRD->ControlPC = pUnwoundState->_pc;
- pRD->pCurrentContext->Sp = pRD->SP = pUnwoundState->_sp;
- pRD->pCurrentContext->Fp = (DWORD64)(pUnwoundState->captureCalleeSavedRegisters[0]);
- pRD->pCurrentContext->S1 = (DWORD64)(pUnwoundState->captureCalleeSavedRegisters[1]);
- pRD->pCurrentContext->S2 = (DWORD64)(pUnwoundState->captureCalleeSavedRegisters[2]);
- pRD->pCurrentContext->S3 = (DWORD64)(pUnwoundState->captureCalleeSavedRegisters[3]);
- pRD->pCurrentContext->S4 = (DWORD64)(pUnwoundState->captureCalleeSavedRegisters[4]);
- pRD->pCurrentContext->S5 = (DWORD64)(pUnwoundState->captureCalleeSavedRegisters[5]);
- pRD->pCurrentContext->S6 = (DWORD64)(pUnwoundState->captureCalleeSavedRegisters[6]);
- pRD->pCurrentContext->S7 = (DWORD64)(pUnwoundState->captureCalleeSavedRegisters[7]);
- pRD->pCurrentContext->S8 = (DWORD64)(pUnwoundState->captureCalleeSavedRegisters[8]);
- pRD->pCurrentContext->S9 = (DWORD64)(pUnwoundState->captureCalleeSavedRegisters[9]);
- pRD->pCurrentContext->S10 = (DWORD64)(pUnwoundState->captureCalleeSavedRegisters[10]);
- pRD->pCurrentContext->S11 = (DWORD64)(pUnwoundState->captureCalleeSavedRegisters[11]);
- pRD->pCurrentContext->Gp = (DWORD64)(pUnwoundState->captureCalleeSavedRegisters[12]);
- pRD->pCurrentContext->Tp = (DWORD64)(pUnwoundState->captureCalleeSavedRegisters[13]);
- pRD->pCurrentContext->Ra = 0; // Unwind again to get Caller's PC
-
- pRD->pCurrentContextPointers->Fp = pUnwoundState->ptrCalleeSavedRegisters[0];
- pRD->pCurrentContextPointers->S1 = pUnwoundState->ptrCalleeSavedRegisters[1];
- pRD->pCurrentContextPointers->S2 = pUnwoundState->ptrCalleeSavedRegisters[2];
- pRD->pCurrentContextPointers->S3 = pUnwoundState->ptrCalleeSavedRegisters[3];
- pRD->pCurrentContextPointers->S4 = pUnwoundState->ptrCalleeSavedRegisters[4];
- pRD->pCurrentContextPointers->S5 = pUnwoundState->ptrCalleeSavedRegisters[5];
- pRD->pCurrentContextPointers->S6 = pUnwoundState->ptrCalleeSavedRegisters[6];
- pRD->pCurrentContextPointers->S7 = pUnwoundState->ptrCalleeSavedRegisters[7];
- pRD->pCurrentContextPointers->S8 = pUnwoundState->ptrCalleeSavedRegisters[8];
- pRD->pCurrentContextPointers->S9 = pUnwoundState->ptrCalleeSavedRegisters[9];
- pRD->pCurrentContextPointers->S10 = pUnwoundState->ptrCalleeSavedRegisters[10];
- pRD->pCurrentContextPointers->S11 = pUnwoundState->ptrCalleeSavedRegisters[11];
- pRD->pCurrentContextPointers->Gp = pUnwoundState->ptrCalleeSavedRegisters[12];
- pRD->pCurrentContextPointers->Tp = pUnwoundState->ptrCalleeSavedRegisters[13];
- pRD->pCurrentContextPointers->Ra = NULL;
- return;
- }
-#endif // DACCESS_COMPILE
-
- // reset pContext; it's only valid for active (top-most) frame
- pRD->pContext = NULL;
- pRD->ControlPC = GetReturnAddress(); // m_MachState._pc;
- pRD->SP = (DWORD64)(size_t)m_MachState._sp;
-
- pRD->pCurrentContext->Pc = pRD->ControlPC;
- pRD->pCurrentContext->Sp = pRD->SP;
-
-#ifdef TARGET_UNIX
- pRD->pCurrentContext->Fp = m_MachState.ptrCalleeSavedRegisters[0] ? *m_MachState.ptrCalleeSavedRegisters[0] : m_MachState.captureCalleeSavedRegisters[0];
- pRD->pCurrentContext->S1 = m_MachState.ptrCalleeSavedRegisters[1] ? *m_MachState.ptrCalleeSavedRegisters[1] : m_MachState.captureCalleeSavedRegisters[1];
- pRD->pCurrentContext->S2 = m_MachState.ptrCalleeSavedRegisters[2] ? *m_MachState.ptrCalleeSavedRegisters[2] : m_MachState.captureCalleeSavedRegisters[2];
- pRD->pCurrentContext->S3 = m_MachState.ptrCalleeSavedRegisters[3] ? *m_MachState.ptrCalleeSavedRegisters[3] : m_MachState.captureCalleeSavedRegisters[3];
- pRD->pCurrentContext->S4 = m_MachState.ptrCalleeSavedRegisters[4] ? *m_MachState.ptrCalleeSavedRegisters[4] : m_MachState.captureCalleeSavedRegisters[4];
- pRD->pCurrentContext->S5 = m_MachState.ptrCalleeSavedRegisters[5] ? *m_MachState.ptrCalleeSavedRegisters[5] : m_MachState.captureCalleeSavedRegisters[5];
- pRD->pCurrentContext->S6 = m_MachState.ptrCalleeSavedRegisters[6] ? *m_MachState.ptrCalleeSavedRegisters[6] : m_MachState.captureCalleeSavedRegisters[6];
- pRD->pCurrentContext->S7 = m_MachState.ptrCalleeSavedRegisters[7] ? *m_MachState.ptrCalleeSavedRegisters[7] : m_MachState.captureCalleeSavedRegisters[7];
- pRD->pCurrentContext->S8 = m_MachState.ptrCalleeSavedRegisters[8] ? *m_MachState.ptrCalleeSavedRegisters[8] : m_MachState.captureCalleeSavedRegisters[8];
- pRD->pCurrentContext->S9 = m_MachState.ptrCalleeSavedRegisters[9] ? *m_MachState.ptrCalleeSavedRegisters[9] : m_MachState.captureCalleeSavedRegisters[9];
- pRD->pCurrentContext->S10 = m_MachState.ptrCalleeSavedRegisters[10] ? *m_MachState.ptrCalleeSavedRegisters[10] : m_MachState.captureCalleeSavedRegisters[10];
- pRD->pCurrentContext->S11 = m_MachState.ptrCalleeSavedRegisters[11] ? *m_MachState.ptrCalleeSavedRegisters[11] : m_MachState.captureCalleeSavedRegisters[11];
- pRD->pCurrentContext->Gp = m_MachState.ptrCalleeSavedRegisters[12] ? *m_MachState.ptrCalleeSavedRegisters[12] : m_MachState.captureCalleeSavedRegisters[12];
- pRD->pCurrentContext->Tp = m_MachState.ptrCalleeSavedRegisters[13] ? *m_MachState.ptrCalleeSavedRegisters[13] : m_MachState.captureCalleeSavedRegisters[13];
- pRD->pCurrentContext->Ra = 0; // Unwind again to get Caller's PC
-#else // TARGET_UNIX
- pRD->pCurrentContext->Fp = *m_MachState.ptrCalleeSavedRegisters[0];
- pRD->pCurrentContext->S1 = *m_MachState.ptrCalleeSavedRegisters[1];
- pRD->pCurrentContext->S2 = *m_MachState.ptrCalleeSavedRegisters[2];
- pRD->pCurrentContext->S3 = *m_MachState.ptrCalleeSavedRegisters[3];
- pRD->pCurrentContext->S4 = *m_MachState.ptrCalleeSavedRegisters[4];
- pRD->pCurrentContext->S5 = *m_MachState.ptrCalleeSavedRegisters[5];
- pRD->pCurrentContext->S6 = *m_MachState.ptrCalleeSavedRegisters[6];
- pRD->pCurrentContext->S7 = *m_MachState.ptrCalleeSavedRegisters[7];
- pRD->pCurrentContext->S8 = *m_MachState.ptrCalleeSavedRegisters[8];
- pRD->pCurrentContext->S9 = *m_MachState.ptrCalleeSavedRegisters[9];
- pRD->pCurrentContext->S10 = *m_MachState.ptrCalleeSavedRegisters[10];
- pRD->pCurrentContext->S11 = *m_MachState.ptrCalleeSavedRegisters[11];
- pRD->pCurrentContext->Gp = *m_MachState.ptrCalleeSavedRegisters[12];
- pRD->pCurrentContext->Tp = *m_MachState.ptrCalleeSavedRegisters[13];
- pRD->pCurrentContext->Ra = 0; // Unwind again to get Caller's PC
-#endif
-
-#if !defined(DACCESS_COMPILE)
- pRD->pCurrentContextPointers->Fp = m_MachState.ptrCalleeSavedRegisters[0];
- pRD->pCurrentContextPointers->S1 = m_MachState.ptrCalleeSavedRegisters[1];
- pRD->pCurrentContextPointers->S2 = m_MachState.ptrCalleeSavedRegisters[2];
- pRD->pCurrentContextPointers->S3 = m_MachState.ptrCalleeSavedRegisters[3];
- pRD->pCurrentContextPointers->S4 = m_MachState.ptrCalleeSavedRegisters[4];
- pRD->pCurrentContextPointers->S5 = m_MachState.ptrCalleeSavedRegisters[5];
- pRD->pCurrentContextPointers->S6 = m_MachState.ptrCalleeSavedRegisters[6];
- pRD->pCurrentContextPointers->S7 = m_MachState.ptrCalleeSavedRegisters[7];
- pRD->pCurrentContextPointers->S8 = m_MachState.ptrCalleeSavedRegisters[8];
- pRD->pCurrentContextPointers->S9 = m_MachState.ptrCalleeSavedRegisters[9];
- pRD->pCurrentContextPointers->S10 = m_MachState.ptrCalleeSavedRegisters[10];
- pRD->pCurrentContextPointers->S11 = m_MachState.ptrCalleeSavedRegisters[11];
- pRD->pCurrentContextPointers->Gp = m_MachState.ptrCalleeSavedRegisters[12];
- pRD->pCurrentContextPointers->Tp = m_MachState.ptrCalleeSavedRegisters[13];
- pRD->pCurrentContextPointers->Ra = NULL; // Unwind again to get Caller's PC
-#endif
- ClearRegDisplayArgumentAndScratchRegisters(pRD);
-}
-
void UpdateRegDisplayFromCalleeSavedRegisters(REGDISPLAY * pRD, CalleeSavedRegisters * pCalleeSaved)
{
LIMITED_METHOD_CONTRACT;
diff --git a/src/coreclr/vm/runtimehandles.cpp b/src/coreclr/vm/runtimehandles.cpp
index 95a2c8c08aa19f..f8dabeffe20bf5 100644
--- a/src/coreclr/vm/runtimehandles.cpp
+++ b/src/coreclr/vm/runtimehandles.cpp
@@ -1,7 +1,6 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
-
#include "common.h"
#include "corhdr.h"
#include "runtimehandles.h"
@@ -1848,14 +1847,14 @@ extern "C" void QCALLTYPE RuntimeMethodHandle_StripMethodInstantiation(MethodDes
// For {task-returning, async} variants Reflection hands out only the task-returning variant.
// the async varinat is an implementation detail that conceptually does not exist.
// TODO: (async) the filtering may not cover all scenarios. Review and add tests.
-//
+//
// For generic methods we always hand out an instantiating stub except for a generic method definition
// For non-generic methods on generic types we need an instantiating stub if it's one of the following
// - static method on a generic class
// - static or instance method on a generic interface
// - static or instance method on a generic value type
// The Reflection policy is to always hand out instantiating stubs in these cases
-//
+//
// For methods on non-generic value types we can use either the canonical method or the unboxing stub
// The Reflection policy is to always hand out unboxing stubs if the methods are virtual methods
// The reason for this is that in the current implementation of the class loader, the v-table slots for
@@ -1886,8 +1885,8 @@ FCIMPL2(MethodDesc*, RuntimeMethodHandle::GetStubIfNeededInternal,
if (pMethod->IsAsyncVariantMethod())
return NULL;
- // Perf optimization: this logic is actually duplicated in FindOrCreateAssociatedMethodDescForReflection, but since it
- // is the more common case it's worth the duplicate check here to avoid the helper method frame
+ // Perf optimization: this logic is duplicated from FindOrCreateAssociatedMethodDescForReflection,
+ // but it's worth repeating here to avoid unnecessary overhead in the common case.
if (pMethod->HasMethodInstantiation()
|| (!instType.IsValueType()
&& (!instType.HasInstantiation() || instType.IsGenericTypeDefinition())))
diff --git a/src/coreclr/vm/threads.cpp b/src/coreclr/vm/threads.cpp
index b86922e7fec1c5..ee16db9fec5398 100644
--- a/src/coreclr/vm/threads.cpp
+++ b/src/coreclr/vm/threads.cpp
@@ -291,18 +291,15 @@ static StackWalkAction DetectHandleILStubsForDebugger_StackWalkCallback(CrawlFra
return SWA_CONTINUE;
}
-// This is really just a heuristic to detect if we are executing in an M2U IL stub or
-// one of the marshaling methods it calls. It doesn't deal with U2M IL stubs.
-// We loop through the frame chain looking for an uninitialized TransitionFrame.
-// If there is one, then we are executing in an M2U IL stub or one of the methods it calls.
-// On the other hand, if there is an initialized TransitionFrame, then we are not.
-// Also, if there is an HMF on the stack, then we stop. This could be the case where
-// an IL stub calls an FCALL which ends up in a managed method, and the debugger wants to
-// stop in those cases. Some examples are COMException..ctor and custom marshalers.
+// This is a heuristic to detect if we are executing in an M2U IL stub or one of its marshaling methods.
+// It does not handle U2M IL stubs.
//
-// X86 IL stubs use InlinedCallFrame and are indistinguishable from ordinary methods with
-// inlined P/Invoke when judging just from the frame chain. We use stack walk to decide
-// this case.
+// We walk the frame chain looking for an uninitialized TransitionFrame.
+// If found, we are in an M2U IL stub or one of its called methods.
+// If a TransitionFrame is initialized, then we are not.
+//
+// On x86, IL stubs use InlinedCallFrame, which looks like regular methods with inlined P/Invoke calls,
+// so we rely on stack walking to detect this scenario.
bool Thread::DetectHandleILStubsForDebugger()
{
CONTRACTL {
@@ -317,13 +314,8 @@ bool Thread::DetectHandleILStubsForDebugger()
{
while (pFrame != FRAME_TOP)
{
- // Check for HMF's. See the comment at the beginning of this function.
- if (pFrame->GetFrameIdentifier() == FrameIdentifier::HelperMethodFrame)
- {
- break;
- }
// If there is an entry frame (i.e. U2M managed), we should break.
- else if (pFrame->GetFrameType() == Frame::TYPE_ENTRY)
+ if (pFrame->GetFrameType() == Frame::TYPE_ENTRY)
{
break;
}
@@ -1471,10 +1463,6 @@ Thread::Thread()
m_dwAVInRuntimeImplOkayCount = 0;
-#ifdef _DEBUG
- m_pHelperMethodFrameCallerList = (HelperMethodFrameCallerList*)-1;
-#endif
-
m_pExceptionDuringStartup = NULL;
#ifdef HAVE_GCCOVER
diff --git a/src/coreclr/vm/threads.h b/src/coreclr/vm/threads.h
index 02edbbeb0f0563..b54eec3d61d0d9 100644
--- a/src/coreclr/vm/threads.h
+++ b/src/coreclr/vm/threads.h
@@ -1,8 +1,5 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
-// THREADS.H -
-//
-
//
//
@@ -135,7 +132,6 @@ class ThreadBaseObject;
class AppDomainStack;
class DomainAssembly;
class DeadlockAwareLock;
-struct HelperMethodFrameCallerList;
class EECodeInfo;
class DebuggerPatchSkip;
class FaultingExceptionFrame;
@@ -3505,14 +3501,6 @@ friend class DebuggerController;
}
#endif // _DEBUG
-#ifdef _DEBUG
-private:
- friend class FCallTransitionState;
- friend class PermitHelperMethodFrameState;
- friend class CompletedFCallTransitionState;
- HelperMethodFrameCallerList *m_pHelperMethodFrameCallerList;
-#endif // _DEBUG
-
private:
// If HasStarted fails, we cache the exception here, and rethrow on the thread which
// calls Thread.Start.
diff --git a/src/coreclr/vm/virtualcallstub.cpp b/src/coreclr/vm/virtualcallstub.cpp
index 491b164ce97963..83de18676fa34d 100644
--- a/src/coreclr/vm/virtualcallstub.cpp
+++ b/src/coreclr/vm/virtualcallstub.cpp
@@ -1,17 +1,7 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
-//
-// File: VirtualCallStub.CPP
-//
-// This file contains the virtual call stub manager and caches
-//
-
-
-//
-
-//
-// ============================================================================
+// This file contains the virtual call stub manager and caches
#include "common.h"
#include "array.h"
@@ -2493,8 +2483,8 @@ VirtualCallStubManager::GetRepresentativeMethodDescFromToken(
POSTCONDITION(CheckPointer(RETVAL));
} CONTRACT_END;
- // This is called when trying to create a HelperMethodFrame, which means there are
- // potentially managed references on the stack that are not yet protected.
+ // This is called in a context where managed references on the stack may not be fully protected,
+ // so garbage collection must be forbidden here.
GCX_FORBID();
if (token.IsTypedToken())
diff --git a/src/coreclr/vm/wasm/gmscpu.h b/src/coreclr/vm/wasm/gmscpu.h
deleted file mode 100644
index 5355cfbc546ee6..00000000000000
--- a/src/coreclr/vm/wasm/gmscpu.h
+++ /dev/null
@@ -1,72 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-
-#ifndef __gmscpu_h__
-#define __gmscpu_h__
-
-#define __gmscpu_h__
-
- // A MachState indicates the register state of the processor at some point in time (usually
- // just before or after a call is made). It can be made one of two ways. Either explicitly
- // (when you for some reason know the values of all the registers), or implicitly using the
- // GET_STATE macros.
-
- typedef DPTR(struct MachState) PTR_MachState;
- struct MachState {
-
- BOOL isValid() { LIMITED_METHOD_DAC_CONTRACT; return TRUE; }
- TADDR GetRetAddr() { LIMITED_METHOD_DAC_CONTRACT; return 0; }
-
- friend class HelperMethodFrame;
- friend class CheckAsmOffsets;
- friend struct LazyMachState;
- };
-
- /********************************************************************/
- /* This allows you to defer the computation of the Machine state
- until later. Note that we don't reuse slots, because we want
- this to be threadsafe without locks */
-
- struct LazyMachState : public MachState {
- // compute the machine state of the processor as it will exist just
- // after the return after at most'funCallDepth' number of functions.
- // if 'testFtn' is non-NULL, the return address is tested at each
- // return instruction encountered. If this test returns non-NULL,
- // then stack walking stops (thus you can walk up to the point that the
- // return address matches some criteria
-
- // Normally this is called with funCallDepth=1 and testFtn = 0 so that
- // it returns the state of the processor after the function that called 'captureState()'
- void setLazyStateFromUnwind(MachState* copy);
- static void unwindLazyState(LazyMachState* baseState,
- MachState* lazyState,
- DWORD threadId,
- int funCallDepth = 1);
-
- friend class HelperMethodFrame;
- friend class CheckAsmOffsets;
- };
-
- // R4 - R11
- #define NUM_NONVOLATILE_CONTEXT_POINTERS 8
-
- inline void LazyMachState::setLazyStateFromUnwind(MachState* copy)
- {
- _ASSERTE("LazyMachState::setLazyStateFromUnwind is not implemented");
- }
- typedef DPTR(LazyMachState) PTR_LazyMachState;
-
- // Do the initial capture of the machine state. This is meant to be
- // as light weight as possible, as we may never need the state that
- // we capture. Thus to complete the process you need to call
- // 'getMachState()', which finishes the process
- EXTERN_C void LazyMachStateCaptureState(struct LazyMachState *pState);
-
- // CAPTURE_STATE captures just enough register state so that the state of the
- // processor can be deterined just after the routine that has CAPTURE_STATE in
- // it returns.
-
- #define CAPTURE_STATE(machState, ret) \
- LazyMachStateCaptureState(machState)
-
- #endif
diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/StackWalk/FrameHandling/FrameIterator.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/StackWalk/FrameHandling/FrameIterator.cs
index 56fdae3c78c623..50f61514a22c2a 100644
--- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/StackWalk/FrameHandling/FrameIterator.cs
+++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/StackWalk/FrameHandling/FrameIterator.cs
@@ -35,11 +35,6 @@ private enum FrameType
HijackFrame,
/* Other Frame Types not handled by the iterator */
- HelperMethodFrame,
- HelperMethodFrame_1OBJ,
- HelperMethodFrame_2OBJ,
- HelperMethodFrame_3OBJ,
- HelperMethodFrame_PROTECTOBJ,
UnmanagedToManagedFrame,
ComMethodFrame,
ComPrestubMethodFrame,