From: "Gabriel Ivăncescu" Subject: [PATCH v4 1/9] jscript: Store the necessary function and variable info in the TypeInfo. Message-Id: <5084914ccc51ae6f0d8783c7acf623d2a996c3a3.1576155193.git.gabrielopcode@gmail.com> Date: Thu, 12 Dec 2019 14:53:55 +0200 The TypeInfo is built when it is retrieved and frozen at that moment, even if the script changes after that and more identifiers are added to it, or existing ones deleted. Signed-off-by: Gabriel Ivăncescu --- dlls/jscript/dispex.c | 110 ++++++++++++++++++++++++++++++++++++++++ dlls/jscript/function.c | 31 +++++++++++ dlls/jscript/jscript.h | 1 + 3 files changed, 142 insertions(+) diff --git a/dlls/jscript/dispex.c b/dlls/jscript/dispex.c index 92e9b96..6c6d25a 100644 --- a/dlls/jscript/dispex.c +++ b/dlls/jscript/dispex.c @@ -19,6 +19,7 @@ #include #include "jscript.h" +#include "engine.h" #include "wine/debug.h" @@ -70,6 +71,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 +605,21 @@ static HRESULT fill_protrefs(jsdisp_t *This) return S_OK; } +struct typeinfo_func { + dispex_prop_t *prop; + function_code_t *code; +}; + 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 +659,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--;) + release_bytecode(This->funcs[i].code->bytecode); + IDispatchEx_Release(&This->jsdisp->IDispatchEx_iface); + heap_free(This->funcs); + heap_free(This->vars); heap_free(This); } return ref; @@ -897,17 +930,94 @@ static HRESULT WINAPI DispatchEx_GetTypeInfo(IDispatchEx *iface, UINT iTInfo, LC ITypeInfo **ppTInfo) { jsdisp_t *This = impl_from_IDispatchEx(iface); + dispex_prop_t *prop, *cur, *end, **typevar; + UINT num_funcs = 0, num_vars = 0; + struct typeinfo_func *typefunc; + function_code_t *func_code; ScriptTypeInfo *typeinfo; + unsigned pos; TRACE("(%p)->(%u %u %p)\n", This, iTInfo, lcid, ppTInfo); if (iTInfo != 0) return DISP_E_BADINDEX; + for (prop = This->props, end = prop + This->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 = This->props[get_props_idx(This, prop->hash)].bucket_head; + while (pos) + { + cur = This->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)) + { + if (Function_get_code(as_jsdisp(get_object(prop->u.val)))) + num_funcs++; + } + else num_vars++; + } + if (!(typeinfo = heap_alloc(sizeof(*typeinfo)))) return E_OUTOFMEMORY; typeinfo->ITypeInfo_iface.lpVtbl = &ScriptTypeInfoVtbl; typeinfo->ref = 1; + typeinfo->num_vars = num_vars; + typeinfo->num_funcs = num_funcs; + typeinfo->jsdisp = This; + + 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 = This->props; prop != end; prop++) + { + if (!prop->name || prop->type != PROP_JSVAL || !(prop->flags & PROPF_ENUMERABLE)) + continue; + + if (is_function_prop(prop)) + { + func_code = Function_get_code(as_jsdisp(get_object(prop->u.val))); + if (!func_code) continue; + + typefunc->prop = prop; + typefunc->code = func_code; + typefunc++; + + /* The function may be deleted, so keep a ref */ + bytecode_addref(func_code->bytecode); + } + else + *typevar++ = prop; + } + + /* Keep a ref to the props and their names */ + IDispatchEx_AddRef(&This->IDispatchEx_iface); *ppTInfo = &typeinfo->ITypeInfo_iface; return S_OK; diff --git a/dlls/jscript/function.c b/dlls/jscript/function.c index 7a44f50..52c1267 100644 --- a/dlls/jscript/function.c +++ b/dlls/jscript/function.c @@ -37,6 +37,7 @@ typedef struct { struct _function_vtbl_t { HRESULT (*call)(script_ctx_t*,FunctionInstance*,IDispatch*,unsigned,unsigned,jsval_t*,jsval_t*); HRESULT (*toString)(FunctionInstance*,jsstr_t**); + function_code_t* (*get_code)(FunctionInstance*); void (*destructor)(FunctionInstance*); }; @@ -524,6 +525,16 @@ static HRESULT Function_get_arguments(script_ctx_t *ctx, jsdisp_t *jsthis, jsval return S_OK; } +function_code_t *Function_get_code(jsdisp_t *jsthis) +{ + FunctionInstance *function; + + assert(is_class(jsthis, JSCLASS_FUNCTION)); + function = function_from_jsdisp(jsthis); + + return function->vtbl->get_code(function); +} + static void Function_destructor(jsdisp_t *dispex) { FunctionInstance *function = function_from_jsdisp(dispex); @@ -638,6 +649,11 @@ static HRESULT NativeFunction_toString(FunctionInstance *func, jsstr_t **ret) return S_OK; } +static function_code_t *NativeFunction_get_code(FunctionInstance *function) +{ + return NULL; +} + static void NativeFunction_destructor(FunctionInstance *function) { } @@ -645,6 +661,7 @@ static void NativeFunction_destructor(FunctionInstance *function) static const function_vtbl_t NativeFunctionVtbl = { NativeFunction_call, NativeFunction_toString, + NativeFunction_get_code, NativeFunction_destructor }; @@ -749,6 +766,13 @@ static HRESULT InterpretedFunction_toString(FunctionInstance *func, jsstr_t **re return *ret ? S_OK : E_OUTOFMEMORY; } +static function_code_t *InterpretedFunction_get_code(FunctionInstance *func) +{ + InterpretedFunction *function = (InterpretedFunction*)func; + + return function->func_code; +} + static void InterpretedFunction_destructor(FunctionInstance *func) { InterpretedFunction *function = (InterpretedFunction*)func; @@ -761,6 +785,7 @@ static void InterpretedFunction_destructor(FunctionInstance *func) static const function_vtbl_t InterpretedFunctionVtbl = { InterpretedFunction_call, InterpretedFunction_toString, + InterpretedFunction_get_code, InterpretedFunction_destructor }; @@ -842,6 +867,11 @@ static HRESULT BindFunction_toString(FunctionInstance *function, jsstr_t **ret) return *ret ? S_OK : E_OUTOFMEMORY; } +static function_code_t *BindFunction_get_code(FunctionInstance *function) +{ + return NULL; +} + static void BindFunction_destructor(FunctionInstance *func) { BindFunction *function = (BindFunction*)func; @@ -858,6 +888,7 @@ static void BindFunction_destructor(FunctionInstance *func) static const function_vtbl_t BindFunctionVtbl = { BindFunction_call, BindFunction_toString, + BindFunction_get_code, BindFunction_destructor }; diff --git a/dlls/jscript/jscript.h b/dlls/jscript/jscript.h index 5d635b7..7174db8 100644 --- a/dlls/jscript/jscript.h +++ b/dlls/jscript/jscript.h @@ -307,6 +307,7 @@ HRESULT Function_invoke(jsdisp_t*,IDispatch*,WORD,unsigned,jsval_t*,jsval_t*) DE HRESULT Function_value(script_ctx_t*,vdisp_t*,WORD,unsigned,jsval_t*,jsval_t*) DECLSPEC_HIDDEN; HRESULT Function_get_value(script_ctx_t*,jsdisp_t*,jsval_t*) DECLSPEC_HIDDEN; +struct _function_code_t *Function_get_code(jsdisp_t*) DECLSPEC_HIDDEN; #define DEFAULT_FUNCTION_VALUE {NULL, Function_value,0, Function_get_value} HRESULT throw_eval_error(script_ctx_t*,HRESULT,const WCHAR*) DECLSPEC_HIDDEN; -- 2.21.0