jscript: Store the necessary function and variable info in the TypeInfo.

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 <gabrielopcode@gmail.com>
Signed-off-by: Jacek Caban <jacek@codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
Gabriel Ivăncescu 2019-12-12 14:53:55 +02:00 committed by Alexandre Julliard
parent 0f23cf61da
commit 94bd9ab8a9
3 changed files with 142 additions and 0 deletions

View File

@ -19,6 +19,7 @@
#include <assert.h>
#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;

View File

@ -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
};

View File

@ -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;