diff options
author | Ulf Hermann <ulf.hermann@qt.io> | 2019-05-28 15:13:05 +0200 |
---|---|---|
committer | Ulf Hermann <ulf.hermann@qt.io> | 2019-05-31 12:31:14 +0200 |
commit | 9e6a8598e5ad2f826bf563ff450c911a5f8fbc2d (patch) | |
tree | d9f568941599d5d7ffaa9fbbf1d622874eae4fb0 /src/qml/jsruntime/qv4objectproto.cpp | |
parent | 8733a8762c2db473d3a39d1f01c09156c04e3772 (diff) |
Clean up frozen(), sealed(), nonExtensible() and propertiesFrozen()
They all had some interesting bugs and duplicated each other:
a, propertiesFrozen() changed each property individually, creating a lot
of unnecessary intermediate classes. frozen() changed them all at once.
b, If a class happened to contain only properties that matched the
characteristics of being "sealed" or "frozen", sealed(), frozen() and
propertiesFrozen() would set the flags in place and return the same
class. This is bad because it violates the assumption that an
InternalClass is immutable and it breaks the recursive freezing
algorithm we rely on for the global object. It would stop freezing child
objects at any such class, even if the children were not frozen.
c, propertiesFrozen() did not set any of the flags even though it
effectively sealed and froze the class. Therefore, when requesting the
same class as frozen() it would iterate through all the properties
again.
d, frozen() implicitly also sealed the object and made it
non-extensible. sealed() also implicitly made it non-extensible. This is
impractical as we want to allow objects to be extensible even though all
their properties are frozen. Therefore we only set the flag that belongs
to each method now. We do know, however, that a frozen object is
implicitly sealed. Therefore we can short-circuit this transition.
Furthermore, we need to remove the assert in InternalClass::init() as
you can indeed use frozen objects as prototypes for others, but that
needs to be recorded in the original InternalClass via the isUsedAsProto
flag. In order to set this flag, we need to perform a transition and
therefore, derive from the old InternalClass.
The JavaScript isFrozen() method asks for an _implicitly_, "duck typed",
frozen state, which is different from what our "isFrozen" flag denotes.
Therefore we add a separate const method that just checks whether all
properties are frozen.
Task-number: QTBUG-76033
Change-Id: I375fef83fb99035d470490fdf2348766b090831e
Reviewed-by: Lars Knoll <lars.knoll@qt.io>
Diffstat (limited to 'src/qml/jsruntime/qv4objectproto.cpp')
-rw-r--r-- | src/qml/jsruntime/qv4objectproto.cpp | 8 |
1 files changed, 4 insertions, 4 deletions
diff --git a/src/qml/jsruntime/qv4objectproto.cpp b/src/qml/jsruntime/qv4objectproto.cpp index 6b4c3ba71a..3d3b3f413f 100644 --- a/src/qml/jsruntime/qv4objectproto.cpp +++ b/src/qml/jsruntime/qv4objectproto.cpp @@ -422,7 +422,7 @@ ReturnedValue ObjectPrototype::method_seal(const FunctionObject *b, const Value Scope scope(b); ScopedObject o(scope, a); - o->setInternalClass(o->internalClass()->sealed()); + o->setInternalClass(o->internalClass()->canned()); if (o->arrayData()) { ArrayData::ensureAttributes(o); @@ -448,7 +448,7 @@ ReturnedValue ObjectPrototype::method_freeze(const FunctionObject *b, const Valu if (ArgumentsObject::isNonStrictArgumentsObject(o)) static_cast<ArgumentsObject *>(o.getPointer())->fullyCreate(); - o->setInternalClass(o->internalClass()->frozen()); + o->setInternalClass(o->internalClass()->cryopreserved()); if (o->arrayData()) { ArrayData::ensureAttributes(o); @@ -489,7 +489,7 @@ ReturnedValue ObjectPrototype::method_isSealed(const FunctionObject *b, const Va if (o->isExtensible()) return Encode(false); - if (o->internalClass() != o->internalClass()->sealed()) + if (o->internalClass() != o->internalClass()->canned()) return Encode(false); if (!o->arrayData() || !o->arrayData()->length()) @@ -521,7 +521,7 @@ ReturnedValue ObjectPrototype::method_isFrozen(const FunctionObject *b, const Va if (o->isExtensible()) return Encode(false); - if (o->internalClass() != o->internalClass()->frozen()) + if (!o->internalClass()->isImplicitlyFrozen()) return Encode(false); if (!o->arrayData() || !o->arrayData()->length()) |