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:
parent
0f23cf61da
commit
94bd9ab8a9
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
};
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in New Issue