Merge branch 'runtime_rework' into mach_memory
This commit is contained in:
43
parse.cm
43
parse.cm
@@ -1425,7 +1425,9 @@ var parse = function(tokens, src, filename, tokenizer) {
|
||||
vars: [],
|
||||
in_loop: opts.in_loop == true,
|
||||
function_nr: fn_nr,
|
||||
is_function_scope: opts.is_func == true
|
||||
is_function_scope: opts.is_func == true,
|
||||
func_node: null,
|
||||
has_inner_func: false
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1478,6 +1480,15 @@ var parse = function(tokens, src, filename, tokenizer) {
|
||||
return false
|
||||
}
|
||||
|
||||
var sem_find_func_scope = function(scope) {
|
||||
var s = scope
|
||||
while (s != null) {
|
||||
if (s.is_function_scope) return s
|
||||
s = s.parent
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
var sem_add_intrinsic = function(name) {
|
||||
if (find(intrinsics, name) == null) push(intrinsics, name)
|
||||
}
|
||||
@@ -1635,6 +1646,7 @@ var parse = function(tokens, src, filename, tokenizer) {
|
||||
var pname = null
|
||||
var def_val = null
|
||||
var sr = null
|
||||
var enclosing = null
|
||||
|
||||
if (_assign_kinds[kind] == true) {
|
||||
sem_check_assign_target(scope, expr.left)
|
||||
@@ -1736,9 +1748,12 @@ var parse = function(tokens, src, filename, tokenizer) {
|
||||
}
|
||||
|
||||
if (kind == "function") {
|
||||
enclosing = sem_find_func_scope(scope)
|
||||
if (enclosing != null) enclosing.has_inner_func = true
|
||||
fn_nr_val = expr.function_nr
|
||||
if (fn_nr_val == null) fn_nr_val = scope.function_nr
|
||||
fn_scope = make_scope(scope, fn_nr_val, {is_func: true})
|
||||
fn_scope.func_node = expr
|
||||
expr.outer = scope.function_nr
|
||||
i = 0
|
||||
while (i < length(expr.list)) {
|
||||
@@ -1819,6 +1834,8 @@ var parse = function(tokens, src, filename, tokenizer) {
|
||||
var pname = null
|
||||
var def_val = null
|
||||
var sr = null
|
||||
var enclosing = null
|
||||
var func_scope = null
|
||||
var tt = null
|
||||
|
||||
if (kind == "var_list") {
|
||||
@@ -1941,7 +1958,26 @@ var parse = function(tokens, src, filename, tokenizer) {
|
||||
return null
|
||||
}
|
||||
|
||||
if (kind == "return" || kind == "go") {
|
||||
if (kind == "go") {
|
||||
sem_check_expr(scope, stmt.expression)
|
||||
if (stmt.expression == null || stmt.expression.kind != "(") {
|
||||
sem_error(stmt, "'go' must be followed by a function call")
|
||||
} else {
|
||||
func_scope = sem_find_func_scope(scope)
|
||||
if (func_scope != null && func_scope.func_node != null) {
|
||||
if (func_scope.func_node.disruption != null) {
|
||||
sem_error(stmt, "cannot use 'go' in a function with a disruption clause")
|
||||
}
|
||||
if (func_scope.has_inner_func) {
|
||||
sem_error(stmt, "cannot use 'go' in a function that defines inner functions")
|
||||
}
|
||||
}
|
||||
stmt.tail = true
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
if (kind == "return") {
|
||||
sem_check_expr(scope, stmt.expression)
|
||||
if (stmt.expression != null && stmt.expression.kind == "(") {
|
||||
stmt.tail = true
|
||||
@@ -1982,11 +2018,14 @@ var parse = function(tokens, src, filename, tokenizer) {
|
||||
}
|
||||
|
||||
if (kind == "function") {
|
||||
enclosing = sem_find_func_scope(scope)
|
||||
if (enclosing != null) enclosing.has_inner_func = true
|
||||
name = stmt.name
|
||||
if (name != null) sem_add_var(scope, name, {make: "function", fn_nr: scope.function_nr})
|
||||
fn_nr_val = stmt.function_nr
|
||||
if (fn_nr_val == null) fn_nr_val = scope.function_nr
|
||||
fn_scope = make_scope(scope, fn_nr_val, {is_func: true})
|
||||
fn_scope.func_node = stmt
|
||||
stmt.outer = scope.function_nr
|
||||
i = 0
|
||||
while (i < length(stmt.list)) {
|
||||
|
||||
20627
parse.cm.mcode
20627
parse.cm.mcode
File diff suppressed because it is too large
Load Diff
@@ -650,7 +650,8 @@ var qbe_emit = function(ir, qbe) {
|
||||
continue
|
||||
}
|
||||
if (op == "goinvoke") {
|
||||
emit(` call $cell_rt_goinvoke(l %ctx, l ${s(a1)})`)
|
||||
emit(` %_goret =l call $cell_rt_goinvoke(l %ctx, l ${s(a1)})`)
|
||||
emit(` ret %_goret`)
|
||||
continue
|
||||
}
|
||||
|
||||
|
||||
1931
qbe_emit.cm.mcode
1931
qbe_emit.cm.mcode
File diff suppressed because it is too large
Load Diff
@@ -1702,17 +1702,68 @@ JSValue JS_CallRegisterVM(JSContext *ctx, JSCodeRegister *code,
|
||||
break;
|
||||
}
|
||||
case MACH_GOINVOKE: {
|
||||
/* Async invoke: call and discard result */
|
||||
/* Tail call: replace current frame with callee */
|
||||
JSFrameRegister *fr = (JSFrameRegister *)JS_VALUE_GET_PTR(frame->slots[a]);
|
||||
int nr = (int)objhdr_cap56(fr->hdr);
|
||||
int c_argc = (nr >= 2) ? nr - 2 : 0;
|
||||
ctx->reg_current_frame = frame_ref.val;
|
||||
ctx->current_register_pc = pc > 0 ? pc - 1 : 0;
|
||||
JSValue ret = JS_Call(ctx, fr->function, fr->slots[0],
|
||||
c_argc, &fr->slots[1]);
|
||||
frame = (JSFrameRegister *)JS_VALUE_GET_PTR(frame_ref.val);
|
||||
ctx->reg_current_frame = JS_NULL;
|
||||
if (JS_IsException(ret)) goto disrupt;
|
||||
JSValue fn_val = fr->function;
|
||||
JSFunction *fn = JS_VALUE_GET_FUNCTION(fn_val);
|
||||
|
||||
if (fn->kind == JS_FUNC_KIND_REGISTER) {
|
||||
/* Register function: tail call by replacing current frame */
|
||||
JSCodeRegister *fn_code = fn->u.reg.code;
|
||||
JSFrameRegister *new_frame = alloc_frame_register(ctx, fn_code->nr_slots);
|
||||
if (!new_frame) {
|
||||
frame = (JSFrameRegister *)JS_VALUE_GET_PTR(frame_ref.val);
|
||||
goto disrupt;
|
||||
}
|
||||
frame = (JSFrameRegister *)JS_VALUE_GET_PTR(frame_ref.val);
|
||||
fr = (JSFrameRegister *)JS_VALUE_GET_PTR(frame->slots[a]);
|
||||
fn_val = fr->function;
|
||||
fn = JS_VALUE_GET_FUNCTION(fn_val);
|
||||
fn_code = fn->u.reg.code;
|
||||
new_frame->function = fn_val;
|
||||
/* Copy this + args from call frame to new frame */
|
||||
int copy_count = (c_argc < fn_code->arity) ? c_argc : fn_code->arity;
|
||||
new_frame->slots[0] = fr->slots[0]; /* this */
|
||||
for (int i = 0; i < copy_count; i++)
|
||||
new_frame->slots[1 + i] = fr->slots[1 + i];
|
||||
/* Tail call: callee returns to OUR caller, not to us */
|
||||
new_frame->caller = frame->caller;
|
||||
frame->caller = JS_NULL; /* detach current frame */
|
||||
/* Switch to callee */
|
||||
frame = new_frame;
|
||||
frame_ref.val = JS_MKPTR(frame);
|
||||
code = fn_code;
|
||||
env = fn->u.reg.env_record;
|
||||
pc = code->entry_point;
|
||||
} else {
|
||||
/* C/bytecode function: call it, then return result to our caller */
|
||||
ctx->reg_current_frame = frame_ref.val;
|
||||
ctx->current_register_pc = pc > 0 ? pc - 1 : 0;
|
||||
JSValue ret;
|
||||
if (fn->kind == JS_FUNC_KIND_C)
|
||||
ret = js_call_c_function(ctx, fn_val, fr->slots[0], c_argc, &fr->slots[1]);
|
||||
else
|
||||
ret = JS_CallInternal(ctx, fn_val, fr->slots[0], c_argc, &fr->slots[1], 0);
|
||||
frame = (JSFrameRegister *)JS_VALUE_GET_PTR(frame_ref.val);
|
||||
ctx->reg_current_frame = JS_NULL;
|
||||
if (JS_IsException(ret)) goto disrupt;
|
||||
/* Tail-return: act like MACH_RETURN with the result */
|
||||
result = ret;
|
||||
if (JS_IsNull(frame->caller)) goto done;
|
||||
JSFrameRegister *caller = (JSFrameRegister *)JS_VALUE_GET_PTR(frame->caller);
|
||||
frame->caller = JS_NULL;
|
||||
frame = caller;
|
||||
frame_ref.val = JS_MKPTR(frame);
|
||||
int ret_info = JS_VALUE_GET_INT(frame->address);
|
||||
JSFunction *ret_fn = JS_VALUE_GET_FUNCTION(frame->function);
|
||||
code = ret_fn->u.reg.code;
|
||||
env = ret_fn->u.reg.env_record;
|
||||
pc = ret_info >> 16;
|
||||
int ret_slot = ret_info & 0xFFFF;
|
||||
if (ret_slot != 0xFFFF) frame->slots[ret_slot] = ret;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
@@ -351,8 +351,8 @@ JSValue cell_rt_goframe(JSContext *ctx, JSValue fn, int64_t nargs) {
|
||||
return cell_rt_frame(ctx, fn, nargs);
|
||||
}
|
||||
|
||||
void cell_rt_goinvoke(JSContext *ctx, JSValue frame_val) {
|
||||
cell_rt_invoke(ctx, frame_val);
|
||||
JSValue cell_rt_goinvoke(JSContext *ctx, JSValue frame_val) {
|
||||
return cell_rt_invoke(ctx, frame_val);
|
||||
}
|
||||
|
||||
/* --- Array push/pop --- */
|
||||
|
||||
Reference in New Issue
Block a user