diff options
author | Lars Knoll <lars.knoll@qt.io> | 2018-04-03 15:23:07 +0200 |
---|---|---|
committer | Lars Knoll <lars.knoll@qt.io> | 2018-05-02 14:18:36 +0000 |
commit | bab5e5adf578fb37402ff03f4bd5e9ed3ce4c2d2 (patch) | |
tree | 1bbc320c5594faf5d2156385088c12222b9542b8 /src/qml/jsruntime | |
parent | a6da23bb5f6004e13d22838c7db1246169874930 (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.pri | 2 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4engine.cpp | 30 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4engine_p.h | 4 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4enginebase_p.h | 2 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4global_p.h | 5 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4lookup.cpp | 7 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4managed.cpp | 7 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4managed_p.h | 1 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4objectproto.cpp | 10 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4runtime.cpp | 39 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4string.cpp | 3 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4string_p.h | 6 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4stringobject.cpp | 14 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4symbol.cpp | 116 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4symbol_p.h | 105 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4value.cpp | 3 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4value_p.h | 19 |
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; |