use lookups for the global scope

Gives about 12% speed improvement for the V8 benchmark.
fact.2.js is almost twice as fast.

Change-Id: Icfa1a780b30e131b9531e12f4bd569516c404e86
Reviewed-by: Simon Hausmann <simon.hausmann@digia.com>
This commit is contained in:
Lars Knoll 2013-04-14 12:17:11 +02:00 committed by Simon Hausmann
parent 3dbd772cc4
commit 3e6fc20a2a
13 changed files with 180 additions and 12 deletions

View File

@ -245,10 +245,10 @@ void InstructionSelection::loadRegexp(V4IR::RegExp *sourceRegexp, V4IR::Temp *ta
addInstruction(load);
}
void InstructionSelection::getActivationProperty(const QString &name, V4IR::Temp *temp)
void InstructionSelection::getActivationProperty(const V4IR::Name *name, V4IR::Temp *temp)
{
Instruction::LoadName load;
load.name = identifier(name);
load.name = identifier(*name->id);
load.result = getResultParam(temp);
addInstruction(load);
}

View File

@ -63,7 +63,7 @@ protected:
virtual void loadConst(V4IR::Const *sourceConst, V4IR::Temp *targetTemp);
virtual void loadString(const QString &str, V4IR::Temp *targetTemp);
virtual void loadRegexp(V4IR::RegExp *sourceRegexp, V4IR::Temp *targetTemp);
virtual void getActivationProperty(const QString &name, V4IR::Temp *temp);
virtual void getActivationProperty(const V4IR::Name *name, V4IR::Temp *temp);
virtual void setActivationProperty(V4IR::Temp *source, const QString &targetName);
virtual void initClosure(V4IR::Closure *closure, V4IR::Temp *target);
virtual void getProperty(V4IR::Temp *base, const QString &name, V4IR::Temp *target);

View File

@ -1959,7 +1959,7 @@ V4IR::Expr *Codegen::identifier(const QString &name, int line, int col)
V4IR::Function *f = _function;
while (f && e->parent) {
if ((f->usesArgumentsObject && name == "arguments") || (!f->isStrict && f->hasDirectEval) || f->insideWithOrCatch)
if ((f->usesArgumentsObject && name == "arguments") || (!f->isStrict && f->hasDirectEval) || f->insideWithOrCatch || (f->isNamedExpression && f->name == name))
break;
int index = e->findMember(name);
assert (index < e->members.size());
@ -1974,6 +1974,9 @@ V4IR::Expr *Codegen::identifier(const QString &name, int line, int col)
f = f->outer;
}
if (!e->parent && (!f || !f->insideWithOrCatch) && _mode != EvalCode && (!f || f->name != name))
return _block->GLOBALNAME(name, line, col);
// global context or with. Lookup by name
return _block->NAME(name, line, col);

View File

@ -599,7 +599,23 @@ void InstructionSelection::run(VM::Function *vmFunction, V4IR::Function *functio
void InstructionSelection::callBuiltinInvalid(V4IR::Name *func, V4IR::ExprList *args, V4IR::Temp *result)
{
callRuntimeMethod(result, __qmljs_call_activation_property, func, args);
int argc = prepareVariableArguments(args);
VM::String *s = identifier(*func->id);
if (useFastLookups && func->global) {
uint index = addGlobalLookup(s);
generateFunctionCall(Assembler::Void, __qmljs_call_global_lookup,
Assembler::ContextRegister, Assembler::PointerToValue(result),
Assembler::TrustedImm32(index),
baseAddressForCallArguments(),
Assembler::TrustedImm32(argc));
} else {
generateFunctionCall(Assembler::Void, __qmljs_call_activation_property,
Assembler::ContextRegister, Assembler::PointerToValue(result),
s,
baseAddressForCallArguments(),
Assembler::TrustedImm32(argc));
}
}
void InstructionSelection::callBuiltinTypeofMember(V4IR::Temp *base, const QString &name, V4IR::Temp *result)
@ -830,9 +846,15 @@ void InstructionSelection::loadRegexp(V4IR::RegExp *sourceRegexp, V4IR::Temp *ta
_as->storeValue(v, targetTemp);
}
void InstructionSelection::getActivationProperty(const QString &name, V4IR::Temp *temp)
void InstructionSelection::getActivationProperty(const V4IR::Name *name, V4IR::Temp *temp)
{
String *propertyName = identifier(name);
String *propertyName = identifier(*name->id);
if (useFastLookups && name->global) {
uint index = addGlobalLookup(propertyName);
generateFunctionCall(Assembler::Void, __qmljs_get_global_lookup, Assembler::ContextRegister, Assembler::PointerToValue(temp),
Assembler::TrustedImm32(index));
return;
}
generateFunctionCall(Assembler::Void, __qmljs_get_activation_property, Assembler::ContextRegister, Assembler::PointerToValue(temp), propertyName);
}
@ -1196,3 +1218,17 @@ uint InstructionSelection::addLookup(VM::String *name)
_lookups.append(l);
return index;
}
uint InstructionSelection::addGlobalLookup(VM::String *name)
{
uint index = (uint)_lookups.size();
VM::Lookup l;
l.lookupGlobal = Lookup::lookupGlobalGeneric;
for (int i = 0; i < Lookup::Size; ++i)
l.classList[i] = 0;
l.level = -1;
l.index = UINT_MAX;
l.name = name;
_lookups.append(l);
return index;
}

View File

@ -805,7 +805,7 @@ protected:
virtual void loadConst(V4IR::Const *sourceConst, V4IR::Temp *targetTemp);
virtual void loadString(const QString &str, V4IR::Temp *targetTemp);
virtual void loadRegexp(V4IR::RegExp *sourceRegexp, V4IR::Temp *targetTemp);
virtual void getActivationProperty(const QString &name, V4IR::Temp *temp);
virtual void getActivationProperty(const V4IR::Name *name, V4IR::Temp *temp);
virtual void setActivationProperty(V4IR::Temp *source, const QString &targetName);
virtual void initClosure(V4IR::Closure *closure, V4IR::Temp *target);
virtual void getProperty(V4IR::Temp *base, const QString &name, V4IR::Temp *target);
@ -870,6 +870,7 @@ private:
callRuntimeMethodImp(result, isel_stringIfy(function), function, __VA_ARGS__)
uint addLookup(VM::String *name);
uint addGlobalLookup(VM::String *name);
V4IR::BasicBlock *_block;
V4IR::Function* _function;

View File

@ -86,7 +86,7 @@ void InstructionSelection::visitMove(V4IR::Move *s)
if (*n->id == QStringLiteral("this")) // TODO: `this' should be a builtin.
loadThisObject(t);
else
getActivationProperty(*n->id, t);
getActivationProperty(n, t);
return;
} else if (V4IR::Const *c = s->source->asConst()) {
loadConst(c, t);

View File

@ -134,7 +134,7 @@ public: // to implement by subclasses:
virtual void loadConst(V4IR::Const *sourceConst, V4IR::Temp *targetTemp) = 0;
virtual void loadString(const QString &str, V4IR::Temp *targetTemp) = 0;
virtual void loadRegexp(V4IR::RegExp *sourceRegexp, V4IR::Temp *targetTemp) = 0;
virtual void getActivationProperty(const QString &name, V4IR::Temp *temp) = 0;
virtual void getActivationProperty(const V4IR::Name *name, V4IR::Temp *temp) = 0;
virtual void setActivationProperty(V4IR::Temp *source, const QString &targetName) = 0;
virtual void initClosure(V4IR::Closure *closure, V4IR::Temp *target) = 0;
virtual void getProperty(V4IR::Temp *base, const QString &name, V4IR::Temp *target) = 0;

View File

@ -328,10 +328,20 @@ void RegExp::dump(QTextStream &out)
out << '/' << *value << '/' << f;
}
void Name::initGlobal(const QString *id, quint32 line, quint32 column)
{
this->id = id;
this->builtin = builtin_invalid;
this->global = true;
this->line = line;
this->column = column;
}
void Name::init(const QString *id, quint32 line, quint32 column)
{
this->id = id;
this->builtin = builtin_invalid;
this->global = false;
this->line = line;
this->column = column;
}
@ -340,6 +350,7 @@ void Name::init(Builtin builtin, quint32 line, quint32 column)
{
this->id = 0;
this->builtin = builtin;
this->global = false;
this->line = line;
this->column = column;
}
@ -644,6 +655,14 @@ Name *BasicBlock::NAME(const QString &id, quint32 line, quint32 column)
return e;
}
Name *BasicBlock::GLOBALNAME(const QString &id, quint32 line, quint32 column)
{
Name *e = function->New<Name>();
e->initGlobal(function->newString(id), line, column);
return e;
}
Name *BasicBlock::NAME(Name::Builtin builtin, quint32 line, quint32 column)
{
Name *e = function->New<Name>();

View File

@ -304,9 +304,11 @@ struct Name: Expr {
const QString *id;
Builtin builtin;
bool global;
quint32 line;
quint32 column;
void initGlobal(const QString *id, quint32 line, quint32 column);
void init(const QString *id, quint32 line, quint32 column);
void init(Builtin builtin, quint32 line, quint32 column);
@ -741,6 +743,8 @@ struct BasicBlock {
Name *NAME(const QString &id, quint32 line, quint32 column);
Name *NAME(Name::Builtin builtin, quint32 line, quint32 column);
Name *GLOBALNAME(const QString &id, quint32 line, quint32 column);
Closure *CLOSURE(Function *function);
Expr *UNOP(AluOp op, Temp *expr);

View File

@ -129,6 +129,71 @@ void Lookup::lookupProperty2(Lookup *l, ExecutionContext *ctx, Value *result, co
lookupPropertyGeneric(l, ctx, result, object);
}
void Lookup::lookupGlobalGeneric(Lookup *l, ExecutionContext *ctx, Value *result)
{
Object *o = ctx->engine->globalObject;
PropertyAttributes attrs;
Property *p = l->lookup(o, &attrs);
if (p) {
if (attrs.isData()) {
if (l->level == 0)
l->lookupGlobal = lookupGlobal0;
else if (l->level == 1)
l->lookupGlobal = lookupGlobal1;
else if (l->level == 2)
l->lookupGlobal = lookupGlobal2;
*result = p->value;
return;
} else {
Value res = o->getValue(ctx, p, attrs);
if (result)
*result = res;
return;
}
}
ctx->throwReferenceError(Value::fromString(l->name));
}
void Lookup::lookupGlobal0(Lookup *l, ExecutionContext *ctx, Value *result)
{
Object *o = ctx->engine->globalObject;
if (l->classList[0] == o->internalClass) {
*result = o->memberData[l->index].value;
return;
}
l->lookupGlobal = lookupGlobalGeneric;
lookupGlobalGeneric(l, ctx, result);
}
void Lookup::lookupGlobal1(Lookup *l, ExecutionContext *ctx, Value *result)
{
Object *o = ctx->engine->globalObject;
if (l->classList[0] == o->internalClass &&
l->classList[1] == o->prototype->internalClass) {
*result = o->prototype->memberData[l->index].value;
return;
}
l->lookupGlobal = lookupGlobalGeneric;
lookupGlobalGeneric(l, ctx, result);
}
void Lookup::lookupGlobal2(Lookup *l, ExecutionContext *ctx, Value *result)
{
Object *o = ctx->engine->globalObject;
if (l->classList[0] == o->internalClass) {
o = o->prototype;
if (l->classList[1] == o->internalClass) {
o = o->prototype;
if (l->classList[2] == o->internalClass) {
*result = o->prototype->memberData[l->index].value;
return;
}
}
}
l->lookupGlobal = lookupGlobalGeneric;
lookupGlobalGeneric(l, ctx, result);
}
}
}

View File

@ -55,7 +55,10 @@ namespace VM {
struct Lookup {
enum { Size = 4 };
void (*lookupProperty)(Lookup *l, ExecutionContext *ctx, Value *result, const Value &object);
union {
void (*lookupProperty)(Lookup *l, ExecutionContext *ctx, Value *result, const Value &object);
void (*lookupGlobal)(Lookup *l, ExecutionContext *ctx, Value *result);
};
InternalClass *classList[Size];
int level;
uint index;
@ -66,6 +69,11 @@ struct Lookup {
static void lookupProperty1(Lookup *l, ExecutionContext *ctx, Value *result, const Value &object);
static void lookupProperty2(Lookup *l, ExecutionContext *ctx, Value *result, const Value &object);
static void lookupGlobalGeneric(Lookup *l, ExecutionContext *ctx, Value *result);
static void lookupGlobal0(Lookup *l, ExecutionContext *ctx, Value *result);
static void lookupGlobal1(Lookup *l, ExecutionContext *ctx, Value *result);
static void lookupGlobal2(Lookup *l, ExecutionContext *ctx, Value *result);
Property *lookup(Object *obj, PropertyAttributes *attrs) {
int i = 0;
while (i < level && obj && obj->internalClass == classList[i]) {

View File

@ -721,9 +721,14 @@ void __qmljs_get_activation_property(ExecutionContext *ctx, Value *result, Strin
*result = ctx->getProperty(name);
}
void __qmljs_get_global_lookup(ExecutionContext *ctx, Value *result, int lookupIndex)
{
Lookup *l = ctx->lookups + lookupIndex;
l->lookupGlobal(l, ctx, result);
}
void __qmljs_get_property_lookup(ExecutionContext *ctx, Value *result, const Value &object, int lookupIndex)
{
Value res;
Lookup *l = ctx->lookups + lookupIndex;
l->lookupProperty(l, ctx, result, object);
}
@ -820,6 +825,31 @@ Bool __qmljs_strict_equal(const Value &x, const Value &y, ExecutionContext *ctx)
return false;
}
void __qmljs_call_global_lookup(ExecutionContext *context, Value *result, uint index, Value *args, int argc)
{
Lookup *l = context->lookups + index;
Value v;
l->lookupGlobal(l, context, &v);
FunctionObject *o = v.asFunctionObject();
if (!o)
context->throwTypeError();
Value thisObject = Value::undefinedValue();
if (o == context->engine->evalFunction && l->name->isEqualTo(context->engine->id_eval)) {
Value res = static_cast<EvalFunction *>(o)->evalCall(context, thisObject, args, argc, true);
if (result)
*result = res;
return;
}
Value res = o->call(context, thisObject, args, argc);
if (result)
*result = res;
}
void __qmljs_call_activation_property(ExecutionContext *context, Value *result, String *name, Value *args, int argc)
{
Object *base;

View File

@ -166,6 +166,8 @@ void __qmljs_set_property(ExecutionContext *ctx, const Value &object, String *na
void __qmljs_get_property(ExecutionContext *ctx, Value *result, const Value &object, String *name);
void __qmljs_get_activation_property(ExecutionContext *ctx, Value *result, String *name);
void __qmljs_get_global_lookup(ExecutionContext *ctx, Value *result, int lookupIndex);
void __qmljs_call_global_lookup(ExecutionContext *context, Value *result, uint index, Value *args, int argc);
void __qmljs_get_property_lookup(ExecutionContext *ctx, Value *result, const Value &object, int lookupIndex);
void __qmljs_set_property_lookup(ExecutionContext *ctx, const Value &object, int lookupIndex, const Value &value);