aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorLars Knoll <lars.knoll@qt.io>2018-05-11 22:23:56 +0200
committerLars Knoll <lars.knoll@qt.io>2018-05-13 12:55:20 +0000
commit3d5ba9f86e32950204bfcdf6591c4740a8ef7507 (patch)
tree9c599ad6b7fd2bd06d0880dde70ff21d6f522bef /src
parent2d6b08bd17377aa6bcb663029a196a8d19cac6ac (diff)
Add instructions to simplify for-of loops
Added an IteratorNext instruction to fetch the next iteration value (empty if the iterator is done). This will also help to implement array destructuring without requiring huge amounts of byte code. Change-Id: If96c1e81471e5e2b0b7b2af122238d87741aa371 Reviewed-by: Simon Hausmann <simon.hausmann@qt.io>
Diffstat (limited to 'src')
-rw-r--r--src/qml/compiler/qv4codegen.cpp23
-rw-r--r--src/qml/compiler/qv4instr_moth.cpp7
-rw-r--r--src/qml/compiler/qv4instr_moth_p.h4
-rw-r--r--src/qml/jit/qv4assembler.cpp19
-rw-r--r--src/qml/jit/qv4assembler_p.h1
-rw-r--r--src/qml/jit/qv4jit.cpp21
-rw-r--r--src/qml/jit/qv4jit_p.h2
-rw-r--r--src/qml/jsruntime/qv4engine.cpp2
-rw-r--r--src/qml/jsruntime/qv4engine_p.h5
-rw-r--r--src/qml/jsruntime/qv4runtime.cpp18
-rw-r--r--src/qml/jsruntime/qv4runtimeapi_p.h3
-rw-r--r--src/qml/jsruntime/qv4vme_moth.cpp11
12 files changed, 101 insertions, 15 deletions
diff --git a/src/qml/compiler/qv4codegen.cpp b/src/qml/compiler/qv4codegen.cpp
index 49f0511116..97b71ddbcc 100644
--- a/src/qml/compiler/qv4codegen.cpp
+++ b/src/qml/compiler/qv4codegen.cpp
@@ -2640,19 +2640,17 @@ bool Codegen::visit(ForEachStatement *ast)
if (ExpressionNode *e = ast->lhs->expressionCast()) {
if (AST::Pattern *p = e->patternCast()) {
RegisterScope scope(this);
- Reference right = Reference::fromMember(lhsValue, QStringLiteral("value")).storeOnStack();
- destructurePattern(p, right);
+ destructurePattern(p, lhsValue);
} else {
Reference lhs = expression(e);
if (hasError)
goto error;
lhs = lhs.asLValue();
- Reference::fromMember(lhsValue, QStringLiteral("value")).loadInAccumulator();
+ lhsValue.loadInAccumulator();
lhs.storeConsumeAccumulator();
}
} else if (PatternElement *p = AST::cast<PatternElement *>(ast->lhs)) {
- Reference::fromMember(lhsValue, QStringLiteral("value")).loadInAccumulator();
- initializeAndDestructureBindingElement(p, Reference::fromAccumulator(this));
+ initializeAndDestructureBindingElement(p, lhsValue);
if (hasError)
goto error;
} else {
@@ -2666,16 +2664,15 @@ bool Codegen::visit(ForEachStatement *ast)
error:
in.link();
- Reference next = Reference::fromMember(iterator, QStringLiteral("next"));
- next.loadInAccumulator();
- next = next.asLValue();
- Codegen::Arguments args{0, 0};
- handleCall(next, args);
+ iterator.loadInAccumulator();
+ Instruction::IteratorNext next;
+ bytecodeGenerator->addInstruction(next);
+ Instruction::JumpEmpty jump;
+ BytecodeGenerator::Jump done = bytecodeGenerator->addJumpInstruction(jump);
lhsValue.storeConsumeAccumulator();
- Reference done = Reference::fromMember(lhsValue, QStringLiteral("done"));
- done.loadInAccumulator();
- bytecodeGenerator->jumpFalse().link(body);
+ bytecodeGenerator->jump().link(body);
+ done.link();
end.link();
return false;
}
diff --git a/src/qml/compiler/qv4instr_moth.cpp b/src/qml/compiler/qv4instr_moth.cpp
index 7d9dc25ced..58aa7d7cfd 100644
--- a/src/qml/compiler/qv4instr_moth.cpp
+++ b/src/qml/compiler/qv4instr_moth.cpp
@@ -433,6 +433,9 @@ void dumpBytecode(const char *code, int len, int nLocals, int nFormals, int /*st
d << iterator;
MOTH_END_INSTR(GetIterator)
+ MOTH_BEGIN_INSTR(IteratorNext)
+ MOTH_END_INSTR(IteratorNext)
+
MOTH_BEGIN_INSTR(DeleteMember)
d << dumpRegister(base, nFormals) << "[" << member << "]";
MOTH_END_INSTR(DeleteMember)
@@ -503,6 +506,10 @@ void dumpBytecode(const char *code, int len, int nLocals, int nFormals, int /*st
d << ABSOLUTE_OFFSET();
MOTH_END_INSTR(JumpNotUndefined)
+ MOTH_BEGIN_INSTR(JumpEmpty)
+ d << ABSOLUTE_OFFSET();
+ MOTH_END_INSTR(JumpEmpty)
+
MOTH_BEGIN_INSTR(CmpEqNull)
MOTH_END_INSTR(CmpEqNull)
diff --git a/src/qml/compiler/qv4instr_moth_p.h b/src/qml/compiler/qv4instr_moth_p.h
index 96ab593609..301a43a519 100644
--- a/src/qml/compiler/qv4instr_moth_p.h
+++ b/src/qml/compiler/qv4instr_moth_p.h
@@ -122,6 +122,7 @@ QT_BEGIN_NAMESPACE
#define INSTR_PopScriptContext(op) INSTRUCTION(op, PopScriptContext, 0)
#define INSTR_PopContext(op) INSTRUCTION(op, PopContext, 1, reg)
#define INSTR_GetIterator(op) INSTRUCTION(op, GetIterator, 1, iterator)
+#define INSTR_IteratorNext(op) INSTRUCTION(op, IteratorNext, 0)
#define INSTR_DeleteMember(op) INSTRUCTION(op, DeleteMember, 2, member, base)
#define INSTR_DeleteSubscript(op) INSTRUCTION(op, DeleteSubscript, 2, base, index)
#define INSTR_DeleteName(op) INSTRUCTION(op, DeleteName, 1, name)
@@ -141,6 +142,7 @@ QT_BEGIN_NAMESPACE
#define INSTR_JumpTrue(op) INSTRUCTION(op, JumpTrue, 1, offset)
#define INSTR_JumpFalse(op) INSTRUCTION(op, JumpFalse, 1, offset)
#define INSTR_JumpNotUndefined(op) INSTRUCTION(op, JumpNotUndefined, 1, offset)
+#define INSTR_JumpEmpty(op) INSTRUCTION(op, JumpEmpty, 1, offset)
#define INSTR_CmpEqNull(op) INSTRUCTION(op, CmpEqNull, 0)
#define INSTR_CmpNeNull(op) INSTRUCTION(op, CmpNeNull, 0)
#define INSTR_CmpEqInt(op) INSTRUCTION(op, CmpEqInt, 1, lhs)
@@ -248,6 +250,7 @@ QT_BEGIN_NAMESPACE
F(PopScriptContext) \
F(PopContext) \
F(GetIterator) \
+ F(IteratorNext) \
F(DeleteMember) \
F(DeleteSubscript) \
F(DeleteName) \
@@ -266,6 +269,7 @@ QT_BEGIN_NAMESPACE
F(JumpTrue) \
F(JumpFalse) \
F(JumpNotUndefined) \
+ F(JumpEmpty) \
F(CmpEqNull) \
F(CmpNeNull) \
F(CmpEqInt) \
diff --git a/src/qml/jit/qv4assembler.cpp b/src/qml/jit/qv4assembler.cpp
index c73b3919ae..736dfd0908 100644
--- a/src/qml/jit/qv4assembler.cpp
+++ b/src/qml/jit/qv4assembler.cpp
@@ -707,6 +707,12 @@ struct PlatformAssembler64 : PlatformAssemblerCommon
patches.push_back({ jump, offset });
}
+ void jumpEmpty(int offset)
+ {
+ auto jump = branch64(Equal, AccumulatorRegister, TrustedImm64(Primitive::emptyValue().asReturnedValue()));
+ patches.push_back({ jump, offset });
+ }
+
void toBoolean(std::function<void(RegisterID)> continuation)
{
urshift64(AccumulatorRegister, TrustedImm32(Value::IsIntegerConvertible_Shift), ScratchRegister);
@@ -1150,6 +1156,14 @@ struct PlatformAssembler32 : PlatformAssemblerCommon
patches.push_back({ jump, offset });
}
+ void jumpEmpty(int offset)
+ {
+ auto notEqual = branch32(NotEqual, AccumulatorRegisterTag, TrustedImm32(Primitive::emptyValue().asReturnedValue() >> 32));
+ auto jump = branch32(Equal, AccumulatorRegisterValue, TrustedImm32(Primitive::emptyValue().asReturnedValue() & 0xffffffff));
+ notEqual.link(this);
+ patches.push_back({ jump, offset });
+ }
+
void toBoolean(std::function<void(RegisterID)> continuation)
{
urshift32(AccumulatorRegisterTag, TrustedImm32(Value::IsIntegerConvertible_Shift - 32),
@@ -2001,6 +2015,11 @@ void Assembler::jumpNotUndefined(int offset)
pasm()->jumpNotUndefined(offset);
}
+void JIT::Assembler::jumpEmpty(int offset)
+{
+ pasm()->jumpEmpty(offset);
+}
+
void Assembler::jumpStrictEqualStackSlotInt(int lhs, int rhs, int offset)
{
pasm()->jumpStrictEqualStackSlotInt(lhs, rhs, offset);
diff --git a/src/qml/jit/qv4assembler_p.h b/src/qml/jit/qv4assembler_p.h
index f9a74edc77..99ae48e5ed 100644
--- a/src/qml/jit/qv4assembler_p.h
+++ b/src/qml/jit/qv4assembler_p.h
@@ -141,6 +141,7 @@ public:
void jumpTrue(int offset);
void jumpFalse(int offset);
void jumpNotUndefined(int offset);
+ void jumpEmpty(int offset);
void jumpStrictEqualStackSlotInt(int lhs, int rhs, int offset);
void jumpStrictNotEqualStackSlotInt(int lhs, int rhs, int offset);
diff --git a/src/qml/jit/qv4jit.cpp b/src/qml/jit/qv4jit.cpp
index 4f95232f0d..77024176ae 100644
--- a/src/qml/jit/qv4jit.cpp
+++ b/src/qml/jit/qv4jit.cpp
@@ -714,6 +714,17 @@ void BaselineJIT::generate_GetIterator(int iterator)
as->checkException();
}
+void BaselineJIT::generate_IteratorNext()
+{
+ as->saveAccumulatorInFrame();
+ as->prepareCallWithArgCount(2);
+ as->passAccumulatorAsArg(1);
+ as->passEngineAsArg(0);
+ JIT_GENERATE_RUNTIME_CALL(Runtime::method_iteratorNext, Assembler::ResultInAccumulator);
+ as->checkException();
+}
+
+
static ReturnedValue deleteMemberHelper(QV4::Function *function, const QV4::Value &base, int member)
{
auto engine = function->internalClass->engine;
@@ -907,6 +918,7 @@ void BaselineJIT::generate_Jump(int offset) { as->jump(instructionOffset() + off
void BaselineJIT::generate_JumpTrue(int offset) { as->jumpTrue(instructionOffset() + offset); }
void BaselineJIT::generate_JumpFalse(int offset) { as->jumpFalse(instructionOffset() + offset); }
void BaselineJIT::generate_JumpNotUndefined(int offset) { as->jumpNotUndefined(instructionOffset() + offset); }
+void BaselineJIT::generate_JumpEmpty(int offset) { as->jumpEmpty(instructionOffset() + offset); }
void BaselineJIT::generate_CmpEqNull() { as->cmpeqNull(); }
void BaselineJIT::generate_CmpNeNull() { as->cmpneNull(); }
@@ -1264,6 +1276,9 @@ void BaselineJIT::collectLabelsInBytecode()
MOTH_BEGIN_INSTR(GetIterator)
MOTH_END_INSTR(GetIterator)
+ MOTH_BEGIN_INSTR(IteratorNext)
+ MOTH_END_INSTR(IteratorNext)
+
MOTH_BEGIN_INSTR(DeleteMember)
MOTH_END_INSTR(DeleteMember)
@@ -1320,7 +1335,11 @@ void BaselineJIT::collectLabelsInBytecode()
MOTH_BEGIN_INSTR(JumpNotUndefined)
addLabel(code - start + offset);
- MOTH_END_INSTR(JumpUndefined)
+ MOTH_END_INSTR(JumpNotUndefined)
+
+ MOTH_BEGIN_INSTR(JumpEmpty)
+ addLabel(code - start + offset);
+ MOTH_END_INSTR(JumpEmpty)
MOTH_BEGIN_INSTR(CmpEqNull)
MOTH_END_INSTR(CmpEqNull)
diff --git a/src/qml/jit/qv4jit_p.h b/src/qml/jit/qv4jit_p.h
index 333cf05f09..d395ea908c 100644
--- a/src/qml/jit/qv4jit_p.h
+++ b/src/qml/jit/qv4jit_p.h
@@ -186,6 +186,7 @@ public:
void generate_PopScriptContext() override;
void generate_PopContext(int reg) override;
void generate_GetIterator(int iterator) override;
+ void generate_IteratorNext() override;
void generate_DeleteMember(int member, int base) override;
void generate_DeleteSubscript(int base, int index) override;
void generate_DeleteName(int name) override;
@@ -206,6 +207,7 @@ public:
void generate_JumpTrue(int offset) override;
void generate_JumpFalse(int offset) override;
void generate_JumpNotUndefined(int offset) override;
+ void generate_JumpEmpty(int offset) override;
void generate_CmpEqNull() override;
void generate_CmpNeNull() override;
void generate_CmpEqInt(int lhs) override;
diff --git a/src/qml/jsruntime/qv4engine.cpp b/src/qml/jsruntime/qv4engine.cpp
index b703f6e4f3..8227fe0184 100644
--- a/src/qml/jsruntime/qv4engine.cpp
+++ b/src/qml/jsruntime/qv4engine.cpp
@@ -268,6 +268,8 @@ ExecutionEngine::ExecutionEngine(QJSEngine *jsEngine)
jsStrings[String_byteOffset] = newIdentifier(QStringLiteral("byteOffset"));
jsStrings[String_buffer] = newIdentifier(QStringLiteral("buffer"));
jsStrings[String_lastIndex] = newIdentifier(QStringLiteral("lastIndex"));
+ jsStrings[String_next] = newIdentifier(QStringLiteral("next"));
+ jsStrings[String_done] = newIdentifier(QStringLiteral("done"));
jsSymbols[Symbol_hasInstance] = Symbol::create(this, QStringLiteral("@Symbol.hasInstance"));
jsSymbols[Symbol_isConcatSpreadable] = Symbol::create(this, QStringLiteral("@Symbol.isConcatSpreadable"));
diff --git a/src/qml/jsruntime/qv4engine_p.h b/src/qml/jsruntime/qv4engine_p.h
index e8218d0d1c..46bf58de07 100644
--- a/src/qml/jsruntime/qv4engine_p.h
+++ b/src/qml/jsruntime/qv4engine_p.h
@@ -327,6 +327,9 @@ public:
String_byteOffset,
String_buffer,
String_lastIndex,
+ String_next,
+ String_done,
+
NJSStrings
};
Value *jsStrings;
@@ -384,6 +387,8 @@ public:
String *id_byteOffset() const { return reinterpret_cast<String *>(jsStrings + String_byteOffset); }
String *id_buffer() const { return reinterpret_cast<String *>(jsStrings + String_buffer); }
String *id_lastIndex() const { return reinterpret_cast<String *>(jsStrings + String_lastIndex); }
+ String *id_next() const { return reinterpret_cast<String *>(jsStrings + String_next); }
+ String *id_done() const { return reinterpret_cast<String *>(jsStrings + String_done); }
Symbol *symbol_hasInstance() const { return reinterpret_cast<Symbol *>(jsSymbols + Symbol_hasInstance); }
Symbol *symbol_isConcatSpreadable() const { return reinterpret_cast<Symbol *>(jsSymbols + Symbol_isConcatSpreadable); }
diff --git a/src/qml/jsruntime/qv4runtime.cpp b/src/qml/jsruntime/qv4runtime.cpp
index 986684302c..eadbcb9557 100644
--- a/src/qml/jsruntime/qv4runtime.cpp
+++ b/src/qml/jsruntime/qv4runtime.cpp
@@ -715,6 +715,24 @@ ReturnedValue Runtime::method_getIterator(ExecutionEngine *engine, const Value &
return engine->newForInIteratorObject(o)->asReturnedValue();
}
+ReturnedValue Runtime::method_iteratorNext(ExecutionEngine *engine, const Value &iterator)
+{
+ Q_ASSERT(iterator.isObject());
+
+ Scope scope(engine);
+ ScopedFunctionObject f(scope, static_cast<const Object &>(iterator).get(engine->id_next()));
+ if (!f)
+ return engine->throwTypeError();
+ JSCallData cData(scope, 0, nullptr, &iterator);
+ ScopedObject o(scope, f->call(cData));
+ if (!o)
+ return engine->throwTypeError();
+ ScopedValue v(scope, o->get(engine->id_done()));
+ if (v->toBoolean() == true)
+ return Primitive::emptyValue().asReturnedValue();
+ return o->get(engine->id_value());
+}
+
void Runtime::method_storeNameSloppy(ExecutionEngine *engine, int nameIndex, const Value &value)
{
Scope scope(engine);
diff --git a/src/qml/jsruntime/qv4runtimeapi_p.h b/src/qml/jsruntime/qv4runtimeapi_p.h
index c98433359b..1e14c23d7e 100644
--- a/src/qml/jsruntime/qv4runtimeapi_p.h
+++ b/src/qml/jsruntime/qv4runtimeapi_p.h
@@ -144,8 +144,9 @@ struct ExceptionCheck<void (*)(QV4::NoThrowEngine *, A, B, C)> {
F(ReturnedValue, arrayLiteral, (ExecutionEngine *engine, Value *values, uint length)) \
F(ReturnedValue, objectLiteral, (ExecutionEngine *engine, const Value *args, int classId, int arrayValueCount, int arrayGetterSetterCountAndFlags)) \
\
- /* for-in and for-of */ \
+ /* for-in, for-of and array destructuring */ \
F(ReturnedValue, getIterator, (ExecutionEngine *engine, const Value &in, int iterator)) \
+ F(ReturnedValue, iteratorNext, (ExecutionEngine *engine, const Value &iterator)) \
\
/* unary operators */ \
F(ReturnedValue, uMinus, (const Value &value)) \
diff --git a/src/qml/jsruntime/qv4vme_moth.cpp b/src/qml/jsruntime/qv4vme_moth.cpp
index 5daead19d2..9fd57e0dcb 100644
--- a/src/qml/jsruntime/qv4vme_moth.cpp
+++ b/src/qml/jsruntime/qv4vme_moth.cpp
@@ -959,6 +959,12 @@ QV4::ReturnedValue VME::interpret(CppStackFrame &frame, const uchar *code)
CHECK_EXCEPTION;
MOTH_END_INSTR(GetIterator)
+ MOTH_BEGIN_INSTR(IteratorNext)
+ STORE_ACC();
+ acc = Runtime::method_iteratorNext(engine, accumulator);
+ CHECK_EXCEPTION;
+ MOTH_END_INSTR(IteratorNext)
+
MOTH_BEGIN_INSTR(DeleteMember)
if (!Runtime::method_deleteMember(engine, STACK_VALUE(base), member)) {
if (function->isStrict()) {
@@ -1086,6 +1092,11 @@ QV4::ReturnedValue VME::interpret(CppStackFrame &frame, const uchar *code)
code += offset;
MOTH_END_INSTR(JumpNotUndefined)
+ MOTH_BEGIN_INSTR(JumpEmpty)
+ if (Q_UNLIKELY(acc == QV4::Primitive::emptyValue().asReturnedValue()))
+ code += offset;
+ MOTH_END_INSTR(JumpEmpty)
+
MOTH_BEGIN_INSTR(CmpEqNull)
acc = Encode(ACC.isNullOrUndefined());
MOTH_END_INSTR(CmpEqNull)