mirror of
https://github.com/janet-lang/janet
synced 2024-06-25 22:53:16 +00:00
Work on simplifying calling procedure
This commit is contained in:
parent
15dd15278c
commit
3274e87a45
4
Makefile
4
Makefile
|
@ -6,8 +6,8 @@ TARGET=interp
|
||||||
PREFIX=/usr/local
|
PREFIX=/usr/local
|
||||||
|
|
||||||
# C sources
|
# C sources
|
||||||
HEADERS=vm.h ds.h compile.h parse.h value.h datatypes.h gc.h util.h gst.h stl.h disasm.h
|
HEADERS=vm.h ds.h compile.h parse.h value.h datatypes.h gc.h util.h gst.h stl.h disasm.h thread.h
|
||||||
SOURCES=main.c parse.c value.c vm.c ds.c compile.c gc.c stl.c disasm.c
|
SOURCES=main.c parse.c value.c vm.c ds.c compile.c gc.c stl.c disasm.c thread.c
|
||||||
OBJECTS=$(patsubst %.c,%.o,$(SOURCES))
|
OBJECTS=$(patsubst %.c,%.o,$(SOURCES))
|
||||||
|
|
||||||
all: $(TARGET)
|
all: $(TARGET)
|
||||||
|
|
12
compile.c
12
compile.c
|
@ -1246,22 +1246,22 @@ static Slot compile_form(GstCompiler *c, FormOptions opts, GstValue *form) {
|
||||||
/* Free up some slots */
|
/* Free up some slots */
|
||||||
compiler_drop_slot(c, scope, callee);
|
compiler_drop_slot(c, scope, callee);
|
||||||
compiler_tracker_free(c, scope, &tracker);
|
compiler_tracker_free(c, scope, &tracker);
|
||||||
/* Push arguments to stack */
|
|
||||||
gst_buffer_push_u16(c->vm, buffer, GST_OP_PSH);
|
|
||||||
gst_buffer_push_u16(c->vm, buffer, callee.index);
|
|
||||||
gst_buffer_push_u16(c->vm, buffer, gst_tuple_length(form) - 1);
|
|
||||||
/* Write the location of all of the arguments */
|
|
||||||
compiler_tracker_write(c, &tracker, 0);
|
|
||||||
/* If this is in tail position do a tail call. */
|
/* If this is in tail position do a tail call. */
|
||||||
if (opts.isTail) {
|
if (opts.isTail) {
|
||||||
gst_buffer_push_u16(c->vm, buffer, GST_OP_TCL);
|
gst_buffer_push_u16(c->vm, buffer, GST_OP_TCL);
|
||||||
|
gst_buffer_push_u16(c->vm, buffer, callee.index);
|
||||||
|
gst_buffer_push_u16(c->vm, buffer, gst_tuple_length(form) - 1);
|
||||||
ret.hasReturned = 1;
|
ret.hasReturned = 1;
|
||||||
ret.isNil = 1;
|
ret.isNil = 1;
|
||||||
} else {
|
} else {
|
||||||
ret = compiler_get_target(c, opts);
|
ret = compiler_get_target(c, opts);
|
||||||
gst_buffer_push_u16(c->vm, buffer, GST_OP_CAL);
|
gst_buffer_push_u16(c->vm, buffer, GST_OP_CAL);
|
||||||
|
gst_buffer_push_u16(c->vm, buffer, callee.index);
|
||||||
gst_buffer_push_u16(c->vm, buffer, ret.index);
|
gst_buffer_push_u16(c->vm, buffer, ret.index);
|
||||||
|
gst_buffer_push_u16(c->vm, buffer, gst_tuple_length(form) - 1);
|
||||||
}
|
}
|
||||||
|
/* Write the location of all of the arguments */
|
||||||
|
compiler_tracker_write(c, &tracker, 0);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -165,8 +165,6 @@ struct Gst {
|
||||||
/* Return state */
|
/* Return state */
|
||||||
const char *crash;
|
const char *crash;
|
||||||
GstValue ret; /* Returned value from gst_start. Also holds errors. */
|
GstValue ret; /* Returned value from gst_start. Also holds errors. */
|
||||||
/* Temporary array for use in function dispatch */
|
|
||||||
GstValue tempArray[GST_MAX_SEARCH_DEPTH];
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Bytecode */
|
/* Bytecode */
|
||||||
|
@ -210,7 +208,6 @@ enum GstOpCode {
|
||||||
GST_OP_UTY, /* End try block */
|
GST_OP_UTY, /* End try block */
|
||||||
GST_OP_RET, /* Return from function */
|
GST_OP_RET, /* Return from function */
|
||||||
GST_OP_RTN, /* Return nil */
|
GST_OP_RTN, /* Return nil */
|
||||||
GST_OP_PSH, /* Push a stack frame */
|
|
||||||
GST_OP_CAL, /* Call function */
|
GST_OP_CAL, /* Call function */
|
||||||
GST_OP_TCL /* Tail call */
|
GST_OP_TCL /* Tail call */
|
||||||
};
|
};
|
||||||
|
|
7
disasm.c
7
disasm.c
|
@ -193,14 +193,11 @@ void gst_dasm(FILE * out, uint16_t *byteCode, uint32_t len) {
|
||||||
case GST_OP_RTN:
|
case GST_OP_RTN:
|
||||||
current += dasm_fixed_op(out, current, "returnNil", 0);
|
current += dasm_fixed_op(out, current, "returnNil", 0);
|
||||||
break;
|
break;
|
||||||
case GST_OP_PSH:
|
|
||||||
current += dasm_varg_op(out, current, "push", 1);
|
|
||||||
break;
|
|
||||||
case GST_OP_CAL:
|
case GST_OP_CAL:
|
||||||
current += dasm_fixed_op(out, current, "call", 1);
|
current += dasm_varg_op(out, current, "call", 2);
|
||||||
break;
|
break;
|
||||||
case GST_OP_TCL:
|
case GST_OP_TCL:
|
||||||
current += dasm_fixed_op(out, current, "tailCall", 0);
|
current += dasm_varg_op(out, current, "tailCall", 1);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
fprintf(out, "\n");
|
fprintf(out, "\n");
|
||||||
|
|
1
gst.h
1
gst.h
|
@ -8,5 +8,6 @@
|
||||||
#include "compile.h"
|
#include "compile.h"
|
||||||
#include "value.h"
|
#include "value.h"
|
||||||
#include "stl.h"
|
#include "stl.h"
|
||||||
|
#include "thread.h"
|
||||||
|
|
||||||
#endif // gst_h_INCLUDED
|
#endif // gst_h_INCLUDED
|
||||||
|
|
7
main.c
7
main.c
|
@ -48,7 +48,7 @@ void debug_repl(FILE *in, FILE *out) {
|
||||||
if (out) {
|
if (out) {
|
||||||
fprintf(out, "\n");
|
fprintf(out, "\n");
|
||||||
fprintf(out, "%s\n", buffer);
|
fprintf(out, "%s\n", buffer);
|
||||||
for (i = 0; i < p.index; ++i) {
|
for (i = 1; i < p.index; ++i) {
|
||||||
fprintf(out, " ");
|
fprintf(out, " ");
|
||||||
}
|
}
|
||||||
fprintf(out, "^\n");
|
fprintf(out, "^\n");
|
||||||
|
@ -78,7 +78,10 @@ void debug_repl(FILE *in, FILE *out) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Print asm */
|
/* Print asm */
|
||||||
/* gst_dasm_function(stdout, func.data.function); */
|
//if (out) {
|
||||||
|
//fprintf(out, "\n");
|
||||||
|
//gst_dasm_function(out, func.data.function);
|
||||||
|
//}
|
||||||
|
|
||||||
/* Execute function */
|
/* Execute function */
|
||||||
if (gst_run(&vm, func)) {
|
if (gst_run(&vm, func)) {
|
||||||
|
|
20
sample.gst
20
sample.gst
|
@ -1,18 +1,6 @@
|
||||||
# GST is a general purpose language. It is small, not slow, and supports meta-
|
|
||||||
# programming. It also should be structured and static enough to easily scale to
|
|
||||||
# large programs. Lastly, it is interoperable with C and C++.
|
|
||||||
|
|
||||||
# Syntax - There is very little syntax. This simplifies parsing and makes macros
|
|
||||||
# easier to implement, which are useful in metaprogramming.
|
|
||||||
(+ 1 2 3)
|
|
||||||
|
|
||||||
# Unlike most lisps, it is not a pure functional language. Also unlike lisp, gst does
|
|
||||||
# not make much use of a list data structure, instead using arrays and objects for
|
|
||||||
# better performance at runtime.
|
|
||||||
(do
|
(do
|
||||||
(:= a 1)
|
(:= a (set-class {} {"call" (fn [self a] (set self "last" a) (print self) self)}))
|
||||||
(while (< a 1025)
|
(a 1)
|
||||||
(print a)
|
(a 2)
|
||||||
(:= a (* a 2))
|
(a 3)
|
||||||
)
|
|
||||||
)
|
)
|
||||||
|
|
4
stl.c
4
stl.c
|
@ -44,8 +44,8 @@ int gst_stl_callforeach(Gst *vm) {
|
||||||
uint32_t argCount = gst_count_args(vm);
|
uint32_t argCount = gst_count_args(vm);
|
||||||
uint32_t i;
|
uint32_t i;
|
||||||
if (argCount) {
|
if (argCount) {
|
||||||
for (i = 0; i < argCount - 1; ++i)
|
for (i = 1; i < argCount; ++i)
|
||||||
gst_call(vm, func, 1, vm->thread->data + vm->thread->count + 1 + i);
|
gst_call(vm, func, 1, vm->thread->data + vm->thread->count + i);
|
||||||
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");
|
||||||
|
|
233
thread.c
Normal file
233
thread.c
Normal file
|
@ -0,0 +1,233 @@
|
||||||
|
#include "datatypes.h"
|
||||||
|
#include "thread.h"
|
||||||
|
#include "vm.h"
|
||||||
|
#include "util.h"
|
||||||
|
#include "ds.h"
|
||||||
|
|
||||||
|
/* Create a new thread */
|
||||||
|
GstThread *gst_thread(Gst *vm, GstValue callee, uint32_t capacity) {
|
||||||
|
GstThread *thread = gst_alloc(vm, sizeof(GstThread));
|
||||||
|
GstValue *data, *stack;
|
||||||
|
if (capacity < GST_FRAME_SIZE) capacity = GST_FRAME_SIZE;
|
||||||
|
data = gst_alloc(vm, sizeof(GstValue) * capacity);
|
||||||
|
thread->capacity = capacity;
|
||||||
|
thread->count = GST_FRAME_SIZE;
|
||||||
|
thread->data = data;
|
||||||
|
thread->status = GST_THREAD_PENDING;
|
||||||
|
stack = data + GST_FRAME_SIZE;
|
||||||
|
gst_frame_size(stack) = 0;
|
||||||
|
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_endframe(vm, thread);
|
||||||
|
return thread;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Ensure that the thread has enough EXTRA capacity */
|
||||||
|
void gst_thread_ensure_extra(Gst *vm, GstThread *thread, uint32_t extra) {
|
||||||
|
GstValue *newData, *stack;
|
||||||
|
uint32_t usedCapacity, neededCapacity, newCapacity;
|
||||||
|
stack = thread->data + thread->count;
|
||||||
|
usedCapacity = thread->count + gst_frame_size(stack) + GST_FRAME_SIZE;
|
||||||
|
neededCapacity = usedCapacity + extra;
|
||||||
|
if (thread->capacity >= neededCapacity) return;
|
||||||
|
newCapacity = 2 * neededCapacity;
|
||||||
|
newData = gst_alloc(vm, sizeof(GstValue) * newCapacity);
|
||||||
|
gst_memcpy(newData, thread->data, sizeof(GstValue) * usedCapacity);
|
||||||
|
thread->data = newData;
|
||||||
|
thread->capacity = newCapacity;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Push a value on the current stack frame*/
|
||||||
|
void gst_thread_push(Gst *vm, GstThread *thread, GstValue x) {
|
||||||
|
GstValue *stack;
|
||||||
|
gst_thread_ensure_extra(vm, thread, 1);
|
||||||
|
stack = thread->data + thread->count;
|
||||||
|
stack[gst_frame_size(stack)++] = x;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Push n nils onto the stack */
|
||||||
|
void gst_thread_pushnil(Gst *vm, GstThread *thread, uint32_t n) {
|
||||||
|
GstValue *stack, *current, *end;
|
||||||
|
gst_thread_ensure_extra(vm, thread, n);
|
||||||
|
stack = thread->data + thread->count;
|
||||||
|
current = stack + gst_frame_size(stack);
|
||||||
|
end = current + n;
|
||||||
|
for (; current < end; ++current) {
|
||||||
|
current->type = GST_NIL;
|
||||||
|
}
|
||||||
|
gst_frame_size(stack) += n;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Package up extra args after and including n into tuple at n*/
|
||||||
|
void gst_thread_tuplepack(Gst *vm, GstThread *thread, uint32_t n) {
|
||||||
|
GstValue *stack = thread->data + thread->count;
|
||||||
|
uint32_t size = gst_frame_size(stack);
|
||||||
|
if (n >= size) {
|
||||||
|
gst_thread_pushnil(vm, thread, n - size + 1);
|
||||||
|
stack = thread->data + thread->count;
|
||||||
|
stack[n].type = GST_TUPLE;
|
||||||
|
stack[n].data.tuple = gst_tuple(vm, 0);
|
||||||
|
} else {
|
||||||
|
uint32_t i;
|
||||||
|
GstValue *tuple = gst_tuple(vm, size - n);
|
||||||
|
for (i = n; i < size; ++i)
|
||||||
|
tuple[i - n] = stack[i];
|
||||||
|
stack[n].type = GST_TUPLE;
|
||||||
|
stack[n].data.tuple = tuple;
|
||||||
|
gst_frame_size(stack) = n + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 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;
|
||||||
|
GstValue *oldStack, *newStack;
|
||||||
|
|
||||||
|
/* Push the frame */
|
||||||
|
gst_thread_ensure_extra(vm, thread, GST_FRAME_SIZE + arity + 4);
|
||||||
|
oldStack = thread->data + thread->count;
|
||||||
|
frameOffset = gst_frame_size(oldStack) + GST_FRAME_SIZE;
|
||||||
|
newStack = oldStack + frameOffset;
|
||||||
|
gst_frame_prevsize(newStack) = gst_frame_size(oldStack);
|
||||||
|
gst_frame_env(newStack) = NULL;
|
||||||
|
gst_frame_errjmp(newStack) = NULL;
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Ensure the extra space and initialize to nil */
|
||||||
|
gst_thread_pushnil(vm, thread, arity);
|
||||||
|
|
||||||
|
/* Return ok */
|
||||||
|
return thread->data + thread->count;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* After pushing arguments to a stack frame created with gst_thread_beginframe, call this
|
||||||
|
* to finalize the frame before starting a function call. */
|
||||||
|
void gst_thread_endframe(Gst *vm, GstThread *thread) {
|
||||||
|
GstValue *stack = thread->data + thread->count;
|
||||||
|
GstValue callee = gst_frame_callee(stack);
|
||||||
|
if (callee.type == GST_FUNCTION) {
|
||||||
|
GstFunction *fn = callee.data.function;
|
||||||
|
gst_frame_pc(stack) = fn->def->byteCode;
|
||||||
|
if (fn->def->flags & GST_FUNCDEF_FLAG_VARARG) {
|
||||||
|
uint32_t arity = fn->def->arity;
|
||||||
|
gst_thread_tuplepack(vm, thread, arity);
|
||||||
|
} else {
|
||||||
|
uint32_t locals = fn->def->locals;
|
||||||
|
if (gst_frame_size(stack) < locals) {
|
||||||
|
gst_thread_pushnil(vm, thread, locals - gst_frame_size(stack));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Pop a stack frame from the thread. Returns the new stack frame, or
|
||||||
|
* NULL if there are no more frames */
|
||||||
|
GstValue *gst_thread_popframe(Gst *vm, GstThread *thread) {
|
||||||
|
GstValue *stack = thread->data + thread->count;
|
||||||
|
uint32_t prevsize = gst_frame_prevsize(stack);
|
||||||
|
GstValue *nextstack = stack - GST_FRAME_SIZE - prevsize;
|
||||||
|
GstFuncEnv *env = gst_frame_env(stack);
|
||||||
|
|
||||||
|
/* Check for closures */
|
||||||
|
if (env != NULL) {
|
||||||
|
uint32_t size = gst_frame_size(stack);
|
||||||
|
env->thread = NULL;
|
||||||
|
env->stackOffset = size;
|
||||||
|
env->values = gst_alloc(vm, sizeof(GstValue) * size);
|
||||||
|
gst_memcpy(env->values, stack, sizeof(GstValue) * size);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Shrink stack */
|
||||||
|
thread->count -= GST_FRAME_SIZE + prevsize;
|
||||||
|
|
||||||
|
/* Check if the stack is empty, and if so, return null */
|
||||||
|
if (thread->count)
|
||||||
|
return nextstack;
|
||||||
|
else
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Move the current stack frame over its parent stack frame, allowing
|
||||||
|
* for primitive tail calls. */
|
||||||
|
GstValue *gst_thread_tail(Gst *vm, GstThread *thread) {
|
||||||
|
GstFuncEnv *env;
|
||||||
|
GstValue *stack = thread->data + thread->count;
|
||||||
|
GstValue *nextStack = gst_thread_popframe(vm, thread);
|
||||||
|
uint32_t i;
|
||||||
|
|
||||||
|
if (nextStack == NULL) return NULL;
|
||||||
|
env = gst_frame_env(nextStack);
|
||||||
|
|
||||||
|
/* Check for old closures */
|
||||||
|
if (env != NULL) {
|
||||||
|
uint32_t size = gst_frame_size(stack);
|
||||||
|
env->thread = NULL;
|
||||||
|
env->stackOffset = size;
|
||||||
|
env->values = gst_alloc(vm, sizeof(GstValue) * size);
|
||||||
|
gst_memcpy(env->values, stack, sizeof(GstValue) * size);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Modify new closure */
|
||||||
|
env = gst_frame_env(stack);
|
||||||
|
if (env != NULL) {
|
||||||
|
env->stackOffset = thread->count;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Copy over (some of) stack frame. Leave ret and prevsize untouched. */
|
||||||
|
gst_frame_env(nextStack) = env;
|
||||||
|
gst_frame_size(nextStack) = gst_frame_size(stack);
|
||||||
|
gst_frame_pc(nextStack) = gst_frame_pc(stack);
|
||||||
|
gst_frame_errjmp(nextStack) = gst_frame_errjmp(stack);
|
||||||
|
gst_frame_errloc(nextStack) = gst_frame_errloc(stack);
|
||||||
|
gst_frame_callee(nextStack) = gst_frame_callee(stack);
|
||||||
|
|
||||||
|
/* Copy stack arguments */
|
||||||
|
for (i = 0; i < gst_frame_size(nextStack); ++i)
|
||||||
|
nextStack[i] = stack[i];
|
||||||
|
|
||||||
|
return nextStack;
|
||||||
|
}
|
41
thread.h
Normal file
41
thread.h
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
#ifndef thread_h_INCLUDED
|
||||||
|
#define thread_h_INCLUDED
|
||||||
|
|
||||||
|
#include "datatypes.h"
|
||||||
|
|
||||||
|
/* Get the current stack frame */
|
||||||
|
#define gst_thread_stack(t) ((t)->data + (t)->count)
|
||||||
|
|
||||||
|
/* Create a new thread */
|
||||||
|
GstThread *gst_thread(Gst *vm, GstValue callee, uint32_t capacity);
|
||||||
|
|
||||||
|
/* Ensure that the thread has enough EXTRA capacity */
|
||||||
|
void gst_thread_ensure_extra(Gst *vm, GstThread *thread, uint32_t extra);
|
||||||
|
|
||||||
|
/* Push a value on the current stack frame*/
|
||||||
|
void gst_thread_push(Gst *vm, GstThread *thread, GstValue x);
|
||||||
|
|
||||||
|
/* Push n nils onto the stack */
|
||||||
|
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);
|
||||||
|
|
||||||
|
/* 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);
|
||||||
|
|
||||||
|
/* After pushing arguments to a stack frame created with gst_thread_beginframe, call this
|
||||||
|
* to finalize the frame before starting a function call. */
|
||||||
|
void gst_thread_endframe(Gst *vm, GstThread *thread);
|
||||||
|
|
||||||
|
/* Pop a stack frame from the thread. Returns the new stack frame, or
|
||||||
|
* NULL if there are no more frames */
|
||||||
|
GstValue *gst_thread_popframe(Gst *vm, GstThread *thread);
|
||||||
|
|
||||||
|
/* Move the current stack frame over its parent stack frame, allowing
|
||||||
|
* for primitive tail calls. Return new stack. */
|
||||||
|
GstValue *gst_thread_tail(Gst *vm, GstThread *thread);
|
||||||
|
|
||||||
|
#endif // thread_h_INCLUDED
|
||||||
|
|
2
util.h
2
util.h
|
@ -51,7 +51,7 @@
|
||||||
/* Size of stack frame in number of values */
|
/* Size of stack frame in number of values */
|
||||||
#define GST_FRAME_SIZE 5
|
#define GST_FRAME_SIZE 5
|
||||||
|
|
||||||
/* Macros for referencing that a stack frame given a stack */
|
/* Macros for referencing a stack frame given a stack */
|
||||||
#define gst_frame_callee(s) (*(s - 1))
|
#define gst_frame_callee(s) (*(s - 1))
|
||||||
#define gst_frame_size(s) ((s - 2)->data.hws[0])
|
#define gst_frame_size(s) ((s - 2)->data.hws[0])
|
||||||
#define gst_frame_prevsize(s) ((s - 2)->data.hws[1])
|
#define gst_frame_prevsize(s) ((s - 2)->data.hws[1])
|
||||||
|
|
393
vm.c
393
vm.c
|
@ -3,6 +3,7 @@
|
||||||
#include "value.h"
|
#include "value.h"
|
||||||
#include "ds.h"
|
#include "ds.h"
|
||||||
#include "gc.h"
|
#include "gc.h"
|
||||||
|
#include "thread.h"
|
||||||
|
|
||||||
/* Macros for errors in the vm */
|
/* Macros for errors in the vm */
|
||||||
|
|
||||||
|
@ -23,40 +24,6 @@ static const char GST_EXPECTED_FUNCTION[] = "expected function";
|
||||||
static const char GST_EXPECTED_NUMBER_ROP[] = "expected right operand to be number";
|
static const char GST_EXPECTED_NUMBER_ROP[] = "expected right operand to be number";
|
||||||
static const char GST_EXPECTED_NUMBER_LOP[] = "expected left operand to be number";
|
static const char GST_EXPECTED_NUMBER_LOP[] = "expected left operand to be number";
|
||||||
|
|
||||||
/* Load a function into the VM. The function will be called with
|
|
||||||
* no arguments when run */
|
|
||||||
static void gst_load(Gst *vm, GstValue callee) {
|
|
||||||
uint32_t startCapacity;
|
|
||||||
uint32_t locals, i;
|
|
||||||
uint16_t *pc;
|
|
||||||
GstValue *stack;
|
|
||||||
GstThread *thread = gst_alloc(vm, sizeof(GstThread));
|
|
||||||
if (callee.type == GST_FUNCTION) {
|
|
||||||
locals = callee.data.function->def->locals;
|
|
||||||
pc = callee.data.function->def->byteCode;
|
|
||||||
} else if (callee.type == GST_CFUNCTION) {
|
|
||||||
locals = 0;
|
|
||||||
pc = NULL;
|
|
||||||
} else {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
startCapacity = locals + GST_FRAME_SIZE + 10;
|
|
||||||
thread->data = gst_alloc(vm, sizeof(GstValue) * startCapacity);
|
|
||||||
thread->capacity = startCapacity;
|
|
||||||
thread->count = GST_FRAME_SIZE;
|
|
||||||
vm->thread = thread;
|
|
||||||
stack = thread->data + GST_FRAME_SIZE;
|
|
||||||
gst_frame_prevsize(stack) = 0;
|
|
||||||
gst_frame_size(stack) = locals;
|
|
||||||
gst_frame_callee(stack) = callee;
|
|
||||||
gst_frame_env(stack) = NULL;
|
|
||||||
gst_frame_errjmp(stack) = NULL;
|
|
||||||
gst_frame_pc(stack) = pc;
|
|
||||||
/* Nil arguments */
|
|
||||||
for (i = 0; i < locals; ++i)
|
|
||||||
stack[i].type = GST_NIL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Contextual macro to state in function with VM */
|
/* Contextual macro to state in function with VM */
|
||||||
#define GST_STATE_SYNC() do { \
|
#define GST_STATE_SYNC() do { \
|
||||||
thread = *vm->thread; \
|
thread = *vm->thread; \
|
||||||
|
@ -358,7 +325,6 @@ static int gst_continue_size(Gst *vm, uint32_t stackBase) {
|
||||||
case GST_OP_ERR: /* Throw error */
|
case GST_OP_ERR: /* Throw error */
|
||||||
vm->ret = stack[pc[1]];
|
vm->ret = stack[pc[1]];
|
||||||
goto vm_error;
|
goto vm_error;
|
||||||
break;
|
|
||||||
|
|
||||||
case GST_OP_TRY: /* Begin try block */
|
case GST_OP_TRY: /* Begin try block */
|
||||||
gst_frame_errloc(stack) = pc[1];
|
gst_frame_errloc(stack) = pc[1];
|
||||||
|
@ -372,201 +338,84 @@ static int gst_continue_size(Gst *vm, uint32_t stackBase) {
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case GST_OP_RTN: /* Return nil */
|
case GST_OP_RTN: /* Return nil */
|
||||||
vm->ret.type = GST_NIL;
|
stack = gst_thread_popframe(vm, &thread);
|
||||||
goto ret;
|
if (thread.count < stackBase) {
|
||||||
|
vm->ret.type = GST_NIL;
|
||||||
|
return GST_RETURN_OK;
|
||||||
|
}
|
||||||
|
stack[gst_frame_ret(stack)].type = GST_NIL;
|
||||||
|
break;
|
||||||
|
|
||||||
case GST_OP_RET: /* Return */
|
case GST_OP_RET: /* Return */
|
||||||
vm->ret = stack[pc[1]];
|
temp = stack[pc[1]];
|
||||||
goto ret;
|
stack = gst_thread_popframe(vm, &thread);
|
||||||
|
if (thread.count < stackBase) {
|
||||||
case GST_OP_PSH: /* Push stack frame */
|
vm->ret = temp;
|
||||||
{
|
return GST_RETURN_OK;
|
||||||
GstValue *nextStack;
|
|
||||||
uint32_t argSlots, fullArgSlots, arity, prefixCount, varArgs, tupleCount, i, locals, nextCount;
|
|
||||||
|
|
||||||
/* Get arguments to op */
|
|
||||||
temp = stack[pc[1]];
|
|
||||||
arity = pc[2];
|
|
||||||
|
|
||||||
/* Get the size of next stack frame */
|
|
||||||
prefixCount = 0;
|
|
||||||
recur:
|
|
||||||
switch(temp.type) {
|
|
||||||
default: gst_error(vm, GST_EXPECTED_FUNCTION);
|
|
||||||
case GST_FUNCTION:
|
|
||||||
{
|
|
||||||
GstFunction *fn = temp.data.function;
|
|
||||||
locals = fn->def->locals;
|
|
||||||
varArgs = fn->def->flags & GST_FUNCDEF_FLAG_VARARG;
|
|
||||||
argSlots = fn->def->arity;
|
|
||||||
if (arity + prefixCount > argSlots) {
|
|
||||||
fullArgSlots = argSlots;
|
|
||||||
tupleCount = arity + prefixCount - fullArgSlots;
|
|
||||||
} else {
|
|
||||||
fullArgSlots = arity + prefixCount;
|
|
||||||
tupleCount = 0;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case GST_CFUNCTION:
|
|
||||||
{
|
|
||||||
locals = argSlots = fullArgSlots = arity + prefixCount;
|
|
||||||
varArgs = tupleCount = 0;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case GST_OBJECT:
|
|
||||||
{
|
|
||||||
GstObject *meta = temp.data.object->meta;
|
|
||||||
if (meta == NULL) gst_error(vm, GST_EXPECTED_FUNCTION);
|
|
||||||
vm->tempArray[prefixCount++] = temp;
|
|
||||||
temp = gst_object_get_cstring(meta, "call");
|
|
||||||
goto recur;
|
|
||||||
}
|
|
||||||
case GST_USERDATA:
|
|
||||||
{
|
|
||||||
GstObject *meta = ((GstUserdataHeader *)temp.data.pointer - 1)->meta;
|
|
||||||
vm->tempArray[prefixCount++] = temp;
|
|
||||||
temp = gst_object_get_cstring(meta, "call");
|
|
||||||
goto recur;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Get next frame size */
|
|
||||||
nextCount = thread.count + gst_frame_size(stack) + GST_FRAME_SIZE;
|
|
||||||
|
|
||||||
/* Ensure capacity */
|
|
||||||
if (nextCount + locals > thread.capacity) {
|
|
||||||
uint32_t newCap = (nextCount + locals) * 2;
|
|
||||||
GstValue *newData = gst_alloc(vm, sizeof(GstValue) * newCap);
|
|
||||||
gst_memcpy(newData, thread.data, thread.capacity * sizeof(GstValue));
|
|
||||||
thread.data = newData;
|
|
||||||
thread.capacity = newCap;
|
|
||||||
stack = thread.data + thread.count;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Set up the new stack frame */
|
|
||||||
nextStack = thread.data + nextCount;
|
|
||||||
gst_frame_prevsize(nextStack) = gst_frame_size(stack);
|
|
||||||
gst_frame_size(nextStack) = locals;
|
|
||||||
gst_frame_ret(nextStack) = 0;
|
|
||||||
gst_frame_env(nextStack) = NULL;
|
|
||||||
gst_frame_callee(nextStack) = temp;
|
|
||||||
gst_frame_errjmp(nextStack) = NULL;
|
|
||||||
|
|
||||||
/* Write prefix args to stack */
|
|
||||||
for (i = 0; i < prefixCount; ++i)
|
|
||||||
nextStack[i] = vm->tempArray[i];
|
|
||||||
|
|
||||||
/* Write arguments to new stack */
|
|
||||||
for (; i < fullArgSlots; ++i)
|
|
||||||
nextStack[i] = stack[pc[3 + i - prefixCount]];
|
|
||||||
|
|
||||||
/* Clear rest of stack */
|
|
||||||
for (; i < locals; ++i)
|
|
||||||
nextStack[i].type = GST_NIL;
|
|
||||||
|
|
||||||
/* Check for varargs and put them in a tuple */
|
|
||||||
if (varArgs) {
|
|
||||||
GstValue *tuple;
|
|
||||||
uint32_t j;
|
|
||||||
tuple = gst_tuple(vm, tupleCount);
|
|
||||||
for (j = argSlots; j < arity; ++j)
|
|
||||||
if (j < prefixCount)
|
|
||||||
tuple[j - argSlots] = vm->tempArray[j - prefixCount];
|
|
||||||
else
|
|
||||||
tuple[j - argSlots] = stack[pc[3 + j - prefixCount]];
|
|
||||||
nextStack[argSlots].type = GST_TUPLE;
|
|
||||||
nextStack[argSlots].data.tuple = tuple;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Increment pc */
|
|
||||||
pc += 3 + arity;
|
|
||||||
}
|
}
|
||||||
|
stack[gst_frame_ret(stack)] = temp;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case GST_OP_CAL: /* Call */
|
case GST_OP_CAL: /* Call */
|
||||||
case GST_OP_TCL: /* Tail call */
|
case GST_OP_TCL: /* Tail call */
|
||||||
if (pc[0] == GST_OP_CAL) {
|
{
|
||||||
gst_frame_ret(stack) = pc[1];
|
GstValue *oldStack;
|
||||||
gst_frame_pc(stack) = pc + 2;
|
temp = stack[pc[1]];
|
||||||
thread.count += gst_frame_size(stack) + GST_FRAME_SIZE;
|
uint32_t i, arity, offset, size;
|
||||||
stack = thread.data + thread.count;
|
uint16_t ret = pc[2];
|
||||||
} else {
|
offset = (*pc == GST_OP_CAL) ? 4 : 3;
|
||||||
uint32_t i;
|
arity = pc[offset - 1];
|
||||||
GstValue *nextStack = stack + gst_frame_size(stack) + GST_FRAME_SIZE;
|
/* Push new frame */
|
||||||
uint32_t nextSize = gst_frame_size(nextStack);
|
stack = gst_thread_beginframe(vm, &thread, temp, arity);
|
||||||
/* Check for closures */
|
oldStack = stack - GST_FRAME_SIZE - gst_frame_prevsize(stack);
|
||||||
if (gst_frame_env(stack) != NULL) {
|
/* Write arguments */
|
||||||
gst_frame_env(stack)->thread = NULL;
|
size = gst_frame_size(stack);
|
||||||
gst_frame_env(stack)->stackOffset = gst_frame_size(stack);
|
for (i = 0; i < arity; ++i)
|
||||||
gst_frame_env(stack)->values = gst_alloc(vm, sizeof(GstValue) * gst_frame_size(stack));
|
stack[i + size - arity] = oldStack[pc[offset + i]];
|
||||||
gst_memcpy(gst_frame_env(stack)->values,
|
/* Finish new frame */
|
||||||
thread.data + thread.count,
|
gst_thread_endframe(vm, &thread);
|
||||||
gst_frame_size(stack) * sizeof(GstValue));
|
/* Check tail call - if so, replace frame. */
|
||||||
}
|
if (*pc == GST_OP_TCL) {
|
||||||
/* Copy over most of stack frame */
|
stack = gst_thread_tail(vm, &thread);
|
||||||
gst_frame_callee(stack) = gst_frame_callee(nextStack);
|
} else {
|
||||||
gst_frame_size(stack) = gst_frame_size(nextStack);
|
gst_frame_ret(oldStack) = ret;
|
||||||
gst_frame_env(stack) = NULL;
|
}
|
||||||
gst_frame_errjmp(stack) = NULL;
|
/* Call function */
|
||||||
/* Replace current stack frame with next */
|
temp = gst_frame_callee(stack);
|
||||||
for (i = 0; i < nextSize; ++i)
|
if (temp.type == GST_FUNCTION) {
|
||||||
stack[i] = nextStack[i];
|
/* Save pc and set new pc */
|
||||||
}
|
gst_frame_pc(oldStack) = pc + offset + arity;
|
||||||
v1 = gst_frame_callee(stack);
|
pc = temp.data.function->def->byteCode;
|
||||||
if (v1.type == GST_FUNCTION) {
|
} else {
|
||||||
pc = v1.data.function->def->byteCode;
|
int status;
|
||||||
} else if (v1.type == GST_CFUNCTION) {
|
GST_STATE_WRITE();
|
||||||
int status;
|
vm->ret.type = GST_NIL;
|
||||||
GST_STATE_WRITE();
|
status = temp.data.cfunction(vm);
|
||||||
vm->ret.type = GST_NIL;
|
GST_STATE_SYNC();
|
||||||
status = v1.data.cfunction(vm);
|
stack = gst_thread_popframe(vm, &thread);
|
||||||
GST_STATE_SYNC();
|
pc += offset + arity;
|
||||||
if (status == GST_RETURN_OK)
|
if (status == GST_RETURN_OK)
|
||||||
goto ret;
|
if (thread.count < stackBase)
|
||||||
else
|
return status;
|
||||||
goto vm_error;
|
else
|
||||||
} else {
|
stack[gst_frame_ret(stack)] = vm->ret;
|
||||||
gst_error(vm, GST_EXPECTED_FUNCTION);
|
else
|
||||||
}
|
goto vm_error;
|
||||||
break;
|
}
|
||||||
|
}
|
||||||
/* Macro for popping stack frame */
|
break;
|
||||||
#define pop_frame(onUnderflow) do { \
|
|
||||||
if (gst_frame_env(stack) != NULL) { \
|
|
||||||
gst_frame_env(stack)->thread = NULL; \
|
|
||||||
gst_frame_env(stack)->stackOffset = gst_frame_size(stack); \
|
|
||||||
gst_frame_env(stack)->values = gst_alloc(vm, sizeof(GstValue) * gst_frame_size(stack)); \
|
|
||||||
gst_memcpy(gst_frame_env(stack)->values, \
|
|
||||||
thread.data + thread.count, \
|
|
||||||
gst_frame_size(stack) * sizeof(GstValue)); \
|
|
||||||
} \
|
|
||||||
if (thread.count <= stackBase) { \
|
|
||||||
thread.count -= gst_frame_prevsize(stack) + GST_FRAME_SIZE; \
|
|
||||||
return (onUnderflow); \
|
|
||||||
} \
|
|
||||||
thread.count -= gst_frame_prevsize(stack) + GST_FRAME_SIZE; \
|
|
||||||
stack = thread.data + thread.count; \
|
|
||||||
} while (0)
|
|
||||||
|
|
||||||
/* Label for return */
|
|
||||||
ret:
|
|
||||||
/* Check for closure */
|
|
||||||
pop_frame(GST_RETURN_OK);
|
|
||||||
pc = gst_frame_pc(stack);
|
|
||||||
stack[gst_frame_ret(stack)] = vm->ret;
|
|
||||||
break;
|
|
||||||
|
|
||||||
/* Handle errors from c functions and vm opcodes */
|
/* Handle errors from c functions and vm opcodes */
|
||||||
vm_error:
|
vm_error:
|
||||||
while (gst_frame_errjmp(stack) == NULL)
|
while (gst_frame_errjmp(stack) == NULL) {
|
||||||
pop_frame(GST_RETURN_ERROR);
|
stack = gst_thread_popframe(vm, &thread);
|
||||||
|
if (thread.count < stackBase)
|
||||||
|
return GST_RETURN_ERROR;
|
||||||
|
}
|
||||||
pc = gst_frame_errjmp(stack);
|
pc = gst_frame_errjmp(stack);
|
||||||
stack[gst_frame_errloc(stack)] = vm->ret;
|
stack[gst_frame_errloc(stack)] = vm->ret;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
#undef pop_frame
|
|
||||||
|
|
||||||
} /* end switch */
|
} /* end switch */
|
||||||
|
|
||||||
/* TODO: Move collection only to places that allocate memory */
|
/* TODO: Move collection only to places that allocate memory */
|
||||||
|
@ -584,106 +433,34 @@ 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 func) {
|
int gst_run(Gst *vm, GstValue callee) {
|
||||||
gst_load(vm, func);
|
vm->thread = gst_thread(vm, callee, 64);
|
||||||
return gst_continue(vm);
|
return gst_continue(vm);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Raw function call implementation for use from c code. Beware code
|
/* Call a gst function */
|
||||||
* duplication between this function and GST_OP_PSH and GST_OP_CAL/GST_OP_TCL */
|
|
||||||
int gst_call(Gst *vm, GstValue callee, uint32_t arity, GstValue *args) {
|
int gst_call(Gst *vm, GstValue callee, uint32_t arity, GstValue *args) {
|
||||||
GstThread thread;
|
|
||||||
GstValue *stack;
|
GstValue *stack;
|
||||||
uint32_t expectedArity, normalArity, varArgs, i, locals, nextCount, size;
|
uint32_t i;
|
||||||
|
stack = gst_thread_beginframe(vm, vm->thread, callee, arity);
|
||||||
/* Initialize some state */
|
for (i = 0; i < arity; ++i)
|
||||||
GST_STATE_SYNC();
|
|
||||||
|
|
||||||
/* Get the size of next stack frame */
|
|
||||||
if (callee.type == GST_FUNCTION) {
|
|
||||||
GstFunction *fn = callee.data.function;
|
|
||||||
locals = fn->def->locals;
|
|
||||||
varArgs = fn->def->flags & GST_FUNCDEF_FLAG_VARARG;
|
|
||||||
expectedArity = fn->def->arity;
|
|
||||||
gst_frame_pc(stack) = fn->def->byteCode;
|
|
||||||
if (arity > expectedArity)
|
|
||||||
normalArity = expectedArity;
|
|
||||||
else
|
|
||||||
normalArity = arity;
|
|
||||||
} else if (callee.type == GST_CFUNCTION) {
|
|
||||||
locals = normalArity = expectedArity = arity;
|
|
||||||
varArgs = 0;
|
|
||||||
} else {
|
|
||||||
gst_c_throwc(vm, GST_EXPECTED_FUNCTION);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Get next frame size */
|
|
||||||
nextCount = thread.count + gst_frame_size(stack) + GST_FRAME_SIZE;
|
|
||||||
|
|
||||||
/* Ensure capacity */
|
|
||||||
if (nextCount + locals > thread.capacity) {
|
|
||||||
uint32_t newCap = (nextCount + locals) * 2;
|
|
||||||
GstValue *newData = gst_alloc(vm, sizeof(GstValue) * newCap);
|
|
||||||
gst_memcpy(newData, thread.data, thread.capacity * sizeof(GstValue));
|
|
||||||
thread.data = newData;
|
|
||||||
thread.capacity = newCap;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Save modified thread object */
|
|
||||||
thread.count = nextCount;
|
|
||||||
*vm->thread = thread;
|
|
||||||
|
|
||||||
/* Set up the new stack frame */
|
|
||||||
size = gst_frame_size(stack);
|
|
||||||
stack = thread.data + nextCount;
|
|
||||||
gst_frame_prevsize(stack) = size;
|
|
||||||
gst_frame_size(stack) = locals;
|
|
||||||
gst_frame_env(stack) = NULL;
|
|
||||||
gst_frame_callee(stack) = callee;
|
|
||||||
gst_frame_errjmp(stack) = NULL;
|
|
||||||
|
|
||||||
/* Write arguments to new stack */
|
|
||||||
for (i = 0; i < normalArity; ++i)
|
|
||||||
stack[i] = args[i];
|
stack[i] = args[i];
|
||||||
|
gst_thread_endframe(vm, vm->thread);
|
||||||
/* Clear stack */
|
callee = gst_frame_callee(stack);
|
||||||
for (; i < locals; ++i)
|
if (callee.type == GST_FUNCTION) {
|
||||||
stack[i].type = GST_NIL;
|
return gst_continue(vm);
|
||||||
|
} else {
|
||||||
/* Check for varargs and put them in a tuple */
|
int status;
|
||||||
if (varArgs) {
|
vm->ret.type = GST_NIL;
|
||||||
GstValue *tuple;
|
status = callee.data.cfunction(vm);
|
||||||
uint32_t j;
|
gst_thread_popframe(vm, vm->thread);
|
||||||
tuple = gst_tuple(vm, arity - expectedArity);
|
return status;
|
||||||
for (j = expectedArity; j < arity; ++j)
|
}
|
||||||
tuple[j - expectedArity] = args[j];
|
|
||||||
stack[expectedArity].type = GST_TUPLE;
|
|
||||||
stack[expectedArity].data.tuple = tuple;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Call the function */
|
|
||||||
if (callee.type == GST_FUNCTION) {
|
|
||||||
return gst_continue_size(vm, thread.count);
|
|
||||||
} else {
|
|
||||||
int status = callee.data.cfunction(vm);
|
|
||||||
GST_STATE_SYNC();
|
|
||||||
/* Check for closures */
|
|
||||||
if (gst_frame_env(stack) != NULL) {
|
|
||||||
gst_frame_env(stack)->thread = NULL;
|
|
||||||
gst_frame_env(stack)->stackOffset = gst_frame_size(stack);
|
|
||||||
gst_frame_env(stack)->values = gst_alloc(vm, sizeof(GstValue) * gst_frame_size(stack));
|
|
||||||
gst_memcpy(gst_frame_env(stack)->values,
|
|
||||||
thread.data + thread.count,
|
|
||||||
gst_frame_size(stack) * sizeof(GstValue));
|
|
||||||
}
|
|
||||||
vm->thread->count -= gst_frame_prevsize(stack) + GST_FRAME_SIZE;
|
|
||||||
return status;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Get an argument from the stack */
|
/* Get an argument from the stack */
|
||||||
GstValue gst_arg(Gst *vm, uint16_t index) {
|
GstValue gst_arg(Gst *vm, uint16_t index) {
|
||||||
GstValue *stack = vm->thread->data + vm->thread->count;
|
GstValue *stack = gst_thread_stack(vm->thread);
|
||||||
uint16_t frameSize = gst_frame_size(stack);
|
uint16_t frameSize = gst_frame_size(stack);
|
||||||
if (frameSize <= index) {
|
if (frameSize <= index) {
|
||||||
GstValue ret;
|
GstValue ret;
|
||||||
|
@ -695,7 +472,7 @@ GstValue gst_arg(Gst *vm, uint16_t index) {
|
||||||
|
|
||||||
/* Put a value on the stack */
|
/* Put a value on the stack */
|
||||||
void gst_set_arg(Gst* vm, uint16_t index, GstValue x) {
|
void gst_set_arg(Gst* vm, uint16_t index, GstValue x) {
|
||||||
GstValue *stack = vm->thread->data + vm->thread->count;
|
GstValue *stack = gst_thread_stack(vm->thread);
|
||||||
uint16_t frameSize = gst_frame_size(stack);
|
uint16_t frameSize = gst_frame_size(stack);
|
||||||
if (frameSize <= index) return;
|
if (frameSize <= index) return;
|
||||||
stack[index] = x;
|
stack[index] = x;
|
||||||
|
@ -703,7 +480,7 @@ void gst_set_arg(Gst* vm, uint16_t index, GstValue x) {
|
||||||
|
|
||||||
/* Get the size of the VMStack */
|
/* Get the size of the VMStack */
|
||||||
uint16_t gst_count_args(Gst *vm) {
|
uint16_t gst_count_args(Gst *vm) {
|
||||||
GstValue *stack = vm->thread->data + vm->thread->count;
|
GstValue *stack = gst_thread_stack(vm->thread);
|
||||||
return gst_frame_size(stack);
|
return gst_frame_size(stack);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user