1
0
mirror of https://github.com/janet-lang/janet synced 2024-06-26 07:03:16 +00:00

Work on more fixes to calling convention

This commit is contained in:
Calvin Rose 2017-03-14 15:55:50 -04:00
parent 3274e87a45
commit 84b7e96921
6 changed files with 147 additions and 87 deletions

View File

@ -388,7 +388,6 @@ static int form_state(GstParser *p, uint8_t c) {
static void dispatch_char(GstParser *p, uint8_t c) { static void dispatch_char(GstParser *p, uint8_t c) {
int done = 0; int done = 0;
++p->index; ++p->index;
/* Handle comments */ /* Handle comments */
if (p->flags & GST_PARSER_FLAG_INCOMMENT) { if (p->flags & GST_PARSER_FLAG_INCOMMENT) {
if (c == '\n') { if (c == '\n') {
@ -405,7 +404,7 @@ static void dispatch_char(GstParser *p, uint8_t c) {
return; return;
} }
} }
/* Dispatch character to state */
while (!done && p->status == GST_PARSER_PENDING) { while (!done && p->status == GST_PARSER_PENDING) {
GstParseState *top = parser_peek(p); GstParseState *top = parser_peek(p);
switch (top->type) { switch (top->type) {

View File

@ -4,3 +4,9 @@
(a 2) (a 2)
(a 3) (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
View File

@ -46,6 +46,7 @@ int gst_stl_callforeach(Gst *vm) {
if (argCount) { if (argCount) {
for (i = 1; i < argCount; ++i) for (i = 1; i < argCount; ++i)
gst_call(vm, func, 1, vm->thread->data + vm->thread->count + i); gst_call(vm, func, 1, vm->thread->data + vm->thread->count + i);
vm->ret.type = GST_NIL;
return GST_RETURN_OK; return GST_RETURN_OK;
} else { } else {
gst_c_throwc(vm, "expected at least one argument"); gst_c_throwc(vm, "expected at least one argument");

View File

@ -19,10 +19,10 @@ GstThread *gst_thread(Gst *vm, GstValue callee, uint32_t capacity) {
gst_frame_prevsize(stack) = 0; gst_frame_prevsize(stack) = 0;
gst_frame_ret(stack) = 0; gst_frame_ret(stack) = 0;
gst_frame_errloc(stack) = 0; gst_frame_errloc(stack) = 0;
gst_frame_callee(stack) = callee;
gst_frame_pc(stack) = NULL; gst_frame_pc(stack) = NULL;
gst_frame_env(stack) = NULL; gst_frame_env(stack) = NULL;
gst_frame_errjmp(stack) = NULL; gst_frame_errjmp(stack) = NULL;
gst_thread_expand_callable(vm, thread, callee);
gst_thread_endframe(vm, thread); gst_thread_endframe(vm, thread);
return 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 /* Push a stack frame to a thread, with space for arity arguments. Returns the new
* stack. */ * stack. */
GstValue *gst_thread_beginframe(Gst *vm, GstThread *thread, GstValue callee, uint32_t arity) { GstValue *gst_thread_beginframe(Gst *vm, GstThread *thread, GstValue callee, uint32_t arity) {
uint32_t frameOffset, recurCount; uint32_t frameOffset;
GstValue *oldStack, *newStack; GstValue *oldStack, *newStack;
/* Push the frame */ /* Push the frame */
@ -100,43 +139,10 @@ GstValue *gst_thread_beginframe(Gst *vm, GstThread *thread, GstValue callee, uin
gst_frame_size(newStack) = 0; gst_frame_size(newStack) = 0;
thread->count += frameOffset; thread->count += frameOffset;
/* Get the true callee of next stack frame */ /* Get real callable */
recurCount = 200; if (gst_thread_expand_callable(vm, thread, callee) == NULL)
recur: return NULL;
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;
}
}
/* Ensure the extra space and initialize to nil */ /* Ensure the extra space and initialize to nil */
gst_thread_pushnil(vm, thread, arity); gst_thread_pushnil(vm, thread, arity);

View File

@ -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*/ /* Package up extra args after and including n into tuple at n*/
void gst_thread_tuplepack(Gst *vm, GstThread *thread, uint32_t 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 /* Push a stack frame to a thread, with space for arity arguments. Returns the new
* stack. */ * stack. */
GstValue *gst_thread_beginframe(Gst *vm, GstThread *thread, GstValue callee, uint32_t arity); GstValue *gst_thread_beginframe(Gst *vm, GstThread *thread, GstValue callee, uint32_t arity);

134
vm.c
View File

@ -66,7 +66,7 @@ static int gst_continue_size(Gst *vm, uint32_t stackBase) {
temp.data.number = v1.data.number op v2.data.number; \ temp.data.number = v1.data.number op v2.data.number; \
stack[pc[1]] = temp; \ stack[pc[1]] = temp; \
pc += 4; \ pc += 4; \
break; continue;
case GST_OP_ADD: /* Addition */ case GST_OP_ADD: /* Addition */
OP_BINARY_MATH(+) 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]]); temp.data.boolean = !gst_truthy(stack[pc[2]]);
stack[pc[1]] = temp; stack[pc[1]] = temp;
pc += 3; pc += 3;
break; continue;
case GST_OP_NEG: /* Unary negation */ case GST_OP_NEG: /* Unary negation */
v1 = stack[pc[2]]; v1 = stack[pc[2]];
@ -96,7 +96,7 @@ static int gst_continue_size(Gst *vm, uint32_t stackBase) {
temp.data.number = -v1.data.number; temp.data.number = -v1.data.number;
stack[pc[1]] = temp; stack[pc[1]] = temp;
pc += 3; pc += 3;
break; continue;
case GST_OP_INV: /* Unary multiplicative inverse */ case GST_OP_INV: /* Unary multiplicative inverse */
v1 = stack[pc[2]]; 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; temp.data.number = 1 / v1.data.number;
stack[pc[1]] = temp; stack[pc[1]] = temp;
pc += 3; pc += 3;
break; continue;
case GST_OP_FLS: /* Load False */ case GST_OP_FLS: /* Load False */
temp.type = GST_BOOLEAN; temp.type = GST_BOOLEAN;
temp.data.boolean = 0; temp.data.boolean = 0;
stack[pc[1]] = temp; stack[pc[1]] = temp;
pc += 2; pc += 2;
break; continue;
case GST_OP_TRU: /* Load True */ case GST_OP_TRU: /* Load True */
temp.type = GST_BOOLEAN; temp.type = GST_BOOLEAN;
temp.data.boolean = 1; temp.data.boolean = 1;
stack[pc[1]] = temp; stack[pc[1]] = temp;
pc += 2; pc += 2;
break; continue;
case GST_OP_NIL: /* Load Nil */ case GST_OP_NIL: /* Load Nil */
temp.type = GST_NIL; temp.type = GST_NIL;
stack[pc[1]] = temp; stack[pc[1]] = temp;
pc += 2; pc += 2;
break; continue;
case GST_OP_I16: /* Load Small Integer */ case GST_OP_I16: /* Load Small Integer */
temp.type = GST_NUMBER; temp.type = GST_NUMBER;
temp.data.number = ((int16_t *)(pc))[2]; temp.data.number = ((int16_t *)(pc))[2];
stack[pc[1]] = temp; stack[pc[1]] = temp;
pc += 3; pc += 3;
break; continue;
case GST_OP_UPV: /* Load Up Value */ case GST_OP_UPV: /* Load Up Value */
case GST_OP_SUV: /* Set 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; pc += 4;
} }
break; continue;
case GST_OP_JIF: /* Jump If */ case GST_OP_JIF: /* Jump If */
if (gst_truthy(stack[pc[1]])) { if (gst_truthy(stack[pc[1]])) {
@ -171,11 +171,11 @@ static int gst_continue_size(Gst *vm, uint32_t stackBase) {
} else { } else {
pc += *((int32_t *)(pc + 2)); pc += *((int32_t *)(pc + 2));
} }
break; continue;
case GST_OP_JMP: /* Jump */ case GST_OP_JMP: /* Jump */
pc += *((int32_t *)(pc + 1)); pc += *((int32_t *)(pc + 1));
break; continue;
case GST_OP_CST: /* Load constant value */ case GST_OP_CST: /* Load constant value */
v1 = gst_frame_callee(stack); 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); gst_error(vm, GST_NO_UPVALUE);
stack[pc[1]] = v1.data.function->def->literals[pc[2]]; stack[pc[1]] = v1.data.function->def->literals[pc[2]];
pc += 3; pc += 3;
break; continue;
case GST_OP_I32: /* Load 32 bit integer */ case GST_OP_I32: /* Load 32 bit integer */
temp.type = GST_NUMBER; temp.type = GST_NUMBER;
temp.data.number = *((int32_t *)(pc + 2)); temp.data.number = *((int32_t *)(pc + 2));
stack[pc[1]] = temp; stack[pc[1]] = temp;
pc += 4; pc += 4;
break; continue;
case GST_OP_F64: /* Load 64 bit float */ case GST_OP_F64: /* Load 64 bit float */
temp.type = GST_NUMBER; temp.type = GST_NUMBER;
temp.data.number = (GstNumber) *((double *)(pc + 2)); temp.data.number = (GstNumber) *((double *)(pc + 2));
stack[pc[1]] = temp; stack[pc[1]] = temp;
pc += 6; pc += 6;
break; continue;
case GST_OP_MOV: /* Move Values */ case GST_OP_MOV: /* Move Values */
stack[pc[1]] = stack[pc[2]]; stack[pc[1]] = stack[pc[2]];
pc += 3; pc += 3;
break; continue;
case GST_OP_CLN: /* Create closure from constant FuncDef */ 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]]); temp.data.boolean = gst_equals(stack[pc[2]], stack[pc[3]]);
stack[pc[1]] = temp; stack[pc[1]] = temp;
pc += 4; pc += 4;
break; continue;
case GST_OP_LTN: /* Less Than */ case GST_OP_LTN: /* Less Than */
temp.type = GST_BOOLEAN; temp.type = GST_BOOLEAN;
temp.data.boolean = (gst_compare(stack[pc[2]], stack[pc[3]]) == -1); temp.data.boolean = (gst_compare(stack[pc[2]], stack[pc[3]]) == -1);
stack[pc[1]] = temp; stack[pc[1]] = temp;
pc += 4; pc += 4;
break; continue;
case GST_OP_LTE: /* Less Than or Equal to */ case GST_OP_LTE: /* Less Than or Equal to */
temp.type = GST_BOOLEAN; temp.type = GST_BOOLEAN;
temp.data.boolean = (gst_compare(stack[pc[2]], stack[pc[3]]) != 1); temp.data.boolean = (gst_compare(stack[pc[2]], stack[pc[3]]) != 1);
stack[pc[1]] = temp; stack[pc[1]] = temp;
pc += 4; pc += 4;
break; continue;
case GST_OP_ARR: /* Array literal */ case GST_OP_ARR: /* Array literal */
{ {
@ -309,8 +309,8 @@ static int gst_continue_size(Gst *vm, uint32_t stackBase) {
if (err != NULL) if (err != NULL)
gst_error(vm, err); gst_error(vm, err);
pc += 4; pc += 4;
break;
} }
continue;
case GST_OP_SET: /* Associative set */ case GST_OP_SET: /* Associative set */
{ {
@ -319,8 +319,8 @@ static int gst_continue_size(Gst *vm, uint32_t stackBase) {
if (err != NULL) if (err != NULL)
gst_error(vm, err); gst_error(vm, err);
pc += 4; pc += 4;
break;
} }
break;
case GST_OP_ERR: /* Throw error */ case GST_OP_ERR: /* Throw error */
vm->ret = stack[pc[1]]; 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_errloc(stack) = pc[1];
gst_frame_errjmp(stack) = pc + *(uint32_t *)(pc + 2); gst_frame_errjmp(stack) = pc + *(uint32_t *)(pc + 2);
pc += 4; pc += 4;
break; continue;
case GST_OP_UTY: /* End try block */ case GST_OP_UTY: /* End try block */
gst_frame_errjmp(stack) = NULL; gst_frame_errjmp(stack) = NULL;
pc++; pc++;
break; continue;
case GST_OP_RTN: /* Return nil */ case GST_OP_RTN: /* Return nil */
stack = gst_thread_popframe(vm, &thread); stack = gst_thread_popframe(vm, &thread);
if (thread.count < stackBase) { if (thread.count < stackBase) {
vm->ret.type = GST_NIL; vm->ret.type = GST_NIL;
GST_STATE_WRITE();
return GST_RETURN_OK; return GST_RETURN_OK;
} }
pc = gst_frame_pc(stack);
stack[gst_frame_ret(stack)].type = GST_NIL; stack[gst_frame_ret(stack)].type = GST_NIL;
break; continue;
case GST_OP_RET: /* Return */ case GST_OP_RET: /* Return */
temp = stack[pc[1]]; temp = stack[pc[1]];
stack = gst_thread_popframe(vm, &thread); stack = gst_thread_popframe(vm, &thread);
if (thread.count < stackBase) { if (thread.count < stackBase) {
vm->ret = temp; vm->ret = temp;
GST_STATE_WRITE();
return GST_RETURN_OK; return GST_RETURN_OK;
} }
pc = gst_frame_pc(stack);
stack[gst_frame_ret(stack)] = temp; stack[gst_frame_ret(stack)] = temp;
break; continue;
case GST_OP_CAL: /* Call */ case GST_OP_CAL: /* Call */
case GST_OP_TCL: /* Tail call */ case GST_OP_TCL: /* Tail call */
{ {
GstValue *oldStack; GstValue *oldStack;
temp = stack[pc[1]]; temp = stack[pc[1]];
int isTCall = *pc == GST_OP_TCL;
uint32_t i, arity, offset, size; uint32_t i, arity, offset, size;
uint16_t ret = pc[2]; uint16_t ret = pc[2];
offset = (*pc == GST_OP_CAL) ? 4 : 3; offset = isTCall ? 3 : 4;
arity = pc[offset - 1]; arity = pc[offset - 1];
/* Push new frame */ /* Push new frame */
stack = gst_thread_beginframe(vm, &thread, temp, arity); 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 */ /* Finish new frame */
gst_thread_endframe(vm, &thread); gst_thread_endframe(vm, &thread);
/* Check tail call - if so, replace frame. */ /* Check tail call - if so, replace frame. */
if (*pc == GST_OP_TCL) { if (isTCall) {
stack = gst_thread_tail(vm, &thread); stack = gst_thread_tail(vm, &thread);
} else { } else {
gst_frame_ret(oldStack) = ret; gst_frame_ret(oldStack) = ret;
@ -384,7 +389,8 @@ static int gst_continue_size(Gst *vm, uint32_t stackBase) {
temp = gst_frame_callee(stack); temp = gst_frame_callee(stack);
if (temp.type == GST_FUNCTION) { if (temp.type == GST_FUNCTION) {
/* Save pc and set new pc */ /* 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; pc = temp.data.function->def->byteCode;
} else { } else {
int status; int status;
@ -393,12 +399,17 @@ static int gst_continue_size(Gst *vm, uint32_t stackBase) {
status = temp.data.cfunction(vm); status = temp.data.cfunction(vm);
GST_STATE_SYNC(); GST_STATE_SYNC();
stack = gst_thread_popframe(vm, &thread); stack = gst_thread_popframe(vm, &thread);
pc += offset + arity;
if (status == GST_RETURN_OK) if (status == GST_RETURN_OK)
if (thread.count < stackBase) if (thread.count < stackBase) {
GST_STATE_WRITE();
return status; return status;
else } else {
stack[gst_frame_ret(stack)] = vm->ret; stack[gst_frame_ret(stack)] = vm->ret;
if (isTCall)
pc = gst_frame_pc(stack);
else
pc += offset + arity;
}
else else
goto vm_error; goto vm_error;
} }
@ -416,7 +427,7 @@ static int gst_continue_size(Gst *vm, uint32_t stackBase) {
stack[gst_frame_errloc(stack)] = vm->ret; stack[gst_frame_errloc(stack)] = vm->ret;
break; break;
} /* end switch */ } /* end switch */
/* TODO: Move collection only to places that allocate memory */ /* TODO: Move collection only to places that allocate memory */
/* This, however, is good for testing to ensure no memory leaks */ /* 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 */ /* Run the vm with a given function */
int gst_run(Gst *vm, GstValue callee) { 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; GstValue *stack;
uint32_t i; vm->thread = gst_thread(vm, callee, 64);
stack = gst_thread_beginframe(vm, vm->thread, callee, arity); if (vm->thread == NULL)
for (i = 0; i < arity; ++i) return GST_RETURN_CRASH;
stack[i] = args[i]; stack = gst_thread_stack(vm->thread);
gst_thread_endframe(vm, vm->thread); /* If callee was not actually a function, get the delegate function */
callee = gst_frame_callee(stack); callee = gst_frame_callee(stack);
if (callee.type == GST_FUNCTION) { if (callee.type == GST_CFUNCTION) {
return gst_continue(vm);
} else {
int status; int status;
vm->ret.type = GST_NIL; vm->ret.type = GST_NIL;
status = callee.data.cfunction(vm); status = callee.data.cfunction(vm);
gst_thread_popframe(vm, vm->thread); gst_thread_popframe(vm, vm->thread);
return status; 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 */ /* Get an argument from the stack */