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;
|
||||
}
|
||||
|
||||
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:
|
||||
|
|
Loading…
Reference in a new issue