diff --git a/es2panda/compiler/base/iterators.cpp b/es2panda/compiler/base/iterators.cpp index f88e502870c12ea562fd86ea605656a49571f3a4..57d8c1ffa711195140322935e9608f13b510b1fa 100644 --- a/es2panda/compiler/base/iterators.cpp +++ b/es2panda/compiler/base/iterators.cpp @@ -78,29 +78,7 @@ void Iterator::Value() const void Iterator::Close(bool abruptCompletion) const { if (type_ == IteratorType::SYNC) { - RegScope rs(pg_); - VReg exception = pg_->AllocReg(); - VReg innerResult = pg_->AllocReg(); - Label *noReturn = pg_->AllocLabel(); - - if (abruptCompletion) { - pg_->StoreAccumulator(node_, exception); - } - - // close iterator - pg_->LoadObjByName(node_, iterator_, "return"); - pg_->StoreAccumulator(node_, method_); - pg_->LoadConst(node_, Constant::JS_UNDEFINED); - pg_->Condition(node_, lexer::TokenType::PUNCTUATOR_NOT_STRICT_EQUAL, method_, noReturn); - CallMethod(); - pg_->StoreAccumulator(node_, innerResult); - pg_->ThrowIfNotObject(node_, innerResult); - - pg_->SetLabel(node_, noReturn); - if (abruptCompletion) { - pg_->LoadAccumulator(node_, exception); - pg_->EmitThrow(node_); - } + SyncClose(abruptCompletion); return; } @@ -179,6 +157,64 @@ void Iterator::Close(bool abruptCompletion) const pg_->ThrowIfNotObject(node_, innerResult); } +void Iterator::SyncClose(bool abruptCompletion) const +{ + RegScope rs(pg_); + VReg completion = pg_->AllocReg(); + VReg innerResult = pg_->AllocReg(); + VReg innnerException = pg_->AllocReg(); + Label *noReturn = pg_->AllocLabel(); + Label *finishClose = pg_->AllocLabel(); + + pg_->StoreAccumulator(node_, completion); + + pg_->StoreConst(node_, innnerException, Constant::JS_HOLE); + + TryContext tryCtx(pg_); + const auto &labelSet = tryCtx.LabelSet(); + + pg_->SetLabel(node_, labelSet.TryBegin()); + // 4. Let innerResult be GetMethod(iterator, "return"). + GetMethod("return"); + + // 5. If innerResult.[[Type]] is normal, then + pg_->BranchIfUndefined(node_, noReturn); + + // c. Set innerResult to Call(return, iterator). + CallMethod(); + pg_->StoreAccumulator(node_, innerResult); + pg_->SetLabel(node_, labelSet.TryEnd()); + pg_->Branch(node_, labelSet.CatchEnd()); + + pg_->SetLabel(node_, labelSet.CatchBegin()); + pg_->StoreAccumulator(node_, innnerException); + pg_->SetLabel(node_, labelSet.CatchEnd()); + + // 6. If completion.[[Type]] is throw, return Completion(completion). + if (abruptCompletion) { + pg_->LoadAccumulator(node_, completion); + pg_->EmitThrow(node_); + } else { + // 7. If innerResult.[[Type]] is throw, return Completion(innerResult). + pg_->LoadAccumulator(node_, innnerException); + pg_->EmitRethrow(node_); + } + + // 8. If Type(innerResult.[[Value]]) is not Object, throw a TypeError exception. + pg_->LoadAccumulator(node_, innerResult); + pg_->ThrowIfNotObject(node_, innerResult); + pg_->Branch(node_, finishClose); + + pg_->SetLabel(node_, noReturn); + // b. If return is undefined, return Completion(completion). + pg_->LoadAccumulator(node_, completion); + if (abruptCompletion) { + pg_->EmitThrow(node_); + } + + pg_->SetLabel(node_, finishClose); +} + DestructuringIterator::DestructuringIterator(PandaGen *pg, const ir::AstNode *node) : Iterator(pg, node, IteratorType::SYNC), done_(pg->AllocReg()), result_(pg->AllocReg()) { diff --git a/es2panda/compiler/base/iterators.h b/es2panda/compiler/base/iterators.h index d43bc95687716999dd39dd9b610df843670b61c7..2ae8fa6606309860d0aa38e576c7ba5e5d73c2a6 100644 --- a/es2panda/compiler/base/iterators.h +++ b/es2panda/compiler/base/iterators.h @@ -63,6 +63,8 @@ public: void Complete() const; void Value() const; void Close(bool abruptCompletion) const; + void SyncClose(bool abruptCompletion) const; + void AsyncClose(bool abruptCompletion) const; protected: PandaGen *pg_; diff --git a/es2panda/test/compiler/js/iteratorclose-uncallable-return-test-1-expected.txt b/es2panda/test/compiler/js/iteratorclose-uncallable-return-test-1-expected.txt new file mode 100644 index 0000000000000000000000000000000000000000..a247b96d92d88a1d82c0d137e161f1d329525238 --- /dev/null +++ b/es2panda/test/compiler/js/iteratorclose-uncallable-return-test-1-expected.txt @@ -0,0 +1,2 @@ +1 +123 diff --git a/es2panda/test/compiler/js/iteratorclose-uncallable-return-test-1.js b/es2panda/test/compiler/js/iteratorclose-uncallable-return-test-1.js new file mode 100644 index 0000000000000000000000000000000000000000..5bb33fa2a02ca32f2ec021568d52678b7fa0ac71 --- /dev/null +++ b/es2panda/test/compiler/js/iteratorclose-uncallable-return-test-1.js @@ -0,0 +1,16 @@ +"use strict"; +var iterable = {}; + +iterable[Symbol.iterator] = function() { + return { + next: function() { + return { done: false, value: 1 }; + }, + return: 1 + }; +}; + +for (let i of iterable) { + print(i); + throw "123"; +} diff --git a/es2panda/test/compiler/js/iteratorclose-undefined-return-test-1-expected.txt b/es2panda/test/compiler/js/iteratorclose-undefined-return-test-1-expected.txt new file mode 100644 index 0000000000000000000000000000000000000000..a247b96d92d88a1d82c0d137e161f1d329525238 --- /dev/null +++ b/es2panda/test/compiler/js/iteratorclose-undefined-return-test-1-expected.txt @@ -0,0 +1,2 @@ +1 +123 diff --git a/es2panda/test/compiler/js/iteratorclose-undefined-return-test-1.js b/es2panda/test/compiler/js/iteratorclose-undefined-return-test-1.js new file mode 100644 index 0000000000000000000000000000000000000000..c39bf3e05886c08b67c7412c28049bdce38bc3f8 --- /dev/null +++ b/es2panda/test/compiler/js/iteratorclose-undefined-return-test-1.js @@ -0,0 +1,16 @@ +"use strict"; +var iterable = {}; + +iterable[Symbol.iterator] = function() { + return { + next: function() { + return { done: false, value: 1 }; + }, + return: undefined + }; +}; + +for (let i of iterable) { + print(i); + throw "123"; +}