From 3e6fc20a2ac4da117aa5f6da278c8dd784741f5e Mon Sep 17 00:00:00 2001 From: Lars Knoll Date: Sun, 14 Apr 2013 12:17:11 +0200 Subject: 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 --- src/v4/moth/qv4isel_moth.cpp | 4 +-- src/v4/moth/qv4isel_moth_p.h | 2 +- src/v4/qv4codegen.cpp | 5 +++- src/v4/qv4isel_masm.cpp | 42 ++++++++++++++++++++++++++-- src/v4/qv4isel_masm_p.h | 3 +- src/v4/qv4isel_p.cpp | 2 +- src/v4/qv4isel_p.h | 2 +- src/v4/qv4jsir.cpp | 19 +++++++++++++ src/v4/qv4jsir_p.h | 4 +++ src/v4/qv4lookup.cpp | 65 ++++++++++++++++++++++++++++++++++++++++++++ src/v4/qv4lookup.h | 10 ++++++- src/v4/qv4runtime.cpp | 32 +++++++++++++++++++++- src/v4/qv4runtime.h | 2 ++ 13 files changed, 180 insertions(+), 12 deletions(-) (limited to 'src') diff --git a/src/v4/moth/qv4isel_moth.cpp b/src/v4/moth/qv4isel_moth.cpp index 31bf1fb36d..00ae4e1029 100644 --- a/src/v4/moth/qv4isel_moth.cpp +++ b/src/v4/moth/qv4isel_moth.cpp @@ -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); } diff --git a/src/v4/moth/qv4isel_moth_p.h b/src/v4/moth/qv4isel_moth_p.h index 090d151df5..5e057139e2 100644 --- a/src/v4/moth/qv4isel_moth_p.h +++ b/src/v4/moth/qv4isel_moth_p.h @@ -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); diff --git a/src/v4/qv4codegen.cpp b/src/v4/qv4codegen.cpp index df931fd767..c91458282f 100644 --- a/src/v4/qv4codegen.cpp +++ b/src/v4/qv4codegen.cpp @@ -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); diff --git a/src/v4/qv4isel_masm.cpp b/src/v4/qv4isel_masm.cpp index 9d8795f198..80803e811c 100644 --- a/src/v4/qv4isel_masm.cpp +++ b/src/v4/qv4isel_masm.cpp @@ -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; +} diff --git a/src/v4/qv4isel_masm_p.h b/src/v4/qv4isel_masm_p.h index ab05b82992..9f8704725f 100644 --- a/src/v4/qv4isel_masm_p.h +++ b/src/v4/qv4isel_masm_p.h @@ -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; diff --git a/src/v4/qv4isel_p.cpp b/src/v4/qv4isel_p.cpp index d355e16104..417e38550e 100644 --- a/src/v4/qv4isel_p.cpp +++ b/src/v4/qv4isel_p.cpp @@ -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); diff --git a/src/v4/qv4isel_p.h b/src/v4/qv4isel_p.h index 4d02b5fff4..e85127c5a9 100644 --- a/src/v4/qv4isel_p.h +++ b/src/v4/qv4isel_p.h @@ -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; diff --git a/src/v4/qv4jsir.cpp b/src/v4/qv4jsir.cpp index ddf6509f27..3dad094624 100644 --- a/src/v4/qv4jsir.cpp +++ b/src/v4/qv4jsir.cpp @@ -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(); + e->initGlobal(function->newString(id), line, column); + return e; +} + + Name *BasicBlock::NAME(Name::Builtin builtin, quint32 line, quint32 column) { Name *e = function->New(); diff --git a/src/v4/qv4jsir_p.h b/src/v4/qv4jsir_p.h index b8377b941d..47368449fc 100644 --- a/src/v4/qv4jsir_p.h +++ b/src/v4/qv4jsir_p.h @@ -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); diff --git a/src/v4/qv4lookup.cpp b/src/v4/qv4lookup.cpp index 991ab2b617..76e1c415ca 100644 --- a/src/v4/qv4lookup.cpp +++ b/src/v4/qv4lookup.cpp @@ -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); +} + } } diff --git a/src/v4/qv4lookup.h b/src/v4/qv4lookup.h index c51940ac2d..c287c97124 100644 --- a/src/v4/qv4lookup.h +++ b/src/v4/qv4lookup.h @@ -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]) { diff --git a/src/v4/qv4runtime.cpp b/src/v4/qv4runtime.cpp index b6a7dd6c99..8aac271f91 100644 --- a/src/v4/qv4runtime.cpp +++ b/src/v4/qv4runtime.cpp @@ -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(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; diff --git a/src/v4/qv4runtime.h b/src/v4/qv4runtime.h index 8640c829df..8487244a72 100644 --- a/src/v4/qv4runtime.h +++ b/src/v4/qv4runtime.h @@ -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); -- cgit v1.2.3