jscript: Use hash table when accessing object properties by name.
This commit is contained in:
parent
71b58e56c2
commit
f1a237d682
|
@ -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; 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);
|
||||
|
|
Loading…
Reference in New Issue