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:
Simon Hausmann 2014-11-11 15:08:30 +01:00 committed by Simon Hausmann
parent faf13a3aa0
commit afbf1f74af
27 changed files with 200 additions and 168 deletions

View File

@ -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

View File

@ -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();
}
}

View File

@ -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)

View File

@ -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);

View File

@ -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);

View File

@ -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();
}

View File

@ -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();
}
}

View File

@ -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();

View File

@ -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();
}

View File

@ -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);

View File

@ -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;
};

View File

@ -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;
}
}

View File

@ -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);
}
}
};

View File

@ -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);
}

View File

@ -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;

View File

@ -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());

View File

@ -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;

View File

@ -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();

View File

@ -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));

View File

@ -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);

View File

@ -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)
{

View File

@ -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);

View File

@ -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))));

View File

@ -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());
}

View File

@ -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);

View File

@ -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")

View File

@ -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();