This makes sure that object instances are always non-NULL and gets rid of all such checks.
Signed-off-by: Gabriel Ivăncescu gabrielopcode@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'");
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com --- dlls/jscript/object.c | 47 +++++++++++++++++ dlls/mshtml/tests/documentmode.js | 88 +++++++++++++++++++++++++++++++ 2 files changed, 135 insertions(+)
diff --git a/dlls/jscript/object.c b/dlls/jscript/object.c index 9d4a747..13cb5ff 100644 --- a/dlls/jscript/object.c +++ b/dlls/jscript/object.c @@ -294,6 +294,52 @@ done: return hres; }
+static HRESULT Object_defineGetter(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r) +{ + property_desc_t desc; + const WCHAR *name; + jsstr_t *name_str; + jsdisp_t *jsthis; + HRESULT hres; + + TRACE("\n"); + + if(!is_object_instance(vthis) || !(jsthis = to_jsdisp(get_object(vthis)))) + goto done; + + hres = to_flat_string(ctx, argc ? argv[0] : jsval_undefined(), &name_str, &name); + if(FAILED(hres)) + return hres; + + if(argc < 2 || !is_object_instance(argv[1])) + hres = JS_E_FUNCTION_EXPECTED; + else { + hres = S_OK; + desc.getter = to_jsdisp(get_object(argv[1])); + if(!desc.getter) { + FIXME("getter is not JS object\n"); + hres = E_NOTIMPL; + } + /* FIXME: Check IsCallable */ + } + + if(SUCCEEDED(hres)) { + desc.flags = desc.mask = PROPF_CONFIGURABLE | PROPF_ENUMERABLE; + desc.explicit_getter = TRUE; + desc.explicit_setter = FALSE; + desc.explicit_value = FALSE; + desc.setter = NULL; + hres = jsdisp_define_property(jsthis, name, &desc); + } + jsstr_release(name_str); + if(FAILED(hres)) + return hres; +done: + if(r) + *r = jsval_undefined(); + return S_OK; +} + HRESULT Object_get_proto_(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r) { jsdisp_t *jsthis; @@ -365,6 +411,7 @@ static void Object_destructor(jsdisp_t *dispex) }
static const builtin_prop_t Object_props[] = { + {L"__defineGetter__", Object_defineGetter, PROPF_METHOD|PROPF_ES6|2}, {L"hasOwnProperty", Object_hasOwnProperty, PROPF_METHOD|1}, {L"isPrototypeOf", Object_isPrototypeOf, PROPF_METHOD|1}, {L"propertyIsEnumerable", Object_propertyIsEnumerable, PROPF_METHOD|1}, diff --git a/dlls/mshtml/tests/documentmode.js b/dlls/mshtml/tests/documentmode.js index 2902902..18dd65e 100644 --- a/dlls/mshtml/tests/documentmode.js +++ b/dlls/mshtml/tests/documentmode.js @@ -1415,6 +1415,94 @@ sync_test("__proto__", function() { } });
+sync_test("__defineGetter__", function() { + var v = document.documentMode; + var r, x = 42; + + if(v < 11) { + ok(x.__defineGetter__ === undefined, "x.__defineGetter__ = " + x.__defineGetter__); + ok(!("__defineGetter__" in Object), "Object.__defineGetter__ = " + Object.__defineGetter__); + return; + } + ok(Object.prototype.hasOwnProperty("__defineGetter__"), "__defineGetter__ is not a property of Object.prototype"); + ok(Object.prototype.__defineGetter__.length === 2, "__defineGetter__.length = " + Object.prototype.__defineGetter__.length); + + function getter() { return "wine"; } + function setter(val) { } + + r = x.__defineGetter__("foo", getter); + ok(r === undefined, "__defineGetter__ on 42 returned " + r); + ok(x.foo === undefined, "42.foo = " + x.foo); + + x = {}; + r = x.__defineGetter__("foo", getter); + ok(r === undefined, "__defineGetter__ returned " + r); + ok(x.foo === "wine", "x.foo = " + x.foo); + r = Object.getOwnPropertyDescriptor(x, "foo"); + ok(r.value === undefined, "x.foo value = " + r.value); + ok(r.get === getter, "x.foo get = " + r.get); + ok(r.set === undefined, "x.foo set = " + r.set); + ok(r.writable === undefined, "x.foo writable = " + r.writable); + ok(r.enumerable === true, "x.foo enumerable = " + r.enumerable); + ok(r.configurable === true, "x.foo configurable = " + r.configurable); + + Object.defineProperty(x, "foo", { get: undefined, set: setter, configurable: false }); + r = Object.getOwnPropertyDescriptor(x, "foo"); + ok(r.value === undefined, "x.foo setter value = " + r.value); + ok(r.get === undefined, "x.foo setter get = " + r.get); + ok(r.set === setter, "x.foo setter set = " + r.set); + ok(r.writable === undefined, "x.foo setter writable = " + r.writable); + ok(r.enumerable === true, "x.foo setter enumerable = " + r.enumerable); + ok(r.configurable === false, "x.foo setter configurable = " + r.configurable); + try { + x.__defineGetter__("foo", getter); + ok(false, "expected exception calling __defineGetter__ on non-configurable property"); + }catch(e) { + ok(e.number === 0xa13d6 - 0x80000000, "__defineGetter__ on non-configurable property threw exception " + e.number); + } + + r = Object.prototype.__defineGetter__.call(undefined, "bar", getter); + ok(r === undefined, "__defineGetter__ on undefined returned " + r); + r = Object.prototype.__defineGetter__.call(null, "bar", getter); + ok(r === undefined, "__defineGetter__ on null returned " + r); + r = x.__defineGetter__(undefined, getter); + ok(r === undefined, "__defineGetter__ undefined prop returned " + r); + ok(x["undefined"] === "wine", "x.undefined = " + x["undefined"]); + r = x.__defineGetter__(false, getter); + ok(r === undefined, "__defineGetter__ undefined prop returned " + r); + ok(x["false"] === "wine", "x.false = " + x["false"]); + + try { + x.__defineGetter__("bar", "string"); + ok(false, "expected exception calling __defineGetter__ with string"); + }catch(e) { + ok(e.number === 0xa138a - 0x80000000, "__defineGetter__ with string threw exception " + e.number); + } + try { + x.__defineGetter__("bar", undefined); + ok(false, "expected exception calling __defineGetter__ with undefined"); + }catch(e) { + ok(e.number === 0xa138a - 0x80000000, "__defineGetter__ with undefined threw exception " + e.number); + } + try { + x.__defineGetter__("bar", null); + ok(false, "expected exception calling __defineGetter__ with null"); + }catch(e) { + ok(e.number === 0xa138a - 0x80000000, "__defineGetter__ with null threw exception " + e.number); + } + try { + Object.prototype.__defineGetter__.call(x, "bar"); + ok(false, "expected exception calling __defineGetter__ with only one arg"); + }catch(e) { + ok(e.number === 0xa138a - 0x80000000, "__defineGetter__ with only one arg threw exception " + e.number); + } + + x.bar = "test"; + ok(x.bar === "test", "x.bar = " + x.bar); + x.__defineGetter__("bar", getter); + ok(x.bar === "wine", "x.bar with getter = " + x.bar); +}); + async_test("postMessage", function() { var v = document.documentMode; var onmessage_called = false;
Hi,
While running your changed tests, I think I found new failures. Being a bot and all I'm not very good at pattern recognition, so I might be wrong, but could you please double-check?
Full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=111176
Your paranoid android.
=== debian11 (32 bit French report) ===
Report validation errors: mshtml:htmldoc has no test summary line (early exit of the main process?) mshtml:htmldoc has unaccounted for todo messages mshtml:htmldoc returned a non-zero exit code despite reporting no failures
Hi Gabriel,
On 3/24/22 16:31, Gabriel Ivăncescu wrote:
- hres = to_flat_string(ctx, argc ? argv[0] : jsval_undefined(), &name_str, &name);
- if(FAILED(hres))
return hres;
- if(argc < 2 || !is_object_instance(argv[1]))
hres = JS_E_FUNCTION_EXPECTED;
- else {
hres = S_OK;
desc.getter = to_jsdisp(get_object(argv[1]));
if(!desc.getter) {
FIXME("getter is not JS object\n");
hres = E_NOTIMPL;
}
/* FIXME: Check IsCallable */
- }
According to the spec, argv[1] is validated before to_string(argv[0]). If you followed spec, error handling could be also nicer here.
Thanks,
Jacek
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com --- dlls/jscript/object.c | 47 +++++++++++++++ dlls/mshtml/tests/documentmode.js | 95 +++++++++++++++++++++++++++++++ 2 files changed, 142 insertions(+)
diff --git a/dlls/jscript/object.c b/dlls/jscript/object.c index 13cb5ff..a697b63 100644 --- a/dlls/jscript/object.c +++ b/dlls/jscript/object.c @@ -340,6 +340,52 @@ done: return S_OK; }
+static HRESULT Object_defineSetter(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r) +{ + property_desc_t desc; + const WCHAR *name; + jsstr_t *name_str; + jsdisp_t *jsthis; + HRESULT hres; + + TRACE("\n"); + + if(!is_object_instance(vthis) || !(jsthis = to_jsdisp(get_object(vthis)))) + goto done; + + hres = to_flat_string(ctx, argc ? argv[0] : jsval_undefined(), &name_str, &name); + if(FAILED(hres)) + return hres; + + if(argc < 2 || !is_object_instance(argv[1])) + hres = JS_E_FUNCTION_EXPECTED; + else { + hres = S_OK; + desc.setter = to_jsdisp(get_object(argv[1])); + if(!desc.setter) { + FIXME("setter is not JS object\n"); + hres = E_NOTIMPL; + } + /* FIXME: Check IsCallable */ + } + + if(SUCCEEDED(hres)) { + desc.flags = desc.mask = PROPF_CONFIGURABLE | PROPF_ENUMERABLE; + desc.explicit_getter = FALSE; + desc.explicit_setter = TRUE; + desc.explicit_value = FALSE; + desc.getter = NULL; + hres = jsdisp_define_property(jsthis, name, &desc); + } + jsstr_release(name_str); + if(FAILED(hres)) + return hres; +done: + if(r) + *r = jsval_undefined(); + return S_OK; +} + HRESULT Object_get_proto_(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r) { jsdisp_t *jsthis; @@ -412,6 +458,7 @@ static void Object_destructor(jsdisp_t *dispex)
static const builtin_prop_t Object_props[] = { {L"__defineGetter__", Object_defineGetter, PROPF_METHOD|PROPF_ES6|2}, + {L"__defineSetter__", Object_defineSetter, PROPF_METHOD|PROPF_ES6|2}, {L"hasOwnProperty", Object_hasOwnProperty, PROPF_METHOD|1}, {L"isPrototypeOf", Object_isPrototypeOf, PROPF_METHOD|1}, {L"propertyIsEnumerable", Object_propertyIsEnumerable, PROPF_METHOD|1}, diff --git a/dlls/mshtml/tests/documentmode.js b/dlls/mshtml/tests/documentmode.js index 18dd65e..4a776f8 100644 --- a/dlls/mshtml/tests/documentmode.js +++ b/dlls/mshtml/tests/documentmode.js @@ -1503,6 +1503,101 @@ sync_test("__defineGetter__", function() { ok(x.bar === "wine", "x.bar with getter = " + x.bar); });
+sync_test("__defineSetter__", function() { + var v = document.documentMode; + var r, x = 42; + + if(v < 11) { + ok(x.__defineSetter__ === undefined, "x.__defineSetter__ = " + x.__defineSetter__); + ok(!("__defineSetter__" in Object), "Object.__defineSetter__ = " + Object.__defineSetter__); + return; + } + ok(Object.prototype.hasOwnProperty("__defineSetter__"), "__defineSetter__ is not a property of Object.prototype"); + ok(Object.prototype.__defineSetter__.length === 2, "__defineSetter__.length = " + Object.prototype.__defineSetter__.length); + + function getter() { return "wine"; } + function setter(val) { this.setterVal = val - 1; } + + r = x.__defineSetter__("foo", setter); + ok(r === undefined, "__defineSetter__ on 42 returned " + r); + ok(x.foo === undefined, "42.foo = " + x.foo); + + x = {}; + r = x.__defineSetter__("foo", setter); + ok(r === undefined, "__defineSetter__ returned " + r); + ok(x.setterVal === undefined, "x.setterVal = " + x.setterVal); + x.foo = 13; + ok(x.setterVal === 12, "x.setterVal = " + x.setterVal); + r = Object.getOwnPropertyDescriptor(x, "foo"); + ok(r.value === undefined, "x.foo value = " + r.value); + ok(r.get === undefined, "x.foo get = " + r.get); + ok(r.set === setter, "x.foo set = " + r.set); + ok(r.writable === undefined, "x.foo writable = " + r.writable); + ok(r.enumerable === true, "x.foo enumerable = " + r.enumerable); + ok(r.configurable === true, "x.foo configurable = " + r.configurable); + + Object.defineProperty(x, "foo", { get: getter, set: undefined, configurable: false }); + r = Object.getOwnPropertyDescriptor(x, "foo"); + ok(r.value === undefined, "x.foo getter value = " + r.value); + ok(r.get === getter, "x.foo getter get = " + r.get); + ok(r.set === undefined, "x.foo getter set = " + r.set); + ok(r.writable === undefined, "x.foo getter writable = " + r.writable); + ok(r.enumerable === true, "x.foo getter enumerable = " + r.enumerable); + ok(r.configurable === false, "x.foo getter configurable = " + r.configurable); + try { + x.__defineSetter__("foo", setter); + ok(false, "expected exception calling __defineSetter__ on non-configurable property"); + }catch(e) { + ok(e.number === 0xa13d6 - 0x80000000, "__defineSetter__ on non-configurable property threw exception " + e.number); + } + + r = Object.prototype.__defineSetter__.call(undefined, "bar", setter); + ok(r === undefined, "__defineSetter__ on undefined returned " + r); + r = Object.prototype.__defineSetter__.call(null, "bar", setter); + ok(r === undefined, "__defineSetter__ on null returned " + r); + r = x.__defineSetter__(null, setter); + ok(r === undefined, "__defineSetter__ null prop returned " + r); + x["null"] = 100; + ok(x.setterVal === 99, "x.setterVal after setting x.null = " + x.setterVal); + r = x.__defineSetter__(50, setter); + ok(r === undefined, "__defineSetter__ 50 prop returned " + r); + x["50"] = 33; + ok(x.setterVal === 32, "x.setterVal after setting x.50 = " + x.setterVal); + + try { + x.__defineSetter__("bar", true); + ok(false, "expected exception calling __defineSetter__ with bool"); + }catch(e) { + ok(e.number === 0xa138a - 0x80000000, "__defineSetter__ with bool threw exception " + e.number); + } + try { + x.__defineSetter__("bar", undefined); + ok(false, "expected exception calling __defineSetter__ with undefined"); + }catch(e) { + ok(e.number === 0xa138a - 0x80000000, "__defineSetter__ with undefined threw exception " + e.number); + } + try { + x.__defineSetter__("bar", null); + ok(false, "expected exception calling __defineSetter__ with null"); + }catch(e) { + ok(e.number === 0xa138a - 0x80000000, "__defineSetter__ with null threw exception " + e.number); + } + try { + Object.prototype.__defineSetter__.call(x, "bar"); + ok(false, "expected exception calling __defineSetter__ with only one arg"); + }catch(e) { + ok(e.number === 0xa138a - 0x80000000, "__defineSetter__ with only one arg threw exception " + e.number); + } + + x.bar = "test"; + ok(x.bar === "test", "x.bar = " + x.bar); + x.__defineSetter__("bar", setter); + ok(x.bar === undefined, "x.bar with setter = " + x.bar); + x.bar = 10; + ok(x.bar === undefined, "x.bar with setter = " + x.bar); + ok(x.setterVal === 9, "x.setterVal after setting bar = " + x.setterVal); +}); + async_test("postMessage", function() { var v = document.documentMode; var onmessage_called = false;
According to the ES6 spec, they don't throw anymore (compared to ES5), but native IE seems to not follow it here and throws anyway.
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com --- dlls/jscript/object.c | 18 ++++++------------ dlls/mshtml/tests/documentmode.js | 24 ++++++++++++++++++++++++ 2 files changed, 30 insertions(+), 12 deletions(-)
diff --git a/dlls/jscript/object.c b/dlls/jscript/object.c index a697b63..62a105f 100644 --- a/dlls/jscript/object.c +++ b/dlls/jscript/object.c @@ -850,10 +850,8 @@ static HRESULT Object_getPrototypeOf(script_ctx_t *ctx, jsval_t vthis, WORD flag { jsdisp_t *obj;
- if(!argc || !is_object_instance(argv[0])) { - FIXME("invalid arguments\n"); - return E_NOTIMPL; - } + if(!argc || !is_object_instance(argv[0])) + return JS_E_OBJECT_EXPECTED;
TRACE("(%s)\n", debugstr_jsval(argv[0]));
@@ -878,10 +876,8 @@ 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)) { - FIXME("invalid arguments %s\n", debugstr_jsval(arg)); - return E_NOTIMPL; - } + if(!is_object_instance(arg)) + return JS_E_OBJECT_EXPECTED;
obj = to_jsdisp(get_object(arg)); if(!obj) { @@ -937,10 +933,8 @@ static HRESULT Object_preventExtensions(script_ctx_t *ctx, jsval_t vthis, WORD f { jsdisp_t *obj;
- if(!argc || !is_object_instance(argv[0])) { - FIXME("invalid arguments\n"); - return E_NOTIMPL; - } + if(!argc || !is_object_instance(argv[0])) + return JS_E_OBJECT_EXPECTED;
TRACE("(%s)\n", debugstr_jsval(argv[0]));
diff --git a/dlls/mshtml/tests/documentmode.js b/dlls/mshtml/tests/documentmode.js index 4a776f8..b4d0beb 100644 --- a/dlls/mshtml/tests/documentmode.js +++ b/dlls/mshtml/tests/documentmode.js @@ -1278,6 +1278,30 @@ sync_test("elem_attr", function() { } });
+sync_test("builtins_diffs", function() { + var v = document.documentMode; + + /* despite what spec says for ES6, IE still throws */ + var props = [ + "freeze", + "getPrototypeOf", + "isExtensible", + "isFrozen", + "isSealed", + "keys", + "preventExtensions", + "seal" + ]; + for(var i = 0; i < props.length; i++) { + try { + Object[props[i]]("test"); + ok(false, "Object." + props[i] + " with non-object: expected exception"); + }catch(e) { + ok(e.number === (v < 9 ? 0xa01b6 : 0xa138f) - 0x80000000, "Object." + props[i] + " with non-object: exception = " + e.number); + } + } +}); + sync_test("__proto__", function() { var v = document.documentMode; var r, x = 42;
Hi,
While running your changed tests, I think I found new failures. Being a bot and all I'm not very good at pattern recognition, so I might be wrong, but could you please double-check?
Full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=111178
Your paranoid android.
=== w10pro64_he (64 bit report) ===
mshtml: htmldoc.c:2541: Test failed: unexpected call UpdateUI htmldoc.c:2853: Test failed: unexpected call Exec_UPDATECOMMANDS
=== w7u_adm (32 bit report) ===
mshtml: script.c:624: Test failed: L"/index.html?es5.js:date_now: unexpected Date.now() result 1648144082912 expected 1648144082967"
According to the ES6 spec, it should work in generic way for objects exposing "source" and "flags", but native IE seems to not follow it here and throws.
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com ---
FFXIV Launcher checks for this.
dlls/mshtml/tests/documentmode.js | 7 +++++++ 1 file changed, 7 insertions(+)
diff --git a/dlls/mshtml/tests/documentmode.js b/dlls/mshtml/tests/documentmode.js index b4d0beb..3f772cf 100644 --- a/dlls/mshtml/tests/documentmode.js +++ b/dlls/mshtml/tests/documentmode.js @@ -1300,6 +1300,13 @@ sync_test("builtins_diffs", function() { ok(e.number === (v < 9 ? 0xa01b6 : 0xa138f) - 0x80000000, "Object." + props[i] + " with non-object: exception = " + e.number); } } + + try { + RegExp.prototype.toString.call({source: "foo", flags: "g"}); + ok(false, "RegExp.toString with non-regexp: expected exception"); + }catch(e) { + ok(e.number === 0xa1398 - 0x80000000, "RegExp.toString with non-regexp: exception = " + e.number); + } });
sync_test("__proto__", function() {
Hi,
While running your changed tests, I think I found new failures. Being a bot and all I'm not very good at pattern recognition, so I might be wrong, but could you please double-check?
Full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=111179
Your paranoid android.
=== w10pro64_ar (64 bit report) ===
mshtml: htmldoc.c:2541: Test failed: unexpected call UpdateUI htmldoc.c:2853: Test failed: unexpected call Exec_UPDATECOMMANDS htmldoc.c:2541: Test failed: unexpected call UpdateUI htmldoc.c:2853: Test failed: unexpected call Exec_UPDATECOMMANDS htmldoc.c:350: Test failed: expected Exec_SETTITLE htmldoc.c:2859: Test failed: unexpected call Exec_SETTITLE
=== w7u_adm (32 bit report) ===
mshtml: script.c:624: Test failed: L"/index.html?es5.js:date_now: unexpected Date.now() result 1648151687557 expected 1648151687618"
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com --- dlls/jscript/object.c | 7 +------ dlls/mshtml/tests/es5.js | 2 ++ 2 files changed, 3 insertions(+), 6 deletions(-)
diff --git a/dlls/jscript/object.c b/dlls/jscript/object.c index 62a105f..7f5d1ef 100644 --- a/dlls/jscript/object.c +++ b/dlls/jscript/object.c @@ -856,13 +856,8 @@ static HRESULT Object_getPrototypeOf(script_ctx_t *ctx, jsval_t vthis, WORD flag TRACE("(%s)\n", debugstr_jsval(argv[0]));
obj = to_jsdisp(get_object(argv[0])); - if(!obj) { - FIXME("Non-JS object\n"); - return E_NOTIMPL; - } - if(r) - *r = obj->prototype + *r = obj && obj->prototype ? jsval_obj(jsdisp_addref(obj->prototype)) : jsval_null(); return S_OK; diff --git a/dlls/mshtml/tests/es5.js b/dlls/mshtml/tests/es5.js index c03a2c2..0339d9b 100644 --- a/dlls/mshtml/tests/es5.js +++ b/dlls/mshtml/tests/es5.js @@ -803,6 +803,8 @@ sync_test("getPrototypeOf", function() { obj = Object.create(null); ok(!("toString" in obj), "toString is in obj"); ok(Object.getPrototypeOf(obj) === null, "Object.getPrototypeOf(obj) = " + Object.getPrototypeOf(obj)); + + ok(Object.getPrototypeOf(external) === null, "Object.getPrototypeOf(non-JS obj) = " + Object.getPrototypeOf(external)); });
sync_test("toString", function() {
Hi,
While running your changed tests, I think I found new failures. Being a bot and all I'm not very good at pattern recognition, so I might be wrong, but could you please double-check?
Full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=111180
Your paranoid android.
=== w8 (32 bit report) ===
mshtml: htmldoc.c:2541: Test failed: unexpected call UpdateUI htmldoc.c:2853: Test failed: unexpected call Exec_UPDATECOMMANDS htmldoc.c:350: Test failed: expected Exec_SETTITLE htmldoc.c:2859: Test failed: unexpected call Exec_SETTITLE
=== w10pro64_ar (64 bit report) ===
mshtml: htmldoc.c:2541: Test failed: unexpected call UpdateUI htmldoc.c:2853: Test failed: unexpected call Exec_UPDATECOMMANDS htmldoc.c:350: Test failed: expected Exec_SETTITLE htmldoc.c:2859: Test failed: unexpected call Exec_SETTITLE
=== w10pro64_zh_CN (64 bit report) ===
mshtml: htmldoc.c:2541: Test failed: unexpected call UpdateUI htmldoc.c:2853: Test failed: unexpected call Exec_UPDATECOMMANDS htmldoc.c:350: Test failed: expected Exec_SETTITLE htmldoc.c:2859: Test failed: unexpected call Exec_SETTITLE
=== w7u_2qxl (32 bit report) ===
mshtml: script.c:624: Test failed: L"/index.html?es5.js:date_now: unexpected Date.now() result 1648154546815 expected 1648154546876"
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com ---
Tested in the next patch (we use the test_own_data_prop_desc helper to avoid redundancy, which also checks enumerable).
dlls/jscript/dispex.c | 1 + 1 file changed, 1 insertion(+)
diff --git a/dlls/jscript/dispex.c b/dlls/jscript/dispex.c index ef13e29..32265d3 100644 --- a/dlls/jscript/dispex.c +++ b/dlls/jscript/dispex.c @@ -2546,6 +2546,7 @@ HRESULT jsdisp_get_own_property(jsdisp_t *obj, const WCHAR *name, BOOL flags_onl switch(prop->type) { case PROP_BUILTIN: case PROP_JSVAL: + case PROP_IDX: desc->mask |= PROPF_WRITABLE; desc->explicit_value = TRUE; if(!flags_only) {
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com --- dlls/jscript/dispex.c | 17 ++++++++++++++++- dlls/mshtml/tests/es5.js | 28 +++++++++++++++++++++++++++- 2 files changed, 43 insertions(+), 2 deletions(-)
diff --git a/dlls/jscript/dispex.c b/dlls/jscript/dispex.c index 32265d3..6ee02a0 100644 --- a/dlls/jscript/dispex.c +++ b/dlls/jscript/dispex.c @@ -285,7 +285,10 @@ static HRESULT find_prop_name(jsdisp_t *This, unsigned hash, const WCHAR *name, for(ptr = name; is_digit(*ptr) && idx < 0x10000; ptr++) idx = idx*10 + (*ptr-'0'); if(!*ptr && idx < This->builtin_info->idx_length(This)) { - prop = alloc_prop(This, name, PROP_IDX, This->builtin_info->idx_put ? PROPF_WRITABLE : 0); + unsigned flags = PROPF_ENUMERABLE; + if(This->builtin_info->idx_put) + flags |= PROPF_WRITABLE; + prop = alloc_prop(This, name, PROP_IDX, flags); if(!prop) return E_OUTOFMEMORY;
@@ -2444,6 +2447,18 @@ HRESULT jsdisp_next_prop(jsdisp_t *obj, DISPID id, enum jsdisp_enum_type enum_ty HRESULT hres;
if(id == DISPID_STARTENUM) { + if(obj->builtin_info->idx_length) { + unsigned i = 0, len = obj->builtin_info->idx_length(obj); + WCHAR name[12]; + + for(i = 0; i < len; i++) { + swprintf(name, ARRAY_SIZE(name), L"%d", i); + hres = find_prop_name(obj, string_hash(name), name, &iter); + if(FAILED(hres)) + return hres; + } + } + if (enum_type == JSDISP_ENUM_ALL) { hres = fill_protrefs(obj); if(FAILED(hres)) diff --git a/dlls/mshtml/tests/es5.js b/dlls/mshtml/tests/es5.js index 0339d9b..2f78ca8 100644 --- a/dlls/mshtml/tests/es5.js +++ b/dlls/mshtml/tests/es5.js @@ -654,12 +654,38 @@ sync_test("property_definitions", function() { });
sync_test("string_idx", function() { - var s = "foobar"; + var i, s = "foobar"; ok(s[0] === "f", "s[0] = " + s[0]); ok(s[5] === "r", "s[5] = " + s[5]); ok(s[6] === undefined, "s[6] = " + s[6]); ok((delete s[0]) === false, "delete s[0] returned true"); ok((delete s[6]) === true, "delete s[6] returned false"); + s[6] = "X"; + ok(s[6] === undefined, "s[6] = " + s[6]); + + s = new String(s); + test_own_data_prop_desc(s, "0", false, true, false); + test_own_data_prop_desc(s, "1", false, true, false); + ok(!Object.prototype.hasOwnProperty.call(s, "6"), "'6' is a property"); + + s[7] = "X"; + ok(s[7] === "X", "s[7] = " + s[7]); + ok(Object.prototype.hasOwnProperty.call(s, "7"), "'7' not a property"); + + Object.defineProperty(s, "8", {writable: false, enumerable: true, configurable: true, value: "Y"}); + ok(s[8] === "Y", "s[8] = " + s[8]); + ok(Object.prototype.hasOwnProperty.call(s, "8"), "'8' not a property"); + + String.prototype[9] = "Z"; + ok(s[9] === "Z", "s[9] = " + s[9]); + delete String.prototype[9]; + + i = 0; + for(var idx in s) { + ok(s[idx] === "foobar XY"[idx], "enum s[" + idx + "] = " + s[idx]); + i++; + } + ok(i === 8, "enum did " + i + " iterations"); });
sync_test("string_trim", function() {
Hi,
While running your changed tests, I think I found new failures. Being a bot and all I'm not very good at pattern recognition, so I might be wrong, but could you please double-check?
Full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=111182
Your paranoid android.
=== w8 (32 bit report) ===
mshtml: htmldoc.c:2541: Test failed: unexpected call UpdateUI htmldoc.c:2853: Test failed: unexpected call Exec_UPDATECOMMANDS
=== w8 (32 bit report) ===
mshtml: script.c:624: Test failed: L"/index.html?es5.js:string_idx: '7' not a property"
=== w8adm (32 bit report) ===
mshtml: script.c:624: Test failed: L"/index.html?es5.js:string_idx: '7' not a property"
=== w864 (32 bit report) ===
mshtml: script.c:624: Test failed: L"/index.html?es5.js:string_idx: '7' not a property"
=== w864 (64 bit report) ===
mshtml: script.c:624: Test failed: L"/index.html?es5.js:string_idx: '7' not a property"