Add JS_TryGetProperty (#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()`
This commit is contained in:
parent
569b238ec4
commit
c15ef1f8dc
1 changed files with 121 additions and 86 deletions
207
quickjs.c
207
quickjs.c
|
@ -7936,6 +7936,61 @@ JSAtom JS_ValueToAtom(JSContext *ctx, JSValue val)
|
||||||
return atom;
|
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,
|
static JSValue JS_GetPropertyValue(JSContext *ctx, JSValue this_obj,
|
||||||
JSValue prop)
|
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 &&
|
if (likely(JS_VALUE_GET_TAG(this_obj) == JS_TAG_OBJECT &&
|
||||||
JS_VALUE_GET_TAG(prop) == JS_TAG_INT)) {
|
JS_VALUE_GET_TAG(prop) == JS_TAG_INT)) {
|
||||||
JSObject *p;
|
JSObject *p = JS_VALUE_GET_OBJ(this_obj);
|
||||||
uint32_t idx;
|
uint32_t idx = JS_VALUE_GET_INT(prop);
|
||||||
/* fast path for array access */
|
JSValue val;
|
||||||
p = JS_VALUE_GET_OBJ(this_obj);
|
/* fast path for array and typed array access */
|
||||||
idx = JS_VALUE_GET_INT(prop);
|
if (js_get_fast_array_element(ctx, p, idx, &val))
|
||||||
switch(p->class_id) {
|
return val;
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
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,
|
JSValue JS_GetPropertyUint32(JSContext *ctx, JSValue this_obj,
|
||||||
uint32_t idx)
|
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:
|
/* 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,
|
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)
|
static int JS_TryGetPropertyInt64(JSContext *ctx, JSValue obj, int64_t idx, JSValue *pval)
|
||||||
{
|
{
|
||||||
JSValue val = JS_UNDEFINED;
|
JSValue val;
|
||||||
JSAtom prop;
|
JSAtom prop;
|
||||||
int present;
|
int present;
|
||||||
|
|
||||||
if (likely((uint64_t)idx <= JS_ATOM_MAX_INT)) {
|
if (likely(JS_VALUE_GET_TAG(obj) == JS_TAG_OBJECT &&
|
||||||
/* fast path */
|
(uint64_t)idx <= INT32_MAX)) {
|
||||||
present = JS_HasProperty(ctx, obj, __JS_AtomFromUInt32(idx));
|
/* 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) {
|
if (present > 0) {
|
||||||
val = JS_GetPropertyValue(ctx, obj, js_int32(idx));
|
val = JS_GetProperty(ctx, obj, prop);
|
||||||
if (unlikely(JS_IsException(val)))
|
if (unlikely(JS_IsException(val)))
|
||||||
present = -1;
|
present = -1;
|
||||||
|
} else if (present == FALSE) {
|
||||||
|
val = JS_UNDEFINED;
|
||||||
}
|
}
|
||||||
} else {
|
JS_FreeAtom(ctx, prop);
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
*pval = val;
|
*pval = val;
|
||||||
return present;
|
return present;
|
||||||
|
@ -8047,9 +8062,12 @@ JSValue JS_GetPropertyInt64(JSContext *ctx, JSValue obj, int64_t idx)
|
||||||
JSAtom prop;
|
JSAtom prop;
|
||||||
JSValue val;
|
JSValue val;
|
||||||
|
|
||||||
if ((uint64_t)idx <= INT32_MAX) {
|
if (likely(JS_VALUE_GET_TAG(obj) == JS_TAG_OBJECT &&
|
||||||
/* fast path for fast arrays */
|
(uint64_t)idx <= INT32_MAX)) {
|
||||||
return JS_GetPropertyValue(ctx, obj, js_int32(idx));
|
/* 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);
|
prop = JS_NewAtomInt64(ctx, idx);
|
||||||
if (prop == JS_ATOM_NULL)
|
if (prop == JS_ATOM_NULL)
|
||||||
|
@ -34907,6 +34925,7 @@ static int js_obj_to_desc(JSContext *ctx, JSPropertyDescriptor *d,
|
||||||
JSValue desc)
|
JSValue desc)
|
||||||
{
|
{
|
||||||
JSValue val, getter, setter;
|
JSValue val, getter, setter;
|
||||||
|
int present;
|
||||||
int flags;
|
int flags;
|
||||||
|
|
||||||
if (!JS_IsObject(desc)) {
|
if (!JS_IsObject(desc)) {
|
||||||
|
@ -34917,7 +34936,10 @@ static int js_obj_to_desc(JSContext *ctx, JSPropertyDescriptor *d,
|
||||||
val = JS_UNDEFINED;
|
val = JS_UNDEFINED;
|
||||||
getter = JS_UNDEFINED;
|
getter = JS_UNDEFINED;
|
||||||
setter = 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);
|
JSValue prop = JS_GetProperty(ctx, desc, JS_ATOM_enumerable);
|
||||||
if (JS_IsException(prop))
|
if (JS_IsException(prop))
|
||||||
goto fail;
|
goto fail;
|
||||||
|
@ -34925,7 +34947,10 @@ static int js_obj_to_desc(JSContext *ctx, JSPropertyDescriptor *d,
|
||||||
if (JS_ToBoolFree(ctx, prop))
|
if (JS_ToBoolFree(ctx, prop))
|
||||||
flags |= JS_PROP_ENUMERABLE;
|
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);
|
JSValue prop = JS_GetProperty(ctx, desc, JS_ATOM_configurable);
|
||||||
if (JS_IsException(prop))
|
if (JS_IsException(prop))
|
||||||
goto fail;
|
goto fail;
|
||||||
|
@ -34933,13 +34958,19 @@ static int js_obj_to_desc(JSContext *ctx, JSPropertyDescriptor *d,
|
||||||
if (JS_ToBoolFree(ctx, prop))
|
if (JS_ToBoolFree(ctx, prop))
|
||||||
flags |= JS_PROP_CONFIGURABLE;
|
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;
|
flags |= JS_PROP_HAS_VALUE;
|
||||||
val = JS_GetProperty(ctx, desc, JS_ATOM_value);
|
val = JS_GetProperty(ctx, desc, JS_ATOM_value);
|
||||||
if (JS_IsException(val))
|
if (JS_IsException(val))
|
||||||
goto fail;
|
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);
|
JSValue prop = JS_GetProperty(ctx, desc, JS_ATOM_writable);
|
||||||
if (JS_IsException(prop))
|
if (JS_IsException(prop))
|
||||||
goto fail;
|
goto fail;
|
||||||
|
@ -34947,7 +34978,10 @@ static int js_obj_to_desc(JSContext *ctx, JSPropertyDescriptor *d,
|
||||||
if (JS_ToBoolFree(ctx, prop))
|
if (JS_ToBoolFree(ctx, prop))
|
||||||
flags |= JS_PROP_WRITABLE;
|
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;
|
flags |= JS_PROP_HAS_GET;
|
||||||
getter = JS_GetProperty(ctx, desc, JS_ATOM_get);
|
getter = JS_GetProperty(ctx, desc, JS_ATOM_get);
|
||||||
if (JS_IsException(getter) ||
|
if (JS_IsException(getter) ||
|
||||||
|
@ -34956,7 +34990,10 @@ static int js_obj_to_desc(JSContext *ctx, JSPropertyDescriptor *d,
|
||||||
goto fail;
|
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;
|
flags |= JS_PROP_HAS_SET;
|
||||||
setter = JS_GetProperty(ctx, desc, JS_ATOM_set);
|
setter = JS_GetProperty(ctx, desc, JS_ATOM_set);
|
||||||
if (JS_IsException(setter) ||
|
if (JS_IsException(setter) ||
|
||||||
|
@ -36995,10 +37032,8 @@ static JSValue js_array_at(JSContext *ctx, JSValue this_val,
|
||||||
|
|
||||||
if (idx < 0 || idx >= len) {
|
if (idx < 0 || idx >= len) {
|
||||||
ret = JS_UNDEFINED;
|
ret = JS_UNDEFINED;
|
||||||
} else if (js_get_fast_array(ctx, obj, &arrp, &count) && count == len) {
|
} else {
|
||||||
ret = js_dup(arrp[idx]);
|
ret = JS_GetPropertyInt64(ctx, obj, idx);
|
||||||
} else if (!JS_TryGetPropertyInt64(ctx, obj, idx, &ret)) {
|
|
||||||
ret = JS_UNDEFINED;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
exception:
|
exception:
|
||||||
|
|
Loading…
Reference in a new issue