aboutsummaryrefslogtreecommitdiffstats
path: root/src/qml/jsruntime
diff options
context:
space:
mode:
authorLars Knoll <lars.knoll@qt.io>2018-04-03 15:23:07 +0200
committerLars Knoll <lars.knoll@qt.io>2018-05-02 14:18:36 +0000
commitbab5e5adf578fb37402ff03f4bd5e9ed3ce4c2d2 (patch)
tree1bbc320c5594faf5d2156385088c12222b9542b8 /src/qml/jsruntime
parenta6da23bb5f6004e13d22838c7db1246169874930 (diff)
Partial Symbol support
Added basic infrastructure to create symbols and convert them back to strings. In addition, storing and retrieving of symbol based properties in Objects works. Change-Id: I185f7aa46e7afa19db5a801102142892e03b7bf1 Reviewed-by: Simon Hausmann <simon.hausmann@qt.io>
Diffstat (limited to 'src/qml/jsruntime')
-rw-r--r--src/qml/jsruntime/jsruntime.pri2
-rw-r--r--src/qml/jsruntime/qv4engine.cpp30
-rw-r--r--src/qml/jsruntime/qv4engine_p.h4
-rw-r--r--src/qml/jsruntime/qv4enginebase_p.h2
-rw-r--r--src/qml/jsruntime/qv4global_p.h5
-rw-r--r--src/qml/jsruntime/qv4lookup.cpp7
-rw-r--r--src/qml/jsruntime/qv4managed.cpp7
-rw-r--r--src/qml/jsruntime/qv4managed_p.h1
-rw-r--r--src/qml/jsruntime/qv4objectproto.cpp10
-rw-r--r--src/qml/jsruntime/qv4runtime.cpp39
-rw-r--r--src/qml/jsruntime/qv4string.cpp3
-rw-r--r--src/qml/jsruntime/qv4string_p.h6
-rw-r--r--src/qml/jsruntime/qv4stringobject.cpp14
-rw-r--r--src/qml/jsruntime/qv4symbol.cpp116
-rw-r--r--src/qml/jsruntime/qv4symbol_p.h105
-rw-r--r--src/qml/jsruntime/qv4value.cpp3
-rw-r--r--src/qml/jsruntime/qv4value_p.h19
17 files changed, 338 insertions, 35 deletions
diff --git a/src/qml/jsruntime/jsruntime.pri b/src/qml/jsruntime/jsruntime.pri
index 1ec00cc744..c7d80d5a82 100644
--- a/src/qml/jsruntime/jsruntime.pri
+++ b/src/qml/jsruntime/jsruntime.pri
@@ -36,6 +36,7 @@ SOURCES += \
$$PWD/qv4runtimecodegen.cpp \
$$PWD/qv4serialize.cpp \
$$PWD/qv4script.cpp \
+ $$PWD/qv4symbol.cpp \
$$PWD/qv4include.cpp \
$$PWD/qv4qobjectwrapper.cpp \
$$PWD/qv4arraybuffer.cpp \
@@ -86,6 +87,7 @@ HEADERS += \
$$PWD/qv4regexp_p.h \
$$PWD/qv4serialize_p.h \
$$PWD/qv4script_p.h \
+ $$PWD/qv4symbol_p.h \
$$PWD/qv4scopedvalue_p.h \
$$PWD/qv4executableallocator_p.h \
$$PWD/qv4include_p.h \
diff --git a/src/qml/jsruntime/qv4engine.cpp b/src/qml/jsruntime/qv4engine.cpp
index af752cf243..5ede4373f2 100644
--- a/src/qml/jsruntime/qv4engine.cpp
+++ b/src/qml/jsruntime/qv4engine.cpp
@@ -52,6 +52,7 @@
#include <qv4numberobject_p.h>
#include <qv4regexpobject_p.h>
#include <qv4regexp_p.h>
+#include "qv4symbol_p.h"
#include <qv4variantobject_p.h>
#include <qv4runtime_p.h>
#include <private/qv4mm_p.h>
@@ -198,12 +199,12 @@ ExecutionEngine::ExecutionEngine(QJSEngine *jsEngine)
jsStackLimit = jsStackBase + JSStackLimit/sizeof(Value);
identifierTable = new IdentifierTable(this);
+ symbolTable = new IdentifierTable(this);
memset(classes, 0, sizeof(classes));
classes[Class_Empty] = memoryManager->allocIC<InternalClass>();
classes[Class_Empty]->init(this);
- classes[Class_String] = classes[Class_Empty]->changeVTable(QV4::String::staticVTable());
classes[Class_MemberData] = classes[Class_Empty]->changeVTable(QV4::MemberData::staticVTable());
classes[Class_SimpleArrayData] = classes[Class_Empty]->changeVTable(QV4::SimpleArrayData::staticVTable());
classes[Class_SparseArrayData] = classes[Class_Empty]->changeVTable(QV4::SparseArrayData::staticVTable());
@@ -211,6 +212,21 @@ ExecutionEngine::ExecutionEngine(QJSEngine *jsEngine)
classes[Class_CallContext] = classes[Class_Empty]->changeVTable(QV4::CallContext::staticVTable());
classes[Class_QmlContext] = classes[Class_Empty]->changeVTable(QV4::QmlContext::staticVTable());
+ Scope scope(this);
+ Scoped<InternalClass> ic(scope);
+ ic = classes[Class_Empty]->changeVTable(QV4::Object::staticVTable());
+ jsObjects[ObjectProto] = memoryManager->allocObject<ObjectPrototype>(ic->d());
+ classes[Class_Object] = ic->changePrototype(objectPrototype()->d());
+ classes[Class_QmlContextWrapper] = classes[Class_Object]->changeVTable(QV4::QQmlContextWrapper::staticVTable());
+
+ ic = newInternalClass(QV4::StringObject::staticVTable(), objectPrototype());
+ jsObjects[StringProto] = memoryManager->allocObject<StringPrototype>(ic->d());
+ classes[Class_String] = classes[Class_Empty]->changeVTable(QV4::String::staticVTable())->changePrototype(stringPrototype()->d());
+ Q_ASSERT(stringPrototype()->d() && classes[Class_String]->prototype);
+
+ jsObjects[SymbolProto] = memoryManager->allocate<SymbolPrototype>();
+ classes[Class_Symbol] = classes[EngineBase::Class_Empty]->changeVTable(QV4::Symbol::staticVTable())->changePrototype(symbolPrototype()->d());
+
jsStrings[String_Empty] = newIdentifier(QString());
jsStrings[String_undefined] = newIdentifier(QStringLiteral("undefined"));
jsStrings[String_null] = newIdentifier(QStringLiteral("null"));
@@ -248,13 +264,6 @@ ExecutionEngine::ExecutionEngine(QJSEngine *jsEngine)
jsStrings[String_buffer] = newIdentifier(QStringLiteral("buffer"));
jsStrings[String_lastIndex] = newIdentifier(QStringLiteral("lastIndex"));
- Scope scope(this);
- Scoped<InternalClass> ic(scope);
- ic = classes[Class_Empty]->changeVTable(QV4::Object::staticVTable());
- jsObjects[ObjectProto] = memoryManager->allocObject<ObjectPrototype>(ic->d());
- classes[Class_Object] = ic->changePrototype(objectPrototype()->d());
- classes[EngineBase::Class_QmlContextWrapper] = classes[Class_Object]->changeVTable(QV4::QQmlContextWrapper::staticVTable());
-
ic = newInternalClass(ArrayPrototype::staticVTable(), objectPrototype());
Q_ASSERT(ic->d()->prototype);
ic = ic->addMember(id_length()->identifier(), Attr_NotConfigurable|Attr_NotEnumerable);
@@ -277,7 +286,6 @@ ExecutionEngine::ExecutionEngine(QJSEngine *jsEngine)
ic = newInternalClass(QV4::StringObject::staticVTable(), objectPrototype());
ic = ic->addMember(id_length()->identifier(), Attr_ReadOnly);
- jsObjects[StringProto] = memoryManager->allocObject<StringPrototype>(ic->d());
classes[Class_StringObject] = ic->changePrototype(stringPrototype()->d());
Q_ASSERT(classes[Class_StringObject]->find(id_length()->identifier()) == Heap::StringObject::LengthPropertyIndex);
@@ -362,8 +370,10 @@ ExecutionEngine::ExecutionEngine(QJSEngine *jsEngine)
#endif
ExecutionContext *global = rootContext();
+
jsObjects[Object_Ctor] = memoryManager->allocate<ObjectCtor>(global);
jsObjects[String_Ctor] = memoryManager->allocate<StringCtor>(global);
+ jsObjects[Symbol_Ctor] = memoryManager->allocate<SymbolCtor>(global);
jsObjects[Number_Ctor] = memoryManager->allocate<NumberCtor>(global);
jsObjects[Boolean_Ctor] = memoryManager->allocate<BooleanCtor>(global);
jsObjects[Array_Ctor] = memoryManager->allocate<ArrayCtor>(global);
@@ -380,6 +390,7 @@ ExecutionEngine::ExecutionEngine(QJSEngine *jsEngine)
static_cast<ObjectPrototype *>(objectPrototype())->init(this, objectCtor());
static_cast<StringPrototype *>(stringPrototype())->init(this, stringCtor());
+ static_cast<SymbolPrototype *>(symbolPrototype())->init(this, symbolCtor());
static_cast<NumberPrototype *>(numberPrototype())->init(this, numberCtor());
static_cast<BooleanPrototype *>(booleanPrototype())->init(this, booleanCtor());
static_cast<ArrayPrototype *>(arrayPrototype())->init(this, arrayCtor());
@@ -426,6 +437,7 @@ ExecutionEngine::ExecutionEngine(QJSEngine *jsEngine)
globalObject->defineDefaultProperty(QStringLiteral("Object"), *objectCtor());
globalObject->defineDefaultProperty(QStringLiteral("String"), *stringCtor());
+ globalObject->defineDefaultProperty(QStringLiteral("Symbol"), *symbolCtor());
FunctionObject *numberObject = numberCtor();
globalObject->defineDefaultProperty(QStringLiteral("Number"), *numberObject);
globalObject->defineDefaultProperty(QStringLiteral("Boolean"), *booleanCtor());
diff --git a/src/qml/jsruntime/qv4engine_p.h b/src/qml/jsruntime/qv4engine_p.h
index 4316967484..ff767a3dde 100644
--- a/src/qml/jsruntime/qv4engine_p.h
+++ b/src/qml/jsruntime/qv4engine_p.h
@@ -161,6 +161,7 @@ public:
RootContext,
IntegerNull, // Has to come after the RootContext to make the context stack safe
ObjectProto,
+ SymbolProto,
ArrayProto,
PropertyListProto,
StringProto,
@@ -187,6 +188,7 @@ public:
Object_Ctor,
String_Ctor,
+ Symbol_Ctor,
Number_Ctor,
Boolean_Ctor,
Array_Ctor,
@@ -214,6 +216,7 @@ public:
ExecutionContext *rootContext() const { return reinterpret_cast<ExecutionContext *>(jsObjects + RootContext); }
FunctionObject *objectCtor() const { return reinterpret_cast<FunctionObject *>(jsObjects + Object_Ctor); }
FunctionObject *stringCtor() const { return reinterpret_cast<FunctionObject *>(jsObjects + String_Ctor); }
+ FunctionObject *symbolCtor() const { return reinterpret_cast<FunctionObject *>(jsObjects + Symbol_Ctor); }
FunctionObject *numberCtor() const { return reinterpret_cast<FunctionObject *>(jsObjects + Number_Ctor); }
FunctionObject *booleanCtor() const { return reinterpret_cast<FunctionObject *>(jsObjects + Boolean_Ctor); }
FunctionObject *arrayCtor() const { return reinterpret_cast<FunctionObject *>(jsObjects + Array_Ctor); }
@@ -232,6 +235,7 @@ public:
FunctionObject *typedArrayCtors;
Object *objectPrototype() const { return reinterpret_cast<Object *>(jsObjects + ObjectProto); }
+ Object *symbolPrototype() const { return reinterpret_cast<Object *>(jsObjects + SymbolProto); }
Object *arrayPrototype() const { return reinterpret_cast<Object *>(jsObjects + ArrayProto); }
Object *propertyListPrototype() const { return reinterpret_cast<Object *>(jsObjects + PropertyListProto); }
Object *stringPrototype() const { return reinterpret_cast<Object *>(jsObjects + StringProto); }
diff --git a/src/qml/jsruntime/qv4enginebase_p.h b/src/qml/jsruntime/qv4enginebase_p.h
index c01b9b1842..4abf92eea5 100644
--- a/src/qml/jsruntime/qv4enginebase_p.h
+++ b/src/qml/jsruntime/qv4enginebase_p.h
@@ -83,6 +83,7 @@ struct Q_QML_EXPORT EngineBase {
Value *jsStackBase = nullptr;
IdentifierTable *identifierTable = nullptr;
+ IdentifierTable *symbolTable = nullptr;
Object *globalObject = nullptr;
// Exception handling
@@ -112,6 +113,7 @@ struct Q_QML_EXPORT EngineBase {
Class_ErrorObjectWithMessage,
Class_ErrorProto,
Class_QmlContextWrapper,
+ Class_Symbol,
NClasses
};
Heap::InternalClass *classes[NClasses];
diff --git a/src/qml/jsruntime/qv4global_p.h b/src/qml/jsruntime/qv4global_p.h
index 6820042406..fce220907e 100644
--- a/src/qml/jsruntime/qv4global_p.h
+++ b/src/qml/jsruntime/qv4global_p.h
@@ -165,7 +165,9 @@ namespace Heap {
struct MemberData;
struct ArrayData;
+ struct StringOrSymbol;
struct String;
+ struct Symbol;
struct Object;
struct ObjectPrototype;
@@ -197,7 +199,9 @@ namespace Heap {
class MemoryManager;
class ExecutableAllocator;
+struct StringOrSymbol;
struct String;
+struct Symbol;
struct Object;
struct ObjectPrototype;
struct ObjectIterator;
@@ -244,6 +248,7 @@ struct Scope;
struct ScopedValue;
template<typename T> struct Scoped;
typedef Scoped<String> ScopedString;
+typedef Scoped<StringOrSymbol> ScopedStringOrSymbol;
typedef Scoped<Object> ScopedObject;
typedef Scoped<ArrayObject> ScopedArrayObject;
typedef Scoped<FunctionObject> ScopedFunctionObject;
diff --git a/src/qml/jsruntime/qv4lookup.cpp b/src/qml/jsruntime/qv4lookup.cpp
index b5a21ca825..e4a7c703fc 100644
--- a/src/qml/jsruntime/qv4lookup.cpp
+++ b/src/qml/jsruntime/qv4lookup.cpp
@@ -109,11 +109,12 @@ ReturnedValue Lookup::resolvePrimitiveGetter(ExecutionEngine *engine, const Valu
break;
case Value::Managed_Type: {
// ### Should move this over to the Object path, as strings also have an internalClass
- Q_ASSERT(object.isString());
- primitiveLookup.proto = engine->stringPrototype()->d();
+ Q_ASSERT(object.isStringOrSymbol());
+ primitiveLookup.proto = static_cast<const Managed &>(object).internalClass()->prototype;
+ Q_ASSERT(primitiveLookup.proto);
Scope scope(engine);
ScopedString name(scope, engine->currentStackFrame->v4Function->compilationUnit->runtimeStrings[nameIndex]);
- if (name->equals(engine->id_length())) {
+ if (object.isString() && name->equals(engine->id_length())) {
// special case, as the property is on the object itself
getter = stringLengthGetter;
return stringLengthGetter(this, engine, object);
diff --git a/src/qml/jsruntime/qv4managed.cpp b/src/qml/jsruntime/qv4managed.cpp
index 924d2263c9..6ed2a9d716 100644
--- a/src/qml/jsruntime/qv4managed.cpp
+++ b/src/qml/jsruntime/qv4managed.cpp
@@ -72,8 +72,13 @@ QString Managed::className() const
const char *s = nullptr;
switch (Type(vtable()->type)) {
case Type_Invalid:
- case Type_String:
return QString();
+ case Type_String:
+ s = "String";
+ break;
+ case Type_Symbol:
+ s = "Symbol";
+ break;
case Type_Object:
s = "Object";
break;
diff --git a/src/qml/jsruntime/qv4managed_p.h b/src/qml/jsruntime/qv4managed_p.h
index 30adf07ffb..7ef5fd4ab8 100644
--- a/src/qml/jsruntime/qv4managed_p.h
+++ b/src/qml/jsruntime/qv4managed_p.h
@@ -182,6 +182,7 @@ public:
Type_Invalid,
Type_String,
Type_Object,
+ Type_Symbol,
Type_ArrayObject,
Type_FunctionObject,
Type_BooleanObject,
diff --git a/src/qml/jsruntime/qv4objectproto.cpp b/src/qml/jsruntime/qv4objectproto.cpp
index 451566137c..94917a45f6 100644
--- a/src/qml/jsruntime/qv4objectproto.cpp
+++ b/src/qml/jsruntime/qv4objectproto.cpp
@@ -484,10 +484,14 @@ ReturnedValue ObjectPrototype::method_toString(const FunctionObject *b, const Va
return Encode(v4->newString(QStringLiteral("[object Undefined]")));
} else if (thisObject->isNull()) {
return Encode(v4->newString(QStringLiteral("[object Null]")));
+ } else if (thisObject->isBoolean()) {
+ return Encode(v4->newString(QStringLiteral("[object Boolean]")));
+ } else if (thisObject->isNumber()) {
+ return Encode(v4->newString(QStringLiteral("[object Number]")));
} else {
- Scope scope(v4);
- ScopedObject obj(scope, thisObject->toObject(scope.engine));
- QString className = obj->className();
+ Q_ASSERT(thisObject->isManaged());
+ const Managed *m = static_cast<const Managed *>(thisObject);
+ QString className = m->className();
return Encode(v4->newString(QStringLiteral("[object %1]").arg(className)));
}
}
diff --git a/src/qml/jsruntime/qv4runtime.cpp b/src/qml/jsruntime/qv4runtime.cpp
index 40e08ededb..106ea65679 100644
--- a/src/qml/jsruntime/qv4runtime.cpp
+++ b/src/qml/jsruntime/qv4runtime.cpp
@@ -461,7 +461,10 @@ Heap::Object *RuntimeHelpers::convertToObject(ExecutionEngine *engine, const Val
case Value::Boolean_Type:
return engine->newBooleanObject(value.booleanValue());
case Value::Managed_Type:
- Q_ASSERT(value.isString());
+ Q_ASSERT(value.isStringOrSymbol());
+ if (!value.isString())
+ // ### this is a symbol, which is an immutable object according to spec
+ return nullptr;
return engine->newStringObject(value.stringValue());
case Value::Integer_Type:
default: // double
@@ -488,6 +491,10 @@ Heap::String *RuntimeHelpers::convertToString(ExecutionEngine *engine, Value val
case Value::Managed_Type: {
if (value.isString())
return static_cast<const String &>(value).d();
+ if (value.isSymbol()) {
+ engine->throwTypeError(QLatin1String("Cannot convert a symbol to a string."));
+ return nullptr;
+ }
value = Primitive::fromReturnedValue(RuntimeHelpers::toPrimitive(value, hint));
Q_ASSERT(value.isPrimitive());
if (value.isString())
@@ -598,7 +605,7 @@ static Q_NEVER_INLINE ReturnedValue getElementFallback(ExecutionEngine *engine,
Q_ASSERT(!!o); // can't fail as null/undefined is covered above
}
- ScopedString name(scope, index.toString(engine));
+ ScopedStringOrSymbol name(scope, index.toStringOrSymbol(engine));
if (scope.hasException())
return Encode::undefined();
return o->get(name);
@@ -652,7 +659,7 @@ static Q_NEVER_INLINE bool setElementFallback(ExecutionEngine *engine, const Val
return o->putIndexed(idx, value);
}
- ScopedString name(scope, index.toString(engine));
+ ScopedStringOrSymbol name(scope, index.toStringOrSymbol(engine));
return o->put(name, value);
}
@@ -1033,24 +1040,30 @@ ReturnedValue Runtime::method_callName(ExecutionEngine *engine, int nameIndex, V
ReturnedValue Runtime::method_callProperty(ExecutionEngine *engine, Value *base, int nameIndex, Value *argv, int argc)
{
Scope scope(engine);
+ ScopedString name(scope, engine->currentStackFrame->v4Function->compilationUnit->runtimeStrings[nameIndex]);
+ ScopedObject lookupObject(scope, base);
- if (!base->isObject()) {
+ if (!lookupObject) {
Q_ASSERT(!base->isEmpty());
if (base->isNullOrUndefined()) {
QString message = QStringLiteral("Cannot call method '%1' of %2")
- .arg(engine->currentStackFrame->v4Function->compilationUnit->runtimeStrings[nameIndex]->toQString(),
- base->toQStringNoThrow());
+ .arg(name->toQString(), base->toQStringNoThrow());
return engine->throwTypeError(message);
}
- ScopedValue thisObject(scope, RuntimeHelpers::convertToObject(engine, *base));
- if (engine->hasException) // type error
- return Encode::undefined();
- base = thisObject;
+ if (base->isManaged()) {
+ Managed *m = static_cast<Managed *>(base);
+ lookupObject = m->internalClass()->prototype;
+ Q_ASSERT(m->internalClass()->prototype);
+ } else {
+ lookupObject = RuntimeHelpers::convertToObject(engine, *base);
+ if (engine->hasException) // type error
+ return Encode::undefined();
+ base = lookupObject;
+ }
}
- ScopedString name(scope, engine->currentStackFrame->v4Function->compilationUnit->runtimeStrings[nameIndex]);
- ScopedFunctionObject f(scope, static_cast<Object *>(base)->get(name));
+ ScopedFunctionObject f(scope, static_cast<Object *>(lookupObject)->get(name));
if (!f) {
QString error = QStringLiteral("Property '%1' of object %2 is not a function")
@@ -1080,7 +1093,7 @@ ReturnedValue Runtime::method_callElement(ExecutionEngine *engine, Value *base,
ScopedValue thisObject(scope, base->toObject(engine));
base = thisObject;
- ScopedString str(scope, index.toString(engine));
+ ScopedStringOrSymbol str(scope, index.toStringOrSymbol(engine));
if (engine->hasException)
return Encode::undefined();
diff --git a/src/qml/jsruntime/qv4string.cpp b/src/qml/jsruntime/qv4string.cpp
index 81044103eb..78377286de 100644
--- a/src/qml/jsruntime/qv4string.cpp
+++ b/src/qml/jsruntime/qv4string.cpp
@@ -138,7 +138,8 @@ void Heap::ComplexString::init(Heap::String *ref, int from, int len)
this->len = len;
}
-void Heap::String::destroy() {
+void Heap::StringOrSymbol::destroy()
+{
if (text) {
internalClass->engine->memoryManager->changeUnmanagedHeapSizeUsage(qptrdiff(-text->size) * (int)sizeof(QChar));
if (!text->ref.deref())
diff --git a/src/qml/jsruntime/qv4string_p.h b/src/qml/jsruntime/qv4string_p.h
index 4e35853f69..c48f46fe6e 100644
--- a/src/qml/jsruntime/qv4string_p.h
+++ b/src/qml/jsruntime/qv4string_p.h
@@ -68,7 +68,9 @@ struct Q_QML_PRIVATE_EXPORT StringOrSymbol : Base
{
mutable QStringData *text;
mutable Identifier identifier;
+
static void markObjects(Heap::Base *that, MarkStack *markStack);
+ void destroy();
inline QString toQString() const {
if (!text)
@@ -96,7 +98,6 @@ struct Q_QML_PRIVATE_EXPORT String : StringOrSymbol {
}
void init(const QString &text);
- void destroy();
void simplifyString() const;
int length() const;
std::size_t retainedTextSize() const {
@@ -175,6 +176,9 @@ struct Q_QML_PRIVATE_EXPORT StringOrSymbol : public Managed {
uint asArrayIndex() const;
+ inline QString toQString() const {
+ return d()->toQString();
+ }
#endif
};
diff --git a/src/qml/jsruntime/qv4stringobject.cpp b/src/qml/jsruntime/qv4stringobject.cpp
index 61176b3706..db873d32e2 100644
--- a/src/qml/jsruntime/qv4stringobject.cpp
+++ b/src/qml/jsruntime/qv4stringobject.cpp
@@ -44,6 +44,7 @@
#include "qv4objectproto_p.h"
#include <private/qv4mm_p.h>
#include "qv4scopedvalue_p.h"
+#include "qv4symbol_p.h"
#include "qv4alloca_p.h"
#include "qv4jscall_p.h"
#include <QtCore/QDateTime>
@@ -152,16 +153,18 @@ ReturnedValue StringCtor::callAsConstructor(const FunctionObject *f, const Value
value = argv[0].toString(v4);
else
value = v4->newString();
+ CHECK_EXCEPTION();
return Encode(v4->newStringObject(value));
}
ReturnedValue StringCtor::call(const FunctionObject *m, const Value *, const Value *argv, int argc)
{
ExecutionEngine *v4 = m->engine();
- if (argc)
- return argv[0].toString(v4)->asReturnedValue();
- else
+ if (!argc)
return v4->newString()->asReturnedValue();
+ if (argv[0].isSymbol())
+ return v4->newString(argv[0].symbolValue()->descriptiveString())->asReturnedValue();
+ return argv[0].toString(v4)->asReturnedValue();
}
void StringPrototype::init(ExecutionEngine *engine, Object *ctor)
@@ -169,6 +172,11 @@ void StringPrototype::init(ExecutionEngine *engine, Object *ctor)
Scope scope(engine);
ScopedObject o(scope);
+ // need to set this once again, as these were not fully defined when creating the string proto
+ Heap::InternalClass *ic = scope.engine->classes[ExecutionEngine::Class_StringObject]->changePrototype(scope.engine->objectPrototype()->d());
+ d()->internalClass.set(scope.engine, ic);
+ d()->string.set(scope.engine, scope.engine->id_empty()->d());
+
ctor->defineReadonlyProperty(engine->id_prototype(), (o = this));
ctor->defineReadonlyProperty(engine->id_length(), Primitive::fromInt32(1));
ctor->defineDefaultProperty(QStringLiteral("fromCharCode"), method_fromCharCode, 1);
diff --git a/src/qml/jsruntime/qv4symbol.cpp b/src/qml/jsruntime/qv4symbol.cpp
new file mode 100644
index 0000000000..82602c7cf2
--- /dev/null
+++ b/src/qml/jsruntime/qv4symbol.cpp
@@ -0,0 +1,116 @@
+/****************************************************************************
+**
+** 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 <qv4symbol_p.h>
+#include <qv4functionobject_p.h>
+
+using namespace QV4;
+
+DEFINE_OBJECT_VTABLE(SymbolCtor);
+DEFINE_MANAGED_VTABLE(Symbol);
+
+void Heap::Symbol::init(Heap::String *description)
+{
+ identifier = Identifier::fromHeapObject(this);
+ QString desc = description->toQString();
+ text = desc.data_ptr();
+ text->ref.ref();
+}
+
+void Heap::SymbolCtor::init(QV4::ExecutionContext *scope)
+{
+ Heap::FunctionObject::init(scope, QStringLiteral("Symbol"));
+}
+
+ReturnedValue QV4::SymbolCtor::call(const QV4::FunctionObject *f, const QV4::Value *, const QV4::Value *argv, int argc)
+{
+ Scope scope(f);
+ ScopedString s(scope);
+ if (argc)
+ s = argv[0].toString(scope.engine);
+ if (scope.hasException())
+ return Encode::undefined();
+ return f->engine()->memoryManager->alloc<Symbol>(s->d())->asReturnedValue();
+}
+
+ReturnedValue SymbolCtor::method_for(const FunctionObject *f, const Value *thisObject, const Value *argv, int argc)
+{
+// Scope scope(f);
+// ScopedValue k(s, argc ? argv[0]: Encode::undefined());
+// ScopedString key(scope, k->toString(scope.engine));
+// CHECK_EXCEPTION();
+}
+
+ReturnedValue SymbolCtor::method_keyFor(const FunctionObject *f, const Value *thisObject, const Value *argv, int argc)
+{
+}
+
+void SymbolPrototype::init(ExecutionEngine *engine, Object *ctor)
+{
+ Scope scope(engine);
+ ScopedValue v(scope);
+ ctor->defineReadonlyProperty(engine->id_prototype(), (v = this));
+
+ defineDefaultProperty(QStringLiteral("toString"), method_toString);
+ defineDefaultProperty(QStringLiteral("valueOf"), method_valueOf);
+}
+
+ReturnedValue SymbolPrototype::method_toString(const FunctionObject *f, const Value *thisObject, const Value *, int)
+{
+ ExecutionEngine *e = f->engine();
+ const Symbol *s = thisObject->as<Symbol>();
+ if (!s)
+ return e->throwTypeError();
+ return e->newString(s->descriptiveString())->asReturnedValue();
+}
+
+ReturnedValue SymbolPrototype::method_valueOf(const FunctionObject *f, const Value *thisObject, const Value *argv, int argc)
+{
+ const Symbol *s = thisObject->as<Symbol>();
+ if (!s) {
+ ExecutionEngine *e = f->engine();
+ return e->throwTypeError();
+ }
+ return s->asReturnedValue();
+}
+
+QString Symbol::descriptiveString() const
+{
+ return QLatin1String("Symbol(") + toQString() + QLatin1String(")");
+}
diff --git a/src/qml/jsruntime/qv4symbol_p.h b/src/qml/jsruntime/qv4symbol_p.h
new file mode 100644
index 0000000000..c33833a971
--- /dev/null
+++ b/src/qml/jsruntime/qv4symbol_p.h
@@ -0,0 +1,105 @@
+/****************************************************************************
+**
+** 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 QV4_SYMBOL_H
+#define QV4_SYMBOL_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 "qv4string_p.h"
+#include "qv4functionobject_p.h"
+
+QT_BEGIN_NAMESPACE
+
+
+namespace QV4 {
+
+namespace Heap {
+
+struct SymbolCtor : FunctionObject {
+ void init(QV4::ExecutionContext *scope);
+};
+
+struct Symbol : StringOrSymbol {
+ void init(Heap::String *description);
+};
+
+}
+
+struct SymbolCtor : FunctionObject
+{
+ V4_OBJECT2(SymbolCtor, FunctionObject)
+
+ static ReturnedValue call(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
+ static ReturnedValue method_for(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
+ static ReturnedValue method_keyFor(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
+};
+
+struct SymbolPrototype : Object
+{
+ V4_PROTOTYPE(objectPrototype)
+ void init(ExecutionEngine *engine, Object *ctor);
+
+ static ReturnedValue method_toString(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
+ static ReturnedValue method_valueOf(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
+};
+
+struct Symbol : StringOrSymbol
+{
+ V4_MANAGED(Symbol, StringOrSymbol)
+ Q_MANAGED_TYPE(Symbol)
+ V4_INTERNALCLASS(Symbol)
+ V4_NEEDS_DESTROY
+
+ QString descriptiveString() const;
+};
+
+}
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/qml/jsruntime/qv4value.cpp b/src/qml/jsruntime/qv4value.cpp
index c558c27521..e095a2b720 100644
--- a/src/qml/jsruntime/qv4value.cpp
+++ b/src/qml/jsruntime/qv4value.cpp
@@ -40,6 +40,7 @@
#include <qv4runtime_p.h>
#include <qv4string_p.h>
#ifndef V4_BOOTSTRAP
+#include <qv4symbol_p.h>
#include <qv4object_p.h>
#include <qv4objectproto_p.h>
#include <private/qv4mm_p.h>
@@ -145,6 +146,8 @@ QString Value::toQStringNoThrow() const
case Value::Managed_Type:
if (String *s = stringValue())
return s->toQString();
+ if (Symbol *s = symbolValue())
+ return s->descriptiveString();
{
Q_ASSERT(isObject());
Scope scope(objectValue()->engine());
diff --git a/src/qml/jsruntime/qv4value_p.h b/src/qml/jsruntime/qv4value_p.h
index 85c345f645..b89011a9a0 100644
--- a/src/qml/jsruntime/qv4value_p.h
+++ b/src/qml/jsruntime/qv4value_p.h
@@ -365,7 +365,17 @@ public:
QML_NEARLY_ALWAYS_INLINE String *stringValue() const {
if (!isString())
return nullptr;
- return reinterpret_cast<String*>(const_cast<Value *>(this));
+ return reinterpret_cast<String *>(const_cast<Value *>(this));
+ }
+ QML_NEARLY_ALWAYS_INLINE StringOrSymbol *stringOrSymbolValue() const {
+ if (!isStringOrSymbol())
+ return nullptr;
+ return reinterpret_cast<StringOrSymbol *>(const_cast<Value *>(this));
+ }
+ QML_NEARLY_ALWAYS_INLINE Symbol *symbolValue() const {
+ if (!isSymbol())
+ return nullptr;
+ return reinterpret_cast<Symbol *>(const_cast<Value *>(this));
}
QML_NEARLY_ALWAYS_INLINE Object *objectValue() const {
if (!isObject())
@@ -411,6 +421,11 @@ public:
return reinterpret_cast<Heap::String *>(m());
return toString(e, *this);
}
+ Heap::StringOrSymbol *toStringOrSymbol(ExecutionEngine *e) const {
+ if (isStringOrSymbol())
+ return reinterpret_cast<Heap::StringOrSymbol *>(m());
+ return reinterpret_cast<Heap::StringOrSymbol *>(toString(e, *this));
+ }
static Heap::String *toString(ExecutionEngine *e, Value val);
Heap::Object *toObject(ExecutionEngine *e) const {
if (isObject())
@@ -518,7 +533,9 @@ bool Value::isSymbol() const
Heap::Base *b = heapObject();
return b && b->internalClass->vtable->isStringOrSymbol && !b->internalClass->vtable->isString;
}
+
inline bool Value::isObject() const
+
{
Heap::Base *b = heapObject();
return b && b->internalClass->vtable->isObject;