aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--qmljs_environment.cpp21
-rw-r--r--qmljs_objects.cpp55
-rw-r--r--qmljs_objects.h8
-rw-r--r--qv4codegen.cpp19
-rw-r--r--qv4codegen_p.h8
-rw-r--r--qv4ir_p.h2
-rw-r--r--qv4isel_p.cpp1
7 files changed, 54 insertions, 60 deletions
diff --git a/qmljs_environment.cpp b/qmljs_environment.cpp
index a7cf2ce539..e2bae58c56 100644
--- a/qmljs_environment.cpp
+++ b/qmljs_environment.cpp
@@ -296,12 +296,6 @@ Value ExecutionContext::getProperty(String *name)
if (hasProperty)
return v;
}
- if (name->isEqualTo(ctx->engine->id_arguments)) {
- Value arguments = Value::fromObject(new (engine->memoryManager) ArgumentsObject(this));
- createMutableBinding(ctx->engine->id_arguments, false);
- setMutableBinding(this, ctx->engine->id_arguments, arguments);
- return arguments;
- }
}
throwReferenceError(Value::fromString(name));
return Value::undefinedValue();
@@ -336,12 +330,6 @@ Value ExecutionContext::getPropertyNoThrow(String *name)
if (hasProperty)
return v;
}
- if (name->isEqualTo(ctx->engine->id_arguments)) {
- Value arguments = Value::fromObject(new (engine->memoryManager) ArgumentsObject(this));
- createMutableBinding(ctx->engine->id_arguments, false);
- setMutableBinding(this, ctx->engine->id_arguments, arguments);
- return arguments;
- }
}
return Value::undefinedValue();
}
@@ -417,14 +405,21 @@ void ExecutionContext::initCallContext(ExecutionContext *parent, const Value tha
if (argc < function->formalParameterCount)
std::fill(arguments + argc, arguments + function->formalParameterCount, Value::undefinedValue());
}
+
locals = function->varCount ? new Value[function->varCount] : 0;
if (function->varCount)
std::fill(locals, locals + function->varCount, Value::undefinedValue());
activation = 0;
-
withObject = 0;
+ if (function->usesArgumentsObject) {
+ ArgumentsObject *args = new (engine->memoryManager) ArgumentsObject(this);
+ args->prototype = engine->objectPrototype;
+ Value arguments = Value::fromObject(args);
+ createMutableBinding(engine->id_arguments, false);
+ setMutableBinding(this, engine->id_arguments, arguments);
+ }
if (engine->debugger)
engine->debugger->aboutToCall(f, this);
diff --git a/qmljs_objects.cpp b/qmljs_objects.cpp
index 871985ac63..ceaa2d72ff 100644
--- a/qmljs_objects.cpp
+++ b/qmljs_objects.cpp
@@ -106,7 +106,6 @@ Value Object::getValue(ExecutionContext *ctx, PropertyDescriptor *p) const
bool Object::inplaceBinOp(Value rhs, String *name, BinOp op, ExecutionContext *ctx)
{
- PropertyDescriptor to_fill;
bool hasProperty = false;
Value v = __get__(ctx, name, &hasProperty);
if (!hasProperty)
@@ -547,6 +546,7 @@ ScriptFunction::ScriptFunction(ExecutionContext *scope, VM::Function *function)
if (!function->name.isEmpty())
name = scope->engine->identifier(function->name);
needsActivation = function->needsActivation();
+ usesArgumentsObject = function->usesArgumentsObject;
strictMode = function->isStrict;
formalParameterCount = function->formals.size();
if (formalParameterCount) {
@@ -795,52 +795,21 @@ Value ScriptFunction::construct(VM::ExecutionContext *ctx)
return ctx->thisObject;
}
-Value ArgumentsObject::__get__(ExecutionContext *ctx, String *name, bool *hasProperty)
-{
- if (name->isEqualTo(ctx->engine->id_length)) {
- if (hasProperty)
- *hasProperty = true;
- return Value::fromInt32(context->argumentCount);
- }
- if (context) {
- bool ok = false;
- int idx = name->toQString().toInt(&ok);
- if (ok && idx >= 0 && idx < context->argumentCount)
- return context->argument(idx);
- }
-
- return Object::__get__(ctx, name, hasProperty);
-}
-
-
ArgumentsObject::ArgumentsObject(ExecutionContext *context)
- : context(context)
{
defineDefaultProperty(context->engine->id_length, Value::fromInt32(context->argumentCount));
-}
-
-void ArgumentsObject::__put__(ExecutionContext *ctx, String *name, Value value)
-{
- if (context) {
- bool ok = false;
- int idx = name->toQString().toInt(&ok);
- if (ok && idx >= 0 && idx < context->argumentCount)
- context->arguments[idx] = value;
- }
-
- return Object::__put__(ctx, name, value);
-}
-
-bool ArgumentsObject::__canPut__(ExecutionContext *ctx, String *name)
-{
- if (context) {
- bool ok = false;
- int idx = name->toQString().toInt(&ok);
- if (ok && idx >= 0 && idx < context->argumentCount)
- return true;
+ for (uint i = 0; i < context->argumentCount; ++i)
+ __put__(context, QString::number(i), context->arguments[i]);
+ if (context->strictMode) {
+ FunctionObject *thrower = context->engine->newNativeFunction(context, 0, __qmljs_throw_type_error);
+ PropertyDescriptor pd = PropertyDescriptor::fromAccessor(thrower, thrower);
+ pd.configurable = PropertyDescriptor::Disabled;
+ pd.enumberable = PropertyDescriptor::Disabled;
+ __defineOwnProperty__(context, QStringLiteral("callee"), &pd);
+ __defineOwnProperty__(context, QStringLiteral("caller"), &pd);
+ } else {
+ defineDefaultProperty(context, QStringLiteral("callee"), Value::fromObject(context->function));
}
-
- return Object::__canPut__(ctx, name);
}
NativeFunction::NativeFunction(ExecutionContext *scope, String *name, Value (*code)(ExecutionContext *))
diff --git a/qmljs_objects.h b/qmljs_objects.h
index ab309718a0..21dc82a2cc 100644
--- a/qmljs_objects.h
+++ b/qmljs_objects.h
@@ -539,6 +539,7 @@ struct Function {
QVector<Function *> nestedFunctions;
bool hasDirectEval: 1;
+ bool usesArgumentsObject : 1;
bool isStrict: 1;
Function(const QString &name)
@@ -546,6 +547,7 @@ struct Function {
, code(0)
, codeData(0)
, hasDirectEval(false)
+ , usesArgumentsObject(false)
, isStrict(false)
{}
~Function();
@@ -563,6 +565,7 @@ struct FunctionObject: Object {
String **varList;
unsigned int varCount;
bool needsActivation;
+ bool usesArgumentsObject;
bool strictMode;
FunctionObject(ExecutionContext *scope)
@@ -573,6 +576,7 @@ struct FunctionObject: Object {
, varList(0)
, varCount(0)
, needsActivation(false)
+ , usesArgumentsObject(false)
, strictMode(false) {}
virtual QString className() { return QStringLiteral("Function"); }
@@ -706,13 +710,9 @@ struct URIErrorObject: ErrorObject {
};
struct ArgumentsObject: Object {
- ExecutionContext *context;
ArgumentsObject(ExecutionContext *context);
virtual QString className() { return QStringLiteral("Arguments"); }
virtual ArgumentsObject *asArgumentsObject() { return this; }
- virtual Value __get__(ExecutionContext *ctx, String *name, bool *hasProperty);
- virtual void __put__(ExecutionContext *ctx, String *name, Value value);
- virtual bool __canPut__(ExecutionContext *ctx, String *name);
};
} // namespace VM
diff --git a/qv4codegen.cpp b/qv4codegen.cpp
index 17b96fe738..6cf1d62beb 100644
--- a/qv4codegen.cpp
+++ b/qv4codegen.cpp
@@ -255,6 +255,14 @@ protected:
}
}
}
+ void checkForArguments(AST::FormalParameterList *parameters)
+ {
+ while (parameters) {
+ if (parameters->name == QStringLiteral("arguments"))
+ _env->usesArgumentsObject = Environment::ArgumentsObjectNotUsed;
+ parameters = parameters->next;
+ }
+ }
virtual bool visit(Program *ast)
{
@@ -273,6 +281,8 @@ protected:
if (! _env->hasDirectEval) {
if (IdentifierExpression *id = cast<IdentifierExpression *>(ast->base)) {
if (id->name == QStringLiteral("eval")) {
+ if (_env->usesArgumentsObject == Environment::ArgumentsObjectUnknown)
+ _env->usesArgumentsObject = Environment::ArgumentsObjectUsed;
_env->hasDirectEval = true;
}
}
@@ -296,6 +306,8 @@ protected:
virtual bool visit(VariableDeclaration *ast)
{
checkName(ast->name, ast->identifierToken);
+ if (ast->name == QLatin1String("arguments"))
+ _env->usesArgumentsObject = Environment::ArgumentsObjectNotUsed;
_env->enter(ast->name.toString());
return true;
}
@@ -303,6 +315,8 @@ protected:
virtual bool visit(IdentifierExpression *ast)
{
checkName(ast->name, ast->identifierToken);
+ if (_env->usesArgumentsObject == Environment::ArgumentsObjectUnknown && ast->name == QLatin1String("arguments"))
+ _env->usesArgumentsObject = Environment::ArgumentsObjectUsed;
return true;
}
@@ -313,6 +327,7 @@ protected:
_env->enter(ast->name.toString());
}
enterEnvironment(ast);
+ checkForArguments(ast->formals);
if (ast->body)
checkDirectivePrologue(ast->body->elements);
return true;
@@ -328,7 +343,10 @@ protected:
_env->functions.append(ast);
_env->hasNestedFunctions = true;
_env->enter(ast->name.toString());
+ if (ast->name == QLatin1String("arguments"))
+ _env->usesArgumentsObject = Environment::ArgumentsObjectNotUsed;
enterEnvironment(ast);
+ checkForArguments(ast->formals);
if (ast->body)
checkDirectivePrologue(ast->body->elements);
return true;
@@ -1661,6 +1679,7 @@ IR::Function *Codegen::defineFunction(const QString &name, AST::Node *ast,
IR::BasicBlock *exitBlock = function->newBasicBlock(IR::Function::DontInsertBlock);
IR::BasicBlock *throwBlock = function->newBasicBlock();
function->hasDirectEval = _env->hasDirectEval;
+ function->usesArgumentsObject = (_env->usesArgumentsObject == Environment::ArgumentsObjectUsed);
function->maxNumberOfArguments = _env->maxNumberOfArguments;
function->isStrict = _env->isStrict;
diff --git a/qv4codegen_p.h b/qv4codegen_p.h
index ba3b477e1b..3776db6304 100644
--- a/qv4codegen_p.h
+++ b/qv4codegen_p.h
@@ -117,6 +117,13 @@ protected:
bool hasDirectEval;
bool hasNestedFunctions;
bool isStrict;
+ enum UsesArgumentsObject {
+ ArgumentsObjectUnknown,
+ ArgumentsObjectNotUsed,
+ ArgumentsObjectUsed
+ };
+
+ UsesArgumentsObject usesArgumentsObject;
Environment(Environment *parent)
: parent(parent)
@@ -124,6 +131,7 @@ protected:
, hasDirectEval(false)
, hasNestedFunctions(false)
, isStrict(false)
+ , usesArgumentsObject(ArgumentsObjectUnknown)
{
if (parent && parent->isStrict)
isStrict = true;
diff --git a/qv4ir_p.h b/qv4ir_p.h
index 5f474f215c..8c570d1947 100644
--- a/qv4ir_p.h
+++ b/qv4ir_p.h
@@ -610,6 +610,7 @@ struct Function {
int insideWith;
bool hasDirectEval: 1;
+ bool usesArgumentsObject : 1;
bool isStrict: 1;
template <typename _Tp> _Tp *New() { return new (pool->allocate(sizeof(_Tp))) _Tp(); }
@@ -621,6 +622,7 @@ struct Function {
, maxNumberOfArguments(0)
, insideWith(0)
, hasDirectEval(false)
+ , usesArgumentsObject(false)
, isStrict(false)
{ this->name = newString(name); }
diff --git a/qv4isel_p.cpp b/qv4isel_p.cpp
index b49d4d3adc..6d5d2297b8 100644
--- a/qv4isel_p.cpp
+++ b/qv4isel_p.cpp
@@ -34,6 +34,7 @@ VM::Function *EvalInstructionSelection::createFunctionMapping(VM::ExecutionEngin
_irToVM.insert(irFunction, vmFunction);
vmFunction->hasDirectEval = irFunction->hasDirectEval;
+ vmFunction->usesArgumentsObject = irFunction->usesArgumentsObject;
vmFunction->isStrict = irFunction->isStrict;
foreach (const QString *formal, irFunction->formals)