Add an identifier cache

This is very similar to the old string cache with a slight
twist:

Only strings we know will be used as identifiers (property names)
get entered into the cache. These are then also persistent and
won't ever get collected.

Change-Id: Id441694ef9faf30a87433ae22eb833d1db1d84f1
Reviewed-by: Simon Hausmann <simon.hausmann@digia.com>
This commit is contained in:
Lars Knoll 2013-01-30 14:56:40 +01:00 committed by Simon Hausmann
parent a49e2acc5a
commit 38094f774b
21 changed files with 229 additions and 77 deletions

View File

@ -149,7 +149,7 @@ static void showException(QQmlJS::VM::ExecutionContext *ctx)
std::cerr << qPrintable(msg->buildFullMessage(ctx)->toQString()) << std::endl;
}
} else {
std::cerr << "Uncaught exception: " << qPrintable(e->__get__(ctx, ctx->engine->identifier(QStringLiteral("message")), 0).toString(ctx)->toQString()) << std::endl;
std::cerr << "Uncaught exception: " << qPrintable(e->__get__(ctx, ctx->engine->newString(QStringLiteral("message")), 0).toString(ctx)->toQString()) << std::endl;
}
}
@ -167,7 +167,7 @@ int executeLLVMCode(void *codePtr)
VM::ExecutionContext *ctx = vm.rootContext;
QQmlJS::VM::Object *globalObject = vm.globalObject.objectValue();
globalObject->__put__(ctx, vm.identifier(QStringLiteral("print")),
globalObject->__put__(ctx, vm.newIdentifier(QStringLiteral("print")),
QQmlJS::VM::Value::fromObject(new (ctx->engine->memoryManager) builtins::Print(ctx)));
void * buf = __qmljs_create_exception_handler(ctx);
@ -371,16 +371,16 @@ int main(int argc, char *argv[])
QQmlJS::VM::Object *globalObject = vm.globalObject.objectValue();
QQmlJS::VM::Object *print = new (ctx->engine->memoryManager) builtins::Print(ctx);
print->prototype = ctx->engine->objectPrototype;
globalObject->__put__(ctx, vm.identifier(QStringLiteral("print")),
globalObject->__put__(ctx, vm.newIdentifier(QStringLiteral("print")),
QQmlJS::VM::Value::fromObject(print));
QQmlJS::VM::Object *gc = new (ctx->engine->memoryManager) builtins::GC(ctx);
gc->prototype = ctx->engine->objectPrototype;
globalObject->__put__(ctx, vm.identifier(QStringLiteral("gc")),
globalObject->__put__(ctx, vm.newIdentifier(QStringLiteral("gc")),
QQmlJS::VM::Value::fromObject(gc));
bool errorInTestHarness = false;
if (!qgetenv("IN_TEST_HARNESS").isEmpty())
globalObject->__put__(ctx, vm.identifier(QStringLiteral("$ERROR")),
globalObject->__put__(ctx, vm.newIdentifier(QStringLiteral("$ERROR")),
QQmlJS::VM::Value::fromObject(new (ctx->engine->memoryManager) builtins::TestHarnessError(ctx, errorInTestHarness)));
foreach (const QString &fn, args) {

View File

@ -969,7 +969,7 @@ uchar *InstructionSelection::squeezeCode() const
VM::String *InstructionSelection::identifier(const QString &s)
{
VM::String *str = engine()->identifier(s);
VM::String *str = engine()->newIdentifier(s);
_vmFunction->identifiers.append(str);
return str;
}

View File

@ -56,6 +56,7 @@
#include <qv4dateobject.h>
#include <qv4jsonobject.h>
#include <qv4stringobject.h>
#include <qv4identifier.h>
namespace QQmlJS {
namespace VM {
@ -72,24 +73,26 @@ ExecutionEngine::ExecutionEngine(EvalISelFactory *factory)
memoryManager->setExecutionEngine(this);
identifierCache = new Identifiers(this);
rootContext = newContext();
rootContext->init(this);
current = rootContext;
id_length = identifier(QStringLiteral("length"));
id_prototype = identifier(QStringLiteral("prototype"));
id_constructor = identifier(QStringLiteral("constructor"));
id_arguments = identifier(QStringLiteral("arguments"));
id_caller = identifier(QStringLiteral("caller"));
id_this = identifier(QStringLiteral("this"));
id___proto__ = identifier(QStringLiteral("__proto__"));
id_enumerable = identifier(QStringLiteral("enumerable"));
id_configurable = identifier(QStringLiteral("configurable"));
id_writable = identifier(QStringLiteral("writable"));
id_value = identifier(QStringLiteral("value"));
id_get = identifier(QStringLiteral("get"));
id_set = identifier(QStringLiteral("set"));
id_eval = identifier(QStringLiteral("eval"));
id_length = newIdentifier(QStringLiteral("length"));
id_prototype = newIdentifier(QStringLiteral("prototype"));
id_constructor = newIdentifier(QStringLiteral("constructor"));
id_arguments = newIdentifier(QStringLiteral("arguments"));
id_caller = newIdentifier(QStringLiteral("caller"));
id_this = newIdentifier(QStringLiteral("this"));
id___proto__ = newIdentifier(QStringLiteral("__proto__"));
id_enumerable = newIdentifier(QStringLiteral("enumerable"));
id_configurable = newIdentifier(QStringLiteral("configurable"));
id_writable = newIdentifier(QStringLiteral("writable"));
id_value = newIdentifier(QStringLiteral("value"));
id_get = newIdentifier(QStringLiteral("get"));
id_set = newIdentifier(QStringLiteral("set"));
id_eval = newIdentifier(QStringLiteral("eval"));
objectPrototype = new (memoryManager) ObjectPrototype();
stringPrototype = new (memoryManager) StringPrototype(rootContext);
@ -229,14 +232,9 @@ ExecutionContext *ExecutionEngine::newContext()
return new ExecutionContext();
}
String *ExecutionEngine::identifier(const QString &s)
{
return new (memoryManager) String(s);
}
Function *ExecutionEngine::newFunction(const QString &name)
{
VM::Function *f = new VM::Function(identifier(name));
VM::Function *f = new VM::Function(newIdentifier(name));
functions.append(f);
return f;
}
@ -287,6 +285,13 @@ String *ExecutionEngine::newString(const QString &s)
return new (memoryManager) String(s);
}
String *ExecutionEngine::newIdentifier(const QString &text)
{
return identifierCache->insert(text);
}
Object *ExecutionEngine::newStringObject(ExecutionContext *ctx, const Value &value)
{
StringObject *object = new (memoryManager) StringObject(ctx, value);
@ -456,6 +461,8 @@ void ExecutionEngine::requireArgumentsAccessors(int n)
void ExecutionEngine::markObjects()
{
identifierCache->mark();
globalObject.mark();
if (globalCode)

View File

@ -92,6 +92,7 @@ struct SyntaxErrorPrototype;
struct TypeErrorPrototype;
struct URIErrorPrototype;
struct EvalFunction;
struct Identifiers;
class RegExp;
@ -103,6 +104,8 @@ struct Q_V4_EXPORT ExecutionEngine
ExecutionContext *rootContext;
WTF::BumpPointerAllocator bumperPointerAllocator; // Used by Yarr Regex engine.
Identifiers *identifierCache;
Debugging::Debugger *debugger;
Value globalObject;
@ -177,8 +180,6 @@ struct Q_V4_EXPORT ExecutionEngine
ExecutionContext *newContext();
String *identifier(const QString &s);
VM::Function *newFunction(const QString &name);
FunctionObject *newBuiltinFunction(ExecutionContext *scope, String *name, Value (*code)(ExecutionContext *));
@ -190,6 +191,9 @@ struct Q_V4_EXPORT ExecutionEngine
FunctionObject *newObjectCtor(ExecutionContext *ctx);
String *newString(const QString &s);
String *newIdentifier(const QString &text);
Object *newStringObject(ExecutionContext *ctx, const Value &value);
FunctionObject *newStringCtor(ExecutionContext *ctx);

View File

@ -146,47 +146,47 @@ Function *__qmljs_register_function(ExecutionContext *ctx, String *name,
Value __qmljs_string_literal_undefined(ExecutionContext *ctx)
{
return Value::fromString(ctx->engine->identifier(QStringLiteral("undefined")));
return Value::fromString(ctx->engine->newString(QStringLiteral("undefined")));
}
Value __qmljs_string_literal_null(ExecutionContext *ctx)
{
return Value::fromString(ctx->engine->identifier(QStringLiteral("null")));
return Value::fromString(ctx->engine->newString(QStringLiteral("null")));
}
Value __qmljs_string_literal_true(ExecutionContext *ctx)
{
return Value::fromString(ctx->engine->identifier(QStringLiteral("true")));
return Value::fromString(ctx->engine->newString(QStringLiteral("true")));
}
Value __qmljs_string_literal_false(ExecutionContext *ctx)
{
return Value::fromString(ctx->engine->identifier(QStringLiteral("false")));
return Value::fromString(ctx->engine->newString(QStringLiteral("false")));
}
Value __qmljs_string_literal_object(ExecutionContext *ctx)
{
return Value::fromString(ctx->engine->identifier(QStringLiteral("object")));
return Value::fromString(ctx->engine->newString(QStringLiteral("object")));
}
Value __qmljs_string_literal_boolean(ExecutionContext *ctx)
{
return Value::fromString(ctx->engine->identifier(QStringLiteral("boolean")));
return Value::fromString(ctx->engine->newString(QStringLiteral("boolean")));
}
Value __qmljs_string_literal_number(ExecutionContext *ctx)
{
return Value::fromString(ctx->engine->identifier(QStringLiteral("number")));
return Value::fromString(ctx->engine->newString(QStringLiteral("number")));
}
Value __qmljs_string_literal_string(ExecutionContext *ctx)
{
return Value::fromString(ctx->engine->identifier(QStringLiteral("string")));
return Value::fromString(ctx->engine->newString(QStringLiteral("string")));
}
Value __qmljs_string_literal_function(ExecutionContext *ctx)
{
return Value::fromString(ctx->engine->identifier(QStringLiteral("function")));
return Value::fromString(ctx->engine->newString(QStringLiteral("function")));
}
Value __qmljs_delete_subscript(ExecutionContext *ctx, Value base, Value index)
@ -448,7 +448,7 @@ String *__qmljs_string_from_utf8(ExecutionContext *ctx, const char *s)
String *__qmljs_identifier_from_utf8(ExecutionContext *ctx, const char *s)
{
return ctx->engine->identifier(QString::fromUtf8(s));
return ctx->engine->newString(QString::fromUtf8(s));
}
int __qmljs_string_length(ExecutionContext *, String *string)
@ -513,8 +513,8 @@ Value __qmljs_object_default_value(ExecutionContext *ctx, Value object, int type
typeHint = NUMBER_HINT;
}
String *meth1 = ctx->engine->identifier("toString");
String *meth2 = ctx->engine->identifier("valueOf");
String *meth1 = ctx->engine->newString("toString");
String *meth2 = ctx->engine->newString("valueOf");
if (typeHint == NUMBER_HINT)
qSwap(meth1, meth2);

View File

@ -188,7 +188,7 @@ Value ArrayPrototype::method_join(ExecutionContext *ctx)
//
// crazy!
//
Value r6 = self.property(ctx, ctx->engine->identifier(QStringLiteral("0")));
Value r6 = self.property(ctx, ctx->engine->newString(QStringLiteral("0")));
if (!(r6.isUndefined() || r6.isNull()))
R = r6.toString(ctx)->toQString();

View File

@ -1304,7 +1304,7 @@ Value DatePrototype::method_toJSON(ExecutionContext *ctx)
if (tv.isNumber() && !std::isfinite(tv.toNumber(ctx)))
return Value::nullValue();
FunctionObject *toIso = O.objectValue()->__get__(ctx, ctx->engine->identifier(QStringLiteral("toISOString"))).asFunctionObject();
FunctionObject *toIso = O.objectValue()->__get__(ctx, ctx->engine->newString(QStringLiteral("toISOString"))).asFunctionObject();
if (!toIso)
__qmljs_throw_type_error(ctx);

View File

@ -79,7 +79,7 @@ ErrorObject::ErrorObject(ExecutionEngine* engine, const Value &message)
subtype = Error;
if (message.type() != Value::Undefined_Type)
defineDefaultProperty(engine->identifier(QStringLiteral("message")), message);
defineDefaultProperty(engine->newString(QStringLiteral("message")), message);
}
void ErrorObject::setNameProperty(ExecutionContext *ctx)

110
src/v4/qv4identifier.h Normal file
View File

@ -0,0 +1,110 @@
/****************************************************************************
**
** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of the V4VM module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia. For licensing terms and
** conditions see http://qt.digia.com/licensing. For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights. These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3.0 as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU General Public License version 3.0 requirements will be
** met: http://www.gnu.org/copyleft/gpl.html.
**
**
** $QT_END_LICENSE$
**
****************************************************************************/
#ifndef QV4IDENTIFIER_H
#define QV4IDENTIFIER_H
#include <qv4string.h>
#include <qmljs_engine.h>
#include <limits.h>
namespace QQmlJS {
namespace VM {
struct Identifiers
{
ExecutionEngine *engine;
uint currentIndex;
QHash<QString, String *> identifiers;
public:
Identifiers(ExecutionEngine *engine) : engine(engine), currentIndex(0) {}
String *insert(const QString &s)
{
QHash<QString, String*>::const_iterator it = identifiers.find(s);
if (it != identifiers.constEnd())
return it.value();
String *str = engine->newString(s);
str->createHashValue();
if (str->subtype == String::StringType_ArrayIndex)
return str;
str->stringIdentifier = currentIndex;
if (currentIndex <= USHRT_MAX) {
str->subtype = String::StringType_Identifier;
++currentIndex;
identifiers.insert(s, str);
}
return str;
}
void toIdentifier(String *s) {
if (s->subtype >= String::StringType_Identifier)
return;
if (s->subtype == String::StringType_Unknown)
s->createHashValue();
if (s->subtype >= String::StringType_Identifier)
return;
QHash<QString, String*>::const_iterator it = identifiers.find(s->toQString());
if (it != identifiers.constEnd()) {
s->subtype = String::StringType_Identifier;
s->stringIdentifier = (*it)->stringIdentifier;
return;
}
s->stringIdentifier = currentIndex;
if (currentIndex <= USHRT_MAX) {
s->subtype = String::StringType_Identifier;
++currentIndex;
identifiers.insert(s->toQString(), s);
}
}
void mark() {
for (QHash<QString, String *>::const_iterator it = identifiers.constBegin(); it != identifiers.constEnd(); ++it)
(*it)->mark();
}
};
}
}
#endif

View File

@ -793,7 +793,7 @@ void InstructionSelection::callSubscript(IR::Temp *base, IR::Temp *index, IR::Ex
String *InstructionSelection::identifier(const QString &s)
{
String *str = engine()->identifier(s);
String *str = engine()->newIdentifier(s);
_vmFunction->identifiers.append(str);
return str;
}

View File

@ -46,10 +46,10 @@ VM::Function *EvalInstructionSelection::createFunctionMapping(VM::ExecutionEngin
foreach (const QString *formal, irFunction->formals)
if (formal)
vmFunction->formals.append(engine->identifier(*formal));
vmFunction->formals.append(engine->newString(*formal));
foreach (const QString *local, irFunction->locals)
if (local)
vmFunction->locals.append(engine->identifier(*local));
vmFunction->locals.append(engine->newString(*local));
foreach (IR::Function *function, irFunction->nestedFunctions)
createFunctionMapping(engine, function);

View File

@ -282,7 +282,7 @@ bool Parser::parseMember(Object *o)
if (!parseValue(&val))
return false;
PropertyDescriptor *p = o->members->insert(context->engine->identifier(key));
PropertyDescriptor *p = o->members->insert(context->engine->newIdentifier(key));
p->value = val;
END;
@ -702,7 +702,7 @@ QString Stringify::Str(const QString &key, Value value)
QString result;
if (Object *o = value.asObject()) {
FunctionObject *toJSON = o->__get__(ctx, ctx->engine->identifier(QStringLiteral("toJSON"))).asFunctionObject();
FunctionObject *toJSON = o->__get__(ctx, ctx->engine->newString(QStringLiteral("toJSON"))).asFunctionObject();
if (toJSON) {
Value arg = Value::fromString(ctx, key);
value = toJSON->call(ctx, value, &arg, 1);

View File

@ -161,7 +161,7 @@ protected:
quintptr strictMode : 1; // used by FunctionObject
quintptr type : 5;
mutable quintptr subtype : 3;
quintptr stringIdentifier : 16;
mutable quintptr stringIdentifier : 16;
#if CPU(X86_64)
quintptr unused : 32;
#endif
@ -171,6 +171,7 @@ protected:
private:
friend class MemoryManager;
friend struct ExecutionContext;
friend struct Identifiers;
};
}

View File

@ -74,7 +74,7 @@ Object::~Object()
void Object::__put__(ExecutionContext *ctx, const QString &name, const Value &value)
{
__put__(ctx, ctx->engine->identifier(name), value);
__put__(ctx, ctx->engine->newString(name), value);
}
Value Object::getValue(ExecutionContext *ctx, const PropertyDescriptor *p) const
@ -139,13 +139,13 @@ void Object::defineDefaultProperty(String *name, Value value)
void Object::defineDefaultProperty(ExecutionContext *context, const QString &name, Value value)
{
defineDefaultProperty(context->engine->identifier(name), value);
defineDefaultProperty(context->engine->newIdentifier(name), value);
}
void Object::defineDefaultProperty(ExecutionContext *context, const QString &name, Value (*code)(ExecutionContext *), int argumentCount)
{
Q_UNUSED(argumentCount);
String *s = context->engine->identifier(name);
String *s = context->engine->newIdentifier(name);
FunctionObject* function = context->engine->newBuiltinFunction(context, s, code);
function->defineReadonlyProperty(context->engine->id_length, Value::fromInt32(argumentCount));
defineDefaultProperty(s, Value::fromObject(function));
@ -154,7 +154,7 @@ void Object::defineDefaultProperty(ExecutionContext *context, const QString &nam
void Object::defineDefaultProperty(ExecutionContext *context, const QString &name, Value (*code)(ExecutionContext *, Value, Value *, int), int argumentCount)
{
Q_UNUSED(argumentCount);
String *s = context->engine->identifier(name);
String *s = context->engine->newIdentifier(name);
FunctionObject* function = context->engine->newBuiltinFunction(context, s, code);
function->defineReadonlyProperty(context->engine->id_length, Value::fromInt32(argumentCount));
defineDefaultProperty(s, Value::fromObject(function));
@ -162,7 +162,7 @@ void Object::defineDefaultProperty(ExecutionContext *context, const QString &nam
void Object::defineReadonlyProperty(ExecutionEngine *engine, const QString &name, Value value)
{
defineReadonlyProperty(engine->identifier(name), value);
defineReadonlyProperty(engine->newIdentifier(name), value);
}
void Object::defineReadonlyProperty(String *name, Value value)
@ -268,6 +268,8 @@ Value Object::__get__(ExecutionContext *ctx, String *name, bool *hasProperty)
if (idx != String::InvalidArrayIndex)
return __get__(ctx, idx, hasProperty);
name->makeIdentifier(ctx);
if (name->isEqualTo(ctx->engine->id___proto__)) {
if (hasProperty)
*hasProperty = true;
@ -307,6 +309,8 @@ void Object::__put__(ExecutionContext *ctx, String *name, Value value)
if (idx != String::InvalidArrayIndex)
return __put__(ctx, idx, value);
name->makeIdentifier(ctx);
PropertyDescriptor *pd = __getOwnProperty__(ctx, name);
// clause 1
if (pd) {
@ -448,6 +452,8 @@ bool Object::__hasProperty__(const ExecutionContext *ctx, String *name) const
if (idx != String::InvalidArrayIndex)
return __hasProperty__(ctx, idx);
name->makeIdentifier(ctx);
if (members && members->find(name) != 0)
return true;
@ -470,6 +476,8 @@ bool Object::__delete__(ExecutionContext *ctx, String *name)
if (idx != String::InvalidArrayIndex)
return __delete__(ctx, idx);
name->makeIdentifier(ctx);
if (members) {
if (PropertyTableEntry *entry = members->findEntry(name)) {
if (entry->descriptor.isConfigurable()) {
@ -500,6 +508,8 @@ bool Object::__defineOwnProperty__(ExecutionContext *ctx, String *name, const Pr
if (idx != String::InvalidArrayIndex)
return __defineOwnProperty__(ctx, idx, desc);
name->makeIdentifier(ctx);
PropertyDescriptor *current;
if (isArrayObject() && name->isEqualTo(ctx->engine->id_length)) {
@ -644,7 +654,7 @@ bool Object::__defineOwnProperty__(ExecutionContext *ctx, PropertyDescriptor *cu
bool Object::__defineOwnProperty__(ExecutionContext *ctx, const QString &name, const PropertyDescriptor *desc)
{
return __defineOwnProperty__(ctx, ctx->engine->identifier(name), desc);
return __defineOwnProperty__(ctx, ctx->engine->newString(name), desc);
}

View File

@ -376,7 +376,7 @@ Value ObjectPrototype::method_toString(ExecutionContext *ctx)
Value ObjectPrototype::method_toLocaleString(ExecutionContext *ctx)
{
Object *o = __qmljs_to_object(ctx->thisObject, ctx).objectValue();
Value ts = o->__get__(ctx, ctx->engine->identifier(QStringLiteral("toString")));
Value ts = o->__get__(ctx, ctx->engine->newString(QStringLiteral("toString")));
FunctionObject *f = ts.asFunctionObject();
if (!f)
__qmljs_throw_type_error(ctx);
@ -540,19 +540,19 @@ Value ObjectPrototype::fromPropertyDescriptor(ExecutionContext *ctx, const Prope
if (desc->isData()) {
pd.value = desc->value;
o->__defineOwnProperty__(ctx, engine->identifier(QStringLiteral("value")), &pd);
o->__defineOwnProperty__(ctx, engine->newString(QStringLiteral("value")), &pd);
pd.value = Value::fromBoolean(desc->writable == PropertyDescriptor::Enabled ? true : false);
o->__defineOwnProperty__(ctx, engine->identifier(QStringLiteral("writable")), &pd);
o->__defineOwnProperty__(ctx, engine->newString(QStringLiteral("writable")), &pd);
} else {
pd.value = desc->get ? Value::fromObject(desc->get) : Value::undefinedValue();
o->__defineOwnProperty__(ctx, engine->identifier(QStringLiteral("get")), &pd);
o->__defineOwnProperty__(ctx, engine->newString(QStringLiteral("get")), &pd);
pd.value = desc->set ? Value::fromObject(desc->set) : Value::undefinedValue();
o->__defineOwnProperty__(ctx, engine->identifier(QStringLiteral("set")), &pd);
o->__defineOwnProperty__(ctx, engine->newString(QStringLiteral("set")), &pd);
}
pd.value = Value::fromBoolean(desc->enumberable == PropertyDescriptor::Enabled ? true : false);
o->__defineOwnProperty__(ctx, engine->identifier(QStringLiteral("enumerable")), &pd);
o->__defineOwnProperty__(ctx, engine->newString(QStringLiteral("enumerable")), &pd);
pd.value = Value::fromBoolean(desc->configurable == PropertyDescriptor::Enabled ? true : false);
o->__defineOwnProperty__(ctx, engine->identifier(QStringLiteral("configurable")), &pd);
o->__defineOwnProperty__(ctx, engine->newString(QStringLiteral("configurable")), &pd);
return Value::fromObject(o);
}

View File

@ -61,7 +61,6 @@ struct PropertyTableEntry {
index(-1)
{ }
inline bool hasName(String *n) const { return name->isEqualTo(n); }
inline unsigned hashValue() const { return name->hashValue(); }
};
@ -114,7 +113,7 @@ public:
{
if (_properties) {
for (PropertyTableEntry *prop = _buckets[name->hashValue() % _bucketCount]; prop; prop = prop->next) {
if (prop && (prop->name == name || prop->hasName(name)))
if (prop && prop->name->isEqualTo(name))
return prop;
}
}
@ -126,7 +125,7 @@ public:
{
if (_properties) {
for (PropertyTableEntry *prop = _buckets[name->hashValue() % _bucketCount]; prop; prop = prop->next) {
if (prop && (prop->name == name || prop->hasName(name)))
if (prop && prop->name->isEqualTo(name))
return &prop->descriptor;
}
}

View File

@ -72,7 +72,7 @@ RegExpObject::RegExpObject(ExecutionEngine *engine, PassRefPtr<RegExp> value, bo
if (!members)
members.reset(new PropertyTable());
lastIndexProperty = members->insert(engine->identifier(QStringLiteral("lastIndex")));
lastIndexProperty = members->insert(engine->newIdentifier(QStringLiteral("lastIndex")));
lastIndexProperty->type = PropertyDescriptor::Data;
lastIndexProperty->writable = PropertyDescriptor::Enabled;
lastIndexProperty->enumberable = PropertyDescriptor::Disabled;
@ -80,10 +80,10 @@ RegExpObject::RegExpObject(ExecutionEngine *engine, PassRefPtr<RegExp> value, bo
lastIndexProperty->value = Value::fromInt32(0);
if (!this->value.get())
return;
defineReadonlyProperty(engine->identifier(QStringLiteral("source")), Value::fromString(engine->newString(this->value->pattern())));
defineReadonlyProperty(engine->identifier(QStringLiteral("global")), Value::fromBoolean(global));
defineReadonlyProperty(engine->identifier(QStringLiteral("ignoreCase")), Value::fromBoolean(this->value->ignoreCase()));
defineReadonlyProperty(engine->identifier(QStringLiteral("multiline")), Value::fromBoolean(this->value->multiLine()));
defineReadonlyProperty(engine->newIdentifier(QStringLiteral("source")), Value::fromString(engine->newString(this->value->pattern())));
defineReadonlyProperty(engine->newIdentifier(QStringLiteral("global")), Value::fromBoolean(global));
defineReadonlyProperty(engine->newIdentifier(QStringLiteral("ignoreCase")), Value::fromBoolean(this->value->ignoreCase()));
defineReadonlyProperty(engine->newIdentifier(QStringLiteral("multiline")), Value::fromBoolean(this->value->multiLine()));
}

View File

@ -40,6 +40,7 @@
****************************************************************************/
#include "qv4string.h"
#include "qv4identifier.h"
#include "qmljs_runtime.h"
#include <QtCore/QHash>
@ -89,6 +90,11 @@ uint String::toUInt(bool *ok) const
return UINT_MAX;
}
void String::makeIdentifierImpl(const ExecutionContext *ctx)
{
ctx->engine->identifierCache->toIdentifier(this);
}
void String::createHashValue() const
{
const QChar *ch = _text.constData();

View File

@ -47,12 +47,14 @@
namespace QQmlJS {
namespace VM {
struct ExecutionEngine;
struct String : public Managed {
enum StringType {
StringType_Unknown,
StringType_ArrayIndex,
StringType_Regular,
StringType_Identifier,
StringType_ArrayIndex
};
String(const QString &text)
@ -62,12 +64,15 @@ struct String : public Managed {
inline bool isEqualTo(const String *other) const {
if (this == other)
return true;
else if (hashValue() == other->hashValue()) {
if (subtype == StringType_ArrayIndex && other->subtype == StringType_ArrayIndex)
if (hashValue() != other->hashValue())
return false;
if (subtype == other->subtype) {
if (subtype == StringType_ArrayIndex)
return true;
return toQString() == other->toQString();
if (subtype == StringType_Identifier)
return stringIdentifier == other->stringIdentifier;
}
return false;
return toQString() == other->toQString();
}
inline const QString &toQString() const {
@ -93,7 +98,16 @@ struct String : public Managed {
}
uint toUInt(bool *ok) const;
void makeIdentifier(const ExecutionContext *ctx) {
if (subtype == StringType_Identifier)
return;
makeIdentifierImpl(ctx);
}
void makeIdentifierImpl(const ExecutionContext *ctx);
private:
friend struct Identifiers;
void createHashValue() const;
QString _text;

View File

@ -312,13 +312,13 @@ Value StringPrototype::method_match(ExecutionContext *parentCtx, Value thisObjec
bool global = rx->global;
// ### use the standard builtin function, not the one that might be redefined in the proto
FunctionObject *exec = parentCtx->engine->regExpPrototype->__get__(parentCtx, parentCtx->engine->identifier(QStringLiteral("exec")), 0).asFunctionObject();
FunctionObject *exec = parentCtx->engine->regExpPrototype->__get__(parentCtx, parentCtx->engine->newString(QStringLiteral("exec")), 0).asFunctionObject();
Value arg = Value::fromString(s);
if (!global)
return exec->call(parentCtx, Value::fromObject(rx), &arg, 1);
String *lastIndex = parentCtx->engine->identifier(QStringLiteral("lastIndex"));
String *lastIndex = parentCtx->engine->newString(QStringLiteral("lastIndex"));
rx->__put__(parentCtx, lastIndex, Value::fromInt32(0));
ArrayObject *a = parentCtx->engine->newArrayObject(parentCtx);

View File

@ -68,6 +68,7 @@ HEADERS += \
qv4isel_p.h \
qv4isel_util_p.h \
debugging.h \
qv4identifier.h \
qv4mm.h \
qv4managed.h \
qv4array.h \