|
|
@@ -21,6 +21,18 @@ bool CallTargetIsArray(ParseNode *pnode)
|
|
|
return pnode->nop == knopName && pnode->sxPid.PropertyIdFromNameNode() == Js::PropertyIds::Array;
|
|
|
}
|
|
|
|
|
|
+#define STARTSTATEMENET_IFTOPLEVEL(isTopLevel, pnode) \
|
|
|
+if ((isTopLevel)) \
|
|
|
+{ \
|
|
|
+ byteCodeGenerator->StartStatement(pnode); \
|
|
|
+}
|
|
|
+
|
|
|
+#define ENDSTATEMENET_IFTOPLEVEL(isTopLevel, pnode) \
|
|
|
+if ((isTopLevel)) \
|
|
|
+{ \
|
|
|
+ byteCodeGenerator->EndStatement(pnode); \
|
|
|
+}
|
|
|
+
|
|
|
BOOL MayHaveSideEffectOnNode(ParseNode *pnode, ParseNode *pnodeSE)
|
|
|
{
|
|
|
// Try to determine whether pnodeSE may kill the named var represented by pnode.
|
|
|
@@ -208,7 +220,7 @@ bool IsArguments(ParseNode *pnode)
|
|
|
}
|
|
|
|
|
|
bool ApplyEnclosesArgs(ParseNode* fncDecl, ByteCodeGenerator* byteCodeGenerator);
|
|
|
-void Emit(ParseNode *pnode, ByteCodeGenerator *byteCodeGenerator, FuncInfo *funcInfo, BOOL fReturnValue, bool isConstructorCall = false, ParseNode *bindPnode = nullptr);
|
|
|
+void Emit(ParseNode *pnode, ByteCodeGenerator *byteCodeGenerator, FuncInfo *funcInfo, BOOL fReturnValue, bool isConstructorCall = false, ParseNode *bindPnode = nullptr, bool isTopLevel = false);
|
|
|
void EmitComputedFunctionNameVar(ParseNode *nameNode, ParseNode *exprNode, ByteCodeGenerator *byteCodeGenerator);
|
|
|
void EmitBinaryOpnds(ParseNode *pnode1, ParseNode *pnode2, ByteCodeGenerator *byteCodeGenerator, FuncInfo *funcInfo);
|
|
|
bool IsExpressionStatement(ParseNode* stmt, const Js::ScriptContext *const scriptContext);
|
|
|
@@ -952,7 +964,7 @@ void ByteCodeGenerator::EmitTopLevelStatement(ParseNode *stmt, FuncInfo *funcInf
|
|
|
EndStatement(stmt);
|
|
|
}
|
|
|
|
|
|
- Emit(stmt, this, funcInfo, fReturnValue);
|
|
|
+ Emit(stmt, this, funcInfo, fReturnValue, false/*isConstructorCall*/, nullptr/*bindPnode*/, true/*isTopLevel*/);
|
|
|
if (funcInfo->IsTmpReg(stmt->location))
|
|
|
{
|
|
|
if (!stmt->isUsed && !fReturnValue)
|
|
|
@@ -9355,7 +9367,7 @@ void TrackGlobalIntAssignments(ParseNodePtr pnode, ByteCodeGenerator * byteCodeG
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-void Emit(ParseNode *pnode, ByteCodeGenerator *byteCodeGenerator, FuncInfo *funcInfo, BOOL fReturnValue, bool isConstructorCall, ParseNode * bindPnode)
|
|
|
+void Emit(ParseNode *pnode, ByteCodeGenerator *byteCodeGenerator, FuncInfo *funcInfo, BOOL fReturnValue, bool isConstructorCall, ParseNode * bindPnode, bool isTopLevel)
|
|
|
{
|
|
|
if (pnode == nullptr)
|
|
|
{
|
|
|
@@ -9463,29 +9475,36 @@ void Emit(ParseNode *pnode, ByteCodeGenerator *byteCodeGenerator, FuncInfo *func
|
|
|
// Unary operators.
|
|
|
// PTNODE(knopNot , "~" ,BitNot ,Uni ,fnopUni)
|
|
|
case knopNot:
|
|
|
+ STARTSTATEMENET_IFTOPLEVEL(isTopLevel, pnode);
|
|
|
Emit(pnode->sxUni.pnode1, byteCodeGenerator, funcInfo, false);
|
|
|
funcInfo->ReleaseLoc(pnode->sxUni.pnode1);
|
|
|
byteCodeGenerator->Writer()->Reg2(
|
|
|
Js::OpCode::Not_A, funcInfo->AcquireLoc(pnode), pnode->sxUni.pnode1->location);
|
|
|
+ ENDSTATEMENET_IFTOPLEVEL(isTopLevel, pnode);
|
|
|
break;
|
|
|
// PTNODE(knopNeg , "unary -" ,Neg ,Uni ,fnopUni)
|
|
|
case knopNeg:
|
|
|
+ STARTSTATEMENET_IFTOPLEVEL(isTopLevel, pnode);
|
|
|
Emit(pnode->sxUni.pnode1, byteCodeGenerator, funcInfo, false);
|
|
|
funcInfo->ReleaseLoc(pnode->sxUni.pnode1);
|
|
|
funcInfo->AcquireLoc(pnode);
|
|
|
byteCodeGenerator->Writer()->Reg2(
|
|
|
Js::OpCode::Neg_A, pnode->location, pnode->sxUni.pnode1->location);
|
|
|
+ ENDSTATEMENET_IFTOPLEVEL(isTopLevel, pnode);
|
|
|
break;
|
|
|
// PTNODE(knopPos , "unary +" ,Pos ,Uni ,fnopUni)
|
|
|
case knopPos:
|
|
|
+ STARTSTATEMENET_IFTOPLEVEL(isTopLevel, pnode);
|
|
|
Emit(pnode->sxUni.pnode1, byteCodeGenerator, funcInfo, false);
|
|
|
funcInfo->ReleaseLoc(pnode->sxUni.pnode1);
|
|
|
byteCodeGenerator->Writer()->Reg2(
|
|
|
Js::OpCode::Conv_Num, funcInfo->AcquireLoc(pnode), pnode->sxUni.pnode1->location);
|
|
|
+ ENDSTATEMENET_IFTOPLEVEL(isTopLevel, pnode);
|
|
|
break;
|
|
|
// PTNODE(knopLogNot , "!" ,LogNot ,Uni ,fnopUni)
|
|
|
case knopLogNot:
|
|
|
{
|
|
|
+ STARTSTATEMENET_IFTOPLEVEL(isTopLevel, pnode);
|
|
|
Js::ByteCodeLabel doneLabel = byteCodeGenerator->Writer()->DefineLabel();
|
|
|
// For boolean expressions that compute a result, we have to burn a register for the result
|
|
|
// so that the back end can identify it cheaply as a single temp lifetime. Revisit this if we do
|
|
|
@@ -9506,6 +9525,7 @@ void Emit(ParseNode *pnode, ByteCodeGenerator *byteCodeGenerator, FuncInfo *func
|
|
|
byteCodeGenerator->Writer()->MarkLabel(doneLabel);
|
|
|
}
|
|
|
funcInfo->ReleaseLoc(pnode->sxUni.pnode1);
|
|
|
+ ENDSTATEMENET_IFTOPLEVEL(isTopLevel, pnode);
|
|
|
break;
|
|
|
}
|
|
|
// PTNODE(knopEllipsis , "..." ,Spread ,Uni , fnopUni)
|
|
|
@@ -9621,6 +9641,7 @@ void Emit(ParseNode *pnode, ByteCodeGenerator *byteCodeGenerator, FuncInfo *func
|
|
|
// PTNODE(knopTypeof , "typeof" ,None ,Uni ,fnopUni)
|
|
|
case knopTypeof:
|
|
|
{
|
|
|
+ STARTSTATEMENET_IFTOPLEVEL(isTopLevel, pnode);
|
|
|
ParseNode* pnodeOpnd = pnode->sxUni.pnode1;
|
|
|
switch (pnodeOpnd->nop)
|
|
|
{
|
|
|
@@ -9659,6 +9680,7 @@ void Emit(ParseNode *pnode, ByteCodeGenerator *byteCodeGenerator, FuncInfo *func
|
|
|
Js::OpCode::Typeof, funcInfo->AcquireLoc(pnode), pnodeOpnd->location);
|
|
|
break;
|
|
|
}
|
|
|
+ ENDSTATEMENET_IFTOPLEVEL(isTopLevel, pnode);
|
|
|
break;
|
|
|
}
|
|
|
// PTNODE(knopVoid , "void" ,Void ,Uni ,fnopUni)
|
|
|
@@ -9669,12 +9691,16 @@ void Emit(ParseNode *pnode, ByteCodeGenerator *byteCodeGenerator, FuncInfo *func
|
|
|
break;
|
|
|
// PTNODE(knopArray , "arr cnst" ,None ,Uni ,fnopUni)
|
|
|
case knopArray:
|
|
|
+ STARTSTATEMENET_IFTOPLEVEL(isTopLevel, pnode);
|
|
|
EmitArrayLiteral(pnode, byteCodeGenerator, funcInfo);
|
|
|
+ ENDSTATEMENET_IFTOPLEVEL(isTopLevel, pnode);
|
|
|
break;
|
|
|
// PTNODE(knopObject , "obj cnst" ,None ,Uni ,fnopUni)
|
|
|
case knopObject:
|
|
|
+ STARTSTATEMENET_IFTOPLEVEL(isTopLevel, pnode);
|
|
|
funcInfo->AcquireLoc(pnode);
|
|
|
EmitObjectInitializers(pnode->sxUni.pnode1, pnode->location, byteCodeGenerator, funcInfo);
|
|
|
+ ENDSTATEMENET_IFTOPLEVEL(isTopLevel, pnode);
|
|
|
break;
|
|
|
// PTNODE(knopComputedName, "[name]" ,None ,Uni ,fnopUni)
|
|
|
case knopComputedName:
|
|
|
@@ -9710,7 +9736,7 @@ void Emit(ParseNode *pnode, ByteCodeGenerator *byteCodeGenerator, FuncInfo *func
|
|
|
break;
|
|
|
case knopInstOf:
|
|
|
{
|
|
|
- byteCodeGenerator->StartStatement(pnode);
|
|
|
+ STARTSTATEMENET_IFTOPLEVEL(isTopLevel, pnode);
|
|
|
EmitBinaryOpnds(pnode->sxBin.pnode1, pnode->sxBin.pnode2, byteCodeGenerator, funcInfo);
|
|
|
funcInfo->ReleaseLoc(pnode->sxBin.pnode2);
|
|
|
funcInfo->ReleaseLoc(pnode->sxBin.pnode1);
|
|
|
@@ -9718,7 +9744,7 @@ void Emit(ParseNode *pnode, ByteCodeGenerator *byteCodeGenerator, FuncInfo *func
|
|
|
uint cacheId = funcInfo->NewIsInstInlineCache();
|
|
|
byteCodeGenerator->Writer()->Reg3C(nopToOp[pnode->nop], pnode->location, pnode->sxBin.pnode1->location,
|
|
|
pnode->sxBin.pnode2->location, cacheId);
|
|
|
- byteCodeGenerator->EndStatement(pnode);
|
|
|
+ ENDSTATEMENET_IFTOPLEVEL(isTopLevel, pnode);
|
|
|
}
|
|
|
break;
|
|
|
case knopEq:
|
|
|
@@ -9729,14 +9755,14 @@ void Emit(ParseNode *pnode, ByteCodeGenerator *byteCodeGenerator, FuncInfo *func
|
|
|
case knopLe:
|
|
|
case knopGe:
|
|
|
case knopGt:
|
|
|
- byteCodeGenerator->StartStatement(pnode);
|
|
|
+ STARTSTATEMENET_IFTOPLEVEL(isTopLevel, pnode);
|
|
|
EmitBinaryOpnds(pnode->sxBin.pnode1, pnode->sxBin.pnode2, byteCodeGenerator, funcInfo);
|
|
|
funcInfo->ReleaseLoc(pnode->sxBin.pnode2);
|
|
|
funcInfo->ReleaseLoc(pnode->sxBin.pnode1);
|
|
|
funcInfo->AcquireLoc(pnode);
|
|
|
byteCodeGenerator->Writer()->Reg3(nopToCMOp[pnode->nop], pnode->location, pnode->sxBin.pnode1->location,
|
|
|
pnode->sxBin.pnode2->location);
|
|
|
- byteCodeGenerator->EndStatement(pnode);
|
|
|
+ ENDSTATEMENET_IFTOPLEVEL(isTopLevel, pnode);
|
|
|
break;
|
|
|
case knopNew:
|
|
|
{
|
|
|
@@ -9915,7 +9941,7 @@ void Emit(ParseNode *pnode, ByteCodeGenerator *byteCodeGenerator, FuncInfo *func
|
|
|
}
|
|
|
case knopIndex:
|
|
|
{
|
|
|
- byteCodeGenerator->StartStatement(pnode);
|
|
|
+ STARTSTATEMENET_IFTOPLEVEL(isTopLevel, pnode);
|
|
|
EmitBinaryOpnds(pnode->sxBin.pnode1, pnode->sxBin.pnode2, byteCodeGenerator, funcInfo);
|
|
|
funcInfo->ReleaseLoc(pnode->sxBin.pnode2);
|
|
|
funcInfo->ReleaseLoc(pnode->sxBin.pnode1);
|
|
|
@@ -9926,7 +9952,7 @@ void Emit(ParseNode *pnode, ByteCodeGenerator *byteCodeGenerator, FuncInfo *func
|
|
|
EmitSuperMethodBegin(pnode, byteCodeGenerator, funcInfo);
|
|
|
byteCodeGenerator->Writer()->Element(
|
|
|
Js::OpCode::LdElemI_A, pnode->location, protoLocation, pnode->sxBin.pnode2->location);
|
|
|
- byteCodeGenerator->EndStatement(pnode);
|
|
|
+ ENDSTATEMENET_IFTOPLEVEL(isTopLevel, pnode);
|
|
|
break;
|
|
|
}
|
|
|
// this is MemberExpression as rvalue
|
|
|
@@ -10003,7 +10029,7 @@ void Emit(ParseNode *pnode, ByteCodeGenerator *byteCodeGenerator, FuncInfo *func
|
|
|
|
|
|
case knopComma:
|
|
|
{
|
|
|
- byteCodeGenerator->StartStatement(pnode);
|
|
|
+ STARTSTATEMENET_IFTOPLEVEL(isTopLevel, pnode);
|
|
|
// The parser marks binary opnd pnodes as used, but value of the first opnd of a comma is not used.
|
|
|
// Easier to correct this here than to check every binary op in the parser.
|
|
|
ParseNode *pnode1 = pnode->sxBin.pnode1;
|
|
|
@@ -10059,7 +10085,7 @@ void Emit(ParseNode *pnode, ByteCodeGenerator *byteCodeGenerator, FuncInfo *func
|
|
|
{
|
|
|
byteCodeGenerator->Writer()->Reg2(Js::OpCode::Ld_A, pnode->location, pnode->sxBin.pnode2->location);
|
|
|
}
|
|
|
- byteCodeGenerator->EndStatement(pnode);
|
|
|
+ ENDSTATEMENET_IFTOPLEVEL(isTopLevel, pnode);
|
|
|
}
|
|
|
break;
|
|
|
|
|
|
@@ -10069,6 +10095,7 @@ void Emit(ParseNode *pnode, ByteCodeGenerator *byteCodeGenerator, FuncInfo *func
|
|
|
// PTNODE(knopLogOr , "||" ,None ,Bin ,fnopBin)
|
|
|
case knopLogOr:
|
|
|
{
|
|
|
+ STARTSTATEMENET_IFTOPLEVEL(isTopLevel, pnode);
|
|
|
Js::ByteCodeLabel doneLabel = byteCodeGenerator->Writer()->DefineLabel();
|
|
|
// For boolean expressions that compute a result, we have to burn a register for the result
|
|
|
// so that the back end can identify it cheaply as a single temp lifetime. Revisit this if we do
|
|
|
@@ -10084,11 +10111,13 @@ void Emit(ParseNode *pnode, ByteCodeGenerator *byteCodeGenerator, FuncInfo *func
|
|
|
byteCodeGenerator->Writer()->Reg2(Js::OpCode::Ld_A, pnode->location, pnode->sxBin.pnode2->location);
|
|
|
funcInfo->ReleaseLoc(pnode->sxBin.pnode2);
|
|
|
byteCodeGenerator->Writer()->MarkLabel(doneLabel);
|
|
|
+ ENDSTATEMENET_IFTOPLEVEL(isTopLevel, pnode);
|
|
|
break;
|
|
|
}
|
|
|
// PTNODE(knopLogAnd , "&&" ,None ,Bin ,fnopBin)
|
|
|
case knopLogAnd:
|
|
|
{
|
|
|
+ STARTSTATEMENET_IFTOPLEVEL(isTopLevel, pnode);
|
|
|
Js::ByteCodeLabel doneLabel = byteCodeGenerator->Writer()->DefineLabel();
|
|
|
// For boolean expressions that compute a result, we have to burn a register for the result
|
|
|
// so that the back end can identify it cheaply as a single temp lifetime. Revisit this if we do
|
|
|
@@ -10104,6 +10133,7 @@ void Emit(ParseNode *pnode, ByteCodeGenerator *byteCodeGenerator, FuncInfo *func
|
|
|
byteCodeGenerator->Writer()->Reg2(Js::OpCode::Ld_A, pnode->location, pnode->sxBin.pnode2->location);
|
|
|
funcInfo->ReleaseLoc(pnode->sxBin.pnode2);
|
|
|
byteCodeGenerator->Writer()->MarkLabel(doneLabel);
|
|
|
+ ENDSTATEMENET_IFTOPLEVEL(isTopLevel, pnode);
|
|
|
break;
|
|
|
}
|
|
|
// PTNODE(knopQmark , "?" ,None ,Tri ,fnopBin)
|
|
|
@@ -10152,7 +10182,7 @@ void Emit(ParseNode *pnode, ByteCodeGenerator *byteCodeGenerator, FuncInfo *func
|
|
|
case knopAsgLsh:
|
|
|
case knopAsgRsh:
|
|
|
case knopAsgRs2:
|
|
|
- byteCodeGenerator->StartStatement(pnode);
|
|
|
+ STARTSTATEMENET_IFTOPLEVEL(isTopLevel, pnode);
|
|
|
// Assign a register for the result only if the result is used or the LHS can't be assigned to
|
|
|
// (i.e., is a constant).
|
|
|
if (pnode->isUsed || fReturnValue || funcInfo->RegIsConst(pnode->sxBin.pnode1->location))
|
|
|
@@ -10181,7 +10211,7 @@ void Emit(ParseNode *pnode, ByteCodeGenerator *byteCodeGenerator, FuncInfo *func
|
|
|
}
|
|
|
funcInfo->ReleaseLoad(pnode->sxBin.pnode1);
|
|
|
|
|
|
- byteCodeGenerator->EndStatement(pnode);
|
|
|
+ ENDSTATEMENET_IFTOPLEVEL(isTopLevel, pnode);
|
|
|
break;
|
|
|
|
|
|
// General nodes.
|
|
|
@@ -10308,7 +10338,9 @@ void Emit(ParseNode *pnode, ByteCodeGenerator *byteCodeGenerator, FuncInfo *func
|
|
|
// Extends
|
|
|
if (pnode->sxClass.pnodeExtends)
|
|
|
{
|
|
|
+ byteCodeGenerator->StartStatement(pnode->sxClass.pnodeExtends);
|
|
|
Emit(pnode->sxClass.pnodeExtends, byteCodeGenerator, funcInfo, false);
|
|
|
+ byteCodeGenerator->EndStatement(pnode->sxClass.pnodeExtends);
|
|
|
}
|
|
|
|
|
|
Assert(pnode->sxClass.pnodeConstructor);
|
|
|
@@ -10370,7 +10402,9 @@ void Emit(ParseNode *pnode, ByteCodeGenerator *byteCodeGenerator, FuncInfo *func
|
|
|
break;
|
|
|
}
|
|
|
case knopStrTemplate:
|
|
|
+ STARTSTATEMENET_IFTOPLEVEL(isTopLevel, pnode);
|
|
|
EmitStringTemplate(pnode, byteCodeGenerator, funcInfo);
|
|
|
+ ENDSTATEMENET_IFTOPLEVEL(isTopLevel, pnode);
|
|
|
break;
|
|
|
case knopEndCode:
|
|
|
byteCodeGenerator->Writer()->RecordStatementAdjustment(Js::FunctionBody::SAT_All);
|