Module: wine Branch: master Commit: 1f49903e66b0a401e47e5951634c804a4b0d242c URL: https://source.winehq.org/git/wine.git/?a=commit;h=1f49903e66b0a401e47e59516...
Author: Jacek Caban jacek@codeweavers.com Date: Fri Apr 2 20:24:37 2021 +0200
jscript: Add Object.isFrozen and Object.isSealed implementation.
Signed-off-by: Jacek Caban jacek@codeweavers.com Signed-off-by: Alexandre Julliard julliard@winehq.org
---
dlls/jscript/dispex.c | 20 ++++++++++++++ dlls/jscript/jscript.h | 1 + dlls/jscript/object.c | 46 ++++++++++++++++++++++++++++++++ dlls/mshtml/tests/es5.js | 68 ++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 135 insertions(+)
diff --git a/dlls/jscript/dispex.c b/dlls/jscript/dispex.c index b62fcee0b04..188de659c4a 100644 --- a/dlls/jscript/dispex.c +++ b/dlls/jscript/dispex.c @@ -2646,6 +2646,26 @@ void jsdisp_freeze(jsdisp_t *obj, BOOL seal) obj->extensible = FALSE; }
+BOOL jsdisp_is_frozen(jsdisp_t *obj, BOOL sealed) +{ + unsigned int i; + + if(obj->extensible) + return FALSE; + + for(i = 0; i < obj->prop_cnt; i++) { + if(obj->props[i].type == PROP_JSVAL) { + if(!sealed && (obj->props[i].flags & PROPF_WRITABLE)) + return FALSE; + }else if(obj->props[i].type != PROP_ACCESSOR) + continue; + if(obj->props[i].flags & PROPF_CONFIGURABLE) + return FALSE; + } + + return TRUE; +} + HRESULT jsdisp_get_prop_name(jsdisp_t *obj, DISPID id, jsstr_t **r) { dispex_prop_t *prop = get_prop(obj, id); diff --git a/dlls/jscript/jscript.h b/dlls/jscript/jscript.h index ec5001af117..3c870a68a54 100644 --- a/dlls/jscript/jscript.h +++ b/dlls/jscript/jscript.h @@ -318,6 +318,7 @@ HRESULT jsdisp_define_data_property(jsdisp_t*,const WCHAR*,unsigned,jsval_t) DEC HRESULT jsdisp_next_prop(jsdisp_t*,DISPID,BOOL,DISPID*) DECLSPEC_HIDDEN; HRESULT jsdisp_get_prop_name(jsdisp_t*,DISPID,jsstr_t**); void jsdisp_freeze(jsdisp_t*,BOOL) DECLSPEC_HIDDEN; +BOOL jsdisp_is_frozen(jsdisp_t*,BOOL) DECLSPEC_HIDDEN;
HRESULT create_builtin_function(script_ctx_t*,builtin_invoke_t,const WCHAR*,const builtin_info_t*,DWORD, jsdisp_t*,jsdisp_t**) DECLSPEC_HIDDEN; diff --git a/dlls/jscript/object.c b/dlls/jscript/object.c index 86c656a719a..b957ea58bdf 100644 --- a/dlls/jscript/object.c +++ b/dlls/jscript/object.c @@ -760,6 +760,50 @@ static HRESULT Object_isExtensible(script_ctx_t *ctx, vdisp_t *jsthis, WORD flag return S_OK; }
+static HRESULT Object_isFrozen(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, + jsval_t *argv, jsval_t *r) +{ + jsdisp_t *obj; + + if(!argc || !is_object_instance(argv[0]) || !get_object(argv[0])) { + WARN("argument is not an object\n"); + return JS_E_OBJECT_EXPECTED; + } + + 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 = jsval_bool(jsdisp_is_frozen(obj, FALSE)); + return S_OK; +} + +static HRESULT Object_isSealed(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, + jsval_t *argv, jsval_t *r) +{ + jsdisp_t *obj; + + if(!argc || !is_object_instance(argv[0]) || !get_object(argv[0])) { + WARN("argument is not an object\n"); + return JS_E_OBJECT_EXPECTED; + } + + 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 = jsval_bool(jsdisp_is_frozen(obj, TRUE)); + return S_OK; +} + static const builtin_prop_t ObjectConstr_props[] = { {L"create", Object_create, PROPF_ES5|PROPF_METHOD|2}, {L"defineProperties", Object_defineProperties, PROPF_ES5|PROPF_METHOD|2}, @@ -768,6 +812,8 @@ static const builtin_prop_t ObjectConstr_props[] = { {L"getOwnPropertyDescriptor", Object_getOwnPropertyDescriptor, PROPF_ES5|PROPF_METHOD|2}, {L"getPrototypeOf", Object_getPrototypeOf, PROPF_ES5|PROPF_METHOD|1}, {L"isExtensible", Object_isExtensible, PROPF_ES5|PROPF_METHOD|1}, + {L"isFrozen", Object_isFrozen, PROPF_ES5|PROPF_METHOD|1}, + {L"isSealed", Object_isSealed, PROPF_ES5|PROPF_METHOD|1}, {L"keys", Object_keys, PROPF_ES5|PROPF_METHOD|1}, {L"preventExtensions", Object_preventExtensions, PROPF_ES5|PROPF_METHOD|1}, {L"seal", Object_seal, PROPF_ES5|PROPF_METHOD|1}, diff --git a/dlls/mshtml/tests/es5.js b/dlls/mshtml/tests/es5.js index 9227fa7e5a5..474c09d3bd7 100644 --- a/dlls/mshtml/tests/es5.js +++ b/dlls/mshtml/tests/es5.js @@ -1104,6 +1104,74 @@ sync_test("seal", function() { ok(o.length === 1, "o.length = " + o.length); });
+sync_test("isFrozen", function() { + ok(Object.isFrozen.length === 1, "Object.isFrozen.length = " + Object.isFrozen.length); + ok(Object.isSealed.length === 1, "Object.isSealed.length = " + Object.isSealed.length); + + var o = Object.freeze({}); + ok(Object.isFrozen(o) === true, "o is not frozen"); + ok(Object.isSealed(o) === true, "o is not sealed"); + ok(Object.isExtensible(o) === false, "o is extensible"); + + ok(Object.isFrozen({}) === false, "{} is frozen"); + ok(Object.isSealed({}) === false, "{} is sealed"); + + o = Object.preventExtensions({}); + ok(Object.isFrozen(o) === true, "o is not frozen"); + ok(Object.isSealed(o) === true, "o is not sealed"); + ok(Object.isExtensible(o) === false, "o is extensible"); + + o = Object.preventExtensions({ prop: 1 }); + ok(Object.isFrozen(o) === false, "o is frozen"); + ok(Object.isSealed(o) === false, "o is sealed"); + ok(Object.isExtensible(o) === false, "o is extensible"); + + o = Object.freeze({ prop: 1 }); + ok(Object.isFrozen(o) === true, "o is not frozen"); + ok(Object.isSealed(o) === true, "o is not sealed"); + ok(Object.isExtensible(o) === false, "o is extensible"); + + o = Object.seal({ prop: 1 }); + ok(Object.isFrozen(o) === false, "o is frozen"); + ok(Object.isSealed(o) === true, "o is not sealed"); + ok(Object.isExtensible(o) === false, "o is extensible"); + + o = {}; + Object.defineProperty(o, "prop", { value: 1 }); + Object.preventExtensions(o); + ok(Object.isFrozen(o) === true, "o is not frozen"); + ok(Object.isSealed(o) === true, "o is not sealed"); + ok(Object.isExtensible(o) === false, "o is extensible"); + + o = {}; + Object.defineProperty(o, "prop", { value: 1, writable: true }); + Object.preventExtensions(o); + ok(Object.isFrozen(o) === false, "o is frozen"); + ok(Object.isSealed(o) === true, "o is not sealed"); + ok(Object.isExtensible(o) === false, "o is extensible"); + + o = {}; + Object.defineProperty(o, "prop", { value: 1, writable: true, configurable: true }); + Object.preventExtensions(o); + ok(Object.isFrozen(o) === false, "o is frozen"); + ok(Object.isSealed(o) === false, "o is sealed"); + ok(Object.isExtensible(o) === false, "o is extensible"); + + o = {}; + Object.defineProperty(o, "prop", { value: 1, configurable: true }); + Object.preventExtensions(o); + ok(Object.isFrozen(o) === false, "o is frozen"); + ok(Object.isSealed(o) === false, "o is sealed"); + ok(Object.isExtensible(o) === false, "o is extensible"); + + o = {}; + Object.defineProperty(o, "prop", { get: function() {}, set: function() {} }); + Object.preventExtensions(o); + ok(Object.isFrozen(o) === true, "o is not frozen"); + ok(Object.isSealed(o) === true, "o is not sealed"); + ok(Object.isExtensible(o) === false, "o is extensible"); +}); + sync_test("head_setter", function() { document.head = ""; ok(typeof(document.head) === "object", "typeof(document.head) = " + typeof(document.head));