From 50adb6318a7911c0e276756fdba7924bdd9c7565 Mon Sep 17 00:00:00 2001 From: Lars Knoll Date: Thu, 13 Jun 2013 14:11:23 +0200 Subject: [PATCH] Properly implement Object.prototype.__proto__ Change-Id: I5c3247f46cd86020425f6df8674f8bda7410757b Reviewed-by: Simon Hausmann --- src/qml/qml/v4/qv4object.cpp | 6 ----- src/qml/qml/v4/qv4objectproto.cpp | 46 ++++++++++++++++++++++++++++++++ src/qml/qml/v4/qv4objectproto_p.h | 3 +++ tests/auto/qml/qjsvalue/tst_qjsvalue.cpp | 2 +- 4 files changed, 50 insertions(+), 7 deletions(-) diff --git a/src/qml/qml/v4/qv4object.cpp b/src/qml/qml/v4/qv4object.cpp index 7394c1f..637f229 100644 --- a/src/qml/qml/v4/qv4object.cpp +++ b/src/qml/qml/v4/qv4object.cpp @@ -587,12 +587,6 @@ Value Object::internalGet(ExecutionContext *ctx, String *name, bool *hasProperty name->makeIdentifier(ctx); - if (name->isEqualTo(ctx->engine->id___proto__)) { - if (hasProperty) - *hasProperty = true; - return Value::fromObject(prototype); - } - Object *o = this; while (o) { uint idx = o->internalClass->find(name); diff --git a/src/qml/qml/v4/qv4objectproto.cpp b/src/qml/qml/v4/qv4objectproto.cpp index efb40ee..0a69588 100644 --- a/src/qml/qml/v4/qv4objectproto.cpp +++ b/src/qml/qml/v4/qv4objectproto.cpp @@ -126,6 +126,11 @@ void ObjectPrototype::init(ExecutionContext *ctx, const Value &ctor) defineDefaultProperty(ctx, QStringLiteral("propertyIsEnumerable"), method_propertyIsEnumerable, 1); defineDefaultProperty(ctx, QStringLiteral("__defineGetter__"), method_defineGetter, 0); defineDefaultProperty(ctx, QStringLiteral("__defineSetter__"), method_defineSetter, 0); + + ExecutionEngine *v4 = ctx->engine; + Property *p = insertMember(v4->id___proto__, Attr_Accessor|Attr_NotEnumerable); + p->setGetter(v4->newBuiltinFunction(v4->rootContext, v4->id___proto__, method_get_proto)); + p->setSetter(v4->newBuiltinFunction(v4->rootContext, v4->id___proto__, method_set_proto)); } Value ObjectPrototype::method_getPrototypeOf(SimpleCallContext *ctx) @@ -456,6 +461,47 @@ Value ObjectPrototype::method_defineSetter(SimpleCallContext *ctx) return Value::undefinedValue(); } +Value ObjectPrototype::method_get_proto(SimpleCallContext *ctx) +{ + Object *o = ctx->thisObject.asObject(); + if (!o) + ctx->throwTypeError(); + + return Value::fromObject(o->prototype); +} + +Value ObjectPrototype::method_set_proto(SimpleCallContext *ctx) +{ + Object *o = ctx->thisObject.asObject(); + if (!o) + ctx->throwTypeError(); + + Value proto = ctx->argument(0); + bool ok = false; + if (proto.isNull()) { + o->prototype = 0; + ok = true; + } else if (Object *p = proto.asObject()) { + if (o->prototype == p) { + ok = true; + } else if (o->extensible) { + Object *pp = p; + while (pp) { + if (pp == o) + break; + pp = pp->prototype; + } + if (!pp) { + ok = true; + o->prototype = p; + } + } + } + if (!ok) + ctx->throwTypeError(QStringLiteral("Cyclic __proto__ value")); + return Value::undefinedValue(); +} + void ObjectPrototype::toPropertyDescriptor(ExecutionContext *ctx, Value v, Property *desc, PropertyAttributes *attrs) { if (!v.isObject()) diff --git a/src/qml/qml/v4/qv4objectproto_p.h b/src/qml/qml/v4/qv4objectproto_p.h index e266953..84bc715 100644 --- a/src/qml/qml/v4/qv4objectproto_p.h +++ b/src/qml/qml/v4/qv4objectproto_p.h @@ -90,6 +90,9 @@ struct ObjectPrototype: Object static Value method_defineGetter(SimpleCallContext *ctx); static Value method_defineSetter(SimpleCallContext *ctx); + static Value method_get_proto(SimpleCallContext *ctx); + static Value method_set_proto(SimpleCallContext *ctx); + static void toPropertyDescriptor(ExecutionContext *ctx, Value v, Property *desc, PropertyAttributes *attrs); static Value fromPropertyDescriptor(ExecutionContext *ctx, const Property *desc, PropertyAttributes attrs); diff --git a/tests/auto/qml/qjsvalue/tst_qjsvalue.cpp b/tests/auto/qml/qjsvalue/tst_qjsvalue.cpp index 8d13541..2b8da26 100644 --- a/tests/auto/qml/qjsvalue/tst_qjsvalue.cpp +++ b/tests/auto/qml/qjsvalue/tst_qjsvalue.cpp @@ -1584,7 +1584,7 @@ void tst_QJSValue::getSetPrototype_evalCyclicPrototype() QJSEngine eng; QJSValue ret = eng.evaluate("o = { }; p = { }; o.__proto__ = p; p.__proto__ = o"); QCOMPARE(ret.isError(), true); - QCOMPARE(ret.toString(), QLatin1String("Error: Cyclic __proto__ value")); + QCOMPARE(ret.toString(), QLatin1String("TypeError: Cyclic __proto__ value")); } void tst_QJSValue::getSetPrototype_eval() -- 2.7.4