Skip to content

Commit c15ef1f

Browse files
authored
Add JS_TryGetProperty (bellard#337)
* Optimize `JS_GetPropertyInt64` and `JS_TryGetPropertyInt64` - add `js_get_fast_array_element()` to special case arrays and typed arrays - use `js_get_fast_array_element()` in `JS_GetPropertyValue()`, `JS_TryGetPropertyInt64()` and `JS_GetPropertyInt64()`. - simplify `js_array_at()`
1 parent 569b238 commit c15ef1f

1 file changed

Lines changed: 121 additions & 86 deletions

File tree

quickjs.c

Lines changed: 121 additions & 86 deletions
Original file line numberDiff line numberDiff line change
@@ -7936,6 +7936,61 @@ JSAtom JS_ValueToAtom(JSContext *ctx, JSValue val)
79367936
return atom;
79377937
}
79387938

7939+
static BOOL js_get_fast_array_element(JSContext *ctx, JSObject *p,
7940+
uint32_t idx, JSValue *pval)
7941+
{
7942+
switch(p->class_id) {
7943+
case JS_CLASS_ARRAY:
7944+
case JS_CLASS_ARGUMENTS:
7945+
if (unlikely(idx >= p->u.array.count)) return FALSE;
7946+
*pval = js_dup(p->u.array.u.values[idx]);
7947+
return TRUE;
7948+
case JS_CLASS_INT8_ARRAY:
7949+
if (unlikely(idx >= p->u.array.count)) return FALSE;
7950+
*pval = js_int32(p->u.array.u.int8_ptr[idx]);
7951+
return TRUE;
7952+
case JS_CLASS_UINT8C_ARRAY:
7953+
case JS_CLASS_UINT8_ARRAY:
7954+
if (unlikely(idx >= p->u.array.count)) return FALSE;
7955+
*pval = js_int32(p->u.array.u.uint8_ptr[idx]);
7956+
return TRUE;
7957+
case JS_CLASS_INT16_ARRAY:
7958+
if (unlikely(idx >= p->u.array.count)) return FALSE;
7959+
*pval = js_int32(p->u.array.u.int16_ptr[idx]);
7960+
return TRUE;
7961+
case JS_CLASS_UINT16_ARRAY:
7962+
if (unlikely(idx >= p->u.array.count)) return FALSE;
7963+
*pval = js_int32(p->u.array.u.uint16_ptr[idx]);
7964+
return TRUE;
7965+
case JS_CLASS_INT32_ARRAY:
7966+
if (unlikely(idx >= p->u.array.count)) return FALSE;
7967+
*pval = js_int32(p->u.array.u.int32_ptr[idx]);
7968+
return TRUE;
7969+
case JS_CLASS_UINT32_ARRAY:
7970+
if (unlikely(idx >= p->u.array.count)) return FALSE;
7971+
*pval = js_uint32(p->u.array.u.uint32_ptr[idx]);
7972+
return TRUE;
7973+
case JS_CLASS_BIG_INT64_ARRAY:
7974+
if (unlikely(idx >= p->u.array.count)) return FALSE;
7975+
*pval = JS_NewBigInt64(ctx, p->u.array.u.int64_ptr[idx]);
7976+
return TRUE;
7977+
case JS_CLASS_BIG_UINT64_ARRAY:
7978+
if (unlikely(idx >= p->u.array.count)) return FALSE;
7979+
*pval = JS_NewBigUint64(ctx, p->u.array.u.uint64_ptr[idx]);
7980+
return TRUE;
7981+
case JS_CLASS_FLOAT32_ARRAY:
7982+
if (unlikely(idx >= p->u.array.count)) return FALSE;
7983+
*pval = js_float64(p->u.array.u.float_ptr[idx]);
7984+
return TRUE;
7985+
case JS_CLASS_FLOAT64_ARRAY:
7986+
if (unlikely(idx >= p->u.array.count)) return FALSE;
7987+
*pval = js_float64(p->u.array.u.double_ptr[idx]);
7988+
return TRUE;
7989+
default:
7990+
return FALSE;
7991+
}
7992+
}
7993+
79397994
static JSValue JS_GetPropertyValue(JSContext *ctx, JSValue this_obj,
79407995
JSValue prop)
79417996
{
@@ -7944,99 +7999,59 @@ static JSValue JS_GetPropertyValue(JSContext *ctx, JSValue this_obj,
79447999

79458000
if (likely(JS_VALUE_GET_TAG(this_obj) == JS_TAG_OBJECT &&
79468001
JS_VALUE_GET_TAG(prop) == JS_TAG_INT)) {
7947-
JSObject *p;
7948-
uint32_t idx;
7949-
/* fast path for array access */
7950-
p = JS_VALUE_GET_OBJ(this_obj);
7951-
idx = JS_VALUE_GET_INT(prop);
7952-
switch(p->class_id) {
7953-
case JS_CLASS_ARRAY:
7954-
case JS_CLASS_ARGUMENTS:
7955-
if (unlikely(idx >= p->u.array.count)) goto slow_path;
7956-
return js_dup(p->u.array.u.values[idx]);
7957-
case JS_CLASS_INT8_ARRAY:
7958-
if (unlikely(idx >= p->u.array.count)) goto slow_path;
7959-
return js_int32(p->u.array.u.int8_ptr[idx]);
7960-
case JS_CLASS_UINT8C_ARRAY:
7961-
case JS_CLASS_UINT8_ARRAY:
7962-
if (unlikely(idx >= p->u.array.count)) goto slow_path;
7963-
return js_int32(p->u.array.u.uint8_ptr[idx]);
7964-
case JS_CLASS_INT16_ARRAY:
7965-
if (unlikely(idx >= p->u.array.count)) goto slow_path;
7966-
return js_int32(p->u.array.u.int16_ptr[idx]);
7967-
case JS_CLASS_UINT16_ARRAY:
7968-
if (unlikely(idx >= p->u.array.count)) goto slow_path;
7969-
return js_int32(p->u.array.u.uint16_ptr[idx]);
7970-
case JS_CLASS_INT32_ARRAY:
7971-
if (unlikely(idx >= p->u.array.count)) goto slow_path;
7972-
return js_int32(p->u.array.u.int32_ptr[idx]);
7973-
case JS_CLASS_UINT32_ARRAY:
7974-
if (unlikely(idx >= p->u.array.count)) goto slow_path;
7975-
return js_uint32(p->u.array.u.uint32_ptr[idx]);
7976-
case JS_CLASS_BIG_INT64_ARRAY:
7977-
if (unlikely(idx >= p->u.array.count)) goto slow_path;
7978-
return JS_NewBigInt64(ctx, p->u.array.u.int64_ptr[idx]);
7979-
case JS_CLASS_BIG_UINT64_ARRAY:
7980-
if (unlikely(idx >= p->u.array.count)) goto slow_path;
7981-
return JS_NewBigUint64(ctx, p->u.array.u.uint64_ptr[idx]);
7982-
case JS_CLASS_FLOAT32_ARRAY:
7983-
if (unlikely(idx >= p->u.array.count)) goto slow_path;
7984-
return js_float64(p->u.array.u.float_ptr[idx]);
7985-
case JS_CLASS_FLOAT64_ARRAY:
7986-
if (unlikely(idx >= p->u.array.count)) goto slow_path;
7987-
return js_float64(p->u.array.u.double_ptr[idx]);
7988-
default:
7989-
goto slow_path;
7990-
}
7991-
} else {
7992-
slow_path:
7993-
atom = JS_ValueToAtom(ctx, prop);
7994-
JS_FreeValue(ctx, prop);
7995-
if (unlikely(atom == JS_ATOM_NULL))
7996-
return JS_EXCEPTION;
7997-
ret = JS_GetProperty(ctx, this_obj, atom);
7998-
JS_FreeAtom(ctx, atom);
7999-
return ret;
8002+
JSObject *p = JS_VALUE_GET_OBJ(this_obj);
8003+
uint32_t idx = JS_VALUE_GET_INT(prop);
8004+
JSValue val;
8005+
/* fast path for array and typed array access */
8006+
if (js_get_fast_array_element(ctx, p, idx, &val))
8007+
return val;
80008008
}
8009+
atom = JS_ValueToAtom(ctx, prop);
8010+
JS_FreeValue(ctx, prop);
8011+
if (unlikely(atom == JS_ATOM_NULL))
8012+
return JS_EXCEPTION;
8013+
ret = JS_GetProperty(ctx, this_obj, atom);
8014+
JS_FreeAtom(ctx, atom);
8015+
return ret;
80018016
}
80028017

80038018
JSValue JS_GetPropertyUint32(JSContext *ctx, JSValue this_obj,
80048019
uint32_t idx)
80058020
{
8006-
return JS_GetPropertyValue(ctx, this_obj, js_uint32(idx));
8021+
return JS_GetPropertyInt64(ctx, this_obj, idx);
80078022
}
80088023

80098024
/* Check if an object has a generalized numeric property. Return value:
8010-
-1 for exception,
8025+
-1 for exception, *pval set to JS_EXCEPTION
80118026
TRUE if property exists, stored into *pval,
8012-
FALSE if proprty does not exist.
8027+
FALSE if property does not exist. *pval set to JS_UNDEFINED.
80138028
*/
80148029
static int JS_TryGetPropertyInt64(JSContext *ctx, JSValue obj, int64_t idx, JSValue *pval)
80158030
{
8016-
JSValue val = JS_UNDEFINED;
8031+
JSValue val;
80178032
JSAtom prop;
80188033
int present;
80198034

8020-
if (likely((uint64_t)idx <= JS_ATOM_MAX_INT)) {
8021-
/* fast path */
8022-
present = JS_HasProperty(ctx, obj, __JS_AtomFromUInt32(idx));
8035+
if (likely(JS_VALUE_GET_TAG(obj) == JS_TAG_OBJECT &&
8036+
(uint64_t)idx <= INT32_MAX)) {
8037+
/* fast path for array and typed array access */
8038+
JSObject *p = JS_VALUE_GET_OBJ(obj);
8039+
if (js_get_fast_array_element(ctx, p, idx, pval))
8040+
return TRUE;
8041+
}
8042+
val = JS_EXCEPTION;
8043+
present = -1;
8044+
prop = JS_NewAtomInt64(ctx, idx);
8045+
if (likely(prop != JS_ATOM_NULL)) {
8046+
present = JS_HasProperty(ctx, obj, prop);
80238047
if (present > 0) {
8024-
val = JS_GetPropertyValue(ctx, obj, js_int32(idx));
8048+
val = JS_GetProperty(ctx, obj, prop);
80258049
if (unlikely(JS_IsException(val)))
80268050
present = -1;
8051+
} else if (present == FALSE) {
8052+
val = JS_UNDEFINED;
80278053
}
8028-
} else {
8029-
prop = JS_NewAtomInt64(ctx, idx);
8030-
present = -1;
8031-
if (likely(prop != JS_ATOM_NULL)) {
8032-
present = JS_HasProperty(ctx, obj, prop);
8033-
if (present > 0) {
8034-
val = JS_GetProperty(ctx, obj, prop);
8035-
if (unlikely(JS_IsException(val)))
8036-
present = -1;
8037-
}
8038-
JS_FreeAtom(ctx, prop);
8039-
}
8054+
JS_FreeAtom(ctx, prop);
80408055
}
80418056
*pval = val;
80428057
return present;
@@ -8047,9 +8062,12 @@ JSValue JS_GetPropertyInt64(JSContext *ctx, JSValue obj, int64_t idx)
80478062
JSAtom prop;
80488063
JSValue val;
80498064

8050-
if ((uint64_t)idx <= INT32_MAX) {
8051-
/* fast path for fast arrays */
8052-
return JS_GetPropertyValue(ctx, obj, js_int32(idx));
8065+
if (likely(JS_VALUE_GET_TAG(obj) == JS_TAG_OBJECT &&
8066+
(uint64_t)idx <= INT32_MAX)) {
8067+
/* fast path for array and typed array access */
8068+
JSObject *p = JS_VALUE_GET_OBJ(obj);
8069+
if (js_get_fast_array_element(ctx, p, idx, &val))
8070+
return val;
80538071
}
80548072
prop = JS_NewAtomInt64(ctx, idx);
80558073
if (prop == JS_ATOM_NULL)
@@ -34907,6 +34925,7 @@ static int js_obj_to_desc(JSContext *ctx, JSPropertyDescriptor *d,
3490734925
JSValue desc)
3490834926
{
3490934927
JSValue val, getter, setter;
34928+
int present;
3491034929
int flags;
3491134930

3491234931
if (!JS_IsObject(desc)) {
@@ -34917,37 +34936,52 @@ static int js_obj_to_desc(JSContext *ctx, JSPropertyDescriptor *d,
3491734936
val = JS_UNDEFINED;
3491834937
getter = JS_UNDEFINED;
3491934938
setter = JS_UNDEFINED;
34920-
if (JS_HasProperty(ctx, desc, JS_ATOM_enumerable)) {
34939+
present = JS_HasProperty(ctx, desc, JS_ATOM_enumerable);
34940+
if (present < 0)
34941+
goto fail;
34942+
if (present) {
3492134943
JSValue prop = JS_GetProperty(ctx, desc, JS_ATOM_enumerable);
3492234944
if (JS_IsException(prop))
3492334945
goto fail;
3492434946
flags |= JS_PROP_HAS_ENUMERABLE;
3492534947
if (JS_ToBoolFree(ctx, prop))
3492634948
flags |= JS_PROP_ENUMERABLE;
3492734949
}
34928-
if (JS_HasProperty(ctx, desc, JS_ATOM_configurable)) {
34950+
present = JS_HasProperty(ctx, desc, JS_ATOM_configurable);
34951+
if (present < 0)
34952+
goto fail;
34953+
if (present) {
3492934954
JSValue prop = JS_GetProperty(ctx, desc, JS_ATOM_configurable);
3493034955
if (JS_IsException(prop))
3493134956
goto fail;
3493234957
flags |= JS_PROP_HAS_CONFIGURABLE;
3493334958
if (JS_ToBoolFree(ctx, prop))
3493434959
flags |= JS_PROP_CONFIGURABLE;
3493534960
}
34936-
if (JS_HasProperty(ctx, desc, JS_ATOM_value)) {
34961+
present = JS_HasProperty(ctx, desc, JS_ATOM_value);
34962+
if (present < 0)
34963+
goto fail;
34964+
if (present) {
3493734965
flags |= JS_PROP_HAS_VALUE;
3493834966
val = JS_GetProperty(ctx, desc, JS_ATOM_value);
3493934967
if (JS_IsException(val))
3494034968
goto fail;
3494134969
}
34942-
if (JS_HasProperty(ctx, desc, JS_ATOM_writable)) {
34970+
present = JS_HasProperty(ctx, desc, JS_ATOM_writable);
34971+
if (present < 0)
34972+
goto fail;
34973+
if (present) {
3494334974
JSValue prop = JS_GetProperty(ctx, desc, JS_ATOM_writable);
3494434975
if (JS_IsException(prop))
3494534976
goto fail;
3494634977
flags |= JS_PROP_HAS_WRITABLE;
3494734978
if (JS_ToBoolFree(ctx, prop))
3494834979
flags |= JS_PROP_WRITABLE;
3494934980
}
34950-
if (JS_HasProperty(ctx, desc, JS_ATOM_get)) {
34981+
present = JS_HasProperty(ctx, desc, JS_ATOM_get);
34982+
if (present < 0)
34983+
goto fail;
34984+
if (present) {
3495134985
flags |= JS_PROP_HAS_GET;
3495234986
getter = JS_GetProperty(ctx, desc, JS_ATOM_get);
3495334987
if (JS_IsException(getter) ||
@@ -34956,7 +34990,10 @@ static int js_obj_to_desc(JSContext *ctx, JSPropertyDescriptor *d,
3495634990
goto fail;
3495734991
}
3495834992
}
34959-
if (JS_HasProperty(ctx, desc, JS_ATOM_set)) {
34993+
present = JS_HasProperty(ctx, desc, JS_ATOM_set);
34994+
if (present < 0)
34995+
goto fail;
34996+
if (present) {
3496034997
flags |= JS_PROP_HAS_SET;
3496134998
setter = JS_GetProperty(ctx, desc, JS_ATOM_set);
3496234999
if (JS_IsException(setter) ||
@@ -36995,10 +37032,8 @@ static JSValue js_array_at(JSContext *ctx, JSValue this_val,
3699537032

3699637033
if (idx < 0 || idx >= len) {
3699737034
ret = JS_UNDEFINED;
36998-
} else if (js_get_fast_array(ctx, obj, &arrp, &count) && count == len) {
36999-
ret = js_dup(arrp[idx]);
37000-
} else if (!JS_TryGetPropertyInt64(ctx, obj, idx, &ret)) {
37001-
ret = JS_UNDEFINED;
37035+
} else {
37036+
ret = JS_GetPropertyInt64(ctx, obj, idx);
3700237037
}
3700337038

3700437039
exception:

0 commit comments

Comments
 (0)