Commit f1a237d6 authored by Piotr Caban's avatar Piotr Caban Committed by Alexandre Julliard

jscript: Use hash table when accessing object properties by name.

parent 71b58e56
......@@ -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;
}
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;
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;
for(i=0; i<This->buf_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; i<This->prop_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+1<This->prop_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);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment