8000 optimized array access by inlining get_array_el, get_array_el2, get_a… · bellard/quickjs@8e8eefb · GitHub
[go: up one dir, main page]

Skip to content

Commit 8e8eefb

Browse files
author
Fabrice Bellard
committed
optimized array access by inlining get_array_el, get_array_el2, get_array_el3 and put_array_el
1 parent 64c55c6 commit 8e8eefb

File tree

2 files changed

+173
-135
lines changed

2 files changed

+173
-135
lines changed

quickjs.c

Lines changed: 150 additions & 135 deletions
Original file line numberDiff line numberDiff line change
@@ -18228,99 +18228,64 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj,
1822818228
}
1822918229
BREAK;
1823018230

18231-
CASE(OP_get_field):
18232-
{
18233-
JSValue val, obj;
18234-
JSAtom atom;
18235-
JSObject *p;
18236-
JSProperty *pr;
18237-
JSShapeProperty *prs;
18238-
18239-
atom = get_u32(pc);
18240-
pc += 4;
18241-
18242-
obj = sp[-1];
18243-
if (likely(JS_VALUE_GET_TAG(obj) == JS_TAG_OBJECT)) {
18244-
p = JS_VALUE_GET_OBJ(obj);
18245-
for(;;) {
18246-
prs = find_own_property(&pr, p, atom);
18247-
if (prs) {
18248-
/* found */
18249-
if (unlikely(prs->flags & JS_PROP_TMASK))
18250-
goto get_field_slow_path;
18251-
val = JS_DupValue(ctx, pr->u.value);
18252-
break;
18253-
}
18254-
if (unlikely(p->is_exotic)) {
18255-
/* XXX: should avoid the slow path for arrays
18256-
and typed arrays by ensuring that 'prop' is
18257-
not numeric */
18258-
obj = JS_MKPTR(JS_TAG_OBJECT, p);
18259-
goto get_field_slow_path;
18260-
}
18261-
p = p->shape->proto;
18262-
if (!p) {
18263-
val = JS_UNDEFINED;
18264-
break;
18265-
}
18266-
}
18267-
} else {
18268-
get_field_slow_path:
18269-
sf->cur_pc = pc;
18270-
val = JS_GetPropertyInternal(ctx, obj, atom, sp[-1], 0);
18271-
if (unlikely(JS_IsException(val)))
18272-
goto exception;
18273-
}
18274-
JS_FreeValue(ctx, sp[-1]);
18275-
sp[-1] = val;
18231+
#define GET_FIELD_INLINE(name, keep) \
18232+
{ \
18233+
JSValue val, obj; \
18234+
JSAtom atom; \
18235+
JSObject *p; \
18236+
JSProperty *pr; \
18237+
JSShapeProperty *prs; \
18238+
\
18239+
atom = get_u32(pc); \
18240+
pc += 4; \
18241+
\
18242+
obj = sp[-1]; \
18243+
if (likely(JS_VALUE_GET_TAG(obj) == JS_TAG_OBJECT)) { \
18244+
p = JS_VALUE_GET_OBJ(obj); \
18245+
for(;;) { \
18246+
prs = find_own_property(&pr, p, atom); \
18247+
if (prs) { \
18248+
/* found */ \
18249+
if (unlikely(prs->flags & JS_PROP_TMASK)) \
18250+
goto name ## _slow_path; \
18251+
val = JS_DupValue(ctx, pr->u.value); \
18252+
break; \
18253+
} \
18254+
if (unlikely(p->is_exotic)) { \
18255+
/* XXX: should avoid the slow path for arrays \
18256+
and typed arrays by ensuring that 'prop' is \
18257+
not numeric */ \
18258+
obj = JS_MKPTR(JS_TAG_OBJECT, p); \
18259+
goto name ## _slow_path; \
18260+
} \
18261+
p = p->shape->proto; \
18262+
if (!p) { \
18263+
val = JS_UNDEFINED; \
18264+
break; \
18265+
} \
18266+
} \
18267+
} else { \
18268+
name ## _slow_path: \
18269+
sf->cur_pc = pc; \
18270+
val = JS_GetPropertyInternal(ctx, obj, atom, sp[-1], 0); \
18271+
if (unlikely(JS_IsException(val))) \
18272+
goto exception; \
18273+
} \
18274+
if (keep) { \
18275+
*sp++ = val; \
18276+
} else { \
18277+
JS_FreeValue(ctx, sp[-1]); \
18278+
sp[-1] = val; \
18279+
} \
1827618280
}
18281+
18282+
18283+
CASE(OP_get_field):
18284+
GET_FIELD_INLINE(get_field, 0);
1827718285
BREAK;
1827818286

1827918287
CASE(OP_get_field2):
18280-
{
18281-
JSValue val, obj;
18282-
JSAtom atom;
18283-
JSObject *p;
18284-
JSProperty *pr;
18285-
JSShapeProperty *prs;
18286-
18287-
atom = get_u32(pc);
18288-
pc += 4;
18289-
18290-
obj = sp[-1];
18291-
if (likely(JS_VALUE_GET_TAG(obj) == JS_TAG_OBJECT)) {
18292-
p = JS_VALUE_GET_OBJ(obj);
18293-
for(;;) {
18294-
prs = find_own_property(&pr, p, atom);
18295-
if (prs) {
18296-
/* found */
18297-
if (unlikely(prs->flags & JS_PROP_TMASK))
18298-
goto get_field2_slow_path;
18299-
val = JS_DupValue(ctx, pr->u.value);
18300-
break;
18301-
}
18302-
if (unlikely(p->is_exotic)) {
18303-
/* XXX: should avoid the slow path for arrays
18304-
and typed arrays by ensuring that 'prop' is
18305-
not numeric */
18306-
obj = JS_MKPTR(JS_TAG_OBJECT, p);
18307-
goto get_field2_slow_path;
18308-
}
18309-
p = p->shape->proto;
18310-
if (!p) {
18311-
val = JS_UNDEFINED;
18312-
break;
18313-
}
18314-
}
18315-
} else {
18316-
get_field2_slow_path:
18317-
sf->cur_pc = pc;
18318-
val = JS_GetPropertyInternal(ctx, obj, atom, sp[-1], 0);
18319-
if (unlikely(JS_IsException(val)))
18320-
goto exception;
18321-
}
18322-
*sp++ = val;
18323-
}
18288+
GET_FIELD_INLINE(get_field2, 1);
1832418289
BREAK;
1832518290

1832618291
CASE(OP_put_field):
@@ -18542,61 +18507,95 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj,
1854218507
}
1854318508
BREAK;
1854418509

18545-
CASE(OP_get_array_el):
18546-
{
18547-
JSValue val;
18548-
18549-
sf->cur_pc = pc;
18550-
val = JS_GetPropertyValue(ctx, sp[-2], sp[-1]);
18551-
JS_FreeValue(ctx, sp[-2]);
18552-
sp[-2] = val;
18553-
sp--;
18554-
if (unlikely(JS_IsException(val)))
18555-
goto exception;
18510+
#define GET_ARRAY_EL_INLINE(name, keep) \
18511+
{ \
18512+
JSValue val, obj, prop; \
18513+
JSObject *p; \
18514+
uint32_t idx; \
18515+
\
18516+
obj = sp[-2]; \
18517+
prop = sp[-1]; \
18518+
if (likely(JS_VALUE_GET_TAG(obj) == JS_TAG_OBJECT && \
18519+
JS_VALUE_GET_TAG(prop) == JS_TAG_INT)) { \
18520+
p = JS_VALUE_GET_OBJ(obj); \
18521+
idx = JS_VALUE_GET_INT(prop); \
18522+
if (unlikely(p->class_id != JS_CLASS_ARRAY)) \
18523+
goto name ## 8020 _slow_path; \
18524+
if (unlikely(idx >= p->u.array.count)) \
18525+
goto name ## _slow_path; \
18526+
val = JS_DupValue(ctx, p->u.array.u.values[idx]); \
18527+
} else { \
18528+
name ## _slow_path: \
18529+
sf->cur_pc = pc; \
18530+
val = JS_GetPropertyValue(ctx, obj, prop); \
18531+
if (unlikely(JS_IsException(val))) { \
18532+
if (keep) \
18533+
sp[-1] = JS_UNDEFINED; \
18534+
else \
18535+
sp--; \
18536+
goto exception; \
18537+
} \
18538+
} \
18539+
if (keep) { \
18540+
sp[-1] = val; \
18541+
} else { \
18542+
JS_FreeValue(ctx, obj); \
18543+
sp[-2] = val; \
18544+
sp--; \
18545+
} \
1855618546
}
18547+
18548+
CASE(OP_get_array_el):
18549+
GET_ARRAY_EL_INLINE(get_array_el, 0);
1855718550
BREAK;
1855818551

1855918552
CASE(OP_get_array_el2):
18560-
{
18561-
JSValue val;
18562-
18563-
sf->cur_pc = pc;
18564-
val = JS_GetPropertyValue(ctx, sp[-2], sp[-1]);
18565-
sp[-1] = val;
18566-
if (unlikely(JS_IsException(val)))
18567-
goto exception;
18568-
}
18553+
GET_ARRAY_EL_INLINE(get_array_el2, 1);
1856918554
BREAK;
1857018555

1857118556
CASE(OP_get_array_el3):
1857218557
{
1857318558
JSValue val;
18559+
JSObject *p;
18560+
uint32_t idx;
1857418561

18575-
switch (JS_VALUE_GET_TAG(sp[-2])) {
18576-
case JS_TAG_INT:
18577-
case JS_TAG_STRING:
18578-
case JS_TAG_SYMBOL:
18579-
/* undefined and null are tested in JS_GetPropertyValue() */
18580-
break;
18581-
default:
18582-
/* must be tested nefore JS_ToPropertyKey */
18583-
if (unlikely(JS_IsUndefined(sp[-2]) || JS_IsNull(sp[-2]))) {
18584-
JS_ThrowTypeError(ctx, "value has no property");
18585-
goto exception;
18562+
if (likely(JS_VALUE_GET_TAG(sp[-2]) == JS_TAG_OBJECT &&
18563+
JS_VALUE_GET_TAG(sp[-1]) == JS_TAG_INT)) {
18564+
p = JS_VALUE_GET_OBJ(sp[-2]);
18565+
idx = JS_VALUE_GET_INT(sp[-1]);
18566+
if (unlikely(p->class_id != JS_CLASS_ARRAY))
18567+
goto get_array_el3_slow_path;
18568+
if (unlikely(idx >= p->u.array.count))
18569+
goto get_array_el3_slow_path;
18570+
val = JS_DupValue(ctx, p->u.array.u.values[idx]);
18571+
} else {
18572+
get_array_el3_slow_path:
18573+
switch (JS_VALUE_GET_TAG(sp[-1])) {
< 3B34 code>18574+
case JS_TAG_INT:
18575+
case JS_TAG_STRING:
18576+
case JS_TAG_SYMBOL:
18577+
/* undefined and null are tested in JS_GetPropertyValue() */
18578+
break;
18579+
default:
18580+
/* must be tested before JS_ToPropertyKey */
18581+
if (unlikely(JS_IsUndefined(sp[-2]) || JS_IsNull(sp[-2]))) {
18582+
JS_ThrowTypeError(ctx, "value has no property");
18583+
goto exception;
18584+
}
18585+
sf->cur_pc = pc;
18586+
ret_val = JS_ToPropertyKey(ctx, sp[-1]);
18587+
if (JS_IsException(ret_val))
18588+
goto exception;
18589+
JS_FreeValue(ctx, sp[-1]);
18590+
sp[-1] = ret_val;
18591+
break;
1858618592
}
1858718593
sf->cur_pc = pc;
18588-
ret_val = JS_ToPropertyKey(ctx, sp[-1]);
18589-
if (JS_IsException(ret_val))
18594+
val = JS_GetPropertyValue(ctx, sp[-2], JS_DupValue(ctx, sp[-1]));
18595+
if (unlikely(JS_IsException(val)))
1859018596
goto exception;
18591-
JS_FreeValue(ctx, sp[-1]);
18592-
sp[-1] = ret_val;
18593-
break;
1859418597
}
18595-
sf->cur_pc = pc;
18596-
val = JS_GetPropertyValue(ctx, sp[-2], JS_DupValue(ctx, sp[-1]));
1859718598
*sp++ = val;
18598-
if (unlikely(JS_IsException(val)))
18599-
goto exception;
1860018599
}
1860118600
BREAK;
1860218601

@@ -18661,13 +18660,29 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj,
1866118660
CASE(OP_put_array_el):
1866218661
{
1866318662
int ret;
18663+
JSObject *p;
18664+
uint32_t idx;
1866418665

18665-
sf->cur_pc = pc;
18666-
ret = JS_SetPropertyValue(ctx, sp[-3], sp[-2], sp[-1], JS_PROP_THROW_STRICT);
18667-
JS_FreeValue(ctx, sp[-3]);
18668- sp -= 3;
18669-
if (unlikely(ret < 0))
18670-
goto exception;
18666+
if (likely(JS_VALUE_GET_TAG(sp[-3]) == JS_TAG_OBJECT &&
18667+
JS_VALUE_GET_TAG(sp[-2]) == JS_TAG_INT)) {
18668+
p = JS_VALUE_GET_OBJ(sp[-3]);
18669+
idx = JS_VALUE_GET_INT(sp[-2]);
18670+
if (unlikely(p->class_id != JS_CLASS_ARRAY))
18671+
goto put_array_el_slow_path;
18672+
if (unlikely(idx >= (uint32_t)p->u.array.count))
18673+
goto put_array_el_slow_path;
18674+
set_value(ctx, &p->u.array.u.values[idx], sp[-1]);
18675+
JS_FreeValue(ctx, sp[-3]);
18676+
sp -= 3;
18677+
} else {
18678+
put_array_el_slow_path:
18679+
sf->cur_pc = pc;
18680+
ret = JS_SetPropertyValue(ctx, sp[-3], sp[-2], sp[-1], JS_PROP_THROW_STRICT);
18681+
JS_FreeValue(ctx, sp[-3]);
18682+
sp -= 3;
18683+
if (unlikely(ret < 0))
18684+
goto exception;
18685+
}
1867118686
}
1867218687
BREAK;
1867318688

tests/microbench.js

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -375,6 +375,28 @@ function array_write(n)
375375
return len * n;
376376
}
377377

378+
function array_update(n)
379+
{
380+
var tab, len, i, j;
381+
tab = [];
382+
len = 10;
383+
for(i = 0; i < len; i++)
384+
tab[i] = i;
385+
for(j = 0; j < n; j++) {
386+
tab[0] += j;
387+
tab[1] += j;
388+
tab[2] += j;
389+
tab[3] += j;
390+
tab[4] += j;
391+
tab[5] += j;
392+
tab[6] += j;
393+
tab[7] += j;
394+
tab[8] += j;
395+
tab[9] += j;
396+
}
397+
return len * n;
398+
}
399+
378400
function array_prop_create(n)
379401
{
380402
var tab, i, j, len;
@@ -1357,6 +1379,7 @@ function main(argc, argv, g)
13571379
prop_delete,
13581380
array_read,
13591381
array_write,
1382+
array_update,
13601383
array_prop_create,
13611384
array_slice,
13621385
array_length_decr,

0 commit comments

Comments
 (0)
0