diff --git a/source/cell.c b/source/cell.c index c8776d4d..672bffc6 100644 --- a/source/cell.c +++ b/source/cell.c @@ -591,6 +591,8 @@ int cell_init(int argc, char **argv) } /* Check for --mach-run flag to generate and run machine code through register VM */ + fprintf(stderr, "DEBUG: argc=%d argv[1]=%s\n", argc, argc > 1 ? argv[1] : "NULL"); + fflush(stderr); if (argc >= 3 && strcmp(argv[1], "--mach-run") == 0) { const char *script_or_file = argv[2]; char *script = NULL; @@ -625,7 +627,7 @@ int cell_init(int argc, char **argv) free(allocated_script); return 1; } - JSContext *ctx = JS_NewContext(rt); + JSContext *ctx = JS_NewContextWithHeapSize(rt, 1024 * 1024); /* 1MB heap for register VM */ if (!ctx) { printf("Failed to create JS context\n"); JS_FreeRuntime(rt); @@ -656,7 +658,11 @@ int cell_init(int argc, char **argv) } /* Execute through register VM */ + fprintf(stderr, "DEBUG: About to execute mach code\n"); + fflush(stderr); JSValue result = JS_IntegrateRegister(ctx, mach_json, JS_NULL); + fprintf(stderr, "DEBUG: Execution done, result tag=%d\n", (int)(result >> 48)); + fflush(stderr); free(mach_json); int exit_code = 0; diff --git a/source/main.c b/source/main.c index 1650a83e..88f74e38 100644 --- a/source/main.c +++ b/source/main.c @@ -1,6 +1,9 @@ extern int cell_init(int argc, char **argv); +#include int main(int argc, char **argv) { + fprintf(stderr, "MAIN: starting\n"); + fflush(stderr); return cell_init(argc, argv); } \ No newline at end of file diff --git a/source/quickjs.c b/source/quickjs.c index 75a9e291..c4cb40f3 100644 --- a/source/quickjs.c +++ b/source/quickjs.c @@ -538,6 +538,10 @@ typedef enum MachOpcode { MACH_OP_CATCH_END, /* catch_end */ MACH_OP_FINALLY_BEGIN, /* finally_begin */ MACH_OP_FINALLY_END, /* finally_end */ + /* Additional operators */ + MACH_OP_IN, /* in dest, key, obj */ + MACH_OP_NEW_OBJECT, /* new_object dest */ + MACH_OP_NEW_ARRAY, /* new_array dest, capacity */ MACH_OP_COUNT } MachOpcode; @@ -611,6 +615,9 @@ static const char *mach_opcode_names[MACH_OP_COUNT] = { [MACH_OP_CATCH_END] = "catch_end", [MACH_OP_FINALLY_BEGIN] = "finally_begin", [MACH_OP_FINALLY_END] = "finally_end", + [MACH_OP_IN] = "in", + [MACH_OP_NEW_OBJECT] = "new_object", + [MACH_OP_NEW_ARRAY] = "new_array", }; /* Compiled instruction for register VM. @@ -30936,61 +30943,52 @@ static int mach_gen_expr (MachGenState *s, cJSON *expr) { cJSON *list = cJSON_GetObjectItem (expr, "list"); int count = cJSON_GetArraySize (list); - /* Compile each element */ - cJSON *elem_slots = cJSON_CreateArray (); + int dest = mach_alloc_slot (s); + /* Emit new_array dest, capacity */ + mach_emit_2 (s, "new_array", dest, count); + + /* Emit store_idx for each element */ + int idx = 0; cJSON *elem; cJSON_ArrayForEach (elem, list) { - int slot = mach_gen_expr (s, elem); - cJSON_AddItemToArray (elem_slots, cJSON_CreateNumber (slot)); + int val_slot = mach_gen_expr (s, elem); + int idx_slot = mach_alloc_slot (s); + mach_emit_const_num (s, idx_slot, idx); + mach_emit_set_elem (s, dest, idx_slot, val_slot); + idx++; } - - int dest = mach_alloc_slot (s); - cJSON *instr = cJSON_CreateArray (); - cJSON_AddItemToArray (instr, cJSON_CreateString ("mkarray")); - cJSON_AddItemToArray (instr, cJSON_CreateNumber (dest)); - cJSON_AddItemToArray (instr, cJSON_CreateNumber (count)); - cJSON *el; - cJSON_ArrayForEach (el, elem_slots) { - cJSON_AddItemToArray (instr, cJSON_CreateNumber (el->valueint)); - } - cJSON_AddItemToArray (s->instructions, instr); - cJSON_Delete (elem_slots); return dest; } /* Object literal */ if (strcmp (kind, "record") == 0) { cJSON *list = cJSON_GetObjectItem (expr, "list"); - int count = cJSON_GetArraySize (list); int dest = mach_alloc_slot (s); - cJSON *instr = cJSON_CreateArray (); - cJSON_AddItemToArray (instr, cJSON_CreateString ("mkrecord")); - cJSON_AddItemToArray (instr, cJSON_CreateNumber (dest)); - cJSON_AddItemToArray (instr, cJSON_CreateNumber (count)); + /* Emit new_object dest */ + mach_emit_1 (s, "new_object", dest); + /* Emit store_prop for each property */ cJSON *pair; cJSON_ArrayForEach (pair, list) { cJSON *key = cJSON_GetObjectItem (pair, "left"); cJSON *val = cJSON_GetObjectItem (pair, "right"); + int val_slot = mach_gen_expr (s, val); + const char *key_kind = cJSON_GetStringValue (cJSON_GetObjectItem (key, "kind")); if (key_kind && strcmp (key_kind, "name") == 0) { const char *name = cJSON_GetStringValue (cJSON_GetObjectItem (key, "name")); - cJSON_AddItemToArray (instr, cJSON_CreateString (name)); + mach_emit_set_prop (s, dest, name, val_slot); } else if (key_kind && strcmp (key_kind, "text") == 0) { const char *name = cJSON_GetStringValue (cJSON_GetObjectItem (key, "value")); - cJSON_AddItemToArray (instr, cJSON_CreateString (name ? name : "")); + mach_emit_set_prop (s, dest, name ? name : "", val_slot); } else { - /* Computed property - emit the key slot (negative to distinguish) */ + /* Computed property */ int key_slot = mach_gen_expr (s, key); - cJSON_AddItemToArray (instr, cJSON_CreateNumber (-1 - key_slot)); + mach_emit_set_elem (s, dest, key_slot, val_slot); } - - int val_slot = mach_gen_expr (s, val); - cJSON_AddItemToArray (instr, cJSON_CreateNumber (val_slot)); } - cJSON_AddItemToArray (s->instructions, instr); return dest; } @@ -31820,6 +31818,9 @@ static MachOpcode mach_opcode_from_string(const char *name) { if (strcmp(name, "catch_end") == 0) return MACH_OP_CATCH_END; if (strcmp(name, "finally_begin") == 0) return MACH_OP_FINALLY_BEGIN; if (strcmp(name, "finally_end") == 0) return MACH_OP_FINALLY_END; + if (strcmp(name, "in") == 0) return MACH_OP_IN; + if (strcmp(name, "new_object") == 0) return MACH_OP_NEW_OBJECT; + if (strcmp(name, "new_array") == 0) return MACH_OP_NEW_ARRAY; return MACH_OP_NOP; } @@ -32005,7 +32006,8 @@ static JSCodeRegister *js_link_mach_unit(JSContext *ctx, cJSON *unit, JSValue en case MACH_OP_NULL: case MACH_OP_TRUE: case MACH_OP_FALSE: - case MACH_OP_RETURN: { + case MACH_OP_RETURN: + case MACH_OP_NEW_OBJECT: { /* op dest/src */ cJSON *a = cJSON_GetArrayItem(item, 1); instr->a = a ? (int16_t)cJSON_GetNumberValue(a) : 0; @@ -32020,7 +32022,8 @@ static JSCodeRegister *js_link_mach_unit(JSContext *ctx, cJSON *unit, JSValue en case MACH_OP_INVOKE: case MACH_OP_SET_THIS: case MACH_OP_MKFUNC: - case MACH_OP_MKFUNC_ARROW: { + case MACH_OP_MKFUNC_ARROW: + case MACH_OP_NEW_ARRAY: { /* op dest, src */ cJSON *a = cJSON_GetArrayItem(item, 1); cJSON *b = cJSON_GetArrayItem(item, 2); @@ -32055,7 +32058,8 @@ static JSCodeRegister *js_link_mach_unit(JSContext *ctx, cJSON *unit, JSValue en case MACH_OP_PUT: case MACH_OP_FRAME: case MACH_OP_GOFRAME: - case MACH_OP_ARG: { + case MACH_OP_ARG: + case MACH_OP_IN: { /* op a, b, c */ cJSON *a = cJSON_GetArrayItem(item, 1); cJSON *b = cJSON_GetArrayItem(item, 2); @@ -32091,6 +32095,19 @@ static JSCodeRegister *js_link_mach_unit(JSContext *ctx, cJSON *unit, JSValue en } break; } + case MACH_OP_DELETE_PROP: { + /* delete_prop dest, obj, "prop" */ + cJSON *dest = cJSON_GetArrayItem(item, 1); + cJSON *obj = cJSON_GetArrayItem(item, 2); + cJSON *prop = cJSON_GetArrayItem(item, 3); + instr->a = dest ? (int16_t)cJSON_GetNumberValue(dest) : 0; + instr->b = obj ? (int16_t)cJSON_GetNumberValue(obj) : 0; + if (prop && cJSON_IsString(prop)) { + JSValue v = JS_NewString(ctx, cJSON_GetStringValue(prop)); + instr->c = mach_cpool_add(&cpool, v); + } + break; + } case MACH_OP_CAP_NAME: { /* cap_name dest, "name" - resolve to env or global */ cJSON *dest = cJSON_GetArrayItem(item, 1); @@ -32481,14 +32498,19 @@ static JSValue JS_CallRegisterVM(JSContext *ctx, JSCodeRegister *code, JS_AddGCRef(ctx, &frame_ref); frame_ref.val = JS_MKPTR(frame); - /* Setup initial frame */ + /* Setup initial frame - note: function member is not set for top-level code */ frame->slots[0] = this_obj; /* slot 0 is this */ + frame->function = JS_NULL; /* Mark as top-level frame (no function object) */ /* Copy arguments */ for (int i = 0; i < argc && i < code->arity; i++) { frame->slots[1 + i] = argv[i]; } + /* Save initial code/env for when we return to top-level */ + JSCodeRegister *initial_code = code; + JSValue initial_env = env; + uint32_t pc = code->entry_point; JSValue result = JS_NULL; @@ -32510,16 +32532,22 @@ static JSValue JS_CallRegisterVM(JSContext *ctx, JSCodeRegister *code, } /* Pop frame and resume caller */ - int ret_info = JS_VALUE_GET_INT(frame->address); JSFrameRegister *caller = (JSFrameRegister *)JS_VALUE_GET_PTR(frame->caller); + int ret_info = JS_VALUE_GET_INT(caller->address); /* Return addr is in CALLER's frame */ frame->caller = JS_NULL; /* Allow GC to collect */ frame = caller; frame_ref.val = JS_MKPTR(frame); - /* Get code from function */ - JSFunction *fn = JS_VALUE_GET_FUNCTION(frame->function); - code = fn->u.reg.code; + /* Get code from function, or use initial code for top-level */ + if (JS_IsNull(frame->function)) { + code = initial_code; + env = initial_env; + } else { + JSFunction *fn = JS_VALUE_GET_FUNCTION(frame->function); + code = fn->u.reg.code; + env = fn->u.reg.env_record; + } pc = ret_info >> 16; frame->slots[ret_info & 0xFFFF] = result; @@ -32574,11 +32602,15 @@ static JSValue JS_CallRegisterVM(JSContext *ctx, JSCodeRegister *code, case MACH_OP_BITXOR: case MACH_OP_SHL: case MACH_OP_SHR: - case MACH_OP_USHR: - frame->slots[instr->a] = reg_vm_binop(ctx, instr->opcode, - frame->slots[instr->b], - frame->slots[instr->c]); + case MACH_OP_USHR: { + JSValue res = reg_vm_binop(ctx, instr->opcode, + frame->slots[instr->b], + frame->slots[instr->c]); + /* GC may have moved frame - refresh from GC root */ + frame = (JSFrameRegister *)JS_VALUE_GET_PTR(frame_ref.val); + frame->slots[instr->a] = res; break; + } case MACH_OP_NEG: { JSValue v = frame->slots[instr->b]; @@ -32641,6 +32673,14 @@ static JSValue JS_CallRegisterVM(JSContext *ctx, JSCodeRegister *code, break; } + case MACH_OP_IN: { + JSValue key = frame->slots[instr->b]; + JSValue obj = frame->slots[instr->c]; + int has = JS_HasProperty(ctx, obj, key); + frame->slots[instr->a] = JS_NewBool(ctx, has > 0); + break; + } + case MACH_OP_LOAD_PROP: { JSValue obj = frame->slots[instr->b]; JSValue key = code->cpool[instr->c]; @@ -32659,7 +32699,7 @@ static JSValue JS_CallRegisterVM(JSContext *ctx, JSCodeRegister *code, case MACH_OP_LOAD_IDX: { JSValue obj = frame->slots[instr->b]; JSValue idx = frame->slots[instr->c]; - if (JS_IsInt(idx)) { + if (JS_IsInt(idx) && JS_IsArray(obj)) { frame->slots[instr->a] = JS_GetPropertyUint32(ctx, obj, JS_VALUE_GET_INT(idx)); } else { frame->slots[instr->a] = JS_GetProperty(ctx, obj, idx); @@ -32671,7 +32711,7 @@ static JSValue JS_CallRegisterVM(JSContext *ctx, JSCodeRegister *code, JSValue obj = frame->slots[instr->a]; JSValue idx = frame->slots[instr->b]; JSValue val = frame->slots[instr->c]; - if (JS_IsInt(idx)) { + if (JS_IsInt(idx) && JS_IsArray(obj)) { JS_SetPropertyUint32(ctx, obj, JS_VALUE_GET_INT(idx), val); } else { JS_SetProperty(ctx, obj, idx, val); @@ -32679,6 +32719,22 @@ static JSValue JS_CallRegisterVM(JSContext *ctx, JSCodeRegister *code, break; } + case MACH_OP_DELETE_PROP: { + JSValue obj = frame->slots[instr->b]; + JSValue key = code->cpool[instr->c]; + int ret = JS_DeleteProperty(ctx, obj, key); + frame->slots[instr->a] = JS_NewBool(ctx, ret >= 0); + break; + } + + case MACH_OP_DELETE_IDX: { + JSValue obj = frame->slots[instr->b]; + JSValue idx = frame->slots[instr->c]; + int ret = JS_DeleteProperty(ctx, obj, idx); + frame->slots[instr->a] = JS_NewBool(ctx, ret >= 0); + break; + } + case MACH_OP_GET: { /* Closure access: get dest, slot, depth */ int depth = instr->c; @@ -32774,13 +32830,15 @@ static JSValue JS_CallRegisterVM(JSContext *ctx, JSCodeRegister *code, frame->slots[instr->a] = func_val; } else { JSCodeRegister *fn_code = fn->u.reg.code; - JSFrameRegister *new_frame = alloc_frame_register(ctx, fn_code->nr_slots); + uint16_t nr_slots = fn_code->nr_slots; + JSFrameRegister *new_frame = alloc_frame_register(ctx, nr_slots); if (!new_frame) { result = JS_EXCEPTION; goto done; } - /* GC may have moved frame - refresh from GC root */ + /* GC may have moved frame and function - refresh from roots */ frame = (JSFrameRegister *)JS_VALUE_GET_PTR(frame_ref.val); + func_val = frame->slots[instr->b]; /* Re-fetch func_val after GC */ new_frame->function = func_val; frame->slots[instr->a] = JS_MKPTR(new_frame); } @@ -32856,13 +32914,15 @@ static JSValue JS_CallRegisterVM(JSContext *ctx, JSCodeRegister *code, JSFunction *fn = JS_VALUE_GET_FUNCTION(func_val); if (fn->kind == JS_FUNC_KIND_REGISTER) { JSCodeRegister *fn_code = fn->u.reg.code; - JSFrameRegister *new_frame = alloc_frame_register(ctx, fn_code->nr_slots); + uint16_t nr_slots = fn_code->nr_slots; + JSFrameRegister *new_frame = alloc_frame_register(ctx, nr_slots); if (!new_frame) { result = JS_EXCEPTION; goto done; } - /* GC may have moved frame - refresh from GC root */ + /* GC may have moved frame and function - refresh from roots */ frame = (JSFrameRegister *)JS_VALUE_GET_PTR(frame_ref.val); + func_val = frame->slots[instr->b]; /* Re-fetch func_val after GC */ new_frame->function = func_val; frame->slots[instr->a] = JS_MKPTR(new_frame); } else { @@ -32929,6 +32989,31 @@ static JSValue JS_CallRegisterVM(JSContext *ctx, JSCodeRegister *code, break; } + case MACH_OP_NEW_OBJECT: { + JSValue obj = JS_NewObject(ctx); + /* GC may have moved frame - refresh from GC root */ + frame = (JSFrameRegister *)JS_VALUE_GET_PTR(frame_ref.val); + if (JS_IsException(obj)) { + result = obj; + goto done; + } + frame->slots[instr->a] = obj; + break; + } + + case MACH_OP_NEW_ARRAY: { + int capacity = instr->b; + JSValue arr = JS_NewArrayLen(ctx, capacity); + /* GC may have moved frame - refresh from GC root */ + frame = (JSFrameRegister *)JS_VALUE_GET_PTR(frame_ref.val); + if (JS_IsException(arr)) { + result = arr; + goto done; + } + frame->slots[instr->a] = arr; + break; + } + case MACH_OP_RETURN: result = frame->slots[instr->a]; @@ -32937,16 +33022,22 @@ static JSValue JS_CallRegisterVM(JSContext *ctx, JSCodeRegister *code, } { - int ret_info = JS_VALUE_GET_INT(frame->address); JSFrameRegister *caller = (JSFrameRegister *)JS_VALUE_GET_PTR(frame->caller); + int ret_info = JS_VALUE_GET_INT(caller->address); /* Return addr is in CALLER's frame */ frame->caller = JS_NULL; frame = caller; frame_ref.val = JS_MKPTR(frame); - JSFunction *fn = JS_VALUE_GET_FUNCTION(frame->function); - code = fn->u.reg.code; - env = fn->u.reg.env_record; + /* Get code from function, or use initial code for top-level */ + if (JS_IsNull(frame->function)) { + code = initial_code; + env = initial_env; + } else { + JSFunction *fn = JS_VALUE_GET_FUNCTION(frame->function); + code = fn->u.reg.code; + env = fn->u.reg.env_record; + } pc = ret_info >> 16; frame->slots[ret_info & 0xFFFF] = result; @@ -32961,16 +33052,22 @@ static JSValue JS_CallRegisterVM(JSContext *ctx, JSCodeRegister *code, } { - int ret_info = JS_VALUE_GET_INT(frame->address); JSFrameRegister *caller = (JSFrameRegister *)JS_VALUE_GET_PTR(frame->caller); + int ret_info = JS_VALUE_GET_INT(caller->address); /* Return addr is in CALLER's frame */ frame->caller = JS_NULL; frame = caller; frame_ref.val = JS_MKPTR(frame); - JSFunction *fn = JS_VALUE_GET_FUNCTION(frame->function); - code = fn->u.reg.code; - env = fn->u.reg.env_record; + /* Get code from function, or use initial code for top-level */ + if (JS_IsNull(frame->function)) { + code = initial_code; + env = initial_env; + } else { + JSFunction *fn = JS_VALUE_GET_FUNCTION(frame->function); + code = fn->u.reg.code; + env = fn->u.reg.env_record; + } pc = ret_info >> 16; frame->slots[ret_info & 0xFFFF] = result; diff --git a/vm_test/op_typeof.txt b/vm_test/op_typeof.txt deleted file mode 100644 index 6eea91be..00000000 --- a/vm_test/op_typeof.txt +++ /dev/null @@ -1 +0,0 @@ -typeof 5 diff --git a/vm_test/op_void.txt b/vm_test/op_void.txt deleted file mode 100644 index 2701e32e..00000000 --- a/vm_test/op_void.txt +++ /dev/null @@ -1 +0,0 @@ -void 0