Skip to content

Commit

Permalink
Implement initial version of property caching
Browse files Browse the repository at this point in the history
  • Loading branch information
svaarala committed Feb 12, 2017
1 parent ca6fd8c commit bf577a6
Show file tree
Hide file tree
Showing 10 changed files with 150 additions and 12 deletions.
10 changes: 10 additions & 0 deletions src-input/duk_bi_array.c
Original file line number Diff line number Diff line change
Expand Up @@ -419,6 +419,11 @@ DUK_LOCAL duk_ret_t duk__array_pop_fastpath(duk_context *ctx, duk_harray *h_arr)
return 0;
}

/* Index properties are not cached but .length is, so invalidate
* property cache.
*/
duk_propcache_invalidate(thr);

len--;
h_arr->length = len;

Expand Down Expand Up @@ -508,6 +513,11 @@ DUK_LOCAL duk_ret_t duk__array_push_fastpath(duk_context *ctx, duk_harray *h_arr
return 0;
}

/* Index properties are not cached but .length is, so invalidate
* property cache.
*/
duk_propcache_invalidate(thr);

tv_src = thr->valstack_bottom;
tv_dst = tv_arraypart + len;
for (i = 0; i < n; i++) {
Expand Down
6 changes: 4 additions & 2 deletions src-input/duk_forwdecl.h
Original file line number Diff line number Diff line change
Expand Up @@ -42,9 +42,10 @@ struct duk_breakpoint;

struct duk_activation;
struct duk_catcher;
struct duk_strcache;
struct duk_strcache_entry;
struct duk_ljstate;
struct duk_strtab_entry;
struct duk_propcache_entry;

#if defined(DUK_USE_DEBUG)
struct duk_fixedbuffer;
Expand Down Expand Up @@ -100,9 +101,10 @@ typedef struct duk_breakpoint duk_breakpoint;

typedef struct duk_activation duk_activation;
typedef struct duk_catcher duk_catcher;
typedef struct duk_strcache duk_strcache;
typedef struct duk_strcache_entry duk_strcache_entry;
typedef struct duk_ljstate duk_ljstate;
typedef struct duk_strtab_entry duk_strtab_entry;
typedef struct duk_propcache_entry duk_propcache_entry;

#if defined(DUK_USE_DEBUG)
typedef struct duk_fixedbuffer duk_fixedbuffer;
Expand Down
28 changes: 26 additions & 2 deletions src-input/duk_heap.h
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,9 @@
#define DUK_HEAP_STRCACHE_SIZE 4
#define DUK_HEAP_STRINGCACHE_NOCACHE_LIMIT 16 /* strings up to the this length are not cached */

/* Propache is used for speeding up property accesses. */
#define DUK_HEAP_PROPCACHE_SIZE 4096

/* helper to insert a (non-string) heap object into heap allocated list */
#define DUK_HEAP_INSERT_INTO_HEAP_ALLOCATED(heap,hdr) duk_heap_insert_into_heap_allocated((heap),(hdr))

Expand Down Expand Up @@ -290,12 +293,24 @@ struct duk_breakpoint {
* Thus, string caches are now at the heap level now.
*/

struct duk_strcache {
struct duk_strcache_entry {
duk_hstring *h;
duk_uint32_t bidx;
duk_uint32_t cidx;
};

/*
* Property cache
*/

struct duk_propcache_entry {
/* All references are borrowed. */
duk_hobject *obj_lookup;
duk_hstring *key_lookup;
duk_tval value;
duk_uint32_t generation;
};

/*
* Longjmp state, contains the information needed to perform a longjmp.
* Longjmp related values are written to value1, value2, and iserror.
Expand Down Expand Up @@ -463,7 +478,11 @@ struct duk_heap {
/* string access cache (codepoint offset -> byte offset) for fast string
* character looping; 'weak' reference which needs special handling in GC.
*/
duk_strcache strcache[DUK_HEAP_STRCACHE_SIZE];
duk_strcache_entry strcache[DUK_HEAP_STRCACHE_SIZE];

/* Property access cache. */
duk_propcache_entry propcache[DUK_HEAP_PROPCACHE_SIZE];
duk_uint32_t propcache_generation;

/* built-in strings */
#if defined(DUK_USE_ROM_STRINGS)
Expand Down Expand Up @@ -566,4 +585,9 @@ DUK_INTERNAL_DECL duk_bool_t duk_heap_mark_and_sweep(duk_heap *heap, duk_small_u

DUK_INTERNAL_DECL duk_uint32_t duk_heap_hashstring(duk_heap *heap, const duk_uint8_t *str, duk_size_t len);

DUK_INTERNAL_DECL void duk_propcache_invalidate_heap(duk_heap *heap);
DUK_INTERNAL_DECL void duk_propcache_invalidate(duk_hthread *thr);
DUK_INTERNAL_DECL duk_tval *duk_propcache_lookup(duk_hthread *thr, duk_hobject *obj, duk_hstring *key);
DUK_INTERNAL_DECL void duk_propcache_insert(duk_hthread *thr, duk_hobject *obj, duk_hstring *key, duk_tval *storage);

#endif /* DUK_HEAP_H_INCLUDED */
7 changes: 6 additions & 1 deletion src-input/duk_heap_alloc.c
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,9 @@ DUK_INTERNAL void duk_free_hobject(duk_heap *heap, duk_hobject *h) {
DUK_ASSERT(heap != NULL);
DUK_ASSERT(h != NULL);

/* FIXME: heap ref only */
duk_propcache_invalidate_heap(heap);

DUK_FREE(heap, DUK_HOBJECT_GET_PROPS(heap, h));

if (DUK_HOBJECT_IS_COMPFUNC(h)) {
Expand Down Expand Up @@ -594,7 +597,8 @@ DUK_LOCAL void duk__dump_type_sizes(void) {
DUK__DUMPSZ(duk_heap);
DUK__DUMPSZ(duk_activation);
DUK__DUMPSZ(duk_catcher);
DUK__DUMPSZ(duk_strcache);
DUK__DUMPSZ(duk_strcache_entry);
DUK__DUMPSZ(duk_propcache_entry);
DUK__DUMPSZ(duk_ljstate);
DUK__DUMPSZ(duk_fixedbuffer);
DUK__DUMPSZ(duk_bitdecoder_ctx);
Expand Down Expand Up @@ -826,6 +830,7 @@ duk_heap *duk_heap_alloc(duk_alloc_function alloc_func,
}
#endif
#endif /* DUK_USE_ROM_STRINGS */
res->propcache_generation = 1; /* invalidate entries with 0 generation */
#if defined(DUK_USE_DEBUGGER_SUPPORT)
res->dbg_read_cb = NULL;
res->dbg_write_cb = NULL;
Expand Down
2 changes: 2 additions & 0 deletions src-input/duk_heap_markandsweep.c
Original file line number Diff line number Diff line change
Expand Up @@ -1129,6 +1129,8 @@ DUK_INTERNAL duk_bool_t duk_heap_mark_and_sweep(duk_heap *heap, duk_small_uint_t
}
#endif

/* FIXME: property cache invalidation or comment why not needed. */

DUK_D(DUK_DPRINT("garbage collect (mark-and-sweep) starting, requested flags: 0x%08lx, effective flags: 0x%08lx",
(unsigned long) flags, (unsigned long) (flags | heap->mark_and_sweep_base_flags)));

Expand Down
55 changes: 55 additions & 0 deletions src-input/duk_heap_propcache.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
#include "duk_internal.h"

DUK_LOCAL DUK_NOINLINE void duk__propcache_scrub(duk_heap *heap) {
/* Explicit scrub to avoid reuse. Generation counts are set
* to zero, and the generation count is then bumped once more
* to one to invalidate the scrubbed entries.
*/
DUK_MEMZERO((void *) heap->propcache, sizeof(heap->propcache));
heap->propcache_generation++;
}

DUK_INTERNAL DUK_ALWAYS_INLINE void duk_propcache_invalidate_heap(duk_heap *heap) {
if (DUK_UNLIKELY(++heap->propcache_generation == 0)) {
duk__propcache_scrub(heap);
}
}

DUK_INTERNAL DUK_ALWAYS_INLINE void duk_propcache_invalidate(duk_hthread *thr) {
duk_propcache_invalidate_heap(thr->heap);
}

DUK_LOCAL duk_size_t duk__compute_prophash(duk_hobject *obj, duk_hstring *key) {
duk_size_t prophash;
prophash = ((duk_size_t) obj) ^ ((duk_size_t) DUK_HSTRING_GET_HASH(key));
prophash = prophash % DUK_HEAP_PROPCACHE_SIZE; /* FIXME: force to be a mask */
return prophash;
}

DUK_INTERNAL duk_tval *duk_propcache_lookup(duk_hthread *thr, duk_hobject *obj, duk_hstring *key) {
duk_size_t prophash;
duk_propcache_entry *ent;

prophash = duk__compute_prophash(obj, key);
ent = thr->heap->propcache + prophash;

if (ent->generation == thr->heap->propcache_generation &&
ent->obj_lookup == obj &&
ent->key_lookup == key) {
return &ent->value;
}

return NULL;
}

DUK_INTERNAL void duk_propcache_insert(duk_hthread *thr, duk_hobject *obj, duk_hstring *key, duk_tval *tv) {
duk_size_t prophash;
duk_propcache_entry *ent;

prophash = duk__compute_prophash(obj, key);
ent = thr->heap->propcache + prophash;
ent->generation = thr->heap->propcache_generation;
ent->obj_lookup = obj;
ent->key_lookup = key;
DUK_TVAL_SET_TVAL(&ent->value, tv);
}
12 changes: 6 additions & 6 deletions src-input/duk_heap_stringcache.c
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
DUK_INTERNAL void duk_heap_strcache_string_remove(duk_heap *heap, duk_hstring *h) {
duk_small_int_t i;
for (i = 0; i < DUK_HEAP_STRCACHE_SIZE; i++) {
duk_strcache *c = heap->strcache + i;
duk_strcache_entry *c = heap->strcache + i;
if (c->h == h) {
DUK_DD(DUK_DDPRINT("deleting weak strcache reference to hstring %p from heap %p",
(void *) h, (void *) heap));
Expand Down Expand Up @@ -92,7 +92,7 @@ DUK_LOCAL const duk_uint8_t *duk__scan_backwards(const duk_uint8_t *p, const duk

DUK_INTERNAL duk_uint_fast32_t duk_heap_strcache_offset_char2byte(duk_hthread *thr, duk_hstring *h, duk_uint_fast32_t char_offset) {
duk_heap *heap;
duk_strcache *sce;
duk_strcache_entry *sce;
duk_uint_fast32_t byte_offset;
duk_small_int_t i;
duk_bool_t use_cache;
Expand Down Expand Up @@ -145,14 +145,14 @@ DUK_INTERNAL duk_uint_fast32_t duk_heap_strcache_offset_char2byte(duk_hthread *t
#if defined(DUK_USE_DEBUG_LEVEL) && (DUK_USE_DEBUG_LEVEL >= 2)
DUK_DDD(DUK_DDDPRINT("stringcache before char2byte (using cache):"));
for (i = 0; i < DUK_HEAP_STRCACHE_SIZE; i++) {
duk_strcache *c = heap->strcache + i;
duk_strcache_entry *c = heap->strcache + i;
DUK_DDD(DUK_DDDPRINT(" [%ld] -> h=%p, cidx=%ld, bidx=%ld",
(long) i, (void *) c->h, (long) c->cidx, (long) c->bidx));
}
#endif

for (i = 0; i < DUK_HEAP_STRCACHE_SIZE; i++) {
duk_strcache *c = heap->strcache + i;
duk_strcache_entry *c = heap->strcache + i;

if (c->h == h) {
sce = c;
Expand Down Expand Up @@ -281,7 +281,7 @@ DUK_INTERNAL duk_uint_fast32_t duk_heap_strcache_offset_char2byte(duk_hthread *t
* C <- sce ==> B
* D D
*/
duk_strcache tmp;
duk_strcache_entry tmp;

tmp = *sce;
DUK_MEMMOVE((void *) (&heap->strcache[1]),
Expand All @@ -294,7 +294,7 @@ DUK_INTERNAL duk_uint_fast32_t duk_heap_strcache_offset_char2byte(duk_hthread *t
#if defined(DUK_USE_DEBUG_LEVEL) && (DUK_USE_DEBUG_LEVEL >= 2)
DUK_DDD(DUK_DDDPRINT("stringcache after char2byte (using cache):"));
for (i = 0; i < DUK_HEAP_STRCACHE_SIZE; i++) {
duk_strcache *c = heap->strcache + i;
duk_strcache_entry *c = heap->strcache + i;
DUK_DDD(DUK_DDDPRINT(" [%ld] -> h=%p, cidx=%ld, bidx=%ld",
(long) i, (void *) c->h, (long) c->cidx, (long) c->bidx));
}
Expand Down
3 changes: 2 additions & 1 deletion src-input/duk_hobject.h
Original file line number Diff line number Diff line change
Expand Up @@ -622,6 +622,7 @@
#define DUK_HOBJECT_GET_PROTOTYPE(heap,h) \
((duk_hobject *) DUK_USE_HEAPPTR_DEC16((heap)->heap_udata, (h)->prototype16))
#define DUK_HOBJECT_SET_PROTOTYPE(heap,h,x) do { \
/* FIXME: caller property invalidation */ \
(h)->prototype16 = DUK_USE_HEAPPTR_ENC16((heap)->heap_udata, (void *) (x)); \
} while (0)
#else
Expand All @@ -632,7 +633,7 @@
} while (0)
#endif

/* note: this updates refcounts */
/* This updates refcounts and automatically invalidates property cache. */
#define DUK_HOBJECT_SET_PROTOTYPE_UPDREF(thr,h,p) duk_hobject_set_prototype_updref((thr), (h), (p))

/*
Expand Down
2 changes: 2 additions & 0 deletions src-input/duk_hobject_misc.c
Original file line number Diff line number Diff line change
Expand Up @@ -43,10 +43,12 @@ DUK_INTERNAL void duk_hobject_set_prototype_updref(duk_hthread *thr, duk_hobject
tmp = DUK_HOBJECT_GET_PROTOTYPE(thr->heap, h);
DUK_HOBJECT_SET_PROTOTYPE(thr->heap, h, p);
DUK_HOBJECT_INCREF_ALLOWNULL(thr, p); /* avoid problems if p == h->prototype */
duk_propcache_invalidate(thr); /* must be done just before finalizers */
DUK_HOBJECT_DECREF_ALLOWNULL(thr, tmp);
#else
DUK_ASSERT(h);
DUK_UNREF(thr);
DUK_HOBJECT_SET_PROTOTYPE(thr->heap, h, p);
duk_propcache_invalidate(thr);
#endif
}
37 changes: 37 additions & 0 deletions src-input/duk_hobject_props.c
Original file line number Diff line number Diff line change
Expand Up @@ -2302,6 +2302,7 @@ DUK_INTERNAL duk_bool_t duk_hobject_getprop(duk_hthread *thr, duk_tval *tv_obj,
duk_context *ctx = (duk_context *) thr;
duk_tval tv_obj_copy;
duk_tval tv_key_copy;
duk_hobject *orig_base;
duk_hobject *curr = NULL;
duk_hstring *key = NULL;
duk_uint32_t arr_idx = DUK__NO_ARRAY_INDEX;
Expand Down Expand Up @@ -2660,6 +2661,22 @@ DUK_INTERNAL duk_bool_t duk_hobject_getprop(duk_hthread *thr, duk_tval *tv_obj,
DUK_ASSERT(curr != NULL);
DUK_ASSERT(key != 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, curr, key);
if (storage) {
DUK_D(DUK_DPRINT("cached lookup %!O -> %!T", key, storage));
duk_pop(ctx);
duk_push_tval(ctx, storage);
/* FIXME: assume no post process? */
return 1;
}
}

sanity = DUK_HOBJECT_PROTOTYPE_CHAIN_SANITY;
do {
if (!duk__get_own_propdesc_raw(thr, curr, key, arr_idx, &desc, DUK_GETDESC_FLAG_PUSH_VALUE)) {
Expand All @@ -2670,6 +2687,9 @@ DUK_INTERNAL duk_bool_t duk_hobject_getprop(duk_hthread *thr, duk_tval *tv_obj,
/* accessor with defined getter */
DUK_ASSERT((desc.flags & DUK_PROPDESC_FLAG_ACCESSOR) != 0);

DUK_D(DUK_DPRINT("prevent caching, getter"));
orig_base = NULL;

duk_pop(ctx); /* [key undefined] -> [key] */
duk_push_hobject(ctx, desc.get);
duk_push_tval(ctx, tv_obj); /* note: original, uncoerced base */
Expand Down Expand Up @@ -2713,6 +2733,8 @@ DUK_INTERNAL duk_bool_t duk_hobject_getprop(duk_hthread *thr, duk_tval *tv_obj,
* Not found
*/

/* XXX: No negative property caching at present. */

duk_to_undefined(ctx, -1); /* [key] -> [undefined] (default value) */

DUK_DDD(DUK_DDDPRINT("-> %!T (not found)", (duk_tval *) duk_get_tval(ctx, -1)));
Expand Down Expand Up @@ -2780,6 +2802,11 @@ 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 */
/* FIXME: other conditions, e.g. not a getter */
duk_propcache_insert(thr, orig_base, key, DUK_GET_TVAL_NEGIDX(ctx, -1));
}

duk_remove_m2(ctx); /* [key result] -> [result] */

DUK_DDD(DUK_DDDPRINT("-> %!T (found)", (duk_tval *) duk_get_tval(ctx, -1)));
Expand Down Expand Up @@ -3335,6 +3362,8 @@ DUK_INTERNAL duk_bool_t duk_hobject_putprop(duk_hthread *thr, duk_tval *tv_obj,

DUK_ASSERT_VALSTACK_SPACE(thr, DUK__VALSTACK_SPACE);

duk_propcache_invalidate(thr);

/*
* Make a copy of tv_obj, tv_key, and tv_val to avoid any issues of
* them being invalidated by a valstack resize.
Expand Down Expand Up @@ -4233,6 +4262,8 @@ DUK_INTERNAL duk_bool_t duk_hobject_delprop_raw(duk_hthread *thr, duk_hobject *o
duk_bool_t throw_flag;
duk_bool_t force_flag;

duk_propcache_invalidate(thr);

throw_flag = (flags & DUK_DELPROP_FLAG_THROW);
force_flag = (flags & DUK_DELPROP_FLAG_FORCE);

Expand Down Expand Up @@ -4597,6 +4628,8 @@ DUK_INTERNAL void duk_hobject_define_property_internal(duk_hthread *thr, duk_hob
duk_tval *tv2 = NULL;
duk_small_uint_t propflags = flags & DUK_PROPDESC_FLAGS_MASK; /* mask out flags not actually stored */

duk_propcache_invalidate(thr);

DUK_DDD(DUK_DDDPRINT("define new property (internal): thr=%p, obj=%!O, key=%!O, flags=0x%02lx, val=%!T",
(void *) thr, (duk_heaphdr *) obj, (duk_heaphdr *) key,
(unsigned long) flags, (duk_tval *) duk_get_tval(ctx, -1)));
Expand Down Expand Up @@ -4718,6 +4751,8 @@ DUK_INTERNAL void duk_hobject_define_property_internal_arridx(duk_hthread *thr,
duk_hstring *key;
duk_tval *tv1, *tv2;

duk_propcache_invalidate(thr);

DUK_DDD(DUK_DDDPRINT("define new property (internal) arr_idx fast path: thr=%p, obj=%!O, "
"arr_idx=%ld, flags=0x%02lx, val=%!T",
(void *) thr, obj, (long) arr_idx, (unsigned long) flags,
Expand Down Expand Up @@ -5059,6 +5094,8 @@ duk_bool_t duk_hobject_define_property_helper(duk_context *ctx,

DUK_ASSERT_VALSTACK_SPACE(thr, DUK__VALSTACK_SPACE);

duk_propcache_invalidate(thr);

/* All the flags fit in 16 bits, so will fit into duk_bool_t. */

has_writable = (defprop_flags & DUK_DEFPROP_HAVE_WRITABLE);
Expand Down

0 comments on commit bf577a6

Please sign in to comment.