diff options
author | Lars Knoll <lars.knoll@qt.io> | 2018-08-26 15:07:50 +0200 |
---|---|---|
committer | Simon Hausmann <simon.hausmann@qt.io> | 2018-08-28 21:45:45 +0000 |
commit | 464b878b973710077b2b92b1682d6f38c83554dd (patch) | |
tree | 2577a70c9809bebc3776a0e11422badfdd310c90 /src/qml/jsruntime/qv4mapobject.cpp | |
parent | bead103138c0d9dff3c9f927c9c4e2f44ee7db4c (diff) |
Implement support for WeakMap
Change-Id: Id23e80fe5918ba7dc897568123bf3db4d35e9092
Reviewed-by: Simon Hausmann <simon.hausmann@qt.io>
Diffstat (limited to 'src/qml/jsruntime/qv4mapobject.cpp')
-rw-r--r-- | src/qml/jsruntime/qv4mapobject.cpp | 160 |
1 files changed, 127 insertions, 33 deletions
diff --git a/src/qml/jsruntime/qv4mapobject.cpp b/src/qml/jsruntime/qv4mapobject.cpp index ca9e1723f9..e8467a17b0 100644 --- a/src/qml/jsruntime/qv4mapobject.cpp +++ b/src/qml/jsruntime/qv4mapobject.cpp @@ -45,18 +45,29 @@ using namespace QV4; +DEFINE_OBJECT_VTABLE(WeakMapCtor); DEFINE_OBJECT_VTABLE(MapCtor); DEFINE_OBJECT_VTABLE(MapObject); +void Heap::WeakMapCtor::init(QV4::ExecutionContext *scope) +{ + Heap::FunctionObject::init(scope, QStringLiteral("WeakMap")); +} + void Heap::MapCtor::init(QV4::ExecutionContext *scope) { Heap::FunctionObject::init(scope, QStringLiteral("Map")); } -ReturnedValue MapCtor::virtualCallAsConstructor(const FunctionObject *f, const Value *argv, int argc, const Value *) +ReturnedValue WeakMapCtor::construct(const FunctionObject *f, const Value *argv, int argc, const Value *, bool weakMap) { Scope scope(f); Scoped<MapObject> a(scope, scope.engine->memoryManager->allocate<MapObject>()); + if (weakMap) { + a->setPrototypeOf(scope.engine->weakMapPrototype()); + scope.engine->memoryManager->registerWeakMap(a->d()); + } + a->d()->isWeakMap = weakMap; if (argc > 0) { ScopedValue iterable(scope, argv[0]); @@ -73,19 +84,20 @@ ReturnedValue MapCtor::virtualCallAsConstructor(const FunctionObject *f, const V ScopedFunctionObject adder(scope, a->get(ScopedString(scope, scope.engine->newString(QString::fromLatin1("set"))))); if (!adder) return scope.engine->throwTypeError(); - ScopedObject iter(scope, Runtime::method_getIterator(scope.engine, iterable, true)); - CHECK_EXCEPTION(); - if (!iter) - return a.asReturnedValue(); + ScopedObject iter(scope, Runtime::method_getIterator(scope.engine, iterable, true)); + if (scope.hasException()) + return Encode::undefined(); + Q_ASSERT(iter); Value *nextValue = scope.alloc(1); ScopedValue done(scope); forever { done = Runtime::method_iteratorNext(scope.engine, iter, nextValue); - CHECK_EXCEPTION(); + if (scope.hasException()) + return Encode::undefined(); if (done->toBoolean()) - return a.asReturnedValue(); + return a->asReturnedValue(); adder->call(a, nextValue, 1); if (scope.engine->hasException) { @@ -95,15 +107,44 @@ ReturnedValue MapCtor::virtualCallAsConstructor(const FunctionObject *f, const V } } } - return a.asReturnedValue(); + return a->asReturnedValue(); +} + +ReturnedValue WeakMapCtor::virtualCallAsConstructor(const FunctionObject *f, const Value *argv, int argc, const Value *newTarget) +{ + return construct(f, argv, argc, newTarget, true); } -ReturnedValue MapCtor::virtualCall(const FunctionObject *f, const Value *, const Value *, int) +ReturnedValue WeakMapCtor::virtualCall(const FunctionObject *f, const Value *, const Value *, int) { Scope scope(f); - return scope.engine->throwTypeError(QString::fromLatin1("Map requires new")); + return scope.engine->throwTypeError(QString::fromLatin1("(Weak)Map requires new")); } + +ReturnedValue MapCtor::virtualCallAsConstructor(const FunctionObject *f, const Value *argv, int argc, const Value *newTarget) +{ + return construct(f, argv, argc, newTarget, false); +} + +void WeakMapPrototype::init(ExecutionEngine *engine, Object *ctor) +{ + Scope scope(engine); + ScopedObject o(scope); + ctor->defineReadonlyConfigurableProperty(engine->id_length(), Primitive::fromInt32(0)); + ctor->defineReadonlyProperty(engine->id_prototype(), (o = this)); + defineDefaultProperty(engine->id_constructor(), (o = ctor)); + + defineDefaultProperty(QStringLiteral("delete"), method_delete, 1); + defineDefaultProperty(QStringLiteral("get"), method_get, 1); + defineDefaultProperty(QStringLiteral("has"), method_has, 1); + defineDefaultProperty(QStringLiteral("set"), method_set, 2); + + ScopedString val(scope, engine->newString(QLatin1String("WeakMap"))); + defineReadonlyConfigurableProperty(engine->symbol_toStringTag(), val); +} + + void MapPrototype::init(ExecutionEngine *engine, Object *ctor) { Scope scope(engine); @@ -119,7 +160,7 @@ void MapPrototype::init(ExecutionEngine *engine, Object *ctor) defineDefaultProperty(QStringLiteral("get"), method_get, 1); defineDefaultProperty(QStringLiteral("has"), method_has, 1); defineDefaultProperty(QStringLiteral("keys"), method_keys, 0); - defineDefaultProperty(QStringLiteral("set"), method_set, 0); + defineDefaultProperty(QStringLiteral("set"), method_set, 2); defineAccessorProperty(QStringLiteral("size"), method_get_size, nullptr); defineDefaultProperty(QStringLiteral("values"), method_values, 0); @@ -142,42 +183,97 @@ void Heap::MapObject::init() void Heap::MapObject::destroy() { delete esTable; - esTable = 0; + esTable = nullptr; +} + +void Heap::MapObject::removeUnmarkedKeys() +{ + esTable->removeUnmarkedKeys(); } void Heap::MapObject::markObjects(Heap::Base *that, MarkStack *markStack) { MapObject *m = static_cast<MapObject *>(that); - m->esTable->markObjects(markStack); + m->esTable->markObjects(markStack, m->isWeakMap); Object::markObjects(that, markStack); } +ReturnedValue WeakMapPrototype::method_delete(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc) +{ + Scope scope(b); + Scoped<MapObject> that(scope, thisObject); + if (!that || !that->d()->isWeakMap) + return scope.engine->throwTypeError(); + if (!argc || !argv[0].isObject()) + return Encode(false); + + return Encode(that->d()->esTable->remove(argv[0])); + +} + +ReturnedValue WeakMapPrototype::method_get(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc) +{ + Scope scope(b); + Scoped<MapObject> that(scope, thisObject); + if (!that || !that->d()->isWeakMap) + return scope.engine->throwTypeError(); + if (!argc || !argv[0].isObject()) + return Encode::undefined(); + + return that->d()->esTable->get(argv[0]); +} + +ReturnedValue WeakMapPrototype::method_has(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc) +{ + Scope scope(b); + Scoped<MapObject> that(scope, thisObject); + if (!that || !that->d()->isWeakMap) + return scope.engine->throwTypeError(); + if (!argc || !argv[0].isObject()) + return Encode(false); + + return Encode(that->d()->esTable->has(argv[0])); +} + +ReturnedValue WeakMapPrototype::method_set(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc) +{ + Scope scope(b); + Scoped<MapObject> that(scope, thisObject); + if ((!that || !that->d()->isWeakMap) || + (!argc || !argv[0].isObject())) + return scope.engine->throwTypeError(); + + that->d()->esTable->set(argv[0], argc > 1 ? argv[1] : Primitive::undefinedValue()); + return that.asReturnedValue(); +} + + ReturnedValue MapPrototype::method_clear(const FunctionObject *b, const Value *thisObject, const Value *, int) { Scope scope(b); Scoped<MapObject> that(scope, thisObject); - if (!that) + if (!that || that->d()->isWeakMap) return scope.engine->throwTypeError(); that->d()->esTable->clear(); return Encode::undefined(); } -ReturnedValue MapPrototype::method_delete(const FunctionObject *b, const Value *thisObject, const Value *argv, int) +ReturnedValue MapPrototype::method_delete(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc) { Scope scope(b); Scoped<MapObject> that(scope, thisObject); - if (!that) + if (!that || that->d()->isWeakMap) return scope.engine->throwTypeError(); - return Encode(that->d()->esTable->remove(argv[0])); + return Encode(that->d()->esTable->remove(argc ? argv[0] : Primitive::undefinedValue())); } ReturnedValue MapPrototype::method_entries(const FunctionObject *b, const Value *thisObject, const Value *, int) { Scope scope(b); Scoped<MapObject> that(scope, thisObject); - if (!that) + if (!that || that->d()->isWeakMap) return scope.engine->throwTypeError(); Scoped<MapIteratorObject> ao(scope, scope.engine->newMapIteratorObject(that)); @@ -189,7 +285,7 @@ ReturnedValue MapPrototype::method_forEach(const FunctionObject *b, const Value { Scope scope(b); Scoped<MapObject> that(scope, thisObject); - if (!that) + if (!that || that->d()->isWeakMap) return scope.engine->throwTypeError(); ScopedFunctionObject callbackfn(scope, argv[0]); @@ -211,31 +307,31 @@ ReturnedValue MapPrototype::method_forEach(const FunctionObject *b, const Value return Encode::undefined(); } -ReturnedValue MapPrototype::method_get(const FunctionObject *b, const Value *thisObject, const Value *argv, int) +ReturnedValue MapPrototype::method_get(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc) { Scope scope(b); Scoped<MapObject> that(scope, thisObject); - if (!that) + if (!that || that->d()->isWeakMap) return scope.engine->throwTypeError(); - return that->d()->esTable->get(argv[0]); + return that->d()->esTable->get(argc ? argv[0] : Primitive::undefinedValue()); } -ReturnedValue MapPrototype::method_has(const FunctionObject *b, const Value *thisObject, const Value *argv, int) +ReturnedValue MapPrototype::method_has(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc) { Scope scope(b); Scoped<MapObject> that(scope, thisObject); - if (!that) + if (!that || that->d()->isWeakMap) return scope.engine->throwTypeError(); - return Encode(that->d()->esTable->has(argv[0])); + return Encode(that->d()->esTable->has(argc ? argv[0] : Primitive::undefinedValue())); } ReturnedValue MapPrototype::method_keys(const FunctionObject *b, const Value *thisObject, const Value *, int) { Scope scope(b); Scoped<MapObject> that(scope, thisObject); - if (!that) + if (!that || that->d()->isWeakMap) return scope.engine->throwTypeError(); Scoped<MapIteratorObject> ao(scope, scope.engine->newMapIteratorObject(that)); @@ -243,14 +339,14 @@ ReturnedValue MapPrototype::method_keys(const FunctionObject *b, const Value *th return ao->asReturnedValue(); } -ReturnedValue MapPrototype::method_set(const FunctionObject *b, const Value *thisObject, const Value *argv, int) +ReturnedValue MapPrototype::method_set(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc) { Scope scope(b); Scoped<MapObject> that(scope, thisObject); - if (!that) + if (!that || that->d()->isWeakMap) return scope.engine->throwTypeError(); - that->d()->esTable->set(argv[0], argv[1]); + that->d()->esTable->set(argc ? argv[0] : Primitive::undefinedValue(), argc > 1 ? argv[1] : Primitive::undefinedValue()); return that.asReturnedValue(); } @@ -258,7 +354,7 @@ ReturnedValue MapPrototype::method_get_size(const FunctionObject *b, const Value { Scope scope(b); Scoped<MapObject> that(scope, thisObject); - if (!that) + if (!that || that->d()->isWeakMap) return scope.engine->throwTypeError(); return Encode(that->d()->esTable->size()); @@ -268,12 +364,10 @@ ReturnedValue MapPrototype::method_values(const FunctionObject *b, const Value * { Scope scope(b); Scoped<MapObject> that(scope, thisObject); - if (!that) + if (!that || that->d()->isWeakMap) return scope.engine->throwTypeError(); Scoped<MapIteratorObject> ao(scope, scope.engine->newMapIteratorObject(that)); ao->d()->iterationKind = IteratorKind::ValueIteratorKind; return ao->asReturnedValue(); } - - |