summaryrefslogtreecommitdiff
path: root/src/vm/methodimpl.cpp
blob: 9cd452c056cd92006fe6ec273b69c20a8998328b (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
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
// 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.
//
// File: methodimpl.cpp
//


//

//
// ============================================================================

#include "common.h"
#include "methodimpl.h"

DWORD MethodImpl::FindSlotIndex(DWORD slot)
{
    CONTRACTL {
        NOTHROW;
        GC_NOTRIGGER;
        MODE_ANY;
        PRECONDITION(CheckPointer(GetSlots()));
    } CONTRACTL_END;

    DWORD dwSize = GetSize();
    if(dwSize == 0) {
        return INVALID_INDEX;
    }

    // Simple binary search
    PTR_DWORD rgSlots = GetSlots();
    INT32     l       = 0;
    INT32     r       = dwSize - 1;
    INT32     pivot;

    while(1) {
        pivot =  (l + r) / 2;

        if(rgSlots[pivot] == slot) {
            break; // found it
        }
        else if(rgSlots[pivot] < slot) {
            l = pivot + 1;
        }
        else {
            r = pivot - 1;
        }

        if(l > r) {
            return INVALID_INDEX; // Not here
        }
    }

    CONSISTENCY_CHECK(pivot >= 0);
    return (DWORD)pivot;
}

PTR_MethodDesc MethodImpl::FindMethodDesc(DWORD slot, PTR_MethodDesc defaultReturn)
{
    CONTRACTL
    {
        if (FORBIDGC_LOADER_USE_ENABLED()) NOTHROW; else THROWS;
        if (FORBIDGC_LOADER_USE_ENABLED()) GC_NOTRIGGER; else GC_TRIGGERS;
        if (FORBIDGC_LOADER_USE_ENABLED()) FORBID_FAULT; else { INJECT_FAULT(COMPlusThrowOM()); }
        MODE_ANY;
    }
    CONTRACTL_END

    DWORD slotIndex = FindSlotIndex(slot);
    if (slotIndex == INVALID_INDEX) {
        return defaultReturn;
    }

    return GetMethodDesc(slotIndex, defaultReturn);
}

PTR_MethodDesc MethodImpl::GetMethodDesc(DWORD slotIndex, PTR_MethodDesc defaultReturn)
{
    CONTRACTL
    {
        if (FORBIDGC_LOADER_USE_ENABLED()) NOTHROW; else THROWS;
        if (FORBIDGC_LOADER_USE_ENABLED()) GC_NOTRIGGER; else GC_TRIGGERS;
        if (FORBIDGC_LOADER_USE_ENABLED()) FORBID_FAULT; else { INJECT_FAULT(COMPlusThrowOM()); }
        MODE_ANY;
    }
    CONTRACTL_END

    DPTR(RelativePointer<PTR_MethodDesc>) pRelPtrForSlot = GetImpMDsNonNull();
    // The method descs are not offset by one
    TADDR base = dac_cast<TADDR>(pRelPtrForSlot) + slotIndex * sizeof(RelativePointer<MethodDesc *>);
    PTR_MethodDesc result = RelativePointer<PTR_MethodDesc>::GetValueMaybeNullAtPtr(base);

    // Prejitted images may leave NULL in this table if
    // the methoddesc is declared in another module.
    // In this case we need to manually compute & restore it
    // from the slot number.

    if (result == NULL)
#ifndef DACCESS_COMPILE 
        result = RestoreSlot(slotIndex, defaultReturn->GetMethodTable());
#else // DACCESS_COMPILE
        DacNotImpl();
#endif // DACCESS_COMPILE

    return result;
}

#ifndef DACCESS_COMPILE 

MethodDesc *MethodImpl::RestoreSlot(DWORD index, MethodTable *pMT)
{
    CONTRACTL
    {
        NOTHROW;
        GC_NOTRIGGER;
        FORBID_FAULT;
        PRECONDITION(!pdwSlots.IsNull());
    }
    CONTRACTL_END

    MethodDesc *result;

    PREFIX_ASSUME(!pdwSlots.IsNull());
    DWORD slot = GetSlots()[index];

    // Since the overridden method is in a different module, we
    // are guaranteed that it is from a different class.  It is
    // either an override of a parent virtual method or parent-implemented
    // interface, or of an interface that this class has introduced.

    // In the former 2 cases, the slot number will be in the parent's
    // vtable section, and we can retrieve the implemented MethodDesc from
    // there.  In the latter case, we can search through our interface
    // map to determine which interface it is from.

    MethodTable *pParentMT = pMT->GetParentMethodTable();
    CONSISTENCY_CHECK(pParentMT != NULL && slot < pParentMT->GetNumVirtuals());
    {
        result = pParentMT->GetMethodDescForSlot(slot);
    }

    _ASSERTE(result != NULL);

    // Don't worry about races since we would all be setting the same result
    if (EnsureWritableExecutablePagesNoThrow(&pImplementedMD.GetValue()[index],
                                             sizeof(pImplementedMD.GetValue()[index])))
        pImplementedMD.GetValue()[index].SetValue(result);

    return result;
}

///////////////////////////////////////////////////////////////////////////////////////
void MethodImpl::SetSize(LoaderHeap *pHeap, AllocMemTracker *pamTracker, DWORD size)
{
    CONTRACTL {
        THROWS;
        GC_NOTRIGGER;
        PRECONDITION(CheckPointer(this));
        PRECONDITION(pdwSlots.GetValueMaybeNull()==NULL && pImplementedMD.GetValueMaybeNull()==NULL);
        INJECT_FAULT(ThrowOutOfMemory());
    } CONTRACTL_END;

    if(size > 0) {
        // An array of DWORDs, the first entry representing count, and the rest representing slot numbers
        S_SIZE_T cbCountAndSlots = S_SIZE_T(sizeof(DWORD)) +        // DWORD for the total count of slots
                                    S_SIZE_T(size) * S_SIZE_T(sizeof(DWORD)) + // DWORD each for the slot numbers
                                    S_SIZE_T(size) * S_SIZE_T(sizeof(mdToken)); // Token each for the method tokens

        // MethodDesc* for each of the implemented methods
        S_SIZE_T cbMethodDescs = S_SIZE_T(size) * S_SIZE_T(sizeof(RelativePointer<MethodDesc *>));

        // Need to align-up the slot entries so that the MethodDesc* array starts on a pointer boundary.
        cbCountAndSlots.AlignUp(sizeof(MethodDesc*));
        S_SIZE_T cbTotal =  cbCountAndSlots + cbMethodDescs;
        if(cbCountAndSlots.IsOverflow())
            ThrowOutOfMemory();

        // Allocate the memory.
        LPBYTE pAllocData = (BYTE*)pamTracker->Track(pHeap->AllocMem(cbTotal));

        // Set the count and slot array
        pdwSlots.SetValue((DWORD*)pAllocData);

        // Set the MethodDesc* array. Make sure to adjust for alignment.
        pImplementedMD.SetValue((RelativePointer<MethodDesc*> *)ALIGN_UP(pAllocData + cbCountAndSlots.Value(), sizeof(RelativePointer <MethodDesc*>)));

        // Store the count in the first entry
        *pdwSlots.GetValue() = size;
    }
}

///////////////////////////////////////////////////////////////////////////////////////
void MethodImpl::SetData(DWORD* slots, mdToken* tokens, RelativePointer<MethodDesc*>* md)
{
    CONTRACTL {
        NOTHROW;
        GC_NOTRIGGER;
        PRECONDITION(CheckPointer(this));
        PRECONDITION(!pdwSlots.IsNull());
    } CONTRACTL_END;

    DWORD *pdwSize = pdwSlots.GetValue();
    DWORD dwSize = *pdwSize;
    memcpy(&(pdwSize[1]), slots, dwSize*sizeof(DWORD));
    
    // Copy tokens that correspond to the slots above
    memcpy(&(pdwSize[1 + dwSize]), tokens, dwSize*sizeof(mdToken));

    RelativePointer<MethodDesc *> *pImplMD = pImplementedMD.GetValue();

    for (uint32_t i = 0; i < dwSize; ++i)
    {
        pImplMD[i].SetValue(md[i].GetValue());
    }
}

#ifdef FEATURE_NATIVE_IMAGE_GENERATION
void MethodImpl::Save(DataImage *image)
{
    STANDARD_VM_CONTRACT;

    DWORD size = GetSize();
    _ASSERTE(size > 0);

    image->StoreStructure(pdwSlots.GetValue(), (size+1)*sizeof(DWORD)+size*sizeof(mdToken),
                                    DataImage::ITEM_METHOD_DESC_COLD,
                                    sizeof(DWORD));
    image->StoreStructure(pImplementedMD.GetValue(), size*sizeof(RelativePointer<MethodDesc*>),
                                    DataImage::ITEM_METHOD_DESC_COLD,
                                    sizeof(MethodDesc*));
}

void MethodImpl::Fixup(DataImage *image, PVOID p, SSIZE_T offset)
{
    STANDARD_VM_CONTRACT;

    DWORD size = GetSize();
    _ASSERTE(size > 0);

    for (DWORD iMD = 0; iMD < size; iMD++)
    {
        // <TODO> Why not use FixupMethodDescPointer? </TODO>
        // <TODO> Does it matter if the MethodDesc needs a restore? </TODO>              

        RelativePointer<MethodDesc *> *pRelPtr = pImplementedMD.GetValue();
        MethodDesc * pMD = pRelPtr[iMD].GetValueMaybeNull();

        if (image->CanEagerBindToMethodDesc(pMD) &&
            image->CanHardBindToZapModule(pMD->GetLoaderModule()))
        {
            image->FixupRelativePointerField(pImplementedMD.GetValue(), iMD * sizeof(RelativePointer<MethodDesc *>));
        }
        else
        {
            image->ZeroPointerField(pImplementedMD.GetValue(), iMD * sizeof(RelativePointer<MethodDesc *>));
        }
    }

    image->FixupRelativePointerField(p, offset + offsetof(MethodImpl, pdwSlots));
    image->FixupRelativePointerField(p, offset + offsetof(MethodImpl, pImplementedMD));
}

#endif // FEATURE_NATIVE_IMAGE_GENERATION

#endif //!DACCESS_COMPILE

#ifdef DACCESS_COMPILE 

void
MethodImpl::EnumMemoryRegions(CLRDataEnumMemoryFlags flags)
{
    SUPPORTS_DAC;
#ifndef STUB_DISPATCH_ALL 
    CONSISTENCY_CHECK_MSG(FALSE, "Stub Dispatch forbidden code");
#else // STUB_DISPATCH_ALL
    // 'this' memory should already be enumerated as
    // part of the base MethodDesc.

    if (GetSlotsRaw().IsValid() && GetSize())
    {
        ULONG32 numSlots = GetSize();
        DacEnumMemoryRegion(dac_cast<TADDR>(GetSlotsRawNonNull()),
                            (numSlots + 1) * sizeof(DWORD) + numSlots * sizeof(mdToken));

        if (GetImpMDs().IsValid())
        {
            DacEnumMemoryRegion(dac_cast<TADDR>(GetImpMDsNonNull()),
                                numSlots * sizeof(RelativePointer<MethodDesc *>));
            for (DWORD i = 0; i < numSlots; i++)
            {
                DPTR(RelativePointer<PTR_MethodDesc>) pRelPtr = GetImpMDsNonNull();
                PTR_MethodDesc methodDesc = pRelPtr[i].GetValueMaybeNull();
                if (methodDesc.IsValid())
                {
                    methodDesc->EnumMemoryRegions(flags);
                }
            }
        }
    }
#endif // STUB_DISPATCH_ALL
}

#endif //DACCESS_COMPILE

#ifndef DACCESS_COMPILE 
MethodImpl::Iterator::Iterator(MethodDesc *pMD) : m_pMD(pMD), m_pImpl(NULL), m_iCur(0)
{
    LIMITED_METHOD_CONTRACT;
    if (pMD->IsMethodImpl())
    {
        m_pImpl = pMD->GetMethodImpl();
    }
}
#endif //!DACCESS_COMPILE