We now pass most of the test cases for it.
Change-Id: Idc43a9baa75c3c1e8fe760d78cf5e6092f051c6e
Reviewed-by: Simon Hausmann <simon.hausmann@digia.com>
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();
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();
}
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);
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)
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) {
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 *))
QVector<Function *> nestedFunctions;
bool hasDirectEval: 1;
+ bool usesArgumentsObject : 1;
bool isStrict: 1;
Function(const QString &name)
, code(0)
, codeData(0)
, hasDirectEval(false)
+ , usesArgumentsObject(false)
, isStrict(false)
{}
~Function();
String **varList;
unsigned int varCount;
bool needsActivation;
+ bool usesArgumentsObject;
bool strictMode;
FunctionObject(ExecutionContext *scope)
, varList(0)
, varCount(0)
, needsActivation(false)
+ , usesArgumentsObject(false)
, strictMode(false) {}
virtual QString className() { return QStringLiteral("Function"); }
};
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
}
}
}
+ void checkForArguments(AST::FormalParameterList *parameters)
+ {
+ while (parameters) {
+ if (parameters->name == QStringLiteral("arguments"))
+ _env->usesArgumentsObject = Environment::ArgumentsObjectNotUsed;
+ parameters = parameters->next;
+ }
+ }
virtual bool visit(Program *ast)
{
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;
}
}
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;
}
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;
}
_env->enter(ast->name.toString());
}
enterEnvironment(ast);
+ checkForArguments(ast->formals);
if (ast->body)
checkDirectivePrologue(ast->body->elements);
return true;
_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;
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;
bool hasDirectEval;
bool hasNestedFunctions;
bool isStrict;
+ enum UsesArgumentsObject {
+ ArgumentsObjectUnknown,
+ ArgumentsObjectNotUsed,
+ ArgumentsObjectUsed
+ };
+
+ UsesArgumentsObject usesArgumentsObject;
Environment(Environment *parent)
: parent(parent)
, hasDirectEval(false)
, hasNestedFunctions(false)
, isStrict(false)
+ , usesArgumentsObject(ArgumentsObjectUnknown)
{
if (parent && parent->isStrict)
isStrict = true;
int insideWith;
bool hasDirectEval: 1;
+ bool usesArgumentsObject : 1;
bool isStrict: 1;
template <typename _Tp> _Tp *New() { return new (pool->allocate(sizeof(_Tp))) _Tp(); }
, maxNumberOfArguments(0)
, insideWith(0)
, hasDirectEval(false)
+ , usesArgumentsObject(false)
, isStrict(false)
{ this->name = newString(name); }
_irToVM.insert(irFunction, vmFunction);
vmFunction->hasDirectEval = irFunction->hasDirectEval;
+ vmFunction->usesArgumentsObject = irFunction->usesArgumentsObject;
vmFunction->isStrict = irFunction->isStrict;
foreach (const QString *formal, irFunction->formals)