more test fixing
This commit is contained in:
347
source/quickjs.c
347
source/quickjs.c
@@ -563,6 +563,11 @@ typedef enum MachOpcode {
|
|||||||
MACH_PUSH, /* push R(B) onto array R(A) */
|
MACH_PUSH, /* push R(B) onto array R(A) */
|
||||||
MACH_POP, /* R(A) = pop last element from array R(B) */
|
MACH_POP, /* R(A) = pop last element from array R(B) */
|
||||||
|
|
||||||
|
MACH_DELETE, /* R(A) = delete R(B)[K(C)] — named property delete */
|
||||||
|
MACH_DELETEINDEX, /* R(A) = delete R(B)[R(C)] — computed property delete */
|
||||||
|
MACH_HASPROP, /* R(A) = R(C) in R(B) — has property check */
|
||||||
|
MACH_REGEXP, /* R(A) = regexp(K(B), K(C)) — regex literal */
|
||||||
|
|
||||||
MACH_NOP,
|
MACH_NOP,
|
||||||
|
|
||||||
MACH_OP_COUNT
|
MACH_OP_COUNT
|
||||||
@@ -620,6 +625,10 @@ static const char *mach_opcode_names[MACH_OP_COUNT] = {
|
|||||||
[MACH_THROW] = "throw",
|
[MACH_THROW] = "throw",
|
||||||
[MACH_PUSH] = "push",
|
[MACH_PUSH] = "push",
|
||||||
[MACH_POP] = "pop",
|
[MACH_POP] = "pop",
|
||||||
|
[MACH_DELETE] = "delete",
|
||||||
|
[MACH_DELETEINDEX] = "deleteindex",
|
||||||
|
[MACH_HASPROP] = "hasprop",
|
||||||
|
[MACH_REGEXP] = "regexp",
|
||||||
[MACH_NOP] = "nop",
|
[MACH_NOP] = "nop",
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -2646,6 +2655,22 @@ static void gc_scan_object (JSContext *ctx, void *ptr, uint8_t *from_base, uint8
|
|||||||
rec->slots[i].val = gc_copy_value (ctx, rec->slots[i].val, from_base, from_end, to_base, to_free, to_end);
|
rec->slots[i].val = gc_copy_value (ctx, rec->slots[i].val, from_base, from_end, to_base, to_free, to_end);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
/* Forward internal GC pointers for regex objects */
|
||||||
|
if (REC_GET_CLASS_ID(rec) == JS_CLASS_REGEXP) {
|
||||||
|
JSRegExp *re = (JSRegExp *)REC_GET_OPAQUE(rec);
|
||||||
|
if (re) {
|
||||||
|
if (re->pattern) {
|
||||||
|
JSValue pv = JS_MKPTR(re->pattern);
|
||||||
|
pv = gc_copy_value(ctx, pv, from_base, from_end, to_base, to_free, to_end);
|
||||||
|
re->pattern = (JSText *)JS_VALUE_GET_PTR(pv);
|
||||||
|
}
|
||||||
|
if (re->bytecode) {
|
||||||
|
JSValue bv = JS_MKPTR(re->bytecode);
|
||||||
|
bv = gc_copy_value(ctx, bv, from_base, from_end, to_base, to_free, to_end);
|
||||||
|
re->bytecode = (JSText *)JS_VALUE_GET_PTR(bv);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case OBJ_FUNCTION: {
|
case OBJ_FUNCTION: {
|
||||||
@@ -6549,6 +6574,7 @@ static JSValue js_call_c_function (JSContext *ctx, JSValue func_obj, JSValue thi
|
|||||||
JSValue ret_val;
|
JSValue ret_val;
|
||||||
JSValue *arg_buf;
|
JSValue *arg_buf;
|
||||||
int arg_count, i;
|
int arg_count, i;
|
||||||
|
int saved_vs_top = -1; /* for value stack padding cleanup */
|
||||||
JSCFunctionEnum cproto;
|
JSCFunctionEnum cproto;
|
||||||
|
|
||||||
f = JS_VALUE_GET_FUNCTION (func_obj);
|
f = JS_VALUE_GET_FUNCTION (func_obj);
|
||||||
@@ -6571,12 +6597,14 @@ static JSValue js_call_c_function (JSContext *ctx, JSValue func_obj, JSValue thi
|
|||||||
arg_buf = argv;
|
arg_buf = argv;
|
||||||
|
|
||||||
if (unlikely (argc < arg_count)) {
|
if (unlikely (argc < arg_count)) {
|
||||||
/* ensure that at least argc_count arguments are readable */
|
/* Pad args on the value stack (GC-scanned) instead of alloca */
|
||||||
arg_buf = alloca (sizeof (arg_buf[0]) * arg_count);
|
saved_vs_top = ctx->value_stack_top;
|
||||||
for (i = 0; i < argc; i++)
|
for (i = 0; i < argc; i++)
|
||||||
arg_buf[i] = argv[i];
|
ctx->value_stack[saved_vs_top + i] = argv[i];
|
||||||
for (i = argc; i < arg_count; i++)
|
for (i = argc; i < arg_count; i++)
|
||||||
arg_buf[i] = JS_NULL;
|
ctx->value_stack[saved_vs_top + i] = JS_NULL;
|
||||||
|
ctx->value_stack_top = saved_vs_top + arg_count;
|
||||||
|
arg_buf = &ctx->value_stack[saved_vs_top];
|
||||||
sf->arg_count = arg_count;
|
sf->arg_count = arg_count;
|
||||||
}
|
}
|
||||||
sf->arg_buf = (JSValue *)arg_buf;
|
sf->arg_buf = (JSValue *)arg_buf;
|
||||||
@@ -6660,6 +6688,10 @@ static JSValue js_call_c_function (JSContext *ctx, JSValue func_obj, JSValue thi
|
|||||||
|
|
||||||
rt->current_stack_frame = sf->prev_frame;
|
rt->current_stack_frame = sf->prev_frame;
|
||||||
|
|
||||||
|
/* Restore value stack if we used it for arg padding */
|
||||||
|
if (saved_vs_top >= 0)
|
||||||
|
ctx->value_stack_top = saved_vs_top;
|
||||||
|
|
||||||
if (unlikely (ctx->trace_hook) && (ctx->trace_type & JS_HOOK_RET))
|
if (unlikely (ctx->trace_hook) && (ctx->trace_type & JS_HOOK_RET))
|
||||||
ctx->trace_hook (ctx, JS_HOOK_RET, NULL, ctx->trace_data);
|
ctx->trace_hook (ctx, JS_HOOK_RET, NULL, ctx->trace_data);
|
||||||
|
|
||||||
@@ -6731,6 +6763,9 @@ static JSValue JS_CallInternal (JSContext *caller_ctx, JSValue func_obj, JSValue
|
|||||||
return js_call_c_function (caller_ctx, func_obj, this_obj, argc, (JSValue *)argv);
|
return js_call_c_function (caller_ctx, func_obj, this_obj, argc, (JSValue *)argv);
|
||||||
case JS_FUNC_KIND_BYTECODE:
|
case JS_FUNC_KIND_BYTECODE:
|
||||||
break; /* continue to bytecode execution below */
|
break; /* continue to bytecode execution below */
|
||||||
|
case JS_FUNC_KIND_REGISTER:
|
||||||
|
return JS_CallRegisterVM(caller_ctx, f->u.reg.code, this_obj, argc, (JSValue *)argv,
|
||||||
|
f->u.reg.env_record, f->u.reg.outer_frame);
|
||||||
default:
|
default:
|
||||||
goto not_a_function;
|
goto not_a_function;
|
||||||
}
|
}
|
||||||
@@ -19757,9 +19792,16 @@ static int js_is_regexp (JSContext *ctx, JSValue obj);
|
|||||||
/* RegExp */
|
/* RegExp */
|
||||||
|
|
||||||
static void js_regexp_finalizer (JSRuntime *rt, JSValue val) {
|
static void js_regexp_finalizer (JSRuntime *rt, JSValue val) {
|
||||||
/* With copying GC, memory is reclaimed automatically */
|
/* JSRegExp is allocated with js_mallocz_rt, not on GC heap */
|
||||||
|
if (JS_IsRecord(val)) {
|
||||||
|
JSRecord *p = (JSRecord *)JS_VALUE_GET_OBJ(val);
|
||||||
|
JSRegExp *re = (JSRegExp *)REC_GET_OPAQUE(p);
|
||||||
|
if (re) {
|
||||||
|
js_free_rt(re);
|
||||||
|
REC_SET_OPAQUE(p, NULL);
|
||||||
|
}
|
||||||
|
}
|
||||||
(void)rt;
|
(void)rt;
|
||||||
(void)val;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* create a string containing the RegExp bytecode */
|
/* create a string containing the RegExp bytecode */
|
||||||
@@ -19852,13 +19894,35 @@ static JSValue js_regexp_constructor_internal (JSContext *ctx, JSValue pattern,
|
|||||||
return JS_EXCEPTION;
|
return JS_EXCEPTION;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Root pattern and bc so GC can update them during allocations */
|
||||||
|
JSGCRef pat_ref, bc_ref;
|
||||||
|
JS_AddGCRef(ctx, &pat_ref);
|
||||||
|
JS_AddGCRef(ctx, &bc_ref);
|
||||||
|
pat_ref.val = pattern;
|
||||||
|
bc_ref.val = bc;
|
||||||
|
|
||||||
obj = JS_NewObjectProtoClass (ctx, ctx->class_proto[JS_CLASS_REGEXP], JS_CLASS_REGEXP);
|
obj = JS_NewObjectProtoClass (ctx, ctx->class_proto[JS_CLASS_REGEXP], JS_CLASS_REGEXP);
|
||||||
if (JS_IsException (obj)) goto fail;
|
if (JS_IsException (obj)) {
|
||||||
|
JS_DeleteGCRef(ctx, &bc_ref);
|
||||||
|
JS_DeleteGCRef(ctx, &pat_ref);
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
p = JS_VALUE_GET_OBJ (obj);
|
p = JS_VALUE_GET_OBJ (obj);
|
||||||
/* Allocate JSRegExp and store in opaque slot */
|
/* Allocate JSRegExp with runtime allocator (not GC heap) so it survives GC.
|
||||||
re = js_malloc (ctx, sizeof(JSRegExp));
|
The pattern/bytecode JSText pointers inside are forwarded by the GC's
|
||||||
if (!re) goto fail;
|
OBJ_RECORD handler for JS_CLASS_REGEXP. */
|
||||||
|
re = js_mallocz_rt (sizeof(JSRegExp));
|
||||||
|
if (!re) {
|
||||||
|
JS_DeleteGCRef(ctx, &bc_ref);
|
||||||
|
JS_DeleteGCRef(ctx, &pat_ref);
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
REC_SET_OPAQUE(p, re);
|
REC_SET_OPAQUE(p, re);
|
||||||
|
/* Re-read pattern and bc from GC roots — they may have been moved */
|
||||||
|
pattern = pat_ref.val;
|
||||||
|
bc = bc_ref.val;
|
||||||
|
JS_DeleteGCRef(ctx, &bc_ref);
|
||||||
|
JS_DeleteGCRef(ctx, &pat_ref);
|
||||||
/* Store pattern and bytecode - need to handle both immediate and heap strings */
|
/* Store pattern and bytecode - need to handle both immediate and heap strings */
|
||||||
re->pattern = MIST_IsImmediateASCII (pattern) ? NULL : (JSText *)JS_VALUE_GET_PTR (pattern);
|
re->pattern = MIST_IsImmediateASCII (pattern) ? NULL : (JSText *)JS_VALUE_GET_PTR (pattern);
|
||||||
re->bytecode = MIST_IsImmediateASCII (bc) ? NULL : (JSText *)JS_VALUE_GET_PTR (bc);
|
re->bytecode = MIST_IsImmediateASCII (bc) ? NULL : (JSText *)JS_VALUE_GET_PTR (bc);
|
||||||
@@ -20025,11 +20089,14 @@ void *lre_realloc (void *opaque, void *ptr, size_t size) {
|
|||||||
/* Convert UTF-32 JSText to UTF-16 buffer for regex engine.
|
/* Convert UTF-32 JSText to UTF-16 buffer for regex engine.
|
||||||
Returns allocated uint16_t buffer that must be freed by caller.
|
Returns allocated uint16_t buffer that must be freed by caller.
|
||||||
Sets *out_len to number of uint16 code units. */
|
Sets *out_len to number of uint16 code units. */
|
||||||
static uint16_t *js_string_to_utf16 (JSContext *ctx, JSText *str, int *out_len) {
|
static uint16_t *js_string_to_utf16 (JSContext *ctx, JSValue str_val, int *out_len) {
|
||||||
|
JSText *str = JS_VALUE_GET_STRING (str_val);
|
||||||
int len = (int)JSText_len (str);
|
int len = (int)JSText_len (str);
|
||||||
/* Worst case: each UTF-32 char becomes 2 UTF-16 surrogates */
|
/* Worst case: each UTF-32 char becomes 2 UTF-16 surrogates */
|
||||||
uint16_t *buf = js_malloc (ctx, len * 2 * sizeof (uint16_t));
|
uint16_t *buf = js_malloc (ctx, len * 2 * sizeof (uint16_t));
|
||||||
if (!buf) return NULL;
|
if (!buf) return NULL;
|
||||||
|
/* Re-read str after js_malloc (GC may have moved it) */
|
||||||
|
str = JS_VALUE_GET_STRING (str_val);
|
||||||
|
|
||||||
int j = 0;
|
int j = 0;
|
||||||
for (int i = 0; i < len; i++) {
|
for (int i = 0; i < len; i++) {
|
||||||
@@ -20061,8 +20128,16 @@ static JSValue js_regexp_exec (JSContext *ctx, JSValue this_val, int argc, JSVal
|
|||||||
|
|
||||||
if (!re) return JS_EXCEPTION;
|
if (!re) return JS_EXCEPTION;
|
||||||
|
|
||||||
|
/* GC-safety: root this_val and str_val since GC may move them */
|
||||||
|
JSGCRef this_ref, str_ref;
|
||||||
|
JS_PushGCRef(ctx, &this_ref);
|
||||||
|
this_ref.val = this_val;
|
||||||
|
|
||||||
str_val = JS_ToString (ctx, argv[0]);
|
str_val = JS_ToString (ctx, argv[0]);
|
||||||
if (JS_IsException (str_val)) return JS_EXCEPTION;
|
if (JS_IsException (str_val)) { JS_PopGCRef(ctx, &this_ref); return JS_EXCEPTION; }
|
||||||
|
|
||||||
|
JS_PushGCRef(ctx, &str_ref);
|
||||||
|
str_ref.val = str_val;
|
||||||
|
|
||||||
ret = JS_EXCEPTION;
|
ret = JS_EXCEPTION;
|
||||||
res = JS_NULL;
|
res = JS_NULL;
|
||||||
@@ -20071,7 +20146,7 @@ static JSValue js_regexp_exec (JSContext *ctx, JSValue this_val, int argc, JSVal
|
|||||||
match0 = JS_NULL;
|
match0 = JS_NULL;
|
||||||
capture = NULL;
|
capture = NULL;
|
||||||
|
|
||||||
val = JS_GetPropertyStr (ctx, this_val, "lastIndex");
|
val = JS_GetPropertyStr (ctx, this_ref.val, "lastIndex");
|
||||||
if (JS_IsException (val) || JS_ToLength (ctx, &last_index, val))
|
if (JS_IsException (val) || JS_ToLength (ctx, &last_index, val))
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
@@ -20079,17 +20154,23 @@ static JSValue js_regexp_exec (JSContext *ctx, JSValue this_val, int argc, JSVal
|
|||||||
re_flags = lre_get_flags (re_bytecode);
|
re_flags = lre_get_flags (re_bytecode);
|
||||||
if ((re_flags & (LRE_FLAG_GLOBAL | LRE_FLAG_STICKY)) == 0) last_index = 0;
|
if ((re_flags & (LRE_FLAG_GLOBAL | LRE_FLAG_STICKY)) == 0) last_index = 0;
|
||||||
|
|
||||||
str = JS_VALUE_GET_STRING (str_val);
|
str = JS_VALUE_GET_STRING (str_ref.val);
|
||||||
capture_count = lre_get_capture_count (re_bytecode);
|
capture_count = lre_get_capture_count (re_bytecode);
|
||||||
|
|
||||||
if (capture_count > 0) {
|
if (capture_count > 0) {
|
||||||
capture = js_malloc (ctx, sizeof (capture[0]) * capture_count * 2);
|
capture = js_malloc (ctx, sizeof (capture[0]) * capture_count * 2);
|
||||||
if (!capture) goto fail;
|
if (!capture) goto fail;
|
||||||
|
/* GC may have run — re-read bytecode and str */
|
||||||
|
re_bytecode = (uint8_t *)re->bytecode->packed;
|
||||||
|
str = JS_VALUE_GET_STRING (str_ref.val);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Convert UTF-32 string to UTF-16 for regex engine */
|
/* Convert UTF-32 string to UTF-16 for regex engine */
|
||||||
utf16_buf = js_string_to_utf16 (ctx, str, &utf16_len);
|
utf16_buf = js_string_to_utf16 (ctx, str_ref.val, &utf16_len);
|
||||||
if (!utf16_buf) goto fail;
|
if (!utf16_buf) goto fail;
|
||||||
|
/* GC may have run inside js_string_to_utf16 — re-read */
|
||||||
|
re_bytecode = (uint8_t *)re->bytecode->packed;
|
||||||
|
str = JS_VALUE_GET_STRING (str_ref.val);
|
||||||
shift = 1; /* UTF-16 mode */
|
shift = 1; /* UTF-16 mode */
|
||||||
str_buf = (uint8_t *)utf16_buf;
|
str_buf = (uint8_t *)utf16_buf;
|
||||||
|
|
||||||
@@ -20102,7 +20183,7 @@ static JSValue js_regexp_exec (JSContext *ctx, JSValue this_val, int argc, JSVal
|
|||||||
if (rc != 1) {
|
if (rc != 1) {
|
||||||
if (rc >= 0) {
|
if (rc >= 0) {
|
||||||
if (rc == 2 || (re_flags & (LRE_FLAG_GLOBAL | LRE_FLAG_STICKY))) {
|
if (rc == 2 || (re_flags & (LRE_FLAG_GLOBAL | LRE_FLAG_STICKY))) {
|
||||||
if (JS_SetPropertyStr (ctx, this_val, "lastIndex", JS_NewInt32 (ctx, 0))
|
if (JS_SetPropertyStr (ctx, this_ref.val, "lastIndex", JS_NewInt32 (ctx, 0))
|
||||||
< 0)
|
< 0)
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
@@ -20117,7 +20198,7 @@ static JSValue js_regexp_exec (JSContext *ctx, JSValue this_val, int argc, JSVal
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (re_flags & (LRE_FLAG_GLOBAL | LRE_FLAG_STICKY)) {
|
if (re_flags & (LRE_FLAG_GLOBAL | LRE_FLAG_STICKY)) {
|
||||||
if (JS_SetPropertyStr (ctx, this_val, "lastIndex", JS_NewInt32 (ctx, (capture[1] - str_buf) >> shift))
|
if (JS_SetPropertyStr (ctx, this_ref.val, "lastIndex", JS_NewInt32 (ctx, (capture[1] - str_buf) >> shift))
|
||||||
< 0)
|
< 0)
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
@@ -20160,6 +20241,7 @@ static JSValue js_regexp_exec (JSContext *ctx, JSValue this_val, int argc, JSVal
|
|||||||
|
|
||||||
s = JS_NULL;
|
s = JS_NULL;
|
||||||
if (start != -1) {
|
if (start != -1) {
|
||||||
|
str = JS_VALUE_GET_STRING(str_ref.val); /* re-read after GC points */
|
||||||
s = js_sub_string (ctx, str, start, end);
|
s = js_sub_string (ctx, str, start, end);
|
||||||
if (JS_IsException (s)) goto fail;
|
if (JS_IsException (s)) goto fail;
|
||||||
}
|
}
|
||||||
@@ -20210,11 +20292,15 @@ static JSValue js_regexp_exec (JSContext *ctx, JSValue this_val, int argc, JSVal
|
|||||||
done:
|
done:
|
||||||
js_free (ctx, capture);
|
js_free (ctx, capture);
|
||||||
js_free (ctx, utf16_buf);
|
js_free (ctx, utf16_buf);
|
||||||
|
JS_PopGCRef(ctx, &str_ref);
|
||||||
|
JS_PopGCRef(ctx, &this_ref);
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
fail:
|
fail:
|
||||||
js_free (ctx, capture);
|
js_free (ctx, capture);
|
||||||
js_free (ctx, utf16_buf);
|
js_free (ctx, utf16_buf);
|
||||||
|
JS_PopGCRef(ctx, &str_ref);
|
||||||
|
JS_PopGCRef(ctx, &this_ref);
|
||||||
return JS_EXCEPTION;
|
return JS_EXCEPTION;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -21744,7 +21830,13 @@ static JSValue js_cell_text (JSContext *ctx, JSValue this_val, int argc, JSValue
|
|||||||
/* Handle array */
|
/* Handle array */
|
||||||
if (JS_IsArray (arg)) {
|
if (JS_IsArray (arg)) {
|
||||||
int64_t len;
|
int64_t len;
|
||||||
if (js_get_length64 (ctx, &len, arg)) return JS_EXCEPTION;
|
JSGCRef arg_ref;
|
||||||
|
JS_AddGCRef(ctx, &arg_ref);
|
||||||
|
arg_ref.val = arg;
|
||||||
|
if (js_get_length64 (ctx, &len, arg_ref.val)) {
|
||||||
|
JS_DeleteGCRef(ctx, &arg_ref);
|
||||||
|
return JS_EXCEPTION;
|
||||||
|
}
|
||||||
|
|
||||||
const char *separator = "";
|
const char *separator = "";
|
||||||
BOOL sep_alloc = FALSE;
|
BOOL sep_alloc = FALSE;
|
||||||
@@ -21767,11 +21859,12 @@ static JSValue js_cell_text (JSContext *ctx, JSValue this_val, int argc, JSValue
|
|||||||
if (!b) goto array_fail;
|
if (!b) goto array_fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
JSValue item = JS_GetPropertyInt64 (ctx, arg, i);
|
JSValue item = JS_GetPropertyInt64 (ctx, arg_ref.val, i);
|
||||||
if (JS_IsException (item)) goto array_fail;
|
if (JS_IsException (item)) goto array_fail;
|
||||||
|
|
||||||
if (!JS_VALUE_IS_TEXT (item)) {
|
if (!JS_VALUE_IS_TEXT (item)) {
|
||||||
if (sep_alloc) JS_FreeCString (ctx, separator);
|
if (sep_alloc) JS_FreeCString (ctx, separator);
|
||||||
|
JS_DeleteGCRef(ctx, &arg_ref);
|
||||||
return JS_ThrowTypeError (ctx, "text: array element is not a string");
|
return JS_ThrowTypeError (ctx, "text: array element is not a string");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -21783,10 +21876,12 @@ static JSValue js_cell_text (JSContext *ctx, JSValue this_val, int argc, JSValue
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (sep_alloc) JS_FreeCString (ctx, separator);
|
if (sep_alloc) JS_FreeCString (ctx, separator);
|
||||||
|
JS_DeleteGCRef(ctx, &arg_ref);
|
||||||
return pretext_end (ctx, b);
|
return pretext_end (ctx, b);
|
||||||
|
|
||||||
array_fail:
|
array_fail:
|
||||||
if (sep_alloc) JS_FreeCString (ctx, separator);
|
if (sep_alloc) JS_FreeCString (ctx, separator);
|
||||||
|
JS_DeleteGCRef(ctx, &arg_ref);
|
||||||
return JS_EXCEPTION;
|
return JS_EXCEPTION;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -29411,10 +29506,12 @@ static cJSON *ast_parse_arrow_function (ASTParseState *s) {
|
|||||||
cJSON_AddItemToObject (node, "statements", stmts);
|
cJSON_AddItemToObject (node, "statements", stmts);
|
||||||
if (s->token_val == '}') ast_next_token (s);
|
if (s->token_val == '}') ast_next_token (s);
|
||||||
} else {
|
} else {
|
||||||
/* Expression body - wrap in implicit return */
|
/* Expression body - wrap in implicit return.
|
||||||
|
Use assign_expr (not full expr) so commas after the body
|
||||||
|
are NOT consumed — matches JS spec (AssignmentExpression). */
|
||||||
cJSON *stmts = cJSON_CreateArray ();
|
cJSON *stmts = cJSON_CreateArray ();
|
||||||
cJSON *ret = ast_node (s, "return", s->token_ptr);
|
cJSON *ret = ast_node (s, "return", s->token_ptr);
|
||||||
cJSON *expr = ast_parse_expr (s);
|
cJSON *expr = ast_parse_assign_expr (s);
|
||||||
cJSON_AddItemToObject (ret, "expression", expr);
|
cJSON_AddItemToObject (ret, "expression", expr);
|
||||||
ast_node_end (s, ret, s->buf_ptr);
|
ast_node_end (s, ret, s->buf_ptr);
|
||||||
cJSON_AddItemToArray (stmts, ret);
|
cJSON_AddItemToArray (stmts, ret);
|
||||||
@@ -30568,6 +30665,7 @@ typedef struct MachVarInfo {
|
|||||||
int slot;
|
int slot;
|
||||||
int is_const; /* 1 for def, function args; 0 for var */
|
int is_const; /* 1 for def, function args; 0 for var */
|
||||||
int is_closure; /* 1 if captured by a nested function */
|
int is_closure; /* 1 if captured by a nested function */
|
||||||
|
int scope_depth; /* block scope nesting level */
|
||||||
} MachVarInfo;
|
} MachVarInfo;
|
||||||
|
|
||||||
/* ---- Compile-time constant pool entry ---- */
|
/* ---- Compile-time constant pool entry ---- */
|
||||||
@@ -30784,6 +30882,7 @@ static void mach_add_var(MachCompState *cs, const char *name, int slot, int is_c
|
|||||||
v->slot = slot;
|
v->slot = slot;
|
||||||
v->is_const = is_const;
|
v->is_const = is_const;
|
||||||
v->is_closure = 0;
|
v->is_closure = 0;
|
||||||
|
v->scope_depth = cs->scope_depth;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Find a variable in the current scope */
|
/* Find a variable in the current scope */
|
||||||
@@ -31206,28 +31305,7 @@ static int mach_compile_expr(MachCompState *cs, cJSON *node, int dest) {
|
|||||||
int save = cs->freereg;
|
int save = cs->freereg;
|
||||||
int lr = mach_compile_expr(cs, left, -1);
|
int lr = mach_compile_expr(cs, left, -1);
|
||||||
int rr = mach_compile_expr(cs, right, -1);
|
int rr = mach_compile_expr(cs, right, -1);
|
||||||
/* Use MACH_ABC with a new opcode or use GETINDEX + check null.
|
mach_emit(cs, MACH_ABC(MACH_HASPROP, dest, rr, lr));
|
||||||
For now, emit a HAS instruction (MACH_GETINDEX) and check if result is non-null.
|
|
||||||
Actually, we need a proper HAS check. Let's use a call to a runtime helper. */
|
|
||||||
/* We'll emit GETFIELD/GETINDEX then JMPNULL to check existence.
|
|
||||||
But "in" checks presence, not value. For string keys, use GETFIELD and check non-null.
|
|
||||||
This is an approximation that works for most cases. */
|
|
||||||
mach_emit(cs, MACH_ABC(MACH_GETINDEX, dest, rr, lr));
|
|
||||||
/* Check if result is null — if null, property doesn't exist → false
|
|
||||||
But this is wrong because a property CAN be set to null.
|
|
||||||
We need a proper HASPROP opcode. For now let's use JMPNULL. */
|
|
||||||
int jmpnull_pc = mach_current_pc(cs);
|
|
||||||
mach_emit(cs, MACH_AsBx(MACH_JMPNULL, dest, 0));
|
|
||||||
mach_emit(cs, MACH_ABx(MACH_LOADTRUE, dest, 0));
|
|
||||||
int jmpend_pc = mach_current_pc(cs);
|
|
||||||
mach_emit(cs, MACH_sJ(MACH_JMP, 0));
|
|
||||||
/* Patch jmpnull to false */
|
|
||||||
int offset = mach_current_pc(cs) - (jmpnull_pc + 1);
|
|
||||||
cs->code[jmpnull_pc] = MACH_AsBx(MACH_JMPNULL, dest, (int16_t)offset);
|
|
||||||
mach_emit(cs, MACH_ABx(MACH_LOADFALSE, dest, 0));
|
|
||||||
/* Patch jmpend */
|
|
||||||
offset = mach_current_pc(cs) - (jmpend_pc + 1);
|
|
||||||
cs->code[jmpend_pc] = MACH_sJ(MACH_JMP, offset);
|
|
||||||
mach_free_reg_to(cs, save);
|
mach_free_reg_to(cs, save);
|
||||||
return dest;
|
return dest;
|
||||||
}
|
}
|
||||||
@@ -31555,6 +31633,63 @@ static int mach_compile_expr(MachCompState *cs, cJSON *node, int dest) {
|
|||||||
return dest;
|
return dest;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Delete operator */
|
||||||
|
if (strcmp(kind, "delete") == 0) {
|
||||||
|
if (dest < 0) dest = mach_reserve_reg(cs);
|
||||||
|
cJSON *operand = cJSON_GetObjectItem(node, "expression");
|
||||||
|
if (!operand) operand = cJSON_GetObjectItem(node, "right");
|
||||||
|
if (operand) {
|
||||||
|
const char *okind = cJSON_GetStringValue(cJSON_GetObjectItem(operand, "kind"));
|
||||||
|
if (okind && strcmp(okind, ".") == 0) {
|
||||||
|
/* delete obj.prop */
|
||||||
|
cJSON *obj_node = cJSON_GetObjectItem(operand, "left");
|
||||||
|
cJSON *prop_node = cJSON_GetObjectItem(operand, "right");
|
||||||
|
const char *pname = cJSON_GetStringValue(cJSON_GetObjectItem(prop_node, "name"));
|
||||||
|
if (!pname) pname = cJSON_GetStringValue(prop_node);
|
||||||
|
int save = cs->freereg;
|
||||||
|
int objr = mach_compile_expr(cs, obj_node, -1);
|
||||||
|
int ki = mach_cpool_add_str(cs, pname);
|
||||||
|
mach_emit(cs, MACH_ABC(MACH_DELETE, dest, objr, ki));
|
||||||
|
mach_free_reg_to(cs, save);
|
||||||
|
return dest;
|
||||||
|
} else if (okind && strcmp(okind, "[") == 0) {
|
||||||
|
/* delete obj[expr] */
|
||||||
|
cJSON *obj_node = cJSON_GetObjectItem(operand, "left");
|
||||||
|
cJSON *idx_node = cJSON_GetObjectItem(operand, "right");
|
||||||
|
int save = cs->freereg;
|
||||||
|
int objr = mach_compile_expr(cs, obj_node, -1);
|
||||||
|
int ir = mach_compile_expr(cs, idx_node, -1);
|
||||||
|
mach_emit(cs, MACH_ABC(MACH_DELETEINDEX, dest, objr, ir));
|
||||||
|
mach_free_reg_to(cs, save);
|
||||||
|
return dest;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mach_emit(cs, MACH_ABx(MACH_LOADTRUE, dest, 0));
|
||||||
|
return dest;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* This reference — slot 0 is always 'this' */
|
||||||
|
if (strcmp(kind, "this") == 0) {
|
||||||
|
if (dest >= 0 && dest != 0) {
|
||||||
|
mach_emit(cs, MACH_ABC(MACH_MOVE, dest, 0, 0));
|
||||||
|
return dest;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Regex literal */
|
||||||
|
if (strcmp(kind, "regexp") == 0) {
|
||||||
|
if (dest < 0) dest = mach_reserve_reg(cs);
|
||||||
|
const char *pattern = cJSON_GetStringValue(cJSON_GetObjectItem(node, "pattern"));
|
||||||
|
const char *flags = cJSON_GetStringValue(cJSON_GetObjectItem(node, "flags"));
|
||||||
|
if (!pattern) pattern = "";
|
||||||
|
if (!flags) flags = "";
|
||||||
|
int pi = mach_cpool_add_str(cs, pattern);
|
||||||
|
int fi = mach_cpool_add_str(cs, flags);
|
||||||
|
mach_emit(cs, MACH_ABC(MACH_REGEXP, dest, pi, fi));
|
||||||
|
return dest;
|
||||||
|
}
|
||||||
|
|
||||||
/* Fallback: unsupported expression kind — load null */
|
/* Fallback: unsupported expression kind — load null */
|
||||||
if (dest < 0) dest = mach_reserve_reg(cs);
|
if (dest < 0) dest = mach_reserve_reg(cs);
|
||||||
mach_emit(cs, MACH_ABx(MACH_LOADNULL, dest, 0));
|
mach_emit(cs, MACH_ABx(MACH_LOADNULL, dest, 0));
|
||||||
@@ -31575,7 +31710,17 @@ static void mach_compile_stmt(MachCompState *cs, cJSON *stmt) {
|
|||||||
cJSON *right = cJSON_GetObjectItem(stmt, "right");
|
cJSON *right = cJSON_GetObjectItem(stmt, "right");
|
||||||
const char *name = cJSON_GetStringValue(cJSON_GetObjectItem(left, "name"));
|
const char *name = cJSON_GetStringValue(cJSON_GetObjectItem(left, "name"));
|
||||||
if (!name) return;
|
if (!name) return;
|
||||||
int slot = mach_find_var(cs, name);
|
/* Check if var exists at current scope depth — if so, reuse it.
|
||||||
|
If it exists at a shallower depth, shadow it with a new slot. */
|
||||||
|
int slot = -1;
|
||||||
|
for (int i = cs->var_count - 1; i >= 0; i--) {
|
||||||
|
if (strcmp(cs->vars[i].name, name) == 0) {
|
||||||
|
if (cs->vars[i].scope_depth == cs->scope_depth) {
|
||||||
|
slot = cs->vars[i].slot; /* same scope — reuse */
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
if (slot < 0) {
|
if (slot < 0) {
|
||||||
slot = mach_reserve_reg(cs);
|
slot = mach_reserve_reg(cs);
|
||||||
mach_add_var(cs, name, slot, strcmp(kind, "def") == 0);
|
mach_add_var(cs, name, slot, strcmp(kind, "def") == 0);
|
||||||
@@ -31650,6 +31795,8 @@ static void mach_compile_stmt(MachCompState *cs, cJSON *stmt) {
|
|||||||
|
|
||||||
/* Block */
|
/* Block */
|
||||||
if (strcmp(kind, "block") == 0) {
|
if (strcmp(kind, "block") == 0) {
|
||||||
|
int saved_var_count = cs->var_count;
|
||||||
|
cs->scope_depth++;
|
||||||
cJSON *stmts = cJSON_GetObjectItem(stmt, "statements");
|
cJSON *stmts = cJSON_GetObjectItem(stmt, "statements");
|
||||||
if (stmts && cJSON_IsArray(stmts)) {
|
if (stmts && cJSON_IsArray(stmts)) {
|
||||||
int count = cJSON_GetArraySize(stmts);
|
int count = cJSON_GetArraySize(stmts);
|
||||||
@@ -31657,6 +31804,10 @@ static void mach_compile_stmt(MachCompState *cs, cJSON *stmt) {
|
|||||||
mach_compile_stmt(cs, cJSON_GetArrayItem(stmts, i));
|
mach_compile_stmt(cs, cJSON_GetArrayItem(stmts, i));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
cs->scope_depth--;
|
||||||
|
for (int i = saved_var_count; i < cs->var_count; i++)
|
||||||
|
sys_free(cs->vars[i].name);
|
||||||
|
cs->var_count = saved_var_count;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -31676,6 +31827,8 @@ static void mach_compile_stmt(MachCompState *cs, cJSON *stmt) {
|
|||||||
|
|
||||||
/* Compile then branch — "then" is a direct array of statements */
|
/* Compile then branch — "then" is a direct array of statements */
|
||||||
if (then_body) {
|
if (then_body) {
|
||||||
|
int saved_vc = cs->var_count;
|
||||||
|
cs->scope_depth++;
|
||||||
if (cJSON_IsArray(then_body)) {
|
if (cJSON_IsArray(then_body)) {
|
||||||
int count = cJSON_GetArraySize(then_body);
|
int count = cJSON_GetArraySize(then_body);
|
||||||
for (int i = 0; i < count; i++)
|
for (int i = 0; i < count; i++)
|
||||||
@@ -31690,6 +31843,10 @@ static void mach_compile_stmt(MachCompState *cs, cJSON *stmt) {
|
|||||||
mach_compile_stmt(cs, then_body);
|
mach_compile_stmt(cs, then_body);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
cs->scope_depth--;
|
||||||
|
for (int i = saved_vc; i < cs->var_count; i++)
|
||||||
|
sys_free(cs->vars[i].name);
|
||||||
|
cs->var_count = saved_vc;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Check for else-if chain ("list") or plain else */
|
/* Check for else-if chain ("list") or plain else */
|
||||||
@@ -31708,6 +31865,8 @@ static void mach_compile_stmt(MachCompState *cs, cJSON *stmt) {
|
|||||||
cs->code[jmpfalse_pc] = MACH_AsBx(MACH_JMPFALSE, cr, (int16_t)offset);
|
cs->code[jmpfalse_pc] = MACH_AsBx(MACH_JMPFALSE, cr, (int16_t)offset);
|
||||||
|
|
||||||
/* Compile else — could be a direct array, object, or else-if stmt */
|
/* Compile else — could be a direct array, object, or else-if stmt */
|
||||||
|
int saved_vc = cs->var_count;
|
||||||
|
cs->scope_depth++;
|
||||||
if (cJSON_IsArray(else_body)) {
|
if (cJSON_IsArray(else_body)) {
|
||||||
int count = cJSON_GetArraySize(else_body);
|
int count = cJSON_GetArraySize(else_body);
|
||||||
for (int i = 0; i < count; i++)
|
for (int i = 0; i < count; i++)
|
||||||
@@ -31722,6 +31881,10 @@ static void mach_compile_stmt(MachCompState *cs, cJSON *stmt) {
|
|||||||
mach_compile_stmt(cs, else_body);
|
mach_compile_stmt(cs, else_body);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
cs->scope_depth--;
|
||||||
|
for (int i = saved_vc; i < cs->var_count; i++)
|
||||||
|
sys_free(cs->vars[i].name);
|
||||||
|
cs->var_count = saved_vc;
|
||||||
|
|
||||||
/* Patch jmpend */
|
/* Patch jmpend */
|
||||||
offset = mach_current_pc(cs) - (jmpend_pc + 1);
|
offset = mach_current_pc(cs) - (jmpend_pc + 1);
|
||||||
@@ -31754,6 +31917,8 @@ static void mach_compile_stmt(MachCompState *cs, cJSON *stmt) {
|
|||||||
|
|
||||||
/* Compile body — "statements" on a child "block"/"body", or directly on the node */
|
/* Compile body — "statements" on a child "block"/"body", or directly on the node */
|
||||||
{
|
{
|
||||||
|
int saved_vc = cs->var_count;
|
||||||
|
cs->scope_depth++;
|
||||||
cJSON *body = cJSON_GetObjectItem(stmt, "block");
|
cJSON *body = cJSON_GetObjectItem(stmt, "block");
|
||||||
if (!body) body = cJSON_GetObjectItem(stmt, "body");
|
if (!body) body = cJSON_GetObjectItem(stmt, "body");
|
||||||
cJSON *stmts = body ? cJSON_GetObjectItem(body, "statements") : NULL;
|
cJSON *stmts = body ? cJSON_GetObjectItem(body, "statements") : NULL;
|
||||||
@@ -31765,6 +31930,10 @@ static void mach_compile_stmt(MachCompState *cs, cJSON *stmt) {
|
|||||||
} else if (body) {
|
} else if (body) {
|
||||||
mach_compile_stmt(cs, body);
|
mach_compile_stmt(cs, body);
|
||||||
}
|
}
|
||||||
|
cs->scope_depth--;
|
||||||
|
for (int i = saved_vc; i < cs->var_count; i++)
|
||||||
|
sys_free(cs->vars[i].name);
|
||||||
|
cs->var_count = saved_vc;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Patch continue chain to loop_top */
|
/* Patch continue chain to loop_top */
|
||||||
@@ -31801,6 +31970,8 @@ static void mach_compile_stmt(MachCompState *cs, cJSON *stmt) {
|
|||||||
|
|
||||||
/* For loop */
|
/* For loop */
|
||||||
if (strcmp(kind, "for") == 0) {
|
if (strcmp(kind, "for") == 0) {
|
||||||
|
int saved_vc = cs->var_count;
|
||||||
|
cs->scope_depth++;
|
||||||
cJSON *init = cJSON_GetObjectItem(stmt, "init");
|
cJSON *init = cJSON_GetObjectItem(stmt, "init");
|
||||||
cJSON *cond = cJSON_GetObjectItem(stmt, "test");
|
cJSON *cond = cJSON_GetObjectItem(stmt, "test");
|
||||||
cJSON *update = cJSON_GetObjectItem(stmt, "update");
|
cJSON *update = cJSON_GetObjectItem(stmt, "update");
|
||||||
@@ -31829,6 +32000,8 @@ static void mach_compile_stmt(MachCompState *cs, cJSON *stmt) {
|
|||||||
|
|
||||||
/* Body — "statements" on a child "block"/"body", or directly on the for node */
|
/* Body — "statements" on a child "block"/"body", or directly on the for node */
|
||||||
{
|
{
|
||||||
|
int body_vc = cs->var_count;
|
||||||
|
cs->scope_depth++;
|
||||||
cJSON *stmts = body ? cJSON_GetObjectItem(body, "statements") : NULL;
|
cJSON *stmts = body ? cJSON_GetObjectItem(body, "statements") : NULL;
|
||||||
if (!stmts) stmts = cJSON_GetObjectItem(stmt, "statements");
|
if (!stmts) stmts = cJSON_GetObjectItem(stmt, "statements");
|
||||||
if (stmts && cJSON_IsArray(stmts)) {
|
if (stmts && cJSON_IsArray(stmts)) {
|
||||||
@@ -31838,6 +32011,10 @@ static void mach_compile_stmt(MachCompState *cs, cJSON *stmt) {
|
|||||||
} else if (body) {
|
} else if (body) {
|
||||||
mach_compile_stmt(cs, body);
|
mach_compile_stmt(cs, body);
|
||||||
}
|
}
|
||||||
|
cs->scope_depth--;
|
||||||
|
for (int i = body_vc; i < cs->var_count; i++)
|
||||||
|
sys_free(cs->vars[i].name);
|
||||||
|
cs->var_count = body_vc;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Patch continue chain to update (or loop_top if no update) */
|
/* Patch continue chain to update (or loop_top if no update) */
|
||||||
@@ -31879,6 +32056,10 @@ static void mach_compile_stmt(MachCompState *cs, cJSON *stmt) {
|
|||||||
}
|
}
|
||||||
cs->loop_break = old_break;
|
cs->loop_break = old_break;
|
||||||
cs->loop_continue = old_continue;
|
cs->loop_continue = old_continue;
|
||||||
|
cs->scope_depth--;
|
||||||
|
for (int i = saved_vc; i < cs->var_count; i++)
|
||||||
|
sys_free(cs->vars[i].name);
|
||||||
|
cs->var_count = saved_vc;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -32228,6 +32409,11 @@ static JSValue reg_vm_binop(JSContext *ctx, int op, JSValue a, JSValue b) {
|
|||||||
|
|
||||||
/* Comparison ops allow mixed types — return false for mismatches */
|
/* Comparison ops allow mixed types — return false for mismatches */
|
||||||
if (op >= MACH_EQ && op <= MACH_GE) {
|
if (op >= MACH_EQ && op <= MACH_GE) {
|
||||||
|
/* Fast path: bitwise-identical values (same object/pointer) */
|
||||||
|
if (a == b) {
|
||||||
|
if (op == MACH_EQ || op == MACH_LE || op == MACH_GE) return JS_TRUE;
|
||||||
|
if (op == MACH_NEQ) return JS_FALSE;
|
||||||
|
}
|
||||||
if (JS_IsNumber(a) && JS_IsNumber(b)) {
|
if (JS_IsNumber(a) && JS_IsNumber(b)) {
|
||||||
double da, db;
|
double da, db;
|
||||||
JS_ToFloat64(ctx, &da, a);
|
JS_ToFloat64(ctx, &da, a);
|
||||||
@@ -32575,8 +32761,18 @@ static JSValue JS_CallRegisterVM(JSContext *ctx, JSCodeRegister *code,
|
|||||||
case MACH_GETFIELD: {
|
case MACH_GETFIELD: {
|
||||||
JSValue obj = frame->slots[b];
|
JSValue obj = frame->slots[b];
|
||||||
JSValue key = code->cpool[c];
|
JSValue key = code->cpool[c];
|
||||||
|
/* Non-proxy functions (arity != 2) can't have properties read */
|
||||||
|
if (JS_IsFunction(obj)) {
|
||||||
|
JSFunction *fn_chk = JS_VALUE_GET_FUNCTION(obj);
|
||||||
|
if (fn_chk->length != 2) {
|
||||||
|
JS_ThrowTypeError(ctx, "cannot read property of non-proxy function");
|
||||||
|
frame = (JSFrameRegister *)JS_VALUE_GET_PTR(frame_ref.val);
|
||||||
|
goto disrupt;
|
||||||
|
}
|
||||||
|
}
|
||||||
JSValue val = JS_GetProperty(ctx, obj, key);
|
JSValue val = JS_GetProperty(ctx, obj, key);
|
||||||
frame = (JSFrameRegister *)JS_VALUE_GET_PTR(frame_ref.val);
|
frame = (JSFrameRegister *)JS_VALUE_GET_PTR(frame_ref.val);
|
||||||
|
if (JS_IsException(val)) goto disrupt;
|
||||||
frame->slots[a] = val;
|
frame->slots[a] = val;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -32586,8 +32782,9 @@ static JSValue JS_CallRegisterVM(JSContext *ctx, JSCodeRegister *code,
|
|||||||
JSValue obj = frame->slots[a];
|
JSValue obj = frame->slots[a];
|
||||||
JSValue key = code->cpool[b];
|
JSValue key = code->cpool[b];
|
||||||
JSValue val = frame->slots[c];
|
JSValue val = frame->slots[c];
|
||||||
JS_SetProperty(ctx, obj, key, val);
|
int ret = JS_SetProperty(ctx, obj, key, val);
|
||||||
frame = (JSFrameRegister *)JS_VALUE_GET_PTR(frame_ref.val);
|
frame = (JSFrameRegister *)JS_VALUE_GET_PTR(frame_ref.val);
|
||||||
|
if (ret < 0) goto disrupt;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -32600,6 +32797,7 @@ static JSValue JS_CallRegisterVM(JSContext *ctx, JSCodeRegister *code,
|
|||||||
else
|
else
|
||||||
val = JS_GetProperty(ctx, obj, idx);
|
val = JS_GetProperty(ctx, obj, idx);
|
||||||
frame = (JSFrameRegister *)JS_VALUE_GET_PTR(frame_ref.val);
|
frame = (JSFrameRegister *)JS_VALUE_GET_PTR(frame_ref.val);
|
||||||
|
if (JS_IsException(val)) goto disrupt;
|
||||||
frame->slots[a] = val;
|
frame->slots[a] = val;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -32609,11 +32807,22 @@ static JSValue JS_CallRegisterVM(JSContext *ctx, JSCodeRegister *code,
|
|||||||
JSValue obj = frame->slots[a];
|
JSValue obj = frame->slots[a];
|
||||||
JSValue idx = frame->slots[b];
|
JSValue idx = frame->slots[b];
|
||||||
JSValue val = frame->slots[c];
|
JSValue val = frame->slots[c];
|
||||||
if (JS_IsInt(idx))
|
int ret;
|
||||||
JS_SetPropertyUint32(ctx, obj, JS_VALUE_GET_INT(idx), val);
|
if (JS_IsInt(idx)) {
|
||||||
else
|
ret = JS_SetPropertyUint32(ctx, obj, JS_VALUE_GET_INT(idx), val);
|
||||||
JS_SetProperty(ctx, obj, idx, val);
|
} else if (JS_IsText(idx) && JS_IsRecord(obj)) {
|
||||||
|
ret = JS_SetProperty(ctx, obj, idx, val);
|
||||||
|
} else if (JS_IsArray(obj)) {
|
||||||
|
JS_ThrowTypeError(ctx, "array index must be a number");
|
||||||
|
ret = -1;
|
||||||
|
} else if (JS_IsRecord(obj)) {
|
||||||
|
JS_ThrowTypeError(ctx, "object key must be a string");
|
||||||
|
ret = -1;
|
||||||
|
} else {
|
||||||
|
ret = JS_SetProperty(ctx, obj, idx, val);
|
||||||
|
}
|
||||||
frame = (JSFrameRegister *)JS_VALUE_GET_PTR(frame_ref.val);
|
frame = (JSFrameRegister *)JS_VALUE_GET_PTR(frame_ref.val);
|
||||||
|
if (ret < 0) goto disrupt;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -32873,6 +33082,46 @@ static JSValue JS_CallRegisterVM(JSContext *ctx, JSCodeRegister *code,
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case MACH_DELETE: {
|
||||||
|
JSValue obj = frame->slots[b];
|
||||||
|
JSValue key = code->cpool[c];
|
||||||
|
int ret = JS_DeleteProperty(ctx, obj, key);
|
||||||
|
frame = (JSFrameRegister *)JS_VALUE_GET_PTR(frame_ref.val);
|
||||||
|
if (ret < 0) goto disrupt;
|
||||||
|
frame->slots[a] = JS_NewBool(ctx, ret >= 0);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case MACH_DELETEINDEX: {
|
||||||
|
JSValue obj = frame->slots[b];
|
||||||
|
JSValue key = frame->slots[c];
|
||||||
|
int ret = JS_DeleteProperty(ctx, obj, key);
|
||||||
|
frame = (JSFrameRegister *)JS_VALUE_GET_PTR(frame_ref.val);
|
||||||
|
if (ret < 0) goto disrupt;
|
||||||
|
frame->slots[a] = JS_NewBool(ctx, ret >= 0);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case MACH_HASPROP: {
|
||||||
|
JSValue obj = frame->slots[b];
|
||||||
|
JSValue key = frame->slots[c];
|
||||||
|
int has = JS_HasProperty(ctx, obj, key);
|
||||||
|
frame = (JSFrameRegister *)JS_VALUE_GET_PTR(frame_ref.val);
|
||||||
|
frame->slots[a] = JS_NewBool(ctx, has > 0);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case MACH_REGEXP: {
|
||||||
|
JSValue argv[2];
|
||||||
|
argv[0] = code->cpool[b]; /* pattern */
|
||||||
|
argv[1] = code->cpool[c]; /* flags */
|
||||||
|
JSValue re = js_regexp_constructor(ctx, JS_NULL, 2, argv);
|
||||||
|
frame = (JSFrameRegister *)JS_VALUE_GET_PTR(frame_ref.val);
|
||||||
|
if (JS_IsException(re)) goto disrupt;
|
||||||
|
frame->slots[a] = re;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case MACH_THROW:
|
case MACH_THROW:
|
||||||
goto disrupt;
|
goto disrupt;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user