diff options
Diffstat (limited to 'src/qml/compiler/qv4codegen.cpp')
| -rw-r--r-- | src/qml/compiler/qv4codegen.cpp | 73 |
1 files changed, 53 insertions, 20 deletions
diff --git a/src/qml/compiler/qv4codegen.cpp b/src/qml/compiler/qv4codegen.cpp index 5851ca3827..44e283a71b 100644 --- a/src/qml/compiler/qv4codegen.cpp +++ b/src/qml/compiler/qv4codegen.cpp @@ -69,6 +69,28 @@ static inline void setJumpOutLocation(QV4::Moth::BytecodeGenerator *bytecodeGene } } +void Codegen::generateThrowException(const QString &type, const QString &text) +{ + RegisterScope scope(this); + Instruction::Construct construct; + if (text.isEmpty()) { + construct.argc = 0; + construct.argv = 0; + } else { + construct.argc = 1; + Instruction::LoadRuntimeString load; + load.stringId = registerString(text); + bytecodeGenerator->addInstruction(load); + construct.argv = Reference::fromAccumulator(this).storeOnStack().stackSlot(); + } + Reference r = referenceForName(type, false); + r = r.storeOnStack(); + construct.func = r.stackSlot(); + bytecodeGenerator->addInstruction(construct); + Instruction::ThrowException throwException; + bytecodeGenerator->addInstruction(throwException); +} + Codegen::Codegen(QV4::Compiler::JSUnitGenerator *jsUnitGenerator, bool strict, CodegenWarningInterface *interface, bool storeSourceLocations) : _module(nullptr), @@ -2139,6 +2161,10 @@ Codegen::Arguments Codegen::pushArgs(ArgumentList *args) Reference e = expression(it->expression); if (hasError()) break; + if (e.throwsReferenceError) { + generateThrowException(QStringLiteral("ReferenceError"), + e.name + QStringLiteral(" is not defined")); + } if (!argc && !it->next && !hasSpread) { // avoid copy for functions taking a single argument if (e.isStackSlot()) @@ -2560,6 +2586,7 @@ bool Codegen::visit(FunctionExpression *ast) Codegen::Reference Codegen::referenceForName(const QString &name, bool isLhs, const SourceLocation &accessLocation) { Context::ResolvedName resolved = _context->resolveName(name, accessLocation); + bool throwsReferenceError = false; if (resolved.type == Context::ResolvedName::Local || resolved.type == Context::ResolvedName::Stack || resolved.type == Context::ResolvedName::Import) { @@ -2572,6 +2599,8 @@ Codegen::Reference Codegen::referenceForName(const QString &name, bool isLhs, co Q_ASSERT(_interface); _interface->reportVarUsedBeforeDeclaration( name, url().toLocalFile(), resolved.declarationLocation, accessLocation); + if (resolved.type == Context::ResolvedName::Stack && resolved.requiresTDZCheck) + throwsReferenceError = true; } if (resolved.isInjected && accessLocation.isValid()) { @@ -2600,6 +2629,7 @@ Codegen::Reference Codegen::referenceForName(const QString &name, bool isLhs, co r.requiresTDZCheck = resolved.requiresTDZCheck; r.name = name; // used to show correct name at run-time when TDZ check fails. r.sourceLocation = accessLocation; + r.throwsReferenceError = throwsReferenceError; return r; } @@ -4447,20 +4477,18 @@ bool Codegen::Reference::storeWipesAccumulator() const void Codegen::Reference::storeAccumulator() const { + if (throwsReferenceError) { + codegen->generateThrowException(QStringLiteral("ReferenceError"), + name + QStringLiteral(" is not defined")); + return; + } + if (isReferenceToConst) { // throw a type error - RegisterScope scope(codegen); - Reference r = codegen->referenceForName(QStringLiteral("TypeError"), false); - r = r.storeOnStack(); - Instruction::Construct construct; - construct.func = r.stackSlot(); - construct.argc = 0; - construct.argv = 0; - codegen->bytecodeGenerator->addInstruction(construct); - Instruction::ThrowException throwException; - codegen->bytecodeGenerator->addInstruction(throwException); + codegen->generateThrowException(QStringLiteral("TypeError")); return; } + switch (type) { case Super: Q_UNREACHABLE_RETURN(); @@ -4531,20 +4559,25 @@ void Codegen::Reference::storeAccumulator() const void Codegen::Reference::loadInAccumulator() const { - auto tdzCheck = [this](bool requiresCheck){ + auto tdzCheck = [this](bool requiresCheck, bool throwsReferenceError) { + if (throwsReferenceError) { + codegen->generateThrowException(QStringLiteral("ReferenceError"), + name + QStringLiteral(" is not defined")); + return; + } if (!requiresCheck) return; Instruction::DeadTemporalZoneCheck check; check.name = codegen->registerString(name); codegen->bytecodeGenerator->addInstruction(check); }; - auto tdzCheckStackSlot = [this, tdzCheck](Moth::StackSlot slot, bool requiresCheck){ + auto tdzCheckStackSlot = [this, tdzCheck](Moth::StackSlot slot, bool requiresCheck, bool throwsReferenceError) { if (!requiresCheck) return; Instruction::LoadReg load; load.reg = slot; codegen->bytecodeGenerator->addInstruction(load); - tdzCheck(true); + tdzCheck(true, throwsReferenceError); }; switch (type) { @@ -4553,7 +4586,7 @@ void Codegen::Reference::loadInAccumulator() const case Super: Q_UNREACHABLE_RETURN(); case SuperProperty: - tdzCheckStackSlot(property, subscriptRequiresTDZCheck); + tdzCheckStackSlot(property, subscriptRequiresTDZCheck, false); Instruction::LoadSuperProperty load; load.property = property.stackSlot(); codegen->bytecodeGenerator->addInstruction(load); @@ -4600,7 +4633,7 @@ QT_WARNING_POP Instruction::LoadReg load; load.reg = stackSlot(); codegen->bytecodeGenerator->addInstruction(load); - tdzCheck(requiresTDZCheck); + tdzCheck(requiresTDZCheck, throwsReferenceError); } return; case ScopedLocal: { if (!scope) { @@ -4613,7 +4646,7 @@ QT_WARNING_POP load.scope = scope; codegen->bytecodeGenerator->addInstruction(load); } - tdzCheck(requiresTDZCheck); + tdzCheck(requiresTDZCheck, throwsReferenceError); return; } case Name: @@ -4655,7 +4688,7 @@ QT_WARNING_POP return; case Member: propertyBase.loadInAccumulator(); - tdzCheck(requiresTDZCheck); + tdzCheck(requiresTDZCheck, throwsReferenceError); if (sourceLocation.isValid()) codegen->bytecodeGenerator->setLocation(sourceLocation); @@ -4691,12 +4724,12 @@ QT_WARNING_POP Instruction::LoadImport load; load.index = index; codegen->bytecodeGenerator->addInstruction(load); - tdzCheck(requiresTDZCheck); + tdzCheck(requiresTDZCheck, throwsReferenceError); } return; case Subscript: { - tdzCheckStackSlot(elementBase, requiresTDZCheck); + tdzCheckStackSlot(elementBase, requiresTDZCheck, throwsReferenceError); elementSubscript.loadInAccumulator(); - tdzCheck(subscriptRequiresTDZCheck); + tdzCheck(subscriptRequiresTDZCheck, false); Instruction::LoadElement load; load.base = elementBase; codegen->bytecodeGenerator->addInstruction(load); |
