Move arguments object creation into the generated code

So far we've been creating the arguments object at runtime
in initCallContext(). It's much more efficient to simply add
arguments as a local variable in qv4codegen if it's being used
and initialize it through a builtin method.

Change-Id: I6913f3565adf3aa1917adae8dceef9f50ecf1722
Reviewed-by: Simon Hausmann <simon.hausmann@digia.com>
This commit is contained in:
Lars Knoll 2013-08-16 12:54:30 +02:00 committed by The Qt Project
parent 51e7447481
commit 3cfc7e0c02
17 changed files with 62 additions and 16 deletions

View File

@ -1820,11 +1820,14 @@ V4IR::Function *Codegen::defineFunction(const QString &name, AST::Node *ast,
V4IR::BasicBlock *exitBlock = function->newBasicBlock(groupStartBlock(), V4IR::Function::DontInsertBlock);
V4IR::BasicBlock *throwBlock = function->newBasicBlock(groupStartBlock());
function->hasDirectEval = _env->hasDirectEval;
function->usesArgumentsObject = (_env->usesArgumentsObject == Environment::ArgumentsObjectUsed);
function->usesArgumentsObject = _env->parent && (_env->usesArgumentsObject == Environment::ArgumentsObjectUsed);
function->maxNumberOfArguments = _env->maxNumberOfArguments;
function->isStrict = _env->isStrict;
function->isNamedExpression = _env->isNamedFunctionExpression;
if (function->usesArgumentsObject)
_env->enter("arguments", Environment::VariableDeclaration);
// variables in global code are properties of the global context object, not locals as with other functions.
if (_mode == FunctionCode) {
unsigned t = 0;
@ -1897,6 +1900,11 @@ V4IR::Function *Codegen::defineFunction(const QString &name, AST::Node *ast,
}
}
}
if (_function->usesArgumentsObject) {
move(_block->NAME("arguments", ast->firstSourceLocation().startLine, ast->firstSourceLocation().startColumn),
_block->CALL(_block->NAME(V4IR::Name::builtin_setup_argument_object,
ast->firstSourceLocation().startLine, ast->firstSourceLocation().startColumn), 0));
}
sourceElements(body);

View File

@ -92,6 +92,7 @@ QT_BEGIN_NAMESPACE
F(CallBuiltinDefineProperty, callBuiltinDefineProperty) \
F(CallBuiltinDefineArray, callBuiltinDefineArray) \
F(CallBuiltinDefineObjectLiteral, callBuiltinDefineObjectLiteral) \
F(CallBuiltinSetupArgumentsObject, callBuiltinSetupArgumentsObject) \
F(CreateValue, createValue) \
F(CreateProperty, createProperty) \
F(CreateActivationProperty, createActivationProperty) \
@ -440,6 +441,10 @@ union Instr
quint32 args;
Param result;
};
struct instr_callBuiltinSetupArgumentsObject {
MOTH_INSTR_HEADER
Param result;
};
struct instr_createValue {
MOTH_INSTR_HEADER
quint32 argc;
@ -577,6 +582,7 @@ union Instr
instr_callBuiltinDefineProperty callBuiltinDefineProperty;
instr_callBuiltinDefineArray callBuiltinDefineArray;
instr_callBuiltinDefineObjectLiteral callBuiltinDefineObjectLiteral;
instr_callBuiltinSetupArgumentsObject callBuiltinSetupArgumentsObject;
instr_createValue createValue;
instr_createProperty createProperty;
instr_createActivationProperty createActivationProperty;

View File

@ -977,6 +977,12 @@ void InstructionSelection::callBuiltinDefineObjectLiteral(V4IR::Temp *result, V4
Assembler::TrustedImmPtr(klass));
}
void InstructionSelection::callBuiltinSetupArgumentObject(V4IR::Temp *result)
{
generateFunctionCall(Assembler::Void, __qmljs_builtin_setup_arguments_object, Assembler::ContextRegister,
Assembler::PointerToValue(result));
}
void InstructionSelection::callValue(V4IR::Temp *value, V4IR::ExprList *args, V4IR::Temp *result)
{
int argc = prepareVariableArguments(args);

View File

@ -815,6 +815,7 @@ protected:
virtual void callBuiltinDefineProperty(V4IR::Temp *object, const QString &name, V4IR::Temp *value);
virtual void callBuiltinDefineArray(V4IR::Temp *result, V4IR::ExprList *args);
virtual void callBuiltinDefineObjectLiteral(V4IR::Temp *result, V4IR::ExprList *args);
virtual void callBuiltinSetupArgumentObject(V4IR::Temp *result);
virtual void callValue(V4IR::Temp *value, V4IR::ExprList *args, V4IR::Temp *result);
virtual void callProperty(V4IR::Temp *base, const QString &name, V4IR::ExprList *args, V4IR::Temp *result);
virtual void callSubscript(V4IR::Temp *base, V4IR::Temp *index, V4IR::ExprList *args, V4IR::Temp *result);

View File

@ -1003,6 +1003,13 @@ void InstructionSelection::callBuiltinDefineObjectLiteral(V4IR::Temp *result, V4
addInstruction(call);
}
void InstructionSelection::callBuiltinSetupArgumentObject(V4IR::Temp *result)
{
Instruction::CallBuiltinSetupArgumentsObject call;
call.result = getResultParam(result);
addInstruction(call);
}
ptrdiff_t InstructionSelection::addInstructionHelper(Instr::Type type, Instr &instr)
{
#ifdef MOTH_THREADED_INTERPRETER

View File

@ -100,6 +100,7 @@ protected:
virtual void callBuiltinDefineProperty(V4IR::Temp *object, const QString &name, V4IR::Temp *value);
virtual void callBuiltinDefineArray(V4IR::Temp *result, V4IR::ExprList *args);
virtual void callBuiltinDefineObjectLiteral(V4IR::Temp *result, V4IR::ExprList *args);
virtual void callBuiltinSetupArgumentObject(V4IR::Temp *result);
virtual void callValue(V4IR::Temp *value, V4IR::ExprList *args, V4IR::Temp *result);
virtual void callProperty(V4IR::Temp *base, const QString &name, V4IR::ExprList *args, V4IR::Temp *result);
virtual void callSubscript(V4IR::Temp *base, V4IR::Temp *index, V4IR::ExprList *args, V4IR::Temp *result);

View File

@ -428,6 +428,10 @@ void IRDecoder::callBuiltin(V4IR::Call *call, V4IR::Temp *result)
callBuiltinDefineObjectLiteral(result, call->args);
return;
case V4IR::Name::builtin_setup_argument_object:
callBuiltinSetupArgumentObject(result);
return;
default:
break;
}

View File

@ -128,6 +128,7 @@ public: // to implement by subclasses:
virtual void callBuiltinDefineProperty(V4IR::Temp *object, const QString &name, V4IR::Temp *value) = 0;
virtual void callBuiltinDefineArray(V4IR::Temp *result, V4IR::ExprList *args) = 0;
virtual void callBuiltinDefineObjectLiteral(V4IR::Temp *result, V4IR::ExprList *args) = 0;
virtual void callBuiltinSetupArgumentObject(V4IR::Temp *result) = 0;
virtual void callValue(V4IR::Temp *value, V4IR::ExprList *args, V4IR::Temp *result) = 0;
virtual void callProperty(V4IR::Temp *base, const QString &name, V4IR::ExprList *args, V4IR::Temp *result) = 0;
virtual void callSubscript(V4IR::Temp *base, V4IR::Temp *index, V4IR::ExprList *args, V4IR::Temp *result) = 0;

View File

@ -413,6 +413,8 @@ static const char *builtin_to_string(Name::Builtin b)
return "builtin_define_getter_setter";
case V4IR::Name::builtin_define_object_literal:
return "builtin_define_object_literal";
case V4IR::Name::builtin_setup_argument_object:
return "builtin_setup_argument_object";
}
return "builtin_(###FIXME)";
};

View File

@ -314,7 +314,8 @@ struct Name: Expr {
builtin_define_property,
builtin_define_array,
builtin_define_getter_setter,
builtin_define_object_literal
builtin_define_object_literal,
builtin_setup_argument_object
};
const QString *id;

View File

@ -50,7 +50,7 @@ static Value throwTypeError(SimpleCallContext *ctx)
DEFINE_MANAGED_VTABLE(ArgumentsObject);
ArgumentsObject::ArgumentsObject(CallContext *context, int formalParameterCount, int actualParameterCount)
ArgumentsObject::ArgumentsObject(CallContext *context)
: Object(context->engine), context(context)
{
vtbl = &static_vtbl;
@ -76,8 +76,8 @@ ArgumentsObject::ArgumentsObject(CallContext *context, int formalParameterCount,
memberData[CalleePropertyIndex].value = Value::fromObject(context->function);
isNonStrictArgumentsObject = true;
uint numAccessors = qMin(formalParameterCount, actualParameterCount);
uint argCount = qMin((uint)actualParameterCount, context->argumentCount);
uint numAccessors = qMin(context->function->formalParameterCount, context->realArgumentCount);
uint argCount = qMin((uint)context->realArgumentCount, context->argumentCount);
arrayReserve(argCount);
ensureArrayAttributes();
context->engine->requireArgumentsAccessors(numAccessors);
@ -94,7 +94,7 @@ ArgumentsObject::ArgumentsObject(CallContext *context, int formalParameterCount,
}
assert(LengthPropertyIndex == internalClass->find(context->engine->id_length));
Property *lp = memberData + ArrayObject::LengthPropertyIndex;
lp->value = Value::fromInt32(actualParameterCount);
lp->value = Value::fromInt32(context->realArgumentCount);
}
void ArgumentsObject::destroy(Managed *that)

View File

@ -78,7 +78,7 @@ protected:
struct ArgumentsObject: Object {
CallContext *context;
QVector<Value> mappedArguments;
ArgumentsObject(CallContext *context, int formalParameterCount, int actualParameterCount);
ArgumentsObject(CallContext *context);
~ArgumentsObject() {}
enum {

View File

@ -160,6 +160,7 @@ void CallContext::initCallContext(ExecutionContext *parentContext, FunctionObjec
this->function = function;
this->arguments = _arguments;
this->realArgumentCount = _argumentCount;
this->argumentCount = _argumentCount;
this->thisObject = _thisObject;
@ -191,14 +192,6 @@ void CallContext::initCallContext(ExecutionContext *parentContext, FunctionObjec
std::fill(arguments + argc, arguments + function->formalParameterCount, Value::undefinedValue());
}
if (function->usesArgumentsObject) {
ArgumentsObject *args = new (engine->memoryManager) ArgumentsObject(this, function->formalParameterCount, argc);
args->prototype = engine->objectPrototype;
activation = engine->newObject();
Property desc = Property::fromValue(Value::fromObject(args));
activation->__defineOwnProperty__(this, engine->id_arguments, desc, Attr_NotConfigurable);
}
}
void CallContext::initQmlContext(ExecutionContext *parentContext, Object *qml, FunctionObject *function)

View File

@ -157,6 +157,7 @@ struct SimpleCallContext : public ExecutionContext
void initSimpleCallContext(ExecutionEngine *engine);
FunctionObject *function;
Value *arguments;
unsigned int realArgumentCount;
unsigned int argumentCount;
};

View File

@ -46,6 +46,7 @@
#include "qv4objectproto_p.h"
#include "qv4globalobject_p.h"
#include "qv4stringobject_p.h"
#include "qv4argumentsobject_p.h"
#include "qv4lookup_p.h"
#include "qv4function_p.h"
#include "qv4exception_p.h"
@ -1221,6 +1222,15 @@ void __qmljs_builtin_define_object_literal(QV4::ExecutionContext *ctx, QV4::Valu
*result = Value::fromObject(o);
}
void __qmljs_builtin_setup_arguments_object(ExecutionContext *ctx, Value *result)
{
assert(ctx->type >= ExecutionContext::Type_CallContext);
CallContext *c = static_cast<CallContext *>(ctx);
ArgumentsObject *args = new (c->engine->memoryManager) ArgumentsObject(c);
args->prototype = c->engine->objectPrototype;
*result = Value::fromObject(args);
}
void __qmljs_increment(Value *result, const Value &value)
{
TRACE1(value);
@ -1264,6 +1274,7 @@ unsigned __qmljs_double_to_uint32(double d)
{
return Value::toUInt32(d);
}
} // namespace QV4
QT_END_NAMESPACE

View File

@ -125,7 +125,7 @@ void __qmljs_builtin_define_property(QV4::ExecutionContext *ctx, const QV4::Valu
void __qmljs_builtin_define_array(QV4::ExecutionContext *ctx, QV4::Value *array, QV4::Value *values, uint length);
void __qmljs_builtin_define_getter_setter(QV4::ExecutionContext *ctx, const QV4::Value &object, QV4::String *name, const QV4::Value *getter, const QV4::Value *setter);
void __qmljs_builtin_define_object_literal(QV4::ExecutionContext *ctx, QV4::Value *result, const QV4::Value *args, QV4::InternalClass *klass);
void __qmljs_builtin_setup_arguments_object(ExecutionContext *ctx, QV4::Value *result);
// constructors
void __qmljs_init_closure(QV4::ExecutionContext *ctx, QV4::Value *result, QV4::Function *clos);
QV4::Function *__qmljs_register_function(QV4::ExecutionContext *ctx, QV4::String *name,

View File

@ -467,6 +467,10 @@ QV4::Value VME::run(QV4::ExecutionContext *context, const uchar *&code,
__qmljs_builtin_define_object_literal(context, VALUEPTR(instr.result), args, instr.internalClass);
MOTH_END_INSTR(CallBuiltinDefineObjectLiteral)
MOTH_BEGIN_INSTR(CallBuiltinSetupArgumentsObject)
__qmljs_builtin_setup_arguments_object(context, VALUEPTR(instr.result));
MOTH_END_INSTR(CallBuiltinSetupArgumentsObject)
MOTH_BEGIN_INSTR(CreateValue)
Q_ASSERT(instr.args + instr.argc <= stackSize);
QV4::Value *args = stack + instr.args;