summaryrefslogtreecommitdiff
path: root/src/vm/commethodrental.cpp
blob: 8276849e5cc1b6bedfaed35d0a707aa472fc0051 (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
//
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//
////////////////////////////////////////////////////////////////////////////////



#include "common.h"
#include "commethodrental.h"
#include "corerror.h"

#ifdef FEATURE_METHOD_RENTAL
// SwapMethodBody
// This method will take the rgMethod as the new function body for a given method. 
//

void QCALLTYPE COMMethodRental::SwapMethodBody(EnregisteredTypeHandle cls, INT32 tkMethod, LPVOID rgMethod, INT32 iSize, INT32 flags, QCall::StackCrawlMarkHandle stackMark)
{
    QCALL_CONTRACT;
    
    BEGIN_QCALL;

    BYTE        *pNewCode       = NULL;
    MethodDesc  *pMethodDesc;
    ReflectionModule *module;
    ICeeGen*    pGen;
    ULONG       methodRVA;
    HRESULT     hr;

    if ( cls == NULL)
    {
        COMPlusThrowArgumentNull(W("cls"));
    }

    MethodTable *pMethodTable = TypeHandle::FromPtr(cls).GetMethodTable();
    PREFIX_ASSUME(pMethodTable != NULL);
    module = (ReflectionModule *) pMethodTable->GetModule();
    pGen = module->GetCeeGen();

    Assembly* caller = SystemDomain::GetCallersAssembly( stackMark );

    _ASSERTE( caller != NULL && "Unable to get calling assembly" );
    _ASSERTE( module->GetCreatingAssembly() != NULL && "ReflectionModule must have a creating assembly to be used with method rental" );

    if (module->GetCreatingAssembly() != caller)
    {
        COMPlusThrow(kSecurityException);
    }

    // Find the methoddesc given the method token
    pMethodDesc = MemberLoader::FindMethod(pMethodTable, tkMethod);
    if (pMethodDesc == NULL)
    {
        COMPlusThrowArgumentException(W("methodtoken"), NULL);
    }
    if (pMethodDesc->GetMethodTable() != pMethodTable || pMethodDesc->GetNumGenericClassArgs() != 0 || pMethodDesc->GetNumGenericMethodArgs() != 0)
    {
        COMPlusThrowArgumentException(W("methodtoken"), W("Argument_TypeDoesNotContainMethod"));
    }
    hr = pGen->AllocateMethodBuffer(iSize, &pNewCode, &methodRVA);    
    if (FAILED(hr))
        COMPlusThrowHR(hr);

    if (pNewCode == NULL)
    {
        COMPlusThrowOM();
    }

    // <TODO>
    // if method desc is pointing to the post-jitted native code block,
    // we want to recycle this code block

    // @todo: SEH handling. Will we need to support a method that can throw exception
    // If not, add an assertion to make sure that there is no SEH contains in the method header.

    // @todo: figure out a way not to copy the code block.

    // @todo: add link time security check. This function can be executed only if fully trusted.</TODO>

    // copy the new function body to the buffer
    memcpy(pNewCode, (void *) rgMethod, iSize);

    // add the starting address of the il blob to the il blob hash table
    // we need to find this information from out of process for debugger inspection
    // APIs so we have to store this information where we can get it later
    module->SetDynamicIL(mdToken(tkMethod), TADDR(pNewCode), FALSE);

    // Reset the methoddesc back to unjited state
    pMethodDesc->Reset();

    if (flags)
    {
        // JITImmediate
#if _DEBUG
        COR_ILMETHOD* ilHeader = pMethodDesc->GetILHeader(TRUE);
        _ASSERTE(((BYTE *)ilHeader) == pNewCode);
#endif
        COR_ILMETHOD_DECODER header((COR_ILMETHOD *)pNewCode, pMethodDesc->GetMDImport(), NULL); 

        // minimum validation on the correctness of method header
        if (header.GetCode() == NULL)
            COMPlusThrowHR(VLDTR_E_MD_BADHEADER);

#ifdef FEATURE_INTERPRETER
        pMethodDesc->MakeJitWorker(&header, CORJIT_FLG_MAKEFINALCODE, 0);
#else // !FEATURE_INTERPRETER
        pMethodDesc->MakeJitWorker(&header, 0, 0);
#endif // !FEATURE_INTERPRETER
    }

    // add feature::
    // If SQL is generating class with inheritance hierarchy, we may need to
    // check the whole vtable to find duplicate entries.

    END_QCALL;

}   // COMMethodRental::SwapMethodBody


#endif // FEATURE_METHOD_RENTAL