From 478f974b331d7da6b4d809495198865b6406ee49 Mon Sep 17 00:00:00 2001 From: Divy Srivastava Date: Thu, 23 Nov 2023 09:26:38 +0530 Subject: [PATCH 01/17] add poly IC --- quickjs-opcode.h | 4 + quickjs.c | 475 ++++++++++++++++++++++++++++++++++++++++++++--- quickjs.h | 19 +- 3 files changed, 472 insertions(+), 26 deletions(-) diff --git a/quickjs-opcode.h b/quickjs-opcode.h index 8063c5303..bec75d760 100644 --- a/quickjs-opcode.h +++ b/quickjs-opcode.h @@ -357,6 +357,10 @@ DEF( is_null, 1, 1, 1, none) DEF(typeof_is_undefined, 1, 1, 1, none) DEF( typeof_is_function, 1, 1, 1, none) +DEF( get_field_ic, 5, 1, 1, none) +DEF( get_field2_ic, 5, 1, 2, none) +DEF( put_field_ic, 5, 2, 0, none) + #undef DEF #undef def #endif /* DEF */ diff --git a/quickjs.c b/quickjs.c index c65363f65..26c5fb106 100644 --- a/quickjs.c +++ b/quickjs.c @@ -298,7 +298,7 @@ typedef struct JSStackFrame { JSValue *arg_buf; /* arguments */ JSValue *var_buf; /* variables */ struct list_head var_ref_list; /* list of JSVarRef.link */ - const uint8_t *cur_pc; /* only used in bytecode functions : PC of the + uint8_t *cur_pc; /* only used in bytecode functions : PC of the instruction after the call */ int arg_count; int js_mode; @@ -529,6 +529,7 @@ typedef struct JSVarDef { #define PC2LINE_RANGE 5 #define PC2LINE_OP_FIRST 1 #define PC2LINE_DIFF_PC_MAX ((255 - PC2LINE_OP_FIRST) / PC2LINE_RANGE) +#define IC_CACHE_ITEM_CAPACITY 8 typedef enum JSFunctionKindEnum { JS_FUNC_NORMAL = 0, @@ -537,6 +538,72 @@ typedef enum JSFunctionKindEnum { JS_FUNC_ASYNC_GENERATOR = (JS_FUNC_GENERATOR | JS_FUNC_ASYNC), } JSFunctionKindEnum; +typedef struct InlineCacheRingItem { + JSShape* shape; + uint32_t prop_offset; +} InlineCacheRingItem; + +typedef struct InlineCacheRingSlot { + JSAtom atom; + InlineCacheRingItem buffer[IC_CACHE_ITEM_CAPACITY]; + uint8_t index; +} InlineCacheRingSlot; + +typedef struct InlineCacheHashSlot { + JSAtom atom; + uint32_t index; + struct InlineCacheHashSlot *next; +} InlineCacheHashSlot; + +typedef struct InlineCache { + uint32_t count; + uint32_t capacity; + uint32_t hash_bits; + JSContext* ctx; + InlineCacheHashSlot **hash; + InlineCacheRingSlot *cache; + uint32_t updated_offset; + BOOL updated; +} InlineCache; + +InlineCache *init_ic(JSContext *ctx); +int rebuild_ic(InlineCache *ic); +int resize_ic_hash(InlineCache *ic); +int free_ic(InlineCache *ic); +uint32_t add_ic_slot(InlineCache *ic, JSAtom atom, JSObject *object, + uint32_t prop_offset); +uint32_t add_ic_slot1(InlineCache *ic, JSAtom atom); + +force_inline int32_t get_ic_prop_offset(InlineCache *ic, uint32_t cache_offset, + JSShape *shape) +{ + uint32_t i; + InlineCacheRingSlot *cr; + InlineCacheRingItem *buffer; + assert(cache_offset < ic->capacity); + cr = ic->cache + cache_offset; + i = cr->index; + for (;;) { + buffer = cr->buffer + i; + if (likely(buffer->shape == shape)) { + cr->index = i; + return buffer->prop_offset; + } + + i = (i + 1) % IC_CACHE_ITEM_CAPACITY; + if (unlikely(i == cr->index)) { + break; + } + } + + return -1; +} + +force_inline JSAtom get_ic_atom(InlineCache *ic, uint32_t cache_offset) { + assert(cache_offset < ic->capacity); + return ic->cache[cache_offset].atom; +} + typedef struct JSFunctionBytecode { JSGCObjectHeader header; /* must come first */ uint8_t js_mode; @@ -567,6 +634,7 @@ typedef struct JSFunctionBytecode { JSValue *cpool; /* constant pool (self pointer) */ int cpool_count; int closure_var_count; + InlineCache *ic; struct { /* debug info, move to separate structure to save memory? */ JSAtom filename; @@ -4994,6 +5062,28 @@ static force_inline JSShapeProperty *find_own_property(JSProperty **ppr, return NULL; } +static force_inline JSShapeProperty* find_own_property_ic(JSProperty** ppr, JSObject* p, JSAtom atom, uint32_t* offset) { + JSShape* sh; + JSShapeProperty *pr, *prop; + intptr_t h; + sh = p->shape; + 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)) { + *ppr = &p->prop[h - 1]; + *offset = h - 1; + /* the compiler should be able to assume that pr != NULL here */ + return pr; + } + h = pr->hash_next; + } + *ppr = NULL; + return NULL; +} + /* indicate that the object may be part of a function prototype cycle */ static void set_cycle_flag(JSContext *ctx, JSValueConst obj) { @@ -5389,13 +5479,22 @@ static void mark_children(JSRuntime *rt, JSGCObjectHeader *gp, case JS_GC_OBJ_TYPE_FUNCTION_BYTECODE: /* the template objects can be part of a cycle */ { + InlineCacheRingItem *buffer; JSFunctionBytecode *b = (JSFunctionBytecode *)gp; - int i; + int i, j; for(i = 0; i < b->cpool_count; i++) { JS_MarkValue(rt, b->cpool[i], mark_func); } if (b->realm) mark_func(rt, &b->realm->header); + if (b->ic) { + for (i = 0; i < b->ic->count; i++) { + buffer = b->ic->cache[i].buffer; + for (j = 0; j < IC_CACHE_ITEM_CAPACITY; j++) + if (buffer[j].shape) + mark_func(rt, &buffer[j].shape->header); + } + } } break; case JS_GC_OBJ_TYPE_VAR_REF: @@ -6807,13 +6906,14 @@ static int JS_AutoInitProperty(JSContext *ctx, JSObject *p, JSAtom prop, JSValue JS_GetPropertyInternal(JSContext *ctx, JSValueConst obj, JSAtom prop, JSValueConst this_obj, - BOOL throw_ref_error) + InlineCache* ic, BOOL throw_ref_error) { JSObject *p; JSProperty *pr; JSShapeProperty *prs; - uint32_t tag; + uint32_t tag, offset, proto_depth; + offset = proto_depth = 0; tag = JS_VALUE_GET_TAG(obj); if (unlikely(tag != JS_TAG_OBJECT)) { switch(tag) { @@ -6853,7 +6953,7 @@ JSValue JS_GetPropertyInternal(JSContext *ctx, JSValueConst obj, } for(;;) { - prs = find_own_property(&pr, p, prop); + prs = find_own_property_ic(&pr, p, prop, &offset); if (prs) { /* found */ if (unlikely(prs->flags & JS_PROP_TMASK)) { @@ -6878,6 +6978,10 @@ JSValue JS_GetPropertyInternal(JSContext *ctx, JSValueConst obj, continue; } } else { + if (ic && proto_depth == 0 && p->shape->is_hashed) { + ic->updated = TRUE; + ic->updated_offset = add_ic_slot(ic, prop, p, offset); + } return JS_DupValue(ctx, pr->u.value); } } @@ -6940,6 +7044,7 @@ JSValue JS_GetPropertyInternal(JSContext *ctx, JSValueConst obj, } } } + proto_depth++; p = p->shape->proto; if (!p) break; @@ -6951,6 +7056,24 @@ JSValue JS_GetPropertyInternal(JSContext *ctx, JSValueConst obj, } } +force_inline JSValue JS_GetPropertyInternalWithIC(JSContext *ctx, JSValueConst obj, + JSAtom prop, JSValueConst this_obj, + InlineCache *ic, int32_t offset, + BOOL throw_ref_error) +{ + uint32_t tag; + JSObject *p; + tag = JS_VALUE_GET_TAG(obj); + if (unlikely(tag != JS_TAG_OBJECT)) + goto slow_path; + p = JS_VALUE_GET_OBJ(obj); + offset = get_ic_prop_offset(ic, offset, p->shape); + if (likely(offset >= 0)) + return JS_DupValue(ctx, p->prop[offset].u.value); + slow_path: + return JS_GetPropertyInternal(ctx, obj, prop, this_obj, ic, throw_ref_error); +} + static JSValue JS_ThrowTypeErrorPrivateNotFound(JSContext *ctx, JSAtom atom) { return JS_ThrowTypeErrorAtom(ctx, "private class field '%s' does not exist", @@ -8161,7 +8284,8 @@ static int JS_SetPropertyGeneric(JSContext *ctx, JS_PROP_THROW or JS_PROP_THROW_STRICT. If JS_PROP_NO_ADD is set, the new property is not added and an error is raised. */ int JS_SetPropertyInternal(JSContext *ctx, JSValueConst this_obj, - JSAtom prop, JSValue val, int flags) + JSAtom prop, JSValue val, int flags, + InlineCache *ic) { JSObject *p, *p1; JSShapeProperty *prs; @@ -8169,6 +8293,7 @@ int JS_SetPropertyInternal(JSContext *ctx, JSValueConst this_obj, uint32_t tag; JSPropertyDescriptor desc; int ret; + uint32_t offset = 0; tag = JS_VALUE_GET_TAG(this_obj); if (unlikely(tag != JS_TAG_OBJECT)) { switch(tag) { @@ -8189,11 +8314,15 @@ int JS_SetPropertyInternal(JSContext *ctx, JSValueConst this_obj, } p = JS_VALUE_GET_OBJ(this_obj); retry: - prs = find_own_property(&pr, p, prop); + prs = find_own_property_ic(&pr, p, prop, &offset); if (prs) { if (likely((prs->flags & (JS_PROP_TMASK | JS_PROP_WRITABLE | JS_PROP_LENGTH)) == JS_PROP_WRITABLE)) { /* fast case */ + if (ic && p->shape->is_hashed) { + ic->updated = TRUE; + ic->updated_offset = add_ic_slot(ic, prop, p, offset); + } set_value(ctx, &pr->u.value, val); return TRUE; } else if (prs->flags & JS_PROP_LENGTH) { @@ -8378,6 +8507,22 @@ int JS_SetPropertyInternal(JSContext *ctx, JSValueConst this_obj, return TRUE; } +force_inline int JS_SetPropertyInternalWithIC(JSContext* ctx, JSValueConst this_obj, JSAtom prop, JSValue val, int flags, InlineCache *ic, int32_t offset) { + uint32_t tag; + JSObject *p; + tag = JS_VALUE_GET_TAG(this_obj); + if (unlikely(tag != JS_TAG_OBJECT)) + goto slow_path; + p = JS_VALUE_GET_OBJ(this_obj); + offset = get_ic_prop_offset(ic, offset, p->shape); + if (likely(offset >= 0)) { + set_value(ctx, &p->prop[offset].u.value, val); + return TRUE; + } + slow_path: + return JS_SetPropertyInternal(ctx, this_obj, prop, val, flags, ic); +} + /* flags can be JS_PROP_THROW or JS_PROP_THROW_STRICT */ static int JS_SetPropertyValue(JSContext *ctx, JSValueConst this_obj, JSValue prop, JSValue val, int flags) @@ -8502,7 +8647,7 @@ static int JS_SetPropertyValue(JSContext *ctx, JSValueConst this_obj, JS_FreeValue(ctx, val); return -1; } - ret = JS_SetPropertyInternal(ctx, this_obj, atom, val, flags); + ret = JS_SetPropertyInternal(ctx, this_obj, atom, val, flags, NULL); JS_FreeAtom(ctx, atom); return ret; } @@ -8542,7 +8687,7 @@ int JS_SetPropertyStr(JSContext *ctx, JSValueConst this_obj, JSAtom atom; int ret; atom = JS_NewAtom(ctx, prop); - ret = JS_SetPropertyInternal(ctx, this_obj, atom, val, JS_PROP_THROW); + ret = JS_SetPropertyInternal(ctx, this_obj, atom, val, JS_PROP_THROW, NULL); JS_FreeAtom(ctx, atom); return ret; } @@ -9299,7 +9444,7 @@ static JSValue JS_GetGlobalVar(JSContext *ctx, JSAtom prop, return JS_DupValue(ctx, pr->u.value); } return JS_GetPropertyInternal(ctx, ctx->global_obj, prop, - ctx->global_obj, throw_ref_error); + ctx->global_obj, NULL, throw_ref_error); } /* construct a reference to a global variable */ @@ -9393,7 +9538,7 @@ static int JS_SetGlobalVar(JSContext *ctx, JSAtom prop, JSValue val, flags = JS_PROP_THROW_STRICT; if (is_strict_mode(ctx)) flags |= JS_PROP_NO_ADD; - return JS_SetPropertyInternal(ctx, ctx->global_obj, prop, val, flags); + return JS_SetPropertyInternal(ctx, ctx->global_obj, prop, val, flags, NULL); } /* return -1, FALSE or TRUE. return FALSE if not configurable or @@ -13099,7 +13244,7 @@ static JSValue build_for_in_iterator(JSContext *ctx, JSValue obj) JS_GPN_STRING_MASK | JS_GPN_ENUM_ONLY)) goto fail; for(i = 0; i < tab_atom_count; i++) { - JS_SetPropertyInternal(ctx, enum_obj, tab_atom[i].atom, JS_NULL, 0); + JS_SetPropertyInternal(ctx, enum_obj, tab_atom[i].atom, JS_NULL, 0, NULL); } js_free_prop_enum(ctx, tab_atom, tab_atom_count); } @@ -14148,11 +14293,12 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj, JSObject *p; JSFunctionBytecode *b; JSStackFrame sf_s, *sf = &sf_s; - const uint8_t *pc; + uint8_t *pc; int opcode, arg_allocated_size, i; JSValue *local_buf, *stack_buf, *var_buf, *arg_buf, *sp, ret_val, *pval; JSVarRef **var_refs; size_t alloca_size; + InlineCache *ic; #if !DIRECT_DISPATCH #define SWITCH(pc) switch (opcode = *pc++) @@ -14192,6 +14338,7 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj, pc = sf->cur_pc; sf->prev_frame = rt->current_stack_frame; rt->current_stack_frame = sf; + ic = b->ic; if (s->throw_flag) goto exception; else @@ -14254,6 +14401,7 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj, sf->prev_frame = rt->current_stack_frame; rt->current_stack_frame = sf; ctx = b->realm; /* set the current realm */ + ic = b->ic; restart: for(;;) { @@ -15477,23 +15625,65 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj, JSAtom atom; atom = get_u32(pc); pc += 4; - - val = JS_GetProperty(ctx, sp[-1], atom); + val = JS_GetPropertyInternal(ctx, sp[-1], atom, sp[-1], ic, FALSE); if (unlikely(JS_IsException(val))) goto exception; + if (ic && ic->updated == TRUE) { + ic->updated = FALSE; + put_u8(pc - 5, OP_get_field_ic); + put_u32(pc - 4, ic->updated_offset); + JS_FreeAtom(ic->ctx, atom); + } JS_FreeValue(ctx, sp[-1]); sp[-1] = val; } BREAK; + CASE(OP_get_field_ic): + { + JSValue val; + JSAtom atom; + int32_t ic_offset; + ic_offset = get_u32(pc); + atom = get_ic_atom(ic, ic_offset); + pc += 4; + val = JS_GetPropertyInternalWithIC(ctx, sp[-1], atom, sp[-1], ic, ic_offset, FALSE); + ic->updated = FALSE; + if (unlikely(JS_IsException(val))) + goto exception; + JS_FreeValue(ctx, sp[-1]); + sp[-1] = val; + } + BREAK; CASE(OP_get_field2): { JSValue val; JSAtom atom; atom = get_u32(pc); pc += 4; + val = JS_GetPropertyInternal(ctx, sp[-1], atom, sp[-1], NULL, FALSE); + if (unlikely(JS_IsException(val))) + goto exception; + if (ic != NULL && ic->updated == TRUE) { + ic->updated = FALSE; + put_u8(pc - 5, OP_get_field2_ic); + put_u32(pc - 4, ic->updated_offset); + JS_FreeAtom(ic->ctx, atom); + } + *sp++ = val; + } + BREAK; - val = JS_GetProperty(ctx, sp[-1], atom); + CASE(OP_get_field2_ic): + { + JSValue val; + JSAtom atom; + int32_t ic_offset; + ic_offset = get_u32(pc); + atom = get_ic_atom(ic, ic_offset); + pc += 4; + val = JS_GetPropertyInternalWithIC(ctx, sp[-1], atom, sp[-1], ic, ic_offset, FALSE); + ic->updated = FALSE; if (unlikely(JS_IsException(val))) goto exception; *sp++ = val; @@ -15506,9 +15696,30 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj, JSAtom atom; atom = get_u32(pc); pc += 4; + ret = JS_SetPropertyInternal(ctx, sp[-2], atom, sp[-1], JS_PROP_THROW_STRICT, ic); + JS_FreeValue(ctx, sp[-2]); + sp -= 2; + if (unlikely(ret < 0)) + goto exception; + if (ic != NULL && ic->updated == TRUE) { + ic->updated = FALSE; + put_u8(pc - 5, OP_put_field_ic); + put_u32(pc - 4, ic->updated_offset); + JS_FreeAtom(ic->ctx, atom); + } + } + BREAK; - ret = JS_SetPropertyInternal(ctx, sp[-2], atom, sp[-1], - JS_PROP_THROW_STRICT); + CASE(OP_put_field_ic): + { + int ret; + JSAtom atom; + int32_t ic_offset; + ic_offset = get_u32(pc); + atom = get_ic_atom(ic, ic_offset); + pc += 4; + ret = JS_SetPropertyInternalWithIC(ctx, sp[-2], atom, sp[-1], JS_PROP_THROW_STRICT, ic, ic_offset); + ic->updated = FALSE; JS_FreeValue(ctx, sp[-2]); sp -= 2; if (unlikely(ret < 0)) @@ -15744,7 +15955,7 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj, atom = JS_ValueToAtom(ctx, sp[-1]); if (unlikely(atom == JS_ATOM_NULL)) goto exception; - val = JS_GetPropertyInternal(ctx, sp[-2], atom, sp[-3], FALSE); + val = JS_GetPropertyInternal(ctx, sp[-2], atom, sp[-3], NULL, FALSE); JS_FreeAtom(ctx, atom); if (unlikely(JS_IsException(val))) goto exception; @@ -16425,7 +16636,7 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj, case OP_with_put_var: /* XXX: check if strict mode */ ret = JS_SetPropertyInternal(ctx, obj, atom, sp[-2], - JS_PROP_THROW_STRICT); + JS_PROP_THROW_STRICT, NULL); JS_FreeValue(ctx, sp[-1]); sp -= 2; if (unlikely(ret < 0)) @@ -17935,6 +18146,7 @@ typedef struct JSFunctionDef { int source_len; JSModuleDef *module; /* != NULL when parsing a module */ + InlineCache *ic; /* inline cache for field op */ } JSFunctionDef; typedef struct JSToken { @@ -19326,6 +19538,10 @@ static void emit_atom(JSParseState *s, JSAtom name) emit_u32(s, JS_DupAtom(s->ctx, name)); } +static void emit_ic(JSParseState *s, JSAtom atom) { + add_ic_slot1(s->cur_func->ic, atom); +} + static int update_label(JSFunctionDef *s, int label, int delta) { LabelSlot *ls; @@ -19989,6 +20205,7 @@ static __exception int js_parse_template(JSParseState *s, int call, int *argc) goto done1; emit_op(s, OP_get_field2); emit_atom(s, JS_ATOM_concat); + emit_ic(s, JS_ATOM_concat); } depth++; } else { @@ -21169,6 +21386,7 @@ static __exception int js_parse_array_literal(JSParseState *s) emit_u32(s, idx); emit_op(s, OP_put_field); emit_atom(s, JS_ATOM_length); + emit_ic(s, JS_ATOM_length); } goto done; } @@ -21233,6 +21451,7 @@ static __exception int js_parse_array_literal(JSParseState *s) emit_op(s, OP_dup1); /* array length - array array length */ emit_op(s, OP_put_field); emit_atom(s, JS_ATOM_length); + emit_ic(s, JS_ATOM_length); } else { emit_op(s, OP_drop); /* array length - array */ } @@ -21333,6 +21552,7 @@ static __exception int get_lvalue(JSParseState *s, int *popcode, int *pscope, case OP_get_field: emit_op(s, OP_get_field2); emit_atom(s, name); + emit_ic(s, name); break; case OP_scope_get_private_field: emit_op(s, OP_scope_get_private_field2); @@ -21480,6 +21700,7 @@ static void put_lvalue(JSParseState *s, int opcode, int scope, case OP_get_field: emit_op(s, OP_put_field); emit_u32(s, name); /* name has refcount */ + emit_ic(s, name); break; case OP_scope_get_private_field: emit_op(s, OP_scope_put_private_field); @@ -21741,6 +21962,7 @@ static int js_parse_destructuring_element(JSParseState *s, int tok, int is_arg, /* get the named property from the source object */ emit_op(s, OP_get_field2); emit_u32(s, prop_name); + emit_ic(s, prop_name); } if (js_parse_destructuring_element(s, tok, is_arg, TRUE, -1, TRUE) < 0) return -1; @@ -21830,6 +22052,7 @@ static int js_parse_destructuring_element(JSParseState *s, int tok, int is_arg, /* source -- val */ emit_op(s, OP_get_field); emit_u32(s, prop_name); + emit_ic(s, prop_name); } } else { /* prop_type = PROP_TYPE_VAR, cannot be a computed property */ @@ -21861,6 +22084,7 @@ static int js_parse_destructuring_element(JSParseState *s, int tok, int is_arg, /* source -- source val */ emit_op(s, OP_get_field2); emit_u32(s, prop_name); + emit_ic(s, prop_name); } set_val: if (tok) { @@ -22644,6 +22868,7 @@ static __exception int js_parse_postfix_expr(JSParseState *s, int parse_flags) } emit_op(s, OP_get_field); emit_atom(s, s->token.u.ident.atom); + emit_ic(s, s->token.u.ident.atom); } } if (next_token(s)) @@ -23165,12 +23390,14 @@ static __exception int js_parse_assign_expr2(JSParseState *s, int parse_flags) emit_op(s, OP_iterator_check_object); emit_op(s, OP_get_field2); emit_atom(s, JS_ATOM_done); + emit_ic(s, JS_ATOM_done); label_next = emit_goto(s, OP_if_true, -1); /* end of loop */ emit_label(s, label_yield); if (is_async) { /* OP_async_yield_star takes the value as parameter */ emit_op(s, OP_get_field); emit_atom(s, JS_ATOM_value); + emit_ic(s, JS_ATOM_value); emit_op(s, OP_await); emit_op(s, OP_async_yield_star); } else { @@ -23199,10 +23426,12 @@ static __exception int js_parse_assign_expr2(JSParseState *s, int parse_flags) emit_op(s, OP_iterator_check_object); emit_op(s, OP_get_field2); emit_atom(s, JS_ATOM_done); + emit_ic(s, JS_ATOM_done); emit_goto(s, OP_if_false, label_yield); emit_op(s, OP_get_field); emit_atom(s, JS_ATOM_value); + emit_ic(s, JS_ATOM_value); emit_label(s, label_return1); emit_op(s, OP_nip); @@ -23220,6 +23449,7 @@ static __exception int js_parse_assign_expr2(JSParseState *s, int parse_flags) emit_op(s, OP_iterator_check_object); emit_op(s, OP_get_field2); emit_atom(s, JS_ATOM_done); + emit_ic(s, JS_ATOM_done); emit_goto(s, OP_if_false, label_yield); emit_goto(s, OP_goto, label_next); /* close the iterator and throw a type error exception */ @@ -23238,6 +23468,7 @@ static __exception int js_parse_assign_expr2(JSParseState *s, int parse_flags) emit_label(s, label_next); emit_op(s, OP_get_field); emit_atom(s, JS_ATOM_value); + emit_ic(s, JS_ATOM_value); emit_op(s, OP_nip); /* keep the value associated with done = true */ emit_op(s, OP_nip); @@ -23474,6 +23705,7 @@ static void emit_return(JSParseState *s, BOOL hasval) emit_op(s, OP_drop); /* next */ emit_op(s, OP_get_field2); emit_atom(s, JS_ATOM_return); + emit_ic(s, JS_ATOM_return); /* stack: iter_obj return_func */ emit_op(s, OP_dup); emit_op(s, OP_is_undefined_or_null); @@ -26522,6 +26754,7 @@ static JSFunctionDef *js_new_function_def(JSContext *ctx, //fd->pc2line_last_pc = 0; fd->last_opcode_line_num = line_num; + fd->ic = init_ic(ctx); return fd; } @@ -30306,6 +30539,12 @@ static JSValue js_create_function(JSContext *ctx, JSFunctionDef *fd) b->arguments_allowed = fd->arguments_allowed; b->backtrace_barrier = fd->backtrace_barrier; b->realm = JS_DupContext(ctx); + b->ic = fd->ic; + rebuild_ic(b->ic); + if (b->ic->count == 0) { + free_ic(b->ic); + b->ic = NULL; + } add_gc_object(ctx->rt, &b->header, JS_GC_OBJ_TYPE_FUNCTION_BYTECODE); @@ -30331,6 +30570,9 @@ static void free_function_bytecode(JSRuntime *rt, JSFunctionBytecode *b) free_bytecode_atoms(rt, b->byte_code_buf, b->byte_code_len, TRUE); + if (b->ic != NULL) + free_ic(b->ic); + if (b->vardefs) { for(i = 0; i < b->arg_count + b->var_count; i++) { JS_FreeAtomRT(rt, b->vardefs[i].var_name); @@ -31926,6 +32168,18 @@ static int JS_WriteFunctionTag(BCWriterState *s, JSValueConst obj) bc_put_leb128(s, b->debug.line_num); bc_put_leb128(s, b->debug.pc2line_len); dbuf_put(&s->dbuf, b->debug.pc2line_buf, b->debug.pc2line_len); + + dbuf_putc(&s->dbuf, 255); + dbuf_putc(&s->dbuf, 73); // 'I' + dbuf_putc(&s->dbuf, 67); // 'C' + if (b->ic == NULL) { + bc_put_leb128(s, 0); + } else { + bc_put_leb128(s, b->ic->count); + for (i = 0; i < b->ic->count; i++) { + bc_put_atom(s, b->ic->cache[i].atom); + } + } } for(i = 0; i < b->cpool_count; i++) { @@ -32742,6 +32996,8 @@ static JSValue JS_ReadFunctionTag(BCReaderState *s) int idx, i, local_count; int function_size, cpool_offset, byte_code_offset; int closure_var_offset, vardefs_offset; + uint32_t ic_len; + JSAtom atom; memset(&bc, 0, sizeof(bc)); bc.header.ref_count = 1; @@ -32899,6 +33155,23 @@ static JSValue JS_ReadFunctionTag(BCReaderState *s) if (bc_get_buf(s, b->debug.pc2line_buf, b->debug.pc2line_len)) goto fail; } + if(s->buf_end - s->ptr > 3 && s->ptr[0] == 255 && s->ptr[1] == 73 && s->ptr[2] == 67) { + s->ptr += 3; + bc_get_leb128(s, &ic_len); + if (ic_len == 0) { + b->ic = NULL; + } else { + b->ic = init_ic(ctx); + if (b->ic == NULL) + goto fail; + for (i = 0; i < ic_len; i++) { + bc_get_atom(s, &atom); + add_ic_slot1(b->ic, atom); + JS_FreeAtom(ctx, atom); + } + rebuild_ic(b->ic); + } + } #ifdef DUMP_READ_OBJECT bc_read_trace(s, "filename: "); print_atom(s->ctx, b->debug.filename); printf("\n"); #endif @@ -42127,7 +42400,7 @@ static JSValue js_reflect_get(JSContext *ctx, JSValueConst this_val, atom = JS_ValueToAtom(ctx, prop); if (unlikely(atom == JS_ATOM_NULL)) return JS_EXCEPTION; - ret = JS_GetPropertyInternal(ctx, obj, atom, receiver, FALSE); + ret = JS_GetPropertyInternal(ctx, obj, atom, receiver, NULL, FALSE); JS_FreeAtom(ctx, atom); return ret; } @@ -42475,7 +42748,7 @@ static JSValue js_proxy_get(JSContext *ctx, JSValueConst obj, JSAtom atom, return JS_EXCEPTION; /* Note: recursion is possible thru the prototype of s->target */ if (JS_IsUndefined(method)) - return JS_GetPropertyInternal(ctx, s->target, atom, receiver, FALSE); + return JS_GetPropertyInternal(ctx, s->target, atom, receiver, NULL, FALSE); atom_val = JS_AtomToValue(ctx, atom); if (JS_IsException(atom_val)) { JS_FreeValue(ctx, method); @@ -50132,3 +50405,161 @@ void JS_AddPerformance(JSContext *ctx) JS_PROP_ENUMERABLE); JS_FreeValue(ctx, performance); } + +/* Poly IC */ + +static force_inline uint32_t get_index_hash(JSAtom atom, int hash_bits) { + return (atom * 0x9e370001) >> (32 - hash_bits); +} + +InlineCache *init_ic(JSContext *ctx) { + InlineCache *ic; + ic = js_malloc(ctx, sizeof(InlineCache)); + if (unlikely(!ic)) + goto fail; + ic->count = 0; + ic->hash_bits = 2; + ic->capacity = 1 << ic->hash_bits; + ic->ctx = ctx; + ic->hash = js_malloc(ctx, sizeof(ic->hash[0]) * ic->capacity); + if (unlikely(!ic->hash)) + goto fail; + memset(ic->hash, 0, sizeof(ic->hash[0]) * ic->capacity); + ic->cache = NULL; + ic->updated = FALSE; + ic->updated_offset = 0; + return ic; +fail: + return NULL; +} + +int rebuild_ic(InlineCache *ic) { + uint32_t i, count; + InlineCacheHashSlot *ch; + if (ic->count == 0) + goto end; + count = 0; + ic->cache = js_malloc(ic->ctx, sizeof(InlineCacheRingSlot) * ic->count); + if (unlikely(!ic->cache)) + goto fail; + memset(ic->cache, 0, sizeof(InlineCacheRingSlot) * ic->count); + for (i = 0; i < ic->capacity; i++) { + for (ch = ic->hash[i]; ch != NULL; ch = ch->next) { + ch->index = count++; + ic->cache[ch->index].atom = JS_DupAtom(ic->ctx, ch->atom); + ic->cache[ch->index].index = 0; + } + } +end: + return 0; +fail: + return -1; +} + +int resize_ic_hash(InlineCache *ic) { + uint32_t new_capacity, i, h; + InlineCacheHashSlot *ch, *ch_next; + InlineCacheHashSlot **new_hash; + ic->hash_bits += 1; + new_capacity = 1 << ic->hash_bits; + new_hash = js_malloc(ic->ctx, sizeof(ic->hash[0]) * new_capacity); + if (unlikely(!new_hash)) + goto fail; + memset(new_hash, 0, sizeof(ic->hash[0]) * new_capacity); + for (i = 0; i < ic->capacity; i++) { + for (ch = ic->hash[i]; ch != NULL; ch = ch_next) { + h = get_index_hash(ch->atom, ic->hash_bits); + ch_next = ch->next; + ch->next = new_hash[h]; + new_hash[h] = ch; + } + } + js_free(ic->ctx, ic->hash); + ic->hash = new_hash; + ic->capacity = new_capacity; + return 0; +fail: + return -1; +} + +int free_ic(InlineCache *ic) { + uint32_t i, j; + InlineCacheHashSlot *ch, *ch_next; + InlineCacheRingItem *buffer; + for (i = 0; i < ic->count; i++) { + buffer = ic->cache[i].buffer; + JS_FreeAtom(ic->ctx, ic->cache[i].atom); + for (j = 0; j < IC_CACHE_ITEM_CAPACITY; j++) { + js_free_shape_null(ic->ctx->rt, buffer[j].shape); + } + } + for (i = 0; i < ic->capacity; i++) { + for (ch = ic->hash[i]; ch != NULL; ch = ch_next) { + ch_next = ch->next; + JS_FreeAtom(ic->ctx, ch->atom); + js_free(ic->ctx, ch); + } + } + if (ic->count > 0) + js_free(ic->ctx, ic->cache); + js_free(ic->ctx, ic->hash); + js_free(ic->ctx, ic); + return 0; +} + +uint32_t add_ic_slot(InlineCache *ic, JSAtom atom, JSObject *object, + uint32_t prop_offset) { + int32_t i; + uint32_t h; + InlineCacheHashSlot *ch; + InlineCacheRingSlot *cr; + JSShape *sh; + cr = NULL; + h = get_index_hash(atom, ic->hash_bits); + for (ch = ic->hash[h]; ch != NULL; ch = ch->next) + if (ch->atom == atom) { + cr = ic->cache + ch->index; + break; + } + + assert(cr != NULL); + i = cr->index; + for (;;) { + if (object->shape == cr->buffer[i].shape) { + cr->buffer[i].prop_offset = prop_offset; + goto end; + } + + i = (i + 1) % IC_CACHE_ITEM_CAPACITY; + if (unlikely(i == cr->index)) + break; + } + + sh = cr->buffer[i].shape; + cr->buffer[i].shape = js_dup_shape(object->shape); + js_free_shape_null(ic->ctx->rt, sh); + cr->buffer[i].prop_offset = prop_offset; +end: + return ch->index; +} + +uint32_t add_ic_slot1(InlineCache *ic, JSAtom atom) { + uint32_t h; + InlineCacheHashSlot *ch; + if (ic->count + 1 >= ic->capacity && resize_ic_hash(ic)) + goto end; + h = get_index_hash(atom, ic->hash_bits); + for (ch = ic->hash[h]; ch != NULL; ch = ch->next) + if (ch->atom == atom) + goto end; + ch = js_malloc(ic->ctx, sizeof(InlineCacheHashSlot)); + if (unlikely(!ch)) + goto end; + ch->atom = JS_DupAtom(ic->ctx, atom); + ch->index = 0; + ch->next = ic->hash[h]; + ic->hash[h] = ch; + ic->count += 1; +end: + return 0; +} diff --git a/quickjs.h b/quickjs.h index a3bf90d3f..5ccd06cbf 100644 --- a/quickjs.h +++ b/quickjs.h @@ -676,13 +676,20 @@ JS_BOOL JS_SetConstructorBit(JSContext *ctx, JSValueConst func_obj, JS_BOOL val) JSValue JS_NewArray(JSContext *ctx); int JS_IsArray(JSContext *ctx, JSValueConst val); +typedef struct InlineCache InlineCache; + JSValue JS_GetPropertyInternal(JSContext *ctx, JSValueConst obj, JSAtom prop, JSValueConst receiver, - JS_BOOL throw_ref_error); + InlineCache *ic, JS_BOOL throw_ref_error); +JSValue JS_GetPropertyInternalWithIC(JSContext *ctx, JSValueConst obj, + JSAtom prop, JSValueConst receiver, + InlineCache *ic, int32_t offset, + JS_BOOL throw_ref_error); + static js_force_inline JSValue JS_GetProperty(JSContext *ctx, JSValueConst this_obj, JSAtom prop) { - return JS_GetPropertyInternal(ctx, this_obj, prop, this_obj, 0); + return JS_GetPropertyInternal(ctx, this_obj, prop, this_obj, NULL, 0); } JSValue JS_GetPropertyStr(JSContext *ctx, JSValueConst this_obj, const char *prop); @@ -691,11 +698,15 @@ JSValue JS_GetPropertyUint32(JSContext *ctx, JSValueConst this_obj, int JS_SetPropertyInternal(JSContext *ctx, JSValueConst this_obj, JSAtom prop, JSValue val, - int flags); + int flags, InlineCache *ic); +int JS_SetPropertyInternalWithIC(JSContext *ctx, JSValueConst this_obj, + JSAtom prop, JSValue val, + int flags, InlineCache *ic, + int32_t offset); static inline int JS_SetProperty(JSContext *ctx, JSValueConst this_obj, JSAtom prop, JSValue val) { - return JS_SetPropertyInternal(ctx, this_obj, prop, val, JS_PROP_THROW); + return JS_SetPropertyInternal(ctx, this_obj, prop, val, JS_PROP_THROW, NULL); } int JS_SetPropertyUint32(JSContext *ctx, JSValueConst this_obj, uint32_t idx, JSValue val); From a09930453273b5f873f026cc31111c42a3d61f20 Mon Sep 17 00:00:00 2001 From: Divy Srivastava Date: Thu, 23 Nov 2023 10:08:14 +0530 Subject: [PATCH 02/17] Formatting --- quickjs.c | 294 ++++++++++++++++++++++++++++-------------------------- 1 file changed, 153 insertions(+), 141 deletions(-) diff --git a/quickjs.c b/quickjs.c index 26c5fb106..9536c5872 100644 --- a/quickjs.c +++ b/quickjs.c @@ -599,7 +599,8 @@ force_inline int32_t get_ic_prop_offset(InlineCache *ic, uint32_t cache_offset, return -1; } -force_inline JSAtom get_ic_atom(InlineCache *ic, uint32_t cache_offset) { +force_inline JSAtom get_ic_atom(InlineCache *ic, uint32_t cache_offset) +{ assert(cache_offset < ic->capacity); return ic->cache[cache_offset].atom; } @@ -5062,7 +5063,9 @@ static force_inline JSShapeProperty *find_own_property(JSProperty **ppr, return NULL; } -static force_inline JSShapeProperty* find_own_property_ic(JSProperty** ppr, JSObject* p, JSAtom atom, uint32_t* offset) { +static force_inline JSShapeProperty* find_own_property_ic(JSProperty** ppr, JSObject* p, + JSAtom atom, uint32_t* offset) +{ JSShape* sh; JSShapeProperty *pr, *prop; intptr_t h; @@ -7057,9 +7060,9 @@ JSValue JS_GetPropertyInternal(JSContext *ctx, JSValueConst obj, } force_inline JSValue JS_GetPropertyInternalWithIC(JSContext *ctx, JSValueConst obj, - JSAtom prop, JSValueConst this_obj, - InlineCache *ic, int32_t offset, - BOOL throw_ref_error) + JSAtom prop, JSValueConst this_obj, + InlineCache *ic, int32_t offset, + BOOL throw_ref_error) { uint32_t tag; JSObject *p; @@ -8507,7 +8510,9 @@ int JS_SetPropertyInternal(JSContext *ctx, JSValueConst this_obj, return TRUE; } -force_inline int JS_SetPropertyInternalWithIC(JSContext* ctx, JSValueConst this_obj, JSAtom prop, JSValue val, int flags, InlineCache *ic, int32_t offset) { +force_inline int JS_SetPropertyInternalWithIC(JSContext *ctx, JSValueConst this_obj, + JSAtom prop, JSValue val, int flags, + InlineCache *ic, int32_t offset) { uint32_t tag; JSObject *p; tag = JS_VALUE_GET_TAG(this_obj); @@ -32169,10 +32174,11 @@ static int JS_WriteFunctionTag(BCWriterState *s, JSValueConst obj) bc_put_leb128(s, b->debug.pc2line_len); dbuf_put(&s->dbuf, b->debug.pc2line_buf, b->debug.pc2line_len); + /* compatibility */ dbuf_putc(&s->dbuf, 255); dbuf_putc(&s->dbuf, 73); // 'I' dbuf_putc(&s->dbuf, 67); // 'C' - if (b->ic == NULL) { + if (b->ic == NULL) { bc_put_leb128(s, 0); } else { bc_put_leb128(s, b->ic->count); @@ -33155,7 +33161,8 @@ static JSValue JS_ReadFunctionTag(BCReaderState *s) if (bc_get_buf(s, b->debug.pc2line_buf, b->debug.pc2line_len)) goto fail; } - if(s->buf_end - s->ptr > 3 && s->ptr[0] == 255 && s->ptr[1] == 73 && s->ptr[2] == 67) { + if (s->buf_end - s->ptr > 3 && s->ptr[0] == 255 && + s->ptr[1] == 73 && s->ptr[2] == 67) { s->ptr += 3; bc_get_leb128(s, &ic_len); if (ic_len == 0) { @@ -50408,158 +50415,163 @@ void JS_AddPerformance(JSContext *ctx) /* Poly IC */ -static force_inline uint32_t get_index_hash(JSAtom atom, int hash_bits) { - return (atom * 0x9e370001) >> (32 - hash_bits); +static force_inline uint32_t get_index_hash(JSAtom atom, int hash_bits) +{ + return (atom * 0x9e370001) >> (32 - hash_bits); } -InlineCache *init_ic(JSContext *ctx) { - InlineCache *ic; - ic = js_malloc(ctx, sizeof(InlineCache)); - if (unlikely(!ic)) - goto fail; - ic->count = 0; - ic->hash_bits = 2; - ic->capacity = 1 << ic->hash_bits; - ic->ctx = ctx; - ic->hash = js_malloc(ctx, sizeof(ic->hash[0]) * ic->capacity); - if (unlikely(!ic->hash)) - goto fail; - memset(ic->hash, 0, sizeof(ic->hash[0]) * ic->capacity); - ic->cache = NULL; - ic->updated = FALSE; - ic->updated_offset = 0; - return ic; +InlineCache *init_ic(JSContext *ctx) +{ + InlineCache *ic; + ic = js_malloc(ctx, sizeof(InlineCache)); + if (unlikely(!ic)) + goto fail; + ic->count = 0; + ic->hash_bits = 2; + ic->capacity = 1 << ic->hash_bits; + ic->ctx = ctx; + ic->hash = js_malloc(ctx, sizeof(ic->hash[0]) * ic->capacity); + if (unlikely(!ic->hash)) + goto fail; + memset(ic->hash, 0, sizeof(ic->hash[0]) * ic->capacity); + ic->cache = NULL; + ic->updated = FALSE; + ic->updated_offset = 0; + return ic; fail: - return NULL; + return NULL; } -int rebuild_ic(InlineCache *ic) { - uint32_t i, count; - InlineCacheHashSlot *ch; - if (ic->count == 0) - goto end; - count = 0; - ic->cache = js_malloc(ic->ctx, sizeof(InlineCacheRingSlot) * ic->count); - if (unlikely(!ic->cache)) - goto fail; - memset(ic->cache, 0, sizeof(InlineCacheRingSlot) * ic->count); - for (i = 0; i < ic->capacity; i++) { - for (ch = ic->hash[i]; ch != NULL; ch = ch->next) { - ch->index = count++; - ic->cache[ch->index].atom = JS_DupAtom(ic->ctx, ch->atom); - ic->cache[ch->index].index = 0; +int rebuild_ic(InlineCache *ic) +{ + uint32_t i, count; + InlineCacheHashSlot *ch; + if (ic->count == 0) + goto end; + count = 0; + ic->cache = js_malloc(ic->ctx, sizeof(InlineCacheRingSlot) * ic->count); + if (unlikely(!ic->cache)) + goto fail; + memset(ic->cache, 0, sizeof(InlineCacheRingSlot) * ic->count); + for (i = 0; i < ic->capacity; i++) { + for (ch = ic->hash[i]; ch != NULL; ch = ch->next) { + ch->index = count++; + ic->cache[ch->index].atom = JS_DupAtom(ic->ctx, ch->atom); + ic->cache[ch->index].index = 0; + } } - } end: - return 0; + return 0; fail: - return -1; + return -1; } -int resize_ic_hash(InlineCache *ic) { - uint32_t new_capacity, i, h; - InlineCacheHashSlot *ch, *ch_next; - InlineCacheHashSlot **new_hash; - ic->hash_bits += 1; - new_capacity = 1 << ic->hash_bits; - new_hash = js_malloc(ic->ctx, sizeof(ic->hash[0]) * new_capacity); - if (unlikely(!new_hash)) - goto fail; - memset(new_hash, 0, sizeof(ic->hash[0]) * new_capacity); - for (i = 0; i < ic->capacity; i++) { - for (ch = ic->hash[i]; ch != NULL; ch = ch_next) { - h = get_index_hash(ch->atom, ic->hash_bits); - ch_next = ch->next; - ch->next = new_hash[h]; - new_hash[h] = ch; - } - } - js_free(ic->ctx, ic->hash); - ic->hash = new_hash; - ic->capacity = new_capacity; - return 0; +int resize_ic_hash(InlineCache *ic) +{ + uint32_t new_capacity, i, h; + InlineCacheHashSlot *ch, *ch_next; + InlineCacheHashSlot **new_hash; + ic->hash_bits += 1; + new_capacity = 1 << ic->hash_bits; + new_hash = js_malloc(ic->ctx, sizeof(ic->hash[0]) * new_capacity); + if (unlikely(!new_hash)) + goto fail; + memset(new_hash, 0, sizeof(ic->hash[0]) * new_capacity); + for (i = 0; i < ic->capacity; i++) { + for (ch = ic->hash[i]; ch != NULL; ch = ch_next) { + h = get_index_hash(ch->atom, ic->hash_bits); + ch_next = ch->next; + ch->next = new_hash[h]; + new_hash[h] = ch; + } + } + js_free(ic->ctx, ic->hash); + ic->hash = new_hash; + ic->capacity = new_capacity; + return 0; fail: - return -1; + return -1; } -int free_ic(InlineCache *ic) { - uint32_t i, j; - InlineCacheHashSlot *ch, *ch_next; - InlineCacheRingItem *buffer; - for (i = 0; i < ic->count; i++) { - buffer = ic->cache[i].buffer; - JS_FreeAtom(ic->ctx, ic->cache[i].atom); - for (j = 0; j < IC_CACHE_ITEM_CAPACITY; j++) { - js_free_shape_null(ic->ctx->rt, buffer[j].shape); +int free_ic(InlineCache *ic) +{ + uint32_t i, j; + InlineCacheHashSlot *ch, *ch_next; + InlineCacheRingItem *buffer; + for (i = 0; i < ic->count; i++) { + buffer = ic->cache[i].buffer; + JS_FreeAtom(ic->ctx, ic->cache[i].atom); + for (j = 0; j < IC_CACHE_ITEM_CAPACITY; j++) { + js_free_shape_null(ic->ctx->rt, buffer[j].shape); + } } - } - for (i = 0; i < ic->capacity; i++) { - for (ch = ic->hash[i]; ch != NULL; ch = ch_next) { - ch_next = ch->next; - JS_FreeAtom(ic->ctx, ch->atom); - js_free(ic->ctx, ch); + for (i = 0; i < ic->capacity; i++) { + for (ch = ic->hash[i]; ch != NULL; ch = ch_next) { + ch_next = ch->next; + JS_FreeAtom(ic->ctx, ch->atom); + js_free(ic->ctx, ch); + } } - } - if (ic->count > 0) - js_free(ic->ctx, ic->cache); - js_free(ic->ctx, ic->hash); - js_free(ic->ctx, ic); - return 0; + if (ic->count > 0) + js_free(ic->ctx, ic->cache); + js_free(ic->ctx, ic->hash); + js_free(ic->ctx, ic); + return 0; } uint32_t add_ic_slot(InlineCache *ic, JSAtom atom, JSObject *object, - uint32_t prop_offset) { - int32_t i; - uint32_t h; - InlineCacheHashSlot *ch; - InlineCacheRingSlot *cr; - JSShape *sh; - cr = NULL; - h = get_index_hash(atom, ic->hash_bits); - for (ch = ic->hash[h]; ch != NULL; ch = ch->next) - if (ch->atom == atom) { - cr = ic->cache + ch->index; - break; - } - - assert(cr != NULL); - i = cr->index; - for (;;) { - if (object->shape == cr->buffer[i].shape) { - cr->buffer[i].prop_offset = prop_offset; - goto end; - } - - i = (i + 1) % IC_CACHE_ITEM_CAPACITY; - if (unlikely(i == cr->index)) - break; - } + uint32_t prop_offset) +{ + int32_t i; + uint32_t h; + InlineCacheHashSlot *ch; + InlineCacheRingSlot *cr; + JSShape *sh; + cr = NULL; + h = get_index_hash(atom, ic->hash_bits); + for (ch = ic->hash[h]; ch != NULL; ch = ch->next) + if (ch->atom == atom) { + cr = ic->cache + ch->index; + break; + } - sh = cr->buffer[i].shape; - cr->buffer[i].shape = js_dup_shape(object->shape); - js_free_shape_null(ic->ctx->rt, sh); - cr->buffer[i].prop_offset = prop_offset; + assert(cr != NULL); + i = cr->index; + for (;;) { + if (object->shape == cr->buffer[i].shape) { + cr->buffer[i].prop_offset = prop_offset; + goto end; + } + i = (i + 1) % IC_CACHE_ITEM_CAPACITY; + if (unlikely(i == cr->index)) + break; + } + sh = cr->buffer[i].shape; + cr->buffer[i].shape = js_dup_shape(object->shape); + js_free_shape_null(ic->ctx->rt, sh); + cr->buffer[i].prop_offset = prop_offset; end: - return ch->index; -} - -uint32_t add_ic_slot1(InlineCache *ic, JSAtom atom) { - uint32_t h; - InlineCacheHashSlot *ch; - if (ic->count + 1 >= ic->capacity && resize_ic_hash(ic)) - goto end; - h = get_index_hash(atom, ic->hash_bits); - for (ch = ic->hash[h]; ch != NULL; ch = ch->next) - if (ch->atom == atom) - goto end; - ch = js_malloc(ic->ctx, sizeof(InlineCacheHashSlot)); - if (unlikely(!ch)) - goto end; - ch->atom = JS_DupAtom(ic->ctx, atom); - ch->index = 0; - ch->next = ic->hash[h]; - ic->hash[h] = ch; - ic->count += 1; + return ch->index; +} + +uint32_t add_ic_slot1(InlineCache *ic, JSAtom atom) +{ + uint32_t h; + InlineCacheHashSlot *ch; + if (ic->count + 1 >= ic->capacity && resize_ic_hash(ic)) + goto end; + h = get_index_hash(atom, ic->hash_bits); + for (ch = ic->hash[h]; ch != NULL; ch = ch->next) + if (ch->atom == atom) + goto end; + ch = js_malloc(ic->ctx, sizeof(InlineCacheHashSlot)); + if (unlikely(!ch)) + goto end; + ch->atom = JS_DupAtom(ic->ctx, atom); + ch->index = 0; + ch->next = ic->hash[h]; + ic->hash[h] = ch; + ic->count += 1; end: - return 0; + return 0; } From b16b435f8a4a575ef55cc0cfe1af7e1fbd44a926 Mon Sep 17 00:00:00 2001 From: Divy Srivastava Date: Thu, 23 Nov 2023 12:08:24 +0530 Subject: [PATCH 03/17] RunGC test262 --- run-test262.c | 1 + 1 file changed, 1 insertion(+) diff --git a/run-test262.c b/run-test262.c index 376833d04..2ac3289ab 100644 --- a/run-test262.c +++ b/run-test262.c @@ -1565,6 +1565,7 @@ int run_test_buf(const char *filename, char *harness, namelist_t *ip, #ifdef CONFIG_AGENT js_agent_free(ctx); #endif + JS_RunGC(rt); JS_FreeContext(ctx); JS_FreeRuntime(rt); From 9059234d21e60526484aad346692adf04c8db5b0 Mon Sep 17 00:00:00 2001 From: Divy Srivastava Date: Thu, 23 Nov 2023 14:20:49 +0530 Subject: [PATCH 04/17] free IC in js_free_function_def --- quickjs.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/quickjs.c b/quickjs.c index 9536c5872..4f8cf67a9 100644 --- a/quickjs.c +++ b/quickjs.c @@ -26815,6 +26815,13 @@ static void js_free_function_def(JSContext *ctx, JSFunctionDef *fd) js_free(ctx, fd->label_slots); js_free(ctx, fd->line_number_slots); + /* free ic if unused */ + if (fd->ic && fd->ic->count == 0) { + /* we might be recovering after the ic is used + in that case, gc handles freeing */ + free_ic(fd->ic); + } + for(i = 0; i < fd->cpool_count; i++) { JS_FreeValue(ctx, fd->cpool[i]); } From 858d55664aa73fbcaa75b51b9e7569db60fcb9c0 Mon Sep 17 00:00:00 2001 From: Divy Srivastava Date: Thu, 23 Nov 2023 15:12:32 +0530 Subject: [PATCH 05/17] Revert t262 changes --- run-test262.c | 1 - 1 file changed, 1 deletion(-) diff --git a/run-test262.c b/run-test262.c index 2ac3289ab..376833d04 100644 --- a/run-test262.c +++ b/run-test262.c @@ -1565,7 +1565,6 @@ int run_test_buf(const char *filename, char *harness, namelist_t *ip, #ifdef CONFIG_AGENT js_agent_free(ctx); #endif - JS_RunGC(rt); JS_FreeContext(ctx); JS_FreeRuntime(rt); From ffc00e51af1765a505ee84005876124c4fa5d94a Mon Sep 17 00:00:00 2001 From: Divy Srivastava Date: Thu, 23 Nov 2023 17:15:19 +0530 Subject: [PATCH 06/17] handle unused ic freeing --- quickjs.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/quickjs.c b/quickjs.c index 4f8cf67a9..5b7b4a08b 100644 --- a/quickjs.c +++ b/quickjs.c @@ -26815,10 +26815,8 @@ static void js_free_function_def(JSContext *ctx, JSFunctionDef *fd) js_free(ctx, fd->label_slots); js_free(ctx, fd->line_number_slots); - /* free ic if unused */ - if (fd->ic && fd->ic->count == 0) { - /* we might be recovering after the ic is used - in that case, gc handles freeing */ + /* free ic */ + if (fd->ic) { free_ic(fd->ic); } @@ -50505,11 +50503,13 @@ int free_ic(InlineCache *ic) uint32_t i, j; InlineCacheHashSlot *ch, *ch_next; InlineCacheRingItem *buffer; - for (i = 0; i < ic->count; i++) { - buffer = ic->cache[i].buffer; - JS_FreeAtom(ic->ctx, ic->cache[i].atom); - for (j = 0; j < IC_CACHE_ITEM_CAPACITY; j++) { - js_free_shape_null(ic->ctx->rt, buffer[j].shape); + if (ic->cache) { + for (i = 0; i < ic->count; i++) { + buffer = ic->cache[i].buffer; + JS_FreeAtom(ic->ctx, ic->cache[i].atom); + for (j = 0; j < IC_CACHE_ITEM_CAPACITY; j++) { + js_free_shape_null(ic->ctx->rt, buffer[j].shape); + } } } for (i = 0; i < ic->capacity; i++) { From 7d0e26a33a63f8ebb14aaba5163451228bf3952d Mon Sep 17 00:00:00 2001 From: Divy Srivastava Date: Tue, 28 Nov 2023 17:08:35 +0530 Subject: [PATCH 07/17] Some review changes --- cutils.h | 3 ++ quickjs.c | 143 +++++++++++++++++++++++++++--------------------------- quickjs.h | 15 ++---- 3 files changed, 77 insertions(+), 84 deletions(-) diff --git a/cutils.h b/cutils.h index 4435e38cf..6f555005d 100644 --- a/cutils.h +++ b/cutils.h @@ -47,6 +47,9 @@ #endif #ifndef countof #define countof(x) (sizeof(x) / sizeof((x)[0])) +#ifndef endof +#define endof(x) ((x) + countof(x)) +#endif #endif typedef int BOOL; diff --git a/quickjs.c b/quickjs.c index 5b7b4a08b..57ec17cb6 100644 --- a/quickjs.c +++ b/quickjs.c @@ -538,48 +538,48 @@ typedef enum JSFunctionKindEnum { JS_FUNC_ASYNC_GENERATOR = (JS_FUNC_GENERATOR | JS_FUNC_ASYNC), } JSFunctionKindEnum; -typedef struct InlineCacheRingItem { +typedef struct JSInlineCacheRingItem { JSShape* shape; uint32_t prop_offset; -} InlineCacheRingItem; +} JSInlineCacheRingItem; -typedef struct InlineCacheRingSlot { +typedef struct JSInlineCacheRingSlot { JSAtom atom; - InlineCacheRingItem buffer[IC_CACHE_ITEM_CAPACITY]; + JSInlineCacheRingItem buffer[IC_CACHE_ITEM_CAPACITY]; uint8_t index; -} InlineCacheRingSlot; +} JSInlineCacheRingSlot; -typedef struct InlineCacheHashSlot { +typedef struct JSInlineCacheHashSlot { JSAtom atom; uint32_t index; - struct InlineCacheHashSlot *next; -} InlineCacheHashSlot; + struct JSInlineCacheHashSlot *next; +} JSInlineCacheHashSlot; -typedef struct InlineCache { +typedef struct JSInlineCache { uint32_t count; uint32_t capacity; uint32_t hash_bits; JSContext* ctx; - InlineCacheHashSlot **hash; - InlineCacheRingSlot *cache; + JSInlineCacheHashSlot **hash; + JSInlineCacheRingSlot *cache; uint32_t updated_offset; BOOL updated; -} InlineCache; +} JSInlineCache; -InlineCache *init_ic(JSContext *ctx); -int rebuild_ic(InlineCache *ic); -int resize_ic_hash(InlineCache *ic); -int free_ic(InlineCache *ic); -uint32_t add_ic_slot(InlineCache *ic, JSAtom atom, JSObject *object, +static JSInlineCache *init_ic(JSContext *ctx); +static int rebuild_ic(JSInlineCache *ic); +static int resize_ic_hash(JSInlineCache *ic); +static int free_ic(JSInlineCache *ic); +static uint32_t add_ic_slot(JSInlineCache *ic, JSAtom atom, JSObject *object, uint32_t prop_offset); -uint32_t add_ic_slot1(InlineCache *ic, JSAtom atom); +static uint32_t add_ic_slot1(JSInlineCache *ic, JSAtom atom); -force_inline int32_t get_ic_prop_offset(InlineCache *ic, uint32_t cache_offset, +static force_inline int32_t get_ic_prop_offset(JSInlineCache *ic, uint32_t cache_offset, JSShape *shape) { uint32_t i; - InlineCacheRingSlot *cr; - InlineCacheRingItem *buffer; + JSInlineCacheRingSlot *cr; + JSInlineCacheRingItem *buffer; assert(cache_offset < ic->capacity); cr = ic->cache + cache_offset; i = cr->index; @@ -599,7 +599,7 @@ force_inline int32_t get_ic_prop_offset(InlineCache *ic, uint32_t cache_offset, return -1; } -force_inline JSAtom get_ic_atom(InlineCache *ic, uint32_t cache_offset) +static force_inline JSAtom get_ic_atom(JSInlineCache *ic, uint32_t cache_offset) { assert(cache_offset < ic->capacity); return ic->cache[cache_offset].atom; @@ -635,7 +635,7 @@ typedef struct JSFunctionBytecode { JSValue *cpool; /* constant pool (self pointer) */ int cpool_count; int closure_var_count; - InlineCache *ic; + JSInlineCache *ic; struct { /* debug info, move to separate structure to save memory? */ JSAtom filename; @@ -5068,16 +5068,17 @@ static force_inline JSShapeProperty* find_own_property_ic(JSProperty** ppr, JSOb { JSShape* sh; JSShapeProperty *pr, *prop; - intptr_t h; + intptr_t h, i; sh = p->shape; 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]; + i = h - 1; + pr = &prop[i]; if (likely(pr->atom == atom)) { - *ppr = &p->prop[h - 1]; - *offset = h - 1; + *ppr = &p->prop[i]; + *offset = i; /* the compiler should be able to assume that pr != NULL here */ return pr; } @@ -5482,7 +5483,7 @@ static void mark_children(JSRuntime *rt, JSGCObjectHeader *gp, case JS_GC_OBJ_TYPE_FUNCTION_BYTECODE: /* the template objects can be part of a cycle */ { - InlineCacheRingItem *buffer; + JSInlineCacheRingItem *buffer, (*buffers)[IC_CACHE_ITEM_CAPACITY]; JSFunctionBytecode *b = (JSFunctionBytecode *)gp; int i, j; for(i = 0; i < b->cpool_count; i++) { @@ -5492,10 +5493,10 @@ static void mark_children(JSRuntime *rt, JSGCObjectHeader *gp, mark_func(rt, &b->realm->header); if (b->ic) { for (i = 0; i < b->ic->count; i++) { - buffer = b->ic->cache[i].buffer; - for (j = 0; j < IC_CACHE_ITEM_CAPACITY; j++) - if (buffer[j].shape) - mark_func(rt, &buffer[j].shape->header); + buffers = &b->ic->cache[i].buffer; + for (buffer = *buffers; buffer != endof(*buffers); buffer++) + if (buffer->shape) + mark_func(rt, &buffer->shape->header); } } } @@ -6909,7 +6910,7 @@ static int JS_AutoInitProperty(JSContext *ctx, JSObject *p, JSAtom prop, JSValue JS_GetPropertyInternal(JSContext *ctx, JSValueConst obj, JSAtom prop, JSValueConst this_obj, - InlineCache* ic, BOOL throw_ref_error) + JSInlineCache* ic, BOOL throw_ref_error) { JSObject *p; JSProperty *pr; @@ -7061,7 +7062,7 @@ JSValue JS_GetPropertyInternal(JSContext *ctx, JSValueConst obj, force_inline JSValue JS_GetPropertyInternalWithIC(JSContext *ctx, JSValueConst obj, JSAtom prop, JSValueConst this_obj, - InlineCache *ic, int32_t offset, + JSInlineCache *ic, int32_t offset, BOOL throw_ref_error) { uint32_t tag; @@ -7073,8 +7074,8 @@ force_inline JSValue JS_GetPropertyInternalWithIC(JSContext *ctx, JSValueConst o offset = get_ic_prop_offset(ic, offset, p->shape); if (likely(offset >= 0)) return JS_DupValue(ctx, p->prop[offset].u.value); - slow_path: - return JS_GetPropertyInternal(ctx, obj, prop, this_obj, ic, throw_ref_error); +slow_path: + return JS_GetPropertyInternal(ctx, obj, prop, this_obj, ic, throw_ref_error); } static JSValue JS_ThrowTypeErrorPrivateNotFound(JSContext *ctx, JSAtom atom) @@ -8288,7 +8289,7 @@ static int JS_SetPropertyGeneric(JSContext *ctx, the new property is not added and an error is raised. */ int JS_SetPropertyInternal(JSContext *ctx, JSValueConst this_obj, JSAtom prop, JSValue val, int flags, - InlineCache *ic) + JSInlineCache *ic) { JSObject *p, *p1; JSShapeProperty *prs; @@ -8512,7 +8513,7 @@ int JS_SetPropertyInternal(JSContext *ctx, JSValueConst this_obj, force_inline int JS_SetPropertyInternalWithIC(JSContext *ctx, JSValueConst this_obj, JSAtom prop, JSValue val, int flags, - InlineCache *ic, int32_t offset) { + JSInlineCache *ic, int32_t offset) { uint32_t tag; JSObject *p; tag = JS_VALUE_GET_TAG(this_obj); @@ -8524,8 +8525,8 @@ force_inline int JS_SetPropertyInternalWithIC(JSContext *ctx, JSValueConst this_ set_value(ctx, &p->prop[offset].u.value, val); return TRUE; } - slow_path: - return JS_SetPropertyInternal(ctx, this_obj, prop, val, flags, ic); +slow_path: + return JS_SetPropertyInternal(ctx, this_obj, prop, val, flags, ic); } /* flags can be JS_PROP_THROW or JS_PROP_THROW_STRICT */ @@ -14303,7 +14304,7 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj, JSValue *local_buf, *stack_buf, *var_buf, *arg_buf, *sp, ret_val, *pval; JSVarRef **var_refs; size_t alloca_size; - InlineCache *ic; + JSInlineCache *ic; #if !DIRECT_DISPATCH #define SWITCH(pc) switch (opcode = *pc++) @@ -18151,7 +18152,7 @@ typedef struct JSFunctionDef { int source_len; JSModuleDef *module; /* != NULL when parsing a module */ - InlineCache *ic; /* inline cache for field op */ + JSInlineCache *ic; /* inline cache for field op */ } JSFunctionDef; typedef struct JSToken { @@ -26816,9 +26817,8 @@ static void js_free_function_def(JSContext *ctx, JSFunctionDef *fd) js_free(ctx, fd->line_number_slots); /* free ic */ - if (fd->ic) { - free_ic(fd->ic); - } + if (fd->ic) + free_ic(fd->ic); for(i = 0; i < fd->cpool_count; i++) { JS_FreeValue(ctx, fd->cpool[i]); @@ -30580,7 +30580,7 @@ static void free_function_bytecode(JSRuntime *rt, JSFunctionBytecode *b) free_bytecode_atoms(rt, b->byte_code_buf, b->byte_code_len, TRUE); - if (b->ic != NULL) + if (b->ic) free_ic(b->ic); if (b->vardefs) { @@ -50425,39 +50425,38 @@ static force_inline uint32_t get_index_hash(JSAtom atom, int hash_bits) return (atom * 0x9e370001) >> (32 - hash_bits); } -InlineCache *init_ic(JSContext *ctx) +JSInlineCache *init_ic(JSContext *ctx) { - InlineCache *ic; - ic = js_malloc(ctx, sizeof(InlineCache)); + JSInlineCache *ic; + ic = js_malloc(ctx, sizeof(JSInlineCache)); if (unlikely(!ic)) goto fail; ic->count = 0; ic->hash_bits = 2; ic->capacity = 1 << ic->hash_bits; ic->ctx = ctx; - ic->hash = js_malloc(ctx, sizeof(ic->hash[0]) * ic->capacity); + ic->hash = js_mallocz(ctx, sizeof(ic->hash[0]) * ic->capacity); if (unlikely(!ic->hash)) goto fail; - memset(ic->hash, 0, sizeof(ic->hash[0]) * ic->capacity); ic->cache = NULL; ic->updated = FALSE; ic->updated_offset = 0; return ic; fail: + js_free(ctx, ic); return NULL; } -int rebuild_ic(InlineCache *ic) +int rebuild_ic(JSInlineCache *ic) { uint32_t i, count; - InlineCacheHashSlot *ch; + JSInlineCacheHashSlot *ch; if (ic->count == 0) goto end; count = 0; - ic->cache = js_malloc(ic->ctx, sizeof(InlineCacheRingSlot) * ic->count); + ic->cache = js_mallocz(ic->ctx, sizeof(JSInlineCacheRingSlot) * ic->count); if (unlikely(!ic->cache)) goto fail; - memset(ic->cache, 0, sizeof(InlineCacheRingSlot) * ic->count); for (i = 0; i < ic->capacity; i++) { for (ch = ic->hash[i]; ch != NULL; ch = ch->next) { ch->index = count++; @@ -50471,17 +50470,16 @@ int rebuild_ic(InlineCache *ic) return -1; } -int resize_ic_hash(InlineCache *ic) +int resize_ic_hash(JSInlineCache *ic) { uint32_t new_capacity, i, h; - InlineCacheHashSlot *ch, *ch_next; - InlineCacheHashSlot **new_hash; - ic->hash_bits += 1; - new_capacity = 1 << ic->hash_bits; - new_hash = js_malloc(ic->ctx, sizeof(ic->hash[0]) * new_capacity); + JSInlineCacheHashSlot *ch, *ch_next; + JSInlineCacheHashSlot **new_hash; + new_capacity = 1 << (ic->hash_bits + 1); + new_hash = js_mallocz(ic->ctx, sizeof(ic->hash[0]) * new_capacity); if (unlikely(!new_hash)) goto fail; - memset(new_hash, 0, sizeof(ic->hash[0]) * new_capacity); + ic->hash_bits += 1; for (i = 0; i < ic->capacity; i++) { for (ch = ic->hash[i]; ch != NULL; ch = ch_next) { h = get_index_hash(ch->atom, ic->hash_bits); @@ -50498,11 +50496,11 @@ int resize_ic_hash(InlineCache *ic) return -1; } -int free_ic(InlineCache *ic) +int free_ic(JSInlineCache *ic) { uint32_t i, j; - InlineCacheHashSlot *ch, *ch_next; - InlineCacheRingItem *buffer; + JSInlineCacheHashSlot *ch, *ch_next; + JSInlineCacheRingItem *buffer; if (ic->cache) { for (i = 0; i < ic->count; i++) { buffer = ic->cache[i].buffer; @@ -50526,21 +50524,22 @@ int free_ic(InlineCache *ic) return 0; } -uint32_t add_ic_slot(InlineCache *ic, JSAtom atom, JSObject *object, +uint32_t add_ic_slot(JSInlineCache *ic, JSAtom atom, JSObject *object, uint32_t prop_offset) { int32_t i; uint32_t h; - InlineCacheHashSlot *ch; - InlineCacheRingSlot *cr; + JSInlineCacheHashSlot *ch; + JSInlineCacheRingSlot *cr; JSShape *sh; cr = NULL; h = get_index_hash(atom, ic->hash_bits); - for (ch = ic->hash[h]; ch != NULL; ch = ch->next) + for (ch = ic->hash[h]; ch != NULL; ch = ch->next) { if (ch->atom == atom) { cr = ic->cache + ch->index; break; } + } assert(cr != NULL); i = cr->index; @@ -50561,17 +50560,17 @@ uint32_t add_ic_slot(InlineCache *ic, JSAtom atom, JSObject *object, return ch->index; } -uint32_t add_ic_slot1(InlineCache *ic, JSAtom atom) +uint32_t add_ic_slot1(JSInlineCache *ic, JSAtom atom) { uint32_t h; - InlineCacheHashSlot *ch; + JSInlineCacheHashSlot *ch; if (ic->count + 1 >= ic->capacity && resize_ic_hash(ic)) goto end; h = get_index_hash(atom, ic->hash_bits); for (ch = ic->hash[h]; ch != NULL; ch = ch->next) if (ch->atom == atom) goto end; - ch = js_malloc(ic->ctx, sizeof(InlineCacheHashSlot)); + ch = js_malloc(ic->ctx, sizeof(JSInlineCacheHashSlot)); if (unlikely(!ch)) goto end; ch->atom = JS_DupAtom(ic->ctx, atom); diff --git a/quickjs.h b/quickjs.h index 5ccd06cbf..79091b2c7 100644 --- a/quickjs.h +++ b/quickjs.h @@ -676,16 +676,11 @@ JS_BOOL JS_SetConstructorBit(JSContext *ctx, JSValueConst func_obj, JS_BOOL val) JSValue JS_NewArray(JSContext *ctx); int JS_IsArray(JSContext *ctx, JSValueConst val); -typedef struct InlineCache InlineCache; +typedef struct JSInlineCache JSInlineCache; JSValue JS_GetPropertyInternal(JSContext *ctx, JSValueConst obj, JSAtom prop, JSValueConst receiver, - InlineCache *ic, JS_BOOL throw_ref_error); -JSValue JS_GetPropertyInternalWithIC(JSContext *ctx, JSValueConst obj, - JSAtom prop, JSValueConst receiver, - InlineCache *ic, int32_t offset, - JS_BOOL throw_ref_error); - + JSInlineCache *ic, JS_BOOL throw_ref_error); static js_force_inline JSValue JS_GetProperty(JSContext *ctx, JSValueConst this_obj, JSAtom prop) { @@ -698,11 +693,7 @@ JSValue JS_GetPropertyUint32(JSContext *ctx, JSValueConst this_obj, int JS_SetPropertyInternal(JSContext *ctx, JSValueConst this_obj, JSAtom prop, JSValue val, - int flags, InlineCache *ic); -int JS_SetPropertyInternalWithIC(JSContext *ctx, JSValueConst this_obj, - JSAtom prop, JSValue val, - int flags, InlineCache *ic, - int32_t offset); + int flags, JSInlineCache *ic); static inline int JS_SetProperty(JSContext *ctx, JSValueConst this_obj, JSAtom prop, JSValue val) { From 50ab4c2b98cee3ae22a74467a70dcde0124cbad2 Mon Sep 17 00:00:00 2001 From: Divy Srivastava Date: Tue, 28 Nov 2023 17:58:16 +0530 Subject: [PATCH 08/17] Set slot count to 4 --- quickjs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/quickjs.c b/quickjs.c index 57ec17cb6..ac63b9e29 100644 --- a/quickjs.c +++ b/quickjs.c @@ -529,7 +529,7 @@ typedef struct JSVarDef { #define PC2LINE_RANGE 5 #define PC2LINE_OP_FIRST 1 #define PC2LINE_DIFF_PC_MAX ((255 - PC2LINE_OP_FIRST) / PC2LINE_RANGE) -#define IC_CACHE_ITEM_CAPACITY 8 +#define IC_CACHE_ITEM_CAPACITY 4 typedef enum JSFunctionKindEnum { JS_FUNC_NORMAL = 0, From 77250c8c3841b06a866a0b65d0cf034851feb944 Mon Sep 17 00:00:00 2001 From: Divy Srivastava Date: Tue, 28 Nov 2023 18:07:56 +0530 Subject: [PATCH 09/17] Use countof --- quickjs.c | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/quickjs.c b/quickjs.c index 00df0d9be..1df3451fc 100644 --- a/quickjs.c +++ b/quickjs.c @@ -7083,7 +7083,7 @@ JSValue JS_GetPropertyInternal(JSContext *ctx, JSValueConst obj, } } -force_inline JSValue JS_GetPropertyInternalWithIC(JSContext *ctx, JSValueConst obj, +static force_inline JSValue JS_GetPropertyInternalWithIC(JSContext *ctx, JSValueConst obj, JSAtom prop, JSValueConst this_obj, JSInlineCache *ic, int32_t offset, BOOL throw_ref_error) @@ -8534,7 +8534,7 @@ int JS_SetPropertyInternal(JSContext *ctx, JSValueConst this_obj, return TRUE; } -force_inline int JS_SetPropertyInternalWithIC(JSContext *ctx, JSValueConst this_obj, +static force_inline int JS_SetPropertyInternalWithIC(JSContext *ctx, JSValueConst this_obj, JSAtom prop, JSValue val, int flags, JSInlineCache *ic, int32_t offset) { uint32_t tag; @@ -51032,14 +51032,13 @@ int free_ic(JSInlineCache *ic) { uint32_t i, j; JSInlineCacheHashSlot *ch, *ch_next; - JSInlineCacheRingItem *buffer; + JSInlineCacheRingItem *buffer, (*buffers)[IC_CACHE_ITEM_CAPACITY]; if (ic->cache) { for (i = 0; i < ic->count; i++) { - buffer = ic->cache[i].buffer; + buffers = &ic->cache[i].buffer; JS_FreeAtom(ic->ctx, ic->cache[i].atom); - for (j = 0; j < IC_CACHE_ITEM_CAPACITY; j++) { - js_free_shape_null(ic->ctx->rt, buffer[j].shape); - } + for (buffer = *buffers; buffer != endof(*buffers); buffer++) + js_free_shape_null(ic->ctx->rt, buffer->shape); } } for (i = 0; i < ic->capacity; i++) { @@ -51080,7 +51079,7 @@ uint32_t add_ic_slot(JSInlineCache *ic, JSAtom atom, JSObject *object, cr->buffer[i].prop_offset = prop_offset; goto end; } - i = (i + 1) % IC_CACHE_ITEM_CAPACITY; + i = (i + 1) % countof(cr->buffer); if (unlikely(i == cr->index)) break; } From 08b343ae3d9e850b54346d3d32a4c633ad02cc2b Mon Sep 17 00:00:00 2001 From: Divy Srivastava Date: Tue, 28 Nov 2023 18:55:37 +0530 Subject: [PATCH 10/17] Convert JSInlineCacheRingItem to SoA --- quickjs.c | 50 ++++++++++++++++++++++++-------------------------- quickjs.h | 2 +- 2 files changed, 25 insertions(+), 27 deletions(-) diff --git a/quickjs.c b/quickjs.c index 1df3451fc..2ca90440a 100644 --- a/quickjs.c +++ b/quickjs.c @@ -549,7 +549,6 @@ typedef struct JSVarDef { #define PC2LINE_RANGE 5 #define PC2LINE_OP_FIRST 1 #define PC2LINE_DIFF_PC_MAX ((255 - PC2LINE_OP_FIRST) / PC2LINE_RANGE) -#define IC_CACHE_ITEM_CAPACITY 4 typedef enum JSFunctionKindEnum { JS_FUNC_NORMAL = 0, @@ -558,14 +557,13 @@ typedef enum JSFunctionKindEnum { JS_FUNC_ASYNC_GENERATOR = (JS_FUNC_GENERATOR | JS_FUNC_ASYNC), } JSFunctionKindEnum; -typedef struct JSInlineCacheRingItem { - JSShape* shape; - uint32_t prop_offset; -} JSInlineCacheRingItem; +#define IC_CACHE_ITEM_CAPACITY 4 typedef struct JSInlineCacheRingSlot { + /* SoA for space optimization: 56 bytes */ + JSShape* shape[IC_CACHE_ITEM_CAPACITY]; + uint32_t prop_offset[IC_CACHE_ITEM_CAPACITY]; JSAtom atom; - JSInlineCacheRingItem buffer[IC_CACHE_ITEM_CAPACITY]; uint8_t index; } JSInlineCacheRingSlot; @@ -599,18 +597,18 @@ static force_inline int32_t get_ic_prop_offset(JSInlineCache *ic, uint32_t cache { uint32_t i; JSInlineCacheRingSlot *cr; - JSInlineCacheRingItem *buffer; + JSShape *shape_slot; assert(cache_offset < ic->capacity); cr = ic->cache + cache_offset; i = cr->index; for (;;) { - buffer = cr->buffer + i; - if (likely(buffer->shape == shape)) { + shape_slot = *(cr->shape + i); + if (likely(shape_slot == shape)) { cr->index = i; - return buffer->prop_offset; + return cr->prop_offset[i]; } - i = (i + 1) % IC_CACHE_ITEM_CAPACITY; + i = (i + 1) % countof(cr->shape); if (unlikely(i == cr->index)) { break; } @@ -5506,7 +5504,7 @@ static void mark_children(JSRuntime *rt, JSGCObjectHeader *gp, case JS_GC_OBJ_TYPE_FUNCTION_BYTECODE: /* the template objects can be part of a cycle */ { - JSInlineCacheRingItem *buffer, (*buffers)[IC_CACHE_ITEM_CAPACITY]; + JSShape **shape, *(*shapes)[IC_CACHE_ITEM_CAPACITY]; JSFunctionBytecode *b = (JSFunctionBytecode *)gp; int i, j; for(i = 0; i < b->cpool_count; i++) { @@ -5516,10 +5514,10 @@ static void mark_children(JSRuntime *rt, JSGCObjectHeader *gp, mark_func(rt, &b->realm->header); if (b->ic) { for (i = 0; i < b->ic->count; i++) { - buffers = &b->ic->cache[i].buffer; - for (buffer = *buffers; buffer != endof(*buffers); buffer++) - if (buffer->shape) - mark_func(rt, &buffer->shape->header); + shapes = &b->ic->cache[i].shape; + for (shape = *shapes; shape != endof(*shapes); shape++) + if (*shape) + mark_func(rt, &(*shape)->header); } } } @@ -51032,13 +51030,13 @@ int free_ic(JSInlineCache *ic) { uint32_t i, j; JSInlineCacheHashSlot *ch, *ch_next; - JSInlineCacheRingItem *buffer, (*buffers)[IC_CACHE_ITEM_CAPACITY]; + JSShape **shape, *(*shapes)[IC_CACHE_ITEM_CAPACITY]; if (ic->cache) { for (i = 0; i < ic->count; i++) { - buffers = &ic->cache[i].buffer; + shapes = &ic->cache[i].shape; JS_FreeAtom(ic->ctx, ic->cache[i].atom); - for (buffer = *buffers; buffer != endof(*buffers); buffer++) - js_free_shape_null(ic->ctx->rt, buffer->shape); + for (shape = *shapes; shape != endof(*shapes); shape++) + js_free_shape_null(ic->ctx->rt, *shape); } } for (i = 0; i < ic->capacity; i++) { @@ -51075,18 +51073,18 @@ uint32_t add_ic_slot(JSInlineCache *ic, JSAtom atom, JSObject *object, assert(cr != NULL); i = cr->index; for (;;) { - if (object->shape == cr->buffer[i].shape) { - cr->buffer[i].prop_offset = prop_offset; + if (object->shape == cr->shape[i]) { + cr->prop_offset[i] = prop_offset; goto end; } - i = (i + 1) % countof(cr->buffer); + i = (i + 1) % countof(cr->shape); if (unlikely(i == cr->index)) break; } - sh = cr->buffer[i].shape; - cr->buffer[i].shape = js_dup_shape(object->shape); + sh = cr->shape[i]; + cr->shape[i] = js_dup_shape(object->shape); js_free_shape_null(ic->ctx->rt, sh); - cr->buffer[i].prop_offset = prop_offset; + cr->prop_offset[i] = prop_offset; end: return ch->index; } diff --git a/quickjs.h b/quickjs.h index 507f5dda9..a20eeebda 100644 --- a/quickjs.h +++ b/quickjs.h @@ -682,7 +682,7 @@ JS_EXTERN JSValue JS_NewDate(JSContext *ctx, double epoch_ms); typedef struct JSInlineCache JSInlineCache; -JSValue JS_GetPropertyInternal(JSContext *ctx, JSValueConst obj, +JS_EXTERN JSValue JS_GetPropertyInternal(JSContext *ctx, JSValueConst obj, JSAtom prop, JSValueConst receiver, JSInlineCache *ic, JS_BOOL throw_ref_error); static js_force_inline JSValue JS_GetProperty(JSContext *ctx, JSValueConst this_obj, From 13a85eaddd8aec66d3c710d8bc056c2bc5ebb85e Mon Sep 17 00:00:00 2001 From: Divy Srivastava Date: Tue, 28 Nov 2023 20:23:41 +0530 Subject: [PATCH 11/17] fd->ic = NULL --- quickjs.c | 1 + 1 file changed, 1 insertion(+) diff --git a/quickjs.c b/quickjs.c index 2ca90440a..be8e0020c 100644 --- a/quickjs.c +++ b/quickjs.c @@ -30697,6 +30697,7 @@ static JSValue js_create_function(JSContext *ctx, JSFunctionDef *fd) b->backtrace_barrier = fd->backtrace_barrier; b->realm = JS_DupContext(ctx); b->ic = fd->ic; + fd->ic = NULL; rebuild_ic(b->ic); if (b->ic->count == 0) { free_ic(b->ic); From 367c3c6c15d639b3db9ba1160891acb76e567e94 Mon Sep 17 00:00:00 2001 From: Divy Srivastava Date: Tue, 28 Nov 2023 21:11:35 +0530 Subject: [PATCH 12/17] remove ctx from ic --- quickjs.c | 78 +++++++++++++++++++++++++++---------------------------- 1 file changed, 38 insertions(+), 40 deletions(-) diff --git a/quickjs.c b/quickjs.c index be8e0020c..9842b0721 100644 --- a/quickjs.c +++ b/quickjs.c @@ -577,7 +577,6 @@ typedef struct JSInlineCache { uint32_t count; uint32_t capacity; uint32_t hash_bits; - JSContext* ctx; JSInlineCacheHashSlot **hash; JSInlineCacheRingSlot *cache; uint32_t updated_offset; @@ -585,12 +584,12 @@ typedef struct JSInlineCache { } JSInlineCache; static JSInlineCache *init_ic(JSContext *ctx); -static int rebuild_ic(JSInlineCache *ic); -static int resize_ic_hash(JSInlineCache *ic); -static int free_ic(JSInlineCache *ic); -static uint32_t add_ic_slot(JSInlineCache *ic, JSAtom atom, JSObject *object, - uint32_t prop_offset); -static uint32_t add_ic_slot1(JSInlineCache *ic, JSAtom atom); +static int rebuild_ic(JSContext *ctx, JSInlineCache *ic); +static int resize_ic_hash(JSContext *ctx, JSInlineCache *ic); +static int free_ic(JSRuntime *rt, JSInlineCache *ic); +static uint32_t add_ic_slot(JSContext *ctx, JSInlineCache *ic, JSAtom atom, JSObject *object, + uint32_t prop_offset); +static uint32_t add_ic_slot1(JSContext *ctx, JSInlineCache *ic, JSAtom atom); static force_inline int32_t get_ic_prop_offset(JSInlineCache *ic, uint32_t cache_offset, JSShape *shape) @@ -7005,7 +7004,7 @@ JSValue JS_GetPropertyInternal(JSContext *ctx, JSValueConst obj, } else { if (ic && proto_depth == 0 && p->shape->is_hashed) { ic->updated = TRUE; - ic->updated_offset = add_ic_slot(ic, prop, p, offset); + ic->updated_offset = add_ic_slot(ctx, ic, prop, p, offset); } return JS_DupValue(ctx, pr->u.value); } @@ -8346,7 +8345,7 @@ int JS_SetPropertyInternal(JSContext *ctx, JSValueConst this_obj, /* fast case */ if (ic && p->shape->is_hashed) { ic->updated = TRUE; - ic->updated_offset = add_ic_slot(ic, prop, p, offset); + ic->updated_offset = add_ic_slot(ctx, ic, prop, p, offset); } set_value(ctx, &pr->u.value, val); return TRUE; @@ -15663,7 +15662,7 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj, ic->updated = FALSE; put_u8(pc - 5, OP_get_field_ic); put_u32(pc - 4, ic->updated_offset); - JS_FreeAtom(ic->ctx, atom); + JS_FreeAtom(ctx, atom); } JS_FreeValue(ctx, sp[-1]); sp[-1] = val; @@ -15699,7 +15698,7 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj, ic->updated = FALSE; put_u8(pc - 5, OP_get_field2_ic); put_u32(pc - 4, ic->updated_offset); - JS_FreeAtom(ic->ctx, atom); + JS_FreeAtom(ctx, atom); } *sp++ = val; } @@ -15736,7 +15735,7 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj, ic->updated = FALSE; put_u8(pc - 5, OP_put_field_ic); put_u32(pc - 4, ic->updated_offset); - JS_FreeAtom(ic->ctx, atom); + JS_FreeAtom(ctx, atom); } } BREAK; @@ -19577,7 +19576,7 @@ static void emit_atom(JSParseState *s, JSAtom name) } static void emit_ic(JSParseState *s, JSAtom atom) { - add_ic_slot1(s->cur_func->ic, atom); + add_ic_slot1(s->ctx, s->cur_func->ic, atom); } static int update_label(JSFunctionDef *s, int label, int delta) @@ -26956,7 +26955,7 @@ static void js_free_function_def(JSContext *ctx, JSFunctionDef *fd) /* free ic */ if (fd->ic) - free_ic(fd->ic); + free_ic(ctx->rt, fd->ic); for(i = 0; i < fd->cpool_count; i++) { JS_FreeValue(ctx, fd->cpool[i]); @@ -30698,9 +30697,9 @@ static JSValue js_create_function(JSContext *ctx, JSFunctionDef *fd) b->realm = JS_DupContext(ctx); b->ic = fd->ic; fd->ic = NULL; - rebuild_ic(b->ic); + rebuild_ic(ctx, b->ic); if (b->ic->count == 0) { - free_ic(b->ic); + free_ic(ctx->rt, b->ic); b->ic = NULL; } @@ -30729,7 +30728,7 @@ static void free_function_bytecode(JSRuntime *rt, JSFunctionBytecode *b) free_bytecode_atoms(rt, b->byte_code_buf, b->byte_code_len, TRUE); if (b->ic) - free_ic(b->ic); + free_ic(rt, b->ic); if (b->vardefs) { for(i = 0; i < b->arg_count + b->var_count; i++) { @@ -33336,10 +33335,10 @@ static JSValue JS_ReadFunctionTag(BCReaderState *s) goto fail; for (i = 0; i < ic_len; i++) { bc_get_atom(s, &atom); - add_ic_slot1(b->ic, atom); + add_ic_slot1(ctx, b->ic, atom); JS_FreeAtom(ctx, atom); } - rebuild_ic(b->ic); + rebuild_ic(ctx, b->ic); } } #ifdef DUMP_READ_OBJECT @@ -50965,7 +50964,6 @@ JSInlineCache *init_ic(JSContext *ctx) ic->count = 0; ic->hash_bits = 2; ic->capacity = 1 << ic->hash_bits; - ic->ctx = ctx; ic->hash = js_mallocz(ctx, sizeof(ic->hash[0]) * ic->capacity); if (unlikely(!ic->hash)) goto fail; @@ -50978,20 +50976,20 @@ JSInlineCache *init_ic(JSContext *ctx) return NULL; } -int rebuild_ic(JSInlineCache *ic) +int rebuild_ic(JSContext *ctx, JSInlineCache *ic) { uint32_t i, count; JSInlineCacheHashSlot *ch; if (ic->count == 0) goto end; count = 0; - ic->cache = js_mallocz(ic->ctx, sizeof(JSInlineCacheRingSlot) * ic->count); + ic->cache = js_mallocz(ctx, sizeof(JSInlineCacheRingSlot) * ic->count); if (unlikely(!ic->cache)) goto fail; for (i = 0; i < ic->capacity; i++) { for (ch = ic->hash[i]; ch != NULL; ch = ch->next) { ch->index = count++; - ic->cache[ch->index].atom = JS_DupAtom(ic->ctx, ch->atom); + ic->cache[ch->index].atom = JS_DupAtom(ctx, ch->atom); ic->cache[ch->index].index = 0; } } @@ -51001,13 +50999,13 @@ int rebuild_ic(JSInlineCache *ic) return -1; } -int resize_ic_hash(JSInlineCache *ic) +int resize_ic_hash(JSContext *ctx, JSInlineCache *ic) { uint32_t new_capacity, i, h; JSInlineCacheHashSlot *ch, *ch_next; JSInlineCacheHashSlot **new_hash; new_capacity = 1 << (ic->hash_bits + 1); - new_hash = js_mallocz(ic->ctx, sizeof(ic->hash[0]) * new_capacity); + new_hash = js_mallocz(ctx, sizeof(ic->hash[0]) * new_capacity); if (unlikely(!new_hash)) goto fail; ic->hash_bits += 1; @@ -51019,7 +51017,7 @@ int resize_ic_hash(JSInlineCache *ic) new_hash[h] = ch; } } - js_free(ic->ctx, ic->hash); + js_free(ctx, ic->hash); ic->hash = new_hash; ic->capacity = new_capacity; return 0; @@ -51027,7 +51025,7 @@ int resize_ic_hash(JSInlineCache *ic) return -1; } -int free_ic(JSInlineCache *ic) +int free_ic(JSRuntime* rt, JSInlineCache *ic) { uint32_t i, j; JSInlineCacheHashSlot *ch, *ch_next; @@ -51035,26 +51033,26 @@ int free_ic(JSInlineCache *ic) if (ic->cache) { for (i = 0; i < ic->count; i++) { shapes = &ic->cache[i].shape; - JS_FreeAtom(ic->ctx, ic->cache[i].atom); + JS_FreeAtomRT(rt, ic->cache[i].atom); for (shape = *shapes; shape != endof(*shapes); shape++) - js_free_shape_null(ic->ctx->rt, *shape); + js_free_shape_null(rt, *shape); } } for (i = 0; i < ic->capacity; i++) { for (ch = ic->hash[i]; ch != NULL; ch = ch_next) { ch_next = ch->next; - JS_FreeAtom(ic->ctx, ch->atom); - js_free(ic->ctx, ch); + JS_FreeAtomRT(rt, ch->atom); + js_free_rt(rt, ch); } } if (ic->count > 0) - js_free(ic->ctx, ic->cache); - js_free(ic->ctx, ic->hash); - js_free(ic->ctx, ic); + js_free_rt(rt, ic->cache); + js_free_rt(rt, ic->hash); + js_free_rt(rt, ic); return 0; } -uint32_t add_ic_slot(JSInlineCache *ic, JSAtom atom, JSObject *object, +uint32_t add_ic_slot(JSContext *ctx, JSInlineCache *ic, JSAtom atom, JSObject *object, uint32_t prop_offset) { int32_t i; @@ -51084,26 +51082,26 @@ uint32_t add_ic_slot(JSInlineCache *ic, JSAtom atom, JSObject *object, } sh = cr->shape[i]; cr->shape[i] = js_dup_shape(object->shape); - js_free_shape_null(ic->ctx->rt, sh); + js_free_shape_null(ctx->rt, sh); cr->prop_offset[i] = prop_offset; end: return ch->index; } -uint32_t add_ic_slot1(JSInlineCache *ic, JSAtom atom) +uint32_t add_ic_slot1(JSContext *ctx, JSInlineCache *ic, JSAtom atom) { uint32_t h; JSInlineCacheHashSlot *ch; - if (ic->count + 1 >= ic->capacity && resize_ic_hash(ic)) + if (ic->count + 1 >= ic->capacity && resize_ic_hash(ctx, ic)) goto end; h = get_index_hash(atom, ic->hash_bits); for (ch = ic->hash[h]; ch != NULL; ch = ch->next) if (ch->atom == atom) goto end; - ch = js_malloc(ic->ctx, sizeof(JSInlineCacheHashSlot)); + ch = js_malloc(ctx, sizeof(JSInlineCacheHashSlot)); if (unlikely(!ch)) goto end; - ch->atom = JS_DupAtom(ic->ctx, atom); + ch->atom = JS_DupAtom(ctx, atom); ch->index = 0; ch->next = ic->hash[h]; ic->hash[h] = ch; From 891a832c3c66a6f48c19d681c6719d9df94ca194 Mon Sep 17 00:00:00 2001 From: Divy Srivastava Date: Tue, 28 Nov 2023 22:06:42 +0530 Subject: [PATCH 13/17] Add JS_GetPropertyInternal2 and JS_SetPropertyInternal2 --- quickjs.c | 50 ++++++++++++++++++++++++++++++++------------------ quickjs.h | 8 ++++---- 2 files changed, 36 insertions(+), 22 deletions(-) diff --git a/quickjs.c b/quickjs.c index 9842b0721..81e34e7be 100644 --- a/quickjs.c +++ b/quickjs.c @@ -6928,7 +6928,7 @@ static int JS_AutoInitProperty(JSContext *ctx, JSObject *p, JSAtom prop, return 0; } -JSValue JS_GetPropertyInternal(JSContext *ctx, JSValueConst obj, +JSValue JS_GetPropertyInternal2(JSContext *ctx, JSValueConst obj, JSAtom prop, JSValueConst this_obj, JSInlineCache* ic, BOOL throw_ref_error) { @@ -7080,6 +7080,14 @@ JSValue JS_GetPropertyInternal(JSContext *ctx, JSValueConst obj, } } +JSValue JS_GetPropertyInternal(JSContext *ctx, JSValueConst obj, + JSAtom prop, JSValueConst this_obj, + BOOL throw_ref_error) +{ + return JS_GetPropertyInternal2(ctx, obj, prop, this_obj, NULL, throw_ref_error); +} + + static force_inline JSValue JS_GetPropertyInternalWithIC(JSContext *ctx, JSValueConst obj, JSAtom prop, JSValueConst this_obj, JSInlineCache *ic, int32_t offset, @@ -7095,7 +7103,7 @@ static force_inline JSValue JS_GetPropertyInternalWithIC(JSContext *ctx, JSValue if (likely(offset >= 0)) return JS_DupValue(ctx, p->prop[offset].u.value); slow_path: - return JS_GetPropertyInternal(ctx, obj, prop, this_obj, ic, throw_ref_error); + return JS_GetPropertyInternal2(ctx, obj, prop, this_obj, ic, throw_ref_error); } static JSValue JS_ThrowTypeErrorPrivateNotFound(JSContext *ctx, JSAtom atom) @@ -8307,9 +8315,9 @@ static int JS_SetPropertyGeneric(JSContext *ctx, freed by the function. 'flags' is a bitmask of JS_PROP_NO_ADD, JS_PROP_THROW or JS_PROP_THROW_STRICT. If JS_PROP_NO_ADD is set, the new property is not added and an error is raised. */ -int JS_SetPropertyInternal(JSContext *ctx, JSValueConst this_obj, - JSAtom prop, JSValue val, int flags, - JSInlineCache *ic) +int JS_SetPropertyInternal2(JSContext *ctx, JSValueConst this_obj, + JSAtom prop, JSValue val, int flags, + JSInlineCache *ic) { JSObject *p, *p1; JSShapeProperty *prs; @@ -8531,6 +8539,12 @@ int JS_SetPropertyInternal(JSContext *ctx, JSValueConst this_obj, return TRUE; } +int JS_SetPropertyInternal(JSContext *ctx, JSValueConst this_obj, + JSAtom prop, JSValue val, int flags) +{ + return JS_SetPropertyInternal2(ctx, this_obj, prop, val, flags, NULL); +} + static force_inline int JS_SetPropertyInternalWithIC(JSContext *ctx, JSValueConst this_obj, JSAtom prop, JSValue val, int flags, JSInlineCache *ic, int32_t offset) { @@ -8546,7 +8560,7 @@ static force_inline int JS_SetPropertyInternalWithIC(JSContext *ctx, JSValueCons return TRUE; } slow_path: - return JS_SetPropertyInternal(ctx, this_obj, prop, val, flags, ic); + return JS_SetPropertyInternal2(ctx, this_obj, prop, val, flags, ic); } /* flags can be JS_PROP_THROW or JS_PROP_THROW_STRICT */ @@ -8673,7 +8687,7 @@ static int JS_SetPropertyValue(JSContext *ctx, JSValueConst this_obj, JS_FreeValue(ctx, val); return -1; } - ret = JS_SetPropertyInternal(ctx, this_obj, atom, val, flags, NULL); + ret = JS_SetPropertyInternal(ctx, this_obj, atom, val, flags); JS_FreeAtom(ctx, atom); return ret; } @@ -8713,7 +8727,7 @@ int JS_SetPropertyStr(JSContext *ctx, JSValueConst this_obj, JSAtom atom; int ret; atom = JS_NewAtom(ctx, prop); - ret = JS_SetPropertyInternal(ctx, this_obj, atom, val, JS_PROP_THROW, NULL); + ret = JS_SetPropertyInternal(ctx, this_obj, atom, val, JS_PROP_THROW); JS_FreeAtom(ctx, atom); return ret; } @@ -9470,7 +9484,7 @@ static JSValue JS_GetGlobalVar(JSContext *ctx, JSAtom prop, return JS_DupValue(ctx, pr->u.value); } return JS_GetPropertyInternal(ctx, ctx->global_obj, prop, - ctx->global_obj, NULL, throw_ref_error); + ctx->global_obj, throw_ref_error); } /* construct a reference to a global variable */ @@ -9564,7 +9578,7 @@ static int JS_SetGlobalVar(JSContext *ctx, JSAtom prop, JSValue val, flags = JS_PROP_THROW_STRICT; if (is_strict_mode(ctx)) flags |= JS_PROP_NO_ADD; - return JS_SetPropertyInternal(ctx, ctx->global_obj, prop, val, flags, NULL); + return JS_SetPropertyInternal(ctx, ctx->global_obj, prop, val, flags); } /* return -1, FALSE or TRUE. return FALSE if not configurable or @@ -13270,7 +13284,7 @@ static JSValue build_for_in_iterator(JSContext *ctx, JSValue obj) JS_GPN_STRING_MASK | JS_GPN_ENUM_ONLY)) goto fail; for(i = 0; i < tab_atom_count; i++) { - JS_SetPropertyInternal(ctx, enum_obj, tab_atom[i].atom, JS_NULL, 0, NULL); + JS_SetPropertyInternal(ctx, enum_obj, tab_atom[i].atom, JS_NULL, 0); } js_free_prop_enum(ctx, tab_atom, tab_atom_count); } @@ -15655,7 +15669,7 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj, JSAtom atom; atom = get_u32(pc); pc += 4; - val = JS_GetPropertyInternal(ctx, sp[-1], atom, sp[-1], ic, FALSE); + val = JS_GetPropertyInternal2(ctx, sp[-1], atom, sp[-1], ic, FALSE); if (unlikely(JS_IsException(val))) goto exception; if (ic && ic->updated == TRUE) { @@ -15691,7 +15705,7 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj, JSAtom atom; atom = get_u32(pc); pc += 4; - val = JS_GetPropertyInternal(ctx, sp[-1], atom, sp[-1], NULL, FALSE); + val = JS_GetPropertyInternal2(ctx, sp[-1], atom, sp[-1], NULL, FALSE); if (unlikely(JS_IsException(val))) goto exception; if (ic != NULL && ic->updated == TRUE) { @@ -15726,7 +15740,7 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj, JSAtom atom; atom = get_u32(pc); pc += 4; - ret = JS_SetPropertyInternal(ctx, sp[-2], atom, sp[-1], JS_PROP_THROW_STRICT, ic); + ret = JS_SetPropertyInternal2(ctx, sp[-2], atom, sp[-1], JS_PROP_THROW_STRICT, ic); JS_FreeValue(ctx, sp[-2]); sp -= 2; if (unlikely(ret < 0)) @@ -15985,7 +15999,7 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj, atom = JS_ValueToAtom(ctx, sp[-1]); if (unlikely(atom == JS_ATOM_NULL)) goto exception; - val = JS_GetPropertyInternal(ctx, sp[-2], atom, sp[-3], NULL, FALSE); + val = JS_GetPropertyInternal2(ctx, sp[-2], atom, sp[-3], NULL, FALSE); JS_FreeAtom(ctx, atom); if (unlikely(JS_IsException(val))) goto exception; @@ -16666,7 +16680,7 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj, case OP_with_put_var: /* XXX: check if strict mode */ ret = JS_SetPropertyInternal(ctx, obj, atom, sp[-2], - JS_PROP_THROW_STRICT, NULL); + JS_PROP_THROW_STRICT); JS_FreeValue(ctx, sp[-1]); sp -= 2; if (unlikely(ret < 0)) @@ -42660,7 +42674,7 @@ static JSValue js_reflect_get(JSContext *ctx, JSValueConst this_val, atom = JS_ValueToAtom(ctx, prop); if (unlikely(atom == JS_ATOM_NULL)) return JS_EXCEPTION; - ret = JS_GetPropertyInternal(ctx, obj, atom, receiver, NULL, FALSE); + ret = JS_GetPropertyInternal(ctx, obj, atom, receiver, FALSE); JS_FreeAtom(ctx, atom); return ret; } @@ -43008,7 +43022,7 @@ static JSValue js_proxy_get(JSContext *ctx, JSValueConst obj, JSAtom atom, return JS_EXCEPTION; /* Note: recursion is possible thru the prototype of s->target */ if (JS_IsUndefined(method)) - return JS_GetPropertyInternal(ctx, s->target, atom, receiver, NULL, FALSE); + return JS_GetPropertyInternal(ctx, s->target, atom, receiver, FALSE); atom_val = JS_AtomToValue(ctx, atom); if (JS_IsException(atom_val)) { JS_FreeValue(ctx, method); diff --git a/quickjs.h b/quickjs.h index a20eeebda..e3940ba81 100644 --- a/quickjs.h +++ b/quickjs.h @@ -684,11 +684,11 @@ typedef struct JSInlineCache JSInlineCache; JS_EXTERN JSValue JS_GetPropertyInternal(JSContext *ctx, JSValueConst obj, JSAtom prop, JSValueConst receiver, - JSInlineCache *ic, JS_BOOL throw_ref_error); + JS_BOOL throw_ref_error); static js_force_inline JSValue JS_GetProperty(JSContext *ctx, JSValueConst this_obj, JSAtom prop) { - return JS_GetPropertyInternal(ctx, this_obj, prop, this_obj, NULL, 0); + return JS_GetPropertyInternal(ctx, this_obj, prop, this_obj, 0); } JS_EXTERN JSValue JS_GetPropertyStr(JSContext *ctx, JSValueConst this_obj, const char *prop); @@ -697,11 +697,11 @@ JS_EXTERN JSValue JS_GetPropertyUint32(JSContext *ctx, JSValueConst this_obj, int JS_SetPropertyInternal(JSContext *ctx, JSValueConst this_obj, JSAtom prop, JSValue val, - int flags, JSInlineCache *ic); + int flags); static inline int JS_SetProperty(JSContext *ctx, JSValueConst this_obj, JSAtom prop, JSValue val) { - return JS_SetPropertyInternal(ctx, this_obj, prop, val, JS_PROP_THROW, NULL); + return JS_SetPropertyInternal(ctx, this_obj, prop, val, JS_PROP_THROW); } JS_EXTERN int JS_SetPropertyUint32(JSContext *ctx, JSValueConst this_obj, uint32_t idx, JSValue val); From ed0005cb9b0392a866891a6d8242175841945930 Mon Sep 17 00:00:00 2001 From: Divy Srivastava Date: Tue, 28 Nov 2023 22:07:24 +0530 Subject: [PATCH 14/17] Fix fmt --- quickjs.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/quickjs.h b/quickjs.h index e3940ba81..07906219b 100644 --- a/quickjs.h +++ b/quickjs.h @@ -683,8 +683,8 @@ JS_EXTERN JSValue JS_NewDate(JSContext *ctx, double epoch_ms); typedef struct JSInlineCache JSInlineCache; JS_EXTERN JSValue JS_GetPropertyInternal(JSContext *ctx, JSValueConst obj, - JSAtom prop, JSValueConst receiver, - JS_BOOL throw_ref_error); + JSAtom prop, JSValueConst receiver, + JS_BOOL throw_ref_error); static js_force_inline JSValue JS_GetProperty(JSContext *ctx, JSValueConst this_obj, JSAtom prop) { From 5fd4765bf7d27232c6e6a1e15c1e8e7f4bd505b7 Mon Sep 17 00:00:00 2001 From: Divy Srivastava Date: Tue, 28 Nov 2023 22:08:10 +0530 Subject: [PATCH 15/17] Update header --- quickjs.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/quickjs.h b/quickjs.h index 07906219b..b018badd6 100644 --- a/quickjs.h +++ b/quickjs.h @@ -680,8 +680,6 @@ JS_EXTERN int JS_IsArray(JSContext *ctx, JSValueConst val); JS_EXTERN JSValue JS_NewDate(JSContext *ctx, double epoch_ms); -typedef struct JSInlineCache JSInlineCache; - JS_EXTERN JSValue JS_GetPropertyInternal(JSContext *ctx, JSValueConst obj, JSAtom prop, JSValueConst receiver, JS_BOOL throw_ref_error); From f78616699ca73e50137ed62bcec813a92fab6591 Mon Sep 17 00:00:00 2001 From: Divy Srivastava Date: Wed, 29 Nov 2023 10:57:12 +0530 Subject: [PATCH 16/17] review changes --- quickjs.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/quickjs.c b/quickjs.c index 81e34e7be..76e0485d4 100644 --- a/quickjs.c +++ b/quickjs.c @@ -591,7 +591,7 @@ static uint32_t add_ic_slot(JSContext *ctx, JSInlineCache *ic, JSAtom atom, JSOb uint32_t prop_offset); static uint32_t add_ic_slot1(JSContext *ctx, JSInlineCache *ic, JSAtom atom); -static force_inline int32_t get_ic_prop_offset(JSInlineCache *ic, uint32_t cache_offset, +static int32_t get_ic_prop_offset(JSInlineCache *ic, uint32_t cache_offset, JSShape *shape) { uint32_t i; @@ -7088,7 +7088,7 @@ JSValue JS_GetPropertyInternal(JSContext *ctx, JSValueConst obj, } -static force_inline JSValue JS_GetPropertyInternalWithIC(JSContext *ctx, JSValueConst obj, +static JSValue JS_GetPropertyInternalWithIC(JSContext *ctx, JSValueConst obj, JSAtom prop, JSValueConst this_obj, JSInlineCache *ic, int32_t offset, BOOL throw_ref_error) @@ -8545,7 +8545,7 @@ int JS_SetPropertyInternal(JSContext *ctx, JSValueConst this_obj, return JS_SetPropertyInternal2(ctx, this_obj, prop, val, flags, NULL); } -static force_inline int JS_SetPropertyInternalWithIC(JSContext *ctx, JSValueConst this_obj, +static int JS_SetPropertyInternalWithIC(JSContext *ctx, JSValueConst this_obj, JSAtom prop, JSValue val, int flags, JSInlineCache *ic, int32_t offset) { uint32_t tag; @@ -51112,7 +51112,7 @@ uint32_t add_ic_slot1(JSContext *ctx, JSInlineCache *ic, JSAtom atom) for (ch = ic->hash[h]; ch != NULL; ch = ch->next) if (ch->atom == atom) goto end; - ch = js_malloc(ctx, sizeof(JSInlineCacheHashSlot)); + ch = js_malloc(ctx, sizeof(*ch)); if (unlikely(!ch)) goto end; ch->atom = JS_DupAtom(ctx, atom); From 9bc9e08c39cef81fa944e86194e30664e9b917e2 Mon Sep 17 00:00:00 2001 From: Divy Srivastava Date: Wed, 29 Nov 2023 10:59:26 +0530 Subject: [PATCH 17/17] format --- quickjs.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/quickjs.c b/quickjs.c index 76e0485d4..671fe01f8 100644 --- a/quickjs.c +++ b/quickjs.c @@ -592,7 +592,7 @@ static uint32_t add_ic_slot(JSContext *ctx, JSInlineCache *ic, JSAtom atom, JSOb static uint32_t add_ic_slot1(JSContext *ctx, JSInlineCache *ic, JSAtom atom); static int32_t get_ic_prop_offset(JSInlineCache *ic, uint32_t cache_offset, - JSShape *shape) + JSShape *shape) { uint32_t i; JSInlineCacheRingSlot *cr; @@ -7089,9 +7089,9 @@ JSValue JS_GetPropertyInternal(JSContext *ctx, JSValueConst obj, static JSValue JS_GetPropertyInternalWithIC(JSContext *ctx, JSValueConst obj, - JSAtom prop, JSValueConst this_obj, - JSInlineCache *ic, int32_t offset, - BOOL throw_ref_error) + JSAtom prop, JSValueConst this_obj, + JSInlineCache *ic, int32_t offset, + BOOL throw_ref_error) { uint32_t tag; JSObject *p; @@ -8540,14 +8540,14 @@ int JS_SetPropertyInternal2(JSContext *ctx, JSValueConst this_obj, } int JS_SetPropertyInternal(JSContext *ctx, JSValueConst this_obj, - JSAtom prop, JSValue val, int flags) + JSAtom prop, JSValue val, int flags) { return JS_SetPropertyInternal2(ctx, this_obj, prop, val, flags, NULL); } static int JS_SetPropertyInternalWithIC(JSContext *ctx, JSValueConst this_obj, - JSAtom prop, JSValue val, int flags, - JSInlineCache *ic, int32_t offset) { + JSAtom prop, JSValue val, int flags, + JSInlineCache *ic, int32_t offset) { uint32_t tag; JSObject *p; tag = JS_VALUE_GET_TAG(this_obj);