aboutsummaryrefslogtreecommitdiffstats
path: root/src/qml/compiler/qv4codegen.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/qml/compiler/qv4codegen.cpp')
-rw-r--r--src/qml/compiler/qv4codegen.cpp73
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);