diff --git a/quickjs.c b/quickjs.c index 601afc8..7a388d0 100644 --- a/quickjs.c +++ b/quickjs.c @@ -7936,6 +7936,61 @@ JSAtom JS_ValueToAtom(JSContext *ctx, JSValue val) return atom; } +static BOOL js_get_fast_array_element(JSContext *ctx, JSObject *p, + uint32_t idx, JSValue *pval) +{ + switch(p->class_id) { + case JS_CLASS_ARRAY: + case JS_CLASS_ARGUMENTS: + if (unlikely(idx >= p->u.array.count)) return FALSE; + *pval = js_dup(p->u.array.u.values[idx]); + return TRUE; + case JS_CLASS_INT8_ARRAY: + if (unlikely(idx >= p->u.array.count)) return FALSE; + *pval = js_int32(p->u.array.u.int8_ptr[idx]); + return TRUE; + case JS_CLASS_UINT8C_ARRAY: + case JS_CLASS_UINT8_ARRAY: + if (unlikely(idx >= p->u.array.count)) return FALSE; + *pval = js_int32(p->u.array.u.uint8_ptr[idx]); + return TRUE; + case JS_CLASS_INT16_ARRAY: + if (unlikely(idx >= p->u.array.count)) return FALSE; + *pval = js_int32(p->u.array.u.int16_ptr[idx]); + return TRUE; + case JS_CLASS_UINT16_ARRAY: + if (unlikely(idx >= p->u.array.count)) return FALSE; + *pval = js_int32(p->u.array.u.uint16_ptr[idx]); + return TRUE; + case JS_CLASS_INT32_ARRAY: + if (unlikely(idx >= p->u.array.count)) return FALSE; + *pval = js_int32(p->u.array.u.int32_ptr[idx]); + return TRUE; + case JS_CLASS_UINT32_ARRAY: + if (unlikely(idx >= p->u.array.count)) return FALSE; + *pval = js_uint32(p->u.array.u.uint32_ptr[idx]); + return TRUE; + case JS_CLASS_BIG_INT64_ARRAY: + if (unlikely(idx >= p->u.array.count)) return FALSE; + *pval = JS_NewBigInt64(ctx, p->u.array.u.int64_ptr[idx]); + return TRUE; + case JS_CLASS_BIG_UINT64_ARRAY: + if (unlikely(idx >= p->u.array.count)) return FALSE; + *pval = JS_NewBigUint64(ctx, p->u.array.u.uint64_ptr[idx]); + return TRUE; + case JS_CLASS_FLOAT32_ARRAY: + if (unlikely(idx >= p->u.array.count)) return FALSE; + *pval = js_float64(p->u.array.u.float_ptr[idx]); + return TRUE; + case JS_CLASS_FLOAT64_ARRAY: + if (unlikely(idx >= p->u.array.count)) return FALSE; + *pval = js_float64(p->u.array.u.double_ptr[idx]); + return TRUE; + default: + return FALSE; + } +} + static JSValue JS_GetPropertyValue(JSContext *ctx, JSValue this_obj, JSValue prop) { @@ -7944,99 +7999,59 @@ static JSValue JS_GetPropertyValue(JSContext *ctx, JSValue this_obj, if (likely(JS_VALUE_GET_TAG(this_obj) == JS_TAG_OBJECT && JS_VALUE_GET_TAG(prop) == JS_TAG_INT)) { - JSObject *p; - uint32_t idx; - /* fast path for array access */ - p = JS_VALUE_GET_OBJ(this_obj); - idx = JS_VALUE_GET_INT(prop); - switch(p->class_id) { - case JS_CLASS_ARRAY: - case JS_CLASS_ARGUMENTS: - if (unlikely(idx >= p->u.array.count)) goto slow_path; - return js_dup(p->u.array.u.values[idx]); - case JS_CLASS_INT8_ARRAY: - if (unlikely(idx >= p->u.array.count)) goto slow_path; - return js_int32(p->u.array.u.int8_ptr[idx]); - case JS_CLASS_UINT8C_ARRAY: - case JS_CLASS_UINT8_ARRAY: - if (unlikely(idx >= p->u.array.count)) goto slow_path; - return js_int32(p->u.array.u.uint8_ptr[idx]); - case JS_CLASS_INT16_ARRAY: - if (unlikely(idx >= p->u.array.count)) goto slow_path; - return js_int32(p->u.array.u.int16_ptr[idx]); - case JS_CLASS_UINT16_ARRAY: - if (unlikely(idx >= p->u.array.count)) goto slow_path; - return js_int32(p->u.array.u.uint16_ptr[idx]); - case JS_CLASS_INT32_ARRAY: - if (unlikely(idx >= p->u.array.count)) goto slow_path; - return js_int32(p->u.array.u.int32_ptr[idx]); - case JS_CLASS_UINT32_ARRAY: - if (unlikely(idx >= p->u.array.count)) goto slow_path; - return js_uint32(p->u.array.u.uint32_ptr[idx]); - case JS_CLASS_BIG_INT64_ARRAY: - if (unlikely(idx >= p->u.array.count)) goto slow_path; - return JS_NewBigInt64(ctx, p->u.array.u.int64_ptr[idx]); - case JS_CLASS_BIG_UINT64_ARRAY: - if (unlikely(idx >= p->u.array.count)) goto slow_path; - return JS_NewBigUint64(ctx, p->u.array.u.uint64_ptr[idx]); - case JS_CLASS_FLOAT32_ARRAY: - if (unlikely(idx >= p->u.array.count)) goto slow_path; - return js_float64(p->u.array.u.float_ptr[idx]); - case JS_CLASS_FLOAT64_ARRAY: - if (unlikely(idx >= p->u.array.count)) goto slow_path; - return js_float64(p->u.array.u.double_ptr[idx]); - default: - goto slow_path; - } - } else { - slow_path: - atom = JS_ValueToAtom(ctx, prop); - JS_FreeValue(ctx, prop); - if (unlikely(atom == JS_ATOM_NULL)) - return JS_EXCEPTION; - ret = JS_GetProperty(ctx, this_obj, atom); - JS_FreeAtom(ctx, atom); - return ret; + JSObject *p = JS_VALUE_GET_OBJ(this_obj); + uint32_t idx = JS_VALUE_GET_INT(prop); + JSValue val; + /* fast path for array and typed array access */ + if (js_get_fast_array_element(ctx, p, idx, &val)) + return val; } + atom = JS_ValueToAtom(ctx, prop); + JS_FreeValue(ctx, prop); + if (unlikely(atom == JS_ATOM_NULL)) + return JS_EXCEPTION; + ret = JS_GetProperty(ctx, this_obj, atom); + JS_FreeAtom(ctx, atom); + return ret; } JSValue JS_GetPropertyUint32(JSContext *ctx, JSValue this_obj, uint32_t idx) { - return JS_GetPropertyValue(ctx, this_obj, js_uint32(idx)); + return JS_GetPropertyInt64(ctx, this_obj, idx); } /* Check if an object has a generalized numeric property. Return value: - -1 for exception, + -1 for exception, *pval set to JS_EXCEPTION TRUE if property exists, stored into *pval, - FALSE if proprty does not exist. + FALSE if property does not exist. *pval set to JS_UNDEFINED. */ static int JS_TryGetPropertyInt64(JSContext *ctx, JSValue obj, int64_t idx, JSValue *pval) { - JSValue val = JS_UNDEFINED; + JSValue val; JSAtom prop; int present; - if (likely((uint64_t)idx <= JS_ATOM_MAX_INT)) { - /* fast path */ - present = JS_HasProperty(ctx, obj, __JS_AtomFromUInt32(idx)); + if (likely(JS_VALUE_GET_TAG(obj) == JS_TAG_OBJECT && + (uint64_t)idx <= INT32_MAX)) { + /* fast path for array and typed array access */ + JSObject *p = JS_VALUE_GET_OBJ(obj); + if (js_get_fast_array_element(ctx, p, idx, pval)) + return TRUE; + } + val = JS_EXCEPTION; + present = -1; + prop = JS_NewAtomInt64(ctx, idx); + if (likely(prop != JS_ATOM_NULL)) { + present = JS_HasProperty(ctx, obj, prop); if (present > 0) { - val = JS_GetPropertyValue(ctx, obj, js_int32(idx)); + val = JS_GetProperty(ctx, obj, prop); if (unlikely(JS_IsException(val))) present = -1; + } else if (present == FALSE) { + val = JS_UNDEFINED; } - } else { - prop = JS_NewAtomInt64(ctx, idx); - present = -1; - if (likely(prop != JS_ATOM_NULL)) { - present = JS_HasProperty(ctx, obj, prop); - if (present > 0) { - val = JS_GetProperty(ctx, obj, prop); - if (unlikely(JS_IsException(val))) - present = -1; - } - JS_FreeAtom(ctx, prop); - } + JS_FreeAtom(ctx, prop); } *pval = val; return present; @@ -8047,9 +8062,12 @@ JSValue JS_GetPropertyInt64(JSContext *ctx, JSValue obj, int64_t idx) JSAtom prop; JSValue val; - if ((uint64_t)idx <= INT32_MAX) { - /* fast path for fast arrays */ - return JS_GetPropertyValue(ctx, obj, js_int32(idx)); + if (likely(JS_VALUE_GET_TAG(obj) == JS_TAG_OBJECT && + (uint64_t)idx <= INT32_MAX)) { + /* fast path for array and typed array access */ + JSObject *p = JS_VALUE_GET_OBJ(obj); + if (js_get_fast_array_element(ctx, p, idx, &val)) + return val; } prop = JS_NewAtomInt64(ctx, idx); if (prop == JS_ATOM_NULL) @@ -34907,6 +34925,7 @@ static int js_obj_to_desc(JSContext *ctx, JSPropertyDescriptor *d, JSValue desc) { JSValue val, getter, setter; + int present; int flags; if (!JS_IsObject(desc)) { @@ -34917,7 +34936,10 @@ static int js_obj_to_desc(JSContext *ctx, JSPropertyDescriptor *d, val = JS_UNDEFINED; getter = JS_UNDEFINED; setter = JS_UNDEFINED; - if (JS_HasProperty(ctx, desc, JS_ATOM_enumerable)) { + present = JS_HasProperty(ctx, desc, JS_ATOM_enumerable); + if (present < 0) + goto fail; + if (present) { JSValue prop = JS_GetProperty(ctx, desc, JS_ATOM_enumerable); if (JS_IsException(prop)) goto fail; @@ -34925,7 +34947,10 @@ static int js_obj_to_desc(JSContext *ctx, JSPropertyDescriptor *d, if (JS_ToBoolFree(ctx, prop)) flags |= JS_PROP_ENUMERABLE; } - if (JS_HasProperty(ctx, desc, JS_ATOM_configurable)) { + present = JS_HasProperty(ctx, desc, JS_ATOM_configurable); + if (present < 0) + goto fail; + if (present) { JSValue prop = JS_GetProperty(ctx, desc, JS_ATOM_configurable); if (JS_IsException(prop)) goto fail; @@ -34933,13 +34958,19 @@ static int js_obj_to_desc(JSContext *ctx, JSPropertyDescriptor *d, if (JS_ToBoolFree(ctx, prop)) flags |= JS_PROP_CONFIGURABLE; } - if (JS_HasProperty(ctx, desc, JS_ATOM_value)) { + present = JS_HasProperty(ctx, desc, JS_ATOM_value); + if (present < 0) + goto fail; + if (present) { flags |= JS_PROP_HAS_VALUE; val = JS_GetProperty(ctx, desc, JS_ATOM_value); if (JS_IsException(val)) goto fail; } - if (JS_HasProperty(ctx, desc, JS_ATOM_writable)) { + present = JS_HasProperty(ctx, desc, JS_ATOM_writable); + if (present < 0) + goto fail; + if (present) { JSValue prop = JS_GetProperty(ctx, desc, JS_ATOM_writable); if (JS_IsException(prop)) goto fail; @@ -34947,7 +34978,10 @@ static int js_obj_to_desc(JSContext *ctx, JSPropertyDescriptor *d, if (JS_ToBoolFree(ctx, prop)) flags |= JS_PROP_WRITABLE; } - if (JS_HasProperty(ctx, desc, JS_ATOM_get)) { + present = JS_HasProperty(ctx, desc, JS_ATOM_get); + if (present < 0) + goto fail; + if (present) { flags |= JS_PROP_HAS_GET; getter = JS_GetProperty(ctx, desc, JS_ATOM_get); if (JS_IsException(getter) || @@ -34956,7 +34990,10 @@ static int js_obj_to_desc(JSContext *ctx, JSPropertyDescriptor *d, goto fail; } } - if (JS_HasProperty(ctx, desc, JS_ATOM_set)) { + present = JS_HasProperty(ctx, desc, JS_ATOM_set); + if (present < 0) + goto fail; + if (present) { flags |= JS_PROP_HAS_SET; setter = JS_GetProperty(ctx, desc, JS_ATOM_set); if (JS_IsException(setter) || @@ -36995,10 +37032,8 @@ static JSValue js_array_at(JSContext *ctx, JSValue this_val, if (idx < 0 || idx >= len) { ret = JS_UNDEFINED; - } else if (js_get_fast_array(ctx, obj, &arrp, &count) && count == len) { - ret = js_dup(arrp[idx]); - } else if (!JS_TryGetPropertyInt64(ctx, obj, idx, &ret)) { - ret = JS_UNDEFINED; + } else { + ret = JS_GetPropertyInt64(ctx, obj, idx); } exception: