-
Notifications
You must be signed in to change notification settings - Fork 5.1k
Add support for string constructors to the interpreter #115914
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||
---|---|---|---|---|
|
@@ -8,7 +8,7 @@ | |||
#include "interpexec.h" | ||||
#include "callstubgenerator.h" | ||||
|
||||
void InvokeCompiledMethod(MethodDesc *pMD, int8_t *pArgs, int8_t *pRet) | ||||
void InvokeCompiledMethod(MethodDesc *pMD, int8_t *pArgs, int8_t *pRet, PCODE pCode) | ||||
{ | ||||
CONTRACTL | ||||
{ | ||||
|
@@ -41,7 +41,7 @@ void InvokeCompiledMethod(MethodDesc *pMD, int8_t *pArgs, int8_t *pRet) | |||
} | ||||
} | ||||
|
||||
pHeader->SetTarget(pMD->GetNativeCode()); // The method to call | ||||
pHeader->SetTarget(pCode); // The method to call | ||||
|
||||
pHeader->Invoke(pHeader->Routines, pArgs, pRet, pHeader->TotalStackSize); | ||||
} | ||||
|
@@ -1151,7 +1151,7 @@ void InterpExecMethod(InterpreterFrame *pInterpreterFrame, InterpMethodContextFr | |||
else if (codeInfo.GetCodeManager() != ExecutionManager::GetInterpreterCodeManager()) | ||||
{ | ||||
MethodDesc *pMD = codeInfo.GetMethodDesc(); | ||||
InvokeCompiledMethod(pMD, stack + callArgsOffset, stack + returnOffset); | ||||
InvokeCompiledMethod(pMD, stack + callArgsOffset, stack + returnOffset, pMD->GetNativeCode()); | ||||
break; | ||||
} | ||||
|
||||
|
@@ -1213,6 +1213,28 @@ void InterpExecMethod(InterpreterFrame *pInterpreterFrame, InterpMethodContextFr | |||
ip += 5; | ||||
goto CALL_INTERP_SLOT; | ||||
} | ||||
case INTOP_NEWOBJ_VAROBJSIZE: | ||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What's the difference between this and In other words - if the JIT produced a regular There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Right now, nowhere, but mdarrays are going to use this opcode and have special behavior. I'm open to generating call for this and reserving the opcode only for mdarray. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
I think it would make more sense. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'll test generating CALL and see if anything breaks. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We can't use INTOP_CALL because the string ctors aren't IL, they're icalls:
Right now we can only call IL methods with INTOP_CALL because of how it implements invoking native code. I wanted to originally pierce through and find the managed method that implements the ctors and call that, but it sounded like there's not a way to do that from inside the JIT (and adding a new method to the JIT to do it would have been a pain anyway, and was opposed when I suggested it). The new opcode I added happens to be constructed in a way that works for icalls. And then the mdarrays PR will expand it to also handle the unique calling convention for mdarray ctors. IMO it makes sense to have a dedicated opcode for the two variable-size objects we have in the type system. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The interpreter will need a way to call icalls. I am actually surprised that we are not hitting problem with calling icalls in more places. What would it take to make icalls work in the interpreter instead of adding new special opcode?
I agree that mdarray ctors have unique calling convention and it makes sense to have a special opcode for those. I do not think the string ctors are special like that. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We would need to detect whether a method will successfully I think what I would do if I had to fix this now is only attempt calls through This complicates the existing call opcodes at execution time though because we don't have anywhere to store this flag. We would need to add an additional data item to store it, or add new opcode(s) for 'non-IL calls'. This is because we use a tag bit to put the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
We have a temporary hack for that https://github.com/dotnet/runtime/blob/main/src/coreclr/vm/interpexec.cpp#L1144-L1150 . You can update the hack to invoke the native code instead of There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
There is a discussion about how this should work in one of the Teams chats. @janvorli started a design doc to describe how this should work. |
||||
{ | ||||
returnOffset = ip[1]; | ||||
callArgsOffset = ip[2]; | ||||
methodSlot = ip[3]; | ||||
|
||||
size_t targetMethod = (size_t)pMethod->pDataItems[methodSlot]; | ||||
assert(targetMethod & INTERP_METHOD_HANDLE_TAG); | ||||
MethodDesc *pMD = (MethodDesc*)(targetMethod & ~INTERP_METHOD_HANDLE_TAG); | ||||
|
||||
// If we are constructing a type with a component size (i.e. a string) its constructor is a special | ||||
// fcall that is basically a static method that returns the new instance. | ||||
// Get the address of the fcall that implements the ctor | ||||
PCODE code = pMD->TryGetMultiCallableAddrOfCode(CORINFO_ACCESS_ANY); | ||||
assert(code); | ||||
|
||||
// callArgsOffset points to the ctor arguments, which are what the fcall expects. | ||||
// returnOffset points to where the new instance goes, and the fcall will write it there. | ||||
InvokeCompiledMethod(pMD, stack + callArgsOffset, stack + returnOffset, code); | ||||
ip += 5; | ||||
break; | ||||
} | ||||
case INTOP_ZEROBLK_IMM: | ||||
memset(LOCAL_VAR(ip[1], void*), 0, ip[2]); | ||||
ip += 3; | ||||
|
Uh oh!
There was an error while loading. Please reload this page.