This commit is contained in:
2025-12-28 23:55:57 -06:00
parent 6d7581eff8
commit 3b53a9dcc3

View File

@@ -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)))