diff options
author | Lars Knoll <lars.knoll@qt.io> | 2018-06-19 13:28:26 +0200 |
---|---|---|
committer | Lars Knoll <lars.knoll@qt.io> | 2018-06-25 07:36:48 +0000 |
commit | 1596112e146b28541bcee412ed159cdea7e692d0 (patch) | |
tree | 29e858041496256c9c9c700fca4fb7220d78d46e /src/qml/jsruntime/qv4proxy.cpp | |
parent | 3823e9b94f849f8344b81250fac708ac2eaccd16 (diff) |
Add Proxy support for prototype handling
Cleanup get/setPrototypeOf and fix some smaller incompatibilities
in the default implementation for Object.
Add the methods to the vtable and reimplement them according to
spec for ProxyObjects.
Clean up the Object.prototype.get/setPrototypeOf/__proto__ methods
and fix a smaller bug in the Reflect API for those methods.
Change-Id: I6e438753332ec4db963d6cdcf86f340ff212777a
Reviewed-by: Simon Hausmann <simon.hausmann@qt.io>
Diffstat (limited to 'src/qml/jsruntime/qv4proxy.cpp')
-rw-r--r-- | src/qml/jsruntime/qv4proxy.cpp | 83 |
1 files changed, 83 insertions, 0 deletions
diff --git a/src/qml/jsruntime/qv4proxy.cpp b/src/qml/jsruntime/qv4proxy.cpp index e499dfbcf1..80e1b70a1a 100644 --- a/src/qml/jsruntime/qv4proxy.cpp +++ b/src/qml/jsruntime/qv4proxy.cpp @@ -361,6 +361,89 @@ bool ProxyObject::preventExtensions(Managed *m) return result; } +Heap::Object *ProxyObject::getPrototypeOf(const Managed *m) +{ + Scope scope(m); + const ProxyObject *o = static_cast<const ProxyObject *>(m); + if (!o->d()->handler) { + scope.engine->throwTypeError(); + return nullptr; + } + + ScopedObject target(scope, o->d()->target); + Q_ASSERT(target); + ScopedObject handler(scope, o->d()->handler); + ScopedString name(scope, scope.engine->newString(QStringLiteral("getPrototypeOf"))); + ScopedValue trap(scope, handler->get(name)); + if (scope.hasException()) + return nullptr; + if (trap->isNullOrUndefined()) + return target->getPrototypeOf(); + if (!trap->isFunctionObject()) { + scope.engine->throwTypeError(); + return nullptr; + } + + JSCallData cdata(scope, 1, nullptr, handler); + cdata.args[0] = target; + + ScopedValue trapResult(scope, static_cast<const FunctionObject *>(trap.ptr)->call(cdata)); + if (!trapResult->isNull() && !trapResult->isObject()) { + scope.engine->throwTypeError(); + return nullptr; + } + Heap::Object *proto = trapResult->isNull() ? nullptr : static_cast<Heap::Object *>(trapResult->heapObject()); + if (!target->isExtensible()) { + Heap::Object *targetProto = target->getPrototypeOf(); + if (proto != targetProto) { + scope.engine->throwTypeError(); + return nullptr; + } + } + return proto; +} + +bool ProxyObject::setPrototypeOf(Managed *m, const Object *p) +{ + Scope scope(m); + const ProxyObject *o = static_cast<const ProxyObject *>(m); + if (!o->d()->handler) { + scope.engine->throwTypeError(); + return false; + } + + ScopedObject target(scope, o->d()->target); + Q_ASSERT(target); + ScopedObject handler(scope, o->d()->handler); + ScopedString name(scope, scope.engine->newString(QStringLiteral("setPrototypeOf"))); + ScopedValue trap(scope, handler->get(name)); + if (scope.hasException()) + return false; + if (trap->isNullOrUndefined()) + return target->setPrototypeOf(p); + if (!trap->isFunctionObject()) { + scope.engine->throwTypeError(); + return false; + } + + JSCallData cdata(scope, 2, nullptr, handler); + cdata.args[0] = target; + cdata.args[1] = p ? p->asReturnedValue() : Encode::null(); + + ScopedValue trapResult(scope, static_cast<const FunctionObject *>(trap.ptr)->call(cdata)); + bool result = trapResult->toBoolean(); + if (!result) + return false; + if (!target->isExtensible()) { + Heap::Object *targetProto = target->getPrototypeOf(); + if (p->d() != targetProto) { + scope.engine->throwTypeError(); + return false; + } + } + return true; +} + //ReturnedValue ProxyObject::callAsConstructor(const FunctionObject *f, const Value *argv, int argc) //{ |