14
14
#ifdef TARGET_WASM
15
15
void InvokeCalliStub (PCODE ftn, CallStubHeader *stubHeaderTemplate, int8_t *pArgs, int8_t *pRet);
16
16
void InvokeCompiledMethod (MethodDesc *pMD, int8_t *pArgs, int8_t *pRet, PCODE target);
17
+ void InvokeDelegateInvokeMethod (MethodDesc *pMDDelegateInvoke, int8_t *pArgs, int8_t *pRet, PCODE target);
17
18
#else
18
19
#include " callstubgenerator.h"
19
20
21
+ CallStubHeader *UpdateCallStubForMethod (MethodDesc *pMD)
22
+ {
23
+ CONTRACTL
24
+ {
25
+ THROWS;
26
+ MODE_ANY;
27
+ PRECONDITION (CheckPointer (pMD));
28
+ }
29
+ CONTRACTL_END
30
+
31
+ GCX_PREEMP ();
32
+
33
+ CallStubGenerator callStubGenerator;
34
+
35
+ AllocMemTracker amTracker;
36
+ CallStubHeader *header = callStubGenerator.GenerateCallStub (pMD, &amTracker, true /* interpreterToNative */ );
37
+
38
+ if (pMD->SetCallStub (header))
39
+ {
40
+ amTracker.SuppressRelease ();
41
+ }
42
+ else
43
+ {
44
+ // We have lost the race for generating the header, use the one that was generated by another thread
45
+ // and let the amTracker release the memory of the one we generated.
46
+ header = pMD->GetCallStub ();
47
+ }
48
+
49
+ return header;
50
+ }
51
+
20
52
void InvokeCompiledMethod (MethodDesc *pMD, int8_t *pArgs, int8_t *pRet, PCODE target)
21
53
{
22
54
CONTRACTL
@@ -32,22 +64,7 @@ void InvokeCompiledMethod(MethodDesc *pMD, int8_t *pArgs, int8_t *pRet, PCODE ta
32
64
CallStubHeader *pHeader = pMD->GetCallStub ();
33
65
if (pHeader == NULL )
34
66
{
35
- CallStubGenerator callStubGenerator;
36
- GCX_PREEMP ();
37
-
38
- AllocMemTracker amTracker;
39
- pHeader = callStubGenerator.GenerateCallStub (pMD, &amTracker, true /* interpreterToNative */ );
40
-
41
- if (pMD->SetCallStub (pHeader))
42
- {
43
- amTracker.SuppressRelease ();
44
- }
45
- else
46
- {
47
- // We have lost the race for generating the header, use the one that was generated by another thread
48
- // and let the amTracker release the memory of the one we generated.
49
- pHeader = pMD->GetCallStub ();
50
- }
67
+ pHeader = UpdateCallStubForMethod (pMD);
51
68
}
52
69
53
70
// Interpreter-FIXME: Potential race condition if a single CallStubHeader is reused for multiple targets.
@@ -56,6 +73,34 @@ void InvokeCompiledMethod(MethodDesc *pMD, int8_t *pArgs, int8_t *pRet, PCODE ta
56
73
pHeader->Invoke (pHeader->Routines , pArgs, pRet, pHeader->TotalStackSize );
57
74
}
58
75
76
+ void InvokeDelegateInvokeMethod (MethodDesc *pMDDelegateInvoke, int8_t *pArgs, int8_t *pRet, PCODE target)
77
+ {
78
+ CONTRACTL
79
+ {
80
+ THROWS;
81
+ MODE_ANY;
82
+ PRECONDITION (CheckPointer (pMDDelegateInvoke));
83
+ PRECONDITION (CheckPointer (pArgs));
84
+ PRECONDITION (CheckPointer (pRet));
85
+ }
86
+ CONTRACTL_END
87
+
88
+ CallStubHeader *stubHeaderTemplate = pMDDelegateInvoke->GetCallStub ();
89
+ if (stubHeaderTemplate == NULL )
90
+ {
91
+ stubHeaderTemplate = UpdateCallStubForMethod (pMDDelegateInvoke);
92
+ }
93
+
94
+ // CallStubHeaders encode their destination addresses in the Routines array, so they need to be
95
+ // copied to a local buffer before we can actually set their target address.
96
+ size_t templateSize = stubHeaderTemplate->GetSize ();
97
+ uint8_t * actualCallStub = (uint8_t *)alloca (templateSize);
98
+ memcpy (actualCallStub, stubHeaderTemplate, templateSize);
99
+ CallStubHeader *pHeader = (CallStubHeader*)actualCallStub;
100
+ pHeader->SetTarget (target); // The method to call
101
+ pHeader->Invoke (pHeader->Routines , pArgs, pRet, pHeader->TotalStackSize );
102
+ }
103
+
59
104
void InvokeCalliStub (PCODE ftn, CallStubHeader *stubHeaderTemplate, int8_t *pArgs, int8_t *pRet)
60
105
{
61
106
CONTRACTL
@@ -84,7 +129,6 @@ CallStubHeader *CreateNativeToInterpreterCallStub(InterpMethod* pInterpMethod)
84
129
CallStubHeader *pHeader = VolatileLoadWithoutBarrier (&pInterpMethod->pCallStub );
85
130
GCX_PREEMP ();
86
131
87
- AllocMemTracker amTracker;
88
132
if (pHeader == NULL )
89
133
{
90
134
// Ensure that there is an interpreter thread context instance and thus an interpreter stack
@@ -1881,6 +1925,30 @@ void InterpExecMethod(InterpreterFrame *pInterpreterFrame, InterpMethodContextFr
1881
1925
break ;
1882
1926
}
1883
1927
1928
+ case INTOP_CALLDELEGATE:
1929
+ {
1930
+ returnOffset = ip[1 ];
1931
+ callArgsOffset = ip[2 ];
1932
+ methodSlot = ip[3 ];
1933
+
1934
+ // targetMethod holds a pointer to the Invoke method of the delegate, not the final actual target.
1935
+ targetMethod = (MethodDesc*)pMethod->pDataItems [methodSlot];
1936
+
1937
+ ip += 4 ;
1938
+
1939
+ DELEGATEREF delegateObj = LOCAL_VAR (callArgsOffset, DELEGATEREF);
1940
+ NULL_CHECK (delegateObj);
1941
+ PCODE targetAddress = delegateObj->GetMethodPtr ();
1942
+ OBJECTREF targetMethodObj = delegateObj->GetTarget ();
1943
+ LOCAL_VAR (callArgsOffset, OBJECTREF) = targetMethodObj;
1944
+
1945
+ // TODO! Once we are investigating performance here, we may want to optimize this so that
1946
+ // delegate calls to interpeted methods don't have to go through the native invoke here, but for
1947
+ // now this should work well.
1948
+ InvokeDelegateInvokeMethod (targetMethod, stack + callArgsOffset, stack + returnOffset, targetAddress);
1949
+ break ;
1950
+ }
1951
+
1884
1952
case INTOP_CALL:
1885
1953
{
1886
1954
returnOffset = ip[1 ];
0 commit comments