jscript: Implement Object.prototype.__proto__ property.
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
87ac636cbb
commit
46367d1ecc
|
@ -461,7 +461,8 @@ static HRESULT prop_put(jsdisp_t *This, dispex_prop_t *prop, jsval_t val)
|
|||
prop_iter = prototype_iter->props + prop_iter->u.ref;
|
||||
} while(prop_iter->type == PROP_PROTREF);
|
||||
|
||||
if(prop_iter->type == PROP_ACCESSOR)
|
||||
if(prop_iter->type == PROP_ACCESSOR ||
|
||||
(prop_iter->type == PROP_BUILTIN && prop_iter->u.p->setter))
|
||||
prop = prop_iter;
|
||||
}
|
||||
|
||||
|
@ -2654,6 +2655,26 @@ HRESULT jsdisp_define_data_property(jsdisp_t *obj, const WCHAR *name, unsigned f
|
|||
return jsdisp_define_property(obj, name, &prop_desc);
|
||||
}
|
||||
|
||||
HRESULT jsdisp_change_prototype(jsdisp_t *obj, jsdisp_t *proto)
|
||||
{
|
||||
DWORD i;
|
||||
|
||||
if(obj->prototype == proto)
|
||||
return S_OK;
|
||||
|
||||
if(obj->prototype) {
|
||||
for(i = 0; i < obj->prop_cnt; i++)
|
||||
if(obj->props[i].type == PROP_PROTREF)
|
||||
obj->props[i].type = PROP_DELETED;
|
||||
jsdisp_release(obj->prototype);
|
||||
}
|
||||
|
||||
obj->prototype = proto;
|
||||
if(proto)
|
||||
jsdisp_addref(proto);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
void jsdisp_freeze(jsdisp_t *obj, BOOL seal)
|
||||
{
|
||||
unsigned int i;
|
||||
|
|
|
@ -104,6 +104,7 @@ HRESULT get_dispatch_typeinfo(ITypeInfo**) DECLSPEC_HIDDEN;
|
|||
#define PROPF_VERSION_SHIFT 16
|
||||
#define PROPF_HTML (SCRIPTLANGUAGEVERSION_HTML << PROPF_VERSION_SHIFT)
|
||||
#define PROPF_ES5 ((SCRIPTLANGUAGEVERSION_HTML|SCRIPTLANGUAGEVERSION_ES5) << PROPF_VERSION_SHIFT)
|
||||
#define PROPF_ES6 ((SCRIPTLANGUAGEVERSION_HTML|SCRIPTLANGUAGEVERSION_ES6) << PROPF_VERSION_SHIFT)
|
||||
|
||||
/*
|
||||
* This is our internal dispatch flag informing calee that it's called directly from interpreter.
|
||||
|
@ -326,6 +327,7 @@ HRESULT jsdisp_define_property(jsdisp_t*,const WCHAR*,property_desc_t*) DECLSPEC
|
|||
HRESULT jsdisp_define_data_property(jsdisp_t*,const WCHAR*,unsigned,jsval_t) DECLSPEC_HIDDEN;
|
||||
HRESULT jsdisp_next_prop(jsdisp_t*,DISPID,enum jsdisp_enum_type,DISPID*) DECLSPEC_HIDDEN;
|
||||
HRESULT jsdisp_get_prop_name(jsdisp_t*,DISPID,jsstr_t**);
|
||||
HRESULT jsdisp_change_prototype(jsdisp_t*,jsdisp_t*) DECLSPEC_HIDDEN;
|
||||
void jsdisp_freeze(jsdisp_t*,BOOL) DECLSPEC_HIDDEN;
|
||||
BOOL jsdisp_is_frozen(jsdisp_t*,BOOL) DECLSPEC_HIDDEN;
|
||||
|
||||
|
|
|
@ -216,6 +216,33 @@ static HRESULT Object_isPrototypeOf(script_ctx_t *ctx, vdisp_t *jsthis, WORD fla
|
|||
return S_OK;
|
||||
}
|
||||
|
||||
static HRESULT Object_get_proto_(script_ctx_t *ctx, jsdisp_t *jsthis, jsval_t *r)
|
||||
{
|
||||
TRACE("%p\n", jsthis);
|
||||
|
||||
if(r)
|
||||
*r = jsthis->prototype
|
||||
? jsval_obj(jsdisp_addref(jsthis->prototype))
|
||||
: jsval_null();
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
static HRESULT Object_set_proto_(script_ctx_t *ctx, jsdisp_t *jsthis, jsval_t value)
|
||||
{
|
||||
jsdisp_t *proto;
|
||||
|
||||
TRACE("%p\n", jsthis);
|
||||
|
||||
if(is_undefined(value) || is_null(value))
|
||||
proto = NULL;
|
||||
else if(!is_object_instance(value) || !(proto = to_jsdisp(get_object(value)))) {
|
||||
FIXME("not an object\n");
|
||||
return E_FAIL;
|
||||
}
|
||||
|
||||
return jsdisp_change_prototype(jsthis, proto);
|
||||
}
|
||||
|
||||
static HRESULT Object_get_value(script_ctx_t *ctx, jsdisp_t *jsthis, jsval_t *r)
|
||||
{
|
||||
jsstr_t *ret;
|
||||
|
@ -236,6 +263,7 @@ static void Object_destructor(jsdisp_t *dispex)
|
|||
}
|
||||
|
||||
static const builtin_prop_t Object_props[] = {
|
||||
{L"__proto__", NULL, PROPF_ES6, Object_get_proto_, Object_set_proto_},
|
||||
{L"hasOwnProperty", Object_hasOwnProperty, PROPF_METHOD|1},
|
||||
{L"isPrototypeOf", Object_isPrototypeOf, PROPF_METHOD|1},
|
||||
{L"propertyIsEnumerable", Object_propertyIsEnumerable, PROPF_METHOD|1},
|
||||
|
|
|
@ -1025,3 +1025,58 @@ sync_test("elem_attr", function() {
|
|||
r = elem.getAttribute("className");
|
||||
ok(r === "cls3", "className attr = " + r);
|
||||
});
|
||||
|
||||
sync_test("__proto__", function() {
|
||||
var v = document.documentMode;
|
||||
var r, x = 42;
|
||||
|
||||
if(v < 11) {
|
||||
ok(x.__proto__ === undefined, "x.__proto__ = " + x.__proto__);
|
||||
ok(!("__proto__" in Object), "Object.__proto__ = " + Object.__proto__);
|
||||
return;
|
||||
}
|
||||
|
||||
ok(x.__proto__ === Number.prototype, "x.__proto__ = " + x.__proto__);
|
||||
ok(Object.__proto__ === Function.prototype, "Object.__proto__ = " + Object.__proto__);
|
||||
ok(Object.prototype.__proto__ === null, "Object.prototype.__proto__ = " + Object.prototype.__proto__);
|
||||
ok(Object.prototype.hasOwnProperty("__proto__"), "__proto__ is not a property of Object.prototype");
|
||||
ok(!Object.prototype.hasOwnProperty.call(x, "__proto__"), "__proto__ is a property of x");
|
||||
|
||||
x.__proto__ = Object.prototype;
|
||||
ok(x.__proto__ === Number.prototype, "x.__proto__ set to Object.prototype = " + x.__proto__);
|
||||
ok(!Object.prototype.hasOwnProperty.call(x, "__proto__"), "__proto__ is a property of x after set to Object.prototype");
|
||||
x = {};
|
||||
x.__proto__ = null;
|
||||
r = Object.getPrototypeOf(x);
|
||||
ok(x.__proto__ === undefined, "x.__proto__ after set to null = " + x.__proto__);
|
||||
ok(r === null, "getPrototypeOf(x) after set to null = " + r);
|
||||
|
||||
function check(expect, msg) {
|
||||
var r = Object.getPrototypeOf(x);
|
||||
ok(x.__proto__ === expect, "x.__proto__ " + msg + " = " + x.__proto__);
|
||||
ok(r === expect, "getPrototypeOf(x) " + msg + " = " + r);
|
||||
ok(!Object.prototype.hasOwnProperty.call(x, "__proto__"), "__proto__ is a property of x " + msg);
|
||||
}
|
||||
|
||||
x = {};
|
||||
check(Object.prototype, "after x set to {}");
|
||||
x.__proto__ = Number.prototype;
|
||||
check(Number.prototype, "after set to Number.prototype");
|
||||
x.__proto__ = Object.prototype;
|
||||
check(Object.prototype, "after re-set to Object.prototype");
|
||||
|
||||
function ctor() { }
|
||||
var obj = new ctor();
|
||||
x.__proto__ = obj;
|
||||
check(obj, "after set to obj");
|
||||
x.__proto__ = ctor.prototype;
|
||||
check(obj.__proto__, "after set to ctor.prototype");
|
||||
ok(obj.__proto__ === ctor.prototype, "obj.__proto__ !== ctor.prototype");
|
||||
|
||||
r = (delete x.__proto__);
|
||||
todo_wine.
|
||||
ok(r, "delete x.__proto__ returned " + r);
|
||||
ok(Object.prototype.hasOwnProperty("__proto__"), "__proto__ is not a property of Object.prototype after delete");
|
||||
r = Object.getPrototypeOf(x);
|
||||
ok(r === ctor.prototype, "x.__proto__ after delete = " + r);
|
||||
});
|
||||
|
|
Loading…
Reference in New Issue