mirror of
https://github.com/bellard/quickjs.git
synced 2025-11-15 10:12:14 +03:00
optimized array access by inlining get_array_el, get_array_el2, get_array_el3 and put_array_el
This commit is contained in:
285
quickjs.c
285
quickjs.c
@@ -18228,99 +18228,64 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj,
|
||||
}
|
||||
BREAK;
|
||||
|
||||
CASE(OP_get_field):
|
||||
{
|
||||
JSValue val, obj;
|
||||
JSAtom atom;
|
||||
JSObject *p;
|
||||
JSProperty *pr;
|
||||
JSShapeProperty *prs;
|
||||
|
||||
atom = get_u32(pc);
|
||||
pc += 4;
|
||||
|
||||
obj = sp[-1];
|
||||
if (likely(JS_VALUE_GET_TAG(obj) == JS_TAG_OBJECT)) {
|
||||
p = JS_VALUE_GET_OBJ(obj);
|
||||
for(;;) {
|
||||
prs = find_own_property(&pr, p, atom);
|
||||
if (prs) {
|
||||
/* found */
|
||||
if (unlikely(prs->flags & JS_PROP_TMASK))
|
||||
goto get_field_slow_path;
|
||||
val = JS_DupValue(ctx, pr->u.value);
|
||||
break;
|
||||
}
|
||||
if (unlikely(p->is_exotic)) {
|
||||
/* XXX: should avoid the slow path for arrays
|
||||
and typed arrays by ensuring that 'prop' is
|
||||
not numeric */
|
||||
obj = JS_MKPTR(JS_TAG_OBJECT, p);
|
||||
goto get_field_slow_path;
|
||||
}
|
||||
p = p->shape->proto;
|
||||
if (!p) {
|
||||
val = JS_UNDEFINED;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
get_field_slow_path:
|
||||
sf->cur_pc = pc;
|
||||
val = JS_GetPropertyInternal(ctx, obj, atom, sp[-1], 0);
|
||||
if (unlikely(JS_IsException(val)))
|
||||
goto exception;
|
||||
}
|
||||
JS_FreeValue(ctx, sp[-1]);
|
||||
sp[-1] = val;
|
||||
#define GET_FIELD_INLINE(name, keep) \
|
||||
{ \
|
||||
JSValue val, obj; \
|
||||
JSAtom atom; \
|
||||
JSObject *p; \
|
||||
JSProperty *pr; \
|
||||
JSShapeProperty *prs; \
|
||||
\
|
||||
atom = get_u32(pc); \
|
||||
pc += 4; \
|
||||
\
|
||||
obj = sp[-1]; \
|
||||
if (likely(JS_VALUE_GET_TAG(obj) == JS_TAG_OBJECT)) { \
|
||||
p = JS_VALUE_GET_OBJ(obj); \
|
||||
for(;;) { \
|
||||
prs = find_own_property(&pr, p, atom); \
|
||||
if (prs) { \
|
||||
/* found */ \
|
||||
if (unlikely(prs->flags & JS_PROP_TMASK)) \
|
||||
goto name ## _slow_path; \
|
||||
val = JS_DupValue(ctx, pr->u.value); \
|
||||
break; \
|
||||
} \
|
||||
if (unlikely(p->is_exotic)) { \
|
||||
/* XXX: should avoid the slow path for arrays \
|
||||
and typed arrays by ensuring that 'prop' is \
|
||||
not numeric */ \
|
||||
obj = JS_MKPTR(JS_TAG_OBJECT, p); \
|
||||
goto name ## _slow_path; \
|
||||
} \
|
||||
p = p->shape->proto; \
|
||||
if (!p) { \
|
||||
val = JS_UNDEFINED; \
|
||||
break; \
|
||||
} \
|
||||
} \
|
||||
} else { \
|
||||
name ## _slow_path: \
|
||||
sf->cur_pc = pc; \
|
||||
val = JS_GetPropertyInternal(ctx, obj, atom, sp[-1], 0); \
|
||||
if (unlikely(JS_IsException(val))) \
|
||||
goto exception; \
|
||||
} \
|
||||
if (keep) { \
|
||||
*sp++ = val; \
|
||||
} else { \
|
||||
JS_FreeValue(ctx, sp[-1]); \
|
||||
sp[-1] = val; \
|
||||
} \
|
||||
}
|
||||
|
||||
|
||||
CASE(OP_get_field):
|
||||
GET_FIELD_INLINE(get_field, 0);
|
||||
BREAK;
|
||||
|
||||
CASE(OP_get_field2):
|
||||
{
|
||||
JSValue val, obj;
|
||||
JSAtom atom;
|
||||
JSObject *p;
|
||||
JSProperty *pr;
|
||||
JSShapeProperty *prs;
|
||||
|
||||
atom = get_u32(pc);
|
||||
pc += 4;
|
||||
|
||||
obj = sp[-1];
|
||||
if (likely(JS_VALUE_GET_TAG(obj) == JS_TAG_OBJECT)) {
|
||||
p = JS_VALUE_GET_OBJ(obj);
|
||||
for(;;) {
|
||||
prs = find_own_property(&pr, p, atom);
|
||||
if (prs) {
|
||||
/* found */
|
||||
if (unlikely(prs->flags & JS_PROP_TMASK))
|
||||
goto get_field2_slow_path;
|
||||
val = JS_DupValue(ctx, pr->u.value);
|
||||
break;
|
||||
}
|
||||
if (unlikely(p->is_exotic)) {
|
||||
/* XXX: should avoid the slow path for arrays
|
||||
and typed arrays by ensuring that 'prop' is
|
||||
not numeric */
|
||||
obj = JS_MKPTR(JS_TAG_OBJECT, p);
|
||||
goto get_field2_slow_path;
|
||||
}
|
||||
p = p->shape->proto;
|
||||
if (!p) {
|
||||
val = JS_UNDEFINED;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
get_field2_slow_path:
|
||||
sf->cur_pc = pc;
|
||||
val = JS_GetPropertyInternal(ctx, obj, atom, sp[-1], 0);
|
||||
if (unlikely(JS_IsException(val)))
|
||||
goto exception;
|
||||
}
|
||||
*sp++ = val;
|
||||
}
|
||||
GET_FIELD_INLINE(get_field2, 1);
|
||||
BREAK;
|
||||
|
||||
CASE(OP_put_field):
|
||||
@@ -18542,61 +18507,95 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj,
|
||||
}
|
||||
BREAK;
|
||||
|
||||
CASE(OP_get_array_el):
|
||||
{
|
||||
JSValue val;
|
||||
|
||||
sf->cur_pc = pc;
|
||||
val = JS_GetPropertyValue(ctx, sp[-2], sp[-1]);
|
||||
JS_FreeValue(ctx, sp[-2]);
|
||||
sp[-2] = val;
|
||||
sp--;
|
||||
if (unlikely(JS_IsException(val)))
|
||||
goto exception;
|
||||
#define GET_ARRAY_EL_INLINE(name, keep) \
|
||||
{ \
|
||||
JSValue val, obj, prop; \
|
||||
JSObject *p; \
|
||||
uint32_t idx; \
|
||||
\
|
||||
obj = sp[-2]; \
|
||||
prop = sp[-1]; \
|
||||
if (likely(JS_VALUE_GET_TAG(obj) == JS_TAG_OBJECT && \
|
||||
JS_VALUE_GET_TAG(prop) == JS_TAG_INT)) { \
|
||||
p = JS_VALUE_GET_OBJ(obj); \
|
||||
idx = JS_VALUE_GET_INT(prop); \
|
||||
if (unlikely(p->class_id != JS_CLASS_ARRAY)) \
|
||||
goto name ## _slow_path; \
|
||||
if (unlikely(idx >= p->u.array.count)) \
|
||||
goto name ## _slow_path; \
|
||||
val = JS_DupValue(ctx, p->u.array.u.values[idx]); \
|
||||
} else { \
|
||||
name ## _slow_path: \
|
||||
sf->cur_pc = pc; \
|
||||
val = JS_GetPropertyValue(ctx, obj, prop); \
|
||||
if (unlikely(JS_IsException(val))) { \
|
||||
if (keep) \
|
||||
sp[-1] = JS_UNDEFINED; \
|
||||
else \
|
||||
sp--; \
|
||||
goto exception; \
|
||||
} \
|
||||
} \
|
||||
if (keep) { \
|
||||
sp[-1] = val; \
|
||||
} else { \
|
||||
JS_FreeValue(ctx, obj); \
|
||||
sp[-2] = val; \
|
||||
sp--; \
|
||||
} \
|
||||
}
|
||||
|
||||
CASE(OP_get_array_el):
|
||||
GET_ARRAY_EL_INLINE(get_array_el, 0);
|
||||
BREAK;
|
||||
|
||||
CASE(OP_get_array_el2):
|
||||
{
|
||||
JSValue val;
|
||||
|
||||
sf->cur_pc = pc;
|
||||
val = JS_GetPropertyValue(ctx, sp[-2], sp[-1]);
|
||||
sp[-1] = val;
|
||||
if (unlikely(JS_IsException(val)))
|
||||
goto exception;
|
||||
}
|
||||
GET_ARRAY_EL_INLINE(get_array_el2, 1);
|
||||
BREAK;
|
||||
|
||||
CASE(OP_get_array_el3):
|
||||
{
|
||||
JSValue val;
|
||||
JSObject *p;
|
||||
uint32_t idx;
|
||||
|
||||
switch (JS_VALUE_GET_TAG(sp[-2])) {
|
||||
case JS_TAG_INT:
|
||||
case JS_TAG_STRING:
|
||||
case JS_TAG_SYMBOL:
|
||||
/* undefined and null are tested in JS_GetPropertyValue() */
|
||||
break;
|
||||
default:
|
||||
/* must be tested nefore JS_ToPropertyKey */
|
||||
if (unlikely(JS_IsUndefined(sp[-2]) || JS_IsNull(sp[-2]))) {
|
||||
JS_ThrowTypeError(ctx, "value has no property");
|
||||
goto exception;
|
||||
if (likely(JS_VALUE_GET_TAG(sp[-2]) == JS_TAG_OBJECT &&
|
||||
JS_VALUE_GET_TAG(sp[-1]) == JS_TAG_INT)) {
|
||||
p = JS_VALUE_GET_OBJ(sp[-2]);
|
||||
idx = JS_VALUE_GET_INT(sp[-1]);
|
||||
if (unlikely(p->class_id != JS_CLASS_ARRAY))
|
||||
goto get_array_el3_slow_path;
|
||||
if (unlikely(idx >= p->u.array.count))
|
||||
goto get_array_el3_slow_path;
|
||||
val = JS_DupValue(ctx, p->u.array.u.values[idx]);
|
||||
} else {
|
||||
get_array_el3_slow_path:
|
||||
switch (JS_VALUE_GET_TAG(sp[-1])) {
|
||||
case JS_TAG_INT:
|
||||
case JS_TAG_STRING:
|
||||
case JS_TAG_SYMBOL:
|
||||
/* undefined and null are tested in JS_GetPropertyValue() */
|
||||
break;
|
||||
default:
|
||||
/* must be tested before JS_ToPropertyKey */
|
||||
if (unlikely(JS_IsUndefined(sp[-2]) || JS_IsNull(sp[-2]))) {
|
||||
JS_ThrowTypeError(ctx, "value has no property");
|
||||
goto exception;
|
||||
}
|
||||
sf->cur_pc = pc;
|
||||
ret_val = JS_ToPropertyKey(ctx, sp[-1]);
|
||||
if (JS_IsException(ret_val))
|
||||
goto exception;
|
||||
JS_FreeValue(ctx, sp[-1]);
|
||||
sp[-1] = ret_val;
|
||||
break;
|
||||
}
|
||||
sf->cur_pc = pc;
|
||||
ret_val = JS_ToPropertyKey(ctx, sp[-1]);
|
||||
if (JS_IsException(ret_val))
|
||||
val = JS_GetPropertyValue(ctx, sp[-2], JS_DupValue(ctx, sp[-1]));
|
||||
if (unlikely(JS_IsException(val)))
|
||||
goto exception;
|
||||
JS_FreeValue(ctx, sp[-1]);
|
||||
sp[-1] = ret_val;
|
||||
break;
|
||||
}
|
||||
sf->cur_pc = pc;
|
||||
val = JS_GetPropertyValue(ctx, sp[-2], JS_DupValue(ctx, sp[-1]));
|
||||
*sp++ = val;
|
||||
if (unlikely(JS_IsException(val)))
|
||||
goto exception;
|
||||
}
|
||||
BREAK;
|
||||
|
||||
@@ -18661,13 +18660,29 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj,
|
||||
CASE(OP_put_array_el):
|
||||
{
|
||||
int ret;
|
||||
JSObject *p;
|
||||
uint32_t idx;
|
||||
|
||||
sf->cur_pc = pc;
|
||||
ret = JS_SetPropertyValue(ctx, sp[-3], sp[-2], sp[-1], JS_PROP_THROW_STRICT);
|
||||
JS_FreeValue(ctx, sp[-3]);
|
||||
sp -= 3;
|
||||
if (unlikely(ret < 0))
|
||||
goto exception;
|
||||
if (likely(JS_VALUE_GET_TAG(sp[-3]) == JS_TAG_OBJECT &&
|
||||
JS_VALUE_GET_TAG(sp[-2]) == JS_TAG_INT)) {
|
||||
p = JS_VALUE_GET_OBJ(sp[-3]);
|
||||
idx = JS_VALUE_GET_INT(sp[-2]);
|
||||
if (unlikely(p->class_id != JS_CLASS_ARRAY))
|
||||
goto put_array_el_slow_path;
|
||||
if (unlikely(idx >= (uint32_t)p->u.array.count))
|
||||
goto put_array_el_slow_path;
|
||||
set_value(ctx, &p->u.array.u.values[idx], sp[-1]);
|
||||
JS_FreeValue(ctx, sp[-3]);
|
||||
sp -= 3;
|
||||
} else {
|
||||
put_array_el_slow_path:
|
||||
sf->cur_pc = pc;
|
||||
ret = JS_SetPropertyValue(ctx, sp[-3], sp[-2], sp[-1], JS_PROP_THROW_STRICT);
|
||||
JS_FreeValue(ctx, sp[-3]);
|
||||
sp -= 3;
|
||||
if (unlikely(ret < 0))
|
||||
goto exception;
|
||||
}
|
||||
}
|
||||
BREAK;
|
||||
|
||||
|
||||
@@ -375,6 +375,28 @@ function array_write(n)
|
||||
return len * n;
|
||||
}
|
||||
|
||||
function array_update(n)
|
||||
{
|
||||
var tab, len, i, j;
|
||||
tab = [];
|
||||
len = 10;
|
||||
for(i = 0; i < len; i++)
|
||||
tab[i] = i;
|
||||
for(j = 0; j < n; j++) {
|
||||
tab[0] += j;
|
||||
tab[1] += j;
|
||||
tab[2] += j;
|
||||
tab[3] += j;
|
||||
tab[4] += j;
|
||||
tab[5] += j;
|
||||
tab[6] += j;
|
||||
tab[7] += j;
|
||||
tab[8] += j;
|
||||
tab[9] += j;
|
||||
}
|
||||
return len * n;
|
||||
}
|
||||
|
||||
function array_prop_create(n)
|
||||
{
|
||||
var tab, i, j, len;
|
||||
@@ -1357,6 +1379,7 @@ function main(argc, argv, g)
|
||||
prop_delete,
|
||||
array_read,
|
||||
array_write,
|
||||
array_update,
|
||||
array_prop_create,
|
||||
array_slice,
|
||||
array_length_decr,
|
||||
|
||||
Reference in New Issue
Block a user