aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLars Knoll <lars.knoll@qt.io>2018-08-26 15:07:50 +0200
committerSimon Hausmann <simon.hausmann@qt.io>2018-08-28 21:45:45 +0000
commit464b878b973710077b2b92b1682d6f38c83554dd (patch)
tree2577a70c9809bebc3776a0e11422badfdd310c90
parentbead103138c0d9dff3c9f927c9c4e2f44ee7db4c (diff)
Implement support for WeakMap
Change-Id: Id23e80fe5918ba7dc897568123bf3db4d35e9092 Reviewed-by: Simon Hausmann <simon.hausmann@qt.io>
-rw-r--r--src/qml/jsruntime/qv4engine.cpp5
-rw-r--r--src/qml/jsruntime/qv4engine_p.h4
-rw-r--r--src/qml/jsruntime/qv4estable.cpp22
-rw-r--r--src/qml/jsruntime/qv4estable_p.h4
-rw-r--r--src/qml/jsruntime/qv4global_p.h4
-rw-r--r--src/qml/jsruntime/qv4mapobject.cpp160
-rw-r--r--src/qml/jsruntime/qv4mapobject_p.h35
-rw-r--r--src/qml/jsruntime/qv4setobject.cpp2
-rw-r--r--src/qml/memory/qv4mm.cpp19
-rw-r--r--src/qml/memory/qv4mm_p.h3
-rw-r--r--tests/auto/qml/ecmascripttests/TestExpectations90
-rw-r--r--tests/auto/qml/qjsengine/tst_qjsengine.cpp1
12 files changed, 218 insertions, 131 deletions
diff --git a/src/qml/jsruntime/qv4engine.cpp b/src/qml/jsruntime/qv4engine.cpp
index d6cfb1dcc1..7087e49b30 100644
--- a/src/qml/jsruntime/qv4engine.cpp
+++ b/src/qml/jsruntime/qv4engine.cpp
@@ -485,6 +485,10 @@ ExecutionEngine::ExecutionEngine(QJSEngine *jsEngine)
sequencePrototype()->cast<SequencePrototype>()->init();
#endif
+ jsObjects[WeakMap_Ctor] = memoryManager->allocate<WeakMapCtor>(global);
+ jsObjects[WeakMapProto] = memoryManager->allocate<WeakMapPrototype>();
+ static_cast<WeakMapPrototype *>(weakMapPrototype())->init(this, weakMapCtor());
+
jsObjects[Map_Ctor] = memoryManager->allocate<MapCtor>(global);
jsObjects[MapProto] = memoryManager->allocate<MapPrototype>();
static_cast<MapPrototype *>(mapPrototype())->init(this, mapCtor());
@@ -548,6 +552,7 @@ ExecutionEngine::ExecutionEngine(QJSEngine *jsEngine)
globalObject->defineDefaultProperty(QStringLiteral("ArrayBuffer"), *arrayBufferCtor());
globalObject->defineDefaultProperty(QStringLiteral("DataView"), *dataViewCtor());
globalObject->defineDefaultProperty(QStringLiteral("Set"), *setCtor());
+ globalObject->defineDefaultProperty(QStringLiteral("WeakMap"), *weakMapCtor());
globalObject->defineDefaultProperty(QStringLiteral("Map"), *mapCtor());
for (int i = 0; i < NTypedArrayTypes; ++i)
diff --git a/src/qml/jsruntime/qv4engine_p.h b/src/qml/jsruntime/qv4engine_p.h
index 0f4a4a75a2..028615abfb 100644
--- a/src/qml/jsruntime/qv4engine_p.h
+++ b/src/qml/jsruntime/qv4engine_p.h
@@ -166,6 +166,7 @@ public:
ArrayBufferProto,
DataViewProto,
SetProto,
+ WeakMapProto,
MapProto,
IntrinsicTypedArrayProto,
ValueTypeProto,
@@ -198,6 +199,7 @@ public:
ArrayBuffer_Ctor,
DataView_Ctor,
Set_Ctor,
+ WeakMap_Ctor,
Map_Ctor,
IntrinsicTypedArray_Ctor,
@@ -235,6 +237,7 @@ public:
FunctionObject *arrayBufferCtor() const { return reinterpret_cast<FunctionObject *>(jsObjects + ArrayBuffer_Ctor); }
FunctionObject *dataViewCtor() const { return reinterpret_cast<FunctionObject *>(jsObjects + DataView_Ctor); }
FunctionObject *setCtor() const { return reinterpret_cast<FunctionObject *>(jsObjects + Set_Ctor); }
+ FunctionObject *weakMapCtor() const { return reinterpret_cast<FunctionObject *>(jsObjects + WeakMap_Ctor); }
FunctionObject *mapCtor() const { return reinterpret_cast<FunctionObject *>(jsObjects + Map_Ctor); }
FunctionObject *intrinsicTypedArrayCtor() const { return reinterpret_cast<FunctionObject *>(jsObjects + IntrinsicTypedArray_Ctor); }
FunctionObject *typedArrayCtors;
@@ -269,6 +272,7 @@ public:
Object *arrayBufferPrototype() const { return reinterpret_cast<Object *>(jsObjects + ArrayBufferProto); }
Object *dataViewPrototype() const { return reinterpret_cast<Object *>(jsObjects + DataViewProto); }
Object *setPrototype() const { return reinterpret_cast<Object *>(jsObjects + SetProto); }
+ Object *weakMapPrototype() const { return reinterpret_cast<Object *>(jsObjects + WeakMapProto); }
Object *mapPrototype() const { return reinterpret_cast<Object *>(jsObjects + MapProto); }
Object *intrinsicTypedArrayPrototype() const { return reinterpret_cast<Object *>(jsObjects + IntrinsicTypedArrayProto); }
Object *typedArrayPrototype;
diff --git a/src/qml/jsruntime/qv4estable.cpp b/src/qml/jsruntime/qv4estable.cpp
index 55b7407000..4b0eddb989 100644
--- a/src/qml/jsruntime/qv4estable.cpp
+++ b/src/qml/jsruntime/qv4estable.cpp
@@ -38,6 +38,7 @@
****************************************************************************/
#include "qv4estable_p.h"
+#include "qv4object_p.h"
using namespace QV4;
@@ -67,10 +68,11 @@ ESTable::~ESTable()
m_values = nullptr;
}
-void ESTable::markObjects(MarkStack *s)
+void ESTable::markObjects(MarkStack *s, bool isWeakMap)
{
for (uint i = 0; i < m_size; ++i) {
- m_keys[i].mark(s);
+ if (!isWeakMap)
+ m_keys[i].mark(s);
m_values[i].mark(s);
}
}
@@ -179,3 +181,19 @@ void ESTable::iterate(uint idx, Value *key, Value *value)
*value = m_values[idx];
}
+void ESTable::removeUnmarkedKeys()
+{
+ uint idx = 0;
+ uint toIdx = 0;
+ for (; idx < m_size; ++idx) {
+ Q_ASSERT(m_keys[idx].isObject());
+ Object &o = static_cast<Object &>(m_keys[idx]);
+ if (o.d()->isMarked()) {
+ m_keys[toIdx] = m_keys[idx];
+ m_values[toIdx] = m_values[idx];
+ ++toIdx;
+ }
+ }
+ m_size = toIdx;
+}
+
diff --git a/src/qml/jsruntime/qv4estable_p.h b/src/qml/jsruntime/qv4estable_p.h
index c665467760..f54fc37a7b 100644
--- a/src/qml/jsruntime/qv4estable_p.h
+++ b/src/qml/jsruntime/qv4estable_p.h
@@ -64,7 +64,7 @@ public:
ESTable();
~ESTable();
- void markObjects(MarkStack *s);
+ void markObjects(MarkStack *s, bool isWeakMap);
void clear();
void set(const Value &k, const Value &v);
bool has(const Value &k) const;
@@ -73,6 +73,8 @@ public:
uint size() const;
void iterate(uint idx, Value *k, Value *v);
+ void removeUnmarkedKeys();
+
private:
Value *m_keys = nullptr;
Value *m_values = nullptr;
diff --git a/src/qml/jsruntime/qv4global_p.h b/src/qml/jsruntime/qv4global_p.h
index e812894a97..5019d4af3a 100644
--- a/src/qml/jsruntime/qv4global_p.h
+++ b/src/qml/jsruntime/qv4global_p.h
@@ -195,6 +195,8 @@ namespace Heap {
struct DataView;
struct TypedArray;
+ struct MapObject;
+
template <typename T, size_t> struct Pointer;
}
@@ -242,6 +244,8 @@ struct ArrayBuffer;
struct DataView;
struct TypedArray;
+struct MapObject;
+
// ReturnedValue is used to return values from runtime methods
// the type has to be a primitive type (no struct or union), so that the compiler
// will return it in a register on all platforms.
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();
}
-
-
diff --git a/src/qml/jsruntime/qv4mapobject_p.h b/src/qml/jsruntime/qv4mapobject_p.h
index 6793612bcb..a0fae2a14a 100644
--- a/src/qml/jsruntime/qv4mapobject_p.h
+++ b/src/qml/jsruntime/qv4mapobject_p.h
@@ -64,7 +64,11 @@ class ESTable;
namespace Heap {
-struct MapCtor : FunctionObject {
+struct WeakMapCtor : FunctionObject {
+ void init(QV4::ExecutionContext *scope);
+};
+
+struct MapCtor : WeakMapCtor {
void init(QV4::ExecutionContext *scope);
};
@@ -72,19 +76,32 @@ struct MapObject : Object {
static void markObjects(Heap::Base *that, MarkStack *markStack);
void init();
void destroy();
+ void removeUnmarkedKeys();
+
+ MapObject *nextWeakMap;
ESTable *esTable;
+ bool isWeakMap;
};
}
-struct MapCtor: FunctionObject
+struct WeakMapCtor: FunctionObject
{
- V4_OBJECT2(MapCtor, FunctionObject)
+ V4_OBJECT2(WeakMapCtor, FunctionObject)
+
+ static ReturnedValue construct(const FunctionObject *f, const Value *argv, int argc, const Value *, bool weakMap);
static ReturnedValue virtualCallAsConstructor(const FunctionObject *f, const Value *argv, int argc, const Value *);
static ReturnedValue virtualCall(const FunctionObject *f, const Value *thisObject, const Value *argv, int argc);
};
+struct MapCtor : WeakMapCtor
+{
+ V4_OBJECT2(MapCtor, WeakMapCtor)
+
+ static ReturnedValue virtualCallAsConstructor(const FunctionObject *f, const Value *argv, int argc, const Value *);
+};
+
struct MapObject : Object
{
V4_OBJECT2(MapObject, Object)
@@ -92,7 +109,17 @@ struct MapObject : Object
V4_NEEDS_DESTROY
};
-struct MapPrototype : Object
+struct WeakMapPrototype : Object
+{
+ void init(ExecutionEngine *engine, Object *ctor);
+
+ static ReturnedValue method_delete(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
+ static ReturnedValue method_get(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
+ static ReturnedValue method_has(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
+ static ReturnedValue method_set(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
+};
+
+struct MapPrototype : WeakMapPrototype
{
void init(ExecutionEngine *engine, Object *ctor);
diff --git a/src/qml/jsruntime/qv4setobject.cpp b/src/qml/jsruntime/qv4setobject.cpp
index 30e849bfed..a03cc3ddf8 100644
--- a/src/qml/jsruntime/qv4setobject.cpp
+++ b/src/qml/jsruntime/qv4setobject.cpp
@@ -139,7 +139,7 @@ void Heap::SetObject::destroy()
void Heap::SetObject::markObjects(Heap::Base *that, MarkStack *markStack)
{
SetObject *s = static_cast<SetObject *>(that);
- s->esTable->markObjects(markStack);
+ s->esTable->markObjects(markStack, false);
Object::markObjects(that, markStack);
}
diff --git a/src/qml/memory/qv4mm.cpp b/src/qml/memory/qv4mm.cpp
index 258fac57af..065204b5d3 100644
--- a/src/qml/memory/qv4mm.cpp
+++ b/src/qml/memory/qv4mm.cpp
@@ -61,6 +61,7 @@
#include <algorithm>
#include "qv4alloca_p.h"
#include "qv4profiling_p.h"
+#include "qv4mapobject_p.h"
//#define MM_STATS
@@ -976,6 +977,18 @@ void MemoryManager::sweep(bool lastSweep, ClassDestroyStatsCallback classCountPt
(*it) = Primitive::undefinedValue();
}
+ // remove objects from weak maps and sets
+ Heap::MapObject *map = weakMaps;
+ Heap::MapObject **lastMap = &weakMaps;
+ while (map) {
+ if (map->isMarked()) {
+ map->removeUnmarkedKeys();
+ *lastMap = map;
+ lastMap = &map->nextWeakMap;
+ }
+ map = map->nextWeakMap;
+ }
+
// onDestruction handlers may have accessed other QObject wrappers and reset their value, so ensure
// that they are all set to undefined.
for (PersistentValueStorage::Iterator it = m_weakValues->begin(); it != m_weakValues->end(); ++it) {
@@ -1179,6 +1192,12 @@ size_t MemoryManager::getLargeItemsMem() const
return hugeItemAllocator.usedMem();
}
+void MemoryManager::registerWeakMap(Heap::MapObject *map)
+{
+ map->nextWeakMap = weakMaps;
+ weakMaps = map;
+}
+
MemoryManager::~MemoryManager()
{
delete m_persistentValues;
diff --git a/src/qml/memory/qv4mm_p.h b/src/qml/memory/qv4mm_p.h
index e3a011caf9..da162d2dfe 100644
--- a/src/qml/memory/qv4mm_p.h
+++ b/src/qml/memory/qv4mm_p.h
@@ -274,6 +274,8 @@ public:
return static_cast<typename ManagedType::Data *>(b);
}
+ void registerWeakMap(Heap::MapObject *map);
+
protected:
/// expects size to be aligned
Heap::Base *allocString(std::size_t unmanagedSize);
@@ -296,6 +298,7 @@ public:
PersistentValueStorage *m_persistentValues;
PersistentValueStorage *m_weakValues;
QVector<Value *> m_pendingFreedObjectWrapperValue;
+ Heap::MapObject *weakMaps = nullptr;
std::size_t unmanagedHeapSize = 0; // the amount of bytes of heap that is not managed by the memory manager, but which is held onto by managed items.
std::size_t unmanagedHeapSizeGCLimit;
diff --git a/tests/auto/qml/ecmascripttests/TestExpectations b/tests/auto/qml/ecmascripttests/TestExpectations
index 2848317683..7fd3178ffc 100644
--- a/tests/auto/qml/ecmascripttests/TestExpectations
+++ b/tests/auto/qml/ecmascripttests/TestExpectations
@@ -215,26 +215,15 @@ built-ins/Map/iterator-items-are-not-object.js fails
built-ins/Map/map-iterable-throws-when-set-is-not-callable.js fails
built-ins/Map/map-iterable.js fails
built-ins/Map/proto-from-ctor-realm.js fails
-built-ins/Map/prototype/clear/context-is-weakmap-object-throws.js fails
-built-ins/Map/prototype/delete/context-is-weakmap-object-throws.js fails
built-ins/Map/prototype/delete/does-not-break-iterators.js fails
built-ins/Map/prototype/delete/returns-true-for-deleted-entry.js fails
-built-ins/Map/prototype/entries/does-not-have-mapdata-internal-slot-weakmap.js fails
built-ins/Map/prototype/forEach/callback-parameters.js fails
built-ins/Map/prototype/forEach/deleted-values-during-foreach.js fails
-built-ins/Map/prototype/forEach/does-not-have-mapdata-internal-slot-weakmap.js fails
built-ins/Map/prototype/forEach/iterates-in-key-insertion-order.js fails
built-ins/Map/prototype/forEach/iterates-values-added-after-foreach-begins.js fails
built-ins/Map/prototype/forEach/iterates-values-deleted-then-readded.js fails
-built-ins/Map/prototype/get/does-not-have-mapdata-internal-slot-weakmap.js fails
-built-ins/Map/prototype/has/does-not-have-mapdata-internal-slot-weakmap.js fails
-built-ins/Map/prototype/keys/does-not-have-mapdata-internal-slot-weakmap.js fails
built-ins/Map/prototype/set/append-new-values.js fails
-built-ins/Map/prototype/set/does-not-have-mapdata-internal-slot-weakmap.js fails
-built-ins/Map/prototype/set/length.js fails
-built-ins/Map/prototype/size/does-not-have-mapdata-internal-slot-weakmap.js fails
built-ins/Map/prototype/size/returns-count-of-present-values-by-iterable.js fails
-built-ins/Map/prototype/values/does-not-have-mapdata-internal-slot-weakmap.js fails
built-ins/Math/max/zeros.js fails
built-ins/Math/round/S15.8.2.15_A7.js fails
built-ins/Number/isFinite/arg-is-not-number.js fails
@@ -497,7 +486,6 @@ built-ins/Set/prototype/forEach/does-not-have-setdata-internal-slot-weakset.js f
built-ins/Set/prototype/forEach/iterates-values-revisits-after-delete-re-add.js fails
built-ins/Set/prototype/forEach/this-arg-explicit-cannot-override-lexical-this-arrow.js fails
built-ins/Set/prototype/has/does-not-have-setdata-internal-slot-weakset.js fails
-built-ins/Set/prototype/values/does-not-have-setdata-internal-slot-weakset.js fails
built-ins/SharedArrayBuffer/data-allocation-after-object-creation.js fails
built-ins/SharedArrayBuffer/proto-from-ctor-realm.js fails
built-ins/SharedArrayBuffer/prototype-from-newtarget.js fails
@@ -657,9 +645,6 @@ built-ins/TypedArrays/internals/Set/key-is-minus-zero.js fails
built-ins/TypedArrays/internals/Set/key-is-not-integer.js fails
built-ins/TypedArrays/internals/Set/key-is-out-of-bounds.js fails
built-ins/TypedArrays/internals/Set/tonumber-value-throws.js strictFails
-built-ins/WeakMap/constructor.js fails
-built-ins/WeakMap/empty-iterable.js fails
-built-ins/WeakMap/get-set-method-failure.js fails
built-ins/WeakMap/iterable-failure.js fails
built-ins/WeakMap/iterable.js fails
built-ins/WeakMap/iterator-close-after-set-failure.js fails
@@ -667,84 +652,10 @@ built-ins/WeakMap/iterator-item-first-entry-returns-abrupt.js fails
built-ins/WeakMap/iterator-item-second-entry-returns-abrupt.js fails
built-ins/WeakMap/iterator-items-are-not-object-close-iterator.js fails
built-ins/WeakMap/iterator-items-are-not-object.js fails
-built-ins/WeakMap/iterator-next-failure.js fails
-built-ins/WeakMap/iterator-value-failure.js fails
-built-ins/WeakMap/length.js fails
-built-ins/WeakMap/name.js fails
-built-ins/WeakMap/no-iterable.js fails
-built-ins/WeakMap/properties-of-map-instances.js fails
-built-ins/WeakMap/properties-of-the-weakmap-prototype-object.js fails
built-ins/WeakMap/proto-from-ctor-realm.js fails
-built-ins/WeakMap/prototype-of-weakmap.js fails
-built-ins/WeakMap/prototype/Symbol.toStringTag.js fails
-built-ins/WeakMap/prototype/constructor.js fails
built-ins/WeakMap/prototype/delete/delete-entry-initial-iterable.js fails
-built-ins/WeakMap/prototype/delete/delete-entry.js fails
-built-ins/WeakMap/prototype/delete/delete.js fails
-built-ins/WeakMap/prototype/delete/does-not-have-weakmapdata-internal-slot-array.js fails
-built-ins/WeakMap/prototype/delete/does-not-have-weakmapdata-internal-slot-map.js fails
-built-ins/WeakMap/prototype/delete/does-not-have-weakmapdata-internal-slot-object.js fails
-built-ins/WeakMap/prototype/delete/does-not-have-weakmapdata-internal-slot-set.js fails
-built-ins/WeakMap/prototype/delete/does-not-have-weakmapdata-internal-slot-weakmap-prototype.js fails
-built-ins/WeakMap/prototype/delete/length.js fails
-built-ins/WeakMap/prototype/delete/name.js fails
-built-ins/WeakMap/prototype/delete/returns-false-value-is-not-object.js fails
-built-ins/WeakMap/prototype/delete/returns-false-when-delete-is-noop.js fails
-built-ins/WeakMap/prototype/delete/this-not-object-throw-boolean.js fails
-built-ins/WeakMap/prototype/delete/this-not-object-throw-null.js fails
-built-ins/WeakMap/prototype/delete/this-not-object-throw-number.js fails
-built-ins/WeakMap/prototype/delete/this-not-object-throw-string.js fails
-built-ins/WeakMap/prototype/delete/this-not-object-throw-symbol.js fails
-built-ins/WeakMap/prototype/delete/this-not-object-throw-undefined.js fails
-built-ins/WeakMap/prototype/get/does-not-have-weakmapdata-internal-slot-map.js fails
-built-ins/WeakMap/prototype/get/does-not-have-weakmapdata-internal-slot-set.js fails
-built-ins/WeakMap/prototype/get/does-not-have-weakmapdata-internal-slot.js fails
-built-ins/WeakMap/prototype/get/get.js fails
-built-ins/WeakMap/prototype/get/length.js fails
-built-ins/WeakMap/prototype/get/name.js fails
-built-ins/WeakMap/prototype/get/returns-undefined-key-is-not-object.js fails
-built-ins/WeakMap/prototype/get/returns-undefined.js fails
built-ins/WeakMap/prototype/get/returns-value.js fails
-built-ins/WeakMap/prototype/get/this-not-object-throw.js fails
-built-ins/WeakMap/prototype/has/does-not-have-weakmapdata-internal-slot-array.js fails
-built-ins/WeakMap/prototype/has/does-not-have-weakmapdata-internal-slot-map.js fails
-built-ins/WeakMap/prototype/has/does-not-have-weakmapdata-internal-slot-object.js fails
-built-ins/WeakMap/prototype/has/does-not-have-weakmapdata-internal-slot-set.js fails
-built-ins/WeakMap/prototype/has/does-not-have-weakmapdata-internal-slot-weakmap-prototype.js fails
-built-ins/WeakMap/prototype/has/has.js fails
-built-ins/WeakMap/prototype/has/length.js fails
-built-ins/WeakMap/prototype/has/name.js fails
-built-ins/WeakMap/prototype/has/returns-false-when-value-is-not-object.js fails
-built-ins/WeakMap/prototype/has/returns-false-when-value-not-present.js fails
-built-ins/WeakMap/prototype/has/returns-true-when-value-present.js fails
-built-ins/WeakMap/prototype/has/this-not-object-throw-boolean.js fails
-built-ins/WeakMap/prototype/has/this-not-object-throw-null.js fails
-built-ins/WeakMap/prototype/has/this-not-object-throw-number.js fails
-built-ins/WeakMap/prototype/has/this-not-object-throw-string.js fails
-built-ins/WeakMap/prototype/has/this-not-object-throw-symbol.js fails
-built-ins/WeakMap/prototype/has/this-not-object-throw-undefined.js fails
-built-ins/WeakMap/prototype/prototype-attributes.js fails
-built-ins/WeakMap/prototype/set/adds-element.js fails
-built-ins/WeakMap/prototype/set/does-not-have-weakmapdata-internal-slot-array.js fails
-built-ins/WeakMap/prototype/set/does-not-have-weakmapdata-internal-slot-map.js fails
-built-ins/WeakMap/prototype/set/does-not-have-weakmapdata-internal-slot-object.js fails
-built-ins/WeakMap/prototype/set/does-not-have-weakmapdata-internal-slot-set.js fails
-built-ins/WeakMap/prototype/set/does-not-have-weakmapdata-internal-slot-weakmap-prototype.js fails
-built-ins/WeakMap/prototype/set/key-not-object-throw.js fails
-built-ins/WeakMap/prototype/set/length.js fails
-built-ins/WeakMap/prototype/set/name.js fails
-built-ins/WeakMap/prototype/set/returns-this-when-ignoring-duplicate.js fails
-built-ins/WeakMap/prototype/set/returns-this.js fails
-built-ins/WeakMap/prototype/set/set.js fails
-built-ins/WeakMap/prototype/set/this-not-object-throw-boolean.js fails
-built-ins/WeakMap/prototype/set/this-not-object-throw-null.js fails
-built-ins/WeakMap/prototype/set/this-not-object-throw-number.js fails
-built-ins/WeakMap/prototype/set/this-not-object-throw-string.js fails
-built-ins/WeakMap/prototype/set/this-not-object-throw-symbol.js fails
-built-ins/WeakMap/prototype/set/this-not-object-throw-undefined.js fails
built-ins/WeakMap/set-not-callable-throws.js fails
-built-ins/WeakMap/undefined-newtarget.js fails
-built-ins/WeakMap/weakmap.js fails
built-ins/WeakSet/add-not-callable-throws.js fails
built-ins/WeakSet/constructor.js fails
built-ins/WeakSet/empty-iterable.js fails
@@ -1325,7 +1236,6 @@ language/statements/class/subclass/builtin-objects/RegExp/super-must-be-called.j
language/statements/class/subclass/builtin-objects/Set/super-must-be-called.js fails
language/statements/class/subclass/builtin-objects/String/super-must-be-called.js fails
language/statements/class/subclass/builtin-objects/TypedArray/super-must-be-called.js fails
-language/statements/class/subclass/builtin-objects/WeakMap/regular-subclassing.js fails
language/statements/class/subclass/builtin-objects/WeakMap/super-must-be-called.js fails
language/statements/class/subclass/builtin-objects/WeakSet/regular-subclassing.js fails
language/statements/class/subclass/builtin-objects/WeakSet/super-must-be-called.js fails
diff --git a/tests/auto/qml/qjsengine/tst_qjsengine.cpp b/tests/auto/qml/qjsengine/tst_qjsengine.cpp
index 7ea652e070..191bd7fca0 100644
--- a/tests/auto/qml/qjsengine/tst_qjsengine.cpp
+++ b/tests/auto/qml/qjsengine/tst_qjsengine.cpp
@@ -979,6 +979,7 @@ void tst_QJSEngine::globalObjectProperties_enumerate()
<< "Float32Array"
<< "Float64Array"
<< "Set"
+ << "WeakMap"
<< "Map"
<< "Reflect"
<< "Proxy"