[PATCH 02/10] jscript: Store the necessary function and variable info in the script TypeInfo.

Gabriel Ivăncescu gabrielopcode at gmail.com
Mon Dec 9 08:01:01 CST 2019


Signed-off-by: Gabriel Ivăncescu <gabrielopcode at 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;
-- 
2.21.0




More information about the wine-devel mailing list