From 94bd9ab8a900e5c6e82b392bc53002dd7e693d46 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gabriel=20Iv=C4=83ncescu?= Date: Thu, 12 Dec 2019 14:53:55 +0200 Subject: [PATCH] jscript: Store the necessary function and variable info in the TypeInfo. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 Signed-off-by: Jacek Caban Signed-off-by: Alexandre Julliard --- 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 92e9b968da0..6c6d25a9c16 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 7a44f5092b8..52c12676dc6 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 5d635b7f41f..7174db8e0c1 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;