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:
parent
a49e2acc5a
commit
38094f774b
|
@ -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) {
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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();
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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()));
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -68,6 +68,7 @@ HEADERS += \
|
|||
qv4isel_p.h \
|
||||
qv4isel_util_p.h \
|
||||
debugging.h \
|
||||
qv4identifier.h \
|
||||
qv4mm.h \
|
||||
qv4managed.h \
|
||||
qv4array.h \
|
||||
|
|
Loading…
Reference in New Issue