Make maximumCallDepth thread-local, expose changing it when feasible

This commit is contained in:
K. Lange 2023-12-24 09:05:52 +09:00
parent 80754593ad
commit 416ed28206
4 changed files with 25 additions and 14 deletions

View File

@ -167,6 +167,7 @@ typedef struct KrkThreadState {
KrkInstance * module; /**< The current module execution context. */
KrkValue currentException; /**< When an exception is thrown, it is stored here. */
int flags; /**< Thread-local VM flags; each thread inherits the low byte of the global VM flags. */
unsigned int maximumCallDepth; /**< Maximum recursive call depth. */
KrkValue * stackMax; /**< End of allocated stack space. */
KrkValue scratchSpace[KRK_THREAD_SCRATCH_SIZE]; /**< A place to store a few values to keep them from being prematurely GC'd. */
@ -201,7 +202,6 @@ typedef struct KrkVM {
KrkThreadState * threads; /**< Invasive linked list of all VM threads. */
FILE * callgrindFile; /**< File to write unprocessed callgrind data to. */
size_t maximumCallDepth; /**< Maximum recursive call depth. */
struct DebuggerState * dbgState; /**< Opaque debugger state pointer. */
} KrkVM;

View File

@ -201,6 +201,16 @@ KRK_Function(members) {
return krk_pop();
}
KRK_Function(set_recursion_depth) {
unsigned int maxdepth;
if (!krk_parseArgs("I",(const char*[]){"maxdepth"},&maxdepth)) return NONE_VAL();
if (krk_currentThread.exitOnFrame != 0) {
return krk_runtimeError(vm.exceptions->valueError, "Can not change recursion depth in this context.");
}
krk_setMaximumRecursionDepth(maxdepth);
return NONE_VAL();
}
void krk_module_init_kuroko(void) {
/**
* kuroko = module()
@ -250,6 +260,8 @@ void krk_module_init_kuroko(void) {
"Obtain the memory representation of a stack value.");
KRK_DOC(BIND_FUNC(vm.system,members),
"Obtain a copy of a dict of the direct members of an object.");
KRK_DOC(BIND_FUNC(vm.system,set_recursion_depth),
"Change the maximum recursion depth of the current thread if possible.");
krk_attachNamedObject(&vm.system->fields, "module", (KrkObj*)vm.baseClasses->moduleClass);
krk_attachNamedObject(&vm.system->fields, "path_sep", (KrkObj*)S(PATH_SEP));
KrkValue module_paths = krk_list_of(0,NULL,0);

View File

@ -36,6 +36,7 @@ struct Thread {
pid_t tid;
unsigned int started:1;
unsigned int alive:1;
unsigned int maxrec;
};
/**
@ -61,11 +62,13 @@ KRK_Function(current_thread) {
static volatile int _threadLock = 0;
static void * _startthread(void * _threadObj) {
struct Thread * self = _threadObj;
#if defined(__APPLE__) && defined(__aarch64__)
krk_forceThreadData();
#endif
memset(&krk_currentThread, 0, sizeof(KrkThreadState));
krk_currentThread.frames = calloc(vm.maximumCallDepth,sizeof(KrkCallFrame));
krk_currentThread.maximumCallDepth = self->maxrec;
krk_currentThread.frames = calloc(krk_currentThread.maximumCallDepth,sizeof(KrkCallFrame));
vm.globalFlags |= KRK_GLOBAL_THREADS;
_obtain_lock(_threadLock);
if (vm.threads->next) {
@ -75,7 +78,6 @@ static void * _startthread(void * _threadObj) {
_release_lock(_threadLock);
/* Get our run function */
struct Thread * self = _threadObj;
self->threadState = &krk_currentThread;
self->tid = gettid();
@ -126,13 +128,15 @@ KRK_Method(Thread,join) {
}
KRK_Method(Thread,start) {
METHOD_TAKES_NONE();
unsigned int maxrec = krk_currentThread.maximumCallDepth;
if (!krk_parseArgs(".|I", (const char*[]){"maxrec"}, &maxrec)) return NONE_VAL();
if (self->started)
return krk_runtimeError(KRK_EXC(ThreadError), "Thread has already been started.");
self->started = 1;
self->alive = 1;
self->maxrec = maxrec;
pthread_create(&self->nativeRef, NULL, _startthread, (void*)self);
return argv[0];

View File

@ -606,7 +606,7 @@ _finishKwarg:
return 2;
}
if (unlikely(krk_currentThread.frameCount == vm.maximumCallDepth)) {
if (unlikely(krk_currentThread.frameCount == (size_t)krk_currentThread.maximumCallDepth)) {
krk_runtimeError(vm.exceptions->baseException, "maximum recursion depth exceeded");
goto _errorAfterKeywords;
}
@ -892,13 +892,8 @@ int krk_isFalsey(KrkValue value) {
}
void krk_setMaximumRecursionDepth(size_t maxDepth) {
vm.maximumCallDepth = maxDepth;
KrkThreadState * thread = vm.threads;
while (thread) {
thread->frames = realloc(thread->frames, maxDepth * sizeof(KrkCallFrame));
thread = thread->next;
}
krk_currentThread.maximumCallDepth = maxDepth;
krk_currentThread.frames = realloc(krk_currentThread.frames, maxDepth * sizeof(KrkCallFrame));
}
void krk_initVM(int flags) {
@ -907,11 +902,11 @@ void krk_initVM(int flags) {
#endif
vm.globalFlags = flags & 0xFF00;
vm.maximumCallDepth = KRK_CALL_FRAMES_MAX;
/* Reset current thread */
krk_resetStack();
krk_currentThread.frames = calloc(vm.maximumCallDepth,sizeof(KrkCallFrame));
krk_currentThread.maximumCallDepth = KRK_CALL_FRAMES_MAX;
krk_currentThread.frames = calloc(krk_currentThread.maximumCallDepth,sizeof(KrkCallFrame));
krk_currentThread.flags = flags & 0x00FF;
krk_currentThread.module = NULL;
vm.threads = &krk_currentThread;