diff options
-rw-r--r-- | qmljs_environment.cpp | 21 | ||||
-rw-r--r-- | qmljs_objects.cpp | 55 | ||||
-rw-r--r-- | qmljs_objects.h | 8 | ||||
-rw-r--r-- | qv4codegen.cpp | 19 | ||||
-rw-r--r-- | qv4codegen_p.h | 8 | ||||
-rw-r--r-- | qv4ir_p.h | 2 | ||||
-rw-r--r-- | qv4isel_p.cpp | 1 |
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; @@ -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) |