diff options
author | Christian Kamm <[email protected]> | 2011-11-21 14:51:03 +0100 |
---|---|---|
committer | Christian Kamm <[email protected]> | 2011-11-25 10:36:42 +0100 |
commit | 097850c842ce872d31716ddb528ebfad346475da (patch) | |
tree | fcbf558b7c37f1f4bb2bb3ea0bcf398d5a7f2b32 /src/libs | |
parent | e2b0835b58aefdab91edda097c1180dae08058f6 (diff) |
QmlJS: Speed up ValueOwner construction.
* Don't build all default values (including the global object)
separately for each ValueOwner instance.
* Instead, keep all global, immutable values in a single, shared
instance.
While refactoring, some cases where we *modified* the global object had
to be removed:
* C++ context properties no longer get injected into the global object,
instead they now have their own scope just above the global one.
* The Qt object's prototype no longer gets modified in Link. Instead,
it's now a reference to the "Qt" object provided in a qmltypes file.
* The whole concept of a function 'Activation' that could potentially
affect the global object was removed.
Change-Id: Id382faf965efa747fcc7a9b0bc2c90429d84d61b
Reviewed-by: Leandro Melo <[email protected]>
Diffstat (limited to 'src/libs')
-rw-r--r-- | src/libs/qmljs/qmljsevaluate.cpp | 8 | ||||
-rw-r--r-- | src/libs/qmljs/qmljsinterpreter.cpp | 147 | ||||
-rw-r--r-- | src/libs/qmljs/qmljsinterpreter.h | 46 | ||||
-rw-r--r-- | src/libs/qmljs/qmljslink.cpp | 12 | ||||
-rw-r--r-- | src/libs/qmljs/qmljsscopechain.cpp | 16 | ||||
-rw-r--r-- | src/libs/qmljs/qmljsscopechain.h | 4 | ||||
-rw-r--r-- | src/libs/qmljs/qmljsvalueowner.cpp | 838 | ||||
-rw-r--r-- | src/libs/qmljs/qmljsvalueowner.h | 73 |
8 files changed, 412 insertions, 732 deletions
diff --git a/src/libs/qmljs/qmljsevaluate.cpp b/src/libs/qmljs/qmljsevaluate.cpp index d5eddd78464..69a1abe22d6 100644 --- a/src/libs/qmljs/qmljsevaluate.cpp +++ b/src/libs/qmljs/qmljsevaluate.cpp @@ -273,13 +273,13 @@ bool Evaluate::visit(AST::NumericLiteral *) bool Evaluate::visit(AST::RegExpLiteral *) { - _result = _valueOwner->regexpCtor()->construct(); + _result = _valueOwner->regexpCtor()->returnValue(); return false; } bool Evaluate::visit(AST::ArrayLiteral *) { - _result = _valueOwner->arrayCtor()->construct(); + _result = _valueOwner->arrayCtor()->returnValue(); return false; } @@ -347,7 +347,7 @@ bool Evaluate::visit(AST::FieldMemberExpression *ast) bool Evaluate::visit(AST::NewMemberExpression *ast) { if (const FunctionValue *ctor = value_cast<FunctionValue>(value(ast->base))) { - _result = ctor->construct(); + _result = ctor->returnValue(); } return false; } @@ -355,7 +355,7 @@ bool Evaluate::visit(AST::NewMemberExpression *ast) bool Evaluate::visit(AST::NewExpression *ast) { if (const FunctionValue *ctor = value_cast<FunctionValue>(value(ast->expression))) { - _result = ctor->construct(); + _result = ctor->returnValue(); } return false; } diff --git a/src/libs/qmljs/qmljsinterpreter.cpp b/src/libs/qmljs/qmljsinterpreter.cpp index b231815d6d7..746bbb0f01d 100644 --- a/src/libs/qmljs/qmljsinterpreter.cpp +++ b/src/libs/qmljs/qmljsinterpreter.cpp @@ -169,11 +169,6 @@ public: { return false; } - - virtual const Value *invoke(const Activation *) const - { - return valueOwner()->unknownValue(); - } }; } // end of anonymous namespace @@ -1115,105 +1110,18 @@ QList<const ObjectValue *> PrototypeIterator::all() return m_prototypes; } -Activation::Activation(Context *parentContext) - : _thisObject(0), - _calledAsFunction(true), - _parentContext(parentContext) -{ -} - -Activation::~Activation() -{ -} - -Context *Activation::parentContext() const -{ - return _parentContext; -} - -Context *Activation::context() const -{ - // ### FIXME: Real context for activations. - return 0; -} - -bool Activation::calledAsConstructor() const -{ - return ! _calledAsFunction; -} - -void Activation::setCalledAsConstructor(bool calledAsConstructor) -{ - _calledAsFunction = ! calledAsConstructor; -} - -bool Activation::calledAsFunction() const -{ - return _calledAsFunction; -} - -void Activation::setCalledAsFunction(bool calledAsFunction) -{ - _calledAsFunction = calledAsFunction; -} - -ObjectValue *Activation::thisObject() const -{ - return _thisObject; -} - -void Activation::setThisObject(ObjectValue *thisObject) -{ - _thisObject = thisObject; -} - -ValueList Activation::arguments() const -{ - return _arguments; -} - -void Activation::setArguments(const ValueList &arguments) -{ - _arguments = arguments; -} - FunctionValue::FunctionValue(ValueOwner *valueOwner) : ObjectValue(valueOwner) { + setClassName("Function"); setMember(QLatin1String("length"), valueOwner->numberValue()); + setPrototype(valueOwner->functionPrototype()); } FunctionValue::~FunctionValue() { } -const Value *FunctionValue::construct(const ValueList &actuals) const -{ - Activation activation; - activation.setCalledAsConstructor(true); - activation.setThisObject(valueOwner()->newObject()); - activation.setArguments(actuals); - return invoke(&activation); -} - -const Value *FunctionValue::call(const ValueList &actuals) const -{ - Activation activation; - activation.setCalledAsFunction(true); - activation.setThisObject(valueOwner()->globalObject()); // ### FIXME: it should be `null' - activation.setArguments(actuals); - return invoke(&activation); -} - -const Value *FunctionValue::call(const ObjectValue *thisObject, const ValueList &actuals) const -{ - Activation activation; - activation.setCalledAsFunction(true); - activation.setThisObject(const_cast<ObjectValue *>(thisObject)); // ### FIXME: remove the const_cast - activation.setArguments(actuals); - return invoke(&activation); -} - const Value *FunctionValue::returnValue() const { return valueOwner()->unknownValue(); @@ -1244,11 +1152,6 @@ bool FunctionValue::isVariadic() const return true; } -const Value *FunctionValue::invoke(const Activation *activation) const -{ - return activation->thisObject(); // ### FIXME: it should return undefined -} - const FunctionValue *FunctionValue::asFunctionValue() const { return this; @@ -1265,7 +1168,6 @@ Function::Function(ValueOwner *valueOwner) , _optionalNamedArgumentCount(0) , _isVariadic(false) { - setClassName("Function"); } Function::~Function() @@ -1327,11 +1229,6 @@ QString Function::argumentName(int index) const return FunctionValue::argumentName(index); } -const Value *Function::invoke(const Activation *) const -{ - return _returnValue; -} - bool Function::isVariadic() const { return _isVariadic; @@ -1394,7 +1291,9 @@ void CppQmlTypesLoader::parseQmlTypeDescriptions(const QByteArray &xml, } CppQmlTypes::CppQmlTypes(ValueOwner *valueOwner) - : _valueOwner(valueOwner) + : _cppContextProperties(0) + , _valueOwner(valueOwner) + { } @@ -1544,6 +1443,16 @@ const CppComponentValue *CppQmlTypes::objectByCppName(const QString &cppName) co return objectByQualifiedName(qualifiedName(cppPackage, cppName, ComponentVersion())); } +void CppQmlTypes::setCppContextProperties(const ObjectValue *contextProperties) +{ + _cppContextProperties = contextProperties; +} + +const ObjectValue *CppQmlTypes::cppContextProperties() const +{ + return _cppContextProperties; +} + ConvertToNumber::ConvertToNumber(ValueOwner *valueOwner) : _valueOwner(valueOwner), _result(0) @@ -1595,14 +1504,14 @@ void ConvertToNumber::visit(const StringValue *) void ConvertToNumber::visit(const ObjectValue *object) { if (const FunctionValue *valueOfMember = value_cast<FunctionValue>(object->lookupMember("valueOf", ContextPtr()))) { - _result = value_cast<NumberValue>(valueOfMember->call(object)); // ### invoke convert-to-number? + _result = value_cast<NumberValue>(valueOfMember->returnValue()); } } void ConvertToNumber::visit(const FunctionValue *object) { if (const FunctionValue *valueOfMember = value_cast<FunctionValue>(object->lookupMember("valueOf", ContextPtr()))) { - _result = value_cast<NumberValue>(valueOfMember->call(object)); // ### invoke convert-to-number? + _result = value_cast<NumberValue>(valueOfMember->returnValue()); } } @@ -1656,14 +1565,14 @@ void ConvertToString::visit(const StringValue *value) void ConvertToString::visit(const ObjectValue *object) { if (const FunctionValue *toStringMember = value_cast<FunctionValue>(object->lookupMember("toString", ContextPtr()))) { - _result = value_cast<StringValue>(toStringMember->call(object)); // ### invoke convert-to-string? + _result = value_cast<StringValue>(toStringMember->returnValue()); } } void ConvertToString::visit(const FunctionValue *object) { if (const FunctionValue *toStringMember = value_cast<FunctionValue>(object->lookupMember("toString", ContextPtr()))) { - _result = value_cast<StringValue>(toStringMember->call(object)); // ### invoke convert-to-string? + _result = value_cast<StringValue>(toStringMember->returnValue()); } } @@ -1699,25 +1608,19 @@ void ConvertToObject::visit(const UndefinedValue *) _result = _valueOwner->nullValue(); } -void ConvertToObject::visit(const NumberValue *value) +void ConvertToObject::visit(const NumberValue *) { - ValueList actuals; - actuals.append(value); - _result = _valueOwner->numberCtor()->construct(actuals); + _result = _valueOwner->numberCtor()->returnValue(); } -void ConvertToObject::visit(const BooleanValue *value) +void ConvertToObject::visit(const BooleanValue *) { - ValueList actuals; - actuals.append(value); - _result = _valueOwner->booleanCtor()->construct(actuals); + _result = _valueOwner->booleanCtor()->returnValue(); } -void ConvertToObject::visit(const StringValue *value) +void ConvertToObject::visit(const StringValue *) { - ValueList actuals; - actuals.append(value); - _result = _valueOwner->stringCtor()->construct(actuals); + _result = _valueOwner->stringCtor()->returnValue(); } void ConvertToObject::visit(const ObjectValue *object) diff --git a/src/libs/qmljs/qmljsinterpreter.h b/src/libs/qmljs/qmljsinterpreter.h index c13f3d6b9a0..1e71e278bad 100644 --- a/src/libs/qmljs/qmljsinterpreter.h +++ b/src/libs/qmljs/qmljsinterpreter.h @@ -536,51 +536,12 @@ private: int _metaObjectRevision; }; -class QMLJS_EXPORT Activation -{ -public: - explicit Activation(Context *parentContext = 0); - virtual ~Activation(); - - Context *context() const; - Context *parentContext() const; - - bool calledAsConstructor() const; - void setCalledAsConstructor(bool calledAsConstructor); - - bool calledAsFunction() const; - void setCalledAsFunction(bool calledAsFunction); - - ObjectValue *thisObject() const; - void setThisObject(ObjectValue *thisObject); - - ValueList arguments() const; - void setArguments(const ValueList &arguments); - -private: - ObjectValue *_thisObject; - ValueList _arguments; - bool _calledAsFunction; - Context *_parentContext; -}; - - class QMLJS_EXPORT FunctionValue: public ObjectValue { public: FunctionValue(ValueOwner *valueOwner); virtual ~FunctionValue(); - // [[construct]] - const Value *construct(const ValueList &actuals = ValueList()) const; - - // [[call]] - const Value *call(const ValueList &actuals = ValueList()) const; - - const Value *call(const ObjectValue *thisObject, - const ValueList &actuals = ValueList()) const; - - virtual const Value *returnValue() const; // Access to the names of arguments @@ -601,8 +562,6 @@ public: virtual const Value *argument(int index) const; - virtual const Value *invoke(const Activation *activation) const; - // Value interface virtual const FunctionValue *asFunctionValue() const; virtual void accept(ValueVisitor *visitor) const; @@ -625,7 +584,6 @@ public: virtual int optionalNamedArgumentCount() const; virtual const Value *argument(int index) const; virtual QString argumentName(int index) const; - virtual const Value *invoke(const Activation *activation) const; virtual bool isVariadic() const; private: @@ -686,10 +644,14 @@ public: LanguageUtils::ComponentVersion version) const; const CppComponentValue *objectByCppName(const QString &cppName) const; + void setCppContextProperties(const ObjectValue *contextProperties); + const ObjectValue *cppContextProperties() const; + private: // "Package.CppName ImportVersion" -> CppComponentValue QHash<QString, const CppComponentValue *> _objectsByQualifiedName; QHash<QString, QSet<LanguageUtils::FakeMetaObject::ConstPtr> > _fakeMetaObjectsByPackage; + const ObjectValue *_cppContextProperties; ValueOwner *_valueOwner; }; diff --git a/src/libs/qmljs/qmljslink.cpp b/src/libs/qmljs/qmljslink.cpp index 63ff773c330..69ec84d7683 100644 --- a/src/libs/qmljs/qmljslink.cpp +++ b/src/libs/qmljs/qmljslink.cpp @@ -154,8 +154,8 @@ Link::Link(const Snapshot &snapshot, const QStringList &importPaths, const Libra d->valueOwner->cppQmlTypes().load(cppData.exportedTypes); } - // populate global object with context properties from C++ - ObjectValue *global = d->valueOwner->globalObject(); + // build an object with the context properties from C++ + ObjectValue *cppContextProperties = d->valueOwner->newObject(/* prototype = */ 0); foreach (const ModelManagerInterface::CppData &cppData, cppDataHash) { QHashIterator<QString, QString> it(cppData.contextProperties); while (it.hasNext()) { @@ -166,9 +166,10 @@ Link::Link(const Snapshot &snapshot, const QStringList &importPaths, const Libra value = d->valueOwner->cppQmlTypes().objectByCppName(cppTypeName); if (!value) value = d->valueOwner->unknownValue(); - global->setMember(it.key(), value); + cppContextProperties->setMember(it.key(), value); } } + d->valueOwner->cppQmlTypes().setCppContextProperties(cppContextProperties); } } @@ -205,11 +206,6 @@ Context::ImportsPerDocument LinkPrivate::linkImports() // load library objects shipped with Creator valueOwner->cppQmlTypes().load(CppQmlTypesLoader::defaultLibraryObjects); - // the 'Qt' object is dumped even though it is not exported - // it contains useful information, in particular on enums - add the - // object as a prototype to our custom Qt object to offer these for completion - const_cast<ObjectValue *>(valueOwner->qtObject())->setPrototype(valueOwner->cppQmlTypes().objectByCppName(QLatin1String("Qt"))); - if (document) { // do it on document first, to make sure import errors are shown Imports *imports = new Imports(valueOwner); diff --git a/src/libs/qmljs/qmljsscopechain.cpp b/src/libs/qmljs/qmljsscopechain.cpp index 6993e7a5f79..946304293f8 100644 --- a/src/libs/qmljs/qmljsscopechain.cpp +++ b/src/libs/qmljs/qmljsscopechain.cpp @@ -100,6 +100,7 @@ ScopeChain::ScopeChain(const Document::Ptr &document, const ContextPtr &context) : m_document(document) , m_context(context) , m_globalScope(0) + , m_cppContextProperties(0) , m_qmlTypes(0) , m_jsImports(0) , m_modified(false) @@ -154,6 +155,17 @@ void ScopeChain::setGlobalScope(const ObjectValue *globalScope) m_globalScope = globalScope; } +const ObjectValue *ScopeChain::cppContextProperties() const +{ + return m_cppContextProperties; +} + +void ScopeChain::setCppContextProperties(const ObjectValue *cppContextProperties) +{ + m_modified = true; + m_cppContextProperties = cppContextProperties; +} + QSharedPointer<const QmlComponentChain> ScopeChain::qmlComponentChain() const { return m_qmlComponentScope; @@ -243,6 +255,9 @@ void ScopeChain::update() const m_all += m_globalScope; + if (m_cppContextProperties) + m_all += m_cppContextProperties; + // the root scope in js files doesn't see instantiating components if (m_jsScopes.count() != 1 || !m_qmlScopeObjects.isEmpty()) { if (m_qmlComponentScope) { @@ -278,6 +293,7 @@ void ScopeChain::initializeRootScope() Bind *bind = m_document->bind(); m_globalScope = valueOwner->globalObject(); + m_cppContextProperties = valueOwner->cppQmlTypes().cppContextProperties(); QHash<const Document *, QmlComponentChain *> componentScopes; QmlComponentChain *chain = new QmlComponentChain(m_document); diff --git a/src/libs/qmljs/qmljsscopechain.h b/src/libs/qmljs/qmljsscopechain.h index 344e594ff9f..91a60d4a86c 100644 --- a/src/libs/qmljs/qmljsscopechain.h +++ b/src/libs/qmljs/qmljsscopechain.h @@ -86,6 +86,9 @@ public: const ObjectValue *globalScope() const; void setGlobalScope(const ObjectValue *globalScope); + const ObjectValue *cppContextProperties() const; + void setCppContextProperties(const ObjectValue *cppContextProperties); + QSharedPointer<const QmlComponentChain> qmlComponentChain() const; void setQmlComponentChain(const QSharedPointer<const QmlComponentChain> &qmlComponentChain); @@ -115,6 +118,7 @@ private: ContextPtr m_context; const ObjectValue *m_globalScope; + const ObjectValue *m_cppContextProperties; QSharedPointer<const QmlComponentChain> m_qmlComponentScope; QList<const ObjectValue *> m_qmlScopeObjects; const TypeScope *m_qmlTypes; diff --git a/src/libs/qmljs/qmljsvalueowner.cpp b/src/libs/qmljs/qmljsvalueowner.cpp index cc2d77b7d1c..4902838a6e0 100644 --- a/src/libs/qmljs/qmljsvalueowner.cpp +++ b/src/libs/qmljs/qmljsvalueowner.cpp @@ -32,6 +32,8 @@ #include "qmljsvalueowner.h" +#include "qmljscontext.h" + using namespace QmlJS; /*! @@ -47,477 +49,73 @@ using namespace QmlJS; namespace { -//////////////////////////////////////////////////////////////////////////////// -// constructors -//////////////////////////////////////////////////////////////////////////////// -class ObjectCtor: public Function -{ -public: - ObjectCtor(ValueOwner *valueOwner); - - virtual const Value *invoke(const Activation *activation) const; -}; - -class FunctionCtor: public Function +class QtObjectPrototypeReference : public Reference { public: - FunctionCtor(ValueOwner *valueOwner); - - virtual const Value *invoke(const Activation *activation) const; -}; - -class ArrayCtor: public Function -{ -public: - ArrayCtor(ValueOwner *valueOwner); - - virtual const Value *invoke(const Activation *activation) const; -}; - -class StringCtor: public Function -{ -public: - StringCtor(ValueOwner *valueOwner); - - virtual const Value *invoke(const Activation *activation) const; -}; - -class BooleanCtor: public Function -{ -public: - BooleanCtor(ValueOwner *valueOwner); - - virtual const Value *invoke(const Activation *activation) const; -}; - -class NumberCtor: public Function -{ -public: - NumberCtor(ValueOwner *valueOwner); - - virtual const Value *invoke(const Activation *activation) const; + QtObjectPrototypeReference(ValueOwner *owner) + : Reference(owner) + {} + +private: + virtual const Value *value(ReferenceContext *referenceContext) const + { + return referenceContext->context()->valueOwner()->cppQmlTypes().objectByCppName(QLatin1String("Qt")); + } }; -class DateCtor: public Function -{ -public: - DateCtor(ValueOwner *valueOwner); +} // end of anonymous namespace - virtual const Value *invoke(const Activation *activation) const; -}; -class RegExpCtor: public Function +// globally shared data +class QmlJS::SharedValueOwner : public ValueOwner { public: - RegExpCtor(ValueOwner *valueOwner); - - virtual const Value *invoke(const Activation *activation) const; + SharedValueOwner(); + + ObjectValue *_objectPrototype; + ObjectValue *_functionPrototype; + ObjectValue *_numberPrototype; + ObjectValue *_booleanPrototype; + ObjectValue *_stringPrototype; + ObjectValue *_arrayPrototype; + ObjectValue *_datePrototype; + ObjectValue *_regexpPrototype; + + Function *_objectCtor; + Function *_functionCtor; + Function *_arrayCtor; + Function *_stringCtor; + Function *_booleanCtor; + Function *_numberCtor; + Function *_dateCtor; + Function *_regexpCtor; + + ObjectValue *_globalObject; + ObjectValue *_mathObject; + ObjectValue *_qtObject; + ObjectValue *_qmlKeysObject; + ObjectValue *_qmlFontObject; + ObjectValue *_qmlPointObject; + ObjectValue *_qmlSizeObject; + ObjectValue *_qmlRectObject; + ObjectValue *_qmlVector3DObject; + + NullValue _nullValue; + UndefinedValue _undefinedValue; + UnknownValue _unknownValue; + NumberValue _numberValue; + RealValue _realValue; + IntValue _intValue; + BooleanValue _booleanValue; + StringValue _stringValue; + UrlValue _urlValue; + ColorValue _colorValue; + AnchorLineValue _anchorLineValue; }; +Q_GLOBAL_STATIC(SharedValueOwner, sharedValueOwner) -ObjectCtor::ObjectCtor(ValueOwner *valueOwner) - : Function(valueOwner) -{ -} - -FunctionCtor::FunctionCtor(ValueOwner *valueOwner) - : Function(valueOwner) -{ -} - -ArrayCtor::ArrayCtor(ValueOwner *valueOwner) - : Function(valueOwner) -{ -} - -StringCtor::StringCtor(ValueOwner *valueOwner) - : Function(valueOwner) -{ -} - -BooleanCtor::BooleanCtor(ValueOwner *valueOwner) - : Function(valueOwner) -{ -} - -NumberCtor::NumberCtor(ValueOwner *valueOwner) - : Function(valueOwner) -{ -} - -DateCtor::DateCtor(ValueOwner *valueOwner) - : Function(valueOwner) -{ -} - -RegExpCtor::RegExpCtor(ValueOwner *valueOwner) - : Function(valueOwner) -{ -} - -const Value *ObjectCtor::invoke(const Activation *activation) const -{ - ObjectValue *thisObject = activation->thisObject(); - if (activation->calledAsFunction()) - thisObject = valueOwner()->newObject(); - - thisObject->setClassName("Object"); - thisObject->setPrototype(valueOwner()->objectPrototype()); - thisObject->setMember("length", valueOwner()->numberValue()); - return thisObject; -} - -const Value *FunctionCtor::invoke(const Activation *activation) const -{ - ObjectValue *thisObject = activation->thisObject(); - if (activation->calledAsFunction()) - thisObject = valueOwner()->newObject(); - - thisObject->setClassName("Function"); - thisObject->setPrototype(valueOwner()->functionPrototype()); - thisObject->setMember("length", valueOwner()->numberValue()); - return thisObject; -} - -const Value *ArrayCtor::invoke(const Activation *activation) const -{ - ObjectValue *thisObject = activation->thisObject(); - if (activation->calledAsFunction()) - thisObject = valueOwner()->newObject(); - - thisObject->setClassName("Array"); - thisObject->setPrototype(valueOwner()->arrayPrototype()); - thisObject->setMember("length", valueOwner()->numberValue()); - return thisObject; -} - -const Value *StringCtor::invoke(const Activation *activation) const -{ - if (activation->calledAsFunction()) - return valueOwner()->convertToString(activation->thisObject()); - - ObjectValue *thisObject = activation->thisObject(); - thisObject->setClassName("String"); - thisObject->setPrototype(valueOwner()->stringPrototype()); - thisObject->setMember("length", valueOwner()->numberValue()); - return thisObject; -} - -const Value *BooleanCtor::invoke(const Activation *activation) const -{ - if (activation->calledAsFunction()) - return valueOwner()->convertToBoolean(activation->thisObject()); - - ObjectValue *thisObject = activation->thisObject(); - thisObject->setClassName("Boolean"); - thisObject->setPrototype(valueOwner()->booleanPrototype()); - return thisObject; -} - -const Value *NumberCtor::invoke(const Activation *activation) const -{ - if (activation->calledAsFunction()) - return valueOwner()->convertToNumber(activation->thisObject()); - - ObjectValue *thisObject = activation->thisObject(); - thisObject->setClassName("Number"); - thisObject->setPrototype(valueOwner()->numberPrototype()); - return thisObject; -} - -const Value *DateCtor::invoke(const Activation *activation) const -{ - if (activation->calledAsFunction()) - return valueOwner()->stringValue(); - - ObjectValue *thisObject = activation->thisObject(); - thisObject->setClassName("Date"); - thisObject->setPrototype(valueOwner()->datePrototype()); - return thisObject; -} - -const Value *RegExpCtor::invoke(const Activation *activation) const -{ - ObjectValue *thisObject = activation->thisObject(); - if (activation->calledAsFunction()) - thisObject = valueOwner()->newObject(); - - thisObject->setClassName("RegExp"); - thisObject->setPrototype(valueOwner()->regexpPrototype()); - thisObject->setMember("source", valueOwner()->stringValue()); - thisObject->setMember("global", valueOwner()->booleanValue()); - thisObject->setMember("ignoreCase", valueOwner()->booleanValue()); - thisObject->setMember("multiline", valueOwner()->booleanValue()); - thisObject->setMember("lastIndex", valueOwner()->numberValue()); - return thisObject; -} - -} // end of anonymous namespace - - -ValueOwner::ValueOwner() - : _objectPrototype(0), - _functionPrototype(0), - _numberPrototype(0), - _booleanPrototype(0), - _stringPrototype(0), - _arrayPrototype(0), - _datePrototype(0), - _regexpPrototype(0), - _objectCtor(0), - _functionCtor(0), - _arrayCtor(0), - _stringCtor(0), - _booleanCtor(0), - _numberCtor(0), - _dateCtor(0), - _regexpCtor(0), - _globalObject(0), - _mathObject(0), - _qtObject(0), - _qmlKeysObject(0), - _qmlFontObject(0), - _qmlPointObject(0), - _qmlSizeObject(0), - _qmlRectObject(0), - _qmlVector3DObject(0), - _convertToNumber(this), - _convertToString(this), - _convertToObject(this), - _cppQmlTypes(this) -{ - initializePrototypes(); -} - -ValueOwner::~ValueOwner() -{ - qDeleteAll(_registeredValues); -} - -const NullValue *ValueOwner::nullValue() const -{ - return &_nullValue; -} - -const UndefinedValue *ValueOwner::undefinedValue() const -{ - return &_undefinedValue; -} - -const UnknownValue *ValueOwner::unknownValue() const -{ - return &_unknownValue; -} - -const NumberValue *ValueOwner::numberValue() const -{ - return &_numberValue; -} - -const RealValue *ValueOwner::realValue() const -{ - return &_realValue; -} - -const IntValue *ValueOwner::intValue() const -{ - return &_intValue; -} - -const BooleanValue *ValueOwner::booleanValue() const -{ - return &_booleanValue; -} - -const StringValue *ValueOwner::stringValue() const -{ - return &_stringValue; -} - -const UrlValue *ValueOwner::urlValue() const -{ - return &_urlValue; -} - -const ColorValue *ValueOwner::colorValue() const -{ - return &_colorValue; -} - -const AnchorLineValue *ValueOwner::anchorLineValue() const -{ - return &_anchorLineValue; -} - -const Value *ValueOwner::newArray() -{ - return arrayCtor()->construct(); -} - -ObjectValue *ValueOwner::newObject() -{ - return newObject(_objectPrototype); -} - -ObjectValue *ValueOwner::newObject(const ObjectValue *prototype) -{ - ObjectValue *object = new ObjectValue(this); - object->setPrototype(prototype); - return object; -} - -Function *ValueOwner::newFunction() -{ - Function *function = new Function(this); - function->setPrototype(functionPrototype()); - return function; -} - -ObjectValue *ValueOwner::globalObject() const -{ - return _globalObject; -} - -ObjectValue *ValueOwner::objectPrototype() const -{ - return _objectPrototype; -} - -ObjectValue *ValueOwner::functionPrototype() const -{ - return _functionPrototype; -} - -ObjectValue *ValueOwner::numberPrototype() const -{ - return _numberPrototype; -} - -ObjectValue *ValueOwner::booleanPrototype() const -{ - return _booleanPrototype; -} - -ObjectValue *ValueOwner::stringPrototype() const -{ - return _stringPrototype; -} - -ObjectValue *ValueOwner::arrayPrototype() const -{ - return _arrayPrototype; -} - -ObjectValue *ValueOwner::datePrototype() const -{ - return _datePrototype; -} - -ObjectValue *ValueOwner::regexpPrototype() const -{ - return _regexpPrototype; -} - -const FunctionValue *ValueOwner::objectCtor() const -{ - return _objectCtor; -} - -const FunctionValue *ValueOwner::functionCtor() const -{ - return _functionCtor; -} - -const FunctionValue *ValueOwner::arrayCtor() const -{ - return _arrayCtor; -} - -const FunctionValue *ValueOwner::stringCtor() const -{ - return _stringCtor; -} - -const FunctionValue *ValueOwner::booleanCtor() const -{ - return _booleanCtor; -} - -const FunctionValue *ValueOwner::numberCtor() const -{ - return _numberCtor; -} - -const FunctionValue *ValueOwner::dateCtor() const -{ - return _dateCtor; -} - -const FunctionValue *ValueOwner::regexpCtor() const -{ - return _regexpCtor; -} - -const ObjectValue *ValueOwner::mathObject() const -{ - return _mathObject; -} - -const ObjectValue *ValueOwner::qtObject() const -{ - return _qtObject; -} - -void ValueOwner::registerValue(Value *value) -{ - // ### get rid of this lock - QMutexLocker locker(&_mutex); - _registeredValues.append(value); -} - -const Value *ValueOwner::convertToBoolean(const Value *value) -{ - return _convertToNumber(value); // ### implement convert to bool -} - -const Value *ValueOwner::convertToNumber(const Value *value) -{ - return _convertToNumber(value); -} - -const Value *ValueOwner::convertToString(const Value *value) -{ - return _convertToString(value); -} - -const Value *ValueOwner::convertToObject(const Value *value) -{ - return _convertToObject(value); -} - -QString ValueOwner::typeId(const Value *value) -{ - return _typeId(value); -} - -Function *ValueOwner::addFunction(ObjectValue *object, const QString &name, const Value *result, int argumentCount, int optionalCount, bool variadic) -{ - Function *function = addFunction(object, name, argumentCount, optionalCount, variadic); - function->setReturnValue(result); - return function; -} - -Function *ValueOwner::addFunction(ObjectValue *object, const QString &name, int argumentCount, int optionalCount, bool variadic) -{ - Function *function = newFunction(); - for (int i = 0; i < argumentCount; ++i) - function->addArgument(unknownValue()); - function->setVariadic(variadic); - function->setOptionalNamedArgumentCount(optionalCount); - object->setMember(name, function); - return function; -} - -void ValueOwner::initializePrototypes() +SharedValueOwner::SharedValueOwner() + : ValueOwner(this) // need to avoid recursing in ValueOwner ctor { _objectPrototype = newObject(/*prototype = */ 0); _functionPrototype = newObject(_objectPrototype); @@ -532,62 +130,76 @@ void ValueOwner::initializePrototypes() _globalObject = newObject(); _globalObject->setClassName("Global"); - // set up the default Object prototype - _objectCtor = new ObjectCtor(this); - _objectCtor->setPrototype(_functionPrototype); + ObjectValue *objectInstance = newObject(); + objectInstance->setClassName("Object"); + objectInstance->setMember("length", numberValue()); + _objectCtor = new Function(this); _objectCtor->setMember("prototype", _objectPrototype); - _objectCtor->setReturnValue(newObject()); + _objectCtor->setReturnValue(objectInstance); _objectCtor->addArgument(unknownValue(), "value"); _objectCtor->setOptionalNamedArgumentCount(1); - _functionCtor = new FunctionCtor(this); - _functionCtor->setPrototype(_functionPrototype); + FunctionValue *functionInstance = new FunctionValue(this); + _functionCtor = new Function(this); _functionCtor->setMember("prototype", _functionPrototype); - _functionCtor->setReturnValue(newFunction()); + _functionCtor->setReturnValue(functionInstance); _functionCtor->setVariadic(true); - _arrayCtor = new ArrayCtor(this); - _arrayCtor->setPrototype(_functionPrototype); + ObjectValue *arrayInstance = newObject(_arrayPrototype); + arrayInstance->setClassName("Array"); + arrayInstance->setMember("length", numberValue()); + _arrayCtor = new Function(this); _arrayCtor->setMember("prototype", _arrayPrototype); - _arrayCtor->setReturnValue(newArray()); + _arrayCtor->setReturnValue(arrayInstance); _arrayCtor->setVariadic(true); - _stringCtor = new StringCtor(this); - _stringCtor->setPrototype(_functionPrototype); + ObjectValue *stringInstance = newObject(_stringPrototype); + stringInstance->setClassName("String"); + stringInstance->setMember("length", numberValue()); + _stringCtor = new Function(this); _stringCtor->setMember("prototype", _stringPrototype); - _stringCtor->setReturnValue(stringValue()); + _stringCtor->setReturnValue(stringInstance); _stringCtor->addArgument(unknownValue(), "value"); _stringCtor->setOptionalNamedArgumentCount(1); - _booleanCtor = new BooleanCtor(this); - _booleanCtor->setPrototype(_functionPrototype); + ObjectValue *booleanInstance = newObject(_booleanPrototype); + booleanInstance->setClassName("Boolean"); + _booleanCtor = new Function(this); _booleanCtor->setMember("prototype", _booleanPrototype); - _booleanCtor->setReturnValue(booleanValue()); + _booleanCtor->setReturnValue(booleanInstance); _booleanCtor->addArgument(unknownValue(), "value"); - _numberCtor = new NumberCtor(this); - _numberCtor->setPrototype(_functionPrototype); + ObjectValue *numberInstance = newObject(_numberPrototype); + numberInstance->setClassName("Number"); + _numberCtor = new Function(this); _numberCtor->setMember("prototype", _numberPrototype); - _numberCtor->setReturnValue(numberValue()); + _numberCtor->setReturnValue(numberInstance); _numberCtor->addArgument(unknownValue(), "value"); _numberCtor->setOptionalNamedArgumentCount(1); - _dateCtor = new DateCtor(this); - _dateCtor->setPrototype(_functionPrototype); + ObjectValue *dateInstance = newObject(_datePrototype); + dateInstance->setClassName("Date"); + _dateCtor = new Function(this); _dateCtor->setMember("prototype", _datePrototype); - _dateCtor->setReturnValue(_datePrototype); + _dateCtor->setReturnValue(dateInstance); _dateCtor->setVariadic(true); - _regexpCtor = new RegExpCtor(this); - _regexpCtor->setPrototype(_functionPrototype); + ObjectValue *regexpInstance = newObject(_regexpPrototype); + regexpInstance->setClassName("RegExp"); + regexpInstance->setMember("source", stringValue()); + regexpInstance->setMember("global", booleanValue()); + regexpInstance->setMember("ignoreCase", booleanValue()); + regexpInstance->setMember("multiline", booleanValue()); + regexpInstance->setMember("lastIndex", numberValue()); + _regexpCtor = new Function(this); _regexpCtor->setMember("prototype", _regexpPrototype); - _regexpCtor->setReturnValue(_regexpPrototype); + _regexpCtor->setReturnValue(regexpInstance); _regexpCtor->addArgument(unknownValue(), "pattern"); _regexpCtor->addArgument(unknownValue(), "flags"); addFunction(_objectCtor, "getPrototypeOf", 1); addFunction(_objectCtor, "getOwnPropertyDescriptor", 2); - addFunction(_objectCtor, "getOwnPropertyNames", newArray(), 1); + addFunction(_objectCtor, "getOwnPropertyNames", arrayInstance, 1); addFunction(_objectCtor, "create", 1, 1); addFunction(_objectCtor, "defineProperty", 3); addFunction(_objectCtor, "defineProperties", 2); @@ -597,7 +209,7 @@ void ValueOwner::initializePrototypes() addFunction(_objectCtor, "isSealed", booleanValue(), 1); addFunction(_objectCtor, "isFrozen", booleanValue(), 1); addFunction(_objectCtor, "isExtensible", booleanValue(), 1); - addFunction(_objectCtor, "keys", newArray(), 1); + addFunction(_objectCtor, "keys", arrayInstance, 1); addFunction(_objectPrototype, "toString", stringValue(), 0); addFunction(_objectPrototype, "toLocaleString", stringValue(), 0); @@ -651,11 +263,11 @@ void ValueOwner::initializePrototypes() addFunction(_stringPrototype, "indexOf", numberValue(), 2); addFunction(_stringPrototype, "lastIndexOf", numberValue(), 2); addFunction(_stringPrototype, "localeCompare", booleanValue(), 1); - addFunction(_stringPrototype, "match", newArray(), 1); + addFunction(_stringPrototype, "match", arrayInstance, 1); addFunction(_stringPrototype, "replace", stringValue(), 2); addFunction(_stringPrototype, "search", numberValue(), 1); addFunction(_stringPrototype, "slice", stringValue(), 2); - addFunction(_stringPrototype, "split", newArray(), 1); + addFunction(_stringPrototype, "split", arrayInstance, 1); addFunction(_stringPrototype, "substring", stringValue(), 2); addFunction(_stringPrototype, "toLowerCase", stringValue(), 0); addFunction(_stringPrototype, "toLocaleLowerCase", stringValue(), 0); @@ -767,7 +379,7 @@ void ValueOwner::initializePrototypes() // set up the default Boolean prototype _regexpPrototype->setMember("constructor", _regexpCtor); - addFunction(_regexpPrototype, "exec", newArray(), 1); + addFunction(_regexpPrototype, "exec", arrayInstance, 1); addFunction(_regexpPrototype, "test", booleanValue(), 1); addFunction(_regexpPrototype, "toString", stringValue(), 0); @@ -889,7 +501,7 @@ void ValueOwner::initializePrototypes() _qmlVector3DObject->setMember("z", realValue()); // global Qt object, in alphabetic order - _qtObject = newObject(/*prototype */ 0); + _qtObject = newObject(new QtObjectPrototypeReference(this)); addFunction(_qtObject, QLatin1String("atob"), &_stringValue, 1); addFunction(_qtObject, QLatin1String("btoa"), &_stringValue, 1); addFunction(_qtObject, QLatin1String("createComponent"), 1); @@ -930,34 +542,264 @@ void ValueOwner::initializePrototypes() addFunction(_globalObject, QLatin1String("QT_TRID_NOOP"), 1); } + +ValueOwner::ValueOwner(const SharedValueOwner *shared) + : _convertToNumber(this) + , _convertToString(this) + , _convertToObject(this) + , _cppQmlTypes(this) +{ + if (shared) + _shared = shared; + else + _shared = sharedValueOwner(); +} + +ValueOwner::~ValueOwner() +{ + qDeleteAll(_registeredValues); +} + +const NullValue *ValueOwner::nullValue() const +{ + return &_shared->_nullValue; +} + +const UndefinedValue *ValueOwner::undefinedValue() const +{ + return &_shared->_undefinedValue; +} + +const UnknownValue *ValueOwner::unknownValue() const +{ + return &_shared->_unknownValue; +} + +const NumberValue *ValueOwner::numberValue() const +{ + return &_shared->_numberValue; +} + +const RealValue *ValueOwner::realValue() const +{ + return &_shared->_realValue; +} + +const IntValue *ValueOwner::intValue() const +{ + return &_shared->_intValue; +} + +const BooleanValue *ValueOwner::booleanValue() const +{ + return &_shared->_booleanValue; +} + +const StringValue *ValueOwner::stringValue() const +{ + return &_shared->_stringValue; +} + +const UrlValue *ValueOwner::urlValue() const +{ + return &_shared->_urlValue; +} + +const ColorValue *ValueOwner::colorValue() const +{ + return &_shared->_colorValue; +} + +const AnchorLineValue *ValueOwner::anchorLineValue() const +{ + return &_shared->_anchorLineValue; +} + +ObjectValue *ValueOwner::newObject() +{ + return newObject(_shared->_objectPrototype); +} + +ObjectValue *ValueOwner::newObject(const Value *prototype) +{ + ObjectValue *object = new ObjectValue(this); + object->setPrototype(prototype); + return object; +} + +const ObjectValue *ValueOwner::globalObject() const +{ + return _shared->_globalObject; +} + +const ObjectValue *ValueOwner::objectPrototype() const +{ + return _shared->_objectPrototype; +} + +const ObjectValue *ValueOwner::functionPrototype() const +{ + return _shared->_functionPrototype; +} + +const ObjectValue *ValueOwner::numberPrototype() const +{ + return _shared->_numberPrototype; +} + +const ObjectValue *ValueOwner::booleanPrototype() const +{ + return _shared->_booleanPrototype; +} + +const ObjectValue *ValueOwner::stringPrototype() const +{ + return _shared->_stringPrototype; +} + +const ObjectValue *ValueOwner::arrayPrototype() const +{ + return _shared->_arrayPrototype; +} + +const ObjectValue *ValueOwner::datePrototype() const +{ + return _shared->_datePrototype; +} + +const ObjectValue *ValueOwner::regexpPrototype() const +{ + return _shared->_regexpPrototype; +} + +const FunctionValue *ValueOwner::objectCtor() const +{ + return _shared->_objectCtor; +} + +const FunctionValue *ValueOwner::functionCtor() const +{ + return _shared->_functionCtor; +} + +const FunctionValue *ValueOwner::arrayCtor() const +{ + return _shared->_arrayCtor; +} + +const FunctionValue *ValueOwner::stringCtor() const +{ + return _shared->_stringCtor; +} + +const FunctionValue *ValueOwner::booleanCtor() const +{ + return _shared->_booleanCtor; +} + +const FunctionValue *ValueOwner::numberCtor() const +{ + return _shared->_numberCtor; +} + +const FunctionValue *ValueOwner::dateCtor() const +{ + return _shared->_dateCtor; +} + +const FunctionValue *ValueOwner::regexpCtor() const +{ + return _shared->_regexpCtor; +} + +const ObjectValue *ValueOwner::mathObject() const +{ + return _shared->_mathObject; +} + +const ObjectValue *ValueOwner::qtObject() const +{ + return _shared->_qtObject; +} + +void ValueOwner::registerValue(Value *value) +{ + // ### get rid of this lock + QMutexLocker locker(&_mutex); + _registeredValues.append(value); +} + +const Value *ValueOwner::convertToBoolean(const Value *value) +{ + return _convertToNumber(value); // ### implement convert to bool +} + +const Value *ValueOwner::convertToNumber(const Value *value) +{ + return _convertToNumber(value); +} + +const Value *ValueOwner::convertToString(const Value *value) +{ + return _convertToString(value); +} + +const Value *ValueOwner::convertToObject(const Value *value) +{ + return _convertToObject(value); +} + +QString ValueOwner::typeId(const Value *value) +{ + return _typeId(value); +} + +Function *ValueOwner::addFunction(ObjectValue *object, const QString &name, const Value *result, int argumentCount, int optionalCount, bool variadic) +{ + Function *function = addFunction(object, name, argumentCount, optionalCount, variadic); + function->setReturnValue(result); + return function; +} + +Function *ValueOwner::addFunction(ObjectValue *object, const QString &name, int argumentCount, int optionalCount, bool variadic) +{ + Function *function = new Function(this); + for (int i = 0; i < argumentCount; ++i) + function->addArgument(unknownValue()); + function->setVariadic(variadic); + function->setOptionalNamedArgumentCount(optionalCount); + object->setMember(name, function); + return function; +} + const ObjectValue *ValueOwner::qmlKeysObject() { - return _qmlKeysObject; + return _shared->_qmlKeysObject; } const ObjectValue *ValueOwner::qmlFontObject() { - return _qmlFontObject; + return _shared->_qmlFontObject; } const ObjectValue *ValueOwner::qmlPointObject() { - return _qmlPointObject; + return _shared->_qmlPointObject; } const ObjectValue *ValueOwner::qmlSizeObject() { - return _qmlSizeObject; + return _shared->_qmlSizeObject; } const ObjectValue *ValueOwner::qmlRectObject() { - return _qmlRectObject; + return _shared->_qmlRectObject; } const ObjectValue *ValueOwner::qmlVector3DObject() { - return _qmlVector3DObject; + return _shared->_qmlVector3DObject; } const Value *ValueOwner::defaultValueForBuiltinType(const QString &name) const diff --git a/src/libs/qmljs/qmljsvalueowner.h b/src/libs/qmljs/qmljsvalueowner.h index d1edfe02485..0add1f1d0b9 100644 --- a/src/libs/qmljs/qmljsvalueowner.h +++ b/src/libs/qmljs/qmljsvalueowner.h @@ -62,13 +62,14 @@ class Imports; class TypeScope; class JSImportScope; class Function; +class SharedValueOwner; class QMLJS_EXPORT ValueOwner { Q_DISABLE_COPY(ValueOwner) public: - ValueOwner(); + ValueOwner(const SharedValueOwner *shared = 0); ~ValueOwner(); const NullValue *nullValue() const; @@ -83,10 +84,8 @@ public: const ColorValue *colorValue() const; const AnchorLineValue *anchorLineValue() const; - ObjectValue *newObject(const ObjectValue *prototype); + ObjectValue *newObject(const Value *prototype); ObjectValue *newObject(); - Function *newFunction(); - const Value *newArray(); // ### remove me // QML objects const ObjectValue *qmlKeysObject(); @@ -100,19 +99,19 @@ public: const Value *defaultValueForBuiltinType(const QString &typeName) const; // global object - ObjectValue *globalObject() const; + const ObjectValue *globalObject() const; const ObjectValue *mathObject() const; const ObjectValue *qtObject() const; // prototypes - ObjectValue *objectPrototype() const; - ObjectValue *functionPrototype() const; - ObjectValue *numberPrototype() const; - ObjectValue *booleanPrototype() const; - ObjectValue *stringPrototype() const; - ObjectValue *arrayPrototype() const; - ObjectValue *datePrototype() const; - ObjectValue *regexpPrototype() const; + const ObjectValue *objectPrototype() const; + const ObjectValue *functionPrototype() const; + const ObjectValue *numberPrototype() const; + const ObjectValue *booleanPrototype() const; + const ObjectValue *stringPrototype() const; + const ObjectValue *arrayPrototype() const; + const ObjectValue *datePrototype() const; + const ObjectValue *regexpPrototype() const; // ctors const FunctionValue *objectCtor() const; @@ -139,64 +138,22 @@ public: void registerValue(Value *value); // internal -private: - void initializePrototypes(); - +protected: Function *addFunction(ObjectValue *object, const QString &name, const Value *result, int argumentCount = 0, int optionalCount = 0, bool variadic = false); Function *addFunction(ObjectValue *object, const QString &name, int argumentCount = 0, int optionalCount = 0, bool variadic = false); -private: - ObjectValue *_objectPrototype; - ObjectValue *_functionPrototype; - ObjectValue *_numberPrototype; - ObjectValue *_booleanPrototype; - ObjectValue *_stringPrototype; - ObjectValue *_arrayPrototype; - ObjectValue *_datePrototype; - ObjectValue *_regexpPrototype; - - Function *_objectCtor; - Function *_functionCtor; - Function *_arrayCtor; - Function *_stringCtor; - Function *_booleanCtor; - Function *_numberCtor; - Function *_dateCtor; - Function *_regexpCtor; - - ObjectValue *_globalObject; - ObjectValue *_mathObject; - ObjectValue *_qtObject; - ObjectValue *_qmlKeysObject; - ObjectValue *_qmlFontObject; - ObjectValue *_qmlPointObject; - ObjectValue *_qmlSizeObject; - ObjectValue *_qmlRectObject; - ObjectValue *_qmlVector3DObject; - - NullValue _nullValue; - UndefinedValue _undefinedValue; - UnknownValue _unknownValue; - NumberValue _numberValue; - RealValue _realValue; - IntValue _intValue; - BooleanValue _booleanValue; - StringValue _stringValue; - UrlValue _urlValue; - ColorValue _colorValue; - AnchorLineValue _anchorLineValue; QList<Value *> _registeredValues; + QMutex _mutex; ConvertToNumber _convertToNumber; ConvertToString _convertToString; ConvertToObject _convertToObject; TypeId _typeId; - CppQmlTypes _cppQmlTypes; - QMutex _mutex; + const SharedValueOwner *_shared; }; } // namespace QmlJS |