/**************************************************************************** ** ** Copyright (C) 2016 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 "qv4string_p.h" #include "qv4value_p.h" #include "qv4identifiertable_p.h" #include "qv4runtime_p.h" #include "qv4objectproto_p.h" #include "qv4stringobject_p.h" #include #include using namespace QV4; void Heap::StringOrSymbol::markObjects(Heap::Base *that, MarkStack *markStack) { StringOrSymbol *s = static_cast(that); Heap::StringOrSymbol *id = s->identifier.asStringOrSymbol(); if (id) id->mark(markStack); } void Heap::String::markObjects(Heap::Base *that, MarkStack *markStack) { StringOrSymbol::markObjects(that, markStack); String *s = static_cast(that); if (s->subtype < StringType_Complex) return; ComplexString *cs = static_cast(s); if (cs->subtype == StringType_AddedString) { cs->left->mark(markStack); cs->right->mark(markStack); } else { Q_ASSERT(cs->subtype == StringType_SubString); cs->left->mark(markStack); } } DEFINE_MANAGED_VTABLE(StringOrSymbol); DEFINE_MANAGED_VTABLE(String); bool String::virtualIsEqualTo(Managed *t, Managed *o) { if (t == o) return true; if (!o->vtable()->isString) return false; return static_cast(t)->isEqualTo(static_cast(o)); } void Heap::String::init(const QString &t) { Base::init(); subtype = String::StringType_Unknown; text = const_cast(t).data_ptr(); text->ref.ref(); } void Heap::ComplexString::init(String *l, String *r) { Base::init(); subtype = String::StringType_AddedString; left = l; right = r; len = left->length() + right->length(); if (left->subtype >= StringType_Complex) largestSubLength = static_cast(left)->largestSubLength; else largestSubLength = left->length(); if (right->subtype >= StringType_Complex) largestSubLength = qMax(largestSubLength, static_cast(right)->largestSubLength); else largestSubLength = qMax(largestSubLength, right->length()); // make sure we don't get excessive depth in our strings if (len > 256 && len >= 2*largestSubLength) simplifyString(); } void Heap::ComplexString::init(Heap::String *ref, int from, int len) { Q_ASSERT(ref->length() >= from + len); Base::init(); subtype = String::StringType_SubString; left = ref; this->from = from; this->len = len; } void Heap::StringOrSymbol::destroy() { if (text) { internalClass->engine->memoryManager->changeUnmanagedHeapSizeUsage(qptrdiff(-text->size) * (int)sizeof(QChar)); if (!text->ref.deref()) QStringData::deallocate(text); } Base::destroy(); } uint String::toUInt(bool *ok) const { *ok = true; if (subtype() >= Heap::String::StringType_Unknown) d()->createHashValue(); if (subtype() == Heap::String::StringType_ArrayIndex) return d()->stringHash; // required for UINT_MAX or numbers starting with a leading 0 double d = RuntimeHelpers::stringToNumber(toQString()); uint l = (uint)d; if (d == l) return l; *ok = false; return UINT_MAX; } void String::createPropertyKeyImpl() const { if (!d()->text) d()->simplifyString(); Q_ASSERT(d()->text); engine()->identifierTable->asPropertyKey(this); } void Heap::String::simplifyString() const { Q_ASSERT(!text); int l = length(); QString result(l, Qt::Uninitialized); QChar *ch = const_cast(result.constData()); append(this, ch); text = result.data_ptr(); text->ref.ref(); const ComplexString *cs = static_cast(this); identifier = PropertyKey::invalid(); cs->left = cs->right = nullptr; internalClass->engine->memoryManager->changeUnmanagedHeapSizeUsage(qptrdiff(text->size) * (qptrdiff)sizeof(QChar)); subtype = StringType_Unknown; } bool Heap::String::startsWithUpper() const { if (subtype == StringType_AddedString) return static_cast(this)->left->startsWithUpper(); const Heap::String *str = this; int offset = 0; if (subtype == StringType_SubString) { const ComplexString *cs = static_cast(this); if (!cs->len) return false; // simplification here is not ideal, but hopefully not a common case. if (cs->left->subtype >= Heap::String::StringType_Complex) cs->left->simplifyString(); str = cs->left; offset = cs->from; } Q_ASSERT(str->subtype < Heap::String::StringType_Complex); return str->text->size > offset && QChar::isUpper(str->text->data()[offset]); } void Heap::String::append(const String *data, QChar *ch) { std::vector worklist; worklist.reserve(32); worklist.push_back(data); while (!worklist.empty()) { const String *item = worklist.back(); worklist.pop_back(); if (item->subtype == StringType_AddedString) { const ComplexString *cs = static_cast(item); worklist.push_back(cs->right); worklist.push_back(cs->left); } else if (item->subtype == StringType_SubString) { const ComplexString *cs = static_cast(item); memcpy(ch, cs->left->toQString().constData() + cs->from, cs->len*sizeof(QChar)); ch += cs->len; } else { memcpy(static_cast(ch), static_cast(item->text->data()), item->text->size * sizeof(QChar)); ch += item->text->size; } } } void Heap::StringOrSymbol::createHashValue() const { if (!text) { Q_ASSERT(internalClass->vtable->isString); static_cast(this)->simplifyString(); } Q_ASSERT(text); const QChar *ch = reinterpret_cast(text->data()); const QChar *end = ch + text->size; stringHash = QV4::String::calculateHashValue(ch, end, &subtype); } qint64 String::virtualGetLength(const Managed *m) { return static_cast(m)->d()->length(); }