@@ -54,7 +54,7 @@ void ESTreeIRGen::genStatement(ESTree::Node *stmt) {
5454 }
5555
5656 if (auto *FOS = llvh::dyn_cast<ESTree::ForOfStatementNode>(stmt)) {
57- return genForOfStatement (FOS);
57+ return FOS-> _await ? genAsyncForOfStatement (FOS) : genForOfStatement (FOS);
5858 }
5959
6060 if (auto *Ret = llvh::dyn_cast<ESTree::ReturnStatementNode>(stmt)) {
@@ -974,6 +974,104 @@ void ESTreeIRGen::genForOfStatement(ESTree::ForOfStatementNode *forOfStmt) {
974974 Builder.setInsertionBlock (exitBlock);
975975}
976976
977+ void ESTreeIRGen::genAsyncForOfStatement (
978+ ESTree::ForOfStatementNode *forOfStmt) {
979+ auto *outerScope = curFunction ()->curScope ();
980+
981+ // If block scoping is enabled, check if anything in the loop might capture,
982+ // so we know whether to create inner scopes for the loop.
983+ bool createInnerScopes = Mod->getContext ().getEnableES6BlockScoping () &&
984+ !treeDoesNotCapture (forOfStmt);
985+
986+ // Create an inner scope for the loop init if needed and set it as the top
987+ // scope. All loop variables will be declared in this scope.
988+ if (createInnerScopes) {
989+ auto *initScope = Builder.createCreateScopeInst (
990+ curFunction ()->getOrCreateInnerVariableScope (forOfStmt), outerScope);
991+ curFunction ()->setCurScope (initScope);
992+ }
993+
994+ emitScopeDeclarations (forOfStmt->getScope ());
995+
996+ auto *function = Builder.getInsertionBlock ()->getParent ();
997+ auto *getNextBlock = Builder.createBasicBlock (function);
998+ auto *bodyBlock = Builder.createBasicBlock (function);
999+ auto *exitBlock = Builder.createBasicBlock (function);
1000+
1001+ // Initialize the goto labels.
1002+ curFunction ()->initLabel (forOfStmt, exitBlock, getNextBlock);
1003+
1004+ auto *exprValue = genExpression (forOfStmt->_right );
1005+ const IteratorRecordSlow iteratorRecord = emitGetAsyncIteratorSlow (exprValue);
1006+
1007+ Builder.createBranchInst (getNextBlock);
1008+
1009+ // Attempt to retrieve the next value. If iteration is complete, finish the
1010+ // loop. This stays outside the SurroundingTry below because exceptions in
1011+ // `.next()` should not call `.return()` on the iterator.
1012+ Builder.setInsertionBlock (getNextBlock);
1013+ auto *nextResult = genYieldOrAwaitExpr (emitIteratorNextSlow (iteratorRecord));
1014+ auto *done = emitIteratorCompleteSlow (nextResult);
1015+ Builder.createCondBranchInst (done, exitBlock, bodyBlock);
1016+
1017+ Builder.setInsertionBlock (bodyBlock);
1018+
1019+ // Create a scope for the body if needed.
1020+ if (createInnerScopes) {
1021+ auto *innerScope = Builder.createCreateScopeInst (
1022+ curFunction ()->curScope ()->getVariableScope (), outerScope);
1023+ curFunction ()->setCurScope (innerScope);
1024+ }
1025+
1026+ auto *nextValue = emitIteratorValueSlow (nextResult);
1027+
1028+ emitTryCatchScaffolding (
1029+ getNextBlock,
1030+ // emitBody.
1031+ [this , forOfStmt, nextValue, &iteratorRecord, getNextBlock](
1032+ BasicBlock *catchBlock) {
1033+ // Generate IR for the body of Try
1034+ SurroundingTry thisTry{
1035+ curFunction (),
1036+ forOfStmt,
1037+ catchBlock,
1038+ {},
1039+ [this , &iteratorRecord, getNextBlock, forOfStmt](
1040+ ESTree::Node *,
1041+ ControlFlowChange cfc,
1042+ BasicBlock *continueTarget) {
1043+ // Only emit the iteratorClose if this is a
1044+ // 'break' or if the target of the control flow
1045+ // change is outside the current loop. If
1046+ // continuing the existing loop, do not close
1047+ // the iterator.
1048+ if (cfc == ControlFlowChange::Break ||
1049+ continueTarget != getNextBlock)
1050+ emitAsyncIteratorCloseSlow (forOfStmt, iteratorRecord, false );
1051+ }};
1052+
1053+ // Note: obtaining the value is not protected, but storing it is.
1054+ createLRef (forOfStmt->_left , false ).emitStore (nextValue);
1055+
1056+ genStatement (forOfStmt->_body );
1057+ Builder.setLocation (SourceErrorManager::convertEndToLocation (
1058+ forOfStmt->_body ->getSourceRange ()));
1059+ },
1060+ // emitNormalCleanup.
1061+ []() {},
1062+ // emitHandler.
1063+ [this , &iteratorRecord, forOfStmt](BasicBlock *) {
1064+ auto *catchReg = Builder.createCatchInst ();
1065+ emitAsyncIteratorCloseSlow (forOfStmt, iteratorRecord, true );
1066+ Builder.createThrowInst (catchReg);
1067+ });
1068+
1069+ // Restore the outer scope for subsequent code.
1070+ curFunction ()->setCurScope (outerScope);
1071+
1072+ Builder.setInsertionBlock (exitBlock);
1073+ }
1074+
9771075void ESTreeIRGen::genForOfFastArrayStatement (
9781076 ESTree::ForOfStatementNode *forOfStmt,
9791077 flow::ArrayType *type) {
0 commit comments