summaryrefslogtreecommitdiff
path: root/src/vm/arm64/gmscpu.h
blob: 7785daf219e766a03126713a97c9d9ff580268da (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
// 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__

// 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;
    
    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,
                                HostCallPreference hostCallPreference = AllowHostCalls);
};

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 *)&copy->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