summaryrefslogtreecommitdiff
path: root/src/vm/arm/gmscpu.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/vm/arm/gmscpu.h')
-rw-r--r--src/vm/arm/gmscpu.h175
1 files changed, 175 insertions, 0 deletions
diff --git a/src/vm/arm/gmscpu.h b/src/vm/arm/gmscpu.h
new file mode 100644
index 0000000000..dee60633ad
--- /dev/null
+++ b/src/vm/arm/gmscpu.h
@@ -0,0 +1,175 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/**************************************************************/
+/* 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,
+ HostCallPreference hostCallPreference = AllowHostCalls);
+
+ 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 = &copy->_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 the routine that has CAPTURE_STATE in
+// it returns.
+
+#define CAPTURE_STATE(machState, ret) \
+ LazyMachStateCaptureState(machState)
+
+#endif