Skip to content

Commit

Permalink
[MERGE #5834 @rhuanjl] Implement ES2018 Async Iteration (Experimental)
Browse files Browse the repository at this point in the history
Merge pull request #5834 from rhuanjl:asyncIteration
  • Loading branch information
Kevin Smith committed Jun 11, 2019
2 parents 345831e + 953e95d commit c60faa4
Show file tree
Hide file tree
Showing 58 changed files with 8,362 additions and 6,099 deletions.
23 changes: 14 additions & 9 deletions lib/Backend/JnHelperMethodList.h
Expand Up @@ -518,15 +518,20 @@ HELPERCALL(NewPropIdArrForCompProps, Js::InterpreterStackFrame::OP_NewPropIdArrF
HELPERCALL(StPropIdArrFromVar, Js::InterpreterStackFrame::OP_StPropIdArrFromVar, 0)


HELPERCALLCHK(LdHomeObj, Js::JavascriptOperators::OP_LdHomeObj, AttrCanNotBeReentrant)
HELPERCALLCHK(LdFuncObj, Js::JavascriptOperators::OP_LdFuncObj, AttrCanNotBeReentrant)
HELPERCALLCHK(SetHomeObj, Js::JavascriptOperators::OP_SetHomeObj, AttrCanNotBeReentrant)
HELPERCALLCHK(LdHomeObjProto, Js::JavascriptOperators::OP_LdHomeObjProto, AttrCanNotBeReentrant)
HELPERCALLCHK(LdFuncObjProto, Js::JavascriptOperators::OP_LdFuncObjProto, AttrCanNotBeReentrant)

HELPERCALLCHK(ImportCall, Js::JavascriptOperators::OP_ImportCall, 0)

HELPERCALLCHK(ResumeYield, Js::JavascriptOperators::OP_ResumeYield, AttrCanThrow)
HELPERCALLCHK(LdHomeObj, Js::JavascriptOperators::OP_LdHomeObj, AttrCanNotBeReentrant)
HELPERCALLCHK(LdFuncObj, Js::JavascriptOperators::OP_LdFuncObj, AttrCanNotBeReentrant)
HELPERCALLCHK(SetHomeObj, Js::JavascriptOperators::OP_SetHomeObj, AttrCanNotBeReentrant)
HELPERCALLCHK(LdHomeObjProto, Js::JavascriptOperators::OP_LdHomeObjProto, AttrCanNotBeReentrant)
HELPERCALLCHK(LdFuncObjProto, Js::JavascriptOperators::OP_LdFuncObjProto, AttrCanNotBeReentrant)

HELPERCALLCHK(ImportCall, Js::JavascriptOperators::OP_ImportCall, 0)
HELPERCALLCHK(NewAsyncFromSyncIterator, Js::JavascriptOperators::OP_NewAsyncFromSyncIterator, AttrCanNotBeReentrant)

HELPERCALLCHK(AsyncYieldIsReturn, Js::JavascriptOperators::OP_AsyncYieldIsReturn, AttrCanNotBeReentrant)
HELPERCALLCHK(ResumeYield, Js::JavascriptOperators::OP_ResumeYield, AttrCanThrow)
HELPERCALL(AsyncYieldStar, Js::InterpreterStackFrame::OP_AsyncYieldStar, AttrCanNotBeReentrant)
HELPERCALL(AsyncYield, Js::InterpreterStackFrame::OP_AsyncYield, AttrCanNotBeReentrant)
HELPERCALL(Await, Js::InterpreterStackFrame::OP_Await, AttrCanNotBeReentrant)

#if DBG
HELPERCALL(IntRangeCheckFailure, Js::JavascriptNativeOperators::IntRangeCheckFailure, AttrCanNotBeReentrant)
Expand Down
52 changes: 52 additions & 0 deletions lib/Backend/Lower.cpp
Expand Up @@ -2938,6 +2938,58 @@ Lowerer::LowerRange(IR::Instr *instrStart, IR::Instr *instrEnd, bool defaultDoFa
break;
}

case Js::OpCode::NewAsyncFromSyncIterator:
{
IR::Opnd *src1Opnd = instr->UnlinkSrc1();

LoadScriptContext(instr);
m_lowererMD.LoadHelperArgument(instr, src1Opnd);
m_lowererMD.ChangeToHelperCall(instr, IR::HelperNewAsyncFromSyncIterator);

break;
}

case Js::OpCode::Await:
{
IR::Opnd *srcOpnd1 = instr->UnlinkSrc1();
IR::Opnd *srcOpnd2 = instr->UnlinkSrc2();
LoadScriptContext(instr);
m_lowererMD.LoadHelperArgument(instr, srcOpnd2);
m_lowererMD.LoadHelperArgument(instr, srcOpnd1);
m_lowererMD.ChangeToHelperCall(instr, IR::HelperAwait);
break;
}

case Js::OpCode::AsyncYield:
{
IR::Opnd *srcOpnd1 = instr->UnlinkSrc1();
IR::Opnd *srcOpnd2 = instr->UnlinkSrc2();
LoadScriptContext(instr);
m_lowererMD.LoadHelperArgument(instr, srcOpnd2);
m_lowererMD.LoadHelperArgument(instr, srcOpnd1);
m_lowererMD.ChangeToHelperCall(instr, IR::HelperAsyncYield);
break;
}

case Js::OpCode::AsyncYieldIsReturn:
{
IR::Opnd *srcOpnd1 = instr->UnlinkSrc1();
m_lowererMD.LoadHelperArgument(instr, srcOpnd1);
m_lowererMD.ChangeToHelperCall(instr, IR::HelperAsyncYieldIsReturn);
break;
}

case Js::OpCode::AsyncYieldStar:
{
IR::Opnd *srcOpnd1 = instr->UnlinkSrc1();
IR::Opnd *srcOpnd2 = instr->UnlinkSrc2();
LoadScriptContext(instr);
m_lowererMD.LoadHelperArgument(instr, srcOpnd2);
m_lowererMD.LoadHelperArgument(instr, srcOpnd1);
m_lowererMD.ChangeToHelperCall(instr, IR::HelperAsyncYieldStar);
break;
}

case Js::OpCode::Yield:
{
instr->FreeSrc1(); // Source is not actually used by the backend other than to calculate lifetime
Expand Down
2 changes: 2 additions & 0 deletions lib/Common/ConfigFlagsList.h
Expand Up @@ -703,6 +703,7 @@ PHASE(All)
#define DEFAULT_CONFIG_ESObjectGetOwnPropertyDescriptors (true)
#define DEFAULT_CONFIG_ESDynamicImport (false)
#define DEFAULT_CONFIG_ESExportNsAs (true)
#define DEFAULT_CONFIG_ES2018AsyncIteration (false)

#define DEFAULT_CONFIG_ESSharedArrayBuffer (false)

Expand Down Expand Up @@ -1180,6 +1181,7 @@ FLAGPR (Boolean, ES6, ES6Unscopables , "Enable ES6 With Statem
FLAGPR (Boolean, ES6, ES6RegExSticky , "Enable ES6 RegEx sticky flag" , DEFAULT_CONFIG_ES6RegExSticky)
FLAGPR (Boolean, ES6, ES2018RegExDotAll , "Enable ES2018 RegEx dotAll flag" , DEFAULT_CONFIG_ES2018RegExDotAll)
FLAGPR (Boolean, ES6, ESExportNsAs , "Enable ES experimental export * as name" , DEFAULT_CONFIG_ESExportNsAs)
FLAGPR (Boolean, ES6, ES2018AsyncIteration , "Enable ES2018 Async Iteration" , DEFAULT_CONFIG_ES2018AsyncIteration)

#ifndef COMPILE_DISABLE_ES6RegExPrototypeProperties
#define COMPILE_DISABLE_ES6RegExPrototypeProperties 0
Expand Down
76 changes: 39 additions & 37 deletions lib/Jsrt/JsrtDebugUtils.cpp
Expand Up @@ -271,6 +271,7 @@ void JsrtDebugUtils::AddPropertyType(Js::DynamicObject * object, Js::IDiagObject
case Js::TypeIds_WeakSet:
case Js::TypeIds_SymbolObject:
case Js::TypeIds_Generator:
case Js::TypeIds_AsyncFromSyncIterator:
case Js::TypeIds_Promise:
case Js::TypeIds_GlobalObject:
case Js::TypeIds_SpreadArgument:
Expand Down Expand Up @@ -428,9 +429,9 @@ const char16 * JsrtDebugUtils::GetClassName(Js::TypeId typeId)
case Js::TypeIds_MapIterator:
case Js::TypeIds_SetIterator:
case Js::TypeIds_StringIterator:
return _u("Object");
return _u("Object");

case Js::TypeIds_Proxy: return _u("Proxy");
case Js::TypeIds_Proxy: return _u("Proxy");
case Js::TypeIds_Array:
case Js::TypeIds_NativeIntArray:
#if ENABLE_COPYONACCESS_ARRAY
Expand All @@ -440,45 +441,46 @@ const char16 * JsrtDebugUtils::GetClassName(Js::TypeId typeId)
case Js::TypeIds_ES5Array:
case Js::TypeIds_CharArray:
case Js::TypeIds_BoolArray:
return _u("Array");
return _u("Array");

case Js::TypeIds_Date:
case Js::TypeIds_VariantDate:
return _u("Date");

case Js::TypeIds_RegEx: return _u("RegExp");
case Js::TypeIds_Error: return _u("Error");
case Js::TypeIds_BooleanObject: return _u("Boolean");
case Js::TypeIds_NumberObject: return _u("Number");
case Js::TypeIds_StringObject: return _u("String");
case Js::TypeIds_Arguments: return _u("Object");
case Js::TypeIds_ArrayBuffer: return _u("ArrayBuffer");
case Js::TypeIds_Int8Array: return _u("Int8Array");
case Js::TypeIds_Uint8Array: return _u("Uint8Array");
case Js::TypeIds_Uint8ClampedArray: return _u("Uint8ClampedArray");
case Js::TypeIds_Int16Array: return _u("Int16Array");
case Js::TypeIds_Uint16Array: return _u("Uint16Array");
case Js::TypeIds_Int32Array: return _u("Int32Array");
case Js::TypeIds_Uint32Array: return _u("Uint32Array");
case Js::TypeIds_Float32Array: return _u("Float32Array");
case Js::TypeIds_Float64Array: return _u("Float64Array");
case Js::TypeIds_Int64Array: return _u("Int64Array");
case Js::TypeIds_Uint64Array: return _u("Uint64Array");
case Js::TypeIds_DataView: return _u("DataView");
case Js::TypeIds_Map: return _u("Map");
case Js::TypeIds_Set: return _u("Set");
case Js::TypeIds_WeakMap: return _u("WeakMap");
case Js::TypeIds_WeakSet: return _u("WeakSet");
case Js::TypeIds_SymbolObject: return _u("Symbol");
case Js::TypeIds_Generator: return _u("Generator");
case Js::TypeIds_Promise: return _u("Promise");
case Js::TypeIds_GlobalObject: return _u("Object");
case Js::TypeIds_SpreadArgument: return _u("Spread");
return _u("Date");

case Js::TypeIds_RegEx: return _u("RegExp");
case Js::TypeIds_Error: return _u("Error");
case Js::TypeIds_BooleanObject: return _u("Boolean");
case Js::TypeIds_NumberObject: return _u("Number");
case Js::TypeIds_StringObject: return _u("String");
case Js::TypeIds_Arguments: return _u("Object");
case Js::TypeIds_ArrayBuffer: return _u("ArrayBuffer");
case Js::TypeIds_Int8Array: return _u("Int8Array");
case Js::TypeIds_Uint8Array: return _u("Uint8Array");
case Js::TypeIds_Uint8ClampedArray: return _u("Uint8ClampedArray");
case Js::TypeIds_Int16Array: return _u("Int16Array");
case Js::TypeIds_Uint16Array: return _u("Uint16Array");
case Js::TypeIds_Int32Array: return _u("Int32Array");
case Js::TypeIds_Uint32Array: return _u("Uint32Array");
case Js::TypeIds_Float32Array: return _u("Float32Array");
case Js::TypeIds_Float64Array: return _u("Float64Array");
case Js::TypeIds_Int64Array: return _u("Int64Array");
case Js::TypeIds_Uint64Array: return _u("Uint64Array");
case Js::TypeIds_DataView: return _u("DataView");
case Js::TypeIds_Map: return _u("Map");
case Js::TypeIds_Set: return _u("Set");
case Js::TypeIds_WeakMap: return _u("WeakMap");
case Js::TypeIds_WeakSet: return _u("WeakSet");
case Js::TypeIds_SymbolObject: return _u("Symbol");
case Js::TypeIds_Generator: return _u("Generator");
case Js::TypeIds_AsyncFromSyncIterator: return _u("AsyncFromSyncIterator");
case Js::TypeIds_Promise: return _u("Promise");
case Js::TypeIds_GlobalObject: return _u("Object");
case Js::TypeIds_SpreadArgument: return _u("Spread");
#ifdef ENABLE_WASM
case Js::TypeIds_WebAssemblyModule: return _u("WebAssembly.Module");
case Js::TypeIds_WebAssemblyInstance:return _u("WebAssembly.Instance");
case Js::TypeIds_WebAssemblyMemory: return _u("WebAssembly.Memory");
case Js::TypeIds_WebAssemblyTable: return _u("WebAssembly.Table");
case Js::TypeIds_WebAssemblyModule: return _u("WebAssembly.Module");
case Js::TypeIds_WebAssemblyInstance: return _u("WebAssembly.Instance");
case Js::TypeIds_WebAssemblyMemory: return _u("WebAssembly.Memory");
case Js::TypeIds_WebAssemblyTable: return _u("WebAssembly.Table");
#endif
default:
Assert(false);
Expand Down
55 changes: 51 additions & 4 deletions lib/Parser/Parse.cpp
Expand Up @@ -6639,7 +6639,10 @@ void Parser::ParseFncName(ParseNodeFnc * pnodeFnc, ushort flags, IdentPtr* pFncN
{
if (pnodeFnc->IsGenerator())
{
Error(ERRsyntax);
if (!m_scriptContext->GetConfig()->IsES2018AsyncIterationEnabled())
{
Error(ERRExperimental);
}
}
pnodeFnc->SetIsAsync();
}
Expand Down Expand Up @@ -10214,9 +10217,26 @@ ParseNodePtr Parser::ParseStatement()
ParseNodeBlock * pnodeBlock = nullptr;
ParseNodePtr *ppnodeScopeSave = nullptr;
ParseNodePtr *ppnodeExprScopeSave = nullptr;
bool isForAwait = false;

ichMin = this->GetScanner()->IchMinTok();
ChkNxtTok(tkLParen, ERRnoLparen);

this->GetScanner()->Scan();
if (m_token.tk == tkAWAIT || (m_token.tk == tkID && m_token.GetIdentifier(this->GetHashTbl()) == wellKnownPropertyPids.await))
{
if (!this->GetScanner()->AwaitIsKeywordRegion())
{
Error(ERRBadAwait); // for await () in a non-async function
}
if (!m_scriptContext->GetConfig()->IsES2018AsyncIterationEnabled())
{
Error(ERRExperimental);
}
isForAwait = true;
this->GetScanner()->Scan();
}
ChkCurTok(tkLParen, ERRnoLparen);

pnodeBlock = StartParseBlock<buildAST>(PnodeBlockType::Regular, ScopeType_Block);
if (buildAST)
{
Expand Down Expand Up @@ -10343,6 +10363,11 @@ ParseNodePtr Parser::ParseStatement()
bool isForOf = (m_token.tk != tkIN);
Assert(!isForOf || (m_token.tk == tkID && m_token.GetIdentifier(this->GetHashTbl()) == wellKnownPropertyPids.of));

if (isForAwait && !isForOf)
{
Error(ERRTokenAfter, _u("in"), _u("for await"));
}

if ((buildAST && nullptr == pnodeT) || !fForInOrOfOkay)
{
if (isForOf)
Expand Down Expand Up @@ -10370,7 +10395,11 @@ ParseNodePtr Parser::ParseStatement()
ParseNodeForInOrForOf * pnodeForInOrForOf = nullptr;
if (buildAST)
{
if (isForOf)
if (isForAwait)
{
pnodeForInOrForOf = CreateNodeForOpT<knopForAwaitOf>(ichMin);
}
else if (isForOf)
{
pnodeForInOrForOf = CreateNodeForOpT<knopForOf>(ichMin);
}
Expand All @@ -10385,7 +10414,7 @@ ParseNodePtr Parser::ParseStatement()

TrackAssignment<true>(pnodeT, nullptr);
}
PushStmt<buildAST>(&stmt, pnodeForInOrForOf, isForOf ? knopForOf : knopForIn, pLabelIdList);
PushStmt<buildAST>(&stmt, pnodeForInOrForOf, isForAwait ? knopForAwaitOf : (isForOf ? knopForOf : knopForIn), pLabelIdList);
ParseNodePtr pnodeBody = ParseStatement<buildAST>();

if (buildAST)
Expand All @@ -10402,6 +10431,11 @@ ParseNodePtr Parser::ParseStatement()
Error(ERRDestructInit);
}

if (isForAwait)
{
Error(ERRValidIfFollowedBy, _u("'for await'"), _u("'of'"));
}

ChkCurTok(tkSColon, ERRnoSemic);
ParseNodePtr pnodeCond = nullptr;
if (m_token.tk != tkSColon)
Expand Down Expand Up @@ -11640,6 +11674,7 @@ void Parser::InitPids()
wellKnownPropertyPids.get = this->GetHashTbl()->PidHashNameLen(g_ssym_get.sz, g_ssym_get.cch);
wellKnownPropertyPids.set = this->GetHashTbl()->PidHashNameLen(g_ssym_set.sz, g_ssym_set.cch);
wellKnownPropertyPids.let = this->GetHashTbl()->PidHashNameLen(g_ssym_let.sz, g_ssym_let.cch);
wellKnownPropertyPids.await = this->GetHashTbl()->PidHashNameLen(g_ssym_await.sz, g_ssym_await.cch);
wellKnownPropertyPids.constructor = this->GetHashTbl()->PidHashNameLen(g_ssym_constructor.sz, g_ssym_constructor.cch);
wellKnownPropertyPids.prototype = this->GetHashTbl()->PidHashNameLen(g_ssym_prototype.sz, g_ssym_prototype.cch);
wellKnownPropertyPids.__proto__ = this->GetHashTbl()->PidHashNameLen(_u("__proto__"), sizeof("__proto__") - 1);
Expand Down Expand Up @@ -12677,6 +12712,9 @@ ParseNode* Parser::CopyPnode(ParseNode *pnode) {
case knopForOf:
Assert(false);
break;
case knopForAwaitOf:
Assert(false);
break;
//PTNODE(knopReturn , "return" ,None ,Uni ,fnopNone)
case knopReturn: {
ParseNode* copyNode = CreateNodeForOpT<knopReturn>(pnode->ichMin, pnode->ichLim);
Expand Down Expand Up @@ -13485,6 +13523,7 @@ void PrintScopesWIndent(ParseNode *pnode, int indentAmt) {
case knopFor: scope = pnode->AsParseNodeFor()->pnodeBlock; firstOnly = true; break;
case knopForIn: scope = pnode->AsParseNodeForInOrForOf()->pnodeBlock; firstOnly = true; break;
case knopForOf: scope = pnode->AsParseNodeForInOrForOf()->pnodeBlock; firstOnly = true; break;
case knopForAwaitOf: scope = pnode->AsParseNodeForInOrForOf()->pnodeBlock; firstOnly = true; break;
}
if (scope) {
Output::Print(_u("[%4d, %4d): "), scope->ichMin, scope->ichLim);
Expand Down Expand Up @@ -14118,6 +14157,14 @@ void PrintPnodeWIndent(ParseNode *pnode, int indentAmt) {
PrintPnodeWIndent(pnode->AsParseNodeForInOrForOf()->pnodeObj, indentAmt + INDENT_SIZE);
PrintPnodeWIndent(pnode->AsParseNodeForInOrForOf()->pnodeBody, indentAmt + INDENT_SIZE);
break;
case knopForAwaitOf:
Indent(indentAmt);
Output::Print(_u("forAwaitOf\n"));
PrintScopesWIndent(pnode, indentAmt + INDENT_SIZE);
PrintPnodeWIndent(pnode->AsParseNodeForInOrForOf()->pnodeLval, indentAmt + INDENT_SIZE);
PrintPnodeWIndent(pnode->AsParseNodeForInOrForOf()->pnodeObj, indentAmt + INDENT_SIZE);
PrintPnodeWIndent(pnode->AsParseNodeForInOrForOf()->pnodeBody, indentAmt + INDENT_SIZE);
break;
//PTNODE(knopReturn , "return" ,None ,Uni ,fnopNone)
case knopReturn:
Indent(indentAmt);
Expand Down
1 change: 1 addition & 0 deletions lib/Parser/Parse.h
Expand Up @@ -474,6 +474,7 @@ class Parser
IdentPtr set;
IdentPtr get;
IdentPtr let;
IdentPtr await;
IdentPtr constructor;
IdentPtr prototype;
IdentPtr __proto__;
Expand Down
3 changes: 3 additions & 0 deletions lib/Parser/pnodewalk.h
Expand Up @@ -483,6 +483,9 @@ class ParseNodeWalker : public WalkerPolicy
case knopForOf:
return WalkForInOrForOf(pnode->AsParseNodeForInOrForOf(), context);

case knopForAwaitOf:
return WalkForInOrForOf(pnode->AsParseNodeForInOrForOf(), context);

//PTNODE(knopReturn , "return" ,None ,Uni ,fnopNone)
case knopReturn:
return WalkReturn(pnode->AsParseNodeReturn(), context);
Expand Down
1 change: 1 addition & 0 deletions lib/Parser/ptlist.h
Expand Up @@ -135,6 +135,7 @@ PTNODE(knopWhile , "while" , Nop , While , fnopNotExp
PTNODE(knopDoWhile , "do-while" , Nop , While , fnopNotExprStmt|fnopCleanup|fnopBreak|fnopContinue , "DoWhileStmt" )
PTNODE(knopForIn , "for in" , Nop , ForInOrForOf, fnopNotExprStmt|fnopCleanup|fnopBreak|fnopContinue , "ForInStmt" )
PTNODE(knopForOf , "for of" , Nop , ForInOrForOf, fnopNotExprStmt|fnopCleanup|fnopBreak|fnopContinue , "ForOfStmt" )
PTNODE(knopForAwaitOf , "for await of" , Nop , ForInOrForOf, fnopNotExprStmt|fnopCleanup|fnopBreak|fnopContinue , "ForAwaitOfStmt" )
PTNODE(knopBlock , "{}" , Nop , Block , fnopNotExprStmt|fnopAllowDefer, "Block" )
PTNODE(knopStrTemplate, "``" , Nop , StrTemplate , fnopNone , "StringTemplateDecl" )
PTNODE(knopWith , "with" , Nop , With , fnopNotExprStmt , "WithStmt" )
Expand Down

0 comments on commit c60faa4

Please sign in to comment.