prop ic
This commit is contained in:
160
source/quickjs.c
160
source/quickjs.c
@@ -13102,31 +13102,8 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj,
|
||||
/* Record call site */
|
||||
profile_record_call_site(rt, b, (uint32_t)(pc - b->byte_code_buf));
|
||||
#endif
|
||||
/* Fast path: check if we can avoid full JS_CallInternal overhead */
|
||||
{
|
||||
JSValue func_obj = call_argv[-1];
|
||||
if (likely(JS_VALUE_GET_TAG(func_obj) == JS_TAG_OBJECT)) {
|
||||
JSObject *func_p = JS_VALUE_GET_OBJ(func_obj);
|
||||
if (likely(func_p->class_id == JS_CLASS_BYTECODE_FUNCTION)) {
|
||||
JSFunctionBytecode *callee_b = func_p->u.func.function_bytecode;
|
||||
/* Check if we can do fast call (simple case, no special handling) */
|
||||
if (likely(call_argc >= callee_b->arg_count &&
|
||||
!callee_b->is_derived_class_constructor &&
|
||||
callee_b->func_kind == 0 &&
|
||||
!caller_ctx->trace_hook)) {
|
||||
/* Recursively call JS_CallInternal with flags indicating
|
||||
we already checked these conditions */
|
||||
ret_val = JS_CallInternal(ctx, func_obj, JS_NULL, JS_NULL,
|
||||
call_argc, call_argv, 0);
|
||||
goto call_done;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/* Slow path: full JS_CallInternal with all checks */
|
||||
ret_val = JS_CallInternal(ctx, call_argv[-1], JS_NULL,
|
||||
JS_NULL, call_argc, call_argv, 0);
|
||||
call_done:
|
||||
if (unlikely(JS_IsException(ret_val)))
|
||||
goto exception;
|
||||
if (opcode == OP_tail_call)
|
||||
@@ -13993,6 +13970,9 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj,
|
||||
JSValue val;
|
||||
JSAtom atom;
|
||||
JSValue obj;
|
||||
const uint8_t *ic_pc;
|
||||
|
||||
ic_pc = pc - 1; /* PC of opcode, before consuming operands */
|
||||
atom = get_u32(pc);
|
||||
pc += 4;
|
||||
|
||||
@@ -14002,34 +13982,59 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj,
|
||||
profile_record_prop_site(rt, b, (uint32_t)(pc - b->byte_code_buf), atom);
|
||||
#endif
|
||||
obj = sp[-1];
|
||||
/* Fast path: try inline property lookup for regular objects */
|
||||
|
||||
/* Monomorphic IC fast path: shape-guarded own-property lookup */
|
||||
if (likely(JS_VALUE_GET_TAG(obj) == JS_TAG_OBJECT)) {
|
||||
JSObject *p = JS_VALUE_GET_OBJ(obj);
|
||||
if (likely(p->class_id == JS_CLASS_OBJECT)) {
|
||||
JSShape *sh = p->shape;
|
||||
JSShapeProperty *pr, *prop;
|
||||
intptr_t h;
|
||||
/* Inline property lookup (same as find_own_property) */
|
||||
h = (uintptr_t)atom & sh->prop_hash_mask;
|
||||
h = prop_hash_end(sh)[-h - 1];
|
||||
prop = get_shape_prop(sh);
|
||||
while (h) {
|
||||
pr = &prop[h - 1];
|
||||
if (likely(pr->atom == atom)) {
|
||||
/* Found it! */
|
||||
if (likely((pr->flags & JS_PROP_TMASK) == JS_PROP_NORMAL)) {
|
||||
val = JS_DupValue(ctx, p->prop[h - 1].u.value);
|
||||
JS_FreeValue(ctx, obj);
|
||||
sp[-1] = val;
|
||||
goto get_field_done;
|
||||
}
|
||||
break;
|
||||
}
|
||||
h = pr->hash_next;
|
||||
JSShape *sh = p->shape;
|
||||
|
||||
/* Simple thread-local IC cache using PC as key */
|
||||
static __thread struct {
|
||||
const uint8_t *pc;
|
||||
JSShape *shape;
|
||||
uint32_t prop_idx;
|
||||
JSAtom atom;
|
||||
} ic_cache[256];
|
||||
|
||||
uint32_t cache_idx = ((uintptr_t)ic_pc >> 3) & 255;
|
||||
struct { const uint8_t *pc; JSShape *shape; uint32_t prop_idx; JSAtom atom; } *slot = &ic_cache[cache_idx];
|
||||
|
||||
/* IC hit: shape guard passed */
|
||||
if (likely(slot->pc == ic_pc && slot->shape == sh && slot->atom == atom)) {
|
||||
JSProperty *pr = &p->prop[slot->prop_idx];
|
||||
JSShapeProperty *prs = &get_shape_prop(sh)[slot->prop_idx];
|
||||
|
||||
/* Double-check it's still a normal data property */
|
||||
if (likely((prs->flags & JS_PROP_TMASK) == JS_PROP_NORMAL)) {
|
||||
val = JS_DupValue(ctx, pr->u.value);
|
||||
JS_FreeValue(ctx, obj);
|
||||
sp[-1] = val;
|
||||
goto get_field_done;
|
||||
}
|
||||
}
|
||||
|
||||
/* IC miss: do lookup and populate cache if it's an own data property */
|
||||
{
|
||||
JSProperty *pr;
|
||||
JSShapeProperty *prs = find_own_property(&pr, p, atom);
|
||||
|
||||
if (prs && (prs->flags & JS_PROP_TMASK) == JS_PROP_NORMAL) {
|
||||
/* Cache this for next time */
|
||||
uint32_t prop_idx = prs - get_shape_prop(sh);
|
||||
slot->pc = ic_pc;
|
||||
slot->shape = sh;
|
||||
slot->prop_idx = prop_idx;
|
||||
slot->atom = atom;
|
||||
|
||||
val = JS_DupValue(ctx, pr->u.value);
|
||||
JS_FreeValue(ctx, obj);
|
||||
sp[-1] = val;
|
||||
goto get_field_done;
|
||||
}
|
||||
}
|
||||
}
|
||||
/* Slow path: use full JS_GetProperty */
|
||||
|
||||
/* Slow path: proto chain, getters, non-objects, etc. */
|
||||
val = JS_GetProperty(ctx, obj, atom);
|
||||
if (unlikely(JS_IsException(val)))
|
||||
goto exception;
|
||||
@@ -14045,6 +14050,9 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj,
|
||||
JSValue val;
|
||||
JSAtom atom;
|
||||
JSValue obj;
|
||||
const uint8_t *ic_pc;
|
||||
|
||||
ic_pc = pc - 1;
|
||||
atom = get_u32(pc);
|
||||
pc += 4;
|
||||
|
||||
@@ -14054,31 +14062,51 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj,
|
||||
profile_record_prop_site(rt, b, (uint32_t)(pc - b->byte_code_buf), atom);
|
||||
#endif
|
||||
obj = sp[-1];
|
||||
/* Fast path: try inline property lookup for regular objects */
|
||||
|
||||
/* Monomorphic IC fast path */
|
||||
if (likely(JS_VALUE_GET_TAG(obj) == JS_TAG_OBJECT)) {
|
||||
JSObject *p = JS_VALUE_GET_OBJ(obj);
|
||||
if (likely(p->class_id == JS_CLASS_OBJECT)) {
|
||||
JSShape *sh = p->shape;
|
||||
JSShapeProperty *pr, *prop;
|
||||
intptr_t h;
|
||||
/* Inline property lookup */
|
||||
h = (uintptr_t)atom & sh->prop_hash_mask;
|
||||
h = prop_hash_end(sh)[-h - 1];
|
||||
prop = get_shape_prop(sh);
|
||||
while (h) {
|
||||
pr = &prop[h - 1];
|
||||
if (likely(pr->atom == atom)) {
|
||||
if (likely((pr->flags & JS_PROP_TMASK) == JS_PROP_NORMAL)) {
|
||||
val = JS_DupValue(ctx, p->prop[h - 1].u.value);
|
||||
*sp++ = val;
|
||||
goto get_field2_done;
|
||||
}
|
||||
break;
|
||||
}
|
||||
h = pr->hash_next;
|
||||
JSShape *sh = p->shape;
|
||||
|
||||
static __thread struct {
|
||||
const uint8_t *pc;
|
||||
JSShape *shape;
|
||||
uint32_t prop_idx;
|
||||
JSAtom atom;
|
||||
} ic_cache2[256];
|
||||
|
||||
uint32_t cache_idx = ((uintptr_t)ic_pc >> 3) & 255;
|
||||
struct { const uint8_t *pc; JSShape *shape; uint32_t prop_idx; JSAtom atom; } *slot = &ic_cache2[cache_idx];
|
||||
|
||||
if (likely(slot->pc == ic_pc && slot->shape == sh && slot->atom == atom)) {
|
||||
JSProperty *pr = &p->prop[slot->prop_idx];
|
||||
JSShapeProperty *prs = &get_shape_prop(sh)[slot->prop_idx];
|
||||
|
||||
if (likely((prs->flags & JS_PROP_TMASK) == JS_PROP_NORMAL)) {
|
||||
val = JS_DupValue(ctx, pr->u.value);
|
||||
*sp++ = val;
|
||||
goto get_field2_done;
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
JSProperty *pr;
|
||||
JSShapeProperty *prs = find_own_property(&pr, p, atom);
|
||||
|
||||
if (prs && (prs->flags & JS_PROP_TMASK) == JS_PROP_NORMAL) {
|
||||
uint32_t prop_idx = prs - get_shape_prop(sh);
|
||||
slot->pc = ic_pc;
|
||||
slot->shape = sh;
|
||||
slot->prop_idx = prop_idx;
|
||||
slot->atom = atom;
|
||||
|
||||
val = JS_DupValue(ctx, pr->u.value);
|
||||
*sp++ = val;
|
||||
goto get_field2_done;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Slow path */
|
||||
val = JS_GetProperty(ctx, obj, atom);
|
||||
if (unlikely(JS_IsException(val)))
|
||||
|
||||
Reference in New Issue
Block a user