Ported ExecutionEngine::newString and newIdentifier to Heap::String
Avoid the use of Returned<String> 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 <lars.knoll@digia.com>
This commit is contained in:
parent
faf13a3aa0
commit
afbf1f74af
|
@ -68,8 +68,10 @@ QV4::Function *CompilationUnit::linkToEngine(ExecutionEngine *engine)
|
|||
runtimeStrings = (QV4::String **)malloc(data->stringTableSize * sizeof(QV4::String*));
|
||||
// memset the strings to 0 in case a GC run happens while we're within the loop below
|
||||
memset(runtimeStrings, 0, data->stringTableSize * sizeof(QV4::String*));
|
||||
for (uint i = 0; i < data->stringTableSize; ++i)
|
||||
runtimeStrings[i] = engine->newIdentifier(data->stringAt(i));
|
||||
for (uint i = 0; i < data->stringTableSize; ++i) {
|
||||
// #### GC
|
||||
runtimeStrings[i] = reinterpret_cast<QV4::String*>(engine->newIdentifier(data->stringAt(i)));
|
||||
}
|
||||
|
||||
runtimeRegularExpressions = new QV4::Value[data->regexpTableSize];
|
||||
// memset the regexps to 0 in case a GC run happens while we're within the loop below
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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<String> *ExecutionEngine::newString(const QString &s)
|
||||
Heap::String *ExecutionEngine::newString(const QString &s)
|
||||
{
|
||||
Scope scope(this);
|
||||
return ScopedString(scope, memoryManager->alloc<String>(this, s))->asReturned<String>();
|
||||
return ScopedString(scope, memoryManager->alloc<String>(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);
|
||||
|
|
|
@ -269,6 +269,7 @@ public:
|
|||
StringValue id_byteLength;
|
||||
StringValue id_byteOffset;
|
||||
StringValue id_buffer;
|
||||
StringValue id_lastIndex;
|
||||
|
||||
QSet<CompiledData::CompilationUnit*> compilationUnits;
|
||||
|
||||
|
@ -308,8 +309,8 @@ public:
|
|||
Heap::Object *newObject();
|
||||
Heap::Object *newObject(InternalClass *internalClass);
|
||||
|
||||
Returned<String> *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);
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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<String>(engine, arg->d(), engine->newString(QString(0xfffe))->getPointer()->d())).getPointer();
|
||||
arg = (s = engine->memoryManager->alloc<String>(engine, arg->d(), engine->newString(QString(0xfffe)))).getPointer();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -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<String> *_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<QV4::String *>(str));
|
||||
return str->d()->identifier;
|
||||
addEntry(const_cast<QV4::Heap::String *>(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;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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<String*>(engine->newIdentifier(string->toQString()));
|
||||
newClass->nameMap.add(newClass->size, name);
|
||||
newClass->propertyData.add(newClass->size, data);
|
||||
++newClass->size;
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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<uint>(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;
|
||||
|
|
|
@ -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();
|
||||
|
||||
|
|
|
@ -359,7 +359,7 @@ double RuntimeHelpers::stringToNumber(const QString &string)
|
|||
return d;
|
||||
}
|
||||
|
||||
Returned<String> *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<String> *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<String>();
|
||||
return value->stringValue()->d();
|
||||
{
|
||||
Scope scope(engine);
|
||||
ScopedValue prim(scope, RuntimeHelpers::toPrimitive(value, STRING_HINT));
|
||||
|
@ -461,23 +461,23 @@ Returned<String> *RuntimeHelpers::convertToString(ExecutionEngine *engine, const
|
|||
|
||||
// This is slightly different from the method above, as
|
||||
// the + operator requires a slightly different conversion
|
||||
static Returned<String> *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<String>();
|
||||
return value->stringValue()->d();
|
||||
{
|
||||
Scope scope(engine);
|
||||
ScopedValue prim(scope, RuntimeHelpers::toPrimitive(value, PREFERREDTYPE_HINT));
|
||||
|
|
|
@ -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<String> *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<String> *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);
|
||||
|
|
|
@ -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<const QChar *>(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<const String *> 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<const QChar *>(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)
|
||||
{
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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<uint>(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))));
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
|
|
|
@ -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<T> &v);
|
||||
|
|
|
@ -376,9 +376,9 @@ QV4::ReturnedValue QQmlNumberExtension::method_toLocaleString(QV4::CallContext *
|
|||
if (ctx->d()->callData->argc > 1) {
|
||||
if (!ctx->d()->callData->args[1].isString())
|
||||
V4THROW_ERROR("Locale: Number.toLocaleString(): Invalid arguments");
|
||||
QV4::String *fs = ctx->d()->callData->args[1].toString(ctx);
|
||||
if (fs->d()->length())
|
||||
format = fs->toQString().at(0).unicode();
|
||||
QString fs = ctx->d()->callData->args[1].toQString();
|
||||
if (fs.length())
|
||||
format = fs.at(0).unicode();
|
||||
}
|
||||
int prec = 2;
|
||||
if (ctx->d()->callData->argc > 2) {
|
||||
|
@ -440,12 +440,12 @@ QV4::ReturnedValue QQmlNumberExtension::method_fromLocaleString(QV4::CallContext
|
|||
numberIdx = 1;
|
||||
}
|
||||
|
||||
QV4::String *ns = ctx->d()->callData->args[numberIdx].toString(ctx);
|
||||
if (!ns->d()->length())
|
||||
QString ns = ctx->d()->callData->args[numberIdx].toQString();
|
||||
if (!ns.length())
|
||||
return QV4::Encode(Q_QNAN);
|
||||
|
||||
bool ok = false;
|
||||
double val = locale.toDouble(ns->toQString(), &ok);
|
||||
double val = locale.toDouble(ns, &ok);
|
||||
|
||||
if (!ok)
|
||||
V4THROW_ERROR("Locale: Number.fromLocaleString(): Invalid format")
|
||||
|
|
|
@ -740,7 +740,7 @@ bool QV8Engine::metaTypeFromJS(const QV4::ValueRef value, int type, void *data)
|
|||
if (value->isUndefined() || value->isNull())
|
||||
*reinterpret_cast<QString*>(data) = QString();
|
||||
else
|
||||
*reinterpret_cast<QString*>(data) = value->toString(m_v4Engine->currentContext())->toQString();
|
||||
*reinterpret_cast<QString*>(data) = value->toQString();
|
||||
return true;
|
||||
case QMetaType::Float:
|
||||
*reinterpret_cast<float*>(data) = value->toNumber();
|
||||
|
|
Loading…
Reference in New Issue