From f1a237d682a116ebbbb995637c16d14b10f69257 Mon Sep 17 00:00:00 2001 From: Piotr Caban Date: Fri, 2 Sep 2011 12:24:25 +0200 Subject: [PATCH] jscript: Use hash table when accessing object properties by name. --- dlls/jscript/dispex.c | 168 +++++++++++++++++++++++++++++++----------- 1 file changed, 124 insertions(+), 44 deletions(-) diff --git a/dlls/jscript/dispex.c b/dlls/jscript/dispex.c index 3a0eabf1d6d..b80f6f2fdff 100644 --- a/dlls/jscript/dispex.c +++ b/dlls/jscript/dispex.c @@ -31,6 +31,7 @@ static const IID IID_IDispatchJS = {0x719c3050,0xf9d3,0x11cf,{0xa4,0x93,0x00,0x40,0x05,0x23,0xa8,0xa6}}; #define FDEX_VERSION_MASK 0xf0000000 +#define GOLDEN_RATIO 0x9E3779B9U typedef enum { PROP_VARIANT, @@ -49,6 +50,9 @@ struct _dispex_prop_t { const builtin_prop_t *p; DWORD ref; } u; + + int bucket_head; + int bucket_next; }; static inline DISPID prop_to_id(jsdisp_t *This, dispex_prop_t *prop) @@ -100,25 +104,68 @@ static const builtin_prop_t *find_builtin_prop(jsdisp_t *This, const WCHAR *name return NULL; } -static dispex_prop_t *alloc_prop(jsdisp_t *This, const WCHAR *name, prop_type_t type, DWORD flags) +static inline unsigned string_hash(const WCHAR *name) { - dispex_prop_t *ret; + unsigned h = 0; + for(; *name; name++) + h = (h>>(sizeof(unsigned)*8-4)) ^ (h<<4) ^ tolowerW(*name); + return h; +} - if(This->buf_size == This->prop_cnt) { - dispex_prop_t *tmp = heap_realloc(This->props, (This->buf_size<<=1)*sizeof(*This->props)); - if(!tmp) - return NULL; - This->props = tmp; +static inline unsigned get_props_idx(jsdisp_t *This, unsigned hash) +{ + return (hash*GOLDEN_RATIO) & (This->buf_size-1); +} + +static inline HRESULT resize_props(jsdisp_t *This) +{ + dispex_prop_t *props; + int i, bucket; + + if(This->buf_size != This->prop_cnt) + return S_FALSE; + + props = heap_realloc(This->props, sizeof(dispex_prop_t)*This->buf_size*2); + if(!props) + return E_OUTOFMEMORY; + This->buf_size *= 2; + This->props = props; + + for(i=0; ibuf_size; i++) { + This->props[i].bucket_head = 0; + This->props[i].bucket_next = 0; } - ret = This->props + This->prop_cnt++; - ret->type = type; - ret->flags = flags; - ret->name = heap_strdupW(name); - if(!ret->name) + for(i=1; iprop_cnt; i++) { + props = This->props+i; + + bucket = get_props_idx(This, string_hash(props->name)); + props->bucket_next = This->props[bucket].bucket_head; + This->props[bucket].bucket_head = i; + } + + return S_OK; +} + +static inline dispex_prop_t* alloc_prop(jsdisp_t *This, const WCHAR *name, prop_type_t type, DWORD flags) +{ + dispex_prop_t *prop; + unsigned bucket; + + if(FAILED(resize_props(This))) return NULL; - return ret; + prop = &This->props[This->prop_cnt]; + prop->name = heap_strdupW(name); + if(!prop->name) + return NULL; + prop->type = type; + prop->flags = flags; + + bucket = get_props_idx(This, string_hash(name)); + prop->bucket_next = This->props[bucket].bucket_head; + This->props[bucket].bucket_head = This->prop_cnt++; + return prop; } static dispex_prop_t *alloc_protref(jsdisp_t *This, const WCHAR *name, DWORD ref) @@ -136,13 +183,25 @@ static dispex_prop_t *alloc_protref(jsdisp_t *This, const WCHAR *name, DWORD ref static HRESULT find_prop_name(jsdisp_t *This, const WCHAR *name, dispex_prop_t **ret) { const builtin_prop_t *builtin; + unsigned bucket, pos, prev = 0; dispex_prop_t *prop; - for(prop = This->props; prop < This->props+This->prop_cnt; prop++) { - if(prop->name && !strcmpW(prop->name, name)) { - *ret = prop; + bucket = get_props_idx(This, string_hash(name)); + pos = This->props[bucket].bucket_head; + while(pos != 0) { + if(!strcmpW(name, This->props[pos].name)) { + if(prev != 0) { + This->props[prev].bucket_next = This->props[pos].bucket_next; + This->props[pos].bucket_next = This->props[bucket].bucket_head; + This->props[bucket].bucket_head = pos; + } + + *ret = &This->props[pos]; return S_OK; } + + prev = pos; + pos = This->props[pos].bucket_next; } builtin = find_builtin_prop(This, name); @@ -162,13 +221,15 @@ static HRESULT find_prop_name(jsdisp_t *This, const WCHAR *name, dispex_prop_t * static HRESULT find_prop_name_prot(jsdisp_t *This, const WCHAR *name, dispex_prop_t **ret) { - dispex_prop_t *prop; + dispex_prop_t *prop, *del=NULL; HRESULT hres; hres = find_prop_name(This, name, &prop); if(FAILED(hres)) return hres; - if(prop) { + if(prop && prop->type==PROP_DELETED) { + del = prop; + } else if(prop) { *ret = prop; return S_OK; } @@ -178,15 +239,23 @@ static HRESULT find_prop_name_prot(jsdisp_t *This, const WCHAR *name, dispex_pro if(FAILED(hres)) return hres; if(prop) { - prop = alloc_protref(This, prop->name, prop - This->prototype->props); - if(!prop) - return E_OUTOFMEMORY; + if(del) { + del->type = PROP_PROTREF; + del->flags = 0; + del->u.ref = prop - This->prototype->props; + prop = del; + }else { + prop = alloc_protref(This, prop->name, prop - This->prototype->props); + if(!prop) + return E_OUTOFMEMORY; + } + *ret = prop; return S_OK; } } - *ret = prop; + *ret = del; return S_OK; } @@ -199,12 +268,18 @@ static HRESULT ensure_prop_name(jsdisp_t *This, const WCHAR *name, BOOL search_p hres = find_prop_name_prot(This, name, &prop); else hres = find_prop_name(This, name, &prop); - if(SUCCEEDED(hres) && !prop) { + if(SUCCEEDED(hres) && (!prop || prop->type==PROP_DELETED)) { TRACE("creating prop %s\n", debugstr_w(name)); - prop = alloc_prop(This, name, PROP_VARIANT, create_flags); - if(!prop) - return E_OUTOFMEMORY; + if(prop) { + prop->type = PROP_VARIANT; + prop->flags = create_flags; + }else { + prop = alloc_prop(This, name, PROP_VARIANT, create_flags); + if(!prop) + return E_OUTOFMEMORY; + } + VariantInit(&prop->u.var); } @@ -410,10 +485,16 @@ static HRESULT fill_protrefs(jsdisp_t *This) hres = find_prop_name(This, iter->name, &prop); if(FAILED(hres)) return hres; - if(!prop) { - prop = alloc_protref(This, iter->name, iter - This->prototype->props); - if(!prop) - return E_OUTOFMEMORY; + if(!prop || prop->type==PROP_DELETED) { + if(prop) { + prop->type = PROP_PROTREF; + prop->flags = 0; + prop->u.ref = iter - This->prototype->props; + }else { + prop = alloc_protref(This, iter->name, iter - This->prototype->props); + if(!prop) + return E_OUTOFMEMORY; + } } } @@ -617,10 +698,10 @@ static HRESULT WINAPI DispatchEx_InvokeEx(IDispatchEx *iface, DISPID id, LCID lc static HRESULT delete_prop(dispex_prop_t *prop) { - heap_free(prop->name); - prop->name = NULL; - prop->type = PROP_DELETED; - + if(prop->type == PROP_VARIANT) { + VariantClear(&prop->u.var); + prop->type = PROP_DELETED; + } return S_OK; } @@ -701,14 +782,15 @@ static HRESULT WINAPI DispatchEx_GetNextDispID(IDispatchEx *iface, DWORD grfdex, return hres; } - iter = get_prop(This, id+1); - if(!iter) { + if(id+1>=0 && id+1prop_cnt) { + iter = &This->props[id+1]; + }else { *pid = DISPID_STARTENUM; return S_FALSE; } while(iter < This->props + This->prop_cnt) { - if(iter->name && (get_flags(This, iter) & PROPF_ENUM)) { + if(iter->name && (get_flags(This, iter) & PROPF_ENUM) && iter->type!=PROP_DELETED) { *pid = prop_to_id(This, iter); return S_OK; } @@ -752,7 +834,7 @@ HRESULT init_dispex(jsdisp_t *dispex, script_ctx_t *ctx, const builtin_info_t *b dispex->ref = 1; dispex->builtin_info = builtin_info; - dispex->props = heap_alloc((dispex->buf_size=4) * sizeof(dispex_prop_t)); + dispex->props = heap_alloc_zero(sizeof(dispex_prop_t)*(dispex->buf_size=4)); if(!dispex->props) return E_OUTOFMEMORY; @@ -761,8 +843,6 @@ HRESULT init_dispex(jsdisp_t *dispex, script_ctx_t *ctx, const builtin_info_t *b jsdisp_addref(prototype); dispex->prop_cnt = 1; - dispex->props[0].name = NULL; - dispex->props[0].flags = 0; if(builtin_info->value_prop.invoke) { dispex->props[0].type = PROP_BUILTIN; dispex->props[0].u.p = &builtin_info->value_prop; @@ -811,7 +891,7 @@ HRESULT init_dispex_from_constr(jsdisp_t *dispex, script_ctx_t *ctx, const built static const WCHAR prototypeW[] = {'p','r','o','t','o','t','y','p','e',0}; hres = find_prop_name_prot(constr, prototypeW, &prop); - if(SUCCEEDED(hres) && prop) { + if(SUCCEEDED(hres) && prop && prop->type!=PROP_DELETED) { jsexcept_t jsexcept; VARIANT var; @@ -874,7 +954,7 @@ HRESULT jsdisp_get_id(jsdisp_t *jsdisp, const WCHAR *name, DWORD flags, DISPID * if(FAILED(hres)) return hres; - if(prop) { + if(prop && prop->type!=PROP_DELETED) { *id = prop_to_id(jsdisp, prop); return S_OK; } @@ -1048,7 +1128,7 @@ HRESULT jsdisp_propget_name(jsdisp_t *obj, const WCHAR *name, VARIANT *var, jsex return hres; V_VT(var) = VT_EMPTY; - if(!prop) + if(!prop || prop->type==PROP_DELETED) return S_OK; return prop_get(obj, prop, &dp, var, ei, caller); @@ -1070,7 +1150,7 @@ HRESULT jsdisp_get_idx(jsdisp_t *obj, DWORD idx, VARIANT *var, jsexcept_t *ei, I return hres; V_VT(var) = VT_EMPTY; - if(!prop) + if(!prop || prop->type==PROP_DELETED) return DISP_E_UNKNOWNNAME; return prop_get(obj, prop, &dp, var, ei, caller);