mirror of
https://github.com/zekexiao/pocketlang.git
synced 2025-03-04 13:15:55 +08:00
Merge pull request #237 from ThakeeNathees/term
new Fiber objects falsely garbage collected -- fixed
This commit is contained in:
commit
e458682486
@ -62,12 +62,13 @@ def log(*msg):
|
|||||||
sys.stderr.write(message + '\n')
|
sys.stderr.write(message + '\n')
|
||||||
|
|
||||||
def parse(path):
|
def parse(path):
|
||||||
|
dir = dirname(path).replace('\\', '/') ## Windows.
|
||||||
text = ""
|
text = ""
|
||||||
with open(path, 'r') as fp:
|
with open(path, 'r') as fp:
|
||||||
for line in fp.readlines():
|
for line in fp.readlines():
|
||||||
if "//<< AMALG_INLINE >>" in line:
|
if "//<< AMALG_INLINE >>" in line:
|
||||||
path = join(dirname(path), _get_include_path(line))
|
path = join(dir, _get_include_path(line))
|
||||||
path = path.replace('\\', '/') ## Aaah windows path.
|
path = path.replace('\\', '/')
|
||||||
text += parse(path) + '\n'
|
text += parse(path) + '\n'
|
||||||
else: text += line
|
else: text += line
|
||||||
|
|
||||||
|
@ -34,8 +34,7 @@ ALLOW_LONG_LINES = ('http://', 'https://', '<script ', '<link ', '<svg ')
|
|||||||
IGNORE_FILES = (
|
IGNORE_FILES = (
|
||||||
"cli/modules/pknative.gen.c", ## FIXME: set gen path.
|
"cli/modules/pknative.gen.c", ## FIXME: set gen path.
|
||||||
"cli/argparse.h", ## FIXME: collect all thirdparty files.
|
"cli/argparse.h", ## FIXME: collect all thirdparty files.
|
||||||
"src/libs/tp_dirent.h",
|
"src/libs/ext_term.c",
|
||||||
"src/libs/tp_cwalk.h",
|
|
||||||
)
|
)
|
||||||
|
|
||||||
## A list of directory, contains C source files to perform static checks.
|
## A list of directory, contains C source files to perform static checks.
|
||||||
|
@ -2734,9 +2734,12 @@ static void compileFunction(Compiler* compiler, FuncType fn_type) {
|
|||||||
|
|
||||||
if (compiler->parser.has_syntax_error) return;
|
if (compiler->parser.has_syntax_error) return;
|
||||||
|
|
||||||
|
// The function will register itself in the owner's constant pool and it's
|
||||||
|
// GC root so we don't need to push it to temp references.
|
||||||
int fn_index;
|
int fn_index;
|
||||||
Function* func = newFunction(compiler->parser.vm, name, name_length,
|
Function* func = newFunction(compiler->parser.vm, name, name_length,
|
||||||
compiler->module, false, NULL, &fn_index);
|
compiler->module, false, NULL, &fn_index);
|
||||||
|
|
||||||
func->is_method = (fn_type == FUNC_METHOD || fn_type == FUNC_CONSTRUCTOR);
|
func->is_method = (fn_type == FUNC_METHOD || fn_type == FUNC_CONSTRUCTOR);
|
||||||
|
|
||||||
checkMaxConstantsReached(compiler, fn_index);
|
checkMaxConstantsReached(compiler, fn_index);
|
||||||
|
@ -81,6 +81,7 @@ static char* stdinRead(PKVM* vm);
|
|||||||
static char* loadScript(PKVM* vm, const char* path);
|
static char* loadScript(PKVM* vm, const char* path);
|
||||||
|
|
||||||
void* pkRealloc(PKVM* vm, void* ptr, size_t size) {
|
void* pkRealloc(PKVM* vm, void* ptr, size_t size) {
|
||||||
|
|
||||||
ASSERT(vm->config.realloc_fn != NULL, "PKVM's allocator was NULL.");
|
ASSERT(vm->config.realloc_fn != NULL, "PKVM's allocator was NULL.");
|
||||||
#if TRACE_MEMORY
|
#if TRACE_MEMORY
|
||||||
void* newptr = vm->config.realloc_fn(ptr, size, vm->config.user_data);
|
void* newptr = vm->config.realloc_fn(ptr, size, vm->config.user_data);
|
||||||
@ -123,6 +124,7 @@ PKVM* pkNewVM(PkConfiguration* config) {
|
|||||||
vm->working_set = (Object**)vm->config.realloc_fn(
|
vm->working_set = (Object**)vm->config.realloc_fn(
|
||||||
NULL, sizeof(Object*) * vm->working_set_capacity, NULL);
|
NULL, sizeof(Object*) * vm->working_set_capacity, NULL);
|
||||||
vm->next_gc = INITIAL_GC_SIZE;
|
vm->next_gc = INITIAL_GC_SIZE;
|
||||||
|
vm->collecting_garbage = false;
|
||||||
vm->min_heap_size = MIN_HEAP_SIZE;
|
vm->min_heap_size = MIN_HEAP_SIZE;
|
||||||
vm->heap_fill_percent = HEAP_FILL_PERCENT;
|
vm->heap_fill_percent = HEAP_FILL_PERCENT;
|
||||||
|
|
||||||
@ -178,7 +180,12 @@ void pkSetUserData(PKVM* vm, void* user_data) {
|
|||||||
PkHandle* pkNewModule(PKVM* vm, const char* name) {
|
PkHandle* pkNewModule(PKVM* vm, const char* name) {
|
||||||
CHECK_ARG_NULL(name);
|
CHECK_ARG_NULL(name);
|
||||||
Module* module = newModuleInternal(vm, name);
|
Module* module = newModuleInternal(vm, name);
|
||||||
return vmNewHandle(vm, VAR_OBJ(module));
|
|
||||||
|
vmPushTempRef(vm, &module->_super); // module.
|
||||||
|
PkHandle* handle = vmNewHandle(vm, VAR_OBJ(module));
|
||||||
|
vmPopTempRef(vm); // module.
|
||||||
|
|
||||||
|
return handle;
|
||||||
}
|
}
|
||||||
|
|
||||||
void pkRegisterModule(PKVM* vm, PkHandle* module) {
|
void pkRegisterModule(PKVM* vm, PkHandle* module) {
|
||||||
@ -218,7 +225,10 @@ PkHandle* pkNewClass(PKVM* vm, const char* name,
|
|||||||
class_->new_fn = new_fn;
|
class_->new_fn = new_fn;
|
||||||
class_->delete_fn = delete_fn;
|
class_->delete_fn = delete_fn;
|
||||||
|
|
||||||
return vmNewHandle(vm, VAR_OBJ(class_));
|
vmPushTempRef(vm, &class_->_super); // class_.
|
||||||
|
PkHandle* handle = vmNewHandle(vm, VAR_OBJ(class_));
|
||||||
|
vmPopTempRef(vm); // class_.
|
||||||
|
return handle;
|
||||||
}
|
}
|
||||||
|
|
||||||
void pkClassAddMethod(PKVM* vm, PkHandle* cls,
|
void pkClassAddMethod(PKVM* vm, PkHandle* cls,
|
||||||
@ -236,6 +246,8 @@ void pkClassAddMethod(PKVM* vm, PkHandle* cls,
|
|||||||
|
|
||||||
Function* fn = newFunction(vm, name, (int)strlen(name),
|
Function* fn = newFunction(vm, name, (int)strlen(name),
|
||||||
class_->owner, true, NULL, NULL);
|
class_->owner, true, NULL, NULL);
|
||||||
|
vmPushTempRef(vm, &fn->_super); // fn.
|
||||||
|
|
||||||
fn->arity = arity;
|
fn->arity = arity;
|
||||||
fn->is_method = true;
|
fn->is_method = true;
|
||||||
fn->native = fptr;
|
fn->native = fptr;
|
||||||
@ -245,7 +257,9 @@ void pkClassAddMethod(PKVM* vm, PkHandle* cls,
|
|||||||
// won't be garbage collected (class handle has reference to the module).
|
// won't be garbage collected (class handle has reference to the module).
|
||||||
|
|
||||||
Closure* method = newClosure(vm, fn);
|
Closure* method = newClosure(vm, fn);
|
||||||
|
vmPopTempRef(vm); // fn.
|
||||||
|
vmPushTempRef(vm, &method->_super); // method.
|
||||||
|
{
|
||||||
if (strcmp(name, CTOR_NAME) == 0) {
|
if (strcmp(name, CTOR_NAME) == 0) {
|
||||||
class_->ctor = method;
|
class_->ctor = method;
|
||||||
|
|
||||||
@ -255,6 +269,8 @@ void pkClassAddMethod(PKVM* vm, PkHandle* cls,
|
|||||||
vmPopTempRef(vm); // method.
|
vmPopTempRef(vm); // method.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
vmPopTempRef(vm); // method.
|
||||||
|
}
|
||||||
|
|
||||||
void pkReleaseHandle(PKVM* vm, PkHandle* handle) {
|
void pkReleaseHandle(PKVM* vm, PkHandle* handle) {
|
||||||
ASSERT(handle != NULL, "Given handle was NULL.");
|
ASSERT(handle != NULL, "Given handle was NULL.");
|
||||||
@ -765,7 +781,11 @@ bool pkSetAttribute(PKVM* vm, int instance, const char* name, int value) {
|
|||||||
VALIDATE_SLOT_INDEX(instance);
|
VALIDATE_SLOT_INDEX(instance);
|
||||||
VALIDATE_SLOT_INDEX(value);
|
VALIDATE_SLOT_INDEX(value);
|
||||||
|
|
||||||
varSetAttrib(vm, SLOT(instance), newString(vm, name), SLOT(value));
|
String* sname = newString(vm, name);
|
||||||
|
vmPushTempRef(vm, &sname->_super); // sname.
|
||||||
|
varSetAttrib(vm, SLOT(instance), sname, SLOT(value));
|
||||||
|
vmPopTempRef(vm); // sname.
|
||||||
|
|
||||||
return !VM_HAS_ERROR(vm);
|
return !VM_HAS_ERROR(vm);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -776,12 +796,19 @@ bool pkGetAttribute(PKVM* vm, int instance, const char* name,
|
|||||||
VALIDATE_SLOT_INDEX(instance);
|
VALIDATE_SLOT_INDEX(instance);
|
||||||
VALIDATE_SLOT_INDEX(index);
|
VALIDATE_SLOT_INDEX(index);
|
||||||
|
|
||||||
SET_SLOT(index, varGetAttrib(vm, SLOT(instance), newString(vm, name)));
|
String* sname = newString(vm, name);
|
||||||
|
vmPushTempRef(vm, &sname->_super); // sname.
|
||||||
|
SET_SLOT(index, varGetAttrib(vm, SLOT(instance), sname));
|
||||||
|
vmPopTempRef(vm); // sname.
|
||||||
|
|
||||||
return !VM_HAS_ERROR(vm);
|
return !VM_HAS_ERROR(vm);
|
||||||
}
|
}
|
||||||
|
|
||||||
static Var _newInstance(PKVM* vm, Class* cls, int argc, Var* argv) {
|
static Var _newInstance(PKVM* vm, Class* cls, int argc, Var* argv) {
|
||||||
Var instance = preConstructSelf(vm, cls);
|
Var instance = preConstructSelf(vm, cls);
|
||||||
|
if (VM_HAS_ERROR(vm)) return VAR_NULL;
|
||||||
|
|
||||||
|
if (IS_OBJ(instance)) vmPushTempRef(vm, AS_OBJ(instance)); // instance.
|
||||||
|
|
||||||
Closure* ctor = cls->ctor;
|
Closure* ctor = cls->ctor;
|
||||||
while (ctor == NULL) {
|
while (ctor == NULL) {
|
||||||
@ -791,6 +818,7 @@ static Var _newInstance(PKVM* vm, Class* cls, int argc, Var* argv) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (ctor != NULL) vmCallMethod(vm, instance, ctor, argc, argv, NULL);
|
if (ctor != NULL) vmCallMethod(vm, instance, ctor, argc, argv, NULL);
|
||||||
|
if (IS_OBJ(instance)) vmPopTempRef(vm); // instance.
|
||||||
|
|
||||||
return instance;
|
return instance;
|
||||||
}
|
}
|
||||||
@ -860,8 +888,12 @@ bool pkCallMethod(PKVM* vm, int instance, const char* method,
|
|||||||
if (ret >= 0) VALIDATE_SLOT_INDEX(ret);
|
if (ret >= 0) VALIDATE_SLOT_INDEX(ret);
|
||||||
|
|
||||||
bool is_method = false;
|
bool is_method = false;
|
||||||
Var callable = getMethod(vm, SLOT(instance), newString(vm, method),
|
String* smethod = newString(vm, method);
|
||||||
|
vmPushTempRef(vm, &smethod->_super); // smethod.
|
||||||
|
Var callable = getMethod(vm, SLOT(instance), smethod,
|
||||||
&is_method);
|
&is_method);
|
||||||
|
vmPopTempRef(vm); // smethod.
|
||||||
|
|
||||||
if (VM_HAS_ERROR(vm)) return false;
|
if (VM_HAS_ERROR(vm)) return false;
|
||||||
|
|
||||||
// Calls a class == construct.
|
// Calls a class == construct.
|
||||||
|
@ -97,7 +97,7 @@ static void popMarkedObjectsInternal(Object* obj, PKVM* vm) {
|
|||||||
switch (obj->type) {
|
switch (obj->type) {
|
||||||
case OBJ_STRING: {
|
case OBJ_STRING: {
|
||||||
vm->bytes_allocated += sizeof(String);
|
vm->bytes_allocated += sizeof(String);
|
||||||
vm->bytes_allocated += ((size_t)((String*)obj)->length + 1);
|
vm->bytes_allocated += ((size_t)((String*)obj)->capacity);
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case OBJ_LIST: {
|
case OBJ_LIST: {
|
||||||
@ -149,7 +149,9 @@ static void popMarkedObjectsInternal(Object* obj, PKVM* vm) {
|
|||||||
|
|
||||||
markObject(vm, &func->owner->_super);
|
markObject(vm, &func->owner->_super);
|
||||||
|
|
||||||
if (!func->is_native) {
|
// If a garbage collection is triggered when allocating a name string
|
||||||
|
// for this function, it's [fn] property will be NULL.
|
||||||
|
if (!func->is_native && func->fn != NULL) {
|
||||||
Fn* fn = func->fn;
|
Fn* fn = func->fn;
|
||||||
vm->bytes_allocated += sizeof(Fn);
|
vm->bytes_allocated += sizeof(Fn);
|
||||||
|
|
||||||
@ -293,14 +295,14 @@ String* newStringVaArgs(PKVM* vm, const char* fmt, va_list args) {
|
|||||||
|
|
||||||
List* newList(PKVM* vm, uint32_t size) {
|
List* newList(PKVM* vm, uint32_t size) {
|
||||||
List* list = ALLOCATE(vm, List);
|
List* list = ALLOCATE(vm, List);
|
||||||
vmPushTempRef(vm, &list->_super);
|
vmPushTempRef(vm, &list->_super); // list.
|
||||||
varInitObject(&list->_super, vm, OBJ_LIST);
|
varInitObject(&list->_super, vm, OBJ_LIST);
|
||||||
pkVarBufferInit(&list->elements);
|
pkVarBufferInit(&list->elements);
|
||||||
if (size > 0) {
|
if (size > 0) {
|
||||||
pkVarBufferFill(&list->elements, vm, VAR_NULL, size);
|
pkVarBufferFill(&list->elements, vm, VAR_NULL, size);
|
||||||
list->elements.count = 0;
|
list->elements.count = 0;
|
||||||
}
|
}
|
||||||
vmPopTempRef(vm);
|
vmPopTempRef(vm); // list.
|
||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -323,13 +325,9 @@ Range* newRange(PKVM* vm, double from, double to) {
|
|||||||
|
|
||||||
Module* newModule(PKVM* vm) {
|
Module* newModule(PKVM* vm) {
|
||||||
Module* module = ALLOCATE(vm, Module);
|
Module* module = ALLOCATE(vm, Module);
|
||||||
|
memset(module, 0, sizeof(Module));
|
||||||
varInitObject(&module->_super, vm, OBJ_MODULE);
|
varInitObject(&module->_super, vm, OBJ_MODULE);
|
||||||
|
|
||||||
module->path = NULL;
|
|
||||||
module->name = NULL;
|
|
||||||
module->initialized = false;
|
|
||||||
module->body = NULL;
|
|
||||||
|
|
||||||
pkVarBufferInit(&module->globals);
|
pkVarBufferInit(&module->globals);
|
||||||
pkUintBufferInit(&module->global_names);
|
pkUintBufferInit(&module->global_names);
|
||||||
pkVarBufferInit(&module->constants);
|
pkVarBufferInit(&module->constants);
|
||||||
@ -343,6 +341,7 @@ Function* newFunction(PKVM* vm, const char* name, int length,
|
|||||||
int* fn_index) {
|
int* fn_index) {
|
||||||
|
|
||||||
Function* func = ALLOCATE(vm, Function);
|
Function* func = ALLOCATE(vm, Function);
|
||||||
|
memset(func, 0, sizeof(Function));
|
||||||
varInitObject(&func->_super, vm, OBJ_FUNC);
|
varInitObject(&func->_super, vm, OBJ_FUNC);
|
||||||
|
|
||||||
vmPushTempRef(vm, &func->_super); // func
|
vmPushTempRef(vm, &func->_super); // func
|
||||||
@ -388,10 +387,7 @@ Closure* newClosure(PKVM* vm, Function* fn) {
|
|||||||
varInitObject(&closure->_super, vm, OBJ_CLOSURE);
|
varInitObject(&closure->_super, vm, OBJ_CLOSURE);
|
||||||
|
|
||||||
closure->fn = fn;
|
closure->fn = fn;
|
||||||
|
memset(closure->upvalues, 0, sizeof(Upvalue*) * fn->upvalue_count);
|
||||||
for (int i = 0; i < fn->upvalue_count; i++) {
|
|
||||||
closure->upvalues[i] = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
return closure;
|
return closure;
|
||||||
}
|
}
|
||||||
@ -411,11 +407,15 @@ Fiber* newFiber(PKVM* vm, Closure* closure) {
|
|||||||
|
|
||||||
Fiber* fiber = ALLOCATE(vm, Fiber);
|
Fiber* fiber = ALLOCATE(vm, Fiber);
|
||||||
|
|
||||||
// Not sure why this memset is needed here. If it doesn't then remove it.
|
// If a garbage collection is triggered here, and the fiber isn't fully
|
||||||
|
// constructed -> it's fields are not intialized yet, would cause a crash
|
||||||
|
// so we need to memset here.
|
||||||
memset(fiber, 0, sizeof(Fiber));
|
memset(fiber, 0, sizeof(Fiber));
|
||||||
|
|
||||||
varInitObject(&fiber->_super, vm, OBJ_FIBER);
|
varInitObject(&fiber->_super, vm, OBJ_FIBER);
|
||||||
|
|
||||||
|
vmPushTempRef(vm, &fiber->_super); // fiber.
|
||||||
|
|
||||||
fiber->state = FIBER_NEW;
|
fiber->state = FIBER_NEW;
|
||||||
fiber->closure = closure;
|
fiber->closure = closure;
|
||||||
|
|
||||||
@ -431,6 +431,7 @@ Fiber* newFiber(PKVM* vm, Closure* closure) {
|
|||||||
if (stack_size == 0) stack_size++;
|
if (stack_size == 0) stack_size++;
|
||||||
|
|
||||||
fiber->stack = ALLOCATE_ARRAY(vm, Var, stack_size);
|
fiber->stack = ALLOCATE_ARRAY(vm, Var, stack_size);
|
||||||
|
ASSERT(fiber->stack != NULL, "Out of memory");
|
||||||
fiber->stack_size = stack_size;
|
fiber->stack_size = stack_size;
|
||||||
fiber->ret = fiber->stack;
|
fiber->ret = fiber->stack;
|
||||||
fiber->sp = fiber->stack + 1;
|
fiber->sp = fiber->stack + 1;
|
||||||
@ -462,6 +463,8 @@ Fiber* newFiber(PKVM* vm, Closure* closure) {
|
|||||||
// but if we're trying to debut it may crash when dumping the return value).
|
// but if we're trying to debut it may crash when dumping the return value).
|
||||||
*fiber->ret = VAR_NULL;
|
*fiber->ret = VAR_NULL;
|
||||||
|
|
||||||
|
vmPopTempRef(vm); // fiber.
|
||||||
|
|
||||||
return fiber;
|
return fiber;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -470,6 +473,12 @@ Class* newClass(PKVM* vm, const char* name, int length,
|
|||||||
const char* docstring, int* cls_index) {
|
const char* docstring, int* cls_index) {
|
||||||
|
|
||||||
Class* cls = ALLOCATE(vm, Class);
|
Class* cls = ALLOCATE(vm, Class);
|
||||||
|
|
||||||
|
// If the garbage collection trigged bellow while allocating for
|
||||||
|
// [cls->name] or other properties, the calss is in the root (temp ref)
|
||||||
|
// and it's property [cls->name] is un initialized, which cause a crash.
|
||||||
|
memset(cls, 0, sizeof(Class));
|
||||||
|
|
||||||
varInitObject(&cls->_super, vm, OBJ_CLASS);
|
varInitObject(&cls->_super, vm, OBJ_CLASS);
|
||||||
|
|
||||||
vmPushTempRef(vm, &cls->_super); // class.
|
vmPushTempRef(vm, &cls->_super); // class.
|
||||||
@ -477,12 +486,7 @@ Class* newClass(PKVM* vm, const char* name, int length,
|
|||||||
pkClosureBufferInit(&cls->methods);
|
pkClosureBufferInit(&cls->methods);
|
||||||
|
|
||||||
cls->class_of = PK_INSTANCE;
|
cls->class_of = PK_INSTANCE;
|
||||||
cls->owner = NULL;
|
|
||||||
cls->super_class = super;
|
cls->super_class = super;
|
||||||
cls->docstring = NULL;
|
|
||||||
cls->ctor = NULL;
|
|
||||||
cls->new_fn = NULL;
|
|
||||||
cls->delete_fn = NULL;
|
|
||||||
|
|
||||||
// Builtin types doesn't belongs to a module.
|
// Builtin types doesn't belongs to a module.
|
||||||
if (module != NULL) {
|
if (module != NULL) {
|
||||||
@ -504,36 +508,38 @@ Instance* newInstance(PKVM* vm, Class* cls) {
|
|||||||
"class with newInstance() function.");
|
"class with newInstance() function.");
|
||||||
|
|
||||||
Instance* inst = ALLOCATE(vm, Instance);
|
Instance* inst = ALLOCATE(vm, Instance);
|
||||||
|
memset(inst, 0, sizeof(Instance));
|
||||||
varInitObject(&inst->_super, vm, OBJ_INST);
|
varInitObject(&inst->_super, vm, OBJ_INST);
|
||||||
|
|
||||||
vmPushTempRef(vm, &inst->_super); // inst.
|
vmPushTempRef(vm, &inst->_super); // inst.
|
||||||
|
|
||||||
inst->cls = cls;
|
inst->cls = cls;
|
||||||
inst->attribs = newMap(vm);
|
|
||||||
|
|
||||||
if (cls->new_fn != NULL) {
|
if (cls->new_fn != NULL) {
|
||||||
inst->native = cls->new_fn(vm);
|
inst->native = cls->new_fn(vm);
|
||||||
} else {
|
} else {
|
||||||
inst->native = NULL;
|
inst->native = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inst->attribs = newMap(vm);
|
||||||
|
|
||||||
vmPopTempRef(vm); // inst.
|
vmPopTempRef(vm); // inst.
|
||||||
return inst;
|
return inst;
|
||||||
}
|
}
|
||||||
|
|
||||||
List* rangeAsList(PKVM* vm, Range* self) {
|
List* rangeAsList(PKVM* vm, Range* self) {
|
||||||
List* list;
|
|
||||||
if (self->from < self->to) {
|
if (self->from < self->to) {
|
||||||
list = newList(vm, (uint32_t)(self->to - self->from));
|
List* list = newList(vm, (uint32_t)(self->to - self->from));
|
||||||
|
vmPushTempRef(vm, &list->_super); // list.
|
||||||
for (double i = self->from; i < self->to; i++) {
|
for (double i = self->from; i < self->to; i++) {
|
||||||
pkVarBufferWrite(&list->elements, vm, VAR_NUM(i));
|
pkVarBufferWrite(&list->elements, vm, VAR_NUM(i));
|
||||||
}
|
}
|
||||||
return list;
|
vmPopTempRef(vm); // list.
|
||||||
|
|
||||||
} else {
|
return list;
|
||||||
list = newList(vm, 0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return list;
|
return newList(vm, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
String* stringLower(PKVM* vm, String* self) {
|
String* stringLower(PKVM* vm, String* self) {
|
||||||
|
@ -27,10 +27,24 @@ void* vmRealloc(PKVM* vm, void* memory, size_t old_size, size_t new_size) {
|
|||||||
// Track the total allocated memory of the VM to trigger the GC.
|
// Track the total allocated memory of the VM to trigger the GC.
|
||||||
// if vmRealloc is called for freeing, the old_size would be 0 since
|
// if vmRealloc is called for freeing, the old_size would be 0 since
|
||||||
// deallocated bytes are traced by garbage collector.
|
// deallocated bytes are traced by garbage collector.
|
||||||
|
//
|
||||||
|
// If we're running a garbage collection, VM's byte allocated will be
|
||||||
|
// re-calculated at vmCollectGarbage() which is equal to the remaining
|
||||||
|
// objects after clening the garbage. And clearing a garbage will
|
||||||
|
// recursively invoke this function so we shouldn't modify it.
|
||||||
|
if (!vm->collecting_garbage) {
|
||||||
vm->bytes_allocated += new_size - old_size;
|
vm->bytes_allocated += new_size - old_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we're garbage collecting no new allocation is allowed.
|
||||||
|
ASSERT(!vm->collecting_garbage || new_size == 0,
|
||||||
|
"No new allocation is allowed while garbage collection is running.");
|
||||||
|
|
||||||
if (new_size > 0 && vm->bytes_allocated > vm->next_gc) {
|
if (new_size > 0 && vm->bytes_allocated > vm->next_gc) {
|
||||||
|
ASSERT(vm->collecting_garbage == false, OOPS);
|
||||||
|
vm->collecting_garbage = true;
|
||||||
vmCollectGarbage(vm);
|
vmCollectGarbage(vm);
|
||||||
|
vm->collecting_garbage = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if TRACE_MEMORY
|
#if TRACE_MEMORY
|
||||||
@ -99,10 +113,6 @@ Module* vmGetModule(PKVM* vm, String* key) {
|
|||||||
|
|
||||||
void vmCollectGarbage(PKVM* vm) {
|
void vmCollectGarbage(PKVM* vm) {
|
||||||
|
|
||||||
// Reset VM's bytes_allocated value and count it again so that we don't
|
|
||||||
// required to know the size of each object that'll be freeing.
|
|
||||||
vm->bytes_allocated = 0;
|
|
||||||
|
|
||||||
// Mark builtin functions.
|
// Mark builtin functions.
|
||||||
for (int i = 0; i < vm->builtins_count; i++) {
|
for (int i = 0; i < vm->builtins_count; i++) {
|
||||||
markObject(vm, &vm->builtins_funcs[i]->_super);
|
markObject(vm, &vm->builtins_funcs[i]->_super);
|
||||||
@ -139,11 +149,23 @@ void vmCollectGarbage(PKVM* vm) {
|
|||||||
markObject(vm, &vm->fiber->_super);
|
markObject(vm, &vm->fiber->_super);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Reset VM's bytes_allocated value and count it again so that we don't
|
||||||
|
// required to know the size of each object that'll be freeing.
|
||||||
|
vm->bytes_allocated = 0;
|
||||||
|
|
||||||
// Pop the marked objects from the working set and push all of it's
|
// Pop the marked objects from the working set and push all of it's
|
||||||
// referenced objects. This will repeat till no more objects left in the
|
// referenced objects. This will repeat till no more objects left in the
|
||||||
// working set.
|
// working set.
|
||||||
popMarkedObjects(vm);
|
popMarkedObjects(vm);
|
||||||
|
|
||||||
|
// Now [vm->bytes_allocated] is equal to the number of bytes allocated for
|
||||||
|
// the root objects which are marked above. Since we're garbage collecting
|
||||||
|
// freeObject() shouldn't modify vm->bytes_allocated. We ensure this by
|
||||||
|
// copying the value to [bytes_allocated] and check after freeing.
|
||||||
|
#ifdef DEBUG
|
||||||
|
size_t bytes_allocated = vm->bytes_allocated;
|
||||||
|
#endif
|
||||||
|
|
||||||
// Now sweep all the un-marked objects in then link list and remove them
|
// Now sweep all the un-marked objects in then link list and remove them
|
||||||
// from the chain.
|
// from the chain.
|
||||||
|
|
||||||
@ -166,6 +188,10 @@ void vmCollectGarbage(PKVM* vm) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef DEBUG
|
||||||
|
ASSERT(bytes_allocated = vm->bytes_allocated, OOPS);
|
||||||
|
#endif
|
||||||
|
|
||||||
// Next GC heap size will be change depends on the byte we've left with now,
|
// Next GC heap size will be change depends on the byte we've left with now,
|
||||||
// and the [heap_fill_percent].
|
// and the [heap_fill_percent].
|
||||||
vm->next_gc = vm->bytes_allocated + (
|
vm->next_gc = vm->bytes_allocated + (
|
||||||
@ -937,7 +963,9 @@ L_vm_main_loop:
|
|||||||
ASSERT_INDEX(index, module->constants.count);
|
ASSERT_INDEX(index, module->constants.count);
|
||||||
ASSERT(IS_OBJ_TYPE(module->constants.data[index], OBJ_FUNC), OOPS);
|
ASSERT(IS_OBJ_TYPE(module->constants.data[index], OBJ_FUNC), OOPS);
|
||||||
Function* fn = (Function*)AS_OBJ(module->constants.data[index]);
|
Function* fn = (Function*)AS_OBJ(module->constants.data[index]);
|
||||||
|
|
||||||
Closure* closure = newClosure(vm, fn);
|
Closure* closure = newClosure(vm, fn);
|
||||||
|
vmPushTempRef(vm, &closure->_super); // closure.
|
||||||
|
|
||||||
// Capture the vaupes.
|
// Capture the vaupes.
|
||||||
for (int i = 0; i < fn->upvalue_count; i++) {
|
for (int i = 0; i < fn->upvalue_count; i++) {
|
||||||
@ -954,6 +982,8 @@ L_vm_main_loop:
|
|||||||
}
|
}
|
||||||
|
|
||||||
PUSH(VAR_OBJ(closure));
|
PUSH(VAR_OBJ(closure));
|
||||||
|
vmPopTempRef(vm); // closure.
|
||||||
|
|
||||||
DISPATCH();
|
DISPATCH();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -69,6 +69,10 @@ struct PKVM {
|
|||||||
// The number of bytes that'll trigger the next GC.
|
// The number of bytes that'll trigger the next GC.
|
||||||
size_t next_gc;
|
size_t next_gc;
|
||||||
|
|
||||||
|
// True if PKVM is running a garbage collection, and no new allocation is
|
||||||
|
// allowed in this phase.
|
||||||
|
bool collecting_garbage;
|
||||||
|
|
||||||
// Minimum size the heap could get.
|
// Minimum size the heap could get.
|
||||||
size_t min_heap_size;
|
size_t min_heap_size;
|
||||||
|
|
||||||
|
@ -8,6 +8,8 @@
|
|||||||
#include "libs.h"
|
#include "libs.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// Standard libraries.
|
||||||
|
|
||||||
void registerModuleMath(PKVM* vm);
|
void registerModuleMath(PKVM* vm);
|
||||||
void registerModuleTypes(PKVM* vm);
|
void registerModuleTypes(PKVM* vm);
|
||||||
void registerModuleTime(PKVM* vm);
|
void registerModuleTime(PKVM* vm);
|
||||||
@ -15,6 +17,7 @@ void registerModuleIO(PKVM* vm);
|
|||||||
void registerModulePath(PKVM* vm);
|
void registerModulePath(PKVM* vm);
|
||||||
void registerModuleDummy(PKVM* vm);
|
void registerModuleDummy(PKVM* vm);
|
||||||
|
|
||||||
|
// Registers the modules.
|
||||||
void registerLibs(PKVM* vm) {
|
void registerLibs(PKVM* vm) {
|
||||||
registerModuleMath(vm);
|
registerModuleMath(vm);
|
||||||
registerModuleTypes(vm);
|
registerModuleTypes(vm);
|
||||||
@ -24,6 +27,6 @@ void registerLibs(PKVM* vm) {
|
|||||||
registerModuleDummy(vm);
|
registerModuleDummy(vm);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Cleanup the modules.
|
||||||
void cleanupLibs(PKVM* vm) {
|
void cleanupLibs(PKVM* vm) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -144,6 +144,10 @@ DEF(_dummyCallMethod,
|
|||||||
if (!pkCallMethod(vm, 1, method, 2, 3, 0)) return;
|
if (!pkCallMethod(vm, 1, method, 2, 3, 0)) return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*****************************************************************************/
|
||||||
|
/* MODULE REGISTER */
|
||||||
|
/*****************************************************************************/
|
||||||
|
|
||||||
void registerModuleDummy(PKVM* vm) {
|
void registerModuleDummy(PKVM* vm) {
|
||||||
|
|
||||||
PkHandle* dummy = pkNewModule(vm, "dummy");
|
PkHandle* dummy = pkNewModule(vm, "dummy");
|
||||||
|
@ -402,6 +402,10 @@ DEF(_fileTell, "") {
|
|||||||
pkSetSlotNumber(vm, 0, (double) ftell(file->fp));
|
pkSetSlotNumber(vm, 0, (double) ftell(file->fp));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*****************************************************************************/
|
||||||
|
/* MODULE REGISTER */
|
||||||
|
/*****************************************************************************/
|
||||||
|
|
||||||
void registerModuleIO(PKVM* vm) {
|
void registerModuleIO(PKVM* vm) {
|
||||||
|
|
||||||
PkHandle* io = pkNewModule(vm, "io");
|
PkHandle* io = pkNewModule(vm, "io");
|
||||||
|
@ -181,6 +181,20 @@ DEF(stdMathRound,
|
|||||||
pkSetSlotNumber(vm, 0, round(num));
|
pkSetSlotNumber(vm, 0, round(num));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DEF(stdMathRand,
|
||||||
|
"rand() -> num\n"
|
||||||
|
"Return a random runber in the range of 0..0x7fff.") {
|
||||||
|
|
||||||
|
// RAND_MAX is implementation dependent but is guaranteed to be at least
|
||||||
|
// 0x7fff on any standard library implementation.
|
||||||
|
// https://www.cplusplus.com/reference/cstdlib/RAND_MAX/
|
||||||
|
pkSetSlotNumber(vm, 0, rand() % 0x7fff);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*****************************************************************************/
|
||||||
|
/* MODULE REGISTER */
|
||||||
|
/*****************************************************************************/
|
||||||
|
|
||||||
void registerModuleMath(PKVM* vm) {
|
void registerModuleMath(PKVM* vm) {
|
||||||
|
|
||||||
PkHandle* math = pkNewModule(vm, "math");
|
PkHandle* math = pkNewModule(vm, "math");
|
||||||
@ -208,6 +222,7 @@ void registerModuleMath(PKVM* vm) {
|
|||||||
pkModuleAddFunction(vm, math, "atan", stdMathArcTangent, 1);
|
pkModuleAddFunction(vm, math, "atan", stdMathArcTangent, 1);
|
||||||
pkModuleAddFunction(vm, math, "log10", stdMathLog10, 1);
|
pkModuleAddFunction(vm, math, "log10", stdMathLog10, 1);
|
||||||
pkModuleAddFunction(vm, math, "round", stdMathRound, 1);
|
pkModuleAddFunction(vm, math, "round", stdMathRound, 1);
|
||||||
|
pkModuleAddFunction(vm, math, "rand", stdMathRand, 0);
|
||||||
|
|
||||||
pkRegisterModule(vm, math);
|
pkRegisterModule(vm, math);
|
||||||
pkReleaseHandle(vm, math);
|
pkReleaseHandle(vm, math);
|
||||||
|
@ -14,7 +14,7 @@
|
|||||||
// Refactor the bellow macro includes.
|
// Refactor the bellow macro includes.
|
||||||
|
|
||||||
#define _CWALK_IMPL
|
#define _CWALK_IMPL
|
||||||
#include "tp_cwalk.h" //<< AMALG_INLINE >>
|
#include "thirdparty/cwalk/cwalk.h" //<< AMALG_INLINE >>
|
||||||
#undef _CWALK_IMPL
|
#undef _CWALK_IMPL
|
||||||
|
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
@ -28,7 +28,7 @@
|
|||||||
#include <direct.h>
|
#include <direct.h>
|
||||||
#include <io.h>
|
#include <io.h>
|
||||||
|
|
||||||
#include "tp_dirent.h" //<< AMALG_INLINE >>
|
#include "thirdparty/dirent/dirent.h" //<< AMALG_INLINE >>
|
||||||
|
|
||||||
// access() function flag defines for windows.
|
// access() function flag defines for windows.
|
||||||
// Reference :https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/access-waccess?view=msvc-170#remarks
|
// Reference :https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/access-waccess?view=msvc-170#remarks
|
||||||
@ -339,6 +339,10 @@ DEF(_pathIsDir, "") {
|
|||||||
pkSetSlotBool(vm, 0, pathIsDir(path));
|
pkSetSlotBool(vm, 0, pathIsDir(path));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*****************************************************************************/
|
||||||
|
/* MODULE REGISTER */
|
||||||
|
/*****************************************************************************/
|
||||||
|
|
||||||
void registerModulePath(PKVM* vm) {
|
void registerModulePath(PKVM* vm) {
|
||||||
PkHandle* path = pkNewModule(vm, "path");
|
PkHandle* path = pkNewModule(vm, "path");
|
||||||
|
|
||||||
|
@ -47,6 +47,10 @@ DEF(_timeSleep,
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*****************************************************************************/
|
||||||
|
/* MODULE REGISTER */
|
||||||
|
/*****************************************************************************/
|
||||||
|
|
||||||
void registerModuleTime(PKVM* vm) {
|
void registerModuleTime(PKVM* vm) {
|
||||||
PkHandle* time = pkNewModule(vm, "time");
|
PkHandle* time = pkNewModule(vm, "time");
|
||||||
|
|
||||||
|
@ -257,7 +257,7 @@ void _vectorRepr(PKVM* vm) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
/* REGISTER TYPES */
|
/* MODULE REGISTER */
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
|
|
||||||
void registerModuleTypes(PKVM* vm) {
|
void registerModuleTypes(PKVM* vm) {
|
||||||
|
21
src/libs/thirdparty/cwalk/LICENSE
vendored
Normal file
21
src/libs/thirdparty/cwalk/LICENSE
vendored
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2020 Leonard Iklé
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in
|
||||||
|
all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
@ -1,27 +1,3 @@
|
|||||||
/*
|
|
||||||
* MIT License
|
|
||||||
*
|
|
||||||
* Copyright (c) 2020 Leonard Iklé
|
|
||||||
*
|
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
* of this software and associated documentation files (the "Software"), to deal
|
|
||||||
* in the Software without restriction, including without limitation the rights
|
|
||||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
* copies of the Software, and to permit persons to whom the Software is
|
|
||||||
* furnished to do so, subject to the following conditions:
|
|
||||||
*
|
|
||||||
* The above copyright notice and this permission notice shall be included in
|
|
||||||
* all copies or substantial portions of the Software.
|
|
||||||
*
|
|
||||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
||||||
* SOFTWARE.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef CWK_LIBRARY_H
|
#ifndef CWK_LIBRARY_H
|
||||||
#define CWK_LIBRARY_H
|
#define CWK_LIBRARY_H
|
||||||
|
|
21
src/libs/thirdparty/dirent/LICENSE
vendored
Normal file
21
src/libs/thirdparty/dirent/LICENSE
vendored
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
The MIT License (MIT)
|
||||||
|
|
||||||
|
Copyright (c) 1998-2019 Toni Ronkko
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in
|
||||||
|
all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
@ -1,27 +1,3 @@
|
|||||||
/*
|
|
||||||
* The MIT License (MIT)
|
|
||||||
*
|
|
||||||
* Copyright (c) 1998-2019 Toni Ronkko
|
|
||||||
*
|
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
* of this software and associated documentation files (the "Software"), to deal
|
|
||||||
* in the Software without restriction, including without limitation the rights
|
|
||||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
* copies of the Software, and to permit persons to whom the Software is
|
|
||||||
* furnished to do so, subject to the following conditions:
|
|
||||||
*
|
|
||||||
* The above copyright notice and this permission notice shall be included in
|
|
||||||
* all copies or substantial portions of the Software.
|
|
||||||
*
|
|
||||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
||||||
* SOFTWARE.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Dirent interface for Microsoft Visual Studio
|
* Dirent interface for Microsoft Visual Studio
|
||||||
*
|
*
|
Loading…
Reference in New Issue
Block a user