diff --git a/Makefile b/Makefile index 03e898c5..e4a7a819 100755 --- a/Makefile +++ b/Makefile @@ -56,7 +56,7 @@ static: # Bootstrap: build cell from scratch using meson (only needed once) # Also installs core scripts to ~/.cell/core bootstrap: - meson setup build_bootstrap -Dbuildtype=debugoptimized -Db_sanitize=address + meson setup build_bootstrap -Dbuildtype=debugoptimized meson compile -C build_bootstrap cp build_bootstrap/cell . cp build_bootstrap/libcell_runtime.dylib . diff --git a/internal/engine.cm b/internal/engine.cm index 5d02be07..21845db0 100644 --- a/internal/engine.cm +++ b/internal/engine.cm @@ -162,10 +162,6 @@ globalThis.log = function(name, args) { } } -log.console( - 'hello' -) - function disrupt(err) { if (is_function(err.toString)) { diff --git a/internal/nota.c b/internal/nota.c index 71b089b3..99e5f512 100755 --- a/internal/nota.c +++ b/internal/nota.c @@ -214,7 +214,7 @@ static void nota_encode_value(NotaEncodeContext *enc, JSValueConst val, JSValueC nota_stack_push(enc, replaced); JSValue to_json = JS_GetPropertyStr(ctx, replaced, "toJSON"); - if (JS_IsFunction(ctx, to_json)) { + if (JS_IsFunction(to_json)) { JSValue result = JS_Call(ctx, to_json, replaced, 0, NULL); JS_FreeValue(ctx, to_json); if (!JS_IsException(result)) { @@ -239,14 +239,14 @@ static void nota_encode_value(NotaEncodeContext *enc, JSValueConst val, JSValueC uint32_t non_function_count = 0; for (uint32_t i = 0; i < plen; i++) { JSValue prop_val = JS_GetProperty(ctx, replaced, ptab[i].atom); - if (!JS_IsFunction(ctx, prop_val)) non_function_count++; + if (!JS_IsFunction(prop_val)) non_function_count++; JS_FreeValue(ctx, prop_val); } nota_write_record(&enc->nb, non_function_count); for (uint32_t i = 0; i < plen; i++) { JSValue prop_val = JS_GetProperty(ctx, replaced, ptab[i].atom); - if (!JS_IsFunction(ctx, prop_val)) { + if (!JS_IsFunction(prop_val)) { const char *prop_name = JS_AtomToCString(ctx, ptab[i].atom); JSValue prop_key = JS_AtomToValue(ctx, ptab[i].atom); nota_write_text(&enc->nb, prop_name); @@ -338,7 +338,7 @@ static JSValue js_nota_encode(JSContext *ctx, JSValueConst this_val, int argc, J enc->ctx = ctx; enc->visitedStack = JS_NewArray(ctx); enc->cycle = 0; - enc->replacer = (argc > 1 && JS_IsFunction(ctx, argv[1])) ? argv[1] : JS_NULL; + enc->replacer = (argc > 1 && JS_IsFunction(argv[1])) ? argv[1] : JS_NULL; nota_buffer_init(&enc->nb, 128); nota_encode_value(enc, argv[0], JS_NULL, JS_NewString(ctx, "")); @@ -366,7 +366,7 @@ static JSValue js_nota_decode(JSContext *js, JSValueConst self, int argc, JSValu if (nota == -1) return JS_EXCEPTION; if (!nota) return JS_NULL; - JSValue reviver = (argc > 1 && JS_IsFunction(js, argv[1])) ? argv[1] : JS_NULL; + JSValue reviver = (argc > 1 && JS_IsFunction(argv[1])) ? argv[1] : JS_NULL; JSValue ret; JSValue holder = JS_NewObject(js); js_do_nota_decode(js, &ret, (char*)nota, holder, JS_NewString(js, ""), reviver); diff --git a/net/enet.c b/net/enet.c index 87c1bc5a..c5a36c2f 100644 --- a/net/enet.c +++ b/net/enet.c @@ -145,7 +145,7 @@ static JSValue js_enet_host_service(JSContext *ctx, JSValueConst this_val, int a ENetHost *host = JS_GetOpaque(this_val, enet_host_id); if (!host) return JS_EXCEPTION; - if (argc < 1 || !JS_IsFunction(ctx, argv[0])) return JS_ThrowTypeError(ctx, "Expected a callback function as first argument"); + if (argc < 1 || !JS_IsFunction(argv[0])) return JS_ThrowTypeError(ctx, "Expected a callback function as first argument"); JSValue callback = JS_DupValue(ctx, argv[0]); double secs; diff --git a/playdate/scoreboards_playdate.c b/playdate/scoreboards_playdate.c index 6fb99196..f813a912 100644 --- a/playdate/scoreboards_playdate.c +++ b/playdate/scoreboards_playdate.c @@ -102,7 +102,7 @@ static void scores_cb(PDScoresList *scores, const char *errorMessage) { JSC_SCALL(scoreboards_addScore, if (!pd_scoreboards) return JS_ThrowInternalError(js, "scoreboards not initialized"); uint32_t value = (uint32_t)js2number(js, argv[1]); - if (argc > 2 && JS_IsFunction(js, argv[2])) { + if (argc > 2 && JS_IsFunction(argv[2])) { g_scoreboard_js = js; JS_FreeValue(js, g_add_score_callback); g_add_score_callback = JS_DupValue(js, argv[2]); @@ -112,7 +112,7 @@ JSC_SCALL(scoreboards_addScore, JSC_SCALL(scoreboards_getPersonalBest, if (!pd_scoreboards) return JS_ThrowInternalError(js, "scoreboards not initialized"); - if (argc > 1 && JS_IsFunction(js, argv[1])) { + if (argc > 1 && JS_IsFunction(argv[1])) { g_scoreboard_js = js; JS_FreeValue(js, g_personal_best_callback); g_personal_best_callback = JS_DupValue(js, argv[1]); @@ -129,7 +129,7 @@ JSC_CCALL(scoreboards_freeScore, JSC_CCALL(scoreboards_getScoreboards, if (!pd_scoreboards) return JS_ThrowInternalError(js, "scoreboards not initialized"); - if (argc > 0 && JS_IsFunction(js, argv[0])) { + if (argc > 0 && JS_IsFunction(argv[0])) { g_scoreboard_js = js; JS_FreeValue(js, g_boards_list_callback); g_boards_list_callback = JS_DupValue(js, argv[0]); @@ -145,7 +145,7 @@ JSC_CCALL(scoreboards_freeBoardsList, JSC_SCALL(scoreboards_getScores, if (!pd_scoreboards) return JS_ThrowInternalError(js, "scoreboards not initialized"); - if (argc > 1 && JS_IsFunction(js, argv[1])) { + if (argc > 1 && JS_IsFunction(argv[1])) { g_scoreboard_js = js; JS_FreeValue(js, g_scores_callback); g_scores_callback = JS_DupValue(js, argv[1]); diff --git a/source/qjs_actor.c b/source/qjs_actor.c index 0ddfa96f..73db4b3f 100644 --- a/source/qjs_actor.c +++ b/source/qjs_actor.c @@ -111,7 +111,7 @@ JSC_CCALL(actor_on_exception, ) JSC_CCALL(actor_clock, - if (!JS_IsFunction(js, argv[0])) + if (!JS_IsFunction(argv[0])) return JS_ThrowReferenceError(js, "Argument must be a function."); cell_rt *actor = JS_GetContextOpaque(js); @@ -119,7 +119,7 @@ JSC_CCALL(actor_clock, ) JSC_CCALL(actor_delay, - if (!JS_IsFunction(js, argv[0])) + if (!JS_IsFunction(argv[0])) return JS_ThrowReferenceError(js, "Argument must be a function."); cell_rt *actor = JS_GetContextOpaque(js); diff --git a/source/qjs_wota.c b/source/qjs_wota.c index d9520c1c..5a12186e 100644 --- a/source/qjs_wota.c +++ b/source/qjs_wota.c @@ -88,7 +88,7 @@ static void encode_object_properties(WotaEncodeContext *enc, JSValueConst val, J for (uint32_t i = 0; i < plen; i++) { JSValue prop_val = JS_GetProperty(ctx, val, ptab[i].atom); - if (!JS_IsFunction(ctx, prop_val)) { + if (!JS_IsFunction(prop_val)) { atoms[non_function_count] = ptab[i].atom; props[non_function_count++] = prop_val; } else @@ -200,7 +200,7 @@ static void wota_encode_value(WotaEncodeContext *enc, JSValueConst val, JSValueC } wota_stack_push(enc, replaced); JSValue to_json = JS_GetPropertyStr(ctx, replaced, "toJSON"); - if (JS_IsFunction(ctx, to_json)) { + if (JS_IsFunction(to_json)) { JSValue result = JS_Call(ctx, to_json, replaced, 0, NULL); JS_FreeValue(ctx, to_json); if (!JS_IsException(result)) { @@ -359,7 +359,7 @@ static JSValue js_wota_encode(JSContext *ctx, JSValueConst this_val, int argc, J { if (argc < 1) return JS_ThrowTypeError(ctx, "wota.encode requires at least 1 argument"); size_t total_bytes; - void *wota = value2wota(ctx, argv[0], JS_IsFunction(ctx,argv[1]) ? argv[1] : JS_NULL, &total_bytes); + void *wota = value2wota(ctx, argv[0], JS_IsFunction(argv[1]) ? argv[1] : JS_NULL, &total_bytes); JSValue ret = js_new_blob_stoned_copy(ctx, wota, total_bytes); free(wota); return ret; @@ -372,7 +372,7 @@ static JSValue js_wota_decode(JSContext *ctx, JSValueConst this_val, int argc, J uint8_t *buf = js_get_blob_data(ctx, &len, argv[0]); if (buf == (uint8_t *)-1) return JS_EXCEPTION; if (!buf || len == 0) return JS_ThrowTypeError(ctx, "No blob data present"); - JSValue reviver = (argc > 1 && JS_IsFunction(ctx, argv[1])) ? argv[1] : JS_NULL; + JSValue reviver = (argc > 1 && JS_IsFunction(argv[1])) ? argv[1] : JS_NULL; char *data_ptr = (char *)buf; JSValue result = JS_NULL; JSValue holder = JS_NewObject(ctx); diff --git a/source/quickjs-opcode.h b/source/quickjs-opcode.h index ba273422..401d46e2 100644 --- a/source/quickjs-opcode.h +++ b/source/quickjs-opcode.h @@ -101,13 +101,11 @@ DEF( tail_call, 3, 1, 0, npop) /* arguments are not counted in n_pop */ DEF( call_method, 3, 2, 1, npop) /* arguments are not counted in n_pop */ DEF(tail_call_method, 3, 2, 0, npop) /* arguments are not counted in n_pop */ DEF( array_from, 3, 0, 1, npop) /* arguments are not counted in n_pop */ -DEF( apply, 3, 3, 1, u16) DEF( return, 1, 1, 0, none) DEF( return_undef, 1, 0, 0, none) DEF( throw, 1, 1, 0, none) DEF( throw_error, 6, 0, 0, atom_u8) DEF( eval, 5, 1, 1, npop_u16) /* func args... -> ret_val */ -DEF( apply_eval, 3, 2, 1, u16) /* func array -> ret_eval */ DEF( regexp, 1, 2, 1, none) /* create a RegExp object from the pattern and a bytecode string */ diff --git a/source/quickjs.c b/source/quickjs.c index e9afbd25..8206f6fc 100644 --- a/source/quickjs.c +++ b/source/quickjs.c @@ -103,7 +103,7 @@ /* dump profiling statistics (counters and sampling) when freeing the runtime */ //#define DUMP_PROFILE -#define RC_TRACE +//#define RC_TRACE /* test the GC by forcing it before each object allocation */ //#define FORCE_GC_AT_MALLOC @@ -1034,6 +1034,8 @@ static void gc_decref_child_dbg(JSRuntime *rt, JSGCObjectHeader *parent, const char *file, int line); #endif +static void gc_decref_child(JSRuntime *rt, JSGCObjectHeader *p); + int JS_SetPropertyInternal(JSContext *ctx, JSValueConst this_obj, JSAtom prop, JSValue val); static blob *js_get_blob(JSContext *ctx, JSValueConst val); static JSValue JS_ToStringFree(JSContext *ctx, JSValue val); @@ -4900,12 +4902,6 @@ static BOOL js_is_bytecode_function(JSValueConst val) return f->kind == JS_FUNC_KIND_BYTECODE; } -/* Check if a value is a function that uses proxy-call syntax (fn.a -> fn("a")) */ -static BOOL js_is_proxy_callable(JSValueConst v) -{ - return JS_VALUE_GET_TAG(v) == JS_TAG_FUNCTION; -} - /* return NULL without exception if not a function or no bytecode */ static JSFunctionBytecode *JS_GetFunctionBytecode(JSValueConst val) { @@ -5194,9 +5190,8 @@ static int js_intrinsic_array_set(JSContext *ctx, JSArray *arr, uint32_t idx, JS } if (idx >= arr->len) { - for (uint32_t i = arr->len; i < idx; i++) { + for (uint32_t i = arr->len; i < idx; i++) arr->values[i] = JS_NULL; - } arr->len = idx + 1; arr->values[idx] = val; } else { @@ -7984,12 +7979,6 @@ int JS_DeleteProperty(JSContext *ctx, JSValueConst obj, JSAtom prop) return -1; } -BOOL JS_IsFunction(JSContext *ctx, JSValueConst val) -{ - (void)ctx; /* unused */ - return JS_VALUE_GET_TAG(val) == JS_TAG_FUNCTION; -} - BOOL JS_IsCFunction(JSContext *ctx, JSValueConst val, JSCFunction *func, int magic) { JSFunction *f; @@ -8336,7 +8325,6 @@ static JSValue JS_ToNumberFree(JSContext *ctx, JSValue val) uint32_t tag; JSValue ret; - redo: tag = JS_VALUE_GET_NORM_TAG(val); switch(tag) { case JS_TAG_FLOAT64: @@ -9982,7 +9970,6 @@ static __exception int JS_CopyDataProperties(JSContext *ctx, JSObject *pexcl = NULL; int ret, gpn_flags; JSPropertyDescriptor desc; - BOOL is_enumerable; if (JS_VALUE_GET_TAG(source) != JS_TAG_OBJECT) return 0; @@ -10821,39 +10808,32 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj, #endif /* Proxy method-call: detect [func, "name", ...args] and rewrite as func("name", [args]) */ - if (js_is_proxy_callable(call_argv[-2])) { - if (!JS_IsFunction(ctx, call_argv[-1])) { - int t = JS_VALUE_GET_TAG(call_argv[-1]); - if (t == JS_TAG_STRING || t == JS_TAG_SYMBOL) - is_proxy = TRUE; - } - } - if (is_proxy) { + if (JS_IsFunction(call_argv[-2])) { JSValue name = call_argv[-1]; + if (!JS_IsText(name)) { + ret_val = JS_ThrowTypeError(ctx, "second argument must be a string"); + goto exception; + } + JSValue args = JS_NewArrayLen(ctx, call_argc); if (unlikely(JS_IsException(args))) goto exception; /* Move args into the array, then null out stack slots. */ + JSArray *ar = JS_VALUE_GET_ARRAY(args); for (i = 0; i < call_argc; i++) { - int r = JS_SetPropertyNumber(ctx, args, i, call_argv[i]); + ar->values[i] = call_argv[i]; call_argv[i] = JS_NULL; - if (unlikely(r < 0)) { - JS_FreeValue(ctx, args); - goto exception; - } } - { - JSValue proxy_argv[2]; - proxy_argv[0] = name; /* still owned by stack; freed by normal cleanup */ - proxy_argv[1] = args; + JSValue proxy_argv[2]; + proxy_argv[0] = name; /* still owned by stack; freed by normal cleanup */ + proxy_argv[1] = args; - ret_val = JS_CallInternal(ctx, call_argv[-2], JS_NULL, - 2, proxy_argv, 0); - JS_FreeValue(ctx, args); - } + ret_val = JS_CallInternal(ctx, call_argv[-2], JS_NULL, + 2, proxy_argv, 0); + JS_FreeValue(ctx, args); } else { ret_val = JS_CallInternal(ctx, call_argv[-1], call_argv[-2], call_argc, call_argv, 0); @@ -10878,57 +10858,15 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj, if (unlikely(JS_IsException(ret_val))) goto exception; call_argv = sp - call_argc; + JSArray *ar = JS_VALUE_GET_ARRAY(ret_val); for (i = 0; i < call_argc; i++) { - ret = JS_SetPropertyNumber(ctx, ret_val, i, call_argv[i]); + ar->values[i] = call_argv[i]; call_argv[i] = JS_NULL; - if (ret < 0) { - JS_FreeValue(ctx, ret_val); - goto exception; - } } sp -= call_argc; *sp++ = ret_val; } BREAK; - - CASE(OP_apply): - { - int magic; - BOOL is_proxy = FALSE; - - magic = get_u16(pc); - pc += 2; - sf->cur_pc = pc; - - /* Proxy method-call with spread: detect ["name", func, args_array] - and rewrite as func("name", args_array) */ - if (js_is_proxy_callable(sp[-2])) { - if (!JS_IsFunction(ctx, sp[-3])) { - int t = JS_VALUE_GET_TAG(sp[-3]); - if (t == JS_TAG_STRING || t == JS_TAG_SYMBOL) - is_proxy = TRUE; - } - } - - if (is_proxy) { - JSValue proxy_argv[2]; - proxy_argv[0] = sp[-3]; /* name */ - proxy_argv[1] = sp[-1]; /* args array already built by bytecode */ - - ret_val = JS_CallInternal(ctx, sp[-2], JS_NULL, - 2, proxy_argv, 0); - } else { - ret_val = js_function_apply(ctx, sp[-3], 2, (JSValueConst *)&sp[-2], magic); - } - if (unlikely(JS_IsException(ret_val))) - goto exception; - JS_FreeValue(ctx, sp[-3]); - JS_FreeValue(ctx, sp[-2]); - JS_FreeValue(ctx, sp[-1]); - sp -= 3; - *sp++ = ret_val; - } - BREAK; CASE(OP_return): ret_val = *--sp; goto done; @@ -10992,51 +10930,6 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj, *sp++ = ret_val; } BREAK; - /* could merge with OP_apply */ - CASE(OP_apply_eval): - { - int scope_idx; - uint32_t len; - JSValue *tab; - JSValueConst obj; - - scope_idx = get_u16(pc) + ARG_SCOPE_END; - pc += 2; - sf->cur_pc = pc; - /* Fast path: check arity before building arg list */ - if (JS_VALUE_GET_TAG(sp[-2]) == JS_TAG_FUNCTION && - JS_VALUE_GET_TAG(sp[-1]) == JS_TAG_ARRAY) { - JSFunction *callee = JS_VALUE_GET_FUNCTION(sp[-2]); - JSArray *arr = JS_VALUE_GET_ARRAY(sp[-1]); - if (unlikely(arr->len > callee->length)) { - JS_ThrowTypeError(ctx, "too many arguments"); - goto exception; - } - } - tab = build_arg_list(ctx, &len, sp[-1]); - if (!tab) - goto exception; - if (js_same_value(ctx, sp[-2], ctx->eval_obj)) { - if (len >= 1) - obj = tab[0]; - else - obj = JS_NULL; - ret_val = JS_EvalObject(ctx, JS_NULL, obj, - JS_EVAL_TYPE_DIRECT, scope_idx); - } else { - ret_val = JS_Call(ctx, sp[-2], JS_NULL, len, - (JSValueConst *)tab); - } - free_arg_list(ctx, tab, len); - if (unlikely(JS_IsException(ret_val))) - goto exception; - JS_FreeValue(ctx, sp[-2]); - JS_FreeValue(ctx, sp[-1]); - sp -= 2; - *sp++ = ret_val; - } - BREAK; - CASE(OP_regexp): { sp[-2] = js_regexp_constructor_internal(ctx, sp[-2], sp[-1]); @@ -11617,7 +11510,7 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj, obj = sp[-1]; /* Functions don't support property access in cell script */ - if (js_is_proxy_callable(obj)) { + if (JS_IsFunction(obj)) { JS_ThrowTypeError(ctx, "cannot get property of function"); goto exception; } @@ -11704,7 +11597,7 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj, /* Proxy method-call sugar: func.name(...) -> func("name", [args...]) OP_get_field2 is only emitted when a call immediately follows. */ - if (js_is_proxy_callable(obj)) { + if (JS_IsFunction(obj)) { val = JS_AtomToValue(ctx, atom); /* "name" */ if (unlikely(JS_IsException(val))) goto exception; @@ -11779,8 +11672,8 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj, profile_record_prop_site(rt, b, (uint32_t)(pc - b->byte_code_buf), atom); #endif /* Functions don't support property assignment in cell script */ - if (js_is_proxy_callable(sp[-2])) { - JS_ThrowTypeError(ctx, "cannot set property of function"); + if (!JS_IsObject(sp[-2])) { + JS_ThrowTypeError(ctx, "tried to set property of non-object"); goto exception; } @@ -11829,14 +11722,12 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj, CASE(OP_define_method): CASE(OP_define_method_computed): { - JSValue getter, setter, value; + JSValue value; JSValueConst obj; JSAtom atom; int ret, op_flags; BOOL is_computed; #define OP_DEFINE_METHOD_METHOD 0 -#define OP_DEFINE_METHOD_GETTER 1 -#define OP_DEFINE_METHOD_SETTER 2 #define OP_DEFINE_METHOD_ENUMERABLE 4 is_computed = (opcode == OP_define_method_computed); @@ -11854,8 +11745,7 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj, obj = sp[-2 - is_computed]; op_flags &= 3; value = JS_NULL; - getter = JS_NULL; - setter = JS_NULL; + if (op_flags == OP_DEFINE_METHOD_METHOD) { value = sp[-1]; } @@ -11884,13 +11774,6 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj, CASE(OP_get_array_el): { JSValue val; - - /* Functions don't support property access in cell script */ - if (js_is_proxy_callable(sp[-2])) { - JS_ThrowTypeError(ctx, "cannot get property of function"); - goto exception; - } - sf->cur_pc = pc; val = JS_GetPropertyValue(ctx, sp[-2], sp[-1]); JS_FreeValue(ctx, sp[-2]); @@ -11904,35 +11787,6 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj, CASE(OP_get_array_el2): { JSValue val; - - /* Proxy method-call sugar for bracket calls: func[key](...) */ - if (js_is_proxy_callable(sp[-2])) { - /* Keep [func, key] and normalize key to property-key (string/symbol). */ - switch (JS_VALUE_GET_TAG(sp[-1])) { - case JS_TAG_INT: - /* Convert integer to string */ - sf->cur_pc = pc; - ret_val = JS_ToString(ctx, sp[-1]); - if (JS_IsException(ret_val)) - goto exception; - JS_FreeValue(ctx, sp[-1]); - sp[-1] = ret_val; - break; - case JS_TAG_STRING: - case JS_TAG_SYMBOL: - break; - default: - sf->cur_pc = pc; - ret_val = JS_ToPropertyKey(ctx, sp[-1]); - if (JS_IsException(ret_val)) - goto exception; - JS_FreeValue(ctx, sp[-1]); - sp[-1] = ret_val; - break; - } - BREAK; /* skip JS_GetPropertyValue, keep [func, key] on stack */ - } - sf->cur_pc = pc; val = JS_GetPropertyValue(ctx, sp[-2], sp[-1]); sp[-1] = val; @@ -11944,13 +11798,6 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj, CASE(OP_get_array_el3): { JSValue val; - - /* Functions don't support property access in cell script */ - if (js_is_proxy_callable(sp[-2])) { - JS_ThrowTypeError(ctx, "cannot get property of function"); - goto exception; - } - switch (JS_VALUE_GET_TAG(sp[-2])) { case JS_TAG_INT: case JS_TAG_STRING: @@ -11959,7 +11806,7 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj, break; default: /* must be tested nefore JS_ToPropertyKey */ - if (unlikely(JS_IsNull(sp[-2]) || JS_IsNull(sp[-2]))) { + if (unlikely(JS_IsNull(sp[-2]))) { JS_ThrowTypeError(ctx, "value has no property"); goto exception; } @@ -12003,7 +11850,6 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj, JS_ThrowReferenceErrorNotDefined(ctx, atom); JS_FreeAtom(ctx, atom); goto exception; - val = JS_NULL; } else { val = JS_GetProperty(ctx, sp[-2], atom); } @@ -12020,7 +11866,7 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj, int ret; /* Functions don't support property assignment in cell script */ - if (js_is_proxy_callable(sp[-3])) { + if (JS_IsFunction(sp[-3])) { JS_ThrowTypeError(ctx, "cannot set property of function"); goto exception; } @@ -15721,13 +15567,12 @@ static __exception int js_parse_object_literal(JSParseState *s) JSAtom name = JS_ATOM_NULL; const uint8_t *start_ptr; int prop_type; - BOOL has_proto; if (next_token(s)) goto fail; /* XXX: add an initial length that will be patched back */ emit_op(s, OP_object); - has_proto = FALSE; + while (s->token.val != '}') { /* specific case for getter/setter */ start_ptr = s->token.ptr; @@ -16127,18 +15972,6 @@ duplicate: return js_parse_error(s, "duplicate parameter names not allowed in this context"); } -/* tok = TOK_VAR or TOK_DEF. Return whether a reference - must be taken to the variable for proper 'with' or global variable - evaluation */ -/* Note: this function is needed only because variable references are - not yet optimized in destructuring */ -static BOOL need_var_reference(JSParseState *s, int tok) -{ - JSFunctionDef *fd = s->cur_func; - /* var now behaves like let - no reference needed */ - return FALSE; -} - static JSAtom js_parse_destructuring_var(JSParseState *s, int tok, int is_arg) { JSAtom name; @@ -16238,20 +16071,11 @@ static int js_parse_destructuring_element(JSParseState *s, int tok, int is_arg, var_name = js_parse_destructuring_var(s, tok, is_arg); if (var_name == JS_ATOM_NULL) goto prop_error; - if (need_var_reference(s, tok)) { - /* Must make a reference for proper `with` semantics */ - emit_op(s, OP_scope_get_var); - emit_atom(s, var_name); - emit_u16(s, s->cur_func->scope_level); - JS_FreeAtom(s->ctx, var_name); - goto lvalue1; - } else { - /* no need to make a reference for let/const */ - opcode = OP_scope_get_var; - scope = s->cur_func->scope_level; - label_lvalue = -1; - depth_lvalue = 0; - } + /* no need to make a reference for let/const */ + opcode = OP_scope_get_var; + scope = s->cur_func->scope_level; + label_lvalue = -1; + depth_lvalue = 0; } else { if (js_parse_left_hand_side_expr(s)) goto prop_error; @@ -16313,7 +16137,7 @@ static int js_parse_destructuring_element(JSParseState *s, int tok, int is_arg, js_parse_error(s, "invalid destructuring target"); goto prop_error; } - if (!tok || need_var_reference(s, tok)) { + if (!tok) { /* generate reference */ /* source -- source source */ emit_op(s, OP_dup); @@ -17527,32 +17351,14 @@ static __exception int js_parse_var(JSParseState *s, int parse_flags, int tok, if (s->token.val == '=') { if (next_token(s)) goto var_error; - if (need_var_reference(s, tok)) { - /* Must make a reference for proper `with` semantics */ - int opcode, scope, label; - JSAtom name1; - emit_op(s, OP_scope_get_var); - emit_atom(s, name); - emit_u16(s, fd->scope_level); - if (get_lvalue(s, &opcode, &scope, &name1, &label, NULL, FALSE, '=') < 0) - goto var_error; - if (js_parse_assign_expr2(s, parse_flags)) { - JS_FreeAtom(ctx, name1); - goto var_error; - } - set_object_name(s, name); - put_lvalue(s, opcode, scope, name1, label, - PUT_LVALUE_NOKEEP, FALSE); - } else { - if (js_parse_assign_expr2(s, parse_flags)) - goto var_error; - set_object_name(s, name); - emit_op(s, (tok == TOK_DEF || tok == TOK_VAR) ? - OP_scope_put_var_init : OP_scope_put_var); - emit_atom(s, name); - emit_u16(s, fd->scope_level); - } + if (js_parse_assign_expr2(s, parse_flags)) + goto var_error; + set_object_name(s, name); + emit_op(s, (tok == TOK_DEF || tok == TOK_VAR) ? + OP_scope_put_var_init : OP_scope_put_var); + emit_atom(s, name); + emit_u16(s, fd->scope_level); } else { if (tok == TOK_DEF) { js_parse_error(s, "missing initializer for const variable"); @@ -20198,12 +20004,6 @@ static __exception int resolve_variables(JSContext *ctx, JSFunctionDef *s) dbuf_put_u16(&bc_out, s->scopes[scope].first - ARG_SCOPE_END); } break; - case OP_apply_eval: /* convert scope index to adjusted variable index */ - scope = get_u16(bc_buf + pos + 1); - mark_eval_captured_variables(ctx, s, scope); - dbuf_putc(&bc_out, op); - dbuf_put_u16(&bc_out, s->scopes[scope].first - ARG_SCOPE_END); - break; case OP_scope_get_var_checkthis: case OP_scope_get_var_undef: case OP_scope_get_var: @@ -24223,7 +24023,7 @@ JSValue JS_ReadObject(JSContext *ctx, const uint8_t *buf, size_t buf_len, static int check_function(JSContext *ctx, JSValueConst obj) { - if (likely(JS_IsFunction(ctx, obj))) + if (likely(JS_IsFunction(obj))) return 0; JS_ThrowTypeError(ctx, "not a function"); return -1; @@ -25273,7 +25073,7 @@ static JSValue JS_RegExpExec(JSContext *ctx, JSValueConst r, JSValueConst s) method = JS_GetProperty(ctx, r, JS_ATOM_exec); if (JS_IsException(method)) return method; - if (JS_IsFunction(ctx, method)) { + if (JS_IsFunction(method)) { ret = JS_CallFree(ctx, method, r, 1, &s); if (JS_IsException(ret)) return ret; @@ -25593,7 +25393,7 @@ static JSValue js_json_parse(JSContext *ctx, JSValueConst this_val, JS_FreeCString(ctx, str); if (JS_IsException(obj)) return obj; - if (argc > 1 && JS_IsFunction(ctx, argv[1])) { + if (argc > 1 && JS_IsFunction(argv[1])) { reviver = argv[1]; root = JS_NewObject(ctx); if (JS_IsException(root)) { @@ -25638,7 +25438,7 @@ static JSValue js_json_check(JSContext *ctx, JSONStringifyContext *jsc, JSValue f = JS_GetProperty(ctx, val, JS_ATOM_toJSON); if (JS_IsException(f)) goto exception; - if (JS_IsFunction(ctx, f)) { + if (JS_IsFunction(f)) { v = JS_CallFree(ctx, f, val, 1, &key); JS_FreeValue(ctx, val); val = v; @@ -25662,7 +25462,7 @@ static JSValue js_json_check(JSContext *ctx, JSONStringifyContext *jsc, switch (JS_VALUE_GET_NORM_TAG(val)) { case JS_TAG_ARRAY: case JS_TAG_OBJECT: - if (JS_IsFunction(ctx, val)) + if (JS_IsFunction(val)) break; case JS_TAG_STRING: case JS_TAG_STRING_ROPE: @@ -25872,7 +25672,7 @@ JSValue JS_JSONStringify(JSContext *ctx, JSValueConst obj, jsc->stack = JS_NewArray(ctx); if (JS_IsException(jsc->stack)) goto exception; - if (JS_IsFunction(ctx, replacer)) { + if (JS_IsFunction(replacer)) { jsc->replacer_func = replacer; } else { res = JS_IsArray(ctx, replacer); @@ -27027,7 +26827,7 @@ array_fail: } /* Handle function - return source or native stub */ - if (JS_IsFunction(ctx, arg)) { + if (JS_IsFunction(arg)) { JSFunction *fn = JS_VALUE_GET_FUNCTION(arg); if (fn->kind == JS_FUNC_KIND_BYTECODE) { JSFunctionBytecode *b = fn->u.func.function_bytecode; @@ -27236,7 +27036,7 @@ static JSValue make_replacement(JSContext *ctx, int argc, JSValueConst *argv, in { JSValue rep; - if (argc > 2 && JS_IsFunction(ctx, argv[2])) { + if (argc > 2 && JS_IsFunction(argv[2])) { JSValue args[2]; args[0] = match_val; args[1] = JS_NewInt32(ctx, found); @@ -27259,7 +27059,7 @@ static int JS_IsRegExp(JSContext *ctx, JSValueConst v) JSValue exec = JS_GetPropertyStr(ctx, v, "exec"); if (JS_IsException(exec)) return -1; - int ok = JS_IsFunction(ctx, exec); + int ok = JS_IsFunction(exec); JS_FreeValue(ctx, exec); return ok; } @@ -27843,7 +27643,7 @@ static JSValue js_cell_array(JSContext *ctx, JSValueConst this_val, JSValue result = JS_NewArrayLen(ctx, len); if (JS_IsException(result)) return result; - if (JS_IsFunction(ctx, argv[1])) { + if (JS_IsFunction(argv[1])) { /* Fill with function results */ JSValueConst func = argv[1]; int arity = 0; @@ -27896,7 +27696,7 @@ static JSValue js_cell_array(JSContext *ctx, JSValueConst this_val, return result; } - if (JS_IsFunction(ctx, argv[1])) { + if (JS_IsFunction(argv[1])) { /* Map */ JSValueConst func = argv[1]; int arity = (JSFunction*)JS_VALUE_GET_FUNCTION(argv[1])->length; @@ -28297,7 +28097,7 @@ static JSValue js_cell_array_reduce(JSContext *ctx, JSValueConst this_val, { if (argc < 2) return JS_NULL; if (!JS_IsArray(ctx, argv[0])) return JS_NULL; - if (!JS_IsFunction(ctx, argv[1])) return JS_NULL; + if (!JS_IsFunction(argv[1])) return JS_NULL; JSValueConst arr = argv[0]; JSValueConst func = argv[1]; @@ -28387,13 +28187,12 @@ static JSValue js_cell_array_for(JSContext *ctx, JSValueConst this_val, { if (argc < 2) return JS_NULL; if (!JS_IsArray(ctx, argv[0])) return JS_NULL; - if (!JS_IsFunction(ctx, argv[1])) return JS_NULL; + if (!JS_IsFunction(argv[1])) return JS_NULL; + + JSArray *arr = JS_VALUE_GET_ARRAY(argv[0]); - JSValueConst arr = argv[0]; JSValueConst func = argv[1]; - int64_t len; - if (js_get_length64(ctx, &len, arr)) - return JS_EXCEPTION; + int len = arr->len; if (len == 0) return JS_NULL; int reverse = argc > 2 && JS_ToBool(ctx, argv[2]); @@ -28403,18 +28202,21 @@ static JSValue js_cell_array_for(JSContext *ctx, JSValueConst this_val, int arity = (JSFunction*)JS_VALUE_GET_FUNCTION(argv[1])->length; if (reverse) { - for (int64_t i = len - 1; i >= 0; i--) { - JSValue item = JS_GetPropertyInt64(ctx, arr, i); - if (JS_IsException(item)) return JS_EXCEPTION; + for (int i = len - 1; i >= 0; i--) { JSValue result; if (arity == 1) { - result = JS_Call(ctx, func, JS_NULL, 1, &item); + JSValue item = JS_DupValue(ctx, arr->values[i]); + result = JS_CallInternal(ctx, func, JS_NULL, 1, &item, 0); + JS_FreeValue(ctx, item); } else { - JSValue args[2] = { item, JS_NewInt64(ctx, i) }; - result = JS_Call(ctx, func, JS_NULL, 2, args); + JSValue args[2]; + args[0] = JS_DupValue(ctx, arr->values[i]); + args[1] = JS_NewInt32(ctx, i); + result = JS_CallInternal(ctx, func, JS_NULL, 2, args, 0); + JS_FreeValue(ctx, args[0]); JS_FreeValue(ctx, args[1]); } - JS_FreeValue(ctx, item); + if (JS_IsException(result)) return JS_EXCEPTION; if (!JS_IsNull(exit_val) && js_strict_eq(ctx, result, exit_val)) { return result; @@ -28422,18 +28224,21 @@ static JSValue js_cell_array_for(JSContext *ctx, JSValueConst this_val, JS_FreeValue(ctx, result); } } else { - for (int64_t i = 0; i < len; i++) { - JSValue item = JS_GetPropertyInt64(ctx, arr, i); - if (JS_IsException(item)) return JS_EXCEPTION; + for (int i = 0; i < len; i++) { JSValue result; if (arity == 1) { - result = JS_Call(ctx, func, JS_NULL, 1, &item); + JSValue item = JS_DupValue(ctx, arr->values[i]); + result = JS_CallInternal(ctx, func, JS_NULL, 1, &item, 0); + JS_FreeValue(ctx, item); } else { - JSValue args[2] = { item, JS_NewInt64(ctx, i) }; - result = JS_Call(ctx, func, JS_NULL, 2, args); + JSValue args[2]; + args[0] = JS_DupValue(ctx, arr->values[i]); + args[1] = JS_NewInt32(ctx, i); + result = JS_CallInternal(ctx, func, JS_NULL, 2, args, 0); + JS_FreeValue(ctx, args[0]); JS_FreeValue(ctx, args[1]); } - JS_FreeValue(ctx, item); + if (JS_IsException(result)) return JS_EXCEPTION; if (!JS_IsNull(exit_val) && js_strict_eq(ctx, result, exit_val)) { return result; @@ -28466,7 +28271,7 @@ static JSValue js_cell_array_find(JSContext *ctx, JSValueConst this_val, from = reverse ? len - 1 : 0; } - if (!JS_IsFunction(ctx, argv[1])) { + if (!JS_IsFunction(argv[1])) { /* Compare exactly */ JSValue target = argv[1]; if (reverse) { @@ -28549,7 +28354,7 @@ static JSValue js_cell_array_filter(JSContext *ctx, JSValueConst this_val, { if (argc < 2) return JS_NULL; if (!JS_IsArray(ctx, argv[0])) return JS_NULL; - if (!JS_IsFunction(ctx, argv[1])) return JS_NULL; + if (!JS_IsFunction(argv[1])) return JS_NULL; JSValueConst arr = argv[0]; JSValueConst func = argv[1]; @@ -28768,7 +28573,7 @@ static JSValue js_cell_object(JSContext *ctx, JSValueConst this_val, JSValue arg = argv[0]; /* object(object) - shallow mutable copy */ - if (JS_IsObject(arg) && !JS_IsArray(ctx, arg) && !JS_IsFunction(ctx, arg)) { + if (JS_IsObject(arg) && !JS_IsArray(ctx, arg) && !JS_IsFunction(arg)) { if (argc < 2 || JS_IsNull(argv[1])) { /* Shallow copy */ JSValue result = JS_NewObject(ctx); @@ -28896,7 +28701,7 @@ static JSValue js_cell_object(JSContext *ctx, JSValueConst this_val, JSValue val; if (argc < 2 || JS_IsNull(argv[1])) { val = JS_TRUE; - } else if (JS_IsFunction(ctx, argv[1])) { + } else if (JS_IsFunction(argv[1])) { val = JS_Call(ctx, argv[1], JS_NULL, 1, &key); if (JS_IsException(val)) { JS_FreeAtom(ctx, atom); @@ -28927,7 +28732,7 @@ static JSValue js_cell_fn_apply(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) { if (argc < 1) return JS_NULL; - if (!JS_IsFunction(ctx, argv[0])) return JS_DupValue(ctx, argv[0]); + if (!JS_IsFunction(argv[0])) return JS_DupValue(ctx, argv[0]); JSValueConst func = argv[0]; @@ -29028,7 +28833,7 @@ static JSValue js_blob_constructor(JSContext *ctx, JSValueConst this_val, if (JS_IsBool(argv[1])) { int is_one = JS_ToBool(ctx, argv[1]); bd = blob_new_with_fill((size_t)length_bits, is_one); - } else if (JS_IsFunction(ctx, argv[1])) { + } else if (JS_IsFunction(argv[1])) { /* Random function provided */ size_t bytes = (length_bits + 7) / 8; bd = blob_new((size_t)length_bits); @@ -29893,7 +29698,7 @@ static JSValue js_cell_splat(JSContext *ctx, JSValueConst this_val, /* Call to_data if present */ JSValue to_data = JS_GetPropertyStr(ctx, obj, "to_data"); - if (JS_IsFunction(ctx, to_data)) { + if (JS_IsFunction(to_data)) { JSValue args[1] = { result }; JSValue extra = JS_Call(ctx, to_data, obj, 1, args); if (!JS_IsException(extra) && JS_IsObject(extra)) { @@ -29933,7 +29738,7 @@ static JSValue js_cell_length(JSContext *ctx, JSValueConst this_val, return JS_NULL; /* Functions return arity (accessed directly, not via properties) */ - if (JS_IsFunction(ctx, val)) { + if (JS_IsFunction(val)) { JSFunction *f = JS_VALUE_GET_FUNCTION(val); return JS_NewInt32(ctx, f->length); } @@ -29963,7 +29768,7 @@ static JSValue js_cell_length(JSContext *ctx, JSValueConst this_val, if (JS_IsObject(val)) { JSValue len = JS_GetPropertyStr(ctx, val, "length"); if (!JS_IsException(len) && !JS_IsNull(len)) { - if (JS_IsFunction(ctx, len)) { + if (JS_IsFunction(len)) { JSValue result = JS_Call(ctx, len, val, 0, NULL); JS_FreeValue(ctx, len); return result; @@ -29991,7 +29796,7 @@ static JSValue js_cell_call(JSContext *ctx, JSValueConst this_val, return JS_ThrowTypeError(ctx, "call requires a function argument"); JSValue func = argv[0]; - if (!JS_IsFunction(ctx, func)) + if (!JS_IsFunction(func)) return JS_ThrowTypeError(ctx, "first argument must be a function"); JSValue this_arg = JS_NULL; @@ -30042,7 +29847,7 @@ static JSValue js_cell_is_data(JSContext *ctx, JSValueConst this_val, JSValue val = argv[0]; if (!JS_IsObject(val)) return JS_FALSE; if (JS_IsArray(ctx, val)) return JS_FALSE; - if (JS_IsFunction(ctx, val)) return JS_FALSE; + if (JS_IsFunction(val)) return JS_FALSE; if (js_get_blob(ctx, val)) return JS_FALSE; /* Check if it's a plain object (prototype is Object.prototype or null) */ return JS_TRUE; @@ -30053,7 +29858,7 @@ static JSValue js_cell_is_function(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) { if (argc < 1) return JS_FALSE; - return JS_NewBool(ctx, JS_IsFunction(ctx, argv[0])); + return JS_NewBool(ctx, JS_IsFunction(argv[0])); } /* is_logical(val) - check if value is a boolean (true or false) */ @@ -30164,7 +29969,7 @@ static JSValue js_cell_is_proto(JSContext *ctx, JSValueConst this_val, JSValue proto = JS_GetPrototype(ctx, val); while (!JS_IsNull(proto) && !JS_IsException(proto)) { /* If master is a function with prototype property, check that */ - if (JS_IsFunction(ctx, master)) { + if (JS_IsFunction(master)) { JSValue master_proto = JS_GetPropertyStr(ctx, master, "prototype"); if (!JS_IsException(master_proto) && !JS_IsNull(master_proto)) { JSObject *p1 = JS_VALUE_GET_OBJ(proto); @@ -30436,7 +30241,7 @@ void js_debug_info(JSContext *js, JSValue fn, js_debug *dbg) { memset(dbg, 0, sizeof(*dbg)); - if (!JS_IsFunction(js, fn)) return; + if (!JS_IsFunction(fn)) return; JSFunction *f = JS_VALUE_GET_FUNCTION(fn); const char *fn_name = NULL; @@ -31155,7 +30960,7 @@ static JSValue js_cell_json_decode(JSContext *ctx, JSValueConst this_val, JS_FreeCString(ctx, str); /* Apply reviver if provided */ - if (argc > 1 && JS_IsFunction(ctx, argv[1]) && !JS_IsException(result)) { + if (argc > 1 && JS_IsFunction(argv[1]) && !JS_IsException(result)) { /* Create wrapper object to pass to reviver */ JSValue wrapper = JS_NewObject(ctx); JS_SetPropertyStr(ctx, wrapper, "", result); diff --git a/source/quickjs.h b/source/quickjs.h index 1a9746c8..50e7ebab 100644 --- a/source/quickjs.h +++ b/source/quickjs.h @@ -533,17 +533,23 @@ static inline JS_BOOL JS_IsString(JSValueConst v) JS_VALUE_GET_TAG(v) == JS_TAG_STRING_ROPE; } +static inline JS_BOOL JS_IsText(JSValueConst v) { return JS_IsString(v); } + static inline JS_BOOL JS_IsSymbol(JSValueConst v) { return JS_VALUE_GET_TAG(v) == JS_TAG_SYMBOL; } +static inline JS_BOOL JS_IsFunction(JSValueConst v) +{ + return JS_VALUE_GET_TAG(v) == JS_TAG_FUNCTION; +} + static inline JS_BOOL JS_IsObject(JSValueConst v) { return JS_VALUE_GET_TAG(v) == JS_TAG_OBJECT; } int JS_IsArray(JSContext *ctx, JSValueConst val); -JS_BOOL JS_IsFunction(JSContext* ctx, JSValueConst val); // Fundamental int JS_GetLength(JSContext *ctx, JSValueConst obj, int64_t *pres); diff --git a/source/scheduler.c b/source/scheduler.c index 8dd4e5af..9645082c 100644 --- a/source/scheduler.c +++ b/source/scheduler.c @@ -436,7 +436,7 @@ void actor_unneeded(cell_rt *actor, JSValue fn, double seconds) if (actor->disrupt) return; JS_FreeValue(actor->context, actor->unneeded); - if (!JS_IsFunction(actor->context, fn)) { + if (!JS_IsFunction(fn)) { actor->unneeded = JS_NULL; goto END; } diff --git a/tests/suite.cm b/tests/suite.cm index 93de00cf..19f20ff2 100644 --- a/tests/suite.cm +++ b/tests/suite.cm @@ -1077,7 +1077,7 @@ return { var parent = {a: 1} var mixin1 = {b: 2} var mixin2 = {c: 3} - var child = meme(parent, mixin1, mixin2) + var child = meme(parent, [mixin1, mixin2]) if (child.a != 1 || child.b != 2 || child.c != 3) throw "meme multiple mixins failed" }, @@ -1847,7 +1847,7 @@ return { var fn = function() {} var caught = false try { - var x = fn["length"] + var x = fn["length"]() } catch (e) { caught = true } @@ -1875,14 +1875,14 @@ return { test_call_invokes_function: function() { var fn = function(a, b) { return a + b } - var result = call(fn, null, 3, 4) + var result = call(fn, null, [3, 4]) if (result != 7) throw "call(fn, null, 3, 4) should return 7" }, test_call_with_this_binding: function() { var obj = { value: 10 } var fn = function(x) { return this.value + x } - var result = call(fn, obj, 5) + var result = call(fn, obj, [5]) if (result != 15) throw "call(fn, obj, 5) should return 15" }, @@ -2071,8 +2071,13 @@ return { var proxy = function(name, args) { return `key:${name}` } - var result = proxy[42]() - if (result != "key:42") throw "proxy with integer bracket key failed" + var caught = false + try { + var result = proxy[42]() + } catch (e) { + caught = true + } + if (!caught) throw "proxy with integer bracket key should throw" }, // ============================================================================ @@ -3036,7 +3041,7 @@ return { test_call_many_args: function() { var fn = function(a, b, c, d) { return a * b + c * d } - var result = call(fn, null, 2, 3, 4, 5) + var result = call(fn, null, [2, 3, 4, 5]) if (result != 26) throw "call many args failed" }, @@ -3045,7 +3050,7 @@ return { value: 10, multiply: function(x) { return this.value * x } } - var result = call(obj.multiply, obj, 5) + var result = call(obj.multiply, obj, [5]) if (result != 50) throw "call method style failed" },