diff --git a/src-input/duk_heap.h b/src-input/duk_heap.h index fc7bcc5ccd..6f593aaa66 100644 --- a/src-input/duk_heap.h +++ b/src-input/duk_heap.h @@ -304,7 +304,7 @@ struct duk_propcache_entry { /* All references are borrowed. */ duk_hobject *obj_lookup; duk_hstring *key_lookup; - duk_tval value; + duk_tval *val_storage; duk_uint32_t generation; }; diff --git a/src-input/duk_heap_propcache.c b/src-input/duk_heap_propcache.c index cc1b5bbf65..1c24615bce 100644 --- a/src-input/duk_heap_propcache.c +++ b/src-input/duk_heap_propcache.c @@ -5,6 +5,7 @@ DUK_LOCAL DUK_NOINLINE void duk__propcache_scrub(duk_heap *heap) { * to zero, and the generation count is then bumped once more * to one to invalidate the scrubbed entries. */ + DUK_D(DUK_DPRINT("INVALIDATE propcache")); DUK_MEMZERO((void *) heap->propcache, sizeof(heap->propcache)); heap->propcache_generation++; } @@ -33,10 +34,15 @@ DUK_INTERNAL duk_tval *duk_propcache_lookup(duk_hthread *thr, duk_hobject *obj, prophash = duk__compute_prophash(obj, key); ent = thr->heap->propcache + prophash; + DUK_D(DUK_DPRINT("lookup, prophash %lu, gen %lu, ent->gen %lu, ent->obj %p, ent->key %p, ent->val %p", + (unsigned long) prophash, (unsigned long) thr->heap->propcache_generation, + (unsigned long) ent->generation, (void *) ent->obj_lookup, + (void *) ent->key_lookup, (void *) ent->val_storage)); + if (ent->generation == thr->heap->propcache_generation && ent->obj_lookup == obj && ent->key_lookup == key) { - return &ent->value; + return ent->val_storage; /* Storage location. */ } return NULL; @@ -51,5 +57,5 @@ DUK_INTERNAL void duk_propcache_insert(duk_hthread *thr, duk_hobject *obj, duk_h ent->generation = thr->heap->propcache_generation; ent->obj_lookup = obj; ent->key_lookup = key; - DUK_TVAL_SET_TVAL(&ent->value, tv); + ent->val_storage = tv; } diff --git a/src-input/duk_hobject_props.c b/src-input/duk_hobject_props.c index 84920b4726..a5f7ea246f 100644 --- a/src-input/duk_hobject_props.c +++ b/src-input/duk_hobject_props.c @@ -570,6 +570,9 @@ DUK_INTERNAL void duk_hobject_realloc_props(duk_hthread *thr, DUK_ASSERT(!DUK_HEAPHDR_HAS_READONLY((duk_heaphdr *) obj)); DUK_ASSERT_VALSTACK_SPACE(thr, DUK__VALSTACK_SPACE); + /* Invalidate property cache. FIXME: also at the end? */ + duk_propcache_invalidate(thr); + /* * Pre resize assertions. */ @@ -2668,10 +2671,11 @@ DUK_INTERNAL duk_bool_t duk_hobject_getprop(duk_hthread *thr, duk_tval *tv_obj, */ duk_tval *storage; storage = duk_propcache_lookup(thr, curr, key); + DUK_D(DUK_DPRINT("propcache GETPROP lookup: %!O %!O -> %p", orig_base, key, (void *) storage)); if (storage) { - DUK_D(DUK_DPRINT("cached lookup %!O -> %!T", key, storage)); - duk_pop(ctx); + DUK_D(DUK_DPRINT("cached GETPROP lookup %!O -> %!T", key, storage)); duk_push_tval(ctx, storage); + duk_remove(ctx, -2); /* FIXME: careful with order */ /* FIXME: assume no post process? */ return 1; } @@ -2802,9 +2806,13 @@ DUK_INTERNAL duk_bool_t duk_hobject_getprop(duk_hthread *thr, duk_tval *tv_obj, } #endif /* !DUK_USE_NONSTD_FUNC_CALLER_PROPERTY */ - if (orig_base && arr_idx == DUK__NO_ARRAY_INDEX) { /* FIXME: condition */ + if (orig_base && arr_idx == DUK__NO_ARRAY_INDEX && desc.e_idx >= 0) { /* FIXME: condition */ /* FIXME: other conditions, e.g. not a getter */ - duk_propcache_insert(thr, orig_base, key, DUK_GET_TVAL_NEGIDX(ctx, -1)); + /* FIXME: note that caching is based on orig_base, but storage location is in 'curr'! */ + duk_tval *tv_storage; + tv_storage = DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(thr->heap, curr, desc.e_idx); + DUK_D(DUK_DPRINT("insert propcache GETPROP %!O", key)); + duk_propcache_insert(thr, orig_base, key, tv_storage); } duk_remove_m2(ctx); /* [key result] -> [result] */ @@ -3338,6 +3346,7 @@ DUK_INTERNAL duk_bool_t duk_hobject_putprop(duk_hthread *thr, duk_tval *tv_obj, duk_tval tv_key_copy; duk_tval tv_val_copy; duk_hobject *orig = NULL; /* NULL if tv_obj is primitive */ + duk_hobject *orig_base; duk_hobject *curr; duk_hstring *key = NULL; duk_propdesc desc; @@ -3362,7 +3371,12 @@ DUK_INTERNAL duk_bool_t duk_hobject_putprop(duk_hthread *thr, duk_tval *tv_obj, DUK_ASSERT_VALSTACK_SPACE(thr, DUK__VALSTACK_SPACE); + /* FIXME... with storage location caching, only need to invalidate + * if new properties are established (may shadow existing chains)? + */ +#if 0 duk_propcache_invalidate(thr); +#endif /* * Make a copy of tv_obj, tv_key, and tv_val to avoid any issues of @@ -3664,6 +3678,23 @@ DUK_INTERNAL duk_bool_t duk_hobject_putprop(duk_hthread *thr, duk_tval *tv_obj, lookup: + DUK_ASSERT(curr != NULL); + orig_base = curr; + + { + /* FIXME: when base is primitive, we cache the "wrong" property, + * which is fine. + */ + duk_tval *storage; + storage = duk_propcache_lookup(thr, orig_base, key); + DUK_D(DUK_DPRINT("propcache PUTPROP lookup: %!O %!O -> %p", orig_base, key, (void *) storage)); + if (storage) { + DUK_D(DUK_DPRINT("cached PUTPROP lookup %!O -> old value %!T", key, storage)); + DUK_TVAL_SET_TVAL_UPDREF(thr, storage, tv_val); + goto success_no_arguments_exotic; + } + } + /* * Check whether the property already exists in the prototype chain. * Note that the actual write goes into the original base object @@ -3888,6 +3919,14 @@ DUK_INTERNAL duk_bool_t duk_hobject_putprop(duk_hthread *thr, duk_tval *tv_obj, if (desc.e_idx >= 0) { tv = DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(thr->heap, orig, desc.e_idx); + + /* FIXME argument exotic condition... */ + if (1) { /* FIXME: condition */ + /* FIXME: other conditions, e.g. not a getter */ + DUK_D(DUK_DPRINT("insert propcache PUTPROP %!O", key)); + duk_propcache_insert(thr, orig_base, key, tv); + } + DUK_DDD(DUK_DDDPRINT("previous entry value: %!iT", (duk_tval *) tv)); DUK_TVAL_SET_TVAL_UPDREF(thr, tv, tv_val); /* side effects; e_idx may be invalidated */ /* don't touch property attributes or hash part */ @@ -4090,6 +4129,12 @@ DUK_INTERNAL duk_bool_t duk_hobject_putprop(duk_hthread *thr, duk_tval *tv_obj, write_to_entry_part: + /* Must invalidate: new property may affect existing inheritance + * chains. + */ + duk_propcache_invalidate(thr); + + /* * Write to entry part */