jscript: Make Object.prototype.__proto__ an actual accessor.
We have to define it after the constructors are initiated. 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
94349fdd9a
commit
364e093ab7
|
@ -488,8 +488,7 @@ 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 ||
|
||||
(prop_iter->type == PROP_BUILTIN && prop_iter->u.p->setter))
|
||||
if(prop_iter->type == PROP_ACCESSOR)
|
||||
prop = prop_iter;
|
||||
}
|
||||
|
||||
|
|
|
@ -911,6 +911,31 @@ static const builtin_info_t JSGlobal_info = {
|
|||
NULL
|
||||
};
|
||||
|
||||
static HRESULT init_object_prototype_accessors(script_ctx_t *ctx, jsdisp_t *object_prototype)
|
||||
{
|
||||
property_desc_t desc;
|
||||
HRESULT hres = S_OK;
|
||||
|
||||
/* __proto__ is an actual accessor on native, despite being a builtin */
|
||||
if(ctx->version >= SCRIPTLANGUAGEVERSION_ES6) {
|
||||
desc.flags = PROPF_CONFIGURABLE;
|
||||
desc.mask = PROPF_CONFIGURABLE | PROPF_ENUMERABLE;
|
||||
desc.explicit_getter = desc.explicit_setter = TRUE;
|
||||
desc.explicit_value = FALSE;
|
||||
|
||||
hres = create_builtin_function(ctx, Object_get_proto_, NULL, NULL, PROPF_METHOD, NULL, &desc.getter);
|
||||
if(SUCCEEDED(hres)) {
|
||||
hres = create_builtin_function(ctx, Object_set_proto_, NULL, NULL, PROPF_METHOD|1, NULL, &desc.setter);
|
||||
if(SUCCEEDED(hres)) {
|
||||
hres = jsdisp_define_property(object_prototype, L"__proto__", &desc);
|
||||
jsdisp_release(desc.setter);
|
||||
}
|
||||
jsdisp_release(desc.getter);
|
||||
}
|
||||
}
|
||||
return hres;
|
||||
}
|
||||
|
||||
static HRESULT init_constructors(script_ctx_t *ctx, jsdisp_t *object_prototype)
|
||||
{
|
||||
HRESULT hres;
|
||||
|
@ -1073,6 +1098,10 @@ HRESULT init_global(script_ctx_t *ctx)
|
|||
if(FAILED(hres))
|
||||
return hres;
|
||||
|
||||
hres = init_object_prototype_accessors(ctx, ctx->object_prototype);
|
||||
if(FAILED(hres))
|
||||
return hres;
|
||||
|
||||
hres = create_math(ctx, &math);
|
||||
if(FAILED(hres))
|
||||
return hres;
|
||||
|
|
|
@ -451,6 +451,8 @@ BOOL bool_obj_value(jsdisp_t*) DECLSPEC_HIDDEN;
|
|||
unsigned array_get_length(jsdisp_t*) DECLSPEC_HIDDEN;
|
||||
|
||||
HRESULT JSGlobal_eval(script_ctx_t*,jsval_t,WORD,unsigned,jsval_t*,jsval_t*) DECLSPEC_HIDDEN;
|
||||
HRESULT Object_get_proto_(script_ctx_t*,jsval_t,WORD,unsigned,jsval_t*,jsval_t*) DECLSPEC_HIDDEN;
|
||||
HRESULT Object_set_proto_(script_ctx_t*,jsval_t,WORD,unsigned,jsval_t*,jsval_t*) DECLSPEC_HIDDEN;
|
||||
|
||||
static inline BOOL is_class(jsdisp_t *jsdisp, jsclass_t class)
|
||||
{
|
||||
|
|
|
@ -289,31 +289,69 @@ done:
|
|||
return hres;
|
||||
}
|
||||
|
||||
static HRESULT Object_get_proto_(script_ctx_t *ctx, jsdisp_t *jsthis, jsval_t *r)
|
||||
HRESULT Object_get_proto_(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r)
|
||||
{
|
||||
TRACE("%p\n", jsthis);
|
||||
jsdisp_t *jsthis;
|
||||
IDispatch *disp;
|
||||
HRESULT hres;
|
||||
|
||||
if(r)
|
||||
*r = jsthis->prototype
|
||||
? jsval_obj(jsdisp_addref(jsthis->prototype))
|
||||
: jsval_null();
|
||||
return S_OK;
|
||||
}
|
||||
TRACE("%s\n", debugstr_jsval(vthis));
|
||||
|
||||
static HRESULT Object_set_proto_(script_ctx_t *ctx, jsdisp_t *jsthis, jsval_t value)
|
||||
{
|
||||
jsdisp_t *proto;
|
||||
hres = to_object(ctx, vthis, &disp);
|
||||
if(FAILED(hres))
|
||||
return hres;
|
||||
|
||||
TRACE("%p\n", jsthis);
|
||||
if(!r)
|
||||
goto done;
|
||||
|
||||
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;
|
||||
if(!(jsthis = to_jsdisp(disp))) {
|
||||
FIXME("Host object this\n");
|
||||
hres = E_FAIL;
|
||||
goto done;
|
||||
}
|
||||
|
||||
return jsdisp_change_prototype(jsthis, proto);
|
||||
*r = jsthis->prototype
|
||||
? jsval_obj(jsdisp_addref(jsthis->prototype))
|
||||
: jsval_null();
|
||||
done:
|
||||
IDispatch_Release(disp);
|
||||
return hres;
|
||||
}
|
||||
|
||||
HRESULT Object_set_proto_(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r)
|
||||
{
|
||||
jsdisp_t *jsthis, *proto;
|
||||
HRESULT hres;
|
||||
|
||||
TRACE("%s\n", debugstr_jsval(vthis));
|
||||
|
||||
if(is_undefined(vthis) || is_null(vthis))
|
||||
return JS_E_OBJECT_EXPECTED;
|
||||
if(!argc) {
|
||||
if(r)
|
||||
*r = jsval_undefined();
|
||||
return S_OK;
|
||||
}
|
||||
if(!is_object_instance(vthis) || !(jsthis = to_jsdisp(get_object(vthis))))
|
||||
goto done;
|
||||
|
||||
if(is_null(argv[0])) {
|
||||
proto = NULL;
|
||||
}else if(is_object_instance(argv[0])) {
|
||||
proto = to_jsdisp(get_object(argv[0]));
|
||||
if(!proto) {
|
||||
FIXME("Host object value\n");
|
||||
return E_FAIL;
|
||||
}
|
||||
}else
|
||||
goto done;
|
||||
|
||||
hres = jsdisp_change_prototype(jsthis, proto);
|
||||
if(FAILED(hres))
|
||||
return hres;
|
||||
|
||||
done:
|
||||
return r ? jsval_copy(argv[0], r) : S_OK;
|
||||
}
|
||||
|
||||
static void Object_destructor(jsdisp_t *dispex)
|
||||
|
@ -322,7 +360,6 @@ 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},
|
||||
|
|
|
@ -1330,6 +1330,66 @@ sync_test("__proto__", function() {
|
|||
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);
|
||||
|
||||
var desc = Object.getOwnPropertyDescriptor(Object.prototype, "__proto__");
|
||||
ok(desc.value === undefined, "__proto__ value = " + desc.value);
|
||||
ok(Object.getPrototypeOf(desc.get) === Function.prototype, "__proto__ getter not a function");
|
||||
ok(Object.getPrototypeOf(desc.set) === Function.prototype, "__proto__ setter not a function");
|
||||
ok(desc.get.length === 0, "__proto__ getter length = " + desc.get.length);
|
||||
ok(desc.set.length === 1, "__proto__ setter length = " + desc.set.length);
|
||||
|
||||
r = desc.get.call(x, 1, 2, 3, 4);
|
||||
ok(r === x.__proto__, "calling __proto__ getter on x returned " + r);
|
||||
|
||||
r = desc.set.call(x, obj);
|
||||
ok(r === obj, "calling __proto__ setter(obj) on x returned " + r);
|
||||
check(obj, "after set to obj via calling setter");
|
||||
r = desc.set.call(x, 42);
|
||||
ok(r === 42, "calling __proto__ setter(42) on x returned " + r);
|
||||
check(obj, "after set to obj via calling setter(42)");
|
||||
r = desc.set.call(x, "foo");
|
||||
ok(r === "foo", "calling __proto__ setter('foo') on x returned " + r);
|
||||
check(obj, "after set to obj via calling setter('foo')");
|
||||
r = desc.set.call(x);
|
||||
ok(r === undefined, "calling __proto__ setter() on x returned " + r);
|
||||
r = desc.set.call(true, obj);
|
||||
ok(r === obj, "calling __proto__ setter(obj) on true value returned " + r);
|
||||
x = true;
|
||||
r = desc.set.call(x, obj);
|
||||
ok(r === obj, "calling __proto__ setter(obj) on x set to true returned " + r);
|
||||
ok(x.__proto__ === Boolean.prototype, "true value __proto__ after set to obj = " + x.__proto__);
|
||||
x = new Boolean(true);
|
||||
r = desc.set.call(x, obj);
|
||||
ok(r === obj, "calling __proto__ setter(obj) on x set to Boolean(true) returned " + r);
|
||||
ok(x.__proto__ === obj, "Boolean(true) __proto__ after set to obj = " + x.__proto__);
|
||||
|
||||
r = desc.get.call(13);
|
||||
ok(r === Number.prototype, "calling __proto__ getter on 13 returned " + r);
|
||||
try {
|
||||
r = desc.get.call(undefined);
|
||||
ok(false, "expected exception calling __proto__ getter on undefined");
|
||||
}catch(e) {
|
||||
ok(e.number === 0xa138f - 0x80000000, "calling __proto__ getter on undefined threw exception " + e.number);
|
||||
}
|
||||
try {
|
||||
r = desc.get.call(null);
|
||||
ok(false, "expected exception calling __proto__ getter on null");
|
||||
}catch(e) {
|
||||
ok(e.number === 0xa138f - 0x80000000, "calling __proto__ getter on null threw exception " + e.number);
|
||||
}
|
||||
|
||||
try {
|
||||
r = desc.set.call(undefined, obj);
|
||||
ok(false, "expected exception calling __proto__ setter on undefined");
|
||||
}catch(e) {
|
||||
ok(e.number === 0xa138f - 0x80000000, "calling __proto__ setter on undefined threw exception " + e.number);
|
||||
}
|
||||
try {
|
||||
r = desc.set.call(null, obj);
|
||||
ok(false, "expected exception calling __proto__ setter on null");
|
||||
}catch(e) {
|
||||
ok(e.number === 0xa138f - 0x80000000, "calling __proto__ setter on null threw exception " + e.number);
|
||||
}
|
||||
});
|
||||
|
||||
async_test("postMessage", function() {
|
||||
|
|
Loading…
Reference in New Issue