From 42087910ab69e950747c00c7eb4c594cb4dea83b Mon Sep 17 00:00:00 2001 From: John Alanbrook Date: Mon, 23 Jun 2025 15:32:05 -0500 Subject: [PATCH] remove proxy and many exotic methods --- source/quickjs.c | 161 ++++++----------------------------------------- source/quickjs.h | 27 +------- 2 files changed, 21 insertions(+), 167 deletions(-) diff --git a/source/quickjs.c b/source/quickjs.c index bd971471..24471e6a 100644 --- a/source/quickjs.c +++ b/source/quickjs.c @@ -1197,7 +1197,7 @@ JSRuntime *JS_NewRuntime2(const JSMallocFunctions *mf, void *opaque) countof(js_std_class_def)) < 0) goto fail; rt->class_array[JS_CLASS_STRING].exotic = &js_string_exotic_methods; - + rt->class_array[JS_CLASS_C_FUNCTION].call = js_call_c_function; rt->class_array[JS_CLASS_C_FUNCTION_DATA].call = js_c_function_data_call; rt->class_array[JS_CLASS_BOUND_FUNCTION].call = js_call_bound_function; @@ -6323,22 +6323,16 @@ static void JS_SetImmutablePrototype(JSContext *ctx, JSValueConst obj) p->has_immutable_prototype = TRUE; } -/* Return -1 (exception) or TRUE/FALSE. 'throw_flag' = FALSE indicates - that it is called from Reflect.setPrototypeOf(). */ +/* Return -1 (exception) or TRUE. */ static int JS_SetPrototypeInternal(JSContext *ctx, JSValueConst obj, - JSValueConst proto_val, - BOOL throw_flag) + JSValueConst proto_val) { JSObject *proto, *p, *p1; JSShape *sh; - if (throw_flag) { - if (JS_VALUE_GET_TAG(obj) == JS_TAG_NULL) - goto not_obj; - } else { - if (JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT) - goto not_obj; - } + if (JS_VALUE_GET_TAG(obj) == JS_TAG_NULL) + goto not_obj; + p = JS_VALUE_GET_OBJ(obj); if (JS_VALUE_GET_TAG(proto_val) != JS_TAG_OBJECT) { if (JS_VALUE_GET_TAG(proto_val) != JS_TAG_NULL) { @@ -6347,57 +6341,30 @@ static int JS_SetPrototypeInternal(JSContext *ctx, JSValueConst obj, return -1; } proto = NULL; - } else { + } else proto = JS_VALUE_GET_OBJ(proto_val); - } - if (throw_flag && JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT) + if (JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT) return TRUE; - if (unlikely(p->is_exotic)) { - const JSClassExoticMethods *em = ctx->rt->class_array[p->class_id].exotic; - int ret; - if (em && em->set_prototype) { - ret = em->set_prototype(ctx, obj, proto_val); - if (ret == 0 && throw_flag) { - JS_ThrowTypeError(ctx, "proxy: bad prototype"); - return -1; - } else { - return ret; - } - } - } - sh = p->shape; if (sh->proto == proto) return TRUE; if (unlikely(p->has_immutable_prototype)) { - if (throw_flag) { - JS_ThrowTypeError(ctx, "prototype is immutable"); - return -1; - } else { - return FALSE; - } + JS_ThrowTypeError(ctx, "prototype is immutable"); + return -1; } if (unlikely(!p->extensible)) { - if (throw_flag) { - JS_ThrowTypeError(ctx, "object is not extensible"); - return -1; - } else { - return FALSE; - } + JS_ThrowTypeError(ctx, "object is not extensible"); + return -1; } if (proto) { /* check if there is a cycle */ p1 = proto; do { if (p1 == p) { - if (throw_flag) { - JS_ThrowTypeError(ctx, "circular prototype chain"); - return -1; - } else { - return FALSE; - } + JS_ThrowTypeError(ctx, "circular prototype chain"); + return -1; } /* Note: for Proxy objects, proto is NULL */ p1 = p1->shape->proto; @@ -6417,7 +6384,7 @@ static int JS_SetPrototypeInternal(JSContext *ctx, JSValueConst obj, /* return -1 (exception) or TRUE/FALSE */ int JS_SetPrototype(JSContext *ctx, JSValueConst obj, JSValueConst proto_val) { - return JS_SetPrototypeInternal(ctx, obj, proto_val, TRUE); + return JS_SetPrototypeInternal(ctx, obj, proto_val); } /* Only works for primitive types, otherwise return JS_NULL. */ @@ -6454,12 +6421,6 @@ JSValue JS_GetPrototype(JSContext *ctx, JSValueConst obj) if (JS_VALUE_GET_TAG(obj) == JS_TAG_OBJECT) { JSObject *p; p = JS_VALUE_GET_OBJ(obj); - if (unlikely(p->is_exotic)) { - const JSClassExoticMethods *em = ctx->rt->class_array[p->class_id].exotic; - if (em && em->get_prototype) { - return em->get_prototype(ctx, obj); - } - } p = p->shape->proto; if (!p) val = JS_NULL; @@ -6709,16 +6670,6 @@ JSValue JS_GetPropertyInternal(JSContext *ctx, JSValueConst obj, } else { const JSClassExoticMethods *em = ctx->rt->class_array[p->class_id].exotic; if (em) { - if (em->get_property) { - JSValue obj1, retval; - /* XXX: should pass throw_ref_error */ - /* Note: if 'p' is a prototype, it can be - freed in the called function */ - obj1 = JS_DupValue(ctx, JS_MKPTR(JS_TAG_OBJECT, p)); - retval = em->get_property(ctx, obj1, prop, this_obj); - JS_FreeValue(ctx, obj1); - return retval; - } if (em->get_own_property) { JSPropertyDescriptor desc; int ret; @@ -6865,40 +6816,7 @@ static int __exception JS_GetOwnPropertyNamesInternal(JSContext *ctx, if (flags & JS_GPN_STRING_MASK) { num_keys_count += js_string_obj_get_length(ctx, JS_MKPTR(JS_TAG_OBJECT, p)); } - } else { - const JSClassExoticMethods *em = ctx->rt->class_array[p->class_id].exotic; - if (em && em->get_own_property_names) { - if (em->get_own_property_names(ctx, &tab_exotic, &exotic_count, - JS_MKPTR(JS_TAG_OBJECT, p))) - return -1; - for(i = 0; i < exotic_count; i++) { - atom = tab_exotic[i].atom; - kind = JS_AtomGetKind(ctx, atom); - if (((flags >> kind) & 1) != 0) { - is_enumerable = FALSE; - if (flags & (JS_GPN_SET_ENUM | JS_GPN_ENUM_ONLY)) { - JSPropertyDescriptor desc; - int res; - /* set the "is_enumerable" field if necessary */ - res = JS_GetOwnPropertyInternal(ctx, &desc, p, atom); - if (res < 0) { - JS_FreePropertyEnum(ctx, tab_exotic, exotic_count); - return -1; - } - if (res) { - is_enumerable = - ((desc.flags & JS_PROP_ENUMERABLE) != 0); - js_free_desc(ctx, &desc); - } - tab_exotic[i].is_enumerable = is_enumerable; - } - if (!(flags & JS_GPN_ENUM_ONLY) || is_enumerable) { - exotic_keys_count++; - } - } - } - } - } + } } /* fill them */ @@ -7115,12 +7033,6 @@ int JS_IsExtensible(JSContext *ctx, JSValueConst obj) if (unlikely(JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT)) return FALSE; p = JS_VALUE_GET_OBJ(obj); - if (unlikely(p->is_exotic)) { - const JSClassExoticMethods *em = ctx->rt->class_array[p->class_id].exotic; - if (em && em->is_extensible) { - return em->is_extensible(ctx, obj); - } - } return p->extensible; } @@ -7132,12 +7044,6 @@ int JS_PreventExtensions(JSContext *ctx, JSValueConst obj) if (unlikely(JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT)) return FALSE; p = JS_VALUE_GET_OBJ(obj); - if (unlikely(p->is_exotic)) { - const JSClassExoticMethods *em = ctx->rt->class_array[p->class_id].exotic; - if (em && em->prevent_extensions) { - return em->prevent_extensions(ctx, obj); - } - } p->extensible = FALSE; return TRUE; } @@ -7153,16 +7059,6 @@ int JS_HasProperty(JSContext *ctx, JSValueConst obj, JSAtom prop) return FALSE; p = JS_VALUE_GET_OBJ(obj); for(;;) { - if (p->is_exotic) { - const JSClassExoticMethods *em = ctx->rt->class_array[p->class_id].exotic; - if (em && em->has_property) { - /* has_property can free the prototype */ - obj1 = JS_DupValue(ctx, JS_MKPTR(JS_TAG_OBJECT, p)); - ret = em->has_property(ctx, obj1, prop); - JS_FreeValue(ctx, obj1); - return ret; - } - } /* JS_GetOwnPropertyInternal can free the prototype */ JS_DupValue(ctx, JS_MKPTR(JS_TAG_OBJECT, p)); ret = JS_GetOwnPropertyInternal(ctx, NULL, p, prop); @@ -7768,15 +7664,6 @@ int JS_SetPropertyInternal(JSContext *ctx, JSValueConst obj, const JSClassExoticMethods *em = ctx->rt->class_array[p1->class_id].exotic; if (em) { JSValue obj1; - if (em->set_property) { - /* set_property can free the prototype */ - obj1 = JS_DupValue(ctx, JS_MKPTR(JS_TAG_OBJECT, p1)); - ret = em->set_property(ctx, obj1, prop, - val, this_obj, flags); - JS_FreeValue(ctx, obj1); - JS_FreeValue(ctx, val); - return ret; - } if (em->get_own_property) { /* get_own_property can free the prototype */ obj1 = JS_DupValue(ctx, JS_MKPTR(JS_TAG_OBJECT, p1)); @@ -12003,14 +11890,6 @@ static __exception int JS_CopyDataProperties(JSContext *ctx, p = JS_VALUE_GET_OBJ(source); gpn_flags = JS_GPN_STRING_MASK | JS_GPN_SYMBOL_MASK | JS_GPN_ENUM_ONLY; - if (p->is_exotic) { - const JSClassExoticMethods *em = ctx->rt->class_array[p->class_id].exotic; - /* cannot use JS_GPN_ENUM_ONLY with e.g. proxies because it - introduces a visible change */ - if (em && em->get_own_property_names) { - gpn_flags &= ~JS_GPN_ENUM_ONLY; - } - } if (JS_GetOwnPropertyNamesInternal(ctx, &tab_atom, &tab_atom_count, p, gpn_flags)) return -1; @@ -13836,7 +13715,7 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj, sf->cur_pc = pc; proto = sp[-1]; if (JS_IsObject(proto) || JS_IsNull(proto)) { - if (JS_SetPrototypeInternal(ctx, sp[-2], proto, TRUE) < 0) + if (JS_SetPrototypeInternal(ctx, sp[-2], proto) < 0) goto exception; } JS_FreeValue(ctx, proto); @@ -27715,7 +27594,7 @@ static JSValue js_object_setPrototypeOf(JSContext *ctx, JSValueConst this_val, { JSValueConst obj; obj = argv[0]; - if (JS_SetPrototypeInternal(ctx, obj, argv[1], TRUE) < 0) + if (JS_SetPrototypeInternal(ctx, obj, argv[1]) < 0) return JS_EXCEPTION; return JS_DupValue(ctx, obj); } @@ -28449,7 +28328,7 @@ static JSValue js_object_set___proto__(JSContext *ctx, JSValueConst this_val, return JS_ThrowTypeErrorNotAnObject(ctx); if (!JS_IsObject(proto) && !JS_IsNull(proto)) return JS_NULL; - if (JS_SetPrototypeInternal(ctx, this_val, proto, TRUE) < 0) + if (JS_SetPrototypeInternal(ctx, this_val, proto) < 0) return JS_EXCEPTION; else return JS_NULL; @@ -28668,7 +28547,7 @@ static JSValue js_function_constructor(JSContext *ctx, JSValueConst new_target, goto fail1; proto = JS_DupValue(ctx, realm->class_proto[JS_CLASS_BYTECODE_FUNCTION]); } - ret = JS_SetPrototypeInternal(ctx, obj, proto, TRUE); + ret = JS_SetPrototypeInternal(ctx, obj, proto); JS_FreeValue(ctx, proto); if (ret < 0) goto fail1; diff --git a/source/quickjs.h b/source/quickjs.h index 246ca618..dbb0d282 100644 --- a/source/quickjs.h +++ b/source/quickjs.h @@ -455,12 +455,7 @@ typedef struct JSClassExoticMethods { returned, the property descriptor 'desc' is filled if != NULL. */ int (*get_own_property)(JSContext *ctx, JSPropertyDescriptor *desc, JSValueConst obj, JSAtom prop); - /* '*ptab' should hold the '*plen' property keys. Return 0 if OK, - -1 if exception. The 'is_enumerable' field is ignored. - */ - int (*get_own_property_names)(JSContext *ctx, JSPropertyEnum **ptab, - uint32_t *plen, - JSValueConst obj); + /* return < 0 if exception, or TRUE/FALSE */ int (*delete_property)(JSContext *ctx, JSValueConst obj, JSAtom prop); /* return < 0 if exception or TRUE/FALSE */ @@ -468,26 +463,6 @@ typedef struct JSClassExoticMethods { JSAtom prop, JSValueConst val, JSValueConst getter, JSValueConst setter, int flags); - /* The following methods can be emulated with the previous ones, - so they are usually not needed */ - /* return < 0 if exception or TRUE/FALSE */ - int (*has_property)(JSContext *ctx, JSValueConst obj, JSAtom atom); - JSValue (*get_property)(JSContext *ctx, JSValueConst obj, JSAtom atom, - JSValueConst receiver); - /* return < 0 if exception or TRUE/FALSE */ - int (*set_property)(JSContext *ctx, JSValueConst obj, JSAtom atom, - JSValueConst value, JSValueConst receiver, int flags); - - /* To get a consistent object behavior when get_prototype != NULL, - get_property, set_property and set_prototype must be != NULL - and the object must be created with a JS_NULL prototype. */ - JSValue (*get_prototype)(JSContext *ctx, JSValueConst obj); - /* return < 0 if exception or TRUE/FALSE */ - int (*set_prototype)(JSContext *ctx, JSValueConst obj, JSValueConst proto_val); - /* return < 0 if exception or TRUE/FALSE */ - int (*is_extensible)(JSContext *ctx, JSValueConst obj); - /* return < 0 if exception or TRUE/FALSE */ - int (*prevent_extensions)(JSContext *ctx, JSValueConst obj); } JSClassExoticMethods; typedef void JSClassFinalizer(JSRuntime *rt, JSValue val);