aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLars Knoll <lars.knoll@qt.io>2018-06-23 21:05:13 +0200
committerLars Knoll <lars.knoll@qt.io>2018-07-02 19:29:36 +0000
commit8728a2b494eb384b65bd4e7c6ec785435a37de9d (patch)
tree85e42b08a4b1e2836ba5db6d40f4b99a6d52f839
parent56602df447c5f16257874f2e97b078dcf76f2467 (diff)
Introduce a PropertyKey class that inherits from Value
This will replace Identifier over the next few commits. The advantage of PropertyKey is that it can be stored on the JS stack, so that a GC run won't accidentally clean up the string/symbol referenced by the key. Change-Id: Ib4daa4616bcfa537e6d371ef7c7740bc7727a50d Reviewed-by: Simon Hausmann <simon.hausmann@qt.io>
-rw-r--r--src/qml/jsruntime/jsruntime.pri2
-rw-r--r--src/qml/jsruntime/qv4global_p.h1
-rw-r--r--src/qml/jsruntime/qv4objectproto.cpp17
-rw-r--r--src/qml/jsruntime/qv4propertykey.cpp60
-rw-r--r--src/qml/jsruntime/qv4propertykey_p.h120
-rw-r--r--src/qml/jsruntime/qv4reflect.cpp17
-rw-r--r--src/qml/jsruntime/qv4runtime.cpp31
-rw-r--r--src/qml/jsruntime/qv4scopedvalue_p.h29
-rw-r--r--src/qml/jsruntime/qv4value.cpp17
-rw-r--r--src/qml/jsruntime/qv4value_p.h2
10 files changed, 260 insertions, 36 deletions
diff --git a/src/qml/jsruntime/jsruntime.pri b/src/qml/jsruntime/jsruntime.pri
index 8b8732590f..243c912266 100644
--- a/src/qml/jsruntime/jsruntime.pri
+++ b/src/qml/jsruntime/jsruntime.pri
@@ -30,6 +30,7 @@ SOURCES += \
$$PWD/qv4numberobject.cpp \
$$PWD/qv4object.cpp \
$$PWD/qv4objectproto.cpp \
+ $$PWD/qv4propertykey.cpp \
$$PWD/qv4proxy.cpp \
$$PWD/qv4qmlcontext.cpp \
$$PWD/qv4reflect.cpp \
@@ -91,6 +92,7 @@ HEADERS += \
$$PWD/qv4numberobject_p.h \
$$PWD/qv4object_p.h \
$$PWD/qv4objectproto_p.h \
+ $$PWD/qv4propertykey_p.h \
$$PWD/qv4proxy_p.h \
$$PWD/qv4qmlcontext_p.h \
$$PWD/qv4reflect_p.h \
diff --git a/src/qml/jsruntime/qv4global_p.h b/src/qml/jsruntime/qv4global_p.h
index 607f8b4d28..e3b3423a9d 100644
--- a/src/qml/jsruntime/qv4global_p.h
+++ b/src/qml/jsruntime/qv4global_p.h
@@ -200,6 +200,7 @@ namespace Heap {
struct CppStackFrame;
class MemoryManager;
class ExecutableAllocator;
+struct PropertyKey;
struct StringOrSymbol;
struct String;
struct Symbol;
diff --git a/src/qml/jsruntime/qv4objectproto.cpp b/src/qml/jsruntime/qv4objectproto.cpp
index daf31833d7..3287912c7d 100644
--- a/src/qml/jsruntime/qv4objectproto.cpp
+++ b/src/qml/jsruntime/qv4objectproto.cpp
@@ -48,6 +48,7 @@
#include "qv4string_p.h"
#include "qv4jscall_p.h"
#include "qv4symbol_p.h"
+#include "qv4propertykey_p.h"
#include <QtCore/QDateTime>
#include <QtCore/QStringList>
@@ -163,12 +164,12 @@ ReturnedValue ObjectPrototype::method_getOwnPropertyDescriptor(const FunctionObj
static_cast<ArgumentsObject *>(O.getPointer())->fullyCreate();
ScopedValue v(scope, argc > 1 ? argv[1] : Primitive::undefinedValue());
- ScopedStringOrSymbol name(scope, v->toPropertyKey(scope.engine));
+ ScopedPropertyKey name(scope, v->toPropertyKey(scope.engine));
if (scope.engine->hasException)
return QV4::Encode::undefined();
ScopedProperty desc(scope);
- PropertyAttributes attrs = O->getOwnProperty(name->toPropertyKey(), desc);
+ PropertyAttributes attrs = O->getOwnProperty(name->toIdentifier(), desc);
return fromPropertyDescriptor(scope.engine, desc, attrs);
}
@@ -284,7 +285,7 @@ ReturnedValue ObjectPrototype::method_defineProperty(const FunctionObject *b, co
return scope.engine->throwTypeError();
ScopedObject O(scope, argv[0]);
- ScopedStringOrSymbol name(scope, (argc > 1 ? argv[1] : Primitive::undefinedValue()).toPropertyKey(scope.engine));
+ ScopedPropertyKey name(scope, (argc > 1 ? argv[1] : Primitive::undefinedValue()).toPropertyKey(scope.engine));
if (scope.engine->hasException)
return QV4::Encode::undefined();
@@ -295,7 +296,7 @@ ReturnedValue ObjectPrototype::method_defineProperty(const FunctionObject *b, co
if (scope.engine->hasException)
return QV4::Encode::undefined();
- if (!O->defineOwnProperty(name->toPropertyKey(), pd, attrs))
+ if (!O->defineOwnProperty(name->toIdentifier(), pd, attrs))
THROW_TYPE_ERROR();
return O.asReturnedValue();
@@ -577,13 +578,13 @@ ReturnedValue ObjectPrototype::method_valueOf(const FunctionObject *b, const Val
ReturnedValue ObjectPrototype::method_hasOwnProperty(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc)
{
Scope scope(b);
- ScopedStringOrSymbol P(scope, (argc ? argv[0] : Primitive::undefinedValue()).toPropertyKey(scope.engine));
+ ScopedPropertyKey P(scope, (argc ? argv[0] : Primitive::undefinedValue()).toPropertyKey(scope.engine));
if (scope.engine->hasException)
return QV4::Encode::undefined();
ScopedObject O(scope, thisObject->toObject(scope.engine));
if (scope.engine->hasException)
return QV4::Encode::undefined();
- bool r = O->getOwnProperty(P->toPropertyKey()) != Attr_Invalid;
+ bool r = O->getOwnProperty(P->toIdentifier()) != Attr_Invalid;
return Encode(r);
}
@@ -609,14 +610,14 @@ ReturnedValue ObjectPrototype::method_isPrototypeOf(const FunctionObject *b, con
ReturnedValue ObjectPrototype::method_propertyIsEnumerable(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc)
{
Scope scope(b);
- ScopedStringOrSymbol p(scope, (argc ? argv[0] : Primitive::undefinedValue()).toPropertyKey(scope.engine));
+ ScopedPropertyKey p(scope, (argc ? argv[0] : Primitive::undefinedValue()).toPropertyKey(scope.engine));
if (scope.engine->hasException)
return QV4::Encode::undefined();
ScopedObject o(scope, thisObject->toObject(scope.engine));
if (scope.engine->hasException)
return QV4::Encode::undefined();
- PropertyAttributes attrs = o->getOwnProperty(p->toPropertyKey());
+ PropertyAttributes attrs = o->getOwnProperty(p->toIdentifier());
return Encode(attrs.isEnumerable());
}
diff --git a/src/qml/jsruntime/qv4propertykey.cpp b/src/qml/jsruntime/qv4propertykey.cpp
new file mode 100644
index 0000000000..4678748ee8
--- /dev/null
+++ b/src/qml/jsruntime/qv4propertykey.cpp
@@ -0,0 +1,60 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qv4propertykey_p.h"
+
+#include <QtCore/qstring.h>
+#include <qv4string_p.h>
+
+QV4::Heap::StringOrSymbol *QV4::PropertyKey::toStringOrSymbol(QV4::ExecutionEngine *e)
+{
+ if (isArrayIndex())
+ return Primitive::fromUInt32(asArrayIndex()).toString(e);
+ return static_cast<Heap::StringOrSymbol *>(asStringOrSymbol());
+}
+
+QString QV4::PropertyKey::toQString() const
+{
+ if (isArrayIndex())
+ return QString::number(asArrayIndex());
+ Heap::Base *b = asStringOrSymbol();
+ Q_ASSERT(b->internalClass->vtable->isStringOrSymbol);
+ Heap::StringOrSymbol *s = static_cast<Heap::StringOrSymbol *>(b);
+ return s->toQString();
+}
diff --git a/src/qml/jsruntime/qv4propertykey_p.h b/src/qml/jsruntime/qv4propertykey_p.h
new file mode 100644
index 0000000000..2e33562514
--- /dev/null
+++ b/src/qml/jsruntime/qv4propertykey_p.h
@@ -0,0 +1,120 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#ifndef QV4PROPERTYKEY_H
+#define QV4PROPERTYKEY_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <private/qv4value_p.h>
+#include <private/qv4identifier_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QString;
+
+namespace QV4 {
+
+struct PropertyKey : private Value
+{
+ // Property keys are Strings, Symbols or unsigned integers.
+ // For convenience we derive them from Values, allowing us to store them
+ // on the JS stack
+ //
+ // They do however behave somewhat different than a Value:
+ // * If the key is a String, the pointer to the string is stored in the identifier
+ // table and thus unique.
+ // * If the key is a Symbol it simply points to the referenced symbol object
+ // * if the key is an array index (a uint < UINT_MAX), it's encoded as an
+ // integer value
+ int id;
+
+ static PropertyKey invalid() { PropertyKey key; key.setRawValue(0); return key; }
+ static PropertyKey fromArrayIndex(uint idx) { PropertyKey key; key.setInt_32(static_cast<int>(idx)); return key; }
+ bool isStringOrSymbol() const { return isManaged(); }
+ uint asArrayIndex() const { return isManaged() ? std::numeric_limits<uint>::max() : value(); }
+ uint isArrayIndex() const { return !isManaged(); }
+ static PropertyKey fromStringOrSymbol(Heap::StringOrSymbol *b)
+ { PropertyKey key; key.setM(reinterpret_cast<Heap::Base *>(b)); return key; }
+ Heap::StringOrSymbol *asStringOrSymbol() const { return reinterpret_cast<Heap::StringOrSymbol *>(heapObject()); }
+
+ bool isString() const {
+ Heap::Base *s = heapObject();
+ return s && s->internalClass->vtable->isString;
+ }
+
+ bool isSymbol() const {
+ Heap::Base *s = heapObject();
+ return s && s->internalClass->vtable->isString && s->internalClass->vtable->isStringOrSymbol;
+ }
+
+ // ### temporary until we transitioned Identifier to PropertyKey
+ static PropertyKey fromIdentifier(Identifier id) {
+ if (id.isArrayIndex())
+ return PropertyKey::fromArrayIndex(id.asArrayIndex());
+ return PropertyKey::fromStringOrSymbol(id.asStringOrSymbol());
+ }
+
+ Identifier toIdentifier() const {
+ if (isArrayIndex())
+ return Identifier::fromArrayIndex(asArrayIndex());
+ return Identifier::fromStringOrSymbol(asStringOrSymbol());
+ }
+
+ Q_QML_EXPORT QString toQString() const;
+ Heap::StringOrSymbol *toStringOrSymbol(ExecutionEngine *e);
+
+ bool operator ==(const PropertyKey &other) const { return id == other.id; }
+ bool operator !=(const PropertyKey &other) const { return id != other.id; }
+ bool operator <(const PropertyKey &other) const { return id < other.id; }
+};
+
+}
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/qml/jsruntime/qv4reflect.cpp b/src/qml/jsruntime/qv4reflect.cpp
index 7d8c8db089..41aa4b402e 100644
--- a/src/qml/jsruntime/qv4reflect.cpp
+++ b/src/qml/jsruntime/qv4reflect.cpp
@@ -41,6 +41,7 @@
#include "qv4symbol_p.h"
#include "qv4runtimeapi_p.h"
#include "qv4objectproto_p.h"
+#include "qv4propertykey_p.h"
using namespace QV4;
@@ -120,7 +121,7 @@ ReturnedValue Reflect::method_defineProperty(const FunctionObject *f, const Valu
return scope.engine->throwTypeError();
ScopedObject O(scope, argv[0]);
- ScopedStringOrSymbol name(scope, (argc > 1 ? argv[1] : Primitive::undefinedValue()).toPropertyKey(scope.engine));
+ ScopedPropertyKey name(scope, (argc > 1 ? argv[1] : Primitive::undefinedValue()).toPropertyKey(scope.engine));
if (scope.engine->hasException)
return QV4::Encode::undefined();
@@ -131,7 +132,7 @@ ReturnedValue Reflect::method_defineProperty(const FunctionObject *f, const Valu
if (scope.engine->hasException)
return QV4::Encode::undefined();
- bool result = O->defineOwnProperty(name->toPropertyKey(), pd, attrs);
+ bool result = O->defineOwnProperty(name->toIdentifier(), pd, attrs);
return Encode(result);
}
@@ -155,12 +156,12 @@ ReturnedValue Reflect::method_get(const FunctionObject *f, const Value *, const
ScopedObject o(scope, static_cast<const Object *>(argv));
Value undef = Primitive::undefinedValue();
const Value *index = argc > 1 ? &argv[1] : &undef;
- ScopedStringOrSymbol name(scope, index->toPropertyKey(scope.engine));
+ ScopedPropertyKey name(scope, index->toPropertyKey(scope.engine));
if (scope.hasException())
return Encode::undefined();
ScopedValue receiver(scope, argc > 2 ? argv[2] : *o);
- return Encode(o->get(name->toPropertyKey(), receiver));
+ return Encode(o->get(name->toIdentifier(), receiver));
}
ReturnedValue Reflect::method_getOwnPropertyDescriptor(const FunctionObject *f, const Value *thisObject, const Value *argv, int argc)
@@ -198,10 +199,10 @@ ReturnedValue Reflect::method_has(const FunctionObject *f, const Value *, const
return Encode(hasProperty);
}
- ScopedStringOrSymbol name(scope, index->toPropertyKey(scope.engine));
+ ScopedPropertyKey name(scope, index->toPropertyKey(scope.engine));
if (scope.engine->hasException)
return false;
- (void) o->get(name, &hasProperty);
+ (void) o->get(name->toIdentifier(), nullptr, &hasProperty);
return Encode(hasProperty);
}
@@ -245,10 +246,10 @@ ReturnedValue Reflect::method_set(const FunctionObject *f, const Value *, const
const Value &val = argc > 2 ? argv[2] : undef;
ScopedValue receiver(scope, argc >3 ? argv[3] : argv[0]);
- Scoped<StringOrSymbol> propertyKey(scope, index->toPropertyKey(scope.engine));
+ ScopedPropertyKey propertyKey(scope, index->toPropertyKey(scope.engine));
if (scope.engine->hasException)
return false;
- bool result = o->put(propertyKey->toPropertyKey(), val, receiver);
+ bool result = o->put(propertyKey->toIdentifier(), val, receiver);
return Encode(result);
}
diff --git a/src/qml/jsruntime/qv4runtime.cpp b/src/qml/jsruntime/qv4runtime.cpp
index 87a1f665b5..eee94a2f60 100644
--- a/src/qml/jsruntime/qv4runtime.cpp
+++ b/src/qml/jsruntime/qv4runtime.cpp
@@ -333,11 +333,10 @@ bool Runtime::method_deleteProperty(ExecutionEngine *engine, const Value &base,
if (n < UINT_MAX)
return o->deleteProperty(Identifier::fromArrayIndex(n));
- Scoped<StringOrSymbol> key(scope, index.toPropertyKey(engine));
+ ScopedPropertyKey key(scope, index.toPropertyKey(engine));
if (engine->hasException)
return false;
- Identifier id = key->toPropertyKey();
- return o->deleteProperty(id);
+ return o->deleteProperty(key->toIdentifier());
}
bool Runtime::method_deleteName(ExecutionEngine *engine, int nameIndex)
@@ -372,10 +371,10 @@ QV4::ReturnedValue Runtime::method_in(ExecutionEngine *engine, const Value &left
if (!ro)
return engine->throwTypeError();
Scope scope(engine);
- ScopedStringOrSymbol s(scope, left.toPropertyKey(engine));
+ ScopedPropertyKey s(scope, left.toPropertyKey(engine));
if (scope.hasException())
return Encode::undefined();
- bool r = ro->hasProperty(s->toPropertyKey());
+ bool r = ro->hasProperty(s->toIdentifier());
return Encode(r);
}
@@ -638,10 +637,10 @@ static Q_NEVER_INLINE ReturnedValue getElementFallback(ExecutionEngine *engine,
Q_ASSERT(!!o); // can't fail as null/undefined is covered above
}
- ScopedStringOrSymbol name(scope, index.toPropertyKey(engine));
+ ScopedPropertyKey name(scope, index.toPropertyKey(engine));
if (scope.hasException())
return Encode::undefined();
- return o->get(name);
+ return o->get(name->toIdentifier());
}
ReturnedValue Runtime::method_loadElement(ExecutionEngine *engine, const Value &object, const Value &index)
@@ -684,10 +683,10 @@ static Q_NEVER_INLINE bool setElementFallback(ExecutionEngine *engine, const Val
return o->put(idx, value);
}
- ScopedStringOrSymbol name(scope, index.toPropertyKey(engine));
+ ScopedPropertyKey name(scope, index.toPropertyKey(engine));
if (engine->hasException)
return false;
- return o->put(name, value);
+ return o->put(name->toIdentifier(), value);
}
void Runtime::method_storeElement(ExecutionEngine *engine, const Value &object, const Value &index, const Value &value)
@@ -1202,11 +1201,11 @@ ReturnedValue Runtime::method_callElement(ExecutionEngine *engine, Value *base,
ScopedValue thisObject(scope, base->toObject(engine));
base = thisObject;
- ScopedStringOrSymbol str(scope, index.toPropertyKey(engine));
+ ScopedPropertyKey str(scope, index.toPropertyKey(engine));
if (engine->hasException)
return Encode::undefined();
- ScopedFunctionObject f(scope, static_cast<Object *>(base)->get(str));
+ ScopedFunctionObject f(scope, static_cast<Object *>(base)->get(str->toIdentifier()));
if (!f)
return engine->throwTypeError();
@@ -1452,7 +1451,7 @@ ReturnedValue Runtime::method_objectLiteral(ExecutionEngine *engine, int classId
if (!additionalArgs)
return o->asReturnedValue();
- Scoped<StringOrSymbol> name(scope);
+ ScopedPropertyKey name(scope);
ScopedProperty pd(scope);
for (int i = 0; i < additionalArgs; ++i) {
Q_ASSERT(args->isInteger());
@@ -1468,7 +1467,7 @@ ReturnedValue Runtime::method_objectLiteral(ExecutionEngine *engine, int classId
pd->value = Primitive::emptyValue();
pd->set = args[2];
}
- bool ok = o->defineOwnProperty(name->toPropertyKey(), pd, (arg == ObjectLiteralArgument::Value ? Attr_Data : Attr_Accessor));
+ bool ok = o->defineOwnProperty(name->toIdentifier(), pd, (arg == ObjectLiteralArgument::Value ? Attr_Data : Attr_Accessor));
if (!ok)
return engine->throwTypeError();
@@ -1523,7 +1522,7 @@ ReturnedValue Runtime::method_createClass(ExecutionEngine *engine, int classInde
ScopedObject receiver(scope, *constructor);
- ScopedStringOrSymbol propertyName(scope);
+ ScopedPropertyKey propertyName(scope);
ScopedFunctionObject function(scope);
ScopedProperty property(scope);
const CompiledData::Method *methods = cls->methodTable();
@@ -1536,9 +1535,9 @@ ReturnedValue Runtime::method_createClass(ExecutionEngine *engine, int classInde
return Encode::undefined();
++computedNames;
} else {
- propertyName = unit->runtimeStrings[methods[i].name];
+ propertyName = PropertyKey::fromStringOrSymbol(unit->runtimeStrings[methods[i].name]);
}
- Identifier id = propertyName->toPropertyKey();
+ Identifier id = propertyName->toIdentifier();
QV4::Function *f = unit->runtimeFunctions[methods[i].function];
Q_ASSERT(f);
function = FunctionObject::createMemberFunction(current, f);
diff --git a/src/qml/jsruntime/qv4scopedvalue_p.h b/src/qml/jsruntime/qv4scopedvalue_p.h
index 73ee17cd40..1a5837935c 100644
--- a/src/qml/jsruntime/qv4scopedvalue_p.h
+++ b/src/qml/jsruntime/qv4scopedvalue_p.h
@@ -53,6 +53,7 @@
#include "qv4engine_p.h"
#include "qv4value_p.h"
#include "qv4property_p.h"
+#include "qv4propertykey_p.h"
#ifdef V4_USE_VALGRIND
#include <valgrind/memcheck.h>
@@ -240,6 +241,34 @@ struct ScopedValue
Value *ptr;
};
+
+struct ScopedPropertyKey
+{
+ ScopedPropertyKey(const Scope &scope)
+ {
+ ptr = reinterpret_cast<PropertyKey *>(scope.alloc<Scope::Uninitialized>());
+ *ptr = PropertyKey::invalid();
+ }
+
+ ScopedPropertyKey(const Scope &scope, const PropertyKey &v)
+ {
+ ptr = reinterpret_cast<PropertyKey *>(scope.alloc<Scope::Uninitialized>());
+ *ptr = v;
+ }
+
+ ScopedPropertyKey &operator=(const PropertyKey &other) {
+ *ptr = other;
+ return *this;
+ }
+
+ PropertyKey *operator->() {
+ return ptr;
+ }
+
+ PropertyKey *ptr;
+};
+
+
template<typename T>
struct Scoped
{
diff --git a/src/qml/jsruntime/qv4value.cpp b/src/qml/jsruntime/qv4value.cpp
index 9febd41a00..6b22967bfa 100644
--- a/src/qml/jsruntime/qv4value.cpp
+++ b/src/qml/jsruntime/qv4value.cpp
@@ -39,6 +39,7 @@
#include <qv4engine_p.h>
#include <qv4runtime_p.h>
#include <qv4string_p.h>
+#include <qv4propertykey_p.h>
#ifndef V4_BOOTSTRAP
#include <qv4symbol_p.h>
#include <qv4object_p.h>
@@ -229,15 +230,25 @@ QString Value::toQString() const
} // switch
}
-Heap::StringOrSymbol *Value::toPropertyKey(ExecutionEngine *e) const
+QV4::PropertyKey Value::toPropertyKey(ExecutionEngine *e) const
{
+ if (isInteger() && int_32() >= 0)
+ return PropertyKey::fromArrayIndex(static_cast<uint>(int_32()));
+ if (isStringOrSymbol()) {
+ Scope scope(e);
+ ScopedStringOrSymbol s(scope, this);
+ s->makeIdentifier();
+ return PropertyKey::fromIdentifier(s->identifier());
+ }
Scope scope(e);
ScopedValue v(scope, RuntimeHelpers::toPrimitive(*this, STRING_HINT));
if (!v->isStringOrSymbol())
v = v->toString(e);
if (e->hasException)
- return nullptr;
- return static_cast<Heap::StringOrSymbol *>(v->m());
+ return PropertyKey::invalid();
+ ScopedStringOrSymbol s(scope, v);
+ s->makeIdentifier();
+ return PropertyKey::fromIdentifier(s->identifier());
}
#endif // V4_BOOTSTRAP
diff --git a/src/qml/jsruntime/qv4value_p.h b/src/qml/jsruntime/qv4value_p.h
index 16bbf241ff..ac0a52f7a8 100644
--- a/src/qml/jsruntime/qv4value_p.h
+++ b/src/qml/jsruntime/qv4value_p.h
@@ -415,7 +415,7 @@ public:
return reinterpret_cast<Heap::String *>(m());
return toString(e, *this);
}
- Heap::StringOrSymbol *toPropertyKey(ExecutionEngine *e) const;
+ QV4::PropertyKey toPropertyKey(ExecutionEngine *e) const;
static Heap::String *toString(ExecutionEngine *e, Value val);
Heap::Object *toObject(ExecutionEngine *e) const {