Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com --- dlls/jscript/dispex.c | 109 ++++++++++++++++++++++++++++++++++++++++ dlls/jscript/function.c | 5 ++ dlls/jscript/jscript.h | 1 + 3 files changed, 115 insertions(+)
diff --git a/dlls/jscript/dispex.c b/dlls/jscript/dispex.c index 68e4e1c..2c309cd 100644 --- a/dlls/jscript/dispex.c +++ b/dlls/jscript/dispex.c @@ -70,6 +70,20 @@ static inline dispex_prop_t *get_prop(jsdisp_t *This, DISPID id) return This->props+id; }
+static inline BOOL is_function_prop(dispex_prop_t *prop) +{ + BOOL ret = FALSE; + + if (is_object_instance(prop->u.val)) + { + jsdisp_t *jsdisp = iface_to_jsdisp(get_object(prop->u.val)); + + if (jsdisp) ret = is_class(jsdisp, JSCLASS_FUNCTION); + jsdisp_release(jsdisp); + } + return ret; +} + static DWORD get_flags(jsdisp_t *This, dispex_prop_t *prop) { if(prop->type == PROP_PROTREF) { @@ -590,9 +604,21 @@ static HRESULT fill_protrefs(jsdisp_t *This) return S_OK; }
+struct typeinfo_func { + dispex_prop_t *prop; + jsdisp_t *disp; +}; + typedef struct { ITypeInfo ITypeInfo_iface; LONG ref; + + UINT num_funcs; + UINT num_vars; + struct typeinfo_func *funcs; + dispex_prop_t **vars; + + jsdisp_t *jsdisp; } ScriptTypeInfo;
static inline ScriptTypeInfo *ScriptTypeInfo_from_ITypeInfo(ITypeInfo *iface) @@ -632,11 +658,17 @@ static ULONG WINAPI ScriptTypeInfo_Release(ITypeInfo *iface) { ScriptTypeInfo *This = ScriptTypeInfo_from_ITypeInfo(iface); LONG ref = InterlockedDecrement(&This->ref); + UINT i;
TRACE("(%p) ref=%d\n", This, ref);
if (!ref) { + for (i = This->num_funcs; i--;) + IDispatchEx_Release(&This->funcs[i].disp->IDispatchEx_iface); + IDispatchEx_Release(&This->jsdisp->IDispatchEx_iface); + heap_free(This->funcs); + heap_free(This->vars); heap_free(This); } return ref; @@ -845,13 +877,90 @@ static inline jsdisp_t *impl_from_IDispatchEx(IDispatchEx *iface)
static HRESULT create_script_typeinfo(jsdisp_t *jsdisp, ITypeInfo **out) { + dispex_prop_t *prop, *cur, *end, **typevar; + UINT num_funcs = 0, num_vars = 0; + struct typeinfo_func *typefunc; ScriptTypeInfo *typeinfo; + jsdisp_t *fn; + unsigned pos;
if (!(typeinfo = heap_alloc(sizeof(*typeinfo)))) return E_OUTOFMEMORY;
+ for (prop = jsdisp->props, end = prop + jsdisp->prop_cnt; prop != end; prop++) + { + if (!prop->name || prop->type != PROP_JSVAL || !(prop->flags & PROPF_ENUMERABLE)) + continue; + + /* If two identifiers differ only by case, the TypeInfo fails */ + pos = jsdisp->props[get_props_idx(jsdisp, prop->hash)].bucket_head; + while (pos) + { + cur = jsdisp->props + pos; + + if (prop->hash == cur->hash && prop != cur && + cur->type == PROP_JSVAL && (cur->flags & PROPF_ENUMERABLE) && + !wcsicmp(prop->name, cur->name)) + { + return TYPE_E_AMBIGUOUSNAME; + } + pos = cur->bucket_next; + } + + if (is_function_prop(prop)) + { + fn = impl_from_IDispatchEx((IDispatchEx*)get_object(prop->u.val)); + if (is_source_function(fn)) num_funcs++; + } + else num_vars++; + } + typeinfo->ITypeInfo_iface.lpVtbl = &ScriptTypeInfoVtbl; typeinfo->ref = 1; + typeinfo->num_vars = num_vars; + typeinfo->num_funcs = num_funcs; + typeinfo->jsdisp = jsdisp; + + typeinfo->funcs = heap_alloc(sizeof(*typeinfo->funcs) * num_funcs); + if (!typeinfo->funcs) + { + heap_free(typeinfo); + return E_OUTOFMEMORY; + } + + typeinfo->vars = heap_alloc(sizeof(*typeinfo->vars) * num_vars); + if (!typeinfo->vars) + { + heap_free(typeinfo->funcs); + heap_free(typeinfo); + return E_OUTOFMEMORY; + } + + typefunc = typeinfo->funcs; + typevar = typeinfo->vars; + for (prop = jsdisp->props; prop != end; prop++) + { + if (!prop->name || prop->type != PROP_JSVAL || !(prop->flags & PROPF_ENUMERABLE)) + continue; + + if (is_function_prop(prop)) + { + fn = impl_from_IDispatchEx((IDispatchEx*)get_object(prop->u.val)); + if (!is_source_function(fn)) continue; + + typefunc->prop = prop; + typefunc->disp = fn; + typefunc++; + + /* The function's object may be deleted, so keep it alive */ + IDispatchEx_AddRef(&fn->IDispatchEx_iface); + } + else + *typevar++ = prop; + } + + /* Keep a ref to the props and their names */ + IDispatchEx_AddRef(&jsdisp->IDispatchEx_iface);
*out = &typeinfo->ITypeInfo_iface; return S_OK; diff --git a/dlls/jscript/function.c b/dlls/jscript/function.c index 7a44f50..98d1259 100644 --- a/dlls/jscript/function.c +++ b/dlls/jscript/function.c @@ -803,6 +803,11 @@ HRESULT create_source_function(script_ctx_t *ctx, bytecode_t *code, function_cod return S_OK; }
+BOOL is_source_function(jsdisp_t *jsdisp) +{ + return function_from_jsdisp(jsdisp)->vtbl == &InterpretedFunctionVtbl; +} + static HRESULT BindFunction_call(script_ctx_t *ctx, FunctionInstance *func, IDispatch *this_obj, unsigned flags, unsigned argc, jsval_t *argv, jsval_t *r) { diff --git a/dlls/jscript/jscript.h b/dlls/jscript/jscript.h index 5d635b7..91923f8 100644 --- a/dlls/jscript/jscript.h +++ b/dlls/jscript/jscript.h @@ -303,6 +303,7 @@ HRESULT create_builtin_function(script_ctx_t*,builtin_invoke_t,const WCHAR*,cons jsdisp_t*,jsdisp_t**) DECLSPEC_HIDDEN; HRESULT create_builtin_constructor(script_ctx_t*,builtin_invoke_t,const WCHAR*,const builtin_info_t*,DWORD, jsdisp_t*,jsdisp_t**) DECLSPEC_HIDDEN; +BOOL is_source_function(jsdisp_t*) DECLSPEC_HIDDEN; HRESULT Function_invoke(jsdisp_t*,IDispatch*,WORD,unsigned,jsval_t*,jsval_t*) DECLSPEC_HIDDEN;
HRESULT Function_value(script_ctx_t*,vdisp_t*,WORD,unsigned,jsval_t*,jsval_t*) DECLSPEC_HIDDEN;