Skip to content

Commit 8727492

Browse files
committed
Updating async function implementation by desugaring to generators
This change removes the function wrapper implementation of async functions. Now the async functions will behave similar to generator functions. The actual function body will be in the sciptFunction field. Symbols now need not be forced to slots. asyncspawn opcode and parse node are no more needed.In the backend async functions are also added to the generator JIT flag. await is desugared into yield.
1 parent ade59a0 commit 8727492

34 files changed

+5033
-5028
lines changed

lib/Backend/BailOut.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1437,7 +1437,7 @@ BailOutRecord::BailOutHelper(Js::JavascriptCallStackLayout * layout, Js::ScriptF
14371437
Js::InterpreterStackFrame* newInstance = nullptr;
14381438
Js::Var* allocation = nullptr;
14391439

1440-
if (executeFunction->IsGenerator())
1440+
if (executeFunction->IsGenerator() || executeFunction->IsAsync())
14411441
{
14421442
// If the FunctionBody is a generator then this call is being made by one of the three
14431443
// generator resuming methods: next(), throw(), or return(). They all pass the generator

lib/Backend/FlowGraph.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1099,7 +1099,7 @@ FlowGraph::Destroy(void)
10991099
// Skipping Try blocks as we have dependency on blocks to get the last instr(see below in this function)
11001100
if (!fHasTry)
11011101
{
1102-
if (this->func->GetJnFunction()->IsGenerator())
1102+
if (this->func->GetJnFunction()->IsGenerator() || this->func->GetJnFunction()->IsAsync())
11031103
{
11041104
// the label could be a yield resume label, in which case we also need to remove it from the YieldOffsetResumeLabels list
11051105
this->func->MapUntilYieldOffsetResumeLabels([this, &labelInstr](int i, const YieldOffsetResumeLabel& yorl)

lib/Backend/Func.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -214,7 +214,7 @@ Func::Func(JitArenaAllocator *alloc, CodeGenWorkItem* workItem, const Js::Functi
214214
m_nonTempLocalVars = Anew(this->m_alloc, BVSparse<JitArenaAllocator>, this->m_alloc);
215215
}
216216

217-
if (this->m_jnFunction->IsGenerator())
217+
if (this->m_jnFunction->IsGenerator() || this->m_jnFunction->IsAsync())
218218
{
219219
m_yieldOffsetResumeLabelList = YieldOffsetResumeLabelList::New(this->m_alloc);
220220
}
@@ -846,8 +846,8 @@ Func::AjustLocalVarSlotOffset()
846846
bool
847847
Func::DoGlobOptsForGeneratorFunc()
848848
{
849-
// Disable GlobOpt optimizations for generators initially. Will visit and enable each one by one.
850-
return !m_jnFunction->IsGenerator();
849+
// Disable GlobOpt optimizations for generators and asyn functions initially. Will visit and enable each one by one.
850+
return !m_jnFunction->IsGenerator() && !m_jnFunction->IsAsync();
851851
}
852852

853853
void

lib/Backend/Func.h

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -281,12 +281,6 @@ static const unsigned __int64 c_debugFillPattern8 = 0xcececececececece;
281281
Assert(this->m_jnFunction); // For now we always have a function body
282282
return this->m_jnFunction->GetIsGlobalFunc();
283283
}
284-
bool IsGeneratorFunc() const
285-
{
286-
Assert(this->IsTopFunc());
287-
Assert(this->m_jnFunction); // For now we always have a function body
288-
return this->m_jnFunction->IsGenerator();
289-
}
290284
bool IsLambda() const
291285
{
292286
Assert(this->IsTopFunc());

lib/Backend/IRBuilder.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1365,7 +1365,7 @@ IRBuilder::BuildImplicitArgIns()
13651365
void
13661366
IRBuilder::BuildGeneratorPreamble()
13671367
{
1368-
if (!this->m_func->GetJnFunction()->IsGenerator())
1368+
if (!this->m_func->GetJnFunction()->IsGenerator() && !this->m_func->GetJnFunction()->IsAsync())
13691369
{
13701370
return;
13711371
}

lib/Backend/JnHelperMethodList.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -494,7 +494,6 @@ HELPERCALL(ScopedLdSuperCtor, Js::JavascriptOperators::OP_ScopedLdSuperCtor,
494494
HELPERCALL(SetHomeObj, Js::JavascriptOperators::OP_SetHomeObj, 0)
495495

496496
HELPERCALL(ResumeYield, Js::JavascriptOperators::OP_ResumeYield, AttrCanThrow)
497-
HELPERCALL(AsyncSpawn, Js::JavascriptOperators::OP_AsyncSpawn, AttrCanThrow)
498497

499498
#include "ExternalHelperMethodList.h"
500499

lib/Backend/Lower.cpp

Lines changed: 21 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -2956,10 +2956,6 @@ Lowerer::LowerRange(IR::Instr *instrStart, IR::Instr *instrEnd, bool defaultDoFa
29562956
break;
29572957
}
29582958

2959-
case Js::OpCode::AsyncSpawn:
2960-
this->LowerBinaryHelperMem(instr, IR::HelperAsyncSpawn);
2961-
break;
2962-
29632959
case Js::OpCode::FrameDisplayCheck:
29642960
instrPrev = this->LowerFrameDisplayCheck(instr);
29652961
break;
@@ -5088,7 +5084,7 @@ Lowerer::LowerNewScObjArrayNoArg(IR::Instr *newObjInstr)
50885084
void
50895085
Lowerer::LowerPrologEpilog()
50905086
{
5091-
if (m_func->GetJnFunction()->IsGenerator())
5087+
if (m_func->GetJnFunction()->IsGenerator() || m_func->GetJnFunction()->IsAsync())
50925088
{
50935089
LowerGeneratorResumeJumpTable();
50945090
}
@@ -5125,7 +5121,7 @@ Lowerer::LowerPrologEpilogAsmJs()
51255121
void
51265122
Lowerer::LowerGeneratorResumeJumpTable()
51275123
{
5128-
Assert(m_func->GetJnFunction()->IsGenerator());
5124+
Assert(m_func->GetJnFunction()->IsGenerator() || m_func->GetJnFunction()->IsAsync());
51295125

51305126
IR::Instr * jumpTableInstr = m_func->m_headInstr;
51315127
AssertMsg(jumpTableInstr->IsEntryInstr(), "First instr isn't an EntryInstr...");
@@ -7572,7 +7568,7 @@ Lowerer::LoadArgumentCount(IR::Instr *const instr)
75727568
instr->SetSrc1(IR::IntConstOpnd::New(instr->m_func->actualCount, TyUint32, instr->m_func, true));
75737569
LowererMD::ChangeToAssign(instr);
75747570
}
7575-
else if (instr->m_func->GetJnFunction()->IsGenerator())
7571+
else if (instr->m_func->GetJnFunction()->IsGenerator() || instr->m_func->GetJnFunction()->IsAsync())
75767572
{
75777573
IR::SymOpnd* symOpnd = LoadCallInfo(instr);
75787574
instr->SetSrc1(symOpnd);
@@ -9611,7 +9607,7 @@ IR::Instr *Lowerer::LowerRestParameter(IR::Opnd *formalsOpnd, IR::Opnd *dstOpnd,
96119607

96129608
LoadScriptContext(helperCallInstr);
96139609

9614-
BOOL isGenerator = this->m_func->GetJnFunction()->IsGenerator();
9610+
BOOL isGenerator = this->m_func->GetJnFunction()->IsGenerator() || this->m_func->GetJnFunction()->IsAsync();
96159611

96169612
// Elements pointer = ebp + (formals count + formals offset + 1)*sizeof(Var)
96179613
IR::RegOpnd *srcOpnd = isGenerator ? generatorArgsPtrOpnd : IR::Opnd::CreateFramePointerOpnd(this->m_func);
@@ -9719,7 +9715,7 @@ Lowerer::LowerArgIn(IR::Instr *instrArgIn)
97199715
// $createRestArray
97209716
instrArgIn->InsertBefore(createRestArrayLabel);
97219717

9722-
if (m_func->GetJnFunction()->IsGenerator())
9718+
if (m_func->GetJnFunction()->IsGenerator() || m_func->GetJnFunction()->IsAsync())
97239719
{
97249720
generatorArgsPtrOpnd = LoadGeneratorArgsPtr(instrArgIn);
97259721
}
@@ -9738,7 +9734,7 @@ Lowerer::LowerArgIn(IR::Instr *instrArgIn)
97389734
if (argIndex == 1)
97399735
{
97409736
// The "this" argument is not source-dependent and doesn't need to be checked.
9741-
if (m_func->GetJnFunction()->IsGenerator())
9737+
if (m_func->GetJnFunction()->IsGenerator() || m_func->GetJnFunction()->IsAsync())
97429738
{
97439739
generatorArgsPtrOpnd = LoadGeneratorArgsPtr(instrArgIn);
97449740
ConvertArgOpndIfGeneratorFunction(instrArgIn, generatorArgsPtrOpnd);
@@ -9792,7 +9788,7 @@ Lowerer::LowerArgIn(IR::Instr *instrArgIn)
97929788

97939789
// Now insert all the checks and undef-assigns.
97949790

9795-
if (m_func->GetJnFunction()->IsGenerator())
9791+
if (m_func->GetJnFunction()->IsGenerator() || m_func->GetJnFunction()->IsAsync())
97969792
{
97979793
generatorArgsPtrOpnd = LoadGeneratorArgsPtr(instrInsert);
97989794
}
@@ -9962,7 +9958,7 @@ Lowerer::LowerArgIn(IR::Instr *instrArgIn)
99629958
void
99639959
Lowerer::ConvertArgOpndIfGeneratorFunction(IR::Instr *instrArgIn, IR::RegOpnd *generatorArgsPtrOpnd)
99649960
{
9965-
if (this->m_func->GetJnFunction()->IsGenerator())
9961+
if (this->m_func->GetJnFunction()->IsGenerator() || this->m_func->GetJnFunction()->IsAsync())
99669962
{
99679963
// Replace stack param operand with offset into arguments array held by
99689964
// the generator object.
@@ -10668,7 +10664,7 @@ Lowerer::LoadCallInfo(IR::Instr * instrInsert)
1066810664
IR::SymOpnd * srcOpnd;
1066910665
Func * func = instrInsert->m_func;
1067010666

10671-
if (func->GetJnFunction()->IsGenerator())
10667+
if (func->GetJnFunction()->IsGenerator() || func->GetJnFunction()->IsAsync())
1067210668
{
1067310669
// Generator function arguments and ArgumentsInfo are not on the stack. Instead they
1067410670
// are accessed off the generator object (which is prm1).
@@ -18115,7 +18111,7 @@ IR::IndirOpnd*
1811518111
Lowerer::GetArgsIndirOpndForTopFunction(IR::Instr* ldElem, IR::Opnd* valueOpnd)
1811618112
{
1811718113
// Load argument set dst = [ebp + index] (or grab from the generator object if m_func is a generator function).
18118-
IR::RegOpnd *baseOpnd = m_func->GetJnFunction()->IsGenerator() ? LoadGeneratorArgsPtr(ldElem) : IR::Opnd::CreateFramePointerOpnd(m_func);
18114+
IR::RegOpnd *baseOpnd = (m_func->GetJnFunction()->IsGenerator() || m_func->GetJnFunction()->IsAsync()) ? LoadGeneratorArgsPtr(ldElem) : IR::Opnd::CreateFramePointerOpnd(m_func);
1811918115
IR::IndirOpnd* argIndirOpnd = nullptr;
1812018116
// The stack looks like this:
1812118117
// ...
@@ -18129,7 +18125,7 @@ Lowerer::GetArgsIndirOpndForTopFunction(IR::Instr* ldElem, IR::Opnd* valueOpnd)
1812918125

1813018126
//actual arguments offset is LowererMD::GetFormalParamOffset() + 1 (this)
1813118127

18132-
uint16 actualOffset = m_func->GetJnFunction()->IsGenerator() ? 1 : GetFormalParamOffset() + 1; //5
18128+
uint16 actualOffset = (m_func->GetJnFunction()->IsGenerator() || m_func->GetJnFunction()->IsAsync()) ? 1 : GetFormalParamOffset() + 1; //5
1813318129
Assert(actualOffset == 5 || m_func->GetJnFunction()->IsGenerator());
1813418130
if (valueOpnd->IsIntConstOpnd())
1813518131
{
@@ -20327,6 +20323,7 @@ Lowerer::GenerateSetHomeObj(IR::Instr* instrInsert)
2032720323
Func *func = instrInsert->m_func;
2032820324

2032920325
IR::LabelInstr *labelScriptFunction = IR::LabelInstr::New(Js::OpCode::Label, func, false);
20326+
IR::LabelInstr *labelForGeneratorScriptFunction = IR::LabelInstr::New(Js::OpCode::Label, func, false);
2033020327

2033120328
IR::Opnd *src2Opnd = instrInsert->UnlinkSrc2();
2033220329
IR::Opnd *src1Opnd = instrInsert->UnlinkSrc1();
@@ -20338,10 +20335,16 @@ Lowerer::GenerateSetHomeObj(IR::Instr* instrInsert)
2033820335
LowererMD::CreateAssign(funcObjRegOpnd, src1Opnd, instrInsert);
2033920336

2034020337
IR::Opnd * vtableAddressOpnd = this->LoadVTableValueOpnd(instrInsert, VTableValue::VtableJavascriptGeneratorFunction);
20338+
InsertCompareBranch(IR::IndirOpnd::New(funcObjRegOpnd, 0, TyMachPtr, func), vtableAddressOpnd,
20339+
Js::OpCode::BrEq_A, true, labelForGeneratorScriptFunction, instrInsert);
20340+
20341+
vtableAddressOpnd = this->LoadVTableValueOpnd(instrInsert, VTableValue::VtableJavascriptAsyncFunction);
2034120342
InsertCompareBranch(IR::IndirOpnd::New(funcObjRegOpnd, 0, TyMachPtr, func), vtableAddressOpnd,
2034220343
Js::OpCode::BrNeq_A, true, labelScriptFunction, instrInsert);
2034320344

20344-
indirOpnd = IR::IndirOpnd::New(funcObjRegOpnd, Js::JavascriptGeneratorFunction::GetOffsetOfScriptFunction() , TyMachPtr, func);
20345+
instrInsert->InsertBefore(labelForGeneratorScriptFunction);
20346+
20347+
indirOpnd = IR::IndirOpnd::New(funcObjRegOpnd, Js::JavascriptGeneratorFunction::GetOffsetOfScriptFunction(), TyMachPtr, func);
2034520348
LowererMD::CreateAssign(funcObjRegOpnd, indirOpnd, instrInsert);
2034620349

2034720350
instrInsert->InsertBefore(labelScriptFunction);
@@ -20363,7 +20366,7 @@ Lowerer::GenerateLoadNewTarget(IR::Instr* instrInsert)
2036320366

2036420367
Assert(!func->IsInlinee());
2036520368

20366-
if (func->GetJnFunction()->IsGenerator())
20369+
if (func->GetJnFunction()->IsGenerator() || func->GetJnFunction()->IsAsync())
2036720370
{
2036820371
instrInsert->SetSrc1(opndUndefAddress);
2036920372
LowererMD::ChangeToAssign(instrInsert);
@@ -21098,7 +21101,7 @@ void Lowerer::GenerateNullOutGeneratorFrame(IR::Instr* insertInstr)
2109821101

2109921102
void Lowerer::LowerFunctionExit(IR::Instr* funcExit)
2110021103
{
21101-
if (m_func->GetJnFunction()->IsGenerator())
21104+
if (m_func->GetJnFunction()->IsGenerator() || m_func->GetJnFunction()->IsAsync())
2110221105
{
2110321106
GenerateNullOutGeneratorFrame(funcExit->m_prev);
2110421107
}

lib/Backend/amd64/LowererMDArch.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -140,7 +140,7 @@ LowererMDArch::Init(LowererMD *lowererMD)
140140
IR::Instr *
141141
LowererMDArch::LoadInputParamPtr(IR::Instr *instrInsert, IR::RegOpnd *optionalDstOpnd /* = nullptr */)
142142
{
143-
if (this->m_func->GetJnFunction()->IsGenerator())
143+
if (this->m_func->GetJnFunction()->IsGenerator() || this->m_func->GetJnFunction()->IsAsync())
144144
{
145145
IR::RegOpnd * argPtrRegOpnd = Lowerer::LoadGeneratorArgsPtr(instrInsert);
146146
IR::IndirOpnd * indirOpnd = IR::IndirOpnd::New(argPtrRegOpnd, 1 * MachPtr, TyMachPtr, this->m_func);
@@ -380,7 +380,7 @@ LowererMDArch::LoadHeapArguments(IR::Instr *instrArgs, bool force /* = false */,
380380
this->m_func->SetArgOffset(paramSym, 2 * MachPtr);
381381
IR::Opnd * srcOpnd = IR::SymOpnd::New(paramSym, TyMachReg, func);
382382

383-
if (this->m_func->GetJnFunction()->IsGenerator())
383+
if (this->m_func->GetJnFunction()->IsGenerator() || this->m_func->GetJnFunction()->IsAsync())
384384
{
385385
// the function object for generator calls is a GeneratorVirtualScriptFunction object
386386
// and we need to pass the real JavascriptGeneratorFunction object so grab it instead
@@ -430,7 +430,7 @@ LowererMDArch::LoadFuncExpression(IR::Instr *instrFuncExpr)
430430
paramOpnd = IR::SymOpnd::New(paramSym, TyMachReg, this->m_func);
431431
}
432432

433-
if (instrFuncExpr->m_func->GetJnFunction()->IsGenerator())
433+
if (instrFuncExpr->m_func->GetJnFunction()->IsGenerator() || instrFuncExpr->m_func->GetJnFunction()->IsAsync())
434434
{
435435
// the function object for generator calls is a GeneratorVirtualScriptFunction object
436436
// and we need to return the real JavascriptGeneratorFunction object so grab it before

lib/Backend/arm/LowerMD.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1993,7 +1993,7 @@ LowererMD::Init(Lowerer *lowerer)
19931993
IR::Instr *
19941994
LowererMD::LoadInputParamPtr(IR::Instr * instrInsert, IR::RegOpnd * optionalDstOpnd /* = nullptr */)
19951995
{
1996-
if (this->m_func->GetJnFunction()->IsGenerator())
1996+
if (this->m_func->GetJnFunction()->IsGenerator() || this->m_func->GetJnFunction()->IsAsync())
19971997
{
19981998
IR::RegOpnd * argPtrRegOpnd = Lowerer::LoadGeneratorArgsPtr(instrInsert);
19991999
IR::IndirOpnd * indirOpnd = IR::IndirOpnd::New(argPtrRegOpnd, 1 * MachPtr, TyMachPtr, this->m_func);
@@ -2087,7 +2087,7 @@ LowererMD::LoadStackArgPtr(IR::Instr * instr)
20872087
instr->SetSrc1(tmpOpnd);
20882088
instr->SetSrc2(IR::IntConstOpnd::New(sizeof(Js::Var), TyMachReg, this->m_func));
20892089
}
2090-
else if (this->m_func->GetJnFunction()->IsGenerator())
2090+
else if (this->m_func->GetJnFunction()->IsGenerator() || this->m_func->GetJnFunction()->IsAsync())
20912091
{
20922092
IR::Instr *instr2 = LoadInputParamPtr(instr, instr->UnlinkDst()->AsRegOpnd());
20932093
instr->Remove();

lib/Backend/i386/LowererMDArch.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -137,7 +137,7 @@ LowererMDArch::Init(LowererMD *lowererMD)
137137
IR::Instr *
138138
LowererMDArch::LoadInputParamPtr(IR::Instr *instrInsert, IR::RegOpnd *optionalDstOpnd /* = nullptr */)
139139
{
140-
if (this->m_func->GetJnFunction()->IsGenerator())
140+
if (this->m_func->GetJnFunction()->IsGenerator() || this->m_func->GetJnFunction()->IsAsync())
141141
{
142142
IR::RegOpnd * argPtrRegOpnd = Lowerer::LoadGeneratorArgsPtr(instrInsert);
143143
IR::IndirOpnd * indirOpnd = IR::IndirOpnd::New(argPtrRegOpnd, 1 * MachPtr, TyMachPtr, this->m_func);
@@ -334,7 +334,7 @@ LowererMDArch::LoadHeapArguments(IR::Instr *instrArgs, bool force, IR::Opnd* opn
334334
this->m_func->SetArgOffset(paramSym, 2 * MachPtr);
335335
IR::Opnd *srcOpnd = IR::SymOpnd::New(paramSym, TyMachReg, func);
336336

337-
if (this->m_func->GetJnFunction()->IsGenerator())
337+
if (this->m_func->GetJnFunction()->IsGenerator() || this->m_func->GetJnFunction()->IsAsync())
338338
{
339339
// the function object for generator calls is a GeneratorVirtualScriptFunction object
340340
// and we need to pass the real JavascriptGeneratorFunction object so grab it instead
@@ -501,7 +501,7 @@ LowererMDArch::LoadFuncExpression(IR::Instr *instrFuncExpr)
501501
paramOpnd = IR::SymOpnd::New(paramSym, TyMachReg, func);
502502
}
503503

504-
if (instrFuncExpr->m_func->GetJnFunction()->IsGenerator())
504+
if (instrFuncExpr->m_func->GetJnFunction()->IsGenerator() || instrFuncExpr->m_func->GetJnFunction()->IsAsync())
505505
{
506506
// the function object for generator calls is a GeneratorVirtualScriptFunction object
507507
// and we need to return the real JavascriptGeneratorFunction object so grab it before

0 commit comments

Comments
 (0)