aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLars Knoll <lars.knoll@qt.io>2018-09-06 13:38:23 +0200
committerLars Knoll <lars.knoll@qt.io>2018-09-07 10:31:57 +0000
commitbd4064eabf79a6166805c877ee622931df6fb172 (patch)
tree9a9d96fbb224ada879836dbfb7cff9e93b44946f
parent15bdbd89639c29f88db1798de66066a4a95759c0 (diff)
Throw a type error when trying to destructure null or undefined
Change-Id: Id1bba1a729124bccb8a90dcf40252fe5c69d27a3 Reviewed-by: Simon Hausmann <simon.hausmann@qt.io>
-rw-r--r--src/qml/compiler/qv4bytecodehandler.cpp3
-rw-r--r--src/qml/compiler/qv4codegen.cpp4
-rw-r--r--src/qml/compiler/qv4instr_moth.cpp3
-rw-r--r--src/qml/compiler/qv4instr_moth_p.h2
-rw-r--r--src/qml/jit/qv4baselinejit.cpp11
-rw-r--r--src/qml/jit/qv4baselinejit_p.h1
-rw-r--r--src/qml/jit/qv4jithelpers.cpp6
-rw-r--r--src/qml/jit/qv4jithelpers_p.h1
-rw-r--r--src/qml/jsruntime/qv4vme_moth.cpp7
-rw-r--r--tests/auto/qml/ecmascripttests/TestExpectations4
10 files changed, 38 insertions, 4 deletions
diff --git a/src/qml/compiler/qv4bytecodehandler.cpp b/src/qml/compiler/qv4bytecodehandler.cpp
index 3a3f4a6adb..5b836c2e9c 100644
--- a/src/qml/compiler/qv4bytecodehandler.cpp
+++ b/src/qml/compiler/qv4bytecodehandler.cpp
@@ -528,6 +528,9 @@ std::vector<int> ByteCodeHandler::collectLabelsInBytecode(const char *code, uint
COLLECTOR_BEGIN_INSTR(InitializeBlockDeadTemporalZone)
COLLECTOR_END_INSTR(InitializeBlockDeadTemporalZone)
+ COLLECTOR_BEGIN_INSTR(ThrowOnNullOrUndefined)
+ COLLECTOR_END_INSTR(ThrowOnNullOrUndefined)
+
COLLECTOR_BEGIN_INSTR(LoadQmlContext)
COLLECTOR_END_INSTR(LoadQmlContext)
diff --git a/src/qml/compiler/qv4codegen.cpp b/src/qml/compiler/qv4codegen.cpp
index 1d6e8819f5..2415142df4 100644
--- a/src/qml/compiler/qv4codegen.cpp
+++ b/src/qml/compiler/qv4codegen.cpp
@@ -619,6 +619,10 @@ void Codegen::destructurePropertyList(const Codegen::Reference &object, PatternP
{
RegisterScope scope(this);
+ object.loadInAccumulator();
+ Instruction::ThrowOnNullOrUndefined t;
+ bytecodeGenerator->addInstruction(t);
+
for (PatternPropertyList *it = bindingList; it; it = it->next) {
PatternProperty *p = it->property;
RegisterScope scope(this);
diff --git a/src/qml/compiler/qv4instr_moth.cpp b/src/qml/compiler/qv4instr_moth.cpp
index b09f1d09d0..00a1e8470b 100644
--- a/src/qml/compiler/qv4instr_moth.cpp
+++ b/src/qml/compiler/qv4instr_moth.cpp
@@ -702,6 +702,9 @@ void dumpBytecode(const char *code, int len, int nLocals, int nFormals, int /*st
d << dumpRegister(firstReg, nFormals) << ", " << count;
MOTH_END_INSTR(InitializeBlockDeadTemporalZone)
+ MOTH_BEGIN_INSTR(ThrowOnNullOrUndefined)
+ MOTH_END_INSTR(ThrowOnNullOrUndefined)
+
MOTH_BEGIN_INSTR(LoadQmlContext)
d << dumpRegister(result, nFormals);
MOTH_END_INSTR(LoadQmlContext)
diff --git a/src/qml/compiler/qv4instr_moth_p.h b/src/qml/compiler/qv4instr_moth_p.h
index 40313551e8..34c80db0e8 100644
--- a/src/qml/compiler/qv4instr_moth_p.h
+++ b/src/qml/compiler/qv4instr_moth_p.h
@@ -195,6 +195,7 @@ QT_BEGIN_NAMESPACE
#define INSTR_LoadQmlContext(op) INSTRUCTION(op, LoadQmlContext, 1, result)
#define INSTR_LoadQmlImportedScripts(op) INSTRUCTION(op, LoadQmlImportedScripts, 1, result)
#define INSTR_InitializeBlockDeadTemporalZone(op) INSTRUCTION(op, InitializeBlockDeadTemporalZone, 2, firstReg, count)
+#define INSTR_ThrowOnNullOrUndefined(op) INSTRUCTION(op, ThrowOnNullOrUndefined, 0)
#define FOR_EACH_MOTH_INSTR_ALL(F) \
F(Nop) \
@@ -332,6 +333,7 @@ QT_BEGIN_NAMESPACE
F(PushScriptContext) \
F(PopScriptContext) \
F(InitializeBlockDeadTemporalZone) \
+ F(ThrowOnNullOrUndefined) \
F(Debug) \
#define MOTH_NUM_INSTRUCTIONS() (static_cast<int>(Moth::Instr::Type::Debug_Wide) + 1)
diff --git a/src/qml/jit/qv4baselinejit.cpp b/src/qml/jit/qv4baselinejit.cpp
index d0ac169e4f..baaab75158 100644
--- a/src/qml/jit/qv4baselinejit.cpp
+++ b/src/qml/jit/qv4baselinejit.cpp
@@ -956,6 +956,17 @@ void BaselineJIT::generate_InitializeBlockDeadTemporalZone(int firstReg, int cou
as->storeReg(i);
}
+void BaselineJIT::generate_ThrowOnNullOrUndefined()
+{
+ STORE_ACC();
+ as->prepareCallWithArgCount(2);
+ as->passAccumulatorAsArg(1);
+ as->passEngineAsArg(0);
+ BASELINEJIT_GENERATE_RUNTIME_CALL(Helpers::throwOnNullOrUndefined, CallResultDestination::Ignore);
+ as->checkException();
+}
+
+
void BaselineJIT::startInstruction(Instr::Type /*instr*/)
{
if (hasLabel())
diff --git a/src/qml/jit/qv4baselinejit_p.h b/src/qml/jit/qv4baselinejit_p.h
index 7e3fcfa5e6..f9c876a1e9 100644
--- a/src/qml/jit/qv4baselinejit_p.h
+++ b/src/qml/jit/qv4baselinejit_p.h
@@ -211,6 +211,7 @@ public:
void generate_LoadQmlContext(int result) override;
void generate_LoadQmlImportedScripts(int result) override;
void generate_InitializeBlockDeadTemporalZone(int firstReg, int count) override;
+ void generate_ThrowOnNullOrUndefined() override;
void startInstruction(Moth::Instr::Type instr) override;
void endInstruction(Moth::Instr::Type instr) override;
diff --git a/src/qml/jit/qv4jithelpers.cpp b/src/qml/jit/qv4jithelpers.cpp
index 7bac5d968d..427356e5ed 100644
--- a/src/qml/jit/qv4jithelpers.cpp
+++ b/src/qml/jit/qv4jithelpers.cpp
@@ -146,6 +146,12 @@ ReturnedValue deleteName(Function *function, int name)
}
}
+void throwOnNullOrUndefined(ExecutionEngine *engine, const Value &v)
+{
+ if (v.isNullOrUndefined())
+ engine->throwTypeError();
+}
+
} // Helpers namespace
} // JIT namespace
} // QV4 namespace
diff --git a/src/qml/jit/qv4jithelpers_p.h b/src/qml/jit/qv4jithelpers_p.h
index bb10d5722b..dd68452e7f 100644
--- a/src/qml/jit/qv4jithelpers_p.h
+++ b/src/qml/jit/qv4jithelpers_p.h
@@ -76,6 +76,7 @@ void pushScriptContext(Value *stack, ExecutionEngine *engine, int index);
void popScriptContext(Value *stack, ExecutionEngine *engine);
ReturnedValue deleteProperty(QV4::Function *function, const QV4::Value &base, const QV4::Value &index);
ReturnedValue deleteName(Function *function, int name);
+void throwOnNullOrUndefined(ExecutionEngine *engine, const Value &v);
} // Helpers namespace
} // JIT namespace
diff --git a/src/qml/jsruntime/qv4vme_moth.cpp b/src/qml/jsruntime/qv4vme_moth.cpp
index f38bd7b48e..6ed371bbf2 100644
--- a/src/qml/jsruntime/qv4vme_moth.cpp
+++ b/src/qml/jsruntime/qv4vme_moth.cpp
@@ -1344,6 +1344,13 @@ QV4::ReturnedValue VME::interpret(CppStackFrame *frame, ExecutionEngine *engine,
STACK_VALUE(i) = acc;
MOTH_END_INSTR(InitializeBlockDeadTemporalZone)
+ MOTH_BEGIN_INSTR(ThrowOnNullOrUndefined)
+ if (Primitive::fromReturnedValue(acc).isNullOrUndefined()) {
+ engine->throwTypeError();
+ goto handleUnwind;
+ }
+ MOTH_END_INSTR(ThrowOnNullOrUndefined)
+
MOTH_BEGIN_INSTR(Debug)
#if QT_CONFIG(qml_debug)
STORE_IP();
diff --git a/tests/auto/qml/ecmascripttests/TestExpectations b/tests/auto/qml/ecmascripttests/TestExpectations
index e88bf14bf8..26a9f4fc23 100644
--- a/tests/auto/qml/ecmascripttests/TestExpectations
+++ b/tests/auto/qml/ecmascripttests/TestExpectations
@@ -656,8 +656,6 @@ language/expressions/assignment/dstr-array-rest-iter-thrw-close-err.js fails
language/expressions/assignment/dstr-array-rest-iter-thrw-close.js fails
language/expressions/assignment/dstr-array-rest-lref-err.js fails
language/expressions/assignment/dstr-array-rest-put-let.js fails
-language/expressions/assignment/dstr-obj-empty-null.js fails
-language/expressions/assignment/dstr-obj-empty-undef.js fails
language/expressions/assignment/dstr-obj-id-put-let.js fails
language/expressions/assignment/dstr-obj-prop-put-let.js fails
language/expressions/assignment/fn-name-lhs-cover.js fails
@@ -1014,8 +1012,6 @@ language/statements/for-of/dstr-array-rest-iter-thrw-close-err.js fails
language/statements/for-of/dstr-array-rest-iter-thrw-close.js fails
language/statements/for-of/dstr-array-rest-lref-err.js fails
language/statements/for-of/dstr-array-rest-put-let.js fails
-language/statements/for-of/dstr-obj-empty-null.js fails
-language/statements/for-of/dstr-obj-empty-undef.js fails
language/statements/for-of/dstr-obj-id-put-let.js fails
language/statements/for-of/dstr-obj-prop-put-let.js fails
language/statements/for-of/head-var-bound-names-let.js sloppyFails