Skip to content
New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

Add JS_TryGetProperty #337

Merged
merged 3 commits into from
Apr 3, 2024
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
207 changes: 121 additions & 86 deletions quickjs.c
Original file line number Diff line number Diff line change
Expand Up @@ -7937,6 +7937,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:
Comment on lines +7944 to +7945
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It might make sense to put these together next to the typed array constants inside the enum so they make up a dense range.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's a good point, but it justifies a separate commit as changing the class ID order has subtle implications, among which all array initializers that use class IDs as index values and possibly other ones too.

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)
{
Expand All @@ -7945,99 +8000,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;
Expand All @@ -8048,9 +8063,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)
Expand Down Expand Up @@ -34890,6 +34908,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)) {
Expand All @@ -34900,37 +34919,52 @@ 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;
flags |= JS_PROP_HAS_ENUMERABLE;
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;
flags |= JS_PROP_HAS_CONFIGURABLE;
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;
flags |= JS_PROP_HAS_WRITABLE;
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) ||
Expand All @@ -34939,7 +34973,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) ||
Expand Down Expand Up @@ -36978,10 +37015,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:
Expand Down
Loading