diff options
author | Lars Knoll <lars.knoll@qt.io> | 2018-04-08 16:43:10 +0200 |
---|---|---|
committer | Lars Knoll <lars.knoll@qt.io> | 2018-05-02 14:18:45 +0000 |
commit | 37b85ca10eef7236dbea0decd265c40fa8d0caf1 (patch) | |
tree | ed3343cd350dff8aa3be1d471c745775ae523855 /src | |
parent | 360a48aa3f5346aa7aaff741e4ef8f5dc8701f51 (diff) |
Add SymbolObject, well known symbols and fix most remaining issues
Added SymbolObject, the equivalent to StringObject which was
still missing so far. Added the predefined standard symbols,
and fixed most test failures related to symbols.
Change-Id: I1e28b439e7c4f5141b4a09bd8fb666c60691f192
Reviewed-by: Simon Hausmann <simon.hausmann@qt.io>
Diffstat (limited to 'src')
-rw-r--r-- | src/qml/jsruntime/qv4engine.cpp | 20 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4engine_p.h | 29 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4enginebase_p.h | 1 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4managed.cpp | 3 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4managed_p.h | 2 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4object.cpp | 27 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4object_p.h | 22 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4objectproto.cpp | 10 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4runtime.cpp | 9 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4runtimeapi_p.h | 2 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4symbol.cpp | 70 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4symbol_p.h | 22 |
12 files changed, 171 insertions, 46 deletions
diff --git a/src/qml/jsruntime/qv4engine.cpp b/src/qml/jsruntime/qv4engine.cpp index 87ae0e09d7..22dc984b4a 100644 --- a/src/qml/jsruntime/qv4engine.cpp +++ b/src/qml/jsruntime/qv4engine.cpp @@ -194,6 +194,7 @@ ExecutionEngine::ExecutionEngine(QJSEngine *jsEngine) typedArrayPrototype = static_cast<Object *>(jsAlloca(NTypedArrayTypes)); typedArrayCtors = static_cast<FunctionObject *>(jsAlloca(NTypedArrayTypes)); jsStrings = jsAlloca(NJSStrings); + jsSymbols = jsAlloca(NJSSymbols); // set up stack limits jsStackLimit = jsStackBase + JSStackLimit/sizeof(Value); @@ -264,6 +265,18 @@ ExecutionEngine::ExecutionEngine(QJSEngine *jsEngine) jsStrings[String_buffer] = newIdentifier(QStringLiteral("buffer")); jsStrings[String_lastIndex] = newIdentifier(QStringLiteral("lastIndex")); + jsSymbols[Symbol_hasInstance] = Symbol::create(this, QStringLiteral("@Symbol.hasInstance")); + jsSymbols[Symbol_isConcatSpreadable] = Symbol::create(this, QStringLiteral("@Symbol.isConcatSpreadable")); + jsSymbols[Symbol_iterator] = Symbol::create(this, QStringLiteral("@Symbol.iterator")); + jsSymbols[Symbol_match] = Symbol::create(this, QStringLiteral("@Symbol.match")); + jsSymbols[Symbol_replace] = Symbol::create(this, QStringLiteral("@Symbol.replace")); + jsSymbols[Symbol_search] = Symbol::create(this, QStringLiteral("@Symbol.search")); + jsSymbols[Symbol_species] = Symbol::create(this, QStringLiteral("@Symbol.species")); + jsSymbols[Symbol_split] = Symbol::create(this, QStringLiteral("@Symbol.split")); + jsSymbols[Symbol_toPrimitive] = Symbol::create(this, QStringLiteral("@Symbol.toPrimitive")); + jsSymbols[Symbol_toStringTag] = Symbol::create(this, QStringLiteral("@Symbol.toStringTag")); + jsSymbols[Symbol_unscopables] = Symbol::create(this, QStringLiteral("@Symbol.unscopables")); + ic = newInternalClass(ArrayPrototype::staticVTable(), objectPrototype()); Q_ASSERT(ic->d()->prototype); ic = ic->addMember(id_length()->identifier(), Attr_NotConfigurable|Attr_NotEnumerable); @@ -289,6 +302,8 @@ ExecutionEngine::ExecutionEngine(QJSEngine *jsEngine) classes[Class_StringObject] = ic->changePrototype(stringPrototype()->d()); Q_ASSERT(classes[Class_StringObject]->find(id_length()->identifier()) == Heap::StringObject::LengthPropertyIndex); + classes[Class_SymbolObject] = newInternalClass(QV4::SymbolObject::staticVTable(), symbolPrototype()); + jsObjects[NumberProto] = memoryManager->allocate<NumberPrototype>(); jsObjects[BooleanProto] = memoryManager->allocate<BooleanPrototype>(); jsObjects[DateProto] = memoryManager->allocate<DatePrototype>(); @@ -593,6 +608,11 @@ Heap::Object *ExecutionEngine::newStringObject(const String *string) return memoryManager->allocate<StringObject>(string); } +Heap::Object *ExecutionEngine::newSymbolObject(const Symbol *symbol) +{ + return memoryManager->allocObject<SymbolObject>(classes[Class_SymbolObject], symbol); +} + Heap::Object *ExecutionEngine::newNumberObject(double value) { return memoryManager->allocate<NumberObject>(value); diff --git a/src/qml/jsruntime/qv4engine_p.h b/src/qml/jsruntime/qv4engine_p.h index 362d95b56a..30e589919c 100644 --- a/src/qml/jsruntime/qv4engine_p.h +++ b/src/qml/jsruntime/qv4engine_p.h @@ -312,6 +312,22 @@ public: }; Value *jsStrings; + enum JSSymbols { + Symbol_hasInstance, + Symbol_isConcatSpreadable, + Symbol_iterator, + Symbol_match, + Symbol_replace, + Symbol_search, + Symbol_species, + Symbol_split, + Symbol_toPrimitive, + Symbol_toStringTag, + Symbol_unscopables, + NJSSymbols + }; + Value *jsSymbols; + String *id_empty() const { return reinterpret_cast<String *>(jsStrings + String_Empty); } String *id_undefined() const { return reinterpret_cast<String *>(jsStrings + String_undefined); } String *id_null() const { return reinterpret_cast<String *>(jsStrings + String_null); } @@ -350,6 +366,18 @@ public: String *id_buffer() const { return reinterpret_cast<String *>(jsStrings + String_buffer); } String *id_lastIndex() const { return reinterpret_cast<String *>(jsStrings + String_lastIndex); } + Symbol *symbol_hasInstance() const { return reinterpret_cast<Symbol *>(jsSymbols + Symbol_hasInstance); } + Symbol *symbol_isConcatSpreadable() const { return reinterpret_cast<Symbol *>(jsSymbols + Symbol_isConcatSpreadable); } + Symbol *symbol_iterator() const { return reinterpret_cast<Symbol *>(jsSymbols + Symbol_iterator); } + Symbol *symbol_match() const { return reinterpret_cast<Symbol *>(jsSymbols + Symbol_match); } + Symbol *symbol_replace() const { return reinterpret_cast<Symbol *>(jsSymbols + Symbol_replace); } + Symbol *symbol_search() const { return reinterpret_cast<Symbol *>(jsSymbols + Symbol_search); } + Symbol *symbol_species() const { return reinterpret_cast<Symbol *>(jsSymbols + Symbol_species); } + Symbol *symbol_split() const { return reinterpret_cast<Symbol *>(jsSymbols + Symbol_split); } + Symbol *symbol_toPrimitive() const { return reinterpret_cast<Symbol *>(jsSymbols + Symbol_toPrimitive); } + Symbol *symbol_toStringTag() const { return reinterpret_cast<Symbol *>(jsSymbols + Symbol_toStringTag); } + Symbol *symbol_unscopables() const { return reinterpret_cast<Symbol *>(jsSymbols + Symbol_unscopables); } + #ifndef V4_BOOTSTRAP QIntrusiveList<CompiledData::CompilationUnit, &CompiledData::CompilationUnit::nextCompilationUnit> compilationUnits; #endif @@ -416,6 +444,7 @@ public: Heap::String *newIdentifier(const QString &text); Heap::Object *newStringObject(const String *string); + Heap::Object *newSymbolObject(const Symbol *symbol); Heap::Object *newNumberObject(double value); Heap::Object *newBooleanObject(bool b); diff --git a/src/qml/jsruntime/qv4enginebase_p.h b/src/qml/jsruntime/qv4enginebase_p.h index 085e44a913..d1257b6248 100644 --- a/src/qml/jsruntime/qv4enginebase_p.h +++ b/src/qml/jsruntime/qv4enginebase_p.h @@ -101,6 +101,7 @@ struct Q_QML_EXPORT EngineBase { Class_ArrayObject, Class_FunctionObject, Class_StringObject, + Class_SymbolObject, Class_ScriptFunction, Class_ObjectProto, Class_RegExp, diff --git a/src/qml/jsruntime/qv4managed.cpp b/src/qml/jsruntime/qv4managed.cpp index 6ed2a9d716..a2e9deb854 100644 --- a/src/qml/jsruntime/qv4managed.cpp +++ b/src/qml/jsruntime/qv4managed.cpp @@ -97,6 +97,9 @@ QString Managed::className() const case Type_StringObject: s = "String"; break; + case Type_SymbolObject: + s = "Symbol"; + break; case Type_DateObject: s = "Date"; break; diff --git a/src/qml/jsruntime/qv4managed_p.h b/src/qml/jsruntime/qv4managed_p.h index 7ef5fd4ab8..5a032ba401 100644 --- a/src/qml/jsruntime/qv4managed_p.h +++ b/src/qml/jsruntime/qv4managed_p.h @@ -188,6 +188,7 @@ public: Type_BooleanObject, Type_NumberObject, Type_StringObject, + Type_SymbolObject, Type_DateObject, Type_RegExpObject, Type_ErrorObject, @@ -212,6 +213,7 @@ public: bool isArrayObject() const { return d()->internalClass->vtable->type == Type_ArrayObject; } bool isStringObject() const { return d()->internalClass->vtable->type == Type_StringObject; } + bool isSymbolObject() const { return d()->internalClass->vtable->type == Type_SymbolObject; } QString className() const; diff --git a/src/qml/jsruntime/qv4object.cpp b/src/qml/jsruntime/qv4object.cpp index a896caaecb..261e99b168 100644 --- a/src/qml/jsruntime/qv4object.cpp +++ b/src/qml/jsruntime/qv4object.cpp @@ -156,7 +156,8 @@ void Object::defineDefaultProperty(const QString &name, const Value &value) defineDefaultProperty(s, value); } -void Object::defineDefaultProperty(const QString &name, ReturnedValue (*code)(const FunctionObject *, const Value *thisObject, const Value *argv, int argc), int argumentCount) +void Object::defineDefaultProperty(const QString &name, ReturnedValue (*code)(const FunctionObject *, const Value *thisObject, const Value *argv, int argc), + int argumentCount, PropertyAttributes attributes) { ExecutionEngine *e = engine(); Scope scope(e); @@ -164,17 +165,21 @@ void Object::defineDefaultProperty(const QString &name, ReturnedValue (*code)(co ExecutionContext *global = e->rootContext(); ScopedFunctionObject function(scope, FunctionObject::createBuiltinFunction(global, s, code)); function->defineReadonlyConfigurableProperty(e->id_length(), Primitive::fromInt32(argumentCount)); - defineDefaultProperty(s, function); + defineDefaultProperty(s, function, attributes); } -void Object::defineDefaultProperty(String *name, ReturnedValue (*code)(const FunctionObject *, const Value *thisObject, const Value *argv, int argc), int argumentCount) +void Object::defineDefaultProperty(StringOrSymbol *nameOrSymbol, ReturnedValue (*code)(const FunctionObject *, const Value *thisObject, const Value *argv, int argc), + int argumentCount, PropertyAttributes attributes) { ExecutionEngine *e = engine(); Scope scope(e); ExecutionContext *global = e->rootContext(); + ScopedString name(scope, nameOrSymbol); + if (!name) + name = e->newString(QChar::fromLatin1('[') + nameOrSymbol->toQString().midRef(1) + QChar::fromLatin1(']')); ScopedFunctionObject function(scope, FunctionObject::createBuiltinFunction(global, name, code)); function->defineReadonlyConfigurableProperty(e->id_length(), Primitive::fromInt32(argumentCount)); - defineDefaultProperty(name, function); + defineDefaultProperty(nameOrSymbol, function, attributes); } void Object::defineAccessorProperty(const QString &name, ReturnedValue (*getter)(const FunctionObject *, const Value *, const Value *, int), @@ -221,7 +226,7 @@ void Object::defineReadonlyConfigurableProperty(const QString &name, const Value defineReadonlyConfigurableProperty(s, value); } -void Object::defineReadonlyConfigurableProperty(String *name, const Value &value) +void Object::defineReadonlyConfigurableProperty(StringOrSymbol *name, const Value &value) { insertMember(name, value, Attr_ReadOnly_ButConfigurable); } @@ -261,7 +266,7 @@ void Object::insertMember(StringOrSymbol *s, const Property *p, PropertyAttribut } // Section 8.12.1 -void Object::getOwnProperty(String *name, PropertyAttributes *attrs, Property *p) +void Object::getOwnProperty(StringOrSymbol *name, PropertyAttributes *attrs, Property *p) { uint idx = name->asArrayIndex(); if (idx != UINT_MAX) @@ -351,7 +356,7 @@ PropertyIndex Object::getValueOrSetter(uint index, PropertyAttributes *attrs) return { nullptr, 0 }; } -bool Object::hasProperty(String *name) const +bool Object::hasProperty(StringOrSymbol *name) const { uint idx = name->asArrayIndex(); if (idx != UINT_MAX) @@ -383,7 +388,7 @@ bool Object::hasProperty(uint index) const return false; } -bool Object::hasOwnProperty(String *name) const +bool Object::hasOwnProperty(StringOrSymbol *name) const { uint idx = name->asArrayIndex(); if (idx != UINT_MAX) @@ -802,7 +807,7 @@ bool Object::internalDeleteIndexedProperty(uint index) } // Section 8.12.9 -bool Object::__defineOwnProperty__(ExecutionEngine *engine, String *name, const Property *p, PropertyAttributes attrs) +bool Object::__defineOwnProperty__(ExecutionEngine *engine, StringOrSymbol *name, const Property *p, PropertyAttributes attrs) { uint idx = name->asArrayIndex(); if (idx != UINT_MAX) @@ -813,7 +818,7 @@ bool Object::__defineOwnProperty__(ExecutionEngine *engine, String *name, const uint memberIndex; - if (isArrayObject() && name->equals(engine->id_length())) { + if (isArrayObject() && name->identifier() == engine->id_length()->identifier()) { Q_ASSERT(Heap::ArrayObject::LengthPropertyIndex == internalClass()->find(engine->id_length()->identifier())); ScopedProperty lp(scope); PropertyAttributes cattrs; @@ -904,7 +909,7 @@ bool Object::defineOwnProperty2(ExecutionEngine *engine, uint index, const Prope return __defineOwnProperty__(engine, index, nullptr, p, attrs); } -bool Object::__defineOwnProperty__(ExecutionEngine *engine, uint index, String *member, const Property *p, PropertyAttributes attrs) +bool Object::__defineOwnProperty__(ExecutionEngine *engine, uint index, StringOrSymbol *member, const Property *p, PropertyAttributes attrs) { // clause 5 if (attrs.isEmpty()) diff --git a/src/qml/jsruntime/qv4object_p.h b/src/qml/jsruntime/qv4object_p.h index 5d46e0e74b..2f8a73de68 100644 --- a/src/qml/jsruntime/qv4object_p.h +++ b/src/qml/jsruntime/qv4object_p.h @@ -240,20 +240,20 @@ struct Q_QML_EXPORT Object: Managed { Heap::Object *prototype() const { return d()->prototype(); } bool setPrototype(Object *proto); - void getOwnProperty(String *name, PropertyAttributes *attrs, Property *p = nullptr); + void getOwnProperty(StringOrSymbol *name, PropertyAttributes *attrs, Property *p = nullptr); void getOwnProperty(uint index, PropertyAttributes *attrs, Property *p = nullptr); PropertyIndex getValueOrSetter(StringOrSymbol *name, PropertyAttributes *attrs); PropertyIndex getValueOrSetter(uint index, PropertyAttributes *attrs); - bool hasProperty(String *name) const; + bool hasProperty(StringOrSymbol *name) const; bool hasProperty(uint index) const; - bool hasOwnProperty(String *name) const; + bool hasOwnProperty(StringOrSymbol *name) const; bool hasOwnProperty(uint index) const; - bool __defineOwnProperty__(ExecutionEngine *engine, uint index, String *member, const Property *p, PropertyAttributes attrs); - bool __defineOwnProperty__(ExecutionEngine *engine, String *name, const Property *p, PropertyAttributes attrs); + bool __defineOwnProperty__(ExecutionEngine *engine, uint index, StringOrSymbol *member, const Property *p, PropertyAttributes attrs); + bool __defineOwnProperty__(ExecutionEngine *engine, StringOrSymbol *name, const Property *p, PropertyAttributes attrs); bool __defineOwnProperty__(ExecutionEngine *engine, uint index, const Property *p, PropertyAttributes attrs); bool __defineOwnProperty__(ExecutionEngine *engine, const QString &name, const Property *p, PropertyAttributes attrs); bool defineOwnProperty2(ExecutionEngine *engine, uint index, const Property *p, PropertyAttributes attrs); @@ -271,12 +271,14 @@ struct Q_QML_EXPORT Object: Managed { bool putValue(uint memberIndex, const Value &value); /* The spec default: Writable: true, Enumerable: false, Configurable: true */ - void defineDefaultProperty(String *name, const Value &value) { - insertMember(name, value, Attr_Data|Attr_NotEnumerable); + void defineDefaultProperty(StringOrSymbol *name, const Value &value, PropertyAttributes attributes = Attr_Data|Attr_NotEnumerable) { + insertMember(name, value, attributes); } void defineDefaultProperty(const QString &name, const Value &value); - void defineDefaultProperty(const QString &name, ReturnedValue (*code)(const FunctionObject *, const Value *thisObject, const Value *argv, int argc), int argumentCount = 0); - void defineDefaultProperty(String *name, ReturnedValue (*code)(const FunctionObject *, const Value *thisObject, const Value *argv, int argc), int argumentCount = 0); + void defineDefaultProperty(const QString &name, ReturnedValue (*code)(const FunctionObject *, const Value *thisObject, const Value *argv, int argc), + int argumentCount = 0, PropertyAttributes attributes = Attr_Data|Attr_NotEnumerable); + void defineDefaultProperty(StringOrSymbol *name, ReturnedValue (*code)(const FunctionObject *, const Value *thisObject, const Value *argv, int argc), + int argumentCount = 0, PropertyAttributes attributes = Attr_Data|Attr_NotEnumerable); void defineAccessorProperty(const QString &name, ReturnedValue (*getter)(const FunctionObject *, const Value *, const Value *, int), ReturnedValue (*setter)(const FunctionObject *, const Value *, const Value *, int)); void defineAccessorProperty(String *name, ReturnedValue (*getter)(const FunctionObject *, const Value *, const Value *, int), @@ -287,7 +289,7 @@ struct Q_QML_EXPORT Object: Managed { /* Fixed: Writable: false, Enumerable: false, Configurable: true */ void defineReadonlyConfigurableProperty(const QString &name, const Value &value); - void defineReadonlyConfigurableProperty(String *name, const Value &value); + void defineReadonlyConfigurableProperty(StringOrSymbol *name, const Value &value); void insertMember(StringOrSymbol *s, const Value &v, PropertyAttributes attributes = Attr_Data) { Scope scope(engine()); diff --git a/src/qml/jsruntime/qv4objectproto.cpp b/src/qml/jsruntime/qv4objectproto.cpp index 94917a45f6..1cf6ff4ed8 100644 --- a/src/qml/jsruntime/qv4objectproto.cpp +++ b/src/qml/jsruntime/qv4objectproto.cpp @@ -154,7 +154,7 @@ ReturnedValue ObjectPrototype::method_getOwnPropertyDescriptor(const FunctionObj static_cast<ArgumentsObject *>(O.getPointer())->fullyCreate(); ScopedValue v(scope, argc > 1 ? argv[1] : Primitive::undefinedValue()); - ScopedString name(scope, v->toString(scope.engine)); + ScopedStringOrSymbol name(scope, v->toStringOrSymbol(scope.engine)); if (scope.engine->hasException) return QV4::Encode::undefined(); @@ -255,7 +255,7 @@ ReturnedValue ObjectPrototype::method_defineProperty(const FunctionObject *b, co return scope.engine->throwTypeError(); ScopedObject O(scope, argv[0]); - ScopedString name(scope, argc > 1 ? argv[1] : Primitive::undefinedValue(), ScopedString::Convert); + ScopedStringOrSymbol name(scope, (argc > 1 ? argv[1] : Primitive::undefinedValue()).toStringOrSymbol(scope.engine)); if (scope.engine->hasException) return QV4::Encode::undefined(); @@ -287,7 +287,7 @@ ReturnedValue ObjectPrototype::method_defineProperties(const FunctionObject *b, ScopedValue val(scope); ObjectIterator it(scope, o, ObjectIterator::EnumerableOnly); - ScopedString name(scope); + ScopedStringOrSymbol name(scope); ScopedProperty pd(scope); ScopedProperty n(scope); while (1) { @@ -518,7 +518,7 @@ 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); - ScopedString P(scope, argc ? argv[0] : Primitive::undefinedValue(), ScopedString::Convert); + ScopedStringOrSymbol P(scope, (argc ? argv[0] : Primitive::undefinedValue()).toStringOrSymbol(scope.engine)); if (scope.engine->hasException) return QV4::Encode::undefined(); ScopedObject O(scope, thisObject->toObject(scope.engine)); @@ -552,7 +552,7 @@ 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); - ScopedString p(scope, argc ? argv[0] : Primitive::undefinedValue(), ScopedString::Convert); + ScopedStringOrSymbol p(scope, (argc ? argv[0] : Primitive::undefinedValue()).toStringOrSymbol(scope.engine)); if (scope.engine->hasException) return QV4::Encode::undefined(); diff --git a/src/qml/jsruntime/qv4runtime.cpp b/src/qml/jsruntime/qv4runtime.cpp index 18e5f29c09..1237edcdc6 100644 --- a/src/qml/jsruntime/qv4runtime.cpp +++ b/src/qml/jsruntime/qv4runtime.cpp @@ -327,7 +327,7 @@ bool Runtime::method_deleteElement(ExecutionEngine *engine, const Value &base, c return o->deleteIndexedProperty(n); } - ScopedString name(scope, index.toString(engine)); + ScopedStringOrSymbol name(scope, index.toStringOrSymbol(engine)); return method_deleteMemberString(engine, base, name); } @@ -338,7 +338,7 @@ bool Runtime::method_deleteMember(ExecutionEngine *engine, const Value &base, in return method_deleteMemberString(engine, base, name); } -bool Runtime::method_deleteMemberString(ExecutionEngine *engine, const Value &base, String *name) +bool Runtime::method_deleteMemberString(ExecutionEngine *engine, const Value &base, StringOrSymbol *name) { Scope scope(engine); ScopedObject obj(scope, base.toObject(engine)); @@ -371,7 +371,7 @@ QV4::ReturnedValue Runtime::method_in(ExecutionEngine *engine, const Value &left if (!ro) return engine->throwTypeError(); Scope scope(engine); - ScopedString s(scope, left.toString(engine)); + ScopedStringOrSymbol s(scope, left.toStringOrSymbol(engine)); if (scope.hasException()) return Encode::undefined(); bool r = ro->hasProperty(s); @@ -463,8 +463,7 @@ Heap::Object *RuntimeHelpers::convertToObject(ExecutionEngine *engine, const Val case Value::Managed_Type: Q_ASSERT(value.isStringOrSymbol()); if (!value.isString()) - // ### this is a symbol, which is an immutable object according to spec - return nullptr; + return engine->newSymbolObject(value.symbolValue()); return engine->newStringObject(value.stringValue()); case Value::Integer_Type: default: // double diff --git a/src/qml/jsruntime/qv4runtimeapi_p.h b/src/qml/jsruntime/qv4runtimeapi_p.h index a1a7bd9ed0..ac456283cb 100644 --- a/src/qml/jsruntime/qv4runtimeapi_p.h +++ b/src/qml/jsruntime/qv4runtimeapi_p.h @@ -119,7 +119,7 @@ struct ExceptionCheck<void (*)(QV4::NoThrowEngine *, A, B, C)> { /* delete */ \ F(bool, deleteElement, (ExecutionEngine *engine, const Value &base, const Value &index)) \ F(bool, deleteMember, (ExecutionEngine *engine, const Value &base, int nameIndex)) \ - F(bool, deleteMemberString, (ExecutionEngine *engine, const Value &base, String *name)) \ + F(bool, deleteMemberString, (ExecutionEngine *engine, const Value &base, StringOrSymbol *name)) \ F(bool, deleteName, (ExecutionEngine *engine, int nameIndex)) \ \ /* exceptions & scopes */ \ diff --git a/src/qml/jsruntime/qv4symbol.cpp b/src/qml/jsruntime/qv4symbol.cpp index 86d727ba07..7bb33dce69 100644 --- a/src/qml/jsruntime/qv4symbol.cpp +++ b/src/qml/jsruntime/qv4symbol.cpp @@ -45,6 +45,7 @@ using namespace QV4; DEFINE_OBJECT_VTABLE(SymbolCtor); DEFINE_MANAGED_VTABLE(Symbol); +DEFINE_OBJECT_VTABLE(SymbolObject); void Heap::Symbol::init(const QString &s) { @@ -60,15 +61,22 @@ void Heap::SymbolCtor::init(QV4::ExecutionContext *scope) Heap::FunctionObject::init(scope, QStringLiteral("Symbol")); } +void Heap::SymbolObject::init(const QV4::Symbol *s) +{ + Object::init(); + symbol.set(internalClass->engine, s->d()); +} + 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(); - QString desc = QLatin1Char('@') + s->toQString(); + QString desc = QChar::fromLatin1('@'); + if (argc && !argv[0].isUndefined()) { + ScopedString s(scope, argv[0].toString(scope.engine)); + if (scope.hasException()) + return Encode::undefined(); + desc += s->toQString(); + } return Symbol::create(scope.engine, desc)->asReturnedValue(); } @@ -101,33 +109,67 @@ void SymbolPrototype::init(ExecutionEngine *engine, Object *ctor) Scope scope(engine); ScopedValue v(scope); ctor->defineReadonlyProperty(engine->id_prototype(), (v = this)); + ctor->defineReadonlyConfigurableProperty(engine->id_length(), Primitive::fromInt32(0)); ctor->defineDefaultProperty(QStringLiteral("for"), SymbolCtor::method_for, 1); ctor->defineDefaultProperty(QStringLiteral("keyFor"), SymbolCtor::method_keyFor, 1); + ctor->defineReadonlyProperty(QStringLiteral("hasInstance"), *engine->symbol_hasInstance()); + ctor->defineReadonlyProperty(QStringLiteral("isConcatSpreadable"), *engine->symbol_isConcatSpreadable()); + ctor->defineReadonlyProperty(QStringLiteral("iterator"), *engine->symbol_iterator()); + ctor->defineReadonlyProperty(QStringLiteral("match"), *engine->symbol_match()); + ctor->defineReadonlyProperty(QStringLiteral("replace"), *engine->symbol_replace()); + ctor->defineReadonlyProperty(QStringLiteral("search"), *engine->symbol_search()); + ctor->defineReadonlyProperty(QStringLiteral("species"), *engine->symbol_species()); + ctor->defineReadonlyProperty(QStringLiteral("split"), *engine->symbol_split()); + ctor->defineReadonlyProperty(QStringLiteral("toPrimitive"), *engine->symbol_toPrimitive()); + ctor->defineReadonlyProperty(QStringLiteral("toStringTag"), *engine->symbol_toStringTag()); + ctor->defineReadonlyProperty(QStringLiteral("unscopables"), *engine->symbol_unscopables()); + defineDefaultProperty(QStringLiteral("constructor"), (v = ctor)); defineDefaultProperty(QStringLiteral("toString"), method_toString); defineDefaultProperty(QStringLiteral("valueOf"), method_valueOf); + defineDefaultProperty(engine->symbol_toPrimitive(), method_symbolToPrimitive, 1, Attr_ReadOnly_ButConfigurable); + + v = engine->newString(QStringLiteral("Symbol")); + defineReadonlyConfigurableProperty(engine->symbol_toStringTag(), v); + } 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(); + Scope scope(f); + Scoped<Symbol> s(scope, thisObject->as<Symbol>()); + if (!s) { + if (const SymbolObject *o = thisObject->as<SymbolObject>()) + s = o->d()->symbol; + else + return scope.engine->throwTypeError(); + } + return scope.engine->newString(s->descriptiveString())->asReturnedValue(); } ReturnedValue SymbolPrototype::method_valueOf(const FunctionObject *f, const Value *thisObject, const Value *, int) { - const Symbol *s = thisObject->as<Symbol>(); + Scope scope(f); + Scoped<Symbol> s(scope, thisObject->as<Symbol>()); if (!s) { - ExecutionEngine *e = f->engine(); - return e->throwTypeError(); + if (const SymbolObject *o = thisObject->as<SymbolObject>()) + s = o->d()->symbol; + else + return scope.engine->throwTypeError(); } return s->asReturnedValue(); } +ReturnedValue SymbolPrototype::method_symbolToPrimitive(const FunctionObject *f, const Value *thisObject, const Value *, int) +{ + if (thisObject->isSymbol()) + return thisObject->asReturnedValue(); + if (const SymbolObject *o = thisObject->as<SymbolObject>()) + return o->d()->symbol->asReturnedValue(); + return f->engine()->throwTypeError(); +} + Heap::Symbol *Symbol::create(ExecutionEngine *e, const QString &s) { Q_ASSERT(s.at(0) == QLatin1Char('@')); diff --git a/src/qml/jsruntime/qv4symbol_p.h b/src/qml/jsruntime/qv4symbol_p.h index 6ff60d22db..3cf6bc5dde 100644 --- a/src/qml/jsruntime/qv4symbol_p.h +++ b/src/qml/jsruntime/qv4symbol_p.h @@ -68,6 +68,14 @@ struct Symbol : StringOrSymbol { void init(const QString &s); }; +#define SymbolObjectMembers(class, Member) \ + Member(class, Pointer, Symbol *, symbol) + +DECLARE_HEAP_OBJECT(SymbolObject, Object) { + DECLARE_MARKOBJECTS(SymbolObject); + void init(const QV4::Symbol *s); +}; + } struct SymbolCtor : FunctionObject @@ -86,6 +94,8 @@ struct SymbolPrototype : Object 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); + + static ReturnedValue method_symbolToPrimitive(const FunctionObject *, const Value *thisObject, const Value *argv, int argc); }; struct Symbol : StringOrSymbol @@ -100,6 +110,18 @@ struct Symbol : StringOrSymbol QString descriptiveString() const; }; +struct SymbolObject : Object +{ + V4_OBJECT2(SymbolObject, Object) + Q_MANAGED_TYPE(SymbolObject) + V4_INTERNALCLASS(SymbolObject) + V4_PROTOTYPE(symbolPrototype) + + static bool put(Managed *, StringOrSymbol *, const Value &) { return false; } + static bool putIndexed(Managed *, uint, const Value &) { return false; } + +}; + } QT_END_NAMESPACE |