summaryrefslogtreecommitdiff
path: root/src/vm/fptrstubs.cpp
blob: 6502a43c555e7cc8f4402db213578a0934c51440 (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
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
// 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.



#include "common.h"
#include "fptrstubs.h"


// -------------------------------------------------------
// FuncPtr stubs
// -------------------------------------------------------

Precode* FuncPtrStubs::Lookup(MethodDesc * pMD, PrecodeType type)
{
    CONTRACTL
    {
        NOTHROW;
        GC_TRIGGERS;
    }
    CONTRACTL_END;

    Precode* pPrecode = NULL;
    {
        CrstHolder ch(&m_hashTableCrst);
        pPrecode = m_hashTable.Lookup(PrecodeKey(pMD, type));
    }
    return pPrecode;
}


#ifndef DACCESS_COMPILE
//
// FuncPtrStubs
//

FuncPtrStubs::FuncPtrStubs()
    : m_hashTableCrst(CrstFuncPtrStubs, CRST_UNSAFE_ANYMODE)
{
    WRAPPER_NO_CONTRACT;
}

PrecodeType FuncPtrStubs::GetDefaultType(MethodDesc* pMD)
{
    WRAPPER_NO_CONTRACT;

    PrecodeType type = PRECODE_STUB;
 
#ifdef HAS_FIXUP_PRECODE
    // Use the faster fixup precode if it is available
    type = PRECODE_FIXUP;
#endif // HAS_FIXUP_PRECODE

#ifdef HAS_REMOTING_PRECODE
    if (pMD->IsRemotingInterceptedViaVirtualDispatch())
    {
        type = PRECODE_REMOTING;
    }
#endif // HAS_REMOTING_PRECODE

    return type;
}

//
// Returns an existing stub, or creates a new one
//

PCODE FuncPtrStubs::GetFuncPtrStub(MethodDesc * pMD, PrecodeType type)
{
    CONTRACTL
    {
        THROWS;
        GC_TRIGGERS;
        SO_INTOLERANT;
        INJECT_FAULT(ThrowOutOfMemory(););
    }
    CONTRACTL_END

    Precode* pPrecode = NULL;
    {
        CrstHolder ch(&m_hashTableCrst);
        pPrecode = m_hashTable.Lookup(PrecodeKey(pMD, type));
    }

    if (pPrecode != NULL)
    {
        return pPrecode->GetEntryPoint();
    }

    PCODE target = NULL;

    if (type != GetDefaultType(pMD) &&
        // Always use stable entrypoint for LCG. If the cached precode pointed directly to JITed code,
        // we would not be able to reuse it when the DynamicMethodDesc got reused for a new DynamicMethod.
        !pMD->IsLCGMethod())
    {
        // Set the target if precode is not of the default type. We are patching the precodes of the default type only.
        target = pMD->GetMultiCallableAddrOfCode();
    }
    else
    if (pMD->HasStableEntryPoint())
    {
        // Set target
        target = pMD->GetStableEntryPoint();
    }
    else
    {
        // Set the target if method is methodimpled. We would not get to patch it otherwise.
        MethodDesc* pMDImpl = MethodTable::MapMethodDeclToMethodImpl(pMD);

        if (pMDImpl != pMD)
            target = pMDImpl->GetMultiCallableAddrOfCode();
    }

    //
    // We currently do not have a precode for this MethodDesc, so we will allocate one.
    // We allocate outside of the lock and then take the lock (m_hashTableCrst) and 
    // if we still do not have a precode we Add the one that we just allocated and 
    // call SuppressRelease to keep our allocation
    // If another thread beat us in adding the precode we don't call SuppressRelease
    // so the AllocMemTracker destructor will free the memory that we allocated
    // 
    {
        AllocMemTracker amt;
        Precode* pNewPrecode = Precode::Allocate(type, pMD, pMD->GetLoaderAllocatorForCode(), &amt);
   
        if (target != NULL)
        {
            pNewPrecode->SetTargetInterlocked(target);
        }

        {
            CrstHolder ch(&m_hashTableCrst);

            // Was an entry added in the meantime?
            // Is the entry still NULL?
            pPrecode = m_hashTable.Lookup(PrecodeKey(pMD, type));

            if (pPrecode == NULL)
            {
                // Use the one we allocated above
                pPrecode = pNewPrecode;
                m_hashTable.Add(pPrecode);
                amt.SuppressRelease();
            }
        }
    }

    return pPrecode->GetEntryPoint();
}
#endif // DACCESS_COMPILE