Drop krk_callSimple

Replace it with two functions that won't run into issues with
trying to call bound objects, instances, etc. that weren't on
the stack. In general, if you have a callable value of unknown
type you should call `krk_callStack` with it on the stack followed
by all of its args; to make this abundantly clear, `krk_callStack`
only takes the argument count. For calling things we know to be
safe (closures and natives), there is `krk_callDirect`, which should
be used, for example, when calling core methods like __repr__.
This commit is contained in:
K. Lange 2021-04-17 19:29:52 +09:00
parent bc27feca69
commit 444cb28d06
23 changed files with 161 additions and 135 deletions

View File

@ -91,7 +91,7 @@ KRK_FUNC(len,{
if (!type->_len) return krk_runtimeError(vm.exceptions->typeError, "object of type '%s' has no len()", krk_typeName(argv[0]));
krk_push(argv[0]);
return krk_callSimple(OBJECT_VAL(type->_len), 1, 0);
return krk_callDirect(type->_len, 1);
})
KRK_FUNC(dir,{
@ -101,7 +101,7 @@ KRK_FUNC(dir,{
return krk_dirObject(argc,argv,hasKw); /* Fallback */
}
krk_push(argv[0]);
return krk_callSimple(OBJECT_VAL(type->_dir), 1, 0);
return krk_callDirect(type->_dir, 1);
})
KRK_FUNC(repr,{
@ -109,7 +109,7 @@ KRK_FUNC(repr,{
/* Everything should have a __repr__ */
KrkClass * type = krk_getType(argv[0]);
krk_push(argv[0]);
return krk_callSimple(OBJECT_VAL(type->_reprer), 1, 0);
return krk_callDirect(type->_reprer, 1);
})
KRK_FUNC(ord,{
@ -117,8 +117,9 @@ KRK_FUNC(ord,{
KrkClass * type = krk_getType(argv[0]);
KrkValue method;
if (krk_tableGet(&type->methods, vm.specialMethodNames[METHOD_ORD], &method)) {
krk_push(method);
krk_push(argv[0]);
return krk_callSimple(method, 1, 0);
return krk_callStack(1);
}
return TYPE_ERROR(string of length 1,argv[0]);
})
@ -128,8 +129,9 @@ KRK_FUNC(chr,{
KrkClass * type = krk_getType(argv[0]);
KrkValue method;
if (krk_tableGet(&type->methods, vm.specialMethodNames[METHOD_CHR], &method)) {
krk_push(method);
krk_push(argv[0]);
return krk_callSimple(method, 1, 0);
return krk_callStack(1);
}
return TYPE_ERROR(int,argv[0]);
})
@ -229,7 +231,7 @@ KRK_METHOD(map,__init__,{
return krk_runtimeError(vm.exceptions->typeError, "'%s' object is not iterable", krk_typeName(argv[i]));
}
krk_push(argv[i]);
KrkValue asIter = krk_callSimple(OBJECT_VAL(type->_iter), 1, 0);
KrkValue asIter = krk_callDirect(type->_iter, 1);
if (krk_currentThread.flags & KRK_THREAD_HAS_EXCEPTION) return NONE_VAL();
/* Attach it to the tuple */
iters->values.values[iters->values.count++] = asIter;
@ -261,7 +263,7 @@ KRK_METHOD(map,__call__,{
for (size_t i = 0; i < AS_TUPLE(iterators)->values.count; ++i) {
/* Obtain the next value and push it */
krk_push(AS_TUPLE(iterators)->values.values[i]);
krk_push(krk_callSimple(AS_TUPLE(iterators)->values.values[i], 0, 0));
krk_push(krk_callStack(0));
if (krk_currentThread.flags & KRK_THREAD_HAS_EXCEPTION) return NONE_VAL();
/* End iteration whenever one runs out */
if (krk_valuesEqual(krk_peek(0), AS_TUPLE(iterators)->values.values[i])) {
@ -272,7 +274,7 @@ KRK_METHOD(map,__call__,{
}
/* Call the function */
KrkValue val = krk_callSimple(function, AS_TUPLE(iterators)->values.count, 0);
KrkValue val = krk_callStack(AS_TUPLE(iterators)->values.count);
krk_currentThread.stackTop = krk_currentThread.stack + stackOffset;
return val;
})
@ -285,12 +287,13 @@ KRK_FUNC(zip,{
krk_tableGet(&vm.builtins->fields, OBJECT_VAL(S("map")), &map);
krk_tableGet(&vm.builtins->fields, OBJECT_VAL(S("tupleOf")), &tupleOfFunc);
krk_push(map);
krk_push(tupleOfFunc);
for (int i = 0; i < argc; ++i) {
krk_push(argv[i]);
}
return krk_callSimple(map, argc+1, 0);
return krk_callStack(argc+1);
})
#define IS_filter(o) (krk_isInstanceOf(o,filter))
@ -304,7 +307,7 @@ KRK_METHOD(filter,__init__,{
return krk_runtimeError(vm.exceptions->typeError, "'%s' object is not iterable", krk_typeName(argv[2]));
}
krk_push(argv[2]);
KrkValue asIter = krk_callSimple(OBJECT_VAL(type->_iter), 1, 0);
KrkValue asIter = krk_callDirect(type->_iter, 1);
if (krk_currentThread.flags & KRK_THREAD_HAS_EXCEPTION) return NONE_VAL();
krk_attachNamedValue(&self->fields, "_iterator", asIter);
return argv[0];
@ -326,7 +329,7 @@ KRK_METHOD(filter,__call__,{
while (1) {
krk_push(iterator);
krk_push(krk_callSimple(iterator, 0, 0));
krk_push(krk_callStack(0));
if (krk_currentThread.flags & KRK_THREAD_HAS_EXCEPTION) return NONE_VAL();
if (krk_valuesEqual(iterator, krk_peek(0))) {
@ -340,8 +343,9 @@ KRK_METHOD(filter,__call__,{
continue;
}
} else {
krk_push(krk_peek(0));
KrkValue result = krk_callSimple(function, 1, 0);
krk_push(function);
krk_push(krk_peek(1));
KrkValue result = krk_callStack(1);
if (krk_isFalsey(result)) {
krk_pop(); /* iterator result */
continue;
@ -370,7 +374,7 @@ KRK_METHOD(enumerate,__init__,{
return krk_runtimeError(vm.exceptions->typeError, "'%s' object is not iterable", krk_typeName(argv[1]));
}
krk_push(argv[1]);
KrkValue asIter = krk_callSimple(OBJECT_VAL(type->_iter), 1, 0);
KrkValue asIter = krk_callDirect(type->_iter, 1);
if (krk_currentThread.flags & KRK_THREAD_HAS_EXCEPTION) return NONE_VAL();
krk_attachNamedValue(&self->fields, "_iterator", asIter);
@ -396,7 +400,7 @@ KRK_METHOD(enumerate,__call__,{
krk_push(OBJECT_VAL(tupleOut));
krk_push(iterator);
krk_push(krk_callSimple(iterator, 0, 0));
krk_push(krk_callStack(0));
if (krk_currentThread.flags & KRK_THREAD_HAS_EXCEPTION) {
krk_currentThread.stackTop = krk_currentThread.stack + stackOffset;
@ -780,13 +784,14 @@ KRK_METHOD(Helper,__call__,{
if (argc == 2) {
krk_tableGet(&AS_INSTANCE(helpModule)->fields, OBJECT_VAL(S("simple")), &callable);
krk_push(argv[1]);
} else {
krk_tableGet(&AS_INSTANCE(helpModule)->fields, OBJECT_VAL(S("interactive")), &callable);
}
if (!IS_NONE(callable)) {
return krk_callSimple(callable, argc == 2, 0);
krk_push(callable);
if (argc == 2) krk_push(argv[1]);
return krk_callStack(argc == 2);
}
return krk_runtimeError(vm.exceptions->typeError, "unexpected error");
@ -856,23 +861,29 @@ KRK_METHOD(property,__get__,{
if (!krk_tableGet(&self->fields, OBJECT_VAL(S("fget")), &fget))
return krk_runtimeError(vm.exceptions->attributeError, "'%s' object has no attribute '%s'", "property", "fget");
krk_push(fget);
krk_push(argv[1]);
return krk_callSimple(fget, 1, 0);
return krk_callStack(1);
})
KRK_METHOD(property,__set__,{
METHOD_TAKES_EXACTLY(2); /* the owner and the value */
krk_push(argv[1]);
krk_push(argv[2]);
KrkValue fset;
if (krk_tableGet(&self->fields, OBJECT_VAL(S("fset")), &fset))
return krk_callSimple(fset, 2, 0);
if (krk_tableGet(&self->fields, OBJECT_VAL(S("fset")), &fset)) {
krk_push(fset);
krk_push(argv[1]);
krk_push(argv[2]);
return krk_callStack(2);
}
KrkValue fget;
if (krk_tableGet(&self->fields, OBJECT_VAL(S("fget")), &fget))
return krk_callSimple(fget, 2, 0);
if (krk_tableGet(&self->fields, OBJECT_VAL(S("fget")), &fget)) {
krk_push(fget);
krk_push(argv[1]);
krk_push(argv[2]);
return krk_callStack(2);
}
return krk_runtimeError(vm.exceptions->attributeError, "attribute can not be set");
})
@ -893,8 +904,7 @@ KRK_FUNC(hash,{
KRK_FUNC(next,{
FUNCTION_TAKES_EXACTLY(1);
krk_push(argv[0]);
krk_push(krk_callSimple(argv[0], 0, 0));
return krk_pop();
return krk_callStack(0);
})
#ifndef STATIC_ONLY

View File

@ -50,7 +50,7 @@ static KrkValue _exception_repr(int argc, KrkValue argv[], int hasKw) {
if (krk_tableGet(&self->fields, OBJECT_VAL(S("arg")), &arg)) {
/* repr it */
krk_push(arg);
KrkValue repred = krk_callSimple(OBJECT_VAL(krk_getType(arg)->_reprer), 1, 0);
KrkValue repred = krk_callDirect(krk_getType(arg)->_reprer, 1);
pushStringBuilderStr(&sb, AS_CSTRING(repred), AS_STRING(repred)->length);
}
@ -74,7 +74,7 @@ static KrkValue _exception_str(int argc, KrkValue argv[], int hasKw) {
return NONE_VAL();
} else if (!IS_STRING(arg)) {
krk_push(arg);
return krk_callSimple(OBJECT_VAL(krk_getType(arg)->_tostr), 1, 0);
return krk_callDirect(krk_getType(arg)->_tostr, 1);
} else {
return arg;
}

View File

@ -457,11 +457,12 @@ static int debuggerHook(KrkCallFrame * frame) {
/* Turn our compiled expression into a callable. */
krk_push(OBJECT_VAL(expression));
krk_push(OBJECT_VAL(krk_newClosure(expression)));
krk_swap(1);
/* Stack silliness, don't ask. */
krk_push(NONE_VAL());
krk_pop();
/* Call the compiled expression with no args, but claim 2 method extras. */
krk_push(krk_callSimple(krk_peek(0), 0, 2));
/* Call the compiled expression with no args. */
krk_push(krk_callStack(0));
fprintf(stderr, "\033[1;30m=> ");
krk_printValue(stderr, krk_peek(0));
fprintf(stderr, "\033[0m\n");
@ -1120,10 +1121,10 @@ _finishArgs:
const char * formatStr = " \033[1;30m=> %s\033[0m\n";
if (type->_reprer) {
krk_push(result);
result = krk_callSimple(OBJECT_VAL(type->_reprer), 1, 0);
result = krk_callDirect(type->_reprer, 1);
} else if (type->_tostr) {
krk_push(result);
result = krk_callSimple(OBJECT_VAL(type->_tostr), 1, 0);
result = krk_callDirect(type->_tostr, 1);
}
if (!IS_STRING(result)) {
fprintf(stdout, " \033[1;31m=> Unable to produce representation for value.\033[0m\n");

View File

@ -495,7 +495,7 @@ extern KrkClass * krk_newClass(KrkString * name, KrkClass * base);
*
* Handles allocation, but not __init__, of the new instance.
* Be sure to populate any fields expected by the class or call
* its __init__ function (eg. with @ref krk_callSimple) as needed.
* its __init__ function (eg. with @ref krk_callStack) as needed.
*/
extern KrkInstance * krk_newInstance(KrkClass * _class);

View File

@ -234,10 +234,10 @@ extern KrkValue FUNC_NAME(str,format)(int,KrkValue*,int);
if (type->_iter) { \
size_t stackOffset = krk_currentThread.stackTop - krk_currentThread.stack; \
krk_push(fromInput); \
krk_push(krk_callSimple(OBJECT_VAL(type->_iter), 1, 0)); \
krk_push(krk_callDirect(type->_iter,1)); \
do { \
krk_push(krk_currentThread.stack[stackOffset]); \
krk_push(krk_callSimple(krk_peek(0), 0, 1)); \
krk_push(krk_callStack(0)); \
if (krk_valuesSame(krk_currentThread.stack[stackOffset], krk_peek(0))) { \
krk_pop(); \
krk_pop(); \

View File

@ -573,19 +573,16 @@ extern int krk_bindMethod(KrkClass * _class, KrkString * name);
*
* @param callee Value referencing a callable object.
* @param argCount Arguments to retreive from stack.
* @param extra Whether extra arguments below argCount should be
* considered as part of this call frame. Generally,
* when this is 1, the value below the arguments is
* the callable object. Most library users will want
* to leave this as 0 when calling normal functions,
* bound method objects, or ubound methods when the
* instance is included in the arguments already.
* @param callableOnStack Whether @p callee is on the stack below the arguments,
* which must be the case for bound methods, classes,
* and instances, as that space will be used for the implicit
* first argument passed to these kinds of callables.
* @return An indicator of how the result should be obtained:
* 1: The VM must be resumed to run managed code.
* 2: The callable was a native function and result should be popped now.
* Else: The call failed. An exception may have already been set.
*/
extern int krk_callValue(KrkValue callee, int argCount, int extra);
extern int krk_callValue(KrkValue callee, int argCount, int callableOnStack);
/**
* @brief Create a list object.
@ -620,20 +617,31 @@ extern KrkValue krk_tuple_of(int argc, KrkValue argv[], int hasKw);
extern KrkValue krk_set_of(int argc, KrkValue argv[], int hasKw);
/**
* @brief Call a callable and manage VM state to obtain the return value.
* @memberof KrkValue
* @brief Call a callable on the stack with @p argCount arguments.
*
* This is a wrapper around various mechanisms including krk_callValue
* intended for use by C extensions to call arbitrary functions without
* knowledge of their implementation details. See the notes for
* @c krk_callValue 's @c extra paramater for details on how @p isMethod is used.
* Calls the callable @p argCount stack entries down from the top
* of the stack, passing @p argCount arguments. Resumes execution
* of the VM for managed calls until they are completed. Pops
* @p argCount items from the stack and returns the result of
* the call.
*
* @param value Callable object reference.
* @param argCount Arguments to collect from the stack.
* @param isMethod This should almost always be 0.
* @return The return value of the function.
*/
extern KrkValue krk_callSimple(KrkValue value, int argCount, int isMethod);
extern KrkValue krk_callStack(int argCount);
/**
* @brief Call a closure or native function with @p argCount arguments.
*
* Calls the closure or native @p callable with arguments from the
* top of the stack. @p argCount arguments are popped from the stack
* and the return value of the call is returned.
*
* @param callable Closure or native function.
* @param argCount Arguments to collect from the stack.
* @return The return value of the function.
*/
extern KrkValue krk_callDirect(KrkObj * callable, int argCount);
/**
* @brief Convenience function for creating new types.

View File

@ -27,7 +27,7 @@
if (!krk_bindMethod(type, S("__float__"))) { \
krk_pop(); \
} else { \
arg = krk_callSimple(krk_peek(0), 0, 1); \
arg = krk_callStack(0); \
} \
} break; \
} }
@ -48,7 +48,7 @@ static KrkValue _math_ ## func(int argc, KrkValue argv[], int hasKw) { \
KrkClass * type = krk_getType(argv[0]); \
krk_push(argv[0]); \
if (!krk_bindMethod(type, S("__" #func "__"))) REAL_NUMBER_NOT(func,argv[0]) \
return krk_callSimple(krk_peek(0), 0, 1); \
return krk_callStack(0); \
} \
}

View File

@ -22,7 +22,8 @@ KRK_FUNC(timeit,{
struct timeval tv_before, tv_after;
gettimeofday(&tv_before,NULL);
for (krk_integer_type t = 0; t < times; ++t) {
krk_callSimple(argv[0],0,0);
krk_push(argv[0]);
krk_callStack(0);
}
gettimeofday(&tv_after,NULL);

View File

@ -7,7 +7,7 @@
#define KEY_ERROR(value) {\
KrkClass * type = krk_getType(value); \
krk_push(value); \
KrkValue asString = krk_callSimple(OBJECT_VAL(type->_reprer), 1, 0); \
KrkValue asString = krk_callDirect(type->_reprer, 1); \
if (IS_STRING(asString)) return krk_runtimeError(vm.exceptions->keyError, "%s", AS_CSTRING(asString)); \
return krk_runtimeError(vm.exceptions->keyError, "key error"); }
@ -110,7 +110,7 @@ KRK_METHOD(dict,__repr__,{
{
KrkClass * type = krk_getType(entry->key);
krk_push(entry->key);
KrkValue result = krk_callSimple(OBJECT_VAL(type->_reprer), 1, 0);
KrkValue result = krk_callDirect(type->_reprer, 1);
if (IS_STRING(result)) {
pushStringBuilderStr(&sb, AS_CSTRING(result), AS_STRING(result)->length);
}
@ -121,7 +121,7 @@ KRK_METHOD(dict,__repr__,{
{
KrkClass * type = krk_getType(entry->value);
krk_push(entry->value);
KrkValue result = krk_callSimple(OBJECT_VAL(type->_reprer), 1, 0);
KrkValue result = krk_callDirect(type->_reprer, 1);
if (IS_STRING(result)) {
pushStringBuilderStr(&sb, AS_CSTRING(result), AS_STRING(result)->length);
}
@ -272,7 +272,7 @@ KRK_METHOD(dictitems,__repr__,{
{
KrkClass * type = krk_getType(entry->key);
krk_push(entry->key);
KrkValue result = krk_callSimple(OBJECT_VAL(type->_reprer), 1, 0);
KrkValue result = krk_callDirect(type->_reprer, 1);
if (IS_STRING(result)) {
pushStringBuilderStr(&sb, AS_CSTRING(result), AS_STRING(result)->length);
}
@ -283,7 +283,7 @@ KRK_METHOD(dictitems,__repr__,{
{
KrkClass * type = krk_getType(entry->value);
krk_push(entry->value);
KrkValue result = krk_callSimple(OBJECT_VAL(type->_reprer), 1, 0);
KrkValue result = krk_callDirect(type->_reprer, 1);
if (IS_STRING(result)) {
pushStringBuilderStr(&sb, AS_CSTRING(result), AS_STRING(result)->length);
}
@ -351,7 +351,7 @@ KRK_METHOD(dictkeys,__repr__,{
{
KrkClass * type = krk_getType(entry->key);
krk_push(entry->key);
KrkValue result = krk_callSimple(OBJECT_VAL(type->_reprer), 1, 0);
KrkValue result = krk_callDirect(type->_reprer, 1);
if (IS_STRING(result)) {
pushStringBuilderStr(&sb, AS_CSTRING(result), AS_STRING(result)->length);
}

View File

@ -234,7 +234,7 @@ KRK_METHOD(method,__str__,{
KrkClass * type = krk_getType(self->receiver);
krk_push(self->receiver);
KrkValue reprVal = krk_callSimple(OBJECT_VAL(type->_reprer), 1, 0);
KrkValue reprVal = krk_callDirect(type->_reprer, 1);
size_t len = AS_STRING(s)->length + AS_STRING(reprVal)->length + sizeof("<bound method of >") + 1;
char * tmp = malloc(len);

View File

@ -206,7 +206,7 @@ int krk_getAwaitable(void) {
krk_push(method);
krk_swap(1);
krk_pop();
krk_push(krk_callSimple(krk_peek(0),0,0));
krk_push(krk_callStack(0));
KrkClass * _type = krk_getType(krk_peek(0));
if (!_type || !_type->_iter) {
krk_runtimeError(vm.exceptions->attributeError, "__await__ returned non-iterator of type '%s'", krk_typeName(krk_peek(0)));

View File

@ -99,7 +99,7 @@ KRK_METHOD(list,__repr__,{
/* repr(self[i]) */
KrkClass * type = krk_getType(self->values.values[i]);
krk_push(self->values.values[i]);
KrkValue result = krk_callSimple(OBJECT_VAL(type->_reprer), 1, 0);
KrkValue result = krk_callDirect(type->_reprer, 1);
if (IS_STRING(result)) {
pushStringBuilderStr(&sb, AS_STRING(result)->chars, AS_STRING(result)->length);

View File

@ -86,7 +86,7 @@ KRK_METHOD(set,__repr__,{
KrkClass * type = krk_getType(entry->key);
krk_push(entry->key);
KrkValue result = krk_callSimple(OBJECT_VAL(type->_reprer), 1, 0);
KrkValue result = krk_callDirect(type->_reprer, 1);
if (IS_STRING(result)) {
pushStringBuilderStr(&sb, AS_CSTRING(result), AS_STRING(result)->length);
}
@ -115,9 +115,10 @@ KRK_METHOD(set,__and__,{
KrkTableEntry * entry = &self->entries.entries[i];
if (IS_KWARGS(entry->key)) continue;
krk_push(contains);
krk_push(argv[1]);
krk_push(entry->key);
KrkValue result = krk_callSimple(contains, 2, 0);
KrkValue result = krk_callStack(2);
if (IS_BOOLEAN(result) && AS_BOOLEAN(result)) {
krk_tableSet(&AS_set(outSet)->entries, entry->key, BOOLEAN_VAL(1));

View File

@ -40,7 +40,7 @@ KRK_METHOD(str,__init__,{
/* Find the type of arg */
krk_push(argv[1]);
if (!krk_getType(argv[1])->_tostr) return krk_runtimeError(vm.exceptions->typeError, "Can not convert %s to str", krk_typeName(argv[1]));
return krk_callSimple(OBJECT_VAL(krk_getType(argv[1])->_tostr), 1, 0);
return krk_callDirect(krk_getType(argv[1])->_tostr, 1);
})
KRK_METHOD(str,__add__,{
@ -257,13 +257,13 @@ KRK_METHOD(str,format,{
krk_push(value);
KrkClass * type = krk_getType(value);
if (type->_tostr) {
asString = krk_callSimple(OBJECT_VAL(type->_tostr), 1, 0);
asString = krk_callDirect(type->_tostr, 1);
} else {
if (!krk_bindMethod(type, AS_STRING(vm.specialMethodNames[METHOD_STR]))) {
errorStr = "Failed to convert field to string.";
goto _formatError;
}
asString = krk_callSimple(krk_peek(0), 0, 1);
asString = krk_callStack(0);
}
if (!IS_STRING(asString)) goto _freeAndDone;
}

View File

@ -16,10 +16,11 @@ static KrkValue _tuple_init(int argc, KrkValue argv[], int hasKw) {
/* Convert this to a call to tupleOf(*arg) */
KrkValue tupleOf;
krk_tableGet(&vm.builtins->fields, OBJECT_VAL(S("tupleOf")), &tupleOf);
krk_push(tupleOf);
krk_push(KWARGS_VAL(KWARGS_LIST));
krk_push(argv[1]);
krk_push(KWARGS_VAL(1));
krk_push(krk_callSimple(tupleOf, 3, 0));
krk_push(krk_callStack(3));
return krk_pop();
} else {
return krk_runtimeError(vm.exceptions->argumentError,
@ -87,7 +88,7 @@ KRK_METHOD(tuple,__repr__,{
for (size_t i = 0; i < self->values.count; ++i) {
KrkClass * type = krk_getType(self->values.values[i]);
krk_push(self->values.values[i]);
KrkValue result = krk_callSimple(OBJECT_VAL(type->_reprer), 1, 0);
KrkValue result = krk_callDirect(type->_reprer, 1);
if (IS_STRING(result)) {
pushStringBuilderStr(&sb, AS_STRING(result)->chars, AS_STRING(result)->length);
}

View File

@ -43,7 +43,7 @@ static KrkValue typeToString(KrkValue val) {
/* Just repr it. */
KrkClass * type = krk_getType(val);
krk_push(val);
return krk_callSimple(OBJECT_VAL(type->_reprer), 1, 0);
return krk_callDirect(type->_reprer, 1);
}
}

View File

@ -108,7 +108,7 @@ KRK_METHOD(Environ,__setitem__,{
krk_push(argv[0]);
krk_push(argv[1]);
krk_push(argv[2]);
return krk_callSimple(OBJECT_VAL(vm.baseClasses->dictClass->_setter), 3, 0);
return krk_callDirect(vm.baseClasses->dictClass->_setter, 3);
}
return krk_runtimeError(OSError, "%s", strerror(errno));
@ -132,7 +132,7 @@ KRK_METHOD(Environ,__delitem__,{
_unsetVar(key);
krk_push(argv[0]);
krk_push(argv[1]);
return krk_callSimple(OBJECT_VAL(vm.baseClasses->dictClass->_delitem), 2, 0);
return krk_callDirect(vm.baseClasses->dictClass->_delitem, 2);
})
static void _loadEnviron(KrkInstance * module) {

View File

@ -44,7 +44,7 @@ inline int krk_hashValue(KrkValue value, uint32_t *hashOut) {
KrkClass * type = krk_getType(value);
if (type && type->_hash) {
krk_push(value);
KrkValue result = krk_callSimple(OBJECT_VAL(type->_hash), 1, 0);
KrkValue result = krk_callDirect(type->_hash, 1);
if (!IS_INTEGER(result)) goto _unhashable;
*hashOut = (uint32_t)AS_INTEGER(result);
return 0;

View File

@ -86,9 +86,9 @@ static void * _startthread(void * _threadObj) {
if (!krk_tableGet(&ourType->methods, OBJECT_VAL(S("run")), &runMethod)) {
krk_runtimeError(ThreadError, "Thread object has no run() method");
} else {
krk_push(runMethod);
krk_push(OBJECT_VAL(self));
krk_callValue(runMethod, 1, 0);
krk_runNext();
krk_callStack(1);
}
self->alive = 0;

View File

@ -31,12 +31,12 @@ void krk_printValue(FILE * f, KrkValue printable) {
KrkClass * type = krk_getType(printable);
if (type->_tostr) {
krk_push(printable);
printable = krk_callSimple(OBJECT_VAL(type->_tostr), 1, 0);
printable = krk_callDirect(type->_tostr, 1);
if (!IS_STRING(printable)) return;
fprintf(f, "%s", AS_CSTRING(printable));
} else if (type->_reprer) {
krk_push(printable);
printable = krk_callSimple(OBJECT_VAL(type->_reprer), 1, 0);
printable = krk_callDirect(type->_reprer, 1);
if (!IS_STRING(printable)) return;
fprintf(f, "%s", AS_CSTRING(printable));
} else {
@ -166,7 +166,7 @@ int krk_valuesEqual(KrkValue a, KrkValue b) {
if (type && type->_eq) {
krk_push(a);
krk_push(b);
KrkValue result = krk_callSimple(OBJECT_VAL(type->_eq),2,0);
KrkValue result = krk_callDirect(type->_eq,2);
if (IS_BOOLEAN(result)) return AS_BOOLEAN(result);
if (IS_NOTIMPL(result)) goto _next;
return !krk_isFalsey(result);
@ -177,7 +177,7 @@ _next:
if (type && type->_eq) {
krk_push(b);
krk_push(a);
KrkValue result = krk_callSimple(OBJECT_VAL(type->_eq),2,0);
KrkValue result = krk_callDirect(type->_eq,2);
if (IS_BOOLEAN(result)) return AS_BOOLEAN(result);
return !krk_isFalsey(result);
}

104
src/vm.c
View File

@ -190,14 +190,14 @@ void krk_dumpTraceback(void) {
/* Is this a SyntaxError? Handle those specially. */
if (krk_isInstanceOf(krk_currentThread.currentException, vm.exceptions->syntaxError)) {
KrkValue result = krk_callSimple(OBJECT_VAL(krk_getType(krk_currentThread.currentException)->_tostr), 1, 0);
KrkValue result = krk_callDirect(krk_getType(krk_currentThread.currentException)->_tostr, 1);
fprintf(stderr, "%s\n", AS_CSTRING(result));
return;
}
/* Clear the exception state while printing the exception. */
krk_currentThread.flags &= ~(KRK_THREAD_HAS_EXCEPTION);
fprintf(stderr, "%s", krk_typeName(krk_currentThread.currentException));
KrkValue result = krk_callSimple(OBJECT_VAL(krk_getType(krk_currentThread.currentException)->_tostr), 1, 0);
KrkValue result = krk_callDirect(krk_getType(krk_currentThread.currentException)->_tostr, 1);
if (!IS_STRING(result)) {
fprintf(stderr, "\n");
} else {
@ -588,7 +588,7 @@ int krk_processComplexArguments(int argCount, KrkValueArray * positionals, KrkTa
* `extra` is passed by `callValue` to tell us which case we have, and thus
* where we need to restore the stack to when we return from this call.
*/
static int call(KrkClosure * closure, int argCount, int extra) {
static int call(KrkClosure * closure, int argCount, int callableOnStack) {
size_t potentialPositionalArgs = closure->function->requiredArgs + closure->function->keywordArgs;
size_t totalArguments = closure->function->requiredArgs + closure->function->keywordArgs + !!(closure->function->flags & KRK_CODEOBJECT_FLAGS_COLLECTS_ARGS) + !!(closure->function->flags & KRK_CODEOBJECT_FLAGS_COLLECTS_KWS);
size_t offsetOfExtraArgs = closure->function->requiredArgs + closure->function->keywordArgs;
@ -730,7 +730,7 @@ _finishKwarg:
if (unlikely(closure->function->flags & (KRK_CODEOBJECT_FLAGS_IS_GENERATOR | KRK_CODEOBJECT_FLAGS_IS_COROUTINE))) {
KrkInstance * gen = krk_buildGenerator(closure, krk_currentThread.stackTop - argCount, argCount);
krk_currentThread.stackTop = krk_currentThread.stackTop - argCount - extra;
krk_currentThread.stackTop = krk_currentThread.stackTop - argCount - callableOnStack;
krk_push(OBJECT_VAL(gen));
return 2;
}
@ -741,7 +741,7 @@ _finishKwarg:
frame->closure = closure;
frame->ip = closure->function->chunk.code;
frame->slots = (krk_currentThread.stackTop - argCount) - krk_currentThread.stack;
frame->outSlots = (krk_currentThread.stackTop - argCount - extra) - krk_currentThread.stack;
frame->outSlots = (krk_currentThread.stackTop - argCount - callableOnStack) - krk_currentThread.stack;
frame->globals = &closure->function->globalsContext->fields;
FRAME_IN(frame);
return 1;
@ -775,11 +775,11 @@ _errorAfterKeywords:
* If callValue returns 0, the VM should already be in the exception state
* and it is not necessary to raise another exception.
*/
int krk_callValue(KrkValue callee, int argCount, int extra) {
int krk_callValue(KrkValue callee, int argCount, int callableOnStack) {
if (likely(IS_OBJECT(callee))) {
switch (OBJECT_TYPE(callee)) {
case KRK_OBJ_CLOSURE:
return call(AS_CLOSURE(callee), argCount, extra);
return call(AS_CLOSURE(callee), argCount, callableOnStack);
case KRK_OBJ_NATIVE: {
NativeFn native = (NativeFn)AS_NATIVE(callee)->function;
if (unlikely(argCount && IS_KWARGS(krk_currentThread.stackTop[-1]))) {
@ -791,7 +791,7 @@ int krk_callValue(KrkValue callee, int argCount, int extra) {
return 0;
}
argCount--; /* Because that popped the kwargs value */
krk_currentThread.stackTop -= argCount + extra; /* We can just put the stack back to normal */
krk_currentThread.stackTop -= argCount + callableOnStack; /* We can just put the stack back to normal */
krk_push(myList);
krk_push(myDict);
krk_currentThread.scratchSpace[0] = NONE_VAL();
@ -815,7 +815,7 @@ int krk_callValue(KrkValue callee, int argCount, int extra) {
free(stackCopy);
}
if (unlikely(krk_currentThread.stackTop == krk_currentThread.stack)) return 0;
krk_currentThread.stackTop -= argCount + extra;
krk_currentThread.stackTop -= argCount + callableOnStack;
krk_push(result);
}
return 2;
@ -862,14 +862,23 @@ int krk_callValue(KrkValue callee, int argCount, int extra) {
/**
* Takes care of runnext/pop
*/
KrkValue krk_callSimple(KrkValue value, int argCount, int isMethod) {
switch (krk_callValue(value, argCount, isMethod)) {
KrkValue krk_callStack(int argCount) {
switch (krk_callValue(krk_peek(argCount), argCount, 1)) {
case 2: return krk_pop();
case 1: return krk_runNext();
default:
if (!IS_NONE(krk_currentThread.currentException)) return NONE_VAL();
default: return NONE_VAL();
}
}
KrkValue krk_callDirect(KrkObj * callable, int argCount) {
if (unlikely(callable->type != KRK_OBJ_CLOSURE && callable->type != KRK_OBJ_NATIVE)) {
return krk_runtimeError(vm.exceptions->typeError, "'%s' is not a function.", krk_typeName(OBJECT_VAL(callable)));
}
switch (krk_callValue(OBJECT_VAL(callable), argCount, 0)) {
case 2: return krk_pop();
case 1: return krk_runNext();
default: return NONE_VAL();
}
return krk_runtimeError(vm.exceptions->typeError, "Invalid internal method call: '%s'", krk_typeName(value));
}
/**
@ -908,7 +917,7 @@ int krk_bindMethod(KrkClass * _class, KrkString * name) {
if (type->_descget) {
krk_push(method);
krk_swap(1);
krk_push(krk_callSimple(OBJECT_VAL(type->_descget), 2, 0));
krk_push(krk_callDirect(type->_descget, 2));
return 1;
}
out = method;
@ -1011,7 +1020,7 @@ int krk_isFalsey(KrkValue value) {
/* If it has a length, and that length is 0, it's Falsey */
if (type->_len) {
krk_push(value);
return !AS_INTEGER(krk_callSimple(OBJECT_VAL(type->_len),1,0));
return !AS_INTEGER(krk_callDirect(type->_len,1));
}
return 0; /* Assume anything else is truthy */
}
@ -1371,7 +1380,7 @@ static KrkValue tryBind(const char * name, KrkValue a, KrkValue b, const char *
krk_push(a);
if (krk_bindMethod(type, methodName)) {
krk_push(b);
value = krk_callSimple(krk_peek(1), 1, 1);
value = krk_callStack(1);
if (!IS_NOTIMPL(value)) goto _success;
krk_pop(); /* name */
} else {
@ -1386,7 +1395,7 @@ static KrkValue tryBind(const char * name, KrkValue a, KrkValue b, const char *
krk_push(b);
if (krk_bindMethod(type, methodName)) {
krk_push(a);
value = krk_callSimple(krk_peek(1), 1, 1);
value = krk_callStack(1);
if (!IS_NOTIMPL(value)) goto _success;
krk_pop(); /* name */
} else {
@ -1718,7 +1727,7 @@ int krk_loadModule(KrkString * path, KrkValue * moduleOut, KrkString * runAs) {
krk_push(krk_valueGetAttribute(OBJECT_VAL(path), "replace"));
krk_push(OBJECT_VAL(S(PATH_SEP)));
krk_push(OBJECT_VAL(S(".")));
krk_push(krk_callSimple(krk_peek(2), 2, 1));
krk_push(krk_callStack(2));
} else {
krk_push(OBJECT_VAL(runAs));
}
@ -1878,7 +1887,7 @@ static int valueGetProperty(KrkString * name) {
if (objectClass->_getattr) {
krk_push(OBJECT_VAL(name));
krk_push(krk_callSimple(OBJECT_VAL(objectClass->_getattr), 2, 0));
krk_push(krk_callDirect(objectClass->_getattr, 2));
return 1;
}
@ -1953,7 +1962,7 @@ static int trySetDescriptor(KrkValue owner, KrkString * name, KrkValue value) {
krk_push(property); /* owner value property */
krk_swap(2); /* property value owner */
krk_swap(1); /* property owner value */
krk_push(krk_callSimple(OBJECT_VAL(type->_descset), 3, 0));
krk_push(krk_callDirect(type->_descset, 3));
return 1;
}
}
@ -2078,7 +2087,7 @@ _resumeHook: (void)0;
if (IS_INSTANCE(exceptionObject))
krk_tableGet_fast(&AS_INSTANCE(exceptionObject)->fields, S("traceback"), &tracebackEntries);
krk_push(tracebackEntries);
krk_callSimple(OBJECT_VAL(type->_exit), 4, 0);
krk_callDirect(type->_exit, 4);
/* Top of stack is now either someone else's problem or a return value */
if (!(krk_currentThread.flags & KRK_THREAD_HAS_EXCEPTION)) {
krk_pop(); /* Handler object */
@ -2090,7 +2099,7 @@ _resumeHook: (void)0;
krk_push(NONE_VAL());
krk_push(NONE_VAL());
krk_push(NONE_VAL());
krk_callSimple(OBJECT_VAL(type->_exit), 4, 0);
krk_callDirect(type->_exit, 4);
if (krk_currentThread.flags & KRK_THREAD_HAS_EXCEPTION) goto _finishException;
}
if (AS_HANDLER_TYPE(handler) != OP_RETURN) break;
@ -2182,7 +2191,7 @@ _finishReturn: (void)0;
case OP_POP: krk_pop(); break;
case OP_RAISE: {
if (IS_CLASS(krk_peek(0))) {
krk_currentThread.currentException = krk_callSimple(krk_peek(0), 0, 1);
krk_currentThread.currentException = krk_callStack(0);
} else {
krk_currentThread.currentException = krk_pop();
}
@ -2197,9 +2206,9 @@ _finishReturn: (void)0;
case OP_INVOKE_GETTER: {
KrkClass * type = krk_getType(krk_peek(1));
if (likely(type->_getter != NULL)) {
krk_push(krk_callSimple(OBJECT_VAL(type->_getter), 2, 0));
krk_push(krk_callDirect(type->_getter, 2));
} else if (IS_CLASS(krk_peek(1)) && AS_CLASS(krk_peek(1))->_classgetitem) {
krk_push(krk_callSimple(OBJECT_VAL(AS_CLASS(krk_peek(1))->_classgetitem), 2, 0));
krk_push(krk_callDirect(AS_CLASS(krk_peek(1))->_classgetitem, 2));
} else {
krk_runtimeError(vm.exceptions->attributeError, "'%s' object is not subscriptable", krk_typeName(krk_peek(1)));
}
@ -2208,7 +2217,7 @@ _finishReturn: (void)0;
case OP_INVOKE_SETTER: {
KrkClass * type = krk_getType(krk_peek(2));
if (likely(type->_setter != NULL)) {
krk_push(krk_callSimple(OBJECT_VAL(type->_setter), 3, 0));
krk_push(krk_callDirect(type->_setter, 3));
} else {
if (type->_getter) {
krk_runtimeError(vm.exceptions->attributeError, "'%s' object is not mutable", krk_typeName(krk_peek(2)));
@ -2221,7 +2230,7 @@ _finishReturn: (void)0;
case OP_INVOKE_GETSLICE: {
KrkClass * type = krk_getType(krk_peek(2));
if (likely(type->_getslice != NULL)) {
krk_push(krk_callSimple(OBJECT_VAL(type->_getslice), 3, 0));
krk_push(krk_callDirect(type->_getslice, 3));
} else {
krk_runtimeError(vm.exceptions->attributeError, "'%s' object is not sliceable", krk_typeName(krk_peek(2)));
}
@ -2230,7 +2239,7 @@ _finishReturn: (void)0;
case OP_INVOKE_SETSLICE: {
KrkClass * type = krk_getType(krk_peek(3));
if (likely(type->_setslice != NULL)) {
krk_push(krk_callSimple(OBJECT_VAL(type->_setslice), 4, 0));
krk_push(krk_callDirect(type->_setslice, 4));
} else {
krk_runtimeError(vm.exceptions->attributeError, "'%s' object is not sliceable", krk_typeName(krk_peek(3)));
}
@ -2239,7 +2248,7 @@ _finishReturn: (void)0;
case OP_INVOKE_DELSLICE: {
KrkClass * type = krk_getType(krk_peek(2));
if (likely(type->_delslice != NULL)) {
krk_callSimple(OBJECT_VAL(type->_delslice), 3, 0);
krk_callDirect(type->_delslice, 3);
} else {
krk_runtimeError(vm.exceptions->attributeError, "'%s' object is not sliceable", krk_typeName(krk_peek(2)));
}
@ -2248,7 +2257,7 @@ _finishReturn: (void)0;
case OP_INVOKE_DELETE: {
KrkClass * type = krk_getType(krk_peek(1));
if (likely(type->_delitem != NULL)) {
krk_callSimple(OBJECT_VAL(type->_delitem), 2, 0);
krk_callDirect(type->_delitem, 2);
} else {
if (type->_getter) {
krk_runtimeError(vm.exceptions->attributeError, "'%s' object is not mutable", krk_typeName(krk_peek(1)));
@ -2261,7 +2270,7 @@ _finishReturn: (void)0;
case OP_INVOKE_ITER: {
KrkClass * type = krk_getType(krk_peek(0));
if (likely(type->_iter != NULL)) {
krk_push(krk_callSimple(OBJECT_VAL(type->_iter), 1, 0));
krk_push(krk_callDirect(type->_iter, 1));
} else {
krk_runtimeError(vm.exceptions->attributeError, "'%s' object is not iterable", krk_typeName(krk_peek(0)));
}
@ -2271,7 +2280,7 @@ _finishReturn: (void)0;
KrkClass * type = krk_getType(krk_peek(0));
if (likely(type->_contains != NULL)) {
krk_swap(1);
krk_push(krk_callSimple(OBJECT_VAL(type->_contains), 2, 0));
krk_push(krk_callDirect(type->_contains, 2));
} else {
krk_runtimeError(vm.exceptions->attributeError, "'%s' object can not be tested for membership", krk_typeName(krk_peek(0)));
}
@ -2440,7 +2449,7 @@ _finishReturn: (void)0;
goto _finishException;
}
krk_push(contextManager);
krk_callSimple(OBJECT_VAL(type->_enter), 1, 0);
krk_callDirect(type->_enter, 1);
/* Ignore result; don't need to pop */
krk_push(NONE_VAL());
KrkValue handler = HANDLER_VAL(OP_PUSH_WITH, cleanupTarget);
@ -2456,11 +2465,11 @@ _finishReturn: (void)0;
if (!IS_NONE(method)) {
krk_push(method);
krk_swap(1);
krk_push(krk_callSimple(krk_peek(1),1,0));
krk_push(krk_callStack(1));
} else {
krk_pop();
krk_push(krk_peek(0));
krk_push(krk_callSimple(krk_peek(0),0,0));
krk_push(krk_callStack(0));
}
if (!krk_valuesSame(krk_peek(0), krk_peek(1))) {
/* Value to yield */
@ -2475,7 +2484,7 @@ _finishReturn: (void)0;
krk_push(method);
krk_swap(1);
krk_pop();
krk_push(krk_callSimple(krk_peek(0),0,0));
krk_push(krk_callStack(0));
} else {
krk_pop();
krk_push(NONE_VAL());
@ -2488,7 +2497,7 @@ _finishReturn: (void)0;
uint16_t offset = OPERAND;
KrkValue iter = krk_peek(0);
krk_push(iter);
krk_push(krk_callSimple(iter, 0, 1));
krk_push(krk_callStack(0));
if (krk_valuesSame(iter, krk_peek(0))) frame->ip += offset;
break;
}
@ -2570,16 +2579,14 @@ _finishReturn: (void)0;
THREE_BYTE_OPERAND;
case OP_SET_LOCAL: {
ONE_BYTE_OPERAND;
uint32_t slot = OPERAND;
krk_currentThread.stack[frame->slots + slot] = krk_peek(0);
krk_currentThread.stack[frame->slots + OPERAND] = krk_peek(0);
break;
}
case OP_CALL_LONG:
THREE_BYTE_OPERAND;
case OP_CALL: {
ONE_BYTE_OPERAND;
int argCount = OPERAND;
if (unlikely(!krk_callValue(krk_peek(argCount), argCount, 1))) goto _finishException;
if (unlikely(!krk_callValue(krk_peek(OPERAND), OPERAND, 1))) goto _finishException;
frame = &krk_currentThread.frames[krk_currentThread.frameCount - 1];
break;
}
@ -2587,8 +2594,7 @@ _finishReturn: (void)0;
THREE_BYTE_OPERAND;
case OP_EXPAND_ARGS: {
ONE_BYTE_OPERAND;
int type = OPERAND;
krk_push(KWARGS_VAL(KWARGS_SINGLE-type));
krk_push(KWARGS_VAL(KWARGS_SINGLE-OPERAND));
break;
}
case OP_CLOSURE_LONG:
@ -2618,16 +2624,14 @@ _finishReturn: (void)0;
THREE_BYTE_OPERAND;
case OP_GET_UPVALUE: {
ONE_BYTE_OPERAND;
int slot = OPERAND;
krk_push(*UPVALUE_LOCATION(frame->closure->upvalues[slot]));
krk_push(*UPVALUE_LOCATION(frame->closure->upvalues[OPERAND]));
break;
}
case OP_SET_UPVALUE_LONG:
THREE_BYTE_OPERAND;
case OP_SET_UPVALUE: {
ONE_BYTE_OPERAND;
int slot = OPERAND;
*UPVALUE_LOCATION(frame->closure->upvalues[slot]) = krk_peek(0);
*UPVALUE_LOCATION(frame->closure->upvalues[OPERAND]) = krk_peek(0);
break;
}
case OP_CLASS_LONG:
@ -2883,12 +2887,12 @@ _finishReturn: (void)0;
}
/* Create the iterator */
krk_push(krk_currentThread.stack[stackStart]);
krk_push(krk_callSimple(OBJECT_VAL(type->_iter), 1, 0));
krk_push(krk_callDirect(type->_iter, 1));
do {
/* Call it until it gives us itself */
krk_push(krk_currentThread.stackTop[-1]);
krk_push(krk_callSimple(krk_peek(0), 0, 1));
krk_push(krk_callStack(0));
if (krk_valuesSame(krk_currentThread.stackTop[-2], krk_currentThread.stackTop[-1])) {
/* We're done. */
krk_pop(); /* The result of iteration */

View File

@ -36,7 +36,7 @@ int main(int argc, char * argv[]) {
KrkClass * type = krk_getType(result);
if (type->_reprer) {
krk_push(result);
result = krk_callSimple(OBJECT_VAL(type->_reprer), 1, 0);
result = krk_callDirect(type->_reprer, 1);
}
if (IS_STRING(result)) {
fprintf(stdout, " => %s\n", AS_CSTRING(result));

View File

@ -105,10 +105,10 @@ static int runSimpleRepl(void) {
const char * formatStr = " \033[1;30m=> %s\033[0m\n";
if (type->_reprer) {
krk_push(result);
result = krk_callSimple(OBJECT_VAL(type->_reprer), 1, 0);
result = krk_callDirect(type->_reprer, 1);
} else if (type->_tostr) {
krk_push(result);
result = krk_callSimple(OBJECT_VAL(type->_tostr), 1, 0);
result = krk_callDirect(type->_tostr, 1);
}
if (!IS_STRING(result)) {
fprintf(stdout, " \033[1;31m=> Unable to produce representation for value.\033[0m\n");