From afbf1f74af678af0eda76035133406aa8883408a Mon Sep 17 00:00:00 2001 From: Simon Hausmann Date: Tue, 11 Nov 2014 15:08:30 +0100 Subject: Ported ExecutionEngine::newString and newIdentifier to Heap::String Avoid the use of Returned for newString and changed the identifier table to use Heap::String. This required moving some code back into Heap::String, but that's code that doesn't call back into the GC, so allocations and therefore future object moves aren't possible. Change-Id: I1dca3e9c12a9c56f09419af8cc8cba39fe04f720 Reviewed-by: Lars Knoll --- src/qml/jsruntime/qv4arrayobject.cpp | 6 +-- src/qml/jsruntime/qv4dateobject.cpp | 2 +- src/qml/jsruntime/qv4engine.cpp | 8 ++-- src/qml/jsruntime/qv4engine_p.h | 5 ++- src/qml/jsruntime/qv4errorobject.cpp | 2 +- src/qml/jsruntime/qv4function.cpp | 2 +- src/qml/jsruntime/qv4functionobject.cpp | 4 +- src/qml/jsruntime/qv4globalobject.cpp | 17 ++++----- src/qml/jsruntime/qv4identifier.cpp | 2 +- src/qml/jsruntime/qv4identifier_p.h | 6 ++- src/qml/jsruntime/qv4identifiertable.cpp | 65 ++++++++++++++++---------------- src/qml/jsruntime/qv4identifiertable_p.h | 27 +++++++------ src/qml/jsruntime/qv4include.cpp | 10 +++-- src/qml/jsruntime/qv4internalclass.cpp | 3 +- src/qml/jsruntime/qv4jsonobject.cpp | 10 ++--- src/qml/jsruntime/qv4qobjectwrapper.cpp | 10 ++++- src/qml/jsruntime/qv4regexpobject.cpp | 4 +- src/qml/jsruntime/qv4runtime.cpp | 26 ++++++------- src/qml/jsruntime/qv4runtime_p.h | 4 +- src/qml/jsruntime/qv4string.cpp | 52 +++++++++++++------------ src/qml/jsruntime/qv4string_p.h | 56 ++++++++++++++++----------- src/qml/jsruntime/qv4stringobject.cpp | 14 +++---- src/qml/jsruntime/qv4value.cpp | 8 ++-- src/qml/jsruntime/qv4value_p.h | 5 ++- 24 files changed, 189 insertions(+), 159 deletions(-) (limited to 'src/qml/jsruntime') diff --git a/src/qml/jsruntime/qv4arrayobject.cpp b/src/qml/jsruntime/qv4arrayobject.cpp index 0935da3255..78cbe88ba9 100644 --- a/src/qml/jsruntime/qv4arrayobject.cpp +++ b/src/qml/jsruntime/qv4arrayobject.cpp @@ -205,7 +205,7 @@ ReturnedValue ArrayPrototype::method_join(CallContext *ctx) if (scope.hasException()) return Encode::undefined(); if (!e->isNullOrUndefined()) - R += e->toString(ctx)->toQString(); + R += e->toQString(); } } else { // @@ -214,7 +214,7 @@ ReturnedValue ArrayPrototype::method_join(CallContext *ctx) ScopedString name(scope, ctx->d()->engine->newString(QStringLiteral("0"))); ScopedValue r6(scope, self->get(name.getPointer())); if (!r6->isNullOrUndefined()) - R = r6->toString(ctx)->toQString(); + R = r6->toQString(); ScopedValue r12(scope); for (quint32 k = 1; k < r2; ++k) { @@ -226,7 +226,7 @@ ReturnedValue ArrayPrototype::method_join(CallContext *ctx) return Encode::undefined(); if (!r12->isNullOrUndefined()) - R += r12->toString(ctx)->toQString(); + R += r12->toQString(); } } diff --git a/src/qml/jsruntime/qv4dateobject.cpp b/src/qml/jsruntime/qv4dateobject.cpp index 26004b5c7e..c5d25e42ae 100644 --- a/src/qml/jsruntime/qv4dateobject.cpp +++ b/src/qml/jsruntime/qv4dateobject.cpp @@ -773,7 +773,7 @@ ReturnedValue DatePrototype::method_parse(CallContext *ctx) { if (!ctx->d()->callData->argc) return Encode(qSNaN()); - return Encode(ParseString(ctx->d()->callData->args[0].toString(ctx)->toQString())); + return Encode(ParseString(ctx->d()->callData->args[0].toQString())); } ReturnedValue DatePrototype::method_UTC(CallContext *ctx) diff --git a/src/qml/jsruntime/qv4engine.cpp b/src/qml/jsruntime/qv4engine.cpp index 164ad176f3..0bb05896b0 100644 --- a/src/qml/jsruntime/qv4engine.cpp +++ b/src/qml/jsruntime/qv4engine.cpp @@ -260,6 +260,7 @@ ExecutionEngine::ExecutionEngine(EvalISelFactory *factory) id_byteLength = newIdentifier(QStringLiteral("byteLength")); id_byteOffset = newIdentifier(QStringLiteral("byteOffset")); id_buffer = newIdentifier(QStringLiteral("buffer")); + id_lastIndex = newIdentifier(QStringLiteral("lastIndex")); memberDataClass = InternalClass::create(this, MemberData::staticVTable(), 0); @@ -532,13 +533,13 @@ Heap::Object *ExecutionEngine::newObject(InternalClass *internalClass) return object->d(); } -Returned *ExecutionEngine::newString(const QString &s) +Heap::String *ExecutionEngine::newString(const QString &s) { Scope scope(this); - return ScopedString(scope, memoryManager->alloc(this, s))->asReturned(); + return ScopedString(scope, memoryManager->alloc(this, s))->d(); } -String *ExecutionEngine::newIdentifier(const QString &text) +Heap::String *ExecutionEngine::newIdentifier(const QString &text) { return identifierTable->insertString(text); } @@ -929,6 +930,7 @@ void ExecutionEngine::markObjects() id_byteLength->mark(this); id_byteOffset->mark(this); id_buffer->mark(this); + id_lastIndex->mark(this); objectCtor.mark(this); stringCtor.mark(this); diff --git a/src/qml/jsruntime/qv4engine_p.h b/src/qml/jsruntime/qv4engine_p.h index 5e2a6cb50b..b4219a9826 100644 --- a/src/qml/jsruntime/qv4engine_p.h +++ b/src/qml/jsruntime/qv4engine_p.h @@ -269,6 +269,7 @@ public: StringValue id_byteLength; StringValue id_byteOffset; StringValue id_buffer; + StringValue id_lastIndex; QSet compilationUnits; @@ -308,8 +309,8 @@ public: Heap::Object *newObject(); Heap::Object *newObject(InternalClass *internalClass); - Returned *newString(const QString &s); - String *newIdentifier(const QString &text); + Heap::String *newString(const QString &s); + Heap::String *newIdentifier(const QString &text); Heap::Object *newStringObject(const ValueRef value); Heap::Object *newNumberObject(const ValueRef value); diff --git a/src/qml/jsruntime/qv4errorobject.cpp b/src/qml/jsruntime/qv4errorobject.cpp index b3830d82b9..7fe0574d6b 100644 --- a/src/qml/jsruntime/qv4errorobject.cpp +++ b/src/qml/jsruntime/qv4errorobject.cpp @@ -165,7 +165,7 @@ ReturnedValue ErrorObject::method_get_stack(CallContext *ctx) trace += QString::number(frame.line); } } - This->d()->stack = ctx->d()->engine->newString(trace)->getPointer()->d(); + This->d()->stack = ctx->d()->engine->newString(trace); } return This->d()->stack->asReturnedValue(); } diff --git a/src/qml/jsruntime/qv4function.cpp b/src/qml/jsruntime/qv4function.cpp index 48be89b40a..aedbff21be 100644 --- a/src/qml/jsruntime/qv4function.cpp +++ b/src/qml/jsruntime/qv4function.cpp @@ -66,7 +66,7 @@ Function::Function(ExecutionEngine *engine, CompiledData::CompilationUnit *unit, break; } // duplicate arguments, need some trick to store them - arg = (s = engine->memoryManager->alloc(engine, arg->d(), engine->newString(QString(0xfffe))->getPointer()->d())).getPointer(); + arg = (s = engine->memoryManager->alloc(engine, arg->d(), engine->newString(QString(0xfffe)))).getPointer(); } } diff --git a/src/qml/jsruntime/qv4functionobject.cpp b/src/qml/jsruntime/qv4functionobject.cpp index 59c5c43ccb..79f179760d 100644 --- a/src/qml/jsruntime/qv4functionobject.cpp +++ b/src/qml/jsruntime/qv4functionobject.cpp @@ -213,9 +213,9 @@ ReturnedValue FunctionCtor::construct(Managed *that, CallData *callData) for (int i = 0; i < callData->argc - 1; ++i) { if (i) arguments += QLatin1String(", "); - arguments += callData->args[i].toString(ctx)->toQString(); + arguments += callData->args[i].toQString(); } - body = callData->args[callData->argc - 1].toString(ctx)->toQString(); + body = callData->args[callData->argc - 1].toQString(); } if (ctx->d()->engine->hasException) return Encode::undefined(); diff --git a/src/qml/jsruntime/qv4globalobject.cpp b/src/qml/jsruntime/qv4globalobject.cpp index 5baee5f4aa..f287fc7aec 100644 --- a/src/qml/jsruntime/qv4globalobject.cpp +++ b/src/qml/jsruntime/qv4globalobject.cpp @@ -435,13 +435,12 @@ static inline int toInt(const QChar &qc, int R) ReturnedValue GlobalFunctions::method_parseInt(CallContext *ctx) { Scope scope(ctx); - ScopedValue string(scope, ctx->argument(0)); + ScopedValue inputString(scope, ctx->argument(0)); ScopedValue radix(scope, ctx->argument(1)); int R = radix->isUndefined() ? 0 : radix->toInt32(); // [15.1.2.2] step by step: - String *inputString = string->toString(ctx); // 1 - QString trimmed = inputString->toQString().trimmed(); // 2 + QString trimmed = inputString->toQString().trimmed(); // 1 + 2 if (ctx->d()->engine->hasException) return Encode::undefined(); @@ -578,7 +577,7 @@ ReturnedValue GlobalFunctions::method_decodeURI(CallContext *context) if (context->d()->callData->argc == 0) return Encode::undefined(); - QString uriString = context->d()->callData->args[0].toString(context)->toQString(); + QString uriString = context->d()->callData->args[0].toQString(); bool ok; QString out = decode(uriString, DecodeNonReserved, &ok); if (!ok) { @@ -596,7 +595,7 @@ ReturnedValue GlobalFunctions::method_decodeURIComponent(CallContext *context) if (context->d()->callData->argc == 0) return Encode::undefined(); - QString uriString = context->d()->callData->args[0].toString(context)->toQString(); + QString uriString = context->d()->callData->args[0].toQString(); bool ok; QString out = decode(uriString, DecodeAll, &ok); if (!ok) { @@ -614,7 +613,7 @@ ReturnedValue GlobalFunctions::method_encodeURI(CallContext *context) if (context->d()->callData->argc == 0) return Encode::undefined(); - QString uriString = context->d()->callData->args[0].toString(context)->toQString(); + QString uriString = context->d()->callData->args[0].toQString(); bool ok; QString out = encode(uriString, uriUnescapedReserved, &ok); if (!ok) { @@ -632,7 +631,7 @@ ReturnedValue GlobalFunctions::method_encodeURIComponent(CallContext *context) if (context->d()->callData->argc == 0) return Encode::undefined(); - QString uriString = context->d()->callData->args[0].toString(context)->toQString(); + QString uriString = context->d()->callData->args[0].toQString(); bool ok; QString out = encode(uriString, uriUnescaped, &ok); if (!ok) { @@ -649,7 +648,7 @@ ReturnedValue GlobalFunctions::method_escape(CallContext *context) if (!context->d()->callData->argc) return context->d()->engine->newString(QStringLiteral("undefined"))->asReturnedValue(); - QString str = context->d()->callData->args[0].toString(context)->toQString(); + QString str = context->d()->callData->args[0].toQString(); return context->d()->engine->newString(escape(str))->asReturnedValue(); } @@ -658,6 +657,6 @@ ReturnedValue GlobalFunctions::method_unescape(CallContext *context) if (!context->d()->callData->argc) return context->d()->engine->newString(QStringLiteral("undefined"))->asReturnedValue(); - QString str = context->d()->callData->args[0].toString(context)->toQString(); + QString str = context->d()->callData->args[0].toQString(); return context->d()->engine->newString(unescape(str))->asReturnedValue(); } diff --git a/src/qml/jsruntime/qv4identifier.cpp b/src/qml/jsruntime/qv4identifier.cpp index d7e0e25ddf..3432f8702d 100644 --- a/src/qml/jsruntime/qv4identifier.cpp +++ b/src/qml/jsruntime/qv4identifier.cpp @@ -152,7 +152,7 @@ const Identifier *IdentifierHashBase::toIdentifier(const QString &str) const return d->identifierTable->identifier(str); } -const Identifier *IdentifierHashBase::toIdentifier(String *str) const +const Identifier *IdentifierHashBase::toIdentifier(Heap::String *str) const { Q_ASSERT(d); return d->identifierTable->identifier(str); diff --git a/src/qml/jsruntime/qv4identifier_p.h b/src/qml/jsruntime/qv4identifier_p.h index afed5c646f..a89ac29d2f 100644 --- a/src/qml/jsruntime/qv4identifier_p.h +++ b/src/qml/jsruntime/qv4identifier_p.h @@ -39,6 +39,10 @@ QT_BEGIN_NAMESPACE namespace QV4 { +namespace Heap { + struct String; +} + struct String; struct IdentifierTable; struct ExecutionEngine; @@ -102,7 +106,7 @@ protected: const IdentifierHashEntry *lookup(const QString &str) const; const IdentifierHashEntry *lookup(String *str) const; const Identifier *toIdentifier(const QString &str) const; - const Identifier *toIdentifier(String *str) const; + const Identifier *toIdentifier(Heap::String *str) const; }; diff --git a/src/qml/jsruntime/qv4identifiertable.cpp b/src/qml/jsruntime/qv4identifiertable.cpp index 4dca1b65f1..46e309c7f3 100644 --- a/src/qml/jsruntime/qv4identifiertable.cpp +++ b/src/qml/jsruntime/qv4identifiertable.cpp @@ -53,41 +53,41 @@ IdentifierTable::IdentifierTable(ExecutionEngine *engine) , numBits(8) { alloc = primeForNumBits(numBits); - entries = (String **)malloc(alloc*sizeof(String *)); - memset(entries, 0, alloc*sizeof(String *)); + entries = (Heap::String **)malloc(alloc*sizeof(Heap::String *)); + memset(entries, 0, alloc*sizeof(Heap::String *)); } IdentifierTable::~IdentifierTable() { for (int i = 0; i < alloc; ++i) if (entries[i]) - delete entries[i]->d()->identifier; + delete entries[i]->identifier; free(entries); } -void IdentifierTable::addEntry(String *str) +void IdentifierTable::addEntry(Heap::String *str) { uint hash = str->hashValue(); - if (str->subtype() == Heap::String::StringType_ArrayIndex) + if (str->subtype == Heap::String::StringType_ArrayIndex) return; - str->d()->identifier = new Identifier; - str->d()->identifier->string = str->toQString(); - str->d()->identifier->hashValue = hash; + str->identifier = new Identifier; + str->identifier->string = str->toQString(); + str->identifier->hashValue = hash; bool grow = (alloc <= size*2); if (grow) { ++numBits; int newAlloc = primeForNumBits(numBits); - String **newEntries = (String **)malloc(newAlloc*sizeof(String *)); - memset(newEntries, 0, newAlloc*sizeof(String *)); + Heap::String **newEntries = (Heap::String **)malloc(newAlloc*sizeof(Heap::String *)); + memset(newEntries, 0, newAlloc*sizeof(Heap::String *)); for (int i = 0; i < alloc; ++i) { - String *e = entries[i]; + Heap::String *e = entries[i]; if (!e) continue; - uint idx = e->d()->stringHash % newAlloc; + uint idx = e->stringHash % newAlloc; while (newEntries[idx]) { ++idx; idx %= newAlloc; @@ -110,49 +110,48 @@ void IdentifierTable::addEntry(String *str) -String *IdentifierTable::insertString(const QString &s) +Heap::String *IdentifierTable::insertString(const QString &s) { uint hash = String::createHashValue(s.constData(), s.length()); uint idx = hash % alloc; - while (String *e = entries[idx]) { - if (e->d()->stringHash == hash && e->toQString() == s) + while (Heap::String *e = entries[idx]) { + if (e->stringHash == hash && e->toQString() == s) return e; ++idx; idx %= alloc; } - Returned *_s = engine->newString(s); - String *str = _s->getPointer(); + Heap::String *str = engine->newString(s); addEntry(str); return str; } -Identifier *IdentifierTable::identifierImpl(const String *str) +Identifier *IdentifierTable::identifierImpl(const Heap::String *str) { - if (str->d()->identifier) - return str->d()->identifier; + if (str->identifier) + return str->identifier; uint hash = str->hashValue(); - if (str->subtype() == Heap::String::StringType_ArrayIndex) + if (str->subtype == Heap::String::StringType_ArrayIndex) return 0; uint idx = hash % alloc; - while (String *e = entries[idx]) { - if (e->d()->stringHash == hash && e->isEqualTo(str)) { - str->d()->identifier = e->d()->identifier; - return e->d()->identifier; + while (Heap::String *e = entries[idx]) { + if (e->stringHash == hash && e->isEqualTo(str)) { + str->identifier = e->identifier; + return e->identifier; } ++idx; idx %= alloc; } - addEntry(const_cast(str)); - return str->d()->identifier; + addEntry(const_cast(str)); + return str->identifier; } Identifier *IdentifierTable::identifier(const QString &s) { - return insertString(s)->d()->identifier; + return insertString(s)->identifier; } Identifier *IdentifierTable::identifier(const char *s, int len) @@ -163,16 +162,16 @@ Identifier *IdentifierTable::identifier(const char *s, int len) QLatin1String latin(s, len); uint idx = hash % alloc; - while (String *e = entries[idx]) { - if (e->d()->stringHash == hash && e->toQString() == latin) - return e->d()->identifier; + while (Heap::String *e = entries[idx]) { + if (e->stringHash == hash && e->toQString() == latin) + return e->identifier; ++idx; idx %= alloc; } - String *str = engine->newString(QString::fromLatin1(s, len))->getPointer(); + Heap::String *str = engine->newString(QString::fromLatin1(s, len)); addEntry(str); - return str->d()->identifier; + return str->identifier; } } diff --git a/src/qml/jsruntime/qv4identifiertable_p.h b/src/qml/jsruntime/qv4identifiertable_p.h index cc792fa3b4..fe88584c2e 100644 --- a/src/qml/jsruntime/qv4identifiertable_p.h +++ b/src/qml/jsruntime/qv4identifiertable_p.h @@ -49,36 +49,39 @@ struct IdentifierTable int alloc; int size; int numBits; - String **entries; + Heap::String **entries; - void addEntry(String *str); + void addEntry(Heap::String *str); public: IdentifierTable(ExecutionEngine *engine); ~IdentifierTable(); - String *insertString(const QString &s); + Heap::String *insertString(const QString &s); - Identifier *identifier(const String *str) { - if (str->d()->identifier) - return str->d()->identifier; + Identifier *identifier(const Heap::String *str) { + if (str->identifier) + return str->identifier; return identifierImpl(str); } + Identifier *identifier(const QV4::String *str) { + return identifier(str->d()); + } Identifier *identifier(const QString &s); Identifier *identifier(const char *s, int len); - Identifier *identifierImpl(const String *str); + Identifier *identifierImpl(const Heap::String *str); void mark(ExecutionEngine *e) { for (int i = 0; i < alloc; ++i) { - String *entry = entries[i]; - if (!entry || entry->markBit()) + Heap::String *entry = entries[i]; + if (!entry || entry->markBit) continue; - entry->d()->markBit = 1; - Q_ASSERT(entry->internalClass()->vtable->markObjects); - entry->internalClass()->vtable->markObjects(entry->d(), e); + entry->markBit = 1; + Q_ASSERT(entry->internalClass->vtable->markObjects); + entry->internalClass->vtable->markObjects(entry, e); } } }; diff --git a/src/qml/jsruntime/qv4include.cpp b/src/qml/jsruntime/qv4include.cpp index 9d6a4ab10a..60ac519dfb 100644 --- a/src/qml/jsruntime/qv4include.cpp +++ b/src/qml/jsruntime/qv4include.cpp @@ -136,6 +136,7 @@ void QV4Include::finished() QV4::Scope scope(v4); QV4::ScopedObject resultObj(scope, m_resultObject.value()); + QV4::ScopedString status(scope, v4->newString(QStringLiteral("status"))); if (m_reply->error() == QNetworkReply::NoError) { QByteArray data = m_reply->readAll(); @@ -146,19 +147,19 @@ void QV4Include::finished() QV4::Script script(v4, qmlglobal, code, m_url.toString()); QV4::ExecutionContext *ctx = v4->currentContext(); - QV4::ScopedString status(scope, v4->newString(QStringLiteral("status"))); script.parse(); if (!scope.engine->hasException) script.run(); if (scope.engine->hasException) { QV4::ScopedValue ex(scope, ctx->catchException()); resultObj->put(status.getPointer(), QV4::ScopedValue(scope, QV4::Primitive::fromInt32(Exception))); - resultObj->put(v4->newString(QStringLiteral("exception"))->getPointer(), ex); + QV4::ScopedString exception(scope, v4->newString(QStringLiteral("exception"))); + resultObj->put(exception.getPointer(), ex); } else { resultObj->put(status.getPointer(), QV4::ScopedValue(scope, QV4::Primitive::fromInt32(Ok))); } } else { - resultObj->put(v4->newString(QStringLiteral("status"))->getPointer(), QV4::ScopedValue(scope, QV4::Primitive::fromInt32(NetworkError))); + resultObj->put(status.getPointer(), QV4::ScopedValue(scope, QV4::Primitive::fromInt32(NetworkError))); } QV4::ScopedValue cb(scope, m_callbackFunction.value()); @@ -226,7 +227,8 @@ QV4::ReturnedValue QV4Include::method_include(QV4::CallContext *ctx) if (scope.engine->hasException) { QV4::ScopedValue ex(scope, ctx->catchException()); result = resultValue(scope.engine, Exception); - result->asObject()->put(scope.engine->newString(QStringLiteral("exception"))->getPointer(), ex); + QV4::ScopedString exception(scope, scope.engine->newString(QStringLiteral("exception"))); + result->asObject()->put(exception.getPointer(), ex); } else { result = resultValue(scope.engine, Ok); } diff --git a/src/qml/jsruntime/qv4internalclass.cpp b/src/qml/jsruntime/qv4internalclass.cpp index 0f8eb2bfff..7247228091 100644 --- a/src/qml/jsruntime/qv4internalclass.cpp +++ b/src/qml/jsruntime/qv4internalclass.cpp @@ -310,7 +310,8 @@ InternalClass *InternalClass::addMemberImpl(String *string, PropertyAttributes d // The incoming string can come from anywhere, so make sure to // store a string in the nameMap that's guaranteed to get // marked properly during GC. - String *name = engine->newIdentifier(string->toQString()); + // #### GC + String *name = reinterpret_cast(engine->newIdentifier(string->toQString())); newClass->nameMap.add(newClass->size, name); newClass->propertyData.add(newClass->size, data); ++newClass->size; diff --git a/src/qml/jsruntime/qv4jsonobject.cpp b/src/qml/jsruntime/qv4jsonobject.cpp index 000ed326cd..69bd97a65d 100644 --- a/src/qml/jsruntime/qv4jsonobject.cpp +++ b/src/qml/jsruntime/qv4jsonobject.cpp @@ -401,7 +401,7 @@ bool JsonParser::parseValue(ValueRef val) return false; DEBUG << "value: string"; END; - val = context->d()->engine->newString(value); + val = Value::fromHeapObject(context->d()->engine->newString(value)); return true; } case BeginArray: { @@ -709,7 +709,7 @@ QString Stringify::Str(const QString &key, ValueRef v) if (!!toJSON) { ScopedCallData callData(scope, 1); callData->thisObject = value; - callData->args[0] = ctx->d()->engine->newString(key); + callData->args[0] = Value::fromHeapObject(ctx->d()->engine->newString(key)); value = toJSON->call(callData); } } @@ -718,7 +718,7 @@ QString Stringify::Str(const QString &key, ValueRef v) ScopedObject holder(scope, ctx->d()->engine->newObject()); holder->put(ctx, QString(), value); ScopedCallData callData(scope, 2); - callData->args[0] = ctx->d()->engine->newString(key); + callData->args[0] = Value::fromHeapObject(ctx->d()->engine->newString(key)); callData->args[1] = value; callData->thisObject = holder; value = replacerFunction->call(callData); @@ -743,7 +743,7 @@ QString Stringify::Str(const QString &key, ValueRef v) if (value->isNumber()) { double d = value->toNumber(); - return std::isfinite(d) ? value->toString(ctx)->toQString() : QStringLiteral("null"); + return std::isfinite(d) ? value->toQString() : QStringLiteral("null"); } o = value.asReturnedValue(); @@ -892,7 +892,7 @@ ReturnedValue JsonObject::method_parse(CallContext *ctx) { Scope scope(ctx); ScopedValue v(scope, ctx->argument(0)); - QString jtext = v->toString(ctx)->toQString(); + QString jtext = v->toQString(); DEBUG << "parsing source = " << jtext; JsonParser parser(ctx, jtext.constData(), jtext.length()); diff --git a/src/qml/jsruntime/qv4qobjectwrapper.cpp b/src/qml/jsruntime/qv4qobjectwrapper.cpp index 58f98fe6ce..0ea43b9b06 100644 --- a/src/qml/jsruntime/qv4qobjectwrapper.cpp +++ b/src/qml/jsruntime/qv4qobjectwrapper.cpp @@ -731,7 +731,10 @@ void QObjectWrapper::advanceIterator(Managed *m, ObjectIterator *it, String *&na const QMetaObject *mo = that->d()->object->metaObject(); const int propertyCount = mo->propertyCount(); if (it->arrayIndex < static_cast(propertyCount)) { - name = that->engine()->newString(QString::fromUtf8(mo->property(it->arrayIndex).name()))->getPointer(); + // #### GC + Scope scope(that->engine()); + ScopedString propName(scope, that->engine()->newString(QString::fromUtf8(mo->property(it->arrayIndex).name()))); + name = propName.getPointer(); ++it->arrayIndex; *attributes = QV4::Attr_Data; p->value = that->get(name); @@ -744,7 +747,10 @@ void QObjectWrapper::advanceIterator(Managed *m, ObjectIterator *it, String *&na ++it->arrayIndex; if (method.access() == QMetaMethod::Private || index == deleteLaterIdx || index == destroyedIdx1 || index == destroyedIdx2) continue; - name = that->engine()->newString(QString::fromUtf8(method.name()))->getPointer(); + // #### GC + Scope scope(that->engine()); + ScopedString methodName(scope, that->engine()->newString(QString::fromUtf8(method.name()))); + name = methodName.getPointer(); *attributes = QV4::Attr_Data; p->value = that->get(name); return; diff --git a/src/qml/jsruntime/qv4regexpobject.cpp b/src/qml/jsruntime/qv4regexpobject.cpp index 44a8b3531e..a73c25c567 100644 --- a/src/qml/jsruntime/qv4regexpobject.cpp +++ b/src/qml/jsruntime/qv4regexpobject.cpp @@ -181,7 +181,7 @@ void RegExpObject::markObjects(Heap::Base *that, ExecutionEngine *e) Property *RegExpObject::lastIndexProperty(ExecutionContext *ctx) { Q_UNUSED(ctx); - Q_ASSERT(0 == internalClass()->find(ctx->d()->engine->newIdentifier(QStringLiteral("lastIndex")))); + Q_ASSERT(0 == internalClass()->find(ctx->d()->engine->id_lastIndex)); return propertyAt(0); } @@ -262,7 +262,7 @@ ReturnedValue RegExpCtor::construct(Managed *m, CallData *callData) QString pattern; if (!r->isUndefined()) - pattern = r->toString(ctx)->toQString(); + pattern = r->toQString(); if (scope.hasException()) return Encode::undefined(); diff --git a/src/qml/jsruntime/qv4runtime.cpp b/src/qml/jsruntime/qv4runtime.cpp index f3e85933a1..57a6524515 100644 --- a/src/qml/jsruntime/qv4runtime.cpp +++ b/src/qml/jsruntime/qv4runtime.cpp @@ -359,7 +359,7 @@ double RuntimeHelpers::stringToNumber(const QString &string) return d; } -Returned *RuntimeHelpers::stringFromNumber(ExecutionEngine *engine, double number) +Heap::String *RuntimeHelpers::stringFromNumber(ExecutionEngine *engine, double number) { QString qstr; RuntimeHelpers::numberToString(&qstr, number, 10); @@ -430,23 +430,23 @@ Heap::Object *RuntimeHelpers::convertToObject(ExecutionEngine *engine, const Val } } -Returned *RuntimeHelpers::convertToString(ExecutionEngine *engine, const ValueRef value) +Heap::String *RuntimeHelpers::convertToString(ExecutionEngine *engine, const ValueRef value) { switch (value->type()) { case Value::Empty_Type: Q_ASSERT(!"empty Value encountered"); case Value::Undefined_Type: - return engine->id_undefined.ret(); + return engine->id_undefined.getPointer()->d(); case Value::Null_Type: - return engine->id_null.ret(); + return engine->id_null.getPointer()->d(); case Value::Boolean_Type: if (value->booleanValue()) - return engine->id_true.ret(); + return engine->id_true.getPointer()->d(); else - return engine->id_false.ret(); + return engine->id_false.getPointer()->d(); case Value::Managed_Type: if (value->isString()) - return value->stringValue()->asReturned(); + return value->stringValue()->d(); { Scope scope(engine); ScopedValue prim(scope, RuntimeHelpers::toPrimitive(value, STRING_HINT)); @@ -461,23 +461,23 @@ Returned *RuntimeHelpers::convertToString(ExecutionEngine *engine, const // This is slightly different from the method above, as // the + operator requires a slightly different conversion -static Returned *convert_to_string_add(ExecutionEngine *engine, const ValueRef value) +static Heap::String *convert_to_string_add(ExecutionEngine *engine, const ValueRef value) { switch (value->type()) { case Value::Empty_Type: Q_ASSERT(!"empty Value encountered"); case Value::Undefined_Type: - return engine->id_undefined.ret(); + return engine->id_undefined.getPointer()->d(); case Value::Null_Type: - return engine->id_null.ret(); + return engine->id_null.getPointer()->d(); case Value::Boolean_Type: if (value->booleanValue()) - return engine->id_true.ret(); + return engine->id_true.getPointer()->d(); else - return engine->id_false.ret(); + return engine->id_false.getPointer()->d(); case Value::Managed_Type: if (value->isString()) - return value->stringValue()->asReturned(); + return value->stringValue()->d(); { Scope scope(engine); ScopedValue prim(scope, RuntimeHelpers::toPrimitive(value, PREFERREDTYPE_HINT)); diff --git a/src/qml/jsruntime/qv4runtime_p.h b/src/qml/jsruntime/qv4runtime_p.h index 24971c695a..6be64aa8ea 100644 --- a/src/qml/jsruntime/qv4runtime_p.h +++ b/src/qml/jsruntime/qv4runtime_p.h @@ -221,12 +221,12 @@ struct Q_QML_PRIVATE_EXPORT RuntimeHelpers { static ReturnedValue toPrimitive(const ValueRef value, int typeHint); static double stringToNumber(const QString &s); - static Returned *stringFromNumber(ExecutionEngine *engine, double number); + static Heap::String *stringFromNumber(ExecutionEngine *engine, double number); static double toNumber(const ValueRef value); static void numberToString(QString *result, double num, int radix = 10); static ReturnedValue toString(ExecutionEngine *engine, const ValueRef value); - static Returned *convertToString(ExecutionEngine *engine, const ValueRef value); + static Heap::String *convertToString(ExecutionEngine *engine, const ValueRef value); static ReturnedValue toObject(ExecutionEngine *engine, const ValueRef value); static Heap::Object *convertToObject(ExecutionEngine *engine, const ValueRef value); diff --git a/src/qml/jsruntime/qv4string.cpp b/src/qml/jsruntime/qv4string.cpp index 945a117364..a06a36d7fd 100644 --- a/src/qml/jsruntime/qv4string.cpp +++ b/src/qml/jsruntime/qv4string.cpp @@ -282,7 +282,7 @@ uint String::toUInt(bool *ok) const *ok = true; if (subtype() == Heap::String::StringType_Unknown) - createHashValue(); + d()->createHashValue(); if (subtype() >= Heap::String::StringType_UInt) return d()->stringHash; @@ -331,6 +331,32 @@ void Heap::String::simplifyString() const largestSubLength = 0; } +void Heap::String::createHashValue() const +{ + if (largestSubLength) + simplifyString(); + Q_ASSERT(!largestSubLength); + const QChar *ch = reinterpret_cast(text->data()); + const QChar *end = ch + text->size; + + // array indices get their number as hash value + bool ok; + stringHash = ::toArrayIndex(ch, end, &ok); + if (ok) { + subtype = (stringHash == UINT_MAX) ? Heap::String::StringType_UInt : Heap::String::StringType_ArrayIndex; + return; + } + + uint h = 0xffffffff; + while (ch < end) { + h = 31 * h + ch->unicode(); + ++ch; + } + + stringHash = h; + subtype = Heap::String::StringType_Regular; +} + void Heap::String::append(const String *data, QChar *ch) { std::vector worklist; @@ -352,31 +378,7 @@ void Heap::String::append(const String *data, QChar *ch) } -void String::createHashValue() const -{ - if (d()->largestSubLength) - d()->simplifyString(); - Q_ASSERT(!d()->largestSubLength); - const QChar *ch = reinterpret_cast(d()->text->data()); - const QChar *end = ch + d()->text->size; - // array indices get their number as hash value - bool ok; - d()->stringHash = ::toArrayIndex(ch, end, &ok); - if (ok) { - setSubtype((d()->stringHash == UINT_MAX) ? Heap::String::StringType_UInt : Heap::String::StringType_ArrayIndex); - return; - } - - uint h = 0xffffffff; - while (ch < end) { - h = 31 * h + ch->unicode(); - ++ch; - } - - d()->stringHash = h; - setSubtype(Heap::String::StringType_Regular); -} uint String::createHashValue(const QChar *ch, int length) { diff --git a/src/qml/jsruntime/qv4string_p.h b/src/qml/jsruntime/qv4string_p.h index 69c9a0f892..989398883e 100644 --- a/src/qml/jsruntime/qv4string_p.h +++ b/src/qml/jsruntime/qv4string_p.h @@ -67,6 +67,35 @@ struct Q_QML_PRIVATE_EXPORT String : Base { len == (uint)text->size); return len; } + void createHashValue() const; + inline unsigned hashValue() const { + if (subtype == StringType_Unknown) + createHashValue(); + Q_ASSERT(!largestSubLength); + + return stringHash; + } + inline QString toQString() const { + if (largestSubLength) + simplifyString(); + QStringDataPtr ptr = { text }; + text->ref.ref(); + return QString(ptr); + } + inline bool isEqualTo(const String *other) const { + if (this == other) + return true; + if (hashValue() != other->hashValue()) + return false; + Q_ASSERT(!largestSubLength); + if (identifier && identifier == other->identifier) + return true; + if (subtype >= Heap::String::StringType_UInt && subtype == other->subtype) + return true; + + return toQString() == other->toQString(); + } + union { mutable QStringData *text; mutable String *left; @@ -96,17 +125,7 @@ struct Q_QML_PRIVATE_EXPORT String : public Managed { bool equals(String *other) const; inline bool isEqualTo(const String *other) const { - if (this == other) - return true; - if (hashValue() != other->hashValue()) - return false; - Q_ASSERT(!d()->largestSubLength); - if (d()->identifier && d()->identifier == other->d()->identifier) - return true; - if (subtype() >= Heap::String::StringType_UInt && subtype() == other->subtype()) - return true; - - return toQString() == other->toQString(); + return d()->isEqualTo(other->d()); } inline bool compare(const String *other) { @@ -114,23 +133,15 @@ struct Q_QML_PRIVATE_EXPORT String : public Managed { } inline QString toQString() const { - if (d()->largestSubLength) - d()->simplifyString(); - QStringDataPtr ptr = { d()->text }; - d()->text->ref.ref(); - return QString(ptr); + return d()->toQString(); } inline unsigned hashValue() const { - if (subtype() == Heap::String::StringType_Unknown) - createHashValue(); - Q_ASSERT(!d()->largestSubLength); - - return d()->stringHash; + return d()->hashValue(); } uint asArrayIndex() const { if (subtype() == Heap::String::StringType_Unknown) - createHashValue(); + d()->createHashValue(); Q_ASSERT(!d()->largestSubLength); if (subtype() == Heap::String::StringType_ArrayIndex) return d()->stringHash; @@ -146,7 +157,6 @@ struct Q_QML_PRIVATE_EXPORT String : public Managed { void makeIdentifierImpl() const; - void createHashValue() const; static uint createHashValue(const QChar *ch, int length); static uint createHashValue(const char *ch, int length); diff --git a/src/qml/jsruntime/qv4stringobject.cpp b/src/qml/jsruntime/qv4stringobject.cpp index a21f2b284a..b9fb8812ea 100644 --- a/src/qml/jsruntime/qv4stringobject.cpp +++ b/src/qml/jsruntime/qv4stringobject.cpp @@ -309,7 +309,7 @@ ReturnedValue StringPrototype::method_indexOf(CallContext *context) QString searchString; if (context->d()->callData->argc) - searchString = context->d()->callData->args[0].toString(context)->toQString(); + searchString = context->d()->callData->args[0].toQString(); int pos = 0; if (context->d()->callData->argc > 1) @@ -480,7 +480,7 @@ ReturnedValue StringPrototype::method_replace(CallContext *ctx) if (StringObject *thisString = ctx->d()->callData->thisObject.asStringObject()) string = thisString->d()->value.stringValue()->toQString(); else - string = ctx->d()->callData->thisObject.toString(ctx)->toQString(); + string = ctx->d()->callData->thisObject.toQString(); int numCaptures = 0; int numStringMatches = 0; @@ -522,7 +522,7 @@ ReturnedValue StringPrototype::method_replace(CallContext *ctx) numCaptures = regExp->value()->captureCount(); } else { numCaptures = 1; - QString searchString = searchValue->toString(ctx)->toQString(); + QString searchString = searchValue->toQString(); int idx = string.indexOf(searchString); if (idx != -1) { numStringMatches = 1; @@ -556,16 +556,16 @@ ReturnedValue StringPrototype::method_replace(CallContext *ctx) Q_ASSERT(matchStart >= static_cast(lastEnd)); uint matchEnd = matchOffsets[i * numCaptures * 2 + 1]; callData->args[numCaptures] = Primitive::fromUInt32(matchStart); - callData->args[numCaptures + 1] = ctx->d()->engine->newString(string); + callData->args[numCaptures + 1] = Value::fromHeapObject(ctx->d()->engine->newString(string)); replacement = searchCallback->call(callData); result += string.midRef(lastEnd, matchStart - lastEnd); - result += replacement->toString(ctx)->toQString(); + result += replacement->toQString(); lastEnd = matchEnd; } result += string.midRef(lastEnd); } else { - QString newString = replaceValue->toString(ctx)->toQString(); + QString newString = replaceValue->toQString(); result.reserve(string.length() + numStringMatches*newString.size()); int lastEnd = 0; @@ -704,7 +704,7 @@ ReturnedValue StringPrototype::method_split(CallContext *ctx) if (array->getLength() < limit) array->push_back((s = ctx->d()->engine->newString(text.mid(offset)))); } else { - QString separator = separatorValue->toString(ctx)->toQString(); + QString separator = separatorValue->toQString(); if (separator.isEmpty()) { for (uint i = 0; i < qMin(limit, uint(text.length())); ++i) array->push_back((s = ctx->d()->engine->newString(text.mid(i, 1)))); diff --git a/src/qml/jsruntime/qv4value.cpp b/src/qml/jsruntime/qv4value.cpp index 410fa6482e..0600a82525 100644 --- a/src/qml/jsruntime/qv4value.cpp +++ b/src/qml/jsruntime/qv4value.cpp @@ -267,14 +267,14 @@ double Primitive::toInteger(double number) } #ifndef V4_BOOTSTRAP -String *Value::toString(ExecutionEngine *e) const +Heap::String *Value::toString(ExecutionEngine *e) const { if (isString()) - return stringValue(); - return RuntimeHelpers::convertToString(e, ValueRef::fromRawValue(this))->getPointer(); + return stringValue()->d(); + return RuntimeHelpers::convertToString(e, ValueRef::fromRawValue(this)); } -String *Value::toString(ExecutionContext *ctx) const +Heap::String *Value::toString(ExecutionContext *ctx) const { return toString(ctx->engine()); } diff --git a/src/qml/jsruntime/qv4value_p.h b/src/qml/jsruntime/qv4value_p.h index 5126d4f0d7..a3b08ba865 100644 --- a/src/qml/jsruntime/qv4value_p.h +++ b/src/qml/jsruntime/qv4value_p.h @@ -343,8 +343,8 @@ struct Q_QML_PRIVATE_EXPORT Value double toNumberImpl() const; QString toQStringNoThrow() const; QString toQString() const; - String *toString(ExecutionEngine *e) const; - String *toString(ExecutionContext *ctx) const; + Heap::String *toString(ExecutionEngine *e) const; + Heap::String *toString(ExecutionContext *ctx) const; Heap::Object *toObject(ExecutionEngine *e) const; Heap::Object *toObject(ExecutionContext *ctx) const; @@ -466,6 +466,7 @@ struct TypedValue : public Value #if QT_POINTER_SIZE == 4 tag = Managed_Type; #endif + return *this; } TypedValue &operator =(T *t); TypedValue &operator =(const Scoped &v); -- cgit v1.2.3