[PATCH v2 1/8] jscript: Store NULL disps as a different type of jsval_null.

Gabriel Ivăncescu gabrielopcode at gmail.com
Thu Mar 24 10:31:06 CDT 2022


This makes sure that object instances are always non-NULL and gets rid of
all such checks.

Signed-off-by: Gabriel Ivăncescu <gabrielopcode at gmail.com>
---

Hopefully, I handled all cases and objects now can never be NULL. I tested
this with a bunch of test apps (some also needing the mshtml proxy object
patches), no difference in behavior or crashes were observed, so I think
it should cover all cases.

 dlls/jscript/array.c       | 13 +++++-----
 dlls/jscript/dispex.c      |  8 +++----
 dlls/jscript/engine.c      | 31 ++++++++----------------
 dlls/jscript/function.c    | 13 ++++++----
 dlls/jscript/json.c        | 11 +++++----
 dlls/jscript/jsutils.c     | 49 ++++++++++++++++----------------------
 dlls/jscript/jsval.h       | 13 ++++++++--
 dlls/jscript/object.c      | 25 +++++++++++--------
 dlls/jscript/set.c         |  2 +-
 dlls/jscript/tests/api.js  |  8 +++++++
 dlls/jscript/tests/lang.js |  2 ++
 11 files changed, 93 insertions(+), 82 deletions(-)

diff --git a/dlls/jscript/array.c b/dlls/jscript/array.c
index 9b97ef2..dcabc0d 100644
--- a/dlls/jscript/array.c
+++ b/dlls/jscript/array.c
@@ -704,7 +704,8 @@ static HRESULT Array_sort(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned
                 hres = JS_E_JSCRIPT_EXPECTED;
                 goto done;
             }
-        }else if(ctx->version >= SCRIPTLANGUAGEVERSION_ES5 ? !is_undefined(argv[0]) : !is_null(argv[0])) {
+        }else if(ctx->version >= SCRIPTLANGUAGEVERSION_ES5 ? !is_undefined(argv[0]) :
+                 (!is_null(argv[0]) || is_null_disp(argv[0]))) {
             WARN("invalid arg %s\n", debugstr_jsval(argv[0]));
             hres = JS_E_JSCRIPT_EXPECTED;
             goto done;
@@ -972,7 +973,7 @@ static HRESULT Array_forEach(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsig
         return hres;
 
     /* Fixme check IsCallable */
-    if(!argc || !is_object_instance(argv[0]) || !get_object(argv[0])) {
+    if(!argc || !is_object_instance(argv[0])) {
         FIXME("Invalid arg %s\n", debugstr_jsval(argc ? argv[0] : jsval_undefined()));
         hres = E_INVALIDARG;
         goto done;
@@ -980,7 +981,7 @@ static HRESULT Array_forEach(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsig
     callback = get_object(argv[0]);
 
     if(argc > 1 && !is_undefined(argv[1])) {
-        if(!is_object_instance(argv[1]) || !get_object(argv[1])) {
+        if(!is_object_instance(argv[1])) {
             FIXME("Unsupported context this %s\n", debugstr_jsval(argv[1]));
             hres = E_NOTIMPL;
             goto done;
@@ -1087,7 +1088,7 @@ static HRESULT Array_map(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned
     }
 
     /* FIXME: check IsCallable */
-    if(!argc || !is_object_instance(argv[0]) || !get_object(argv[0])) {
+    if(!argc || !is_object_instance(argv[0])) {
         FIXME("Invalid arg %s\n", debugstr_jsval(argc ? argv[0] : jsval_undefined()));
         hres = E_INVALIDARG;
         goto done;
@@ -1095,7 +1096,7 @@ static HRESULT Array_map(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned
     callback = get_object(argv[0]);
 
     if(argc > 1) {
-        if(is_object_instance(argv[1]) && get_object(argv[1])) {
+        if(is_object_instance(argv[1])) {
             context_this = get_object(argv[1]);
         }else if(!is_undefined(argv[1])) {
             FIXME("Unsupported context this %s\n", debugstr_jsval(argv[1]));
@@ -1154,7 +1155,7 @@ static HRESULT Array_reduce(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsign
     }
 
     /* Fixme check IsCallable */
-    if(!argc || !is_object_instance(argv[0]) || !get_object(argv[0])) {
+    if(!argc || !is_object_instance(argv[0])) {
         FIXME("Invalid arg %s\n", debugstr_jsval(argc ? argv[0] : jsval_undefined()));
         hres = E_INVALIDARG;
         goto done;
diff --git a/dlls/jscript/dispex.c b/dlls/jscript/dispex.c
index df2f65f..ef13e29 100644
--- a/dlls/jscript/dispex.c
+++ b/dlls/jscript/dispex.c
@@ -574,7 +574,7 @@ static HRESULT invoke_prop_func(jsdisp_t *This, IDispatch *jsthis, dispex_prop_t
         return invoke_prop_func(This->prototype, jsthis ? jsthis : (IDispatch *)&This->IDispatchEx_iface,
                                 This->prototype->props+prop->u.ref, flags, argc, argv, r, caller);
     case PROP_JSVAL: {
-        if(!is_object_instance(prop->u.val) || !get_object(prop->u.val)) {
+        if(!is_object_instance(prop->u.val)) {
             FIXME("invoke %s\n", debugstr_jsval(prop->u.val));
             return E_FAIL;
         }
@@ -593,7 +593,7 @@ static HRESULT invoke_prop_func(jsdisp_t *This, IDispatch *jsthis, dispex_prop_t
         if(FAILED(hres))
             return hres;
 
-        if(is_object_instance(val) && get_object(val)) {
+        if(is_object_instance(val)) {
             hres = disp_call_value(This->ctx, get_object(val),
                                    jsthis ? jsthis : (IDispatch*)&This->IDispatchEx_iface,
                                    flags, argc, argv, r);
@@ -1927,7 +1927,7 @@ HRESULT init_dispex_from_constr(jsdisp_t *dispex, script_ctx_t *ctx, const built
             return hres;
         }
 
-        if(is_object_instance(val) && get_object(val))
+        if(is_object_instance(val))
             prot = iface_to_jsdisp(get_object(val));
         else
             prot = jsdisp_addref(ctx->object_prototype);
@@ -1987,7 +1987,7 @@ HRESULT jsdisp_call_value(jsdisp_t *jsfunc, IDispatch *jsthis, WORD flags, unsig
         }
 
         flags &= ~DISPATCH_JSCRIPT_INTERNAL_MASK;
-        hres = jsfunc->builtin_info->call(jsfunc->ctx, jsval_disp(jsthis), flags, argc, argv, r);
+        hres = jsfunc->builtin_info->call(jsfunc->ctx, jsthis ? jsval_disp(jsthis) : jsval_null(), flags, argc, argv, r);
     }
     return hres;
 }
diff --git a/dlls/jscript/engine.c b/dlls/jscript/engine.c
index d894fbc..c483f2a 100644
--- a/dlls/jscript/engine.c
+++ b/dlls/jscript/engine.c
@@ -131,8 +131,6 @@ static HRESULT stack_pop_object(script_ctx_t *ctx, IDispatch **r)
 
     v = stack_pop(ctx);
     if(is_object_instance(v)) {
-        if(!get_object(v))
-            return JS_E_OBJECT_REQUIRED;
         *r = get_object(v);
         return S_OK;
     }
@@ -539,10 +537,7 @@ HRESULT jsval_strict_equal(jsval_t lval, jsval_t rval, BOOL *ret)
     TRACE("\n");
 
     if(type != jsval_type(rval)) {
-        if(is_null_instance(lval))
-            *ret = is_null_instance(rval);
-        else
-            *ret = FALSE;
+        *ret = FALSE;
         return S_OK;
     }
 
@@ -1034,7 +1029,7 @@ static void set_error_value(script_ctx_t *ctx, jsval_t value)
     ei->valid_value = TRUE;
     ei->value = value;
 
-    if(is_object_instance(value) && get_object(value) && (obj = to_jsdisp(get_object(value)))) {
+    if(is_object_instance(value) && (obj = to_jsdisp(get_object(value)))) {
         UINT32 number;
         jsstr_t *str;
         jsval_t v;
@@ -1360,11 +1355,9 @@ static HRESULT interp_new(script_ctx_t *ctx)
     /* NOTE: Should use to_object here */
 
     if(is_null(constr))
-        return JS_E_OBJECT_EXPECTED;
-    else if(!is_object_instance(constr))
+        return is_null_disp(constr) ? JS_E_INVALID_PROPERTY : JS_E_OBJECT_EXPECTED;
+    if(!is_object_instance(constr))
         return JS_E_INVALID_ACTION;
-    else if(!get_object(constr))
-        return JS_E_INVALID_PROPERTY;
 
     clear_acc(ctx);
     return disp_call_value(ctx, get_object(constr), NULL, DISPATCH_CONSTRUCT | DISPATCH_JSCRIPT_CALLEREXECSSOURCE,
@@ -1807,7 +1800,7 @@ static HRESULT interp_instanceof(script_ctx_t *ctx)
     HRESULT hres;
 
     v = stack_pop(ctx);
-    if(!is_object_instance(v) || !get_object(v)) {
+    if(!is_object_instance(v)) {
         jsval_release(v);
         return JS_E_FUNCTION_EXPECTED;
     }
@@ -1830,7 +1823,9 @@ static HRESULT interp_instanceof(script_ctx_t *ctx)
 
     v = stack_pop(ctx);
 
-    if(is_object_instance(prot)) {
+    if(is_null_disp(v))
+        hres = JS_E_OBJECT_EXPECTED;
+    else if(is_object_instance(prot)) {
         if(is_object_instance(v))
             tmp = iface_to_jsdisp(get_object(v));
         for(iter = tmp; !ret && iter; iter = iter->prototype) {
@@ -1867,7 +1862,7 @@ static HRESULT interp_in(script_ctx_t *ctx)
     TRACE("\n");
 
     obj = stack_pop(ctx);
-    if(!is_object_instance(obj) || !get_object(obj)) {
+    if(!is_object_instance(obj)) {
         jsval_release(obj);
         return JS_E_OBJECT_EXPECTED;
     }
@@ -2126,7 +2121,7 @@ static HRESULT typeof_string(jsval_t v, const WCHAR **ret)
     case JSV_OBJECT: {
         jsdisp_t *dispex;
 
-        if(get_object(v) && (dispex = iface_to_jsdisp(get_object(v)))) {
+        if((dispex = iface_to_jsdisp(get_object(v)))) {
             *ret = is_class(dispex, JSCLASS_FUNCTION) ? L"function" : L"object";
             jsdisp_release(dispex);
         }else {
@@ -2326,12 +2321,6 @@ static HRESULT equal_values(script_ctx_t *ctx, jsval_t lval, jsval_t rval, BOOL
     if(jsval_type(lval) == jsval_type(rval) || (is_number(lval) && is_number(rval)))
        return jsval_strict_equal(lval, rval, ret);
 
-    /* FIXME: NULL disps should be handled in more general way */
-    if(is_object_instance(lval) && !get_object(lval))
-        return equal_values(ctx, jsval_null(), rval, ret);
-    if(is_object_instance(rval) && !get_object(rval))
-        return equal_values(ctx, lval, jsval_null(), ret);
-
     if((is_null(lval) && is_undefined(rval)) || (is_undefined(lval) && is_null(rval))) {
         *ret = TRUE;
         return S_OK;
diff --git a/dlls/jscript/function.c b/dlls/jscript/function.c
index fc8a85c..03c541c 100644
--- a/dlls/jscript/function.c
+++ b/dlls/jscript/function.c
@@ -256,7 +256,7 @@ HRESULT Function_invoke(jsdisp_t *func_this, IDispatch *jsthis, WORD flags, unsi
     assert(is_class(func_this, JSCLASS_FUNCTION));
     function = function_from_jsdisp(func_this);
 
-    return function->vtbl->call(function->dispex.ctx, function, jsval_disp(jsthis), flags, argc, argv, r);
+    return function->vtbl->call(function->dispex.ctx, function, jsthis ? jsval_disp(jsthis) : jsval_null(), flags, argc, argv, r);
 }
 
 static HRESULT Function_get_length(script_ctx_t *ctx, jsdisp_t *jsthis, jsval_t *r)
@@ -336,6 +336,8 @@ static HRESULT Function_apply(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsi
 
     TRACE("\n");
 
+    if(is_null_disp(vthis))
+        return JS_E_OBJECT_REQUIRED;
     if(!is_object_instance(vthis) || (!(function = function_this(vthis)) && to_jsdisp(get_object(vthis))))
         return JS_E_FUNCTION_EXPECTED;
 
@@ -407,6 +409,8 @@ static HRESULT Function_call(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsig
 
     TRACE("\n");
 
+    if(is_null_disp(vthis))
+        return JS_E_OBJECT_REQUIRED;
     if(!(function = function_this(vthis)))
         return JS_E_FUNCTION_EXPECTED;
 
@@ -663,7 +667,7 @@ HRESULT create_builtin_function(script_ctx_t *ctx, builtin_invoke_t value_proc,
         hres = jsdisp_define_data_property(&function->function.dispex, L"length", 0,
                                            jsval_number(function->function.length));
     if(SUCCEEDED(hres))
-        hres = jsdisp_define_data_property(&function->function.dispex, L"prototype", 0, jsval_obj(prototype));
+        hres = jsdisp_define_data_property(&function->function.dispex, L"prototype", 0, prototype ? jsval_obj(prototype) : jsval_null());
     if(FAILED(hres)) {
         jsdisp_release(&function->function.dispex);
         return hres;
@@ -725,8 +729,7 @@ static HRESULT InterpretedFunction_call(script_ctx_t *ctx, FunctionInstance *fun
         this_obj = to_disp(new_obj);
     }else if(is_object_instance(vthis)) {
         this_obj = get_object(vthis);
-        if(this_obj)
-            IDispatch_AddRef(this_obj);
+        IDispatch_AddRef(this_obj);
     }else if(ctx->version >= SCRIPTLANGUAGEVERSION_ES5 && !is_undefined(vthis) && !is_null(vthis)) {
         hres = to_object(ctx, vthis, &this_obj);
         if(FAILED(hres))
@@ -836,7 +839,7 @@ static HRESULT BindFunction_call(script_ctx_t *ctx, FunctionInstance *func, jsva
             memcpy(call_args + function->argc, argv, argc * sizeof(*call_args));
     }
 
-    hres = function->target->vtbl->call(ctx, function->target, jsval_disp(function->this),
+    hres = function->target->vtbl->call(ctx, function->target, function->this ? jsval_disp(function->this) : jsval_null(),
                                         flags, call_argc, call_args, r);
 
     heap_free(call_args);
diff --git a/dlls/jscript/json.c b/dlls/jscript/json.c
index e0867eb..dfcc39d 100644
--- a/dlls/jscript/json.c
+++ b/dlls/jscript/json.c
@@ -404,7 +404,7 @@ static HRESULT maybe_to_primitive(script_ctx_t *ctx, jsval_t val, jsval_t *r)
     jsdisp_t *obj;
     HRESULT hres;
 
-    if(!is_object_instance(val) || !get_object(val) || !(obj = iface_to_jsdisp(get_object(val))))
+    if(!is_object_instance(val) || !(obj = iface_to_jsdisp(get_object(val))))
         return jsval_copy(val, r);
 
     if(is_class(obj, JSCLASS_NUMBER)) {
@@ -640,7 +640,7 @@ static HRESULT stringify(stringify_ctx_t *ctx, jsdisp_t *object, const WCHAR *na
     if(FAILED(hres))
         return hres == DISP_E_UNKNOWNNAME ? S_FALSE : hres;
 
-    if(is_object_instance(value) && get_object(value)) {
+    if(is_object_instance(value)) {
         jsdisp_t *obj;
         DISPID id;
 
@@ -681,7 +681,9 @@ static HRESULT stringify(stringify_ctx_t *ctx, jsdisp_t *object, const WCHAR *na
 
     switch(jsval_type(value)) {
     case JSV_NULL:
-        if(!append_string(ctx, L"null"))
+        if(is_null_disp(value))
+            hres = S_FALSE;
+        else if(!append_string(ctx, L"null"))
             hres = E_OUTOFMEMORY;
         break;
     case JSV_BOOL:
@@ -763,8 +765,7 @@ static HRESULT JSON_stringify(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsi
         return S_OK;
     }
 
-    if(argc >= 2 && is_object_instance(argv[1]) && get_object(argv[1]) &&
-       (replacer = to_jsdisp(get_object(argv[1])))) {
+    if(argc >= 2 && is_object_instance(argv[1]) && (replacer = to_jsdisp(get_object(argv[1])))) {
         if(is_callable(replacer)) {
             stringify_ctx.replacer = jsdisp_addref(replacer);
         }else if(is_class(replacer, JSCLASS_ARRAY)) {
diff --git a/dlls/jscript/jsutils.c b/dlls/jscript/jsutils.c
index 6bc34da..7debf07 100644
--- a/dlls/jscript/jsutils.c
+++ b/dlls/jscript/jsutils.c
@@ -183,8 +183,7 @@ void jsval_release(jsval_t val)
 {
     switch(jsval_type(val)) {
     case JSV_OBJECT:
-        if(get_object(val))
-            IDispatch_Release(get_object(val));
+        IDispatch_Release(get_object(val));
         break;
     case JSV_STRING:
         jsstr_release(get_string(val));
@@ -229,8 +228,7 @@ HRESULT jsval_copy(jsval_t v, jsval_t *r)
         *r = v;
         return S_OK;
     case JSV_OBJECT:
-        if(get_object(v))
-            IDispatch_AddRef(get_object(v));
+        IDispatch_AddRef(get_object(v));
         *r = v;
         return S_OK;
     case JSV_STRING: {
@@ -282,8 +280,11 @@ HRESULT variant_to_jsval(VARIANT *var, jsval_t *r)
         return S_OK;
     }
     case VT_DISPATCH: {
-        if(V_DISPATCH(var))
-            IDispatch_AddRef(V_DISPATCH(var));
+        if(!V_DISPATCH(var)) {
+            *r = jsval_null_disp();
+            return S_OK;
+        }
+        IDispatch_AddRef(V_DISPATCH(var));
         *r = jsval_disp(V_DISPATCH(var));
         return S_OK;
     }
@@ -332,7 +333,7 @@ HRESULT variant_to_jsval(VARIANT *var, jsval_t *r)
                 return S_OK;
             }
         }else {
-            *r = jsval_disp(NULL);
+            *r = jsval_null_disp();
             return S_OK;
         }
         /* fall through */
@@ -348,13 +349,17 @@ HRESULT jsval_to_variant(jsval_t val, VARIANT *retv)
         V_VT(retv) = VT_EMPTY;
         return S_OK;
     case JSV_NULL:
+        if(get_bool(val)) {
+            V_VT(retv) = VT_DISPATCH;
+            V_DISPATCH(retv) = NULL;
+            return S_OK;
+        }
         V_VT(retv) = VT_NULL;
         return S_OK;
     case JSV_OBJECT:
         V_VT(retv) = VT_DISPATCH;
-        if(get_object(val))
-            IDispatch_AddRef(get_object(val));
         V_DISPATCH(retv) = get_object(val);
+        IDispatch_AddRef(get_object(val));
         return S_OK;
     case JSV_STRING:
         V_VT(retv) = VT_BSTR;
@@ -394,11 +399,6 @@ HRESULT to_primitive(script_ctx_t *ctx, jsval_t val, jsval_t *ret, hint_t hint)
         DISPID id;
         HRESULT hres;
 
-        if(!get_object(val)) {
-            *ret = jsval_null();
-            return S_OK;
-        }
-
         jsdisp = iface_to_jsdisp(get_object(val));
         if(!jsdisp)
             return disp_propget(ctx, get_object(val), DISPID_VALUE, ret);
@@ -459,7 +459,7 @@ HRESULT to_boolean(jsval_t val, BOOL *ret)
         *ret = FALSE;
         return S_OK;
     case JSV_OBJECT:
-        *ret = get_object(val) != NULL;
+        *ret = TRUE;
         return S_OK;
     case JSV_STRING:
         *ret = jsstr_length(get_string(val)) != 0;
@@ -839,18 +839,8 @@ HRESULT to_object(script_ctx_t *ctx, jsval_t val, IDispatch **disp)
         *disp = to_disp(dispex);
         break;
     case JSV_OBJECT:
-        if(get_object(val)) {
-            *disp = get_object(val);
-            IDispatch_AddRef(*disp);
-        }else {
-            jsdisp_t *obj;
-
-            hres = create_object(ctx, NULL, &obj);
-            if(FAILED(hres))
-                return hres;
-
-            *disp = to_disp(obj);
-        }
+        *disp = get_object(val);
+        IDispatch_AddRef(*disp);
         break;
     case JSV_BOOL:
         hres = create_bool(ctx, get_bool(val), &dispex);
@@ -859,8 +849,11 @@ HRESULT to_object(script_ctx_t *ctx, jsval_t val, IDispatch **disp)
 
         *disp = to_disp(dispex);
         break;
-    case JSV_UNDEFINED:
     case JSV_NULL:
+        if(is_null_disp(val))
+            return JS_E_OBJECT_REQUIRED;
+        /* fall through */
+    case JSV_UNDEFINED:
         WARN("object expected\n");
         return JS_E_OBJECT_EXPECTED;
     case JSV_VARIANT:
diff --git a/dlls/jscript/jsval.h b/dlls/jscript/jsval.h
index 9f451b1..4e00d08 100644
--- a/dlls/jscript/jsval.h
+++ b/dlls/jscript/jsval.h
@@ -131,6 +131,15 @@ static inline jsval_t jsval_null(void)
 {
     jsval_t ret;
     __JSVAL_TYPE(ret) = JSV_NULL;
+    __JSVAL_BOOL(ret) = FALSE;
+    return ret;
+}
+
+static inline jsval_t jsval_null_disp(void)
+{
+    jsval_t ret;
+    __JSVAL_TYPE(ret) = JSV_NULL;
+    __JSVAL_BOOL(ret) = TRUE;
     return ret;
 }
 
@@ -178,9 +187,9 @@ static inline BOOL is_null(jsval_t v)
     return __JSVAL_TYPE(v) == JSV_NULL;
 }
 
-static inline BOOL is_null_instance(jsval_t v)
+static inline BOOL is_null_disp(jsval_t v)
 {
-    return is_null(v) || (is_object_instance(v) && !__JSVAL_OBJ(v));
+    return is_null(v) && __JSVAL_BOOL(v);
 }
 
 static inline BOOL is_string(jsval_t v)
diff --git a/dlls/jscript/object.c b/dlls/jscript/object.c
index f8f1407..9d4a747 100644
--- a/dlls/jscript/object.c
+++ b/dlls/jscript/object.c
@@ -127,6 +127,11 @@ static HRESULT Object_valueOf(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsi
 
     TRACE("\n");
 
+    if(is_null_disp(vthis)) {
+        if(r) *r = jsval_null_disp();
+        return S_OK;
+    }
+
     hres = to_object(ctx, vthis, &disp);
     if(FAILED(hres))
         return hres;
@@ -554,7 +559,7 @@ static HRESULT jsdisp_define_properties(script_ctx_t *ctx, jsdisp_t *obj, jsval_
         if(FAILED(hres))
             break;
 
-        if(!is_object_instance(desc_val) || !get_object(desc_val) || !(desc_obj = to_jsdisp(get_object(desc_val)))) {
+        if(!is_object_instance(desc_val) || !(desc_obj = to_jsdisp(get_object(desc_val)))) {
             jsval_release(desc_val);
             break;
         }
@@ -631,7 +636,7 @@ static HRESULT Object_defineProperties(script_ctx_t *ctx, jsval_t vthis, WORD fl
     jsdisp_t *obj;
     HRESULT hres;
 
-    if(argc < 1 || !is_object_instance(argv[0]) || !get_object(argv[0]) || !(obj = to_jsdisp(get_object(argv[0])))) {
+    if(argc < 1 || !is_object_instance(argv[0]) || !(obj = to_jsdisp(get_object(argv[0])))) {
         FIXME("not an object\n");
         return E_NOTIMPL;
     }
@@ -779,7 +784,7 @@ static HRESULT object_keys(script_ctx_t *ctx, jsval_t arg, enum jsdisp_enum_type
     jsstr_t *key;
     HRESULT hres;
 
-    if(!is_object_instance(arg) || !get_object(arg)) {
+    if(!is_object_instance(arg)) {
         FIXME("invalid arguments %s\n", debugstr_jsval(arg));
         return E_NOTIMPL;
     }
@@ -838,7 +843,7 @@ static HRESULT Object_preventExtensions(script_ctx_t *ctx, jsval_t vthis, WORD f
 {
     jsdisp_t *obj;
 
-    if(!argc || !is_object_instance(argv[0]) || !get_object(argv[0])) {
+    if(!argc || !is_object_instance(argv[0])) {
         FIXME("invalid arguments\n");
         return E_NOTIMPL;
     }
@@ -861,7 +866,7 @@ static HRESULT Object_freeze(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsig
 {
     jsdisp_t *obj;
 
-    if(!argc || !is_object_instance(argv[0]) || !get_object(argv[0])) {
+    if(!argc || !is_object_instance(argv[0])) {
         WARN("argument is not an object\n");
         return JS_E_OBJECT_EXPECTED;
     }
@@ -884,7 +889,7 @@ static HRESULT Object_seal(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigne
 {
     jsdisp_t *obj;
 
-    if(!argc || !is_object_instance(argv[0]) || !get_object(argv[0])) {
+    if(!argc || !is_object_instance(argv[0])) {
         WARN("argument is not an object\n");
         return JS_E_OBJECT_EXPECTED;
     }
@@ -906,7 +911,7 @@ static HRESULT Object_isExtensible(script_ctx_t *ctx, jsval_t vthis, WORD flags,
 {
     jsdisp_t *obj;
 
-    if(!argc || !is_object_instance(argv[0]) || !get_object(argv[0])) {
+    if(!argc || !is_object_instance(argv[0])) {
         WARN("argument is not an object\n");
         return JS_E_OBJECT_EXPECTED;
     }
@@ -928,7 +933,7 @@ static HRESULT Object_isFrozen(script_ctx_t *ctx, jsval_t vthis, WORD flags, uns
 {
     jsdisp_t *obj;
 
-    if(!argc || !is_object_instance(argv[0]) || !get_object(argv[0])) {
+    if(!argc || !is_object_instance(argv[0])) {
         WARN("argument is not an object\n");
         return JS_E_OBJECT_EXPECTED;
     }
@@ -950,7 +955,7 @@ static HRESULT Object_isSealed(script_ctx_t *ctx, jsval_t vthis, WORD flags, uns
 {
     jsdisp_t *obj;
 
-    if(!argc || !is_object_instance(argv[0]) || !get_object(argv[0])) {
+    if(!argc || !is_object_instance(argv[0])) {
         WARN("argument is not an object\n");
         return JS_E_OBJECT_EXPECTED;
     }
@@ -1005,7 +1010,7 @@ static HRESULT ObjectConstr_value(script_ctx_t *ctx, jsval_t vthis, WORD flags,
         jsdisp_t *obj;
 
         if(argc) {
-            if(!is_undefined(argv[0]) && !is_null(argv[0]) && (!is_object_instance(argv[0]) || get_object(argv[0]))) {
+            if(!is_undefined(argv[0]) && !is_null(argv[0])) {
                 IDispatch *disp;
 
                 hres = to_object(ctx, argv[0], &disp);
diff --git a/dlls/jscript/set.c b/dlls/jscript/set.c
index 35edcf8..7973d42 100644
--- a/dlls/jscript/set.c
+++ b/dlls/jscript/set.c
@@ -274,7 +274,7 @@ static HRESULT Map_forEach(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigne
 
     TRACE("%p (%s)\n", map, debugstr_jsval(argc >= 1 ? argv[0] : jsval_undefined()));
 
-    if(!is_object_instance(callback) || !get_object(callback)) {
+    if(!is_object_instance(callback)) {
         FIXME("invalid callback %s\n", debugstr_jsval(callback));
         return E_FAIL;
     }
diff --git a/dlls/jscript/tests/api.js b/dlls/jscript/tests/api.js
index 8e2b0d6..9eaeddd 100644
--- a/dlls/jscript/tests/api.js
+++ b/dlls/jscript/tests/api.js
@@ -1926,6 +1926,7 @@ ok(isNaN(tmp), "Math.tan(-Infinity) is not NaN");
         [[true], "true"],
         [[false], "false"],
         [[null], "null"],
+        [[nullDisp], undefined],
         [[1], "1"],
         [["test"], "\"test\""],
         [["test\"\\\b\f\n\r\t\u0002 !"], "\"test\\\"\\\\\\b\\f\\n\\r\\t\\u0002 !\""],
@@ -2367,6 +2368,9 @@ ok(bool.toString() === "true", "bool.toString() = " + bool.toString());
 ok(bool.valueOf() === Boolean(1), "bool.valueOf() = " + bool.valueOf());
 ok(bool.toLocaleString() === bool.toString(), "bool.toLocaleString() = " + bool.toLocaleString());
 
+tmp = Object.prototype.valueOf.call(nullDisp);
+ok(tmp === nullDisp, "nullDisp.valueOf != nullDisp");
+
 ok(ActiveXObject instanceof Function, "ActiveXObject is not instance of Function");
 ok(ActiveXObject.prototype instanceof Object, "ActiveXObject.prototype is not instance of Object");
 
@@ -2574,6 +2578,7 @@ testException(function() {createArray().getItem(3);}, "E_SUBSCRIPT_OUT_OF_RANGE"
 testException(function() {date.setTime();}, "E_ARG_NOT_OPT");
 testException(function() {date.setYear();}, "E_ARG_NOT_OPT");
 testException(function() {arr.test();}, "E_NO_PROPERTY");
+testException(function() {[1,2,3].sort(nullDisp);}, "E_JSCRIPT_EXPECTED");
 testException(function() {Number.prototype.toString.call(arr);}, "E_NOT_NUM");
 testException(function() {Number.prototype.toFixed.call(arr);}, "E_NOT_NUM");
 testException(function() {(new Number(3)).toString(1);}, "E_INVALID_CALL_ARG");
@@ -2587,6 +2592,9 @@ testException(function() {eval("nonexistingfunc()")}, "E_OBJECT_EXPECTED");
 testException(function() {(new Object()) instanceof 3;}, "E_NOT_FUNC");
 testException(function() {(new Object()) instanceof null;}, "E_NOT_FUNC");
 testException(function() {(new Object()) instanceof nullDisp;}, "E_NOT_FUNC");
+testException(function() {nullDisp instanceof Object;}, "E_OBJECT_EXPECTED");
+testException(function() {Function.prototype.apply.call(nullDisp, Object, []);}, "E_OBJECT_REQUIRED");
+testException(function() {Function.prototype.call.call(nullDisp, Object);}, "E_OBJECT_REQUIRED");
 testException(function() {"test" in 3;}, "E_OBJECT_EXPECTED");
 testException(function() {"test" in null;}, "E_OBJECT_EXPECTED");
 testException(function() {"test" in nullDisp;}, "E_OBJECT_EXPECTED");
diff --git a/dlls/jscript/tests/lang.js b/dlls/jscript/tests/lang.js
index 23c9c79..cf08423 100644
--- a/dlls/jscript/tests/lang.js
+++ b/dlls/jscript/tests/lang.js
@@ -1906,6 +1906,8 @@ ok(getVT(true && nullDisp) === "VT_DISPATCH",
    "getVT(0 && nullDisp) = " + getVT(true && nullDisp));
 ok(!nullDisp === true, "!nullDisp = " + !nullDisp);
 ok(String(nullDisp) === "null", "String(nullDisp) = " + String(nullDisp));
+ok(+nullDisp === 0, "+nullDisp !== 0");
+ok(''+nullDisp === "null", "''+nullDisp !== null");
 ok(nullDisp != new Object(), "nullDisp == new Object()");
 ok(new Object() != nullDisp, "new Object() == nullDisp");
 ok((typeof Object(nullDisp)) === "object", "typeof Object(nullDisp) !== 'object'");
-- 
2.34.1




More information about the wine-devel mailing list