|
|
|
@@ -538,6 +538,10 @@ typedef enum MachOpcode {
|
|
|
|
MACH_OP_CATCH_END, /* catch_end */
|
|
|
|
MACH_OP_CATCH_END, /* catch_end */
|
|
|
|
MACH_OP_FINALLY_BEGIN, /* finally_begin */
|
|
|
|
MACH_OP_FINALLY_BEGIN, /* finally_begin */
|
|
|
|
MACH_OP_FINALLY_END, /* finally_end */
|
|
|
|
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
|
|
|
|
MACH_OP_COUNT
|
|
|
|
} MachOpcode;
|
|
|
|
} MachOpcode;
|
|
|
|
|
|
|
|
|
|
|
|
@@ -611,6 +615,9 @@ static const char *mach_opcode_names[MACH_OP_COUNT] = {
|
|
|
|
[MACH_OP_CATCH_END] = "catch_end",
|
|
|
|
[MACH_OP_CATCH_END] = "catch_end",
|
|
|
|
[MACH_OP_FINALLY_BEGIN] = "finally_begin",
|
|
|
|
[MACH_OP_FINALLY_BEGIN] = "finally_begin",
|
|
|
|
[MACH_OP_FINALLY_END] = "finally_end",
|
|
|
|
[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.
|
|
|
|
/* Compiled instruction for register VM.
|
|
|
|
@@ -30936,61 +30943,52 @@ static int mach_gen_expr (MachGenState *s, cJSON *expr) {
|
|
|
|
cJSON *list = cJSON_GetObjectItem (expr, "list");
|
|
|
|
cJSON *list = cJSON_GetObjectItem (expr, "list");
|
|
|
|
int count = cJSON_GetArraySize (list);
|
|
|
|
int count = cJSON_GetArraySize (list);
|
|
|
|
|
|
|
|
|
|
|
|
/* Compile each element */
|
|
|
|
int dest = mach_alloc_slot (s);
|
|
|
|
cJSON *elem_slots = cJSON_CreateArray ();
|
|
|
|
/* 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 *elem;
|
|
|
|
cJSON_ArrayForEach (elem, list) {
|
|
|
|
cJSON_ArrayForEach (elem, list) {
|
|
|
|
int slot = mach_gen_expr (s, elem);
|
|
|
|
int val_slot = mach_gen_expr (s, elem);
|
|
|
|
cJSON_AddItemToArray (elem_slots, cJSON_CreateNumber (slot));
|
|
|
|
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;
|
|
|
|
return dest;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* Object literal */
|
|
|
|
/* Object literal */
|
|
|
|
if (strcmp (kind, "record") == 0) {
|
|
|
|
if (strcmp (kind, "record") == 0) {
|
|
|
|
cJSON *list = cJSON_GetObjectItem (expr, "list");
|
|
|
|
cJSON *list = cJSON_GetObjectItem (expr, "list");
|
|
|
|
int count = cJSON_GetArraySize (list);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int dest = mach_alloc_slot (s);
|
|
|
|
int dest = mach_alloc_slot (s);
|
|
|
|
cJSON *instr = cJSON_CreateArray ();
|
|
|
|
/* Emit new_object dest */
|
|
|
|
cJSON_AddItemToArray (instr, cJSON_CreateString ("mkrecord"));
|
|
|
|
mach_emit_1 (s, "new_object", dest);
|
|
|
|
cJSON_AddItemToArray (instr, cJSON_CreateNumber (dest));
|
|
|
|
|
|
|
|
cJSON_AddItemToArray (instr, cJSON_CreateNumber (count));
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Emit store_prop for each property */
|
|
|
|
cJSON *pair;
|
|
|
|
cJSON *pair;
|
|
|
|
cJSON_ArrayForEach (pair, list) {
|
|
|
|
cJSON_ArrayForEach (pair, list) {
|
|
|
|
cJSON *key = cJSON_GetObjectItem (pair, "left");
|
|
|
|
cJSON *key = cJSON_GetObjectItem (pair, "left");
|
|
|
|
cJSON *val = cJSON_GetObjectItem (pair, "right");
|
|
|
|
cJSON *val = cJSON_GetObjectItem (pair, "right");
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int val_slot = mach_gen_expr (s, val);
|
|
|
|
|
|
|
|
|
|
|
|
const char *key_kind = cJSON_GetStringValue (cJSON_GetObjectItem (key, "kind"));
|
|
|
|
const char *key_kind = cJSON_GetStringValue (cJSON_GetObjectItem (key, "kind"));
|
|
|
|
if (key_kind && strcmp (key_kind, "name") == 0) {
|
|
|
|
if (key_kind && strcmp (key_kind, "name") == 0) {
|
|
|
|
const char *name = cJSON_GetStringValue (cJSON_GetObjectItem (key, "name"));
|
|
|
|
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) {
|
|
|
|
} else if (key_kind && strcmp (key_kind, "text") == 0) {
|
|
|
|
const char *name = cJSON_GetStringValue (cJSON_GetObjectItem (key, "value"));
|
|
|
|
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 {
|
|
|
|
} else {
|
|
|
|
/* Computed property - emit the key slot (negative to distinguish) */
|
|
|
|
/* Computed property */
|
|
|
|
int key_slot = mach_gen_expr (s, key);
|
|
|
|
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;
|
|
|
|
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, "catch_end") == 0) return MACH_OP_CATCH_END;
|
|
|
|
if (strcmp(name, "finally_begin") == 0) return MACH_OP_FINALLY_BEGIN;
|
|
|
|
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, "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;
|
|
|
|
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_NULL:
|
|
|
|
case MACH_OP_TRUE:
|
|
|
|
case MACH_OP_TRUE:
|
|
|
|
case MACH_OP_FALSE:
|
|
|
|
case MACH_OP_FALSE:
|
|
|
|
case MACH_OP_RETURN: {
|
|
|
|
case MACH_OP_RETURN:
|
|
|
|
|
|
|
|
case MACH_OP_NEW_OBJECT: {
|
|
|
|
/* op dest/src */
|
|
|
|
/* op dest/src */
|
|
|
|
cJSON *a = cJSON_GetArrayItem(item, 1);
|
|
|
|
cJSON *a = cJSON_GetArrayItem(item, 1);
|
|
|
|
instr->a = a ? (int16_t)cJSON_GetNumberValue(a) : 0;
|
|
|
|
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_INVOKE:
|
|
|
|
case MACH_OP_SET_THIS:
|
|
|
|
case MACH_OP_SET_THIS:
|
|
|
|
case MACH_OP_MKFUNC:
|
|
|
|
case MACH_OP_MKFUNC:
|
|
|
|
case MACH_OP_MKFUNC_ARROW: {
|
|
|
|
case MACH_OP_MKFUNC_ARROW:
|
|
|
|
|
|
|
|
case MACH_OP_NEW_ARRAY: {
|
|
|
|
/* op dest, src */
|
|
|
|
/* op dest, src */
|
|
|
|
cJSON *a = cJSON_GetArrayItem(item, 1);
|
|
|
|
cJSON *a = cJSON_GetArrayItem(item, 1);
|
|
|
|
cJSON *b = cJSON_GetArrayItem(item, 2);
|
|
|
|
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_PUT:
|
|
|
|
case MACH_OP_FRAME:
|
|
|
|
case MACH_OP_FRAME:
|
|
|
|
case MACH_OP_GOFRAME:
|
|
|
|
case MACH_OP_GOFRAME:
|
|
|
|
case MACH_OP_ARG: {
|
|
|
|
case MACH_OP_ARG:
|
|
|
|
|
|
|
|
case MACH_OP_IN: {
|
|
|
|
/* op a, b, c */
|
|
|
|
/* op a, b, c */
|
|
|
|
cJSON *a = cJSON_GetArrayItem(item, 1);
|
|
|
|
cJSON *a = cJSON_GetArrayItem(item, 1);
|
|
|
|
cJSON *b = cJSON_GetArrayItem(item, 2);
|
|
|
|
cJSON *b = cJSON_GetArrayItem(item, 2);
|
|
|
|
@@ -32091,6 +32095,19 @@ static JSCodeRegister *js_link_mach_unit(JSContext *ctx, cJSON *unit, JSValue en
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
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: {
|
|
|
|
case MACH_OP_CAP_NAME: {
|
|
|
|
/* cap_name dest, "name" - resolve to env or global */
|
|
|
|
/* cap_name dest, "name" - resolve to env or global */
|
|
|
|
cJSON *dest = cJSON_GetArrayItem(item, 1);
|
|
|
|
cJSON *dest = cJSON_GetArrayItem(item, 1);
|
|
|
|
@@ -32481,14 +32498,19 @@ static JSValue JS_CallRegisterVM(JSContext *ctx, JSCodeRegister *code,
|
|
|
|
JS_AddGCRef(ctx, &frame_ref);
|
|
|
|
JS_AddGCRef(ctx, &frame_ref);
|
|
|
|
frame_ref.val = JS_MKPTR(frame);
|
|
|
|
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->slots[0] = this_obj; /* slot 0 is this */
|
|
|
|
|
|
|
|
frame->function = JS_NULL; /* Mark as top-level frame (no function object) */
|
|
|
|
|
|
|
|
|
|
|
|
/* Copy arguments */
|
|
|
|
/* Copy arguments */
|
|
|
|
for (int i = 0; i < argc && i < code->arity; i++) {
|
|
|
|
for (int i = 0; i < argc && i < code->arity; i++) {
|
|
|
|
frame->slots[1 + i] = argv[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;
|
|
|
|
uint32_t pc = code->entry_point;
|
|
|
|
JSValue result = JS_NULL;
|
|
|
|
JSValue result = JS_NULL;
|
|
|
|
|
|
|
|
|
|
|
|
@@ -32510,16 +32532,22 @@ static JSValue JS_CallRegisterVM(JSContext *ctx, JSCodeRegister *code,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* Pop frame and resume caller */
|
|
|
|
/* Pop frame and resume caller */
|
|
|
|
int ret_info = JS_VALUE_GET_INT(frame->address);
|
|
|
|
|
|
|
|
JSFrameRegister *caller = (JSFrameRegister *)JS_VALUE_GET_PTR(frame->caller);
|
|
|
|
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 = JS_NULL; /* Allow GC to collect */
|
|
|
|
|
|
|
|
|
|
|
|
frame = caller;
|
|
|
|
frame = caller;
|
|
|
|
frame_ref.val = JS_MKPTR(frame);
|
|
|
|
frame_ref.val = JS_MKPTR(frame);
|
|
|
|
|
|
|
|
|
|
|
|
/* Get code from function */
|
|
|
|
/* Get code from function, or use initial code for top-level */
|
|
|
|
JSFunction *fn = JS_VALUE_GET_FUNCTION(frame->function);
|
|
|
|
if (JS_IsNull(frame->function)) {
|
|
|
|
code = fn->u.reg.code;
|
|
|
|
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;
|
|
|
|
pc = ret_info >> 16;
|
|
|
|
frame->slots[ret_info & 0xFFFF] = result;
|
|
|
|
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_BITXOR:
|
|
|
|
case MACH_OP_SHL:
|
|
|
|
case MACH_OP_SHL:
|
|
|
|
case MACH_OP_SHR:
|
|
|
|
case MACH_OP_SHR:
|
|
|
|
case MACH_OP_USHR:
|
|
|
|
case MACH_OP_USHR: {
|
|
|
|
frame->slots[instr->a] = reg_vm_binop(ctx, instr->opcode,
|
|
|
|
JSValue res = reg_vm_binop(ctx, instr->opcode,
|
|
|
|
frame->slots[instr->b],
|
|
|
|
frame->slots[instr->b],
|
|
|
|
frame->slots[instr->c]);
|
|
|
|
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;
|
|
|
|
break;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
case MACH_OP_NEG: {
|
|
|
|
case MACH_OP_NEG: {
|
|
|
|
JSValue v = frame->slots[instr->b];
|
|
|
|
JSValue v = frame->slots[instr->b];
|
|
|
|
@@ -32641,6 +32673,14 @@ static JSValue JS_CallRegisterVM(JSContext *ctx, JSCodeRegister *code,
|
|
|
|
break;
|
|
|
|
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: {
|
|
|
|
case MACH_OP_LOAD_PROP: {
|
|
|
|
JSValue obj = frame->slots[instr->b];
|
|
|
|
JSValue obj = frame->slots[instr->b];
|
|
|
|
JSValue key = code->cpool[instr->c];
|
|
|
|
JSValue key = code->cpool[instr->c];
|
|
|
|
@@ -32659,7 +32699,7 @@ static JSValue JS_CallRegisterVM(JSContext *ctx, JSCodeRegister *code,
|
|
|
|
case MACH_OP_LOAD_IDX: {
|
|
|
|
case MACH_OP_LOAD_IDX: {
|
|
|
|
JSValue obj = frame->slots[instr->b];
|
|
|
|
JSValue obj = frame->slots[instr->b];
|
|
|
|
JSValue idx = frame->slots[instr->c];
|
|
|
|
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));
|
|
|
|
frame->slots[instr->a] = JS_GetPropertyUint32(ctx, obj, JS_VALUE_GET_INT(idx));
|
|
|
|
} else {
|
|
|
|
} else {
|
|
|
|
frame->slots[instr->a] = JS_GetProperty(ctx, obj, idx);
|
|
|
|
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 obj = frame->slots[instr->a];
|
|
|
|
JSValue idx = frame->slots[instr->b];
|
|
|
|
JSValue idx = frame->slots[instr->b];
|
|
|
|
JSValue val = frame->slots[instr->c];
|
|
|
|
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);
|
|
|
|
JS_SetPropertyUint32(ctx, obj, JS_VALUE_GET_INT(idx), val);
|
|
|
|
} else {
|
|
|
|
} else {
|
|
|
|
JS_SetProperty(ctx, obj, idx, val);
|
|
|
|
JS_SetProperty(ctx, obj, idx, val);
|
|
|
|
@@ -32679,6 +32719,22 @@ static JSValue JS_CallRegisterVM(JSContext *ctx, JSCodeRegister *code,
|
|
|
|
break;
|
|
|
|
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: {
|
|
|
|
case MACH_OP_GET: {
|
|
|
|
/* Closure access: get dest, slot, depth */
|
|
|
|
/* Closure access: get dest, slot, depth */
|
|
|
|
int depth = instr->c;
|
|
|
|
int depth = instr->c;
|
|
|
|
@@ -32774,13 +32830,15 @@ static JSValue JS_CallRegisterVM(JSContext *ctx, JSCodeRegister *code,
|
|
|
|
frame->slots[instr->a] = func_val;
|
|
|
|
frame->slots[instr->a] = func_val;
|
|
|
|
} else {
|
|
|
|
} else {
|
|
|
|
JSCodeRegister *fn_code = fn->u.reg.code;
|
|
|
|
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) {
|
|
|
|
if (!new_frame) {
|
|
|
|
result = JS_EXCEPTION;
|
|
|
|
result = JS_EXCEPTION;
|
|
|
|
goto done;
|
|
|
|
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);
|
|
|
|
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;
|
|
|
|
new_frame->function = func_val;
|
|
|
|
frame->slots[instr->a] = JS_MKPTR(new_frame);
|
|
|
|
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);
|
|
|
|
JSFunction *fn = JS_VALUE_GET_FUNCTION(func_val);
|
|
|
|
if (fn->kind == JS_FUNC_KIND_REGISTER) {
|
|
|
|
if (fn->kind == JS_FUNC_KIND_REGISTER) {
|
|
|
|
JSCodeRegister *fn_code = fn->u.reg.code;
|
|
|
|
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) {
|
|
|
|
if (!new_frame) {
|
|
|
|
result = JS_EXCEPTION;
|
|
|
|
result = JS_EXCEPTION;
|
|
|
|
goto done;
|
|
|
|
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);
|
|
|
|
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;
|
|
|
|
new_frame->function = func_val;
|
|
|
|
frame->slots[instr->a] = JS_MKPTR(new_frame);
|
|
|
|
frame->slots[instr->a] = JS_MKPTR(new_frame);
|
|
|
|
} else {
|
|
|
|
} else {
|
|
|
|
@@ -32929,6 +32989,31 @@ static JSValue JS_CallRegisterVM(JSContext *ctx, JSCodeRegister *code,
|
|
|
|
break;
|
|
|
|
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:
|
|
|
|
case MACH_OP_RETURN:
|
|
|
|
result = frame->slots[instr->a];
|
|
|
|
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);
|
|
|
|
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 = JS_NULL;
|
|
|
|
|
|
|
|
|
|
|
|
frame = caller;
|
|
|
|
frame = caller;
|
|
|
|
frame_ref.val = JS_MKPTR(frame);
|
|
|
|
frame_ref.val = JS_MKPTR(frame);
|
|
|
|
|
|
|
|
|
|
|
|
JSFunction *fn = JS_VALUE_GET_FUNCTION(frame->function);
|
|
|
|
/* Get code from function, or use initial code for top-level */
|
|
|
|
code = fn->u.reg.code;
|
|
|
|
if (JS_IsNull(frame->function)) {
|
|
|
|
env = fn->u.reg.env_record;
|
|
|
|
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;
|
|
|
|
pc = ret_info >> 16;
|
|
|
|
frame->slots[ret_info & 0xFFFF] = result;
|
|
|
|
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);
|
|
|
|
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 = JS_NULL;
|
|
|
|
|
|
|
|
|
|
|
|
frame = caller;
|
|
|
|
frame = caller;
|
|
|
|
frame_ref.val = JS_MKPTR(frame);
|
|
|
|
frame_ref.val = JS_MKPTR(frame);
|
|
|
|
|
|
|
|
|
|
|
|
JSFunction *fn = JS_VALUE_GET_FUNCTION(frame->function);
|
|
|
|
/* Get code from function, or use initial code for top-level */
|
|
|
|
code = fn->u.reg.code;
|
|
|
|
if (JS_IsNull(frame->function)) {
|
|
|
|
env = fn->u.reg.env_record;
|
|
|
|
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;
|
|
|
|
pc = ret_info >> 16;
|
|
|
|
frame->slots[ret_info & 0xFFFF] = result;
|
|
|
|
frame->slots[ret_info & 0xFFFF] = result;
|
|
|
|
|