guards in mcode
This commit is contained in:
@@ -173,7 +173,6 @@ Memory operations come in typed variants. The compiler selects the appropriate v
|
||||
| `store_dynamic` | `obj, val, key` | Store property (dispatches at runtime) |
|
||||
| `delete` | `obj, key` | Delete property |
|
||||
| `in` | `dest, obj, key` | Check if property exists |
|
||||
| `typeof` | `dest, src` | Get type name as text |
|
||||
| `length` | `dest, src` | Get length of array or text |
|
||||
|
||||
### Object and Array Construction
|
||||
@@ -181,7 +180,7 @@ Memory operations come in typed variants. The compiler selects the appropriate v
|
||||
| Instruction | Operands | Description |
|
||||
|-------------|----------|-------------|
|
||||
| `record` | `dest` | Create empty record `{}` |
|
||||
| `array` | `dest, n, ...elems` | Create array with `n` elements |
|
||||
| `array` | `dest, n` | Create empty array (elements added via `push`) |
|
||||
| `push` | `arr, val` | Push value to array |
|
||||
| `pop` | `dest, arr` | Pop value from array |
|
||||
|
||||
|
||||
5707
fold.cm.mcode
5707
fold.cm.mcode
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
62
mcode.cm
62
mcode.cm
@@ -782,13 +782,12 @@ var mcode = function(ast) {
|
||||
var name_str = alloc_slot()
|
||||
emit_const_str(name_str, prop)
|
||||
var args_arr = alloc_slot()
|
||||
var arr_instr = ["array", args_arr, argc]
|
||||
add_instr(["array", args_arr, 0])
|
||||
_i = 0
|
||||
while (_i < argc) {
|
||||
push(arr_instr, args[_i])
|
||||
emit_2("push", args_arr, args[_i])
|
||||
_i = _i + 1
|
||||
}
|
||||
add_instr(arr_instr)
|
||||
var pf = alloc_slot()
|
||||
emit_3("frame", pf, obj, 2)
|
||||
emit_3("setarg", pf, 0, null_slot)
|
||||
@@ -836,13 +835,12 @@ var mcode = function(ast) {
|
||||
var null_slot = alloc_slot()
|
||||
emit_const_null(null_slot)
|
||||
var args_arr = alloc_slot()
|
||||
var arr_instr = ["array", args_arr, argc]
|
||||
add_instr(["array", args_arr, 0])
|
||||
_i = 0
|
||||
while (_i < argc) {
|
||||
push(arr_instr, args[_i])
|
||||
emit_2("push", args_arr, args[_i])
|
||||
_i = _i + 1
|
||||
}
|
||||
add_instr(arr_instr)
|
||||
var pf = alloc_slot()
|
||||
emit_3("frame", pf, obj, 2)
|
||||
emit_3("setarg", pf, 0, null_slot)
|
||||
@@ -1181,17 +1179,29 @@ var mcode = function(ast) {
|
||||
var obj_slot = 0
|
||||
var idx_expr = null
|
||||
var idx_slot = 0
|
||||
var guard_t = 0
|
||||
var guard_err = null
|
||||
var guard_done = null
|
||||
|
||||
if (cop != null) {
|
||||
return gen_compound_assign(node, cop)
|
||||
}
|
||||
|
||||
// Push syntax: arr[] = val
|
||||
// Push syntax: arr[] = val (guarded)
|
||||
if (node.push == true) {
|
||||
arr_expr = left.left
|
||||
arr_slot = gen_expr(arr_expr, -1)
|
||||
val_slot = gen_expr(right, -1)
|
||||
guard_t = alloc_slot()
|
||||
guard_err = gen_label("push_err")
|
||||
guard_done = gen_label("push_done")
|
||||
emit_2("is_array", guard_t, arr_slot)
|
||||
emit_jump_cond("jump_false", guard_t, guard_err)
|
||||
emit_2("push", arr_slot, val_slot)
|
||||
emit_jump(guard_done)
|
||||
emit_label(guard_err)
|
||||
emit_0("disrupt")
|
||||
emit_label(guard_done)
|
||||
return val_slot
|
||||
}
|
||||
|
||||
@@ -1306,6 +1316,9 @@ var mcode = function(ast) {
|
||||
var kname = null
|
||||
var func = null
|
||||
var func_id = 0
|
||||
var guard_t = 0
|
||||
var guard_err = null
|
||||
var guard_done = null
|
||||
|
||||
if (expr == null) {
|
||||
return -1
|
||||
@@ -1343,13 +1356,12 @@ var mcode = function(ast) {
|
||||
}
|
||||
// Create array from expression results
|
||||
arr_slot = alloc_slot()
|
||||
arr_instr = ["array", arr_slot, nexpr]
|
||||
add_instr(["array", arr_slot, 0])
|
||||
_i = 0
|
||||
while (_i < nexpr) {
|
||||
push(arr_instr, expr_slots[_i])
|
||||
emit_2("push", arr_slot, expr_slots[_i])
|
||||
_i = _i + 1
|
||||
}
|
||||
add_instr(arr_instr)
|
||||
// Load format intrinsic
|
||||
fmt_func_slot = find_intrinsic("format")
|
||||
if (fmt_func_slot < 0) {
|
||||
@@ -1546,11 +1558,20 @@ var mcode = function(ast) {
|
||||
return d
|
||||
}
|
||||
}
|
||||
// 2-arg push: push(arr, val) → direct opcode
|
||||
// 2-arg push: push(arr, val) → guarded direct opcode
|
||||
if (nargs == 2 && fname == "push") {
|
||||
a0 = gen_expr(args_list[0], -1)
|
||||
a1 = gen_expr(args_list[1], -1)
|
||||
guard_t = alloc_slot()
|
||||
guard_err = gen_label("push_err")
|
||||
guard_done = gen_label("push_done")
|
||||
emit_2("is_array", guard_t, a0)
|
||||
emit_jump_cond("jump_false", guard_t, guard_err)
|
||||
emit_2("push", a0, a1)
|
||||
emit_jump(guard_done)
|
||||
emit_label(guard_err)
|
||||
emit_0("disrupt")
|
||||
emit_label(guard_done)
|
||||
return a1
|
||||
}
|
||||
}
|
||||
@@ -1732,13 +1753,12 @@ var mcode = function(ast) {
|
||||
_i = _i + 1
|
||||
}
|
||||
dest = alloc_slot()
|
||||
instr = ["array", dest, count]
|
||||
add_instr(["array", dest, 0])
|
||||
_i = 0
|
||||
while (_i < count) {
|
||||
push(instr, elem_slots[_i])
|
||||
emit_2("push", dest, elem_slots[_i])
|
||||
_i = _i + 1
|
||||
}
|
||||
push(s_instructions, instr)
|
||||
return dest
|
||||
}
|
||||
|
||||
@@ -1856,6 +1876,9 @@ var mcode = function(ast) {
|
||||
var func = null
|
||||
var func_id = 0
|
||||
var dest = 0
|
||||
var guard_t = 0
|
||||
var guard_err = null
|
||||
var guard_done = null
|
||||
|
||||
if (stmt == null) {
|
||||
return null
|
||||
@@ -1871,12 +1894,21 @@ var mcode = function(ast) {
|
||||
right = stmt.right
|
||||
name = left.name
|
||||
local_slot = find_var(name)
|
||||
// Pop: var val = arr[]
|
||||
// Pop: var val = arr[] (guarded)
|
||||
if (stmt.pop == true && right != null) {
|
||||
arr_expr = right.left
|
||||
arr_slot = gen_expr(arr_expr, -1)
|
||||
if (local_slot >= 0) {
|
||||
guard_t = alloc_slot()
|
||||
guard_err = gen_label("pop_err")
|
||||
guard_done = gen_label("pop_done")
|
||||
emit_2("is_array", guard_t, arr_slot)
|
||||
emit_jump_cond("jump_false", guard_t, guard_err)
|
||||
emit_2("pop", local_slot, arr_slot)
|
||||
emit_jump(guard_done)
|
||||
emit_label(guard_err)
|
||||
emit_0("disrupt")
|
||||
emit_label(guard_done)
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
37487
mcode.cm.mcode
37487
mcode.cm.mcode
File diff suppressed because it is too large
Load Diff
37099
parse.cm.mcode
37099
parse.cm.mcode
File diff suppressed because it is too large
Load Diff
1306
qbe.cm.mcode
1306
qbe.cm.mcode
File diff suppressed because it is too large
Load Diff
7779
qbe_emit.cm.mcode
7779
qbe_emit.cm.mcode
File diff suppressed because it is too large
Load Diff
@@ -987,13 +987,9 @@ JSValue JS_CallRegisterVM(JSContext *ctx, JSCodeRegister *code,
|
||||
}
|
||||
|
||||
case MACH_GETINDEX: {
|
||||
/* R(A) = R(B)[R(C)] — mcode guarantees R(C) is int */
|
||||
JSValue obj = frame->slots[b];
|
||||
JSValue idx = frame->slots[c];
|
||||
JSValue val;
|
||||
if (JS_IsInt(idx))
|
||||
val = JS_GetPropertyNumber(ctx, obj, JS_VALUE_GET_INT(idx));
|
||||
else
|
||||
val = JS_GetProperty(ctx, obj, idx);
|
||||
JSValue val = JS_GetPropertyNumber(ctx, obj, JS_VALUE_GET_INT(frame->slots[c]));
|
||||
frame = (JSFrameRegister *)JS_VALUE_GET_PTR(frame_ref.val);
|
||||
if (JS_IsException(val)) goto disrupt;
|
||||
frame->slots[a] = val;
|
||||
@@ -1001,25 +997,12 @@ JSValue JS_CallRegisterVM(JSContext *ctx, JSCodeRegister *code,
|
||||
}
|
||||
|
||||
case MACH_SETINDEX: {
|
||||
/* R(A)[R(B)] = R(C) */
|
||||
/* R(A)[R(B)] = R(C) — mcode guarantees R(B) is int */
|
||||
JSValue obj = frame->slots[a];
|
||||
JSValue idx = frame->slots[b];
|
||||
JSValue val = frame->slots[c];
|
||||
int ret;
|
||||
if (JS_IsInt(idx)) {
|
||||
JSValue r = JS_SetPropertyNumber(ctx, obj, JS_VALUE_GET_INT(idx), val);
|
||||
ret = JS_IsException(r) ? -1 : 0;
|
||||
} else if (mist_is_array(obj)) {
|
||||
JS_ThrowTypeError(ctx, "array index must be a number");
|
||||
ret = -1;
|
||||
} else if (mist_is_record(obj) && !mist_is_text(idx) && !mist_is_record(idx)) {
|
||||
JS_ThrowTypeError(ctx, "object key must be a string or object");
|
||||
ret = -1;
|
||||
} else {
|
||||
ret = JS_SetProperty(ctx, obj, idx, val);
|
||||
}
|
||||
JSValue r = JS_SetPropertyNumber(ctx, obj, JS_VALUE_GET_INT(frame->slots[b]), val);
|
||||
frame = (JSFrameRegister *)JS_VALUE_GET_PTR(frame_ref.val);
|
||||
if (ret < 0) goto disrupt;
|
||||
if (JS_IsException(r)) goto disrupt;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -1187,16 +1170,10 @@ JSValue JS_CallRegisterVM(JSContext *ctx, JSCodeRegister *code,
|
||||
}
|
||||
|
||||
case MACH_NEWARRAY: {
|
||||
int count = b;
|
||||
JSValue arr = JS_NewArray(ctx);
|
||||
frame = (JSFrameRegister *)JS_VALUE_GET_PTR(frame_ref.val);
|
||||
if (JS_IsException(arr)) { goto disrupt; }
|
||||
/* Store array in dest immediately so GC can track it */
|
||||
frame->slots[a] = arr;
|
||||
for (int i = 0; i < count; i++) {
|
||||
JS_SetPropertyNumber(ctx, frame->slots[a], i, frame->slots[a + 1 + i]);
|
||||
frame = (JSFrameRegister *)JS_VALUE_GET_PTR(frame_ref.val);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -1216,14 +1193,9 @@ JSValue JS_CallRegisterVM(JSContext *ctx, JSCodeRegister *code,
|
||||
}
|
||||
|
||||
case MACH_PUSH: {
|
||||
/* push R(B) onto array R(A) */
|
||||
/* push R(B) onto array R(A) — mcode guarantees R(A) is array */
|
||||
JSValue arr = frame->slots[a];
|
||||
JSValue val = frame->slots[b];
|
||||
if (!mist_is_array(arr)) {
|
||||
JS_ThrowTypeError(ctx, "cannot push to non-array");
|
||||
frame = (JSFrameRegister *)JS_VALUE_GET_PTR(frame_ref.val);
|
||||
goto disrupt;
|
||||
}
|
||||
JSGCRef arr_gc;
|
||||
JS_PushGCRef(ctx, &arr_gc);
|
||||
arr_gc.val = arr;
|
||||
@@ -1236,13 +1208,8 @@ JSValue JS_CallRegisterVM(JSContext *ctx, JSCodeRegister *code,
|
||||
}
|
||||
|
||||
case MACH_POP: {
|
||||
/* R(A) = pop last element from array R(B) */
|
||||
/* R(A) = pop last element from array R(B) — mcode guarantees R(B) is array */
|
||||
JSValue arr = frame->slots[b];
|
||||
if (!mist_is_array(arr)) {
|
||||
JS_ThrowTypeError(ctx, "cannot pop from non-array");
|
||||
frame = (JSFrameRegister *)JS_VALUE_GET_PTR(frame_ref.val);
|
||||
goto disrupt;
|
||||
}
|
||||
JSValue val = JS_ArrayPop(ctx, arr);
|
||||
frame = (JSFrameRegister *)JS_VALUE_GET_PTR(frame_ref.val);
|
||||
if (JS_IsException(val)) goto disrupt;
|
||||
@@ -1594,30 +1561,21 @@ JSValue JS_CallRegisterVM(JSContext *ctx, JSCodeRegister *code,
|
||||
break;
|
||||
}
|
||||
case MACH_LOAD_INDEX: {
|
||||
/* R(A) = R(B)[R(C)] — mcode guarantees R(C) is int */
|
||||
JSValue obj = frame->slots[b];
|
||||
JSValue idx = frame->slots[c];
|
||||
JSValue val;
|
||||
if (JS_IsInt(idx))
|
||||
val = JS_GetPropertyNumber(ctx, obj, JS_VALUE_GET_INT(idx));
|
||||
else
|
||||
val = JS_GetProperty(ctx, obj, idx);
|
||||
JSValue val = JS_GetPropertyNumber(ctx, obj, JS_VALUE_GET_INT(frame->slots[c]));
|
||||
frame = (JSFrameRegister *)JS_VALUE_GET_PTR(frame_ref.val);
|
||||
if (JS_IsException(val)) goto disrupt;
|
||||
frame->slots[a] = val;
|
||||
break;
|
||||
}
|
||||
case MACH_STORE_INDEX: {
|
||||
/* R(A)[R(B)] = R(C) — mcode guarantees R(B) is int */
|
||||
JSValue obj = frame->slots[a];
|
||||
JSValue idx = frame->slots[b];
|
||||
JSValue val = frame->slots[c];
|
||||
int ret;
|
||||
if (JS_IsInt(idx)) {
|
||||
JSValue r = JS_SetPropertyNumber(ctx, obj, JS_VALUE_GET_INT(idx), val);
|
||||
ret = JS_IsException(r) ? -1 : 0;
|
||||
} else
|
||||
ret = JS_SetProperty(ctx, obj, idx, val);
|
||||
JSValue r = JS_SetPropertyNumber(ctx, obj, JS_VALUE_GET_INT(frame->slots[b]), val);
|
||||
frame = (JSFrameRegister *)JS_VALUE_GET_PTR(frame_ref.val);
|
||||
if (ret < 0) goto disrupt;
|
||||
if (JS_IsException(r)) goto disrupt;
|
||||
break;
|
||||
}
|
||||
case MACH_LOAD_DYNAMIC: {
|
||||
|
||||
@@ -159,8 +159,6 @@ var streamline = function(ir, log) {
|
||||
slot_types[text(instr[1])] = T_FUNCTION
|
||||
} else if (op == "length") {
|
||||
slot_types[text(instr[1])] = T_INT
|
||||
} else if (op == "typeof") {
|
||||
slot_types[text(instr[1])] = T_TEXT
|
||||
} else if (op == "neg_int") {
|
||||
slot_types[text(instr[1])] = T_INT
|
||||
} else if (op == "neg_float") {
|
||||
|
||||
33293
streamline.cm.mcode
33293
streamline.cm.mcode
File diff suppressed because it is too large
Load Diff
12
test_guards.ce
Normal file
12
test_guards.ce
Normal file
@@ -0,0 +1,12 @@
|
||||
// Test array guard emission and optimization
|
||||
var a = [1, 2, 3]
|
||||
push(a, 4)
|
||||
var v = a[]
|
||||
|
||||
var f = function(arr) {
|
||||
push(arr, 99)
|
||||
var x = arr[]
|
||||
return x
|
||||
}
|
||||
|
||||
f(a)
|
||||
14720
tokenize.cm.mcode
14720
tokenize.cm.mcode
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user