diff --git a/build.cm b/build.cm index 1dc568d4..78ad69b0 100644 --- a/build.cm +++ b/build.cm @@ -35,7 +35,7 @@ function replace_sigils(str) { function replace_sigils_array(flags) { var result = [] arrfor(flags, function(flag) { - resultpush(replace_sigils(flag)) + push(result, replace_sigils(flag)) }) return result } @@ -121,30 +121,30 @@ Build.compile_file = function(pkg, file, target, buildtype = 'release') { // Add buildtype-specific flags if (buildtype == 'release') { - cmd_partspush('-O3', '-DNDEBUG') + push(cmd_parts, '-O3', '-DNDEBUG') } else if (buildtype == 'debug') { - cmd_partspush('-O2', '-g') + push(cmd_parts, '-O2', '-g') } else if (buildtype == 'minsize') { - cmd_partspush('-Os', '-DNDEBUG') + push(cmd_parts, '-Os', '-DNDEBUG') } - cmd_partspush('-DCELL_USE_NAME=' + sym_name) - cmd_partspush('-I"' + pkg_dir + '"') + push(cmd_parts, '-DCELL_USE_NAME=' + sym_name) + push(cmd_parts, '-I"' + pkg_dir + '"') // Add package CFLAGS (resolve relative -I paths) arrfor(cflags, function(flag) { if (starts_with(flag, '-I') && !starts_with(flag, '-I/')) { flag = '-I"' + pkg_dir + '/' + text(flag, 2) + '"' } - cmd_partspush(flag) + push(cmd_parts, flag) }) // Add target CFLAGS arrfor(target_cflags, function(flag) { - cmd_partspush(flag) + push(cmd_parts, flag) }) - cmd_partspush('"' + src_path + '"') + push(cmd_parts, '"' + src_path + '"') var cmd_str = text(cmd_parts, ' ') @@ -181,7 +181,7 @@ Build.build_package = function(pkg, target = Build.detect_host_target(), exclude arrfor(c_files, function(file) { var obj = Build.compile_file(pkg, file, target, buildtype) - objectspush(obj) + push(objects, obj) }) return objects @@ -198,17 +198,17 @@ function compute_link_key(objects, ldflags, target_ldflags, target, cc) { // Build a string representing all link inputs var parts = [] - partspush('target:' + target) - partspush('cc:' + cc) + push(parts, 'target:' + target) + push(parts, 'cc:' + cc) arrfor(sorted_objects, function(obj) { // Object paths are content-addressed, so the path itself is the hash - partspush('obj:' + obj) + push(parts, 'obj:' + obj) }) arrfor(ldflags, function(flag) { - partspush('ldflag:' + flag) + push(parts, 'ldflag:' + flag) }) arrfor(target_ldflags, function(flag) { - partspush('target_ldflag:' + flag) + push(parts, 'target_ldflag:' + flag) }) return content_hash(text(parts, '\n')) @@ -249,7 +249,7 @@ Build.build_dynamic = function(pkg, target = Build.detect_host_target(), buildty if (starts_with(flag, '-L') && !starts_with(flag, '-L/')) { flag = '-L"' + pkg_dir + '/' + text(flag, 2) + '"' } - resolved_ldflagspush(flag) + push(resolved_ldflags, flag) }) // Compute link key @@ -279,46 +279,46 @@ Build.build_dynamic = function(pkg, target = Build.detect_host_target(), buildty // Platform-specific flags for undefined symbols (resolved at dlopen) and size optimization if (tc.system == 'darwin') { // Allow undefined symbols - they will be resolved when dlopen'd into the main executable - cmd_partspush('-undefined', 'dynamic_lookup') + push(cmd_parts, '-undefined', 'dynamic_lookup') // Dead-strip unused code - cmd_partspush('-Wl,-dead_strip') + push(cmd_parts, '-Wl,-dead_strip') // Set install_name to stable path so runtime finds it correctly - cmd_partspush('-Wl,-install_name,' + stable_path) + push(cmd_parts, '-Wl,-install_name,' + stable_path) // rpath for .cell/local libraries - cmd_partspush('-Wl,-rpath,@loader_path/../local') - cmd_partspush('-Wl,-rpath,' + local_dir) + push(cmd_parts, '-Wl,-rpath,@loader_path/../local') + push(cmd_parts, '-Wl,-rpath,' + local_dir) } else if (tc.system == 'linux') { // Allow undefined symbols at link time - cmd_partspush('-Wl,--allow-shlib-undefined') + push(cmd_parts, '-Wl,--allow-shlib-undefined') // Garbage collect unused sections - cmd_partspush('-Wl,--gc-sections') + push(cmd_parts, '-Wl,--gc-sections') // rpath for .cell/local libraries - cmd_partspush('-Wl,-rpath,$ORIGIN/../local') - cmd_partspush('-Wl,-rpath,' + local_dir) + push(cmd_parts, '-Wl,-rpath,$ORIGIN/../local') + push(cmd_parts, '-Wl,-rpath,' + local_dir) } else if (tc.system == 'windows') { // Windows DLLs: use --allow-shlib-undefined for mingw - cmd_partspush('-Wl,--allow-shlib-undefined') + push(cmd_parts, '-Wl,--allow-shlib-undefined') } // Add .cell/local to library search path - cmd_partspush('-L"' + local_dir + '"') + push(cmd_parts, '-L"' + local_dir + '"') arrfor(objects, function(obj) { - cmd_partspush('"' + obj + '"') + push(cmd_parts, '"' + obj + '"') }) // Do NOT link against core library - symbols resolved at dlopen time // Add LDFLAGS arrfor(resolved_ldflags, function(flag) { - cmd_partspush(flag) + push(cmd_parts, flag) }) arrfor(target_ldflags, function(flag) { - cmd_partspush(flag) + push(cmd_parts, flag) }) - cmd_partspush('-o', '"' + store_path + '"') + push(cmd_parts, '-o', '"' + store_path + '"') var cmd_str = text(cmd_parts, ' ') @@ -359,7 +359,7 @@ Build.build_static = function(packages, target = Build.detect_host_target(), out var objects = Build.build_package(pkg, target, !is_core, buildtype) arrfor(objects, function(obj) { - all_objectspush(obj) + push(all_objects, obj) }) // Collect LDFLAGS (with sigil replacement) @@ -375,7 +375,7 @@ Build.build_static = function(packages, target = Build.detect_host_target(), out if (starts_with(flag, '-L') && !starts_with(flag, '-L/')) { flag = '-L"' + pkg_dir + '/' + text(flag, 2) + '"' } - all_ldflagspush(flag) + push(all_ldflags, flag) }) } }) @@ -396,18 +396,18 @@ Build.build_static = function(packages, target = Build.detect_host_target(), out var cmd_parts = [cc] arrfor(all_objects, function(obj) { - cmd_partspush('"' + obj + '"') + push(cmd_parts, '"' + obj + '"') }) arrfor(all_ldflags, function(flag) { - cmd_partspush(flag) + push(cmd_parts, flag) }) arrfor(target_ldflags, function(flag) { - cmd_partspush(flag) + push(cmd_parts, flag) }) - cmd_partspush('-o', '"' + output + '"') + push(cmd_parts, '-o', '"' + output + '"') var cmd_str = text(cmd_parts, ' ') @@ -436,10 +436,10 @@ Build.build_all_dynamic = function(target, buildtype = 'release') { if (find(packages, 'core') != null) { try { var lib = Build.build_dynamic('core', target, buildtype) - resultspush({ package: 'core', library: lib }) + push(results, { package: 'core', library: lib }) } catch (e) { log.error('Failed to build core: ' + text(e)) - resultspush({ package: 'core', error: e }) + push(results, { package: 'core', error: e }) } } @@ -449,11 +449,12 @@ Build.build_all_dynamic = function(target, buildtype = 'release') { try { var lib = Build.build_dynamic(pkg, target, buildtype) - resultspush({ package: pkg, library: lib }) + push(results, { package: pkg, library: lib }) } catch (e) { log.error('Failed to build ' + pkg + ': ') - log.error(e) - resultspush({ package: pkg, error: e }) + log.error(e.message) + log.error(e.stack) + push(results, { package: pkg, error: e }) } }) diff --git a/source/quickjs.c b/source/quickjs.c index 3d7aee8f..dce36984 100644 --- a/source/quickjs.c +++ b/source/quickjs.c @@ -338,7 +338,6 @@ struct VMFrame { JSValue cur_func; /* current function object */ JSValue this_obj; /* this binding */ - JSValue new_target; /* new.target binding */ struct JSVarRef **var_refs; /* closure variable references */ struct list_head var_ref_list; /* list of JSVarRef.var_ref_link */ int arg_count; @@ -358,7 +357,6 @@ typedef enum { typedef struct { JSValue func_obj; JSValue this_obj; - JSValue new_target; int argc; JSValue *argv; const uint8_t *ret_pc; @@ -408,7 +406,6 @@ typedef struct JSVarRef { } JSVarRef; typedef enum { - JS_AUTOINIT_ID_PROTOTYPE, JS_AUTOINIT_ID_PROP, } JSAutoInitIDEnum; @@ -428,7 +425,6 @@ struct JSContext { JSValue *class_proto; JSValue function_proto; - JSValue function_ctor; JSValue array_ctor; JSValue regexp_ctor; JSValue native_error_proto[JS_NATIVE_ERROR_COUNT]; @@ -907,10 +903,7 @@ static JSValue js_call_bound_function(JSContext *ctx, JSValueConst func_obj, JSValueConst this_obj, int argc, JSValueConst *argv, int flags); static JSValue JS_CallInternal(JSContext *ctx, JSValueConst func_obj, - JSValueConst this_obj, JSValueConst new_target, - int argc, JSValue *argv, int flags); -static JSValue JS_CallInternal(JSContext *ctx, JSValueConst func_obj, - JSValueConst this_obj, JSValueConst new_target, + JSValueConst this_obj, int argc, JSValue *argv, int flags); static JSValue JS_CallFree(JSContext *ctx, JSValue func_obj, JSValueConst this_obj, int argc, JSValueConst *argv); @@ -958,7 +951,7 @@ static int JS_ToFloat64Free(JSContext *ctx, double *pres, JSValue val); static JSValue js_new_string8_len(JSContext *ctx, const char *buf, int len); static JSValue js_compile_regexp(JSContext *ctx, JSValueConst pattern, JSValueConst flags); -static JSValue js_regexp_constructor_internal(JSContext *ctx, JSValueConst ctor, +static JSValue js_regexp_constructor_internal(JSContext *ctx, JSValue pattern, JSValue bc); static void gc_decref(JSRuntime *rt); static int JS_NewClass1(JSRuntime *rt, JSClassID class_id, @@ -1029,7 +1022,6 @@ static JSAtom js_symbol_to_atom(JSContext *ctx, JSValue val); static void add_gc_object(JSRuntime *rt, JSGCObjectHeader *h, JSGCObjectTypeEnum type); static void remove_gc_object(JSGCObjectHeader *h); -static JSValue js_instantiate_prototype(JSContext *ctx, JSObject *p, JSAtom atom, void *opaque); static JSValue JS_InstantiateFunctionListItem2(JSContext *ctx, JSObject *p, JSAtom atom, void *opaque); static void JS_RunGCInternal(JSRuntime *rt); @@ -1945,7 +1937,6 @@ static void JS_MarkContext(JSRuntime *rt, JSContext *ctx, } JS_MarkValue(rt, ctx->array_ctor, mark_func); JS_MarkValue(rt, ctx->regexp_ctor, mark_func); - JS_MarkValue(rt, ctx->function_ctor, mark_func); if (ctx->array_shape) mark_func(rt, &ctx->array_shape->header); @@ -2003,7 +1994,6 @@ void JS_FreeContext(JSContext *ctx) js_free_rt(rt, ctx->class_proto); JS_FreeValue(ctx, ctx->array_ctor); JS_FreeValue(ctx, ctx->regexp_ctor); - JS_FreeValue(ctx, ctx->function_ctor); js_free_shape_null(ctx->rt, ctx->array_shape); @@ -4905,6 +4895,18 @@ static BOOL js_class_has_bytecode(JSClassID class_id) return class_id == JS_CLASS_BYTECODE_FUNCTION; } +/* Check if a value is a function that uses proxy-call syntax (fn.a -> fn("a")) */ +static BOOL js_is_proxy_callable(JSValueConst v) +{ + JSObject *p; + if (JS_VALUE_GET_TAG(v) != JS_TAG_OBJECT) + return FALSE; + p = JS_VALUE_GET_OBJ(v); + return p->class_id == JS_CLASS_BYTECODE_FUNCTION || + p->class_id == JS_CLASS_C_FUNCTION || + p->class_id == JS_CLASS_C_FUNCTION_DATA; +} + /* return NULL without exception if not a function or no bytecode */ static JSFunctionBytecode *JS_GetFunctionBytecode(JSValueConst val) { @@ -6739,7 +6741,6 @@ static JSValue JS_GetPrototypeFree(JSContext *ctx, JSValue obj) typedef JSValue JSAutoInitFunc(JSContext *ctx, JSObject *p, JSAtom atom, void *opaque); static JSAutoInitFunc *js_autoinit_func_table[] = { - js_instantiate_prototype, /* JS_AUTOINIT_ID_PROTOTYPE */ JS_InstantiateFunctionListItem2, /* JS_AUTOINIT_ID_PROP */ }; @@ -11369,27 +11370,6 @@ static JSValue js_closure2(JSContext *ctx, JSValue func_obj, return JS_EXCEPTION; } -static JSValue js_instantiate_prototype(JSContext *ctx, JSObject *p, JSAtom atom, void *opaque) -{ - JSValue obj, this_val; - int ret; - - this_val = JS_MKPTR(JS_TAG_OBJECT, p); - obj = JS_NewObject(ctx); - if (JS_IsException(obj)) - return JS_EXCEPTION; - set_cycle_flag(ctx, obj); - set_cycle_flag(ctx, this_val); - ret = JS_DefinePropertyValue(ctx, obj, JS_ATOM_constructor, - JS_DupValue(ctx, this_val), - JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE); - if (ret < 0) { - JS_FreeValue(ctx, obj); - return JS_EXCEPTION; - } - return obj; -} - static JSValue js_closure(JSContext *ctx, JSValue bfunc, JSVarRef **cur_var_refs, JSStackFrame *sf) @@ -11510,19 +11490,9 @@ static JSValue js_call_c_function(JSContext *ctx, JSValueConst func_obj, } switch(cproto) { - case JS_CFUNC_constructor: - case JS_CFUNC_constructor_or_func: - /* Constructors are called as regular functions with JS_NULL this */ - this_obj = JS_NULL; - /* fall thru */ case JS_CFUNC_generic: ret_val = func.generic(ctx, this_obj, argc, arg_buf); break; - case JS_CFUNC_constructor_magic: - case JS_CFUNC_constructor_or_func_magic: - /* Constructors are called as regular functions with JS_NULL this */ - this_obj = JS_NULL; - /* fall thru */ case JS_CFUNC_generic_magic: ret_val = func.generic_magic(ctx, this_obj, argc, arg_buf, p->u.cfunc.magic); @@ -11587,7 +11557,7 @@ static JSValue js_call_bound_function(JSContext *ctx, JSValueConst func_obj, { JSObject *p; JSBoundFunction *bf; - JSValueConst *arg_buf, new_target; + JSValueConst *arg_buf; int arg_count, i; p = JS_VALUE_GET_OBJ(func_obj); @@ -11690,7 +11660,6 @@ static void profile_record_prop_site(JSRuntime *rt, JSFunctionBytecode *b, uint3 /* VM frame management for trampoline - no malloc/free! */ static struct VMFrame *vm_push_frame(JSContext *ctx, JSValueConst func_obj, JSValueConst this_obj, - JSValueConst new_target, int argc, JSValue *argv, int flags, const uint8_t *ret_pc, int ret_sp_offset, int call_argc, int call_has_this) @@ -11758,7 +11727,6 @@ static struct VMFrame *vm_push_frame(JSContext *ctx, /* Initialize frame metadata */ frame->cur_func = JS_DupValue(ctx, func_obj); frame->this_obj = JS_DupValue(ctx, this_obj); - frame->new_target = JS_DupValue(ctx, new_target); frame->b = b; frame->ctx = b->realm; frame->pc = b->byte_code_buf; @@ -11809,7 +11777,6 @@ static void vm_pop_frame(JSContext *ctx) /* Free frame values */ JS_FreeValue(ctx, frame->cur_func); JS_FreeValue(ctx, frame->this_obj); - JS_FreeValue(ctx, frame->new_target); /* Pop frame and value stack */ ctx->value_stack_top -= frame->stack_size_allocated; @@ -11844,7 +11811,7 @@ static inline JSValue *vm_frame_get_arg_buf(JSContext *ctx, struct VMFrame *fram /* Trampoline VM dispatcher - runs frames without C recursion */ static JSValue JS_CallTrampoline(JSContext *caller_ctx, JSValueConst func_obj, - JSValueConst this_obj, JSValueConst new_target, + JSValueConst this_obj, int argc, JSValue *argv, int flags) { JSRuntime *rt = caller_ctx->rt; @@ -11869,7 +11836,7 @@ static JSValue JS_CallTrampoline(JSContext *caller_ctx, JSValueConst func_obj, } /* Push initial frame (entry point, no continuation) */ - frame = vm_push_frame(caller_ctx, func_obj, this_obj, new_target, + frame = vm_push_frame(caller_ctx, func_obj, this_obj, argc, argv, flags, NULL, 0, 0, 0); if (!frame) @@ -11896,7 +11863,7 @@ static VMExecState vm_execute_frame(JSContext *ctx, struct VMFrame *frame, /* TODO: Replace with proper bytecode loop extraction */ /* For now, delegate to the old recursive implementation */ *ret_val = JS_CallInternal(ctx, frame->cur_func, frame->this_obj, - frame->new_target, frame->arg_count, + frame->arg_count, vm_frame_get_arg_buf(ctx, frame), 0); if (JS_IsException(*ret_val)) return VM_EXEC_EXCEPTION; @@ -11904,7 +11871,7 @@ static VMExecState vm_execute_frame(JSContext *ctx, struct VMFrame *frame, } static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj, - JSValueConst this_obj, JSValueConst new_target, + JSValueConst this_obj, int argc, JSValue *argv, int flags) { JSRuntime *rt = caller_ctx->rt; @@ -12076,13 +12043,10 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj, { JSValue val; - /* User-defined functions don't support property access in cell script */ - if (JS_VALUE_GET_TAG(sp[-1]) == JS_TAG_OBJECT) { - JSObject *fp = JS_VALUE_GET_OBJ(sp[-1]); - if (fp->class_id == JS_CLASS_BYTECODE_FUNCTION) { - JS_ThrowTypeError(ctx, "cannot get property of function"); - goto exception; - } + /* Functions don't support property access in cell script */ + if (js_is_proxy_callable(sp[-1])) { + JS_ThrowTypeError(ctx, "cannot get property of function"); + goto exception; } sf->cur_pc = pc; @@ -12127,7 +12091,8 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj, *sp++ = JS_DupValue(ctx, sf->cur_func); break; case OP_SPECIAL_OBJECT_NEW_TARGET: - *sp++ = JS_DupValue(ctx, new_target); + /* new.target is always null (constructors not supported) */ + *sp++ = JS_NULL; break; case OP_SPECIAL_OBJECT_VAR_OBJECT: *sp++ = JS_NewObjectProto(ctx, JS_NULL); @@ -12323,7 +12288,7 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj, #endif /* TODO: Use trampoline - for now keep recursive */ ret_val = JS_CallInternal(ctx, call_argv[-1], JS_NULL, - JS_NULL, call_argc, call_argv, 0); + call_argc, call_argv, 0); if (unlikely(JS_IsException(ret_val))) goto exception; if (opcode == OP_tail_call) @@ -12347,16 +12312,13 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj, /* Record call site */ profile_record_call_site(rt, b, (uint32_t)(pc - b->byte_code_buf)); #endif - /* Proxy method-call: detect [bytecode_func, "name", ...args] + /* Proxy method-call: detect [func, "name", ...args] and rewrite as func("name", [args]) */ - if (JS_VALUE_GET_TAG(call_argv[-2]) == JS_TAG_OBJECT) { - JSObject *fp = JS_VALUE_GET_OBJ(call_argv[-2]); - if (fp->class_id == JS_CLASS_BYTECODE_FUNCTION) { - 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 (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; } } @@ -12383,12 +12345,12 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj, proxy_argv[1] = args; ret_val = JS_CallInternal(ctx, call_argv[-2], JS_NULL, - JS_NULL, 2, proxy_argv, 0); + 2, proxy_argv, 0); JS_FreeValue(ctx, args); } } else { ret_val = JS_CallInternal(ctx, call_argv[-1], call_argv[-2], - JS_NULL, call_argc, call_argv, 0); + call_argc, call_argv, 0); } if (unlikely(JS_IsException(ret_val))) goto exception; @@ -12433,16 +12395,13 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj, pc += 2; sf->cur_pc = pc; - /* Proxy method-call with spread: detect ["name", bytecode_func, args_array] + /* Proxy method-call with spread: detect ["name", func, args_array] and rewrite as func("name", args_array) */ - if (JS_VALUE_GET_TAG(sp[-2]) == JS_TAG_OBJECT) { - JSObject *fp = JS_VALUE_GET_OBJ(sp[-2]); - if (fp->class_id == JS_CLASS_BYTECODE_FUNCTION) { - 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 (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; } } @@ -12452,7 +12411,7 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj, proxy_argv[1] = sp[-1]; /* args array already built by bytecode */ ret_val = JS_CallInternal(ctx, sp[-2], JS_NULL, - JS_NULL, 2, proxy_argv, 0); + 2, proxy_argv, 0); } else { ret_val = js_function_apply(ctx, sp[-3], 2, (JSValueConst *)&sp[-2], magic); } @@ -12521,7 +12480,7 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj, JS_EVAL_TYPE_DIRECT, scope_idx); } else { ret_val = JS_CallInternal(ctx, call_argv[-1], JS_NULL, - JS_NULL, call_argc, call_argv, 0); + call_argc, call_argv, 0); } if (unlikely(JS_IsException(ret_val))) goto exception; @@ -12568,8 +12527,7 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj, CASE(OP_regexp): { - sp[-2] = js_regexp_constructor_internal(ctx, JS_NULL, - sp[-2], sp[-1]); + sp[-2] = js_regexp_constructor_internal(ctx, sp[-2], sp[-1]); sp--; } BREAK; @@ -13147,13 +13105,10 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj, #endif obj = sp[-1]; - /* User-defined functions don't support property access in cell script */ - if (JS_VALUE_GET_TAG(obj) == JS_TAG_OBJECT) { - JSObject *fp = JS_VALUE_GET_OBJ(obj); - if (fp->class_id == JS_CLASS_BYTECODE_FUNCTION) { - JS_ThrowTypeError(ctx, "cannot get property of function"); - goto exception; - } + /* Functions don't support property access in cell script */ + if (js_is_proxy_callable(obj)) { + JS_ThrowTypeError(ctx, "cannot get property of function"); + goto exception; } /* Monomorphic IC fast path: shape-guarded own-property lookup */ @@ -13238,15 +13193,12 @@ 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_VALUE_GET_TAG(obj) == JS_TAG_OBJECT) { - JSObject *fp = JS_VALUE_GET_OBJ(obj); - if (fp->class_id == JS_CLASS_BYTECODE_FUNCTION) { - val = JS_AtomToValue(ctx, atom); /* "name" */ - if (unlikely(JS_IsException(val))) - goto exception; - *sp++ = val; /* stack becomes [func, "name"] */ - goto get_field2_done; - } + if (js_is_proxy_callable(obj)) { + val = JS_AtomToValue(ctx, atom); /* "name" */ + if (unlikely(JS_IsException(val))) + goto exception; + *sp++ = val; /* stack becomes [func, "name"] */ + goto get_field2_done; } /* Monomorphic IC fast path */ @@ -13315,13 +13267,10 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj, /* Record property access site */ profile_record_prop_site(rt, b, (uint32_t)(pc - b->byte_code_buf), atom); #endif - /* User-defined functions don't support property assignment in cell script */ - if (JS_VALUE_GET_TAG(sp[-2]) == JS_TAG_OBJECT) { - JSObject *fp = JS_VALUE_GET_OBJ(sp[-2]); - if (fp->class_id == JS_CLASS_BYTECODE_FUNCTION) { - JS_ThrowTypeError(ctx, "cannot set property of function"); - goto exception; - } + /* Functions don't support property assignment in cell script */ + if (js_is_proxy_callable(sp[-2])) { + JS_ThrowTypeError(ctx, "cannot set property of function"); + goto exception; } ret = JS_SetPropertyInternal(ctx, sp[-2], atom, sp[-1], sp[-2], @@ -13450,13 +13399,10 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj, { JSValue val; - /* User-defined functions don't support property access in cell script */ - if (JS_VALUE_GET_TAG(sp[-2]) == JS_TAG_OBJECT) { - JSObject *fp = JS_VALUE_GET_OBJ(sp[-2]); - if (fp->class_id == JS_CLASS_BYTECODE_FUNCTION) { - JS_ThrowTypeError(ctx, "cannot get property of function"); - goto exception; - } + /* 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; @@ -13474,34 +13420,31 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj, JSValue val; /* Proxy method-call sugar for bracket calls: func[key](...) */ - if (JS_VALUE_GET_TAG(sp[-2]) == JS_TAG_OBJECT) { - JSObject *fp = JS_VALUE_GET_OBJ(sp[-2]); - if (fp->class_id == JS_CLASS_BYTECODE_FUNCTION) { - /* 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 */ + 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; @@ -13516,13 +13459,10 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj, { JSValue val; - /* User-defined functions don't support property access in cell script */ - if (JS_VALUE_GET_TAG(sp[-2]) == JS_TAG_OBJECT) { - JSObject *fp = JS_VALUE_GET_OBJ(sp[-2]); - if (fp->class_id == JS_CLASS_BYTECODE_FUNCTION) { - JS_ThrowTypeError(ctx, "cannot get property of function"); - goto exception; - } + /* 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])) { @@ -13593,13 +13533,10 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj, { int ret; - /* User-defined functions don't support property assignment in cell script */ - if (JS_VALUE_GET_TAG(sp[-3]) == JS_TAG_OBJECT) { - JSObject *fp = JS_VALUE_GET_OBJ(sp[-3]); - if (fp->class_id == JS_CLASS_BYTECODE_FUNCTION) { - JS_ThrowTypeError(ctx, "cannot set property of function"); - goto exception; - } + /* Functions don't support property assignment in cell script */ + if (js_is_proxy_callable(sp[-3])) { + JS_ThrowTypeError(ctx, "cannot set property of function"); + goto exception; } sf->cur_pc = pc; @@ -14395,14 +14332,14 @@ CASE(OP_template_concat): JSValue JS_Call(JSContext *ctx, JSValueConst func_obj, JSValueConst this_obj, int argc, JSValueConst *argv) { - return JS_CallInternal(ctx, func_obj, this_obj, JS_NULL, + return JS_CallInternal(ctx, func_obj, this_obj, argc, (JSValue *)argv, JS_CALL_FLAG_COPY_ARGV); } static JSValue JS_CallFree(JSContext *ctx, JSValue func_obj, JSValueConst this_obj, int argc, JSValueConst *argv) { - JSValue res = JS_CallInternal(ctx, func_obj, this_obj, JS_NULL, + JSValue res = JS_CallInternal(ctx, func_obj, this_obj, argc, (JSValue *)argv, JS_CALL_FLAG_COPY_ARGV); JS_FreeValue(ctx, func_obj); return res; @@ -26389,50 +26326,6 @@ int JS_SetPropertyFunctionList(JSContext *ctx, JSValueConst obj, return 0; } -/* Note: 'func_obj' is not necessarily a constructor */ -static void JS_SetConstructor2(JSContext *ctx, - JSValueConst func_obj, - JSValueConst proto, - int proto_flags, int ctor_flags) -{ - JS_DefinePropertyValue(ctx, func_obj, JS_ATOM_prototype, - JS_DupValue(ctx, proto), proto_flags); - JS_DefinePropertyValue(ctx, proto, JS_ATOM_constructor, - JS_DupValue(ctx, func_obj), - ctor_flags); - set_cycle_flag(ctx, func_obj); - set_cycle_flag(ctx, proto); -} - -void JS_SetConstructor(JSContext *ctx, JSValueConst func_obj, - JSValueConst proto) -{ - JS_SetConstructor2(ctx, func_obj, proto, - 0, JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE); -} - -static void JS_NewGlobalCConstructor2(JSContext *ctx, - JSValue func_obj, - const char *name, - JSValueConst proto) -{ - JS_DefinePropertyValueStr(ctx, ctx->global_obj, name, - JS_DupValue(ctx, func_obj), - JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE); - JS_SetConstructor(ctx, func_obj, proto); - JS_FreeValue(ctx, func_obj); -} - -static JSValueConst JS_NewGlobalCConstructor(JSContext *ctx, const char *name, - JSCFunction *func, int length, - JSValueConst proto) -{ - JSValue func_obj; - func_obj = JS_NewCFunction2(ctx, func, name, length, JS_CFUNC_constructor_or_func, 0); - JS_NewGlobalCConstructor2(ctx, func_obj, name, proto); - return func_obj; -} - /* Object class */ static JSValue JS_ToObject(JSContext *ctx, JSValueConst val) @@ -26719,35 +26612,20 @@ static JSValue js_function_apply(JSContext *ctx, JSValueConst this_val, } /* Error class */ -static JSValue js_error_constructor(JSContext *ctx, JSValueConst new_target, +static JSValue js_error_constructor(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv, int magic) { - JSValue obj, msg, proto; - JSValueConst message, options; + JSValue obj, msg; + JSValueConst message, options, proto; int arg_index; - if (JS_IsNull(new_target)) - new_target = JS_GetActiveFunction(ctx); - proto = JS_GetProperty(ctx, new_target, JS_ATOM_prototype); - if (JS_IsException(proto)) - return proto; - if (!JS_IsObject(proto)) { - JSContext *realm; - JSValueConst proto1; - - JS_FreeValue(ctx, proto); - realm = JS_GetFunctionRealm(ctx, new_target); - if (!realm) - return JS_EXCEPTION; - if (magic < 0) { - proto1 = realm->class_proto[JS_CLASS_ERROR]; - } else { - proto1 = realm->native_error_proto[magic]; - } - proto = JS_DupValue(ctx, proto1); + /* Use the appropriate error prototype based on magic */ + if (magic < 0) { + proto = ctx->class_proto[JS_CLASS_ERROR]; + } else { + proto = ctx->native_error_proto[magic]; } obj = JS_NewObjectProtoClass(ctx, proto, JS_CLASS_ERROR); - JS_FreeValue(ctx, proto); if (JS_IsException(obj)) return obj; arg_index = (magic == JS_AGGREGATE_ERROR); @@ -26916,13 +26794,13 @@ static int JS_CopySubArray(JSContext *ctx, return -1; } -static JSValue js_array_constructor(JSContext *ctx, JSValueConst new_target, +static JSValue js_array_constructor(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) { JSValue obj; int i; - obj = js_create_from_ctor(ctx, new_target, JS_CLASS_ARRAY); + obj = JS_NewArray(ctx); if (JS_IsException(obj)) return obj; if (argc == 1 && JS_IsNumber(argv[0])) { @@ -27377,7 +27255,7 @@ static JSValue js_compile_regexp(JSContext *ctx, JSValueConst pattern, /* create a RegExp object from a string containing the RegExp bytecode and the source pattern */ -static JSValue js_regexp_constructor_internal(JSContext *ctx, JSValueConst ctor, +static JSValue js_regexp_constructor_internal(JSContext *ctx, JSValue pattern, JSValue bc) { JSValue obj; @@ -27394,7 +27272,7 @@ static JSValue js_regexp_constructor_internal(JSContext *ctx, JSValueConst ctor, return JS_EXCEPTION; } - obj = js_create_from_ctor(ctx, ctor, JS_CLASS_REGEXP); + obj = JS_NewObjectProtoClass(ctx, ctx->class_proto[JS_CLASS_REGEXP], JS_CLASS_REGEXP); if (JS_IsException(obj)) goto fail; p = JS_VALUE_GET_OBJ(obj); @@ -27434,7 +27312,7 @@ static int js_is_regexp(JSContext *ctx, JSValueConst obj) return js_get_regexp(ctx, obj, FALSE) != NULL; } -static JSValue js_regexp_constructor(JSContext *ctx, JSValueConst new_target, +static JSValue js_regexp_constructor(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) { JSValue pattern, flags, bc, val; @@ -27447,20 +27325,11 @@ static JSValue js_regexp_constructor(JSContext *ctx, JSValueConst new_target, pat_is_regexp = js_is_regexp(ctx, pat); if (pat_is_regexp < 0) return JS_EXCEPTION; - if (JS_IsNull(new_target)) { - /* called as a function */ - new_target = JS_GetActiveFunction(ctx); - if (pat_is_regexp && JS_IsNull(flags1)) { - JSValue ctor; - BOOL res; - ctor = JS_GetProperty(ctx, pat, JS_ATOM_constructor); - if (JS_IsException(ctor)) - return ctor; - res = js_same_value(ctx, ctor, new_target); - JS_FreeValue(ctx, ctor); - if (res) - return JS_DupValue(ctx, pat); - } + /* If called with a regexp and no flags, just return a copy */ + if (pat_is_regexp && JS_IsNull(flags1)) { + re = js_get_regexp(ctx, pat, FALSE); + if (re) + return JS_DupValue(ctx, pat); } re = js_get_regexp(ctx, pat, FALSE); if (re) { @@ -27505,7 +27374,7 @@ static JSValue js_regexp_constructor(JSContext *ctx, JSValueConst new_target, goto fail; JS_FreeValue(ctx, flags); no_compilation: - return js_regexp_constructor_internal(ctx, new_target, pattern, bc); + return js_regexp_constructor_internal(ctx, pattern, bc); fail: JS_FreeValue(ctx, pattern); JS_FreeValue(ctx, flags); @@ -28099,9 +27968,12 @@ void JS_AddIntrinsicRegExp(JSContext *ctx) ctx->class_proto[JS_CLASS_REGEXP] = JS_NewObject(ctx); JS_SetPropertyFunctionList(ctx, ctx->class_proto[JS_CLASS_REGEXP], js_regexp_proto_funcs, countof(js_regexp_proto_funcs)); - obj = JS_NewGlobalCConstructor(ctx, "RegExp", js_regexp_constructor, 2, - ctx->class_proto[JS_CLASS_REGEXP]); - ctx->regexp_ctor = JS_DupValue(ctx, obj); + obj = JS_NewCFunction2(ctx, js_regexp_constructor, "RegExp", 2, + JS_CFUNC_generic, 0); + JS_DefinePropertyValueStr(ctx, ctx->global_obj, "RegExp", + JS_DupValue(ctx, obj), + JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE); + ctx->regexp_ctor = obj; } /* JSON */ @@ -31675,7 +31547,7 @@ static void js_blob_finalizer(JSRuntime *rt, JSValue val) } /* blob() constructor */ -static JSValue js_blob_constructor(JSContext *ctx, JSValueConst new_target, +static JSValue js_blob_constructor(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) { blob *bd = NULL; @@ -32987,32 +32859,34 @@ void JS_AddIntrinsicBaseObjects(JSContext *ctx) ctx->global_obj = JS_NewObject(ctx); ctx->global_var_obj = JS_NewObjectProto(ctx, JS_NULL); - /* Function - no constructor needed */ - ctx->function_ctor = JS_NULL; - /* Error */ obj1 = JS_NewCFunctionMagic(ctx, js_error_constructor, - "Error", 1, JS_CFUNC_constructor_or_func_magic, -1); - JS_NewGlobalCConstructor2(ctx, obj1, - "Error", ctx->class_proto[JS_CLASS_ERROR]); + "Error", 1, JS_CFUNC_generic_magic, -1); + JS_DefinePropertyValueStr(ctx, ctx->global_obj, "Error", + JS_DupValue(ctx, obj1), + JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE); + JS_FreeValue(ctx, obj1); - /* Used to squelch a -Wcast-function-type warning. */ - JSCFunctionType ft = { .generic_magic = js_error_constructor }; for(i = 0; i < JS_NATIVE_ERROR_COUNT; i++) { JSValue func_obj; int n_args; n_args = 1 + (i == JS_AGGREGATE_ERROR); - func_obj = JS_NewCFunction3(ctx, ft.generic, - native_error_name[i], n_args, - JS_CFUNC_constructor_or_func_magic, i, obj1); - JS_NewGlobalCConstructor2(ctx, func_obj, native_error_name[i], - ctx->native_error_proto[i]); + func_obj = JS_NewCFunctionMagic(ctx, js_error_constructor, + native_error_name[i], n_args, + JS_CFUNC_generic_magic, i); + JS_DefinePropertyValueStr(ctx, ctx->global_obj, native_error_name[i], + JS_DupValue(ctx, func_obj), + JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE); + JS_FreeValue(ctx, func_obj); } /* Array */ - obj = JS_NewGlobalCConstructor(ctx, "Array", js_array_constructor, 1, - ctx->class_proto[JS_CLASS_ARRAY]); - ctx->array_ctor = JS_DupValue(ctx, obj); + obj = JS_NewCFunction2(ctx, js_array_constructor, "Array", 1, + JS_CFUNC_generic, 0); + JS_DefinePropertyValueStr(ctx, ctx->global_obj, "Array", + JS_DupValue(ctx, obj), + JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE); + ctx->array_ctor = obj; /* XXX: create auto_initializer */ { diff --git a/source/quickjs.h b/source/quickjs.h index bd1c3d97..bccb946f 100644 --- a/source/quickjs.h +++ b/source/quickjs.h @@ -685,8 +685,6 @@ JSValue JS_NewObjectProto(JSContext *ctx, JSValueConst proto); JSValue JS_NewObject(JSContext *ctx); JS_BOOL JS_IsFunction(JSContext* ctx, JSValueConst val); -JS_BOOL JS_IsConstructor(JSContext* ctx, JSValueConst val); -JS_BOOL JS_SetConstructorBit(JSContext *ctx, JSValueConst func_obj, JS_BOOL val); JSValue JS_NewArray(JSContext *ctx); int JS_IsArray(JSContext *ctx, JSValueConst val); @@ -751,11 +749,6 @@ JSValue JS_Call(JSContext *ctx, JSValueConst func_obj, JSValueConst this_obj, int argc, JSValueConst *argv); JSValue JS_Invoke(JSContext *ctx, JSValueConst this_val, JSAtom atom, int argc, JSValueConst *argv); -JSValue JS_CallConstructor(JSContext *ctx, JSValueConst func_obj, - int argc, JSValueConst *argv); -JSValue JS_CallConstructor2(JSContext *ctx, JSValueConst func_obj, - JSValueConst new_target, - int argc, JSValueConst *argv); /* 'input' must be zero terminated i.e. input[input_len] = '\0'. */ JSValue JS_Eval(JSContext *ctx, const char *input, size_t input_len, const char *filename, int eval_flags); @@ -822,13 +815,9 @@ JSValue JS_ReadObject(JSContext *ctx, const uint8_t *buf, size_t buf_len, JSValue JS_EvalFunction(JSContext *ctx, JSValue fun_obj); /* C function definition */ -typedef enum JSCFunctionEnum { /* XXX: should rename for namespace isolation */ +typedef enum JSCFunctionEnum { JS_CFUNC_generic, JS_CFUNC_generic_magic, - JS_CFUNC_constructor, - JS_CFUNC_constructor_magic, - JS_CFUNC_constructor_or_func, - JS_CFUNC_constructor_or_func_magic, JS_CFUNC_f_f, JS_CFUNC_f_f_f, JS_CFUNC_getter, @@ -841,9 +830,6 @@ typedef enum JSCFunctionEnum { /* XXX: should rename for namespace isolation */ typedef union JSCFunctionType { JSCFunction *generic; JSValue (*generic_magic)(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv, int magic); - JSCFunction *constructor; - JSValue (*constructor_magic)(JSContext *ctx, JSValueConst new_target, int argc, JSValueConst *argv, int magic); - JSCFunction *constructor_or_func; double (*f_f)(double); double (*f_f_f)(double, double); JSValue (*getter)(JSContext *ctx, JSValueConst this_val); @@ -873,8 +859,6 @@ static inline JSValue JS_NewCFunctionMagic(JSContext *ctx, JSCFunctionMagic *fun { return JS_NewCFunction2(ctx, (JSCFunction *)func, name, length, cproto, magic); } -void JS_SetConstructor(JSContext *ctx, JSValueConst func_obj, - JSValueConst proto); /* C property definition */