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:
parent
3dbd772cc4
commit
3e6fc20a2a
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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>();
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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]) {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
Loading…
Reference in New Issue