mirror of
https://github.com/janet-lang/janet
synced 2024-12-23 23:10:26 +00:00
Work on more fixes to calling convention
This commit is contained in:
parent
3274e87a45
commit
84b7e96921
3
parse.c
3
parse.c
@ -388,7 +388,6 @@ static int form_state(GstParser *p, uint8_t c) {
|
||||
static void dispatch_char(GstParser *p, uint8_t c) {
|
||||
int done = 0;
|
||||
++p->index;
|
||||
|
||||
/* Handle comments */
|
||||
if (p->flags & GST_PARSER_FLAG_INCOMMENT) {
|
||||
if (c == '\n') {
|
||||
@ -405,7 +404,7 @@ static void dispatch_char(GstParser *p, uint8_t c) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* Dispatch character to state */
|
||||
while (!done && p->status == GST_PARSER_PENDING) {
|
||||
GstParseState *top = parser_peek(p);
|
||||
switch (top->type) {
|
||||
|
@ -4,3 +4,9 @@
|
||||
(a 2)
|
||||
(a 3)
|
||||
)
|
||||
|
||||
# Run call-for-each test
|
||||
|
||||
(call-for-each print 1 2 3 4)
|
||||
|
||||
(call-for-each (fn [a] (print a "hi")) 1 2 3 45)
|
||||
|
1
stl.c
1
stl.c
@ -46,6 +46,7 @@ int gst_stl_callforeach(Gst *vm) {
|
||||
if (argCount) {
|
||||
for (i = 1; i < argCount; ++i)
|
||||
gst_call(vm, func, 1, vm->thread->data + vm->thread->count + i);
|
||||
vm->ret.type = GST_NIL;
|
||||
return GST_RETURN_OK;
|
||||
} else {
|
||||
gst_c_throwc(vm, "expected at least one argument");
|
||||
|
84
thread.c
84
thread.c
@ -19,10 +19,10 @@ GstThread *gst_thread(Gst *vm, GstValue callee, uint32_t capacity) {
|
||||
gst_frame_prevsize(stack) = 0;
|
||||
gst_frame_ret(stack) = 0;
|
||||
gst_frame_errloc(stack) = 0;
|
||||
gst_frame_callee(stack) = callee;
|
||||
gst_frame_pc(stack) = NULL;
|
||||
gst_frame_env(stack) = NULL;
|
||||
gst_frame_errjmp(stack) = NULL;
|
||||
gst_thread_expand_callable(vm, thread, callee);
|
||||
gst_thread_endframe(vm, thread);
|
||||
return thread;
|
||||
}
|
||||
@ -83,10 +83,49 @@ void gst_thread_tuplepack(Gst *vm, GstThread *thread, uint32_t n) {
|
||||
}
|
||||
}
|
||||
|
||||
/* Expand a callee on the stack frame to its delegate function. This means that
|
||||
* objects and userdata that have a "call" attribut in their class will be
|
||||
* replaced with their delegate function. Call this before pushing any
|
||||
* arguments to the stack. Returns the new stack. */
|
||||
GstValue *gst_thread_expand_callable(Gst *vm, GstThread *thread, GstValue callee) {
|
||||
uint32_t i;
|
||||
GstValue *stack;
|
||||
GstObject *meta;
|
||||
for (i = 0; i < 200; ++i) {
|
||||
switch(callee.type) {
|
||||
default:
|
||||
return NULL;
|
||||
case GST_FUNCTION:
|
||||
stack = thread->data + thread->count;
|
||||
gst_frame_callee(stack) = callee;
|
||||
gst_frame_pc(stack) = callee.data.function->def->byteCode;
|
||||
return stack;
|
||||
case GST_CFUNCTION:
|
||||
stack = thread->data + thread->count;
|
||||
gst_frame_callee(stack) = callee;
|
||||
gst_frame_pc(stack) = NULL;
|
||||
return stack;
|
||||
case GST_OBJECT:
|
||||
meta = callee.data.object->meta;
|
||||
if (meta == NULL) return NULL;
|
||||
gst_thread_push(vm, thread, callee);
|
||||
callee = gst_object_get_cstring(meta, "call");
|
||||
continue;
|
||||
case GST_USERDATA:
|
||||
meta = ((GstUserdataHeader *)callee.data.pointer - 1)->meta;
|
||||
gst_thread_push(vm, thread, callee);
|
||||
callee = gst_object_get_cstring(meta, "call");
|
||||
continue;
|
||||
}
|
||||
}
|
||||
/* Callables nested to deeply */
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Push a stack frame to a thread, with space for arity arguments. Returns the new
|
||||
* stack. */
|
||||
GstValue *gst_thread_beginframe(Gst *vm, GstThread *thread, GstValue callee, uint32_t arity) {
|
||||
uint32_t frameOffset, recurCount;
|
||||
uint32_t frameOffset;
|
||||
GstValue *oldStack, *newStack;
|
||||
|
||||
/* Push the frame */
|
||||
@ -100,43 +139,10 @@ GstValue *gst_thread_beginframe(Gst *vm, GstThread *thread, GstValue callee, uin
|
||||
gst_frame_size(newStack) = 0;
|
||||
thread->count += frameOffset;
|
||||
|
||||
/* Get the true callee of next stack frame */
|
||||
recurCount = 200;
|
||||
recur:
|
||||
if (!recurCount) {
|
||||
return NULL;
|
||||
}
|
||||
switch(callee.type) {
|
||||
default: return NULL;
|
||||
case GST_FUNCTION:
|
||||
gst_frame_callee(newStack) = callee;
|
||||
gst_frame_pc(newStack) = callee.data.function->def->byteCode;
|
||||
break;
|
||||
case GST_CFUNCTION:
|
||||
gst_frame_callee(newStack) = callee;
|
||||
gst_frame_pc(newStack) = NULL;
|
||||
break;
|
||||
case GST_OBJECT:
|
||||
{
|
||||
GstObject *meta = callee.data.object->meta;
|
||||
if (meta == NULL) return NULL;
|
||||
gst_thread_push(vm, thread, callee);
|
||||
callee = gst_object_get_cstring(meta, "call");
|
||||
newStack = thread->data + thread->count;
|
||||
--recurCount;
|
||||
goto recur;
|
||||
}
|
||||
case GST_USERDATA:
|
||||
{
|
||||
GstObject *meta = ((GstUserdataHeader *)callee.data.pointer - 1)->meta;
|
||||
gst_thread_push(vm, thread, callee);
|
||||
callee = gst_object_get_cstring(meta, "call");
|
||||
newStack = thread->data + thread->count;
|
||||
--recurCount;
|
||||
goto recur;
|
||||
}
|
||||
}
|
||||
|
||||
/* Get real callable */
|
||||
if (gst_thread_expand_callable(vm, thread, callee) == NULL)
|
||||
return NULL;
|
||||
|
||||
/* Ensure the extra space and initialize to nil */
|
||||
gst_thread_pushnil(vm, thread, arity);
|
||||
|
||||
|
6
thread.h
6
thread.h
@ -21,6 +21,12 @@ void gst_thread_pushnil(Gst *vm, GstThread *thread, uint32_t n);
|
||||
/* Package up extra args after and including n into tuple at n*/
|
||||
void gst_thread_tuplepack(Gst *vm, GstThread *thread, uint32_t n);
|
||||
|
||||
/* Expand a callee on the stack frame to its delegate function. This means that
|
||||
* objects and userdata that have a "call" attribut in their class will be
|
||||
* replaced with their delegate function. Call this before pushing any
|
||||
* arguments to the stack. Returns the new stack. */
|
||||
GstValue *gst_thread_expand_callable(Gst *vm, GstThread *thread, GstValue callee);
|
||||
|
||||
/* Push a stack frame to a thread, with space for arity arguments. Returns the new
|
||||
* stack. */
|
||||
GstValue *gst_thread_beginframe(Gst *vm, GstThread *thread, GstValue callee, uint32_t arity);
|
||||
|
134
vm.c
134
vm.c
@ -66,7 +66,7 @@ static int gst_continue_size(Gst *vm, uint32_t stackBase) {
|
||||
temp.data.number = v1.data.number op v2.data.number; \
|
||||
stack[pc[1]] = temp; \
|
||||
pc += 4; \
|
||||
break;
|
||||
continue;
|
||||
|
||||
case GST_OP_ADD: /* Addition */
|
||||
OP_BINARY_MATH(+)
|
||||
@ -87,7 +87,7 @@ static int gst_continue_size(Gst *vm, uint32_t stackBase) {
|
||||
temp.data.boolean = !gst_truthy(stack[pc[2]]);
|
||||
stack[pc[1]] = temp;
|
||||
pc += 3;
|
||||
break;
|
||||
continue;
|
||||
|
||||
case GST_OP_NEG: /* Unary negation */
|
||||
v1 = stack[pc[2]];
|
||||
@ -96,7 +96,7 @@ static int gst_continue_size(Gst *vm, uint32_t stackBase) {
|
||||
temp.data.number = -v1.data.number;
|
||||
stack[pc[1]] = temp;
|
||||
pc += 3;
|
||||
break;
|
||||
continue;
|
||||
|
||||
case GST_OP_INV: /* Unary multiplicative inverse */
|
||||
v1 = stack[pc[2]];
|
||||
@ -105,34 +105,34 @@ static int gst_continue_size(Gst *vm, uint32_t stackBase) {
|
||||
temp.data.number = 1 / v1.data.number;
|
||||
stack[pc[1]] = temp;
|
||||
pc += 3;
|
||||
break;
|
||||
continue;
|
||||
|
||||
case GST_OP_FLS: /* Load False */
|
||||
temp.type = GST_BOOLEAN;
|
||||
temp.data.boolean = 0;
|
||||
stack[pc[1]] = temp;
|
||||
pc += 2;
|
||||
break;
|
||||
continue;
|
||||
|
||||
case GST_OP_TRU: /* Load True */
|
||||
temp.type = GST_BOOLEAN;
|
||||
temp.data.boolean = 1;
|
||||
stack[pc[1]] = temp;
|
||||
pc += 2;
|
||||
break;
|
||||
continue;
|
||||
|
||||
case GST_OP_NIL: /* Load Nil */
|
||||
temp.type = GST_NIL;
|
||||
stack[pc[1]] = temp;
|
||||
pc += 2;
|
||||
break;
|
||||
continue;
|
||||
|
||||
case GST_OP_I16: /* Load Small Integer */
|
||||
temp.type = GST_NUMBER;
|
||||
temp.data.number = ((int16_t *)(pc))[2];
|
||||
stack[pc[1]] = temp;
|
||||
pc += 3;
|
||||
break;
|
||||
continue;
|
||||
|
||||
case GST_OP_UPV: /* Load Up Value */
|
||||
case GST_OP_SUV: /* Set Up Value */
|
||||
@ -163,7 +163,7 @@ static int gst_continue_size(Gst *vm, uint32_t stackBase) {
|
||||
}
|
||||
pc += 4;
|
||||
}
|
||||
break;
|
||||
continue;
|
||||
|
||||
case GST_OP_JIF: /* Jump If */
|
||||
if (gst_truthy(stack[pc[1]])) {
|
||||
@ -171,11 +171,11 @@ static int gst_continue_size(Gst *vm, uint32_t stackBase) {
|
||||
} else {
|
||||
pc += *((int32_t *)(pc + 2));
|
||||
}
|
||||
break;
|
||||
continue;
|
||||
|
||||
case GST_OP_JMP: /* Jump */
|
||||
pc += *((int32_t *)(pc + 1));
|
||||
break;
|
||||
continue;
|
||||
|
||||
case GST_OP_CST: /* Load constant value */
|
||||
v1 = gst_frame_callee(stack);
|
||||
@ -184,26 +184,26 @@ static int gst_continue_size(Gst *vm, uint32_t stackBase) {
|
||||
gst_error(vm, GST_NO_UPVALUE);
|
||||
stack[pc[1]] = v1.data.function->def->literals[pc[2]];
|
||||
pc += 3;
|
||||
break;
|
||||
continue;
|
||||
|
||||
case GST_OP_I32: /* Load 32 bit integer */
|
||||
temp.type = GST_NUMBER;
|
||||
temp.data.number = *((int32_t *)(pc + 2));
|
||||
stack[pc[1]] = temp;
|
||||
pc += 4;
|
||||
break;
|
||||
continue;
|
||||
|
||||
case GST_OP_F64: /* Load 64 bit float */
|
||||
temp.type = GST_NUMBER;
|
||||
temp.data.number = (GstNumber) *((double *)(pc + 2));
|
||||
stack[pc[1]] = temp;
|
||||
pc += 6;
|
||||
break;
|
||||
continue;
|
||||
|
||||
case GST_OP_MOV: /* Move Values */
|
||||
stack[pc[1]] = stack[pc[2]];
|
||||
pc += 3;
|
||||
break;
|
||||
continue;
|
||||
|
||||
case GST_OP_CLN: /* Create closure from constant FuncDef */
|
||||
{
|
||||
@ -239,21 +239,21 @@ static int gst_continue_size(Gst *vm, uint32_t stackBase) {
|
||||
temp.data.boolean = gst_equals(stack[pc[2]], stack[pc[3]]);
|
||||
stack[pc[1]] = temp;
|
||||
pc += 4;
|
||||
break;
|
||||
continue;
|
||||
|
||||
case GST_OP_LTN: /* Less Than */
|
||||
temp.type = GST_BOOLEAN;
|
||||
temp.data.boolean = (gst_compare(stack[pc[2]], stack[pc[3]]) == -1);
|
||||
stack[pc[1]] = temp;
|
||||
pc += 4;
|
||||
break;
|
||||
continue;
|
||||
|
||||
case GST_OP_LTE: /* Less Than or Equal to */
|
||||
temp.type = GST_BOOLEAN;
|
||||
temp.data.boolean = (gst_compare(stack[pc[2]], stack[pc[3]]) != 1);
|
||||
stack[pc[1]] = temp;
|
||||
pc += 4;
|
||||
break;
|
||||
continue;
|
||||
|
||||
case GST_OP_ARR: /* Array literal */
|
||||
{
|
||||
@ -309,8 +309,8 @@ static int gst_continue_size(Gst *vm, uint32_t stackBase) {
|
||||
if (err != NULL)
|
||||
gst_error(vm, err);
|
||||
pc += 4;
|
||||
break;
|
||||
}
|
||||
continue;
|
||||
|
||||
case GST_OP_SET: /* Associative set */
|
||||
{
|
||||
@ -319,8 +319,8 @@ static int gst_continue_size(Gst *vm, uint32_t stackBase) {
|
||||
if (err != NULL)
|
||||
gst_error(vm, err);
|
||||
pc += 4;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case GST_OP_ERR: /* Throw error */
|
||||
vm->ret = stack[pc[1]];
|
||||
@ -330,40 +330,45 @@ static int gst_continue_size(Gst *vm, uint32_t stackBase) {
|
||||
gst_frame_errloc(stack) = pc[1];
|
||||
gst_frame_errjmp(stack) = pc + *(uint32_t *)(pc + 2);
|
||||
pc += 4;
|
||||
break;
|
||||
continue;
|
||||
|
||||
case GST_OP_UTY: /* End try block */
|
||||
gst_frame_errjmp(stack) = NULL;
|
||||
pc++;
|
||||
break;
|
||||
continue;
|
||||
|
||||
case GST_OP_RTN: /* Return nil */
|
||||
stack = gst_thread_popframe(vm, &thread);
|
||||
if (thread.count < stackBase) {
|
||||
vm->ret.type = GST_NIL;
|
||||
GST_STATE_WRITE();
|
||||
return GST_RETURN_OK;
|
||||
}
|
||||
pc = gst_frame_pc(stack);
|
||||
stack[gst_frame_ret(stack)].type = GST_NIL;
|
||||
break;
|
||||
continue;
|
||||
|
||||
case GST_OP_RET: /* Return */
|
||||
temp = stack[pc[1]];
|
||||
stack = gst_thread_popframe(vm, &thread);
|
||||
if (thread.count < stackBase) {
|
||||
vm->ret = temp;
|
||||
GST_STATE_WRITE();
|
||||
return GST_RETURN_OK;
|
||||
}
|
||||
pc = gst_frame_pc(stack);
|
||||
stack[gst_frame_ret(stack)] = temp;
|
||||
break;
|
||||
continue;
|
||||
|
||||
case GST_OP_CAL: /* Call */
|
||||
case GST_OP_TCL: /* Tail call */
|
||||
{
|
||||
GstValue *oldStack;
|
||||
temp = stack[pc[1]];
|
||||
int isTCall = *pc == GST_OP_TCL;
|
||||
uint32_t i, arity, offset, size;
|
||||
uint16_t ret = pc[2];
|
||||
offset = (*pc == GST_OP_CAL) ? 4 : 3;
|
||||
offset = isTCall ? 3 : 4;
|
||||
arity = pc[offset - 1];
|
||||
/* Push new frame */
|
||||
stack = gst_thread_beginframe(vm, &thread, temp, arity);
|
||||
@ -375,7 +380,7 @@ static int gst_continue_size(Gst *vm, uint32_t stackBase) {
|
||||
/* Finish new frame */
|
||||
gst_thread_endframe(vm, &thread);
|
||||
/* Check tail call - if so, replace frame. */
|
||||
if (*pc == GST_OP_TCL) {
|
||||
if (isTCall) {
|
||||
stack = gst_thread_tail(vm, &thread);
|
||||
} else {
|
||||
gst_frame_ret(oldStack) = ret;
|
||||
@ -384,7 +389,8 @@ static int gst_continue_size(Gst *vm, uint32_t stackBase) {
|
||||
temp = gst_frame_callee(stack);
|
||||
if (temp.type == GST_FUNCTION) {
|
||||
/* Save pc and set new pc */
|
||||
gst_frame_pc(oldStack) = pc + offset + arity;
|
||||
if (!isTCall)
|
||||
gst_frame_pc(oldStack) = pc + offset + arity;
|
||||
pc = temp.data.function->def->byteCode;
|
||||
} else {
|
||||
int status;
|
||||
@ -393,12 +399,17 @@ static int gst_continue_size(Gst *vm, uint32_t stackBase) {
|
||||
status = temp.data.cfunction(vm);
|
||||
GST_STATE_SYNC();
|
||||
stack = gst_thread_popframe(vm, &thread);
|
||||
pc += offset + arity;
|
||||
if (status == GST_RETURN_OK)
|
||||
if (thread.count < stackBase)
|
||||
if (thread.count < stackBase) {
|
||||
GST_STATE_WRITE();
|
||||
return status;
|
||||
else
|
||||
} else {
|
||||
stack[gst_frame_ret(stack)] = vm->ret;
|
||||
if (isTCall)
|
||||
pc = gst_frame_pc(stack);
|
||||
else
|
||||
pc += offset + arity;
|
||||
}
|
||||
else
|
||||
goto vm_error;
|
||||
}
|
||||
@ -416,7 +427,7 @@ static int gst_continue_size(Gst *vm, uint32_t stackBase) {
|
||||
stack[gst_frame_errloc(stack)] = vm->ret;
|
||||
break;
|
||||
|
||||
} /* end switch */
|
||||
} /* end switch */
|
||||
|
||||
/* TODO: Move collection only to places that allocate memory */
|
||||
/* This, however, is good for testing to ensure no memory leaks */
|
||||
@ -434,28 +445,59 @@ int gst_continue(Gst *vm) {
|
||||
|
||||
/* Run the vm with a given function */
|
||||
int gst_run(Gst *vm, GstValue callee) {
|
||||
vm->thread = gst_thread(vm, callee, 64);
|
||||
return gst_continue(vm);
|
||||
}
|
||||
|
||||
/* Call a gst function */
|
||||
int gst_call(Gst *vm, GstValue callee, uint32_t arity, GstValue *args) {
|
||||
GstValue *stack;
|
||||
uint32_t i;
|
||||
stack = gst_thread_beginframe(vm, vm->thread, callee, arity);
|
||||
for (i = 0; i < arity; ++i)
|
||||
stack[i] = args[i];
|
||||
gst_thread_endframe(vm, vm->thread);
|
||||
callee = gst_frame_callee(stack);
|
||||
if (callee.type == GST_FUNCTION) {
|
||||
return gst_continue(vm);
|
||||
} else {
|
||||
vm->thread = gst_thread(vm, callee, 64);
|
||||
if (vm->thread == NULL)
|
||||
return GST_RETURN_CRASH;
|
||||
stack = gst_thread_stack(vm->thread);
|
||||
/* If callee was not actually a function, get the delegate function */
|
||||
callee = gst_frame_callee(stack);
|
||||
if (callee.type == GST_CFUNCTION) {
|
||||
int status;
|
||||
vm->ret.type = GST_NIL;
|
||||
status = callee.data.cfunction(vm);
|
||||
gst_thread_popframe(vm, vm->thread);
|
||||
return status;
|
||||
} else {
|
||||
return gst_continue(vm);
|
||||
}
|
||||
}
|
||||
|
||||
/* Call a gst function */
|
||||
int gst_call(Gst *vm, GstValue callee, uint32_t arity, GstValue *args) {
|
||||
GstValue *stack;
|
||||
uint32_t i, size;
|
||||
int status;
|
||||
|
||||
/* Set the return position */
|
||||
stack = gst_thread_stack(vm->thread);
|
||||
gst_frame_ret(stack) = gst_frame_size(stack);
|
||||
|
||||
/* Add extra space for returning value */
|
||||
gst_thread_pushnil(vm, vm->thread, 1);
|
||||
stack = gst_thread_beginframe(vm, vm->thread, callee, arity);
|
||||
|
||||
/* Write args to stack */
|
||||
size = gst_frame_size(stack) - arity;
|
||||
for (i = 0; i < arity; ++i)
|
||||
stack[i + size] = args[i];
|
||||
gst_thread_endframe(vm, vm->thread);
|
||||
|
||||
/* Call function */
|
||||
callee = gst_frame_callee(stack);
|
||||
if (callee.type == GST_FUNCTION) {
|
||||
gst_frame_pc(stack) = callee.data.function->def->byteCode;
|
||||
status = gst_continue(vm);
|
||||
} else {
|
||||
vm->ret.type = GST_NIL;
|
||||
status = callee.data.cfunction(vm);
|
||||
gst_thread_popframe(vm, vm->thread);
|
||||
}
|
||||
|
||||
/* Pop the extra nil */
|
||||
--gst_frame_size(gst_thread_stack(vm->thread));
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/* Get an argument from the stack */
|
||||
|
Loading…
Reference in New Issue
Block a user