Commit 364e093a authored by Gabriel Ivăncescu's avatar Gabriel Ivăncescu Committed by Alexandre Julliard

jscript: Make Object.prototype.__proto__ an actual accessor.

We have to define it after the constructors are initiated. Signed-off-by: 's avatarGabriel Ivăncescu <gabrielopcode@gmail.com> Signed-off-by: 's avatarJacek Caban <jacek@codeweavers.com> Signed-off-by: 's avatarAlexandre Julliard <julliard@winehq.org>
parent 94349fdd
......@@ -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));
hres = to_object(ctx, vthis, &disp);
if(FAILED(hres))
return hres;
if(!r)
goto done;
if(!(jsthis = to_jsdisp(disp))) {
FIXME("Host object this\n");
hres = E_FAIL;
goto done;
}
*r = jsthis->prototype
? jsval_obj(jsdisp_addref(jsthis->prototype))
: jsval_null();
done:
IDispatch_Release(disp);
return hres;
}
static HRESULT Object_set_proto_(script_ctx_t *ctx, jsdisp_t *jsthis, jsval_t value)
HRESULT Object_set_proto_(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r)
{
jsdisp_t *proto;
jsdisp_t *jsthis, *proto;
HRESULT hres;
TRACE("%p\n", jsthis);
TRACE("%s\n", debugstr_jsval(vthis));
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(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;
return jsdisp_change_prototype(jsthis, proto);
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() {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment