Fix edgecases around expanded calls to bound callables when no stack space is available
This commit is contained in:
parent
3bc8d72895
commit
55849aa4f0
23
src/vm.c
23
src/vm.c
@ -799,6 +799,17 @@ inline KrkValue krk_callNativeOnStack(size_t argCount, const KrkValue *stackArgs
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sometimes we might call something with a bound receiver, which in most circumstances
|
||||||
|
* can replace the called object on the stack, but sometimes we don't _have_ the called
|
||||||
|
* object on the stack - only its arguments. If that is the case, we unfortunately need
|
||||||
|
* to rotate the stack so we can inject the implicit bound argument at the front.
|
||||||
|
*/
|
||||||
|
static void _rotate(size_t argCount) {
|
||||||
|
krk_push(NONE_VAL());
|
||||||
|
memmove(&krk_currentThread.stackTop[-argCount],&krk_currentThread.stackTop[-argCount-1],sizeof(KrkValue) * argCount);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Call a callable.
|
* Call a callable.
|
||||||
*
|
*
|
||||||
@ -857,6 +868,8 @@ int krk_callValue(KrkValue callee, int argCount, int returnDepth) {
|
|||||||
case KRK_OBJ_INSTANCE: {
|
case KRK_OBJ_INSTANCE: {
|
||||||
KrkClass * _class = AS_INSTANCE(callee)->_class;
|
KrkClass * _class = AS_INSTANCE(callee)->_class;
|
||||||
if (likely(_class->_call != NULL)) {
|
if (likely(_class->_call != NULL)) {
|
||||||
|
if (unlikely(returnDepth == 0)) _rotate(argCount);
|
||||||
|
krk_currentThread.stackTop[-argCount - 1] = callee;
|
||||||
callee = OBJECT_VAL(_class->_call);
|
callee = OBJECT_VAL(_class->_call);
|
||||||
argCount++;
|
argCount++;
|
||||||
returnDepth = returnDepth ? (returnDepth - 1) : 0;
|
returnDepth = returnDepth ? (returnDepth - 1) : 0;
|
||||||
@ -869,8 +882,9 @@ int krk_callValue(KrkValue callee, int argCount, int returnDepth) {
|
|||||||
case KRK_OBJ_CLASS: {
|
case KRK_OBJ_CLASS: {
|
||||||
KrkClass * _class = AS_CLASS(callee);
|
KrkClass * _class = AS_CLASS(callee);
|
||||||
KrkInstance * newInstance = krk_newInstance(_class);
|
KrkInstance * newInstance = krk_newInstance(_class);
|
||||||
krk_currentThread.stackTop[-argCount - 1] = OBJECT_VAL(newInstance);
|
|
||||||
if (likely(_class->_init != NULL)) {
|
if (likely(_class->_init != NULL)) {
|
||||||
|
if (unlikely(returnDepth == 0)) _rotate(argCount);
|
||||||
|
krk_currentThread.stackTop[-argCount - 1] = OBJECT_VAL(newInstance);
|
||||||
callee = OBJECT_VAL(_class->_init);
|
callee = OBJECT_VAL(_class->_init);
|
||||||
argCount++;
|
argCount++;
|
||||||
returnDepth = returnDepth ? (returnDepth - 1) : 0;
|
returnDepth = returnDepth ? (returnDepth - 1) : 0;
|
||||||
@ -880,15 +894,18 @@ int krk_callValue(KrkValue callee, int argCount, int returnDepth) {
|
|||||||
_class->name->chars, argCount);
|
_class->name->chars, argCount);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
return 1;
|
krk_currentThread.stackTop -= argCount + returnDepth;
|
||||||
|
krk_push(OBJECT_VAL(newInstance));
|
||||||
|
return 2;
|
||||||
}
|
}
|
||||||
case KRK_OBJ_BOUND_METHOD: {
|
case KRK_OBJ_BOUND_METHOD: {
|
||||||
KrkBoundMethod * bound = AS_BOUND_METHOD(callee);
|
KrkBoundMethod * bound = AS_BOUND_METHOD(callee);
|
||||||
krk_currentThread.stackTop[-argCount - 1] = bound->receiver;
|
|
||||||
if (unlikely(!bound->method)) {
|
if (unlikely(!bound->method)) {
|
||||||
krk_runtimeError(vm.exceptions->argumentError, "???");
|
krk_runtimeError(vm.exceptions->argumentError, "???");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
if (unlikely(returnDepth == 0)) _rotate(argCount);
|
||||||
|
krk_currentThread.stackTop[-argCount - 1] = bound->receiver;
|
||||||
callee = OBJECT_VAL(bound->method);
|
callee = OBJECT_VAL(bound->method);
|
||||||
argCount++;
|
argCount++;
|
||||||
returnDepth = returnDepth ? (returnDepth - 1) : 0;
|
returnDepth = returnDepth ? (returnDepth - 1) : 0;
|
||||||
|
Loading…
Reference in New Issue
Block a user