diff --git a/Build/NuGet/.pack-version b/Build/NuGet/.pack-version index 97ba4c9069f..3b7139e4beb 100644 --- a/Build/NuGet/.pack-version +++ b/Build/NuGet/.pack-version @@ -1 +1 @@ -1.11.15 +1.11.16 diff --git a/lib/Backend/JnHelperMethodList.h b/lib/Backend/JnHelperMethodList.h index 17a4adfc332..4c37b00cab8 100644 --- a/lib/Backend/JnHelperMethodList.h +++ b/lib/Backend/JnHelperMethodList.h @@ -254,6 +254,17 @@ HELPERCALLCHK(Op_PatchPutValueWithThisPtrNoLocalFastPathPolymorphic, ((void (*)( HELPERCALLCHK(Op_PatchPutRootValueNoLocalFastPath, ((void (*)(Js::FunctionBody *const, Js::InlineCache *const, const Js::InlineCacheIndex, Js::Var, Js::PropertyId, Js::Var, Js::PropertyOperationFlags))Js::JavascriptOperators::PatchPutRootValueNoLocalFastPath), AttrCanThrow) HELPERCALLCHK(Op_PatchPutRootValueNoLocalFastPathPolymorphic, ((void (*)(Js::FunctionBody *const, Js::PolymorphicInlineCache *const, const Js::InlineCacheIndex, Js::Var, Js::PropertyId, Js::Var, Js::PropertyOperationFlags))Js::JavascriptOperators::PatchPutRootValueNoLocalFastPath), AttrCanThrow) +HELPERCALLCHK(Op_PatchInitValueCheckLayout, ((bool (*)(Js::FunctionBody *const, Js::InlineCache *const, const Js::InlineCacheIndex, Js::RecyclableObject*, Js::PropertyId, Js::Var))Js::JavascriptOperators::PatchInitValueCheckLayout), AttrCanThrow) +HELPERCALLCHK(Op_PatchInitValuePolymorphicCheckLayout, ((bool (*)(Js::FunctionBody *const, Js::PolymorphicInlineCache *const, const Js::InlineCacheIndex, Js::RecyclableObject*, Js::PropertyId, Js::Var))Js::JavascriptOperators::PatchInitValueCheckLayout), AttrCanThrow) +HELPERCALLCHK(Op_PatchPutValueCheckLayout, ((bool (*)(Js::FunctionBody *const, Js::InlineCache *const, const Js::InlineCacheIndex, Js::Var, Js::PropertyId, Js::Var, Js::PropertyOperationFlags))Js::JavascriptOperators::PatchPutValueCheckLayout), AttrCanThrow) +HELPERCALLCHK(Op_PatchPutValueWithThisPtrCheckLayout, ((bool (*)(Js::FunctionBody *const, Js::InlineCache *const, const Js::InlineCacheIndex, Js::Var, Js::PropertyId, Js::Var, Js::Var, Js::PropertyOperationFlags))Js::JavascriptOperators::PatchPutValueWithThisPtrCheckLayout), AttrCanThrow) +HELPERCALLCHK(Op_PatchPutValuePolymorphicCheckLayout, ((bool (*)(Js::FunctionBody *const, Js::PolymorphicInlineCache *const, const Js::InlineCacheIndex, Js::Var, Js::PropertyId, Js::Var, Js::PropertyOperationFlags))Js::JavascriptOperators::PatchPutValueCheckLayout), AttrCanThrow) +HELPERCALLCHK(Op_PatchPutValueWithThisPtrPolymorphicCheckLayout, ((bool (*)(Js::FunctionBody *const, Js::PolymorphicInlineCache *const, const Js::InlineCacheIndex, Js::Var, Js::PropertyId, Js::Var, Js::Var, Js::PropertyOperationFlags))Js::JavascriptOperators::PatchPutValueWithThisPtrCheckLayout), AttrCanThrow) +HELPERCALLCHK(Op_PatchPutValueNoLocalFastPathCheckLayout, ((bool (*)(Js::FunctionBody *const, Js::InlineCache *const, const Js::InlineCacheIndex, Js::Var, Js::PropertyId, Js::Var, Js::PropertyOperationFlags))Js::JavascriptOperators::PatchPutValueNoLocalFastPathCheckLayout), AttrCanThrow) +HELPERCALLCHK(Op_PatchPutValueWithThisPtrNoLocalFastPathCheckLayout, ((bool (*)(Js::FunctionBody *const, Js::InlineCache *const, const Js::InlineCacheIndex, Js::Var, Js::PropertyId, Js::Var, Js::Var, Js::PropertyOperationFlags))Js::JavascriptOperators::PatchPutValueWithThisPtrNoLocalFastPathCheckLayout), AttrCanThrow) +HELPERCALLCHK(Op_PatchPutValueNoLocalFastPathPolymorphicCheckLayout, ((bool (*)(Js::FunctionBody *const, Js::PolymorphicInlineCache *const, const Js::InlineCacheIndex, Js::Var, Js::PropertyId, Js::Var, Js::PropertyOperationFlags))Js::JavascriptOperators::PatchPutValueNoLocalFastPathCheckLayout), AttrCanThrow) +HELPERCALLCHK(Op_PatchPutValueWithThisPtrNoLocalFastPathPolymorphicCheckLayout, ((bool (*)(Js::FunctionBody *const, Js::PolymorphicInlineCache *const, const Js::InlineCacheIndex, Js::Var, Js::PropertyId, Js::Var, Js::Var, Js::PropertyOperationFlags))Js::JavascriptOperators::PatchPutValueWithThisPtrNoLocalFastPathCheckLayout), AttrCanThrow) + HELPERCALLCHK(Op_PatchSetPropertyScoped, ((void (*)(Js::FunctionBody *const, Js::InlineCache *const, const Js::InlineCacheIndex, Js::FrameDisplay*, Js::PropertyId, Js::Var, Js::Var, Js::PropertyOperationFlags))Js::JavascriptOperators::PatchSetPropertyScoped), AttrCanThrow) HELPERCALLCHK(Op_ConsolePatchSetPropertyScoped, ((void(*)(Js::FunctionBody *const, Js::InlineCache *const, const Js::InlineCacheIndex, Js::FrameDisplay*, Js::PropertyId, Js::Var, Js::Var, Js::PropertyOperationFlags))Js::JavascriptOperators::PatchSetPropertyScoped), AttrCanThrow) diff --git a/lib/Backend/Lower.cpp b/lib/Backend/Lower.cpp index a4f2bb45071..12333b9cd0b 100644 --- a/lib/Backend/Lower.cpp +++ b/lib/Backend/Lower.cpp @@ -7107,6 +7107,57 @@ Lowerer::LowerStFld( IR::Opnd *dst = stFldInstr->UnlinkDst(); AssertMsg(dst->IsSymOpnd() && dst->AsSymOpnd()->m_sym->IsPropertySym(), "Expected property sym as dst of field store"); + BailOutInfo * bailOutInfo = nullptr; + bool doCheckLayout = false; + IR::PropertySymOpnd * propertySymOpnd = nullptr; + if (dst->AsSymOpnd()->IsPropertySymOpnd()) + { + propertySymOpnd = dst->AsPropertySymOpnd(); + if (stFldInstr->HasBailOutInfo() && !propertySymOpnd->IsTypeCheckSeqCandidate() && propertySymOpnd->TypeCheckRequired()) + { + IR::Instr * instrBailTarget = stFldInstr->ShareBailOut(); + LowerBailTarget(instrBailTarget); + doCheckLayout = true; + bailOutInfo = stFldInstr->GetBailOutInfo(); + switch (helperMethod) + { + case IR::HelperOp_PatchPutValue: + helperMethod = IR::HelperOp_PatchPutValueCheckLayout; + break; + case IR::HelperOp_PatchPutValuePolymorphic: + helperMethod = IR::HelperOp_PatchPutValuePolymorphicCheckLayout; + break; + case IR::HelperOp_PatchPutValueNoLocalFastPath: + helperMethod = IR::HelperOp_PatchPutValueNoLocalFastPathCheckLayout; + break; + case IR::HelperOp_PatchPutValueNoLocalFastPathPolymorphic: + helperMethod = IR::HelperOp_PatchPutValueNoLocalFastPathPolymorphicCheckLayout; + break; + case IR::HelperOp_PatchPutValueWithThisPtr: + helperMethod = IR::HelperOp_PatchPutValueWithThisPtrCheckLayout; + break; + case IR::HelperOp_PatchPutValueWithThisPtrPolymorphic: + helperMethod = IR::HelperOp_PatchPutValueWithThisPtrPolymorphicCheckLayout; + break; + case IR::HelperOp_PatchPutValueWithThisPtrNoLocalFastPath: + helperMethod = IR::HelperOp_PatchPutValueWithThisPtrNoLocalFastPathCheckLayout; + break; + case IR::HelperOp_PatchPutValueWithThisPtrNoLocalFastPathPolymorphic: + helperMethod = IR::HelperOp_PatchPutValueWithThisPtrNoLocalFastPathPolymorphicCheckLayout; + break; + case IR::HelperOp_PatchInitValue: + helperMethod = IR::HelperOp_PatchInitValueCheckLayout; + break; + case IR::HelperOp_PatchInitValuePolymorphic: + helperMethod = IR::HelperOp_PatchInitValuePolymorphicCheckLayout; + break; + default: + AssertOrFailFast(false); + break; + } + } + } + IR::Opnd * inlineCacheOpnd = nullptr; if (withInlineCache) { @@ -7153,7 +7204,20 @@ Lowerer::LowerStFld( } IR::RegOpnd *opndBase = dst->AsSymOpnd()->CreatePropertyOwnerOpnd(m_func); - m_lowererMD.ChangeToHelperCall(stFldInstr, helperMethod, labelBailOut, opndBase, dst->AsSymOpnd()->IsPropertySymOpnd() ? dst->AsSymOpnd()->AsPropertySymOpnd() : nullptr, isHelper); + + IR::Instr * callInstr = + m_lowererMD.ChangeToHelperCall(stFldInstr, helperMethod, labelBailOut, opndBase, propertySymOpnd, isHelper); + + if (doCheckLayout) + { + callInstr->SetDst(IR::RegOpnd::New(TyUint8, bailOutInfo->bailOutFunc)); + IR::Instr * bailOutInstr = IR::BailOutInstr::New(Js::OpCode::BailOnNotEqual, IR::BailOutFailedTypeCheck, bailOutInfo, bailOutInfo->bailOutFunc); + bailOutInstr->SetSrc1(callInstr->GetDst()); + bailOutInstr->SetSrc2(IR::IntConstOpnd::New(0, TyUint8, bailOutInfo->bailOutFunc)); + callInstr->InsertAfter(bailOutInstr); + bailOutInfo->polymorphicCacheIndex = propertySymOpnd->m_inlineCacheIndex; + LowerBailOnEqualOrNotEqual(bailOutInstr, nullptr, nullptr, nullptr, isHelper); + } return instrPrev; } @@ -24950,9 +25014,9 @@ Lowerer::GenerateLdHomeObj(IR::Instr* instr) Func *func = instr->m_func; IR::LabelInstr *labelDone = IR::LabelInstr::New(Js::OpCode::Label, func, false); - IR::LabelInstr *labelInlineFunc = IR::LabelInstr::New(Js::OpCode::Label, func, false); IR::LabelInstr *testLabel = IR::LabelInstr::New(Js::OpCode::Label, func, false); IR::LabelInstr *scriptFuncLabel = IR::LabelInstr::New(Js::OpCode::Label, func, false); + LABELNAMESET(scriptFuncLabel, "ScriptFunctionWithHomeObj"); IR::Opnd *opndUndefAddress = this->LoadLibraryValueOpnd(instr, LibraryValue::ValueUndefined); IR::RegOpnd *instanceRegOpnd = IR::RegOpnd::New(TyMachPtr, func); @@ -24973,23 +25037,30 @@ Lowerer::GenerateLdHomeObj(IR::Instr* instr) if (func->GetJITFunctionBody()->HasHomeObj()) { - // Is this an function with inline cache and home obj?? - IR::Opnd * vtableAddressInlineFuncHomObjOpnd = this->LoadVTableValueOpnd(instr, VTableValue::VtableScriptFunctionWithInlineCacheAndHomeObj); - IR::BranchInstr* inlineFuncHomObjOpndBr = InsertCompareBranch(IR::IndirOpnd::New(instanceRegOpnd, 0, TyMachPtr, func), vtableAddressInlineFuncHomObjOpnd, Js::OpCode::BrNeq_A, labelInlineFunc, instr); - InsertObjectPoison(instanceRegOpnd, inlineFuncHomObjOpndBr, instr, false); - IR::IndirOpnd *indirInlineFuncHomeObjOpnd = IR::IndirOpnd::New(instanceRegOpnd, Js::FunctionWithHomeObj::GetOffsetOfHomeObj(), TyMachPtr, func); - Lowerer::InsertMove(instanceRegOpnd, indirInlineFuncHomeObjOpnd, instr); - InsertBranch(Js::OpCode::Br, testLabel, instr); + IR::RegOpnd* funcObjHasInlineCachesOpnd = IR::RegOpnd::New(TyUint8, instr->m_func); + this->InsertMove(funcObjHasInlineCachesOpnd, IR::IndirOpnd::New(instanceRegOpnd, Js::ScriptFunction::GetOffsetOfHasInlineCaches(), TyUint8, instr->m_func), instr); - instr->InsertBefore(labelInlineFunc); - - // Is this a function with inline cache, home obj and computed name?? - IR::Opnd * vtableAddressInlineFuncHomObjCompNameOpnd = this->LoadVTableValueOpnd(instr, VTableValue::VtableScriptFunctionWithInlineCacheHomeObjAndComputedName); - IR::BranchInstr* inlineFuncHomObjCompNameBr = InsertCompareBranch(IR::IndirOpnd::New(instanceRegOpnd, 0, TyMachPtr, func), vtableAddressInlineFuncHomObjCompNameOpnd, Js::OpCode::BrNeq_A, scriptFuncLabel, instr); + IR::BranchInstr* inlineFuncHomObjCompNameBr = InsertTestBranch(funcObjHasInlineCachesOpnd, funcObjHasInlineCachesOpnd, Js::OpCode::BrEq_A, scriptFuncLabel, instr); InsertObjectPoison(instanceRegOpnd, inlineFuncHomObjCompNameBr, instr, false); - IR::IndirOpnd *indirInlineFuncHomeObjCompNameOpnd = IR::IndirOpnd::New(instanceRegOpnd, Js::FunctionWithComputedName>::GetOffsetOfHomeObj(), TyMachPtr, func); - Lowerer::InsertMove(instanceRegOpnd, indirInlineFuncHomeObjCompNameOpnd, instr); - InsertBranch(Js::OpCode::Br, testLabel, instr); + + if (func->GetJITFunctionBody()->HasComputedName()) + { + // Is this a function with inline cache, home obj and computed name? + { + IR::IndirOpnd* indirInlineFuncHomeObjCompNameOpnd = IR::IndirOpnd::New(instanceRegOpnd, Js::FunctionWithComputedName>::GetOffsetOfHomeObj(), TyMachPtr, func); + Lowerer::InsertMove(instanceRegOpnd, indirInlineFuncHomeObjCompNameOpnd, instr); + InsertBranch(Js::OpCode::Br, testLabel, instr); + } + } + else + { + // Is this a function with inline cache and home obj? + { + IR::IndirOpnd* indirInlineFuncHomeObjOpnd = IR::IndirOpnd::New(instanceRegOpnd, Js::FunctionWithHomeObj::GetOffsetOfHomeObj(), TyMachPtr, func); + Lowerer::InsertMove(instanceRegOpnd, indirInlineFuncHomeObjOpnd, instr); + InsertBranch(Js::OpCode::Br, testLabel, instr); + } + } instr->InsertBefore(scriptFuncLabel); IR::IndirOpnd *indirOpnd = IR::IndirOpnd::New(instanceRegOpnd, Js::ScriptFunctionWithHomeObj::GetOffsetOfHomeObj(), TyMachPtr, func); diff --git a/lib/Common/ChakraCoreVersion.h b/lib/Common/ChakraCoreVersion.h index 3cb11ff51ad..8a3734ecc18 100644 --- a/lib/Common/ChakraCoreVersion.h +++ b/lib/Common/ChakraCoreVersion.h @@ -17,7 +17,7 @@ // ChakraCore version number definitions (used in ChakraCore binary metadata) #define CHAKRA_CORE_MAJOR_VERSION 1 #define CHAKRA_CORE_MINOR_VERSION 11 -#define CHAKRA_CORE_PATCH_VERSION 15 +#define CHAKRA_CORE_PATCH_VERSION 16 #define CHAKRA_CORE_VERSION_RELEASE_QFE 0 // Redundant with PATCH_VERSION. Keep this value set to 0. // ------------- diff --git a/lib/Parser/Parse.cpp b/lib/Parser/Parse.cpp index 8d045e2635a..209f40d061e 100644 --- a/lib/Parser/Parse.cpp +++ b/lib/Parser/Parse.cpp @@ -1738,6 +1738,20 @@ void Parser::BindPidRefsInScope(IdentPtr pid, Symbol *sym, int blockId, uint max } } + if (m_currentNodeFunc && m_currentNodeFunc->pnodeName && pid == m_currentNodeFunc->pnodeName->pid && !m_currentNodeFunc->IsDeclaration() && m_currentNodeFunc->IsBodyAndParamScopeMerged()) + { + Scope* funcExprScope = m_currentNodeFunc->scope; + Assert(funcExprScope->GetScopeType() == ScopeType_FuncExpr); + + ParseNodeBlock* bodyScope = m_currentNodeFunc->pnodeBodyScope; + Assert(bodyScope->blockType == PnodeBlockType::Function); + + if (ref->GetScopeId() < bodyScope->blockId && ref->GetScopeId() > blockId) + { + funcExprScope->SetIsObject(); + } + } + if (ref->GetScopeId() == blockId) { break; @@ -4938,6 +4952,12 @@ ParseNodeFnc * Parser::ParseFncDeclInternal(ushort flags, LPCOLESTR pNameHint, c pnodeFnc->SetIsBaseClassConstructor((flags & fFncBaseClassConstructor) != 0); pnodeFnc->SetHomeObjLocation(Js::Constants::NoRegister); + if (this->m_currentScope && this->m_currentScope->GetScopeType() == ScopeType_Parameter) + { + pnodeFnc->SetIsDeclaredInParamScope(); + this->m_currentScope->SetHasNestedParamFunc(); + } + IdentPtr pFncNamePid = nullptr; bool needScanRCurly = true; ParseFncDeclHelper(pnodeFnc, pNameHint, flags, fUnaryOrParen, noStmtContext, &needScanRCurly, fModule, &pFncNamePid, fAllowIn); @@ -8378,8 +8398,7 @@ ParseNodePtr Parser::ParseExpr(int oplMin, // binding operator, be it unary or binary. Error(ERRsyntax); } - if (m_currentScope->GetScopeType() == ScopeType_Parameter - || (m_currentScope->GetScopeType() == ScopeType_Block && m_currentScope->GetEnclosingScope()->GetScopeType() == ScopeType_Parameter)) // Check whether this is a class definition inside param scope + if(m_currentScope->AncestorScopeIsParameter()) // Yield is not allowed within any parameter scope { Error(ERRsyntax); } @@ -8387,8 +8406,7 @@ ParseNodePtr Parser::ParseExpr(int oplMin, else if (nop == knopAwait) { if (!this->GetScanner()->AwaitIsKeywordRegion() || - m_currentScope->GetScopeType() == ScopeType_Parameter || - (m_currentScope->GetScopeType() == ScopeType_Block && m_currentScope->GetEnclosingScope()->GetScopeType() == ScopeType_Parameter)) // Check whether this is a class definition inside param scope + m_currentScope->AncestorScopeIsParameter()) // Await is not allowed within any parameter scope { // As with the 'yield' keyword, the case where 'await' is scanned as a keyword (tkAWAIT) // but the scanner is not treating await as a keyword (!this->GetScanner()->AwaitIsKeyword()) diff --git a/lib/Parser/ptree.h b/lib/Parser/ptree.h index c27bb49079f..6aaf65eca94 100644 --- a/lib/Parser/ptree.h +++ b/lib/Parser/ptree.h @@ -445,7 +445,7 @@ enum FncFlags : uint kFunctionIsStaticMember = 1 << 24, kFunctionIsGenerator = 1 << 25, // Function is an ES6 generator function kFunctionAsmjsMode = 1 << 26, - // Free = 1 << 27, + kFunctionIsDeclaredInParamScope = 1 << 27, // Function is declared in parameter scope (ex: inside default argument) kFunctionIsAsync = 1 << 28, // function is async kFunctionHasDirectSuper = 1 << 29, // super() kFunctionIsDefaultModuleExport = 1 << 30, // function is the default export of a module @@ -583,6 +583,7 @@ class ParseNodeFnc : public ParseNode void SetHasHomeObj(bool set = true) { SetFlags(kFunctionHasHomeObj, set); } void SetUsesArguments(bool set = true) { SetFlags(kFunctionUsesArguments, set); } void SetIsDefaultModuleExport(bool set = true) { SetFlags(kFunctionIsDefaultModuleExport, set); } + void SetIsDeclaredInParamScope(bool set = true) { SetFlags(kFunctionIsDeclaredInParamScope, set); } void SetNestedFuncEscapes(bool set = true) { nestedFuncEscapes = set; } void SetCanBeDeferred(bool set = true) { canBeDeferred = set; } void ResetBodyAndParamScopeMerged() { isBodyAndParamScopeMerged = false; } @@ -623,6 +624,7 @@ class ParseNodeFnc : public ParseNode bool HasHomeObj() const { return HasFlags(kFunctionHasHomeObj); } bool UsesArguments() const { return HasFlags(kFunctionUsesArguments); } bool IsDefaultModuleExport() const { return HasFlags(kFunctionIsDefaultModuleExport); } + bool IsDeclaredInParamScope() const { return HasFlags(kFunctionIsDeclaredInParamScope); } bool NestedFuncEscapes() const { return nestedFuncEscapes; } bool CanBeDeferred() const { return canBeDeferred; } bool IsBodyAndParamScopeMerged() { return isBodyAndParamScopeMerged; } diff --git a/lib/Runtime/ByteCode/ByteCodeEmitter.cpp b/lib/Runtime/ByteCode/ByteCodeEmitter.cpp index 99ee86882af..639ea47817b 100644 --- a/lib/Runtime/ByteCode/ByteCodeEmitter.cpp +++ b/lib/Runtime/ByteCode/ByteCodeEmitter.cpp @@ -3411,8 +3411,6 @@ void ByteCodeGenerator::EmitScopeList(ParseNode *pnode, ParseNode *breakOnBodySc } this->StartEmitFunction(pnode->AsParseNodeFnc()); - PushFuncInfo(_u("StartEmitFunction"), funcInfo); - if (!funcInfo->IsBodyAndParamScopeMerged()) { this->EmitScopeList(pnode->AsParseNodeFnc()->pnodeBodyScope->pnodeScopes); @@ -3789,6 +3787,11 @@ void ByteCodeGenerator::StartEmitFunction(ParseNodeFnc *pnodeFnc) else if (pnodeFnc->IsBodyAndParamScopeMerged() || bodyScope->GetScopeSlotCount() != 0) { bodyScope->SetMustInstantiate(funcInfo->frameSlotsRegister != Js::Constants::NoRegister); + + if (pnodeFnc->IsBodyAndParamScopeMerged() && paramScope && paramScope->GetHasNestedParamFunc()) + { + paramScope->SetMustInstantiate(funcInfo->frameSlotsRegister != Js::Constants::NoRegister); + } } if (!pnodeFnc->IsBodyAndParamScopeMerged()) @@ -3816,6 +3819,8 @@ void ByteCodeGenerator::StartEmitFunction(ParseNodeFnc *pnodeFnc) } } + PushFuncInfo(_u("StartEmitFunction"), funcInfo); + if (!funcInfo->IsBodyAndParamScopeMerged()) { ParseNodeBlock * paramBlock = pnodeFnc->pnodeScopes; @@ -5931,39 +5936,43 @@ void EmitReference(ParseNode *pnode, ByteCodeGenerator *byteCodeGenerator, FuncI // These have to be emitted before the RHS, but they have to persist until // the end of the expression. // Emit the call target operands first. - switch (pnode->AsParseNodeCall()->pnodeTarget->nop) - { - case knopDot: - case knopIndex: - funcInfo->AcquireLoc(pnode->AsParseNodeCall()->pnodeTarget); - EmitReference(pnode->AsParseNodeCall()->pnodeTarget, byteCodeGenerator, funcInfo); - break; - - case knopName: + // The call target does not need to be emitted for a super call - EmitSuperCall will do this. + if (!pnode->AsParseNodeCall()->isSuperCall) { - Symbol *sym = pnode->AsParseNodeCall()->pnodeTarget->AsParseNodeName()->sym; - if (!sym || sym->GetLocation() == Js::Constants::NoRegister) + switch (pnode->AsParseNodeCall()->pnodeTarget->nop) { + case knopDot: + case knopIndex: funcInfo->AcquireLoc(pnode->AsParseNodeCall()->pnodeTarget); - } - if (sym && (sym->IsInSlot(byteCodeGenerator, funcInfo) || sym->GetScope()->GetFunc() != funcInfo)) + EmitReference(pnode->AsParseNodeCall()->pnodeTarget, byteCodeGenerator, funcInfo); + break; + + case knopName: { - // Can't get the value from the assigned register, so load it here. - EmitLoad(pnode->AsParseNodeCall()->pnodeTarget, byteCodeGenerator, funcInfo); + Symbol* sym = pnode->AsParseNodeCall()->pnodeTarget->AsParseNodeName()->sym; + if (!sym || sym->GetLocation() == Js::Constants::NoRegister) + { + funcInfo->AcquireLoc(pnode->AsParseNodeCall()->pnodeTarget); + } + if (sym && (sym->IsInSlot(byteCodeGenerator, funcInfo) || sym->GetScope()->GetFunc() != funcInfo)) + { + // Can't get the value from the assigned register, so load it here. + EmitLoad(pnode->AsParseNodeCall()->pnodeTarget, byteCodeGenerator, funcInfo); + } + else + { + // EmitLoad will check for needsDeclaration and emit the Use Before Declaration error + // bytecode op as necessary, but EmitReference does not check this (by design). So we + // must manually check here. + EmitUseBeforeDeclaration(pnode->AsParseNodeCall()->pnodeTarget->AsParseNodeName()->sym, byteCodeGenerator, funcInfo); + EmitReference(pnode->AsParseNodeCall()->pnodeTarget, byteCodeGenerator, funcInfo); + } + break; } - else - { - // EmitLoad will check for needsDeclaration and emit the Use Before Declaration error - // bytecode op as necessary, but EmitReference does not check this (by design). So we - // must manually check here. - EmitUseBeforeDeclaration(pnode->AsParseNodeCall()->pnodeTarget->AsParseNodeName()->sym, byteCodeGenerator, funcInfo); - EmitReference(pnode->AsParseNodeCall()->pnodeTarget, byteCodeGenerator, funcInfo); + default: + EmitLoad(pnode->AsParseNodeCall()->pnodeTarget, byteCodeGenerator, funcInfo); + break; } - break; - } - default: - EmitLoad(pnode->AsParseNodeCall()->pnodeTarget, byteCodeGenerator, funcInfo); - break; } // Now the arg list. We evaluate everything now and emit the ArgOut's later. @@ -5977,12 +5986,6 @@ void EmitReference(ParseNode *pnode, ByteCodeGenerator *byteCodeGenerator, FuncI } Emit(pnodeArg, byteCodeGenerator, funcInfo, false); } - - if (pnode->AsParseNodeCall()->isSuperCall) - { - Emit(pnode->AsParseNodeSuperCall()->pnodeThis, byteCodeGenerator, funcInfo, false); - Emit(pnode->AsParseNodeSuperCall()->pnodeNewTarget, byteCodeGenerator, funcInfo, false); - } break; default: @@ -6961,7 +6964,14 @@ void EmitLoad( case knopCall: { ParseNodeCall * pnodeCallLhs = lhs->AsParseNodeCall(); - if (pnodeCallLhs->pnodeTarget->nop == knopImport) + + if (pnodeCallLhs->isSuperCall) + { + funcInfo->AcquireLoc(pnodeCallLhs); + EmitReference(pnodeCallLhs, byteCodeGenerator, funcInfo); + byteCodeGenerator->EmitSuperCall(funcInfo, pnodeCallLhs->AsParseNodeSuperCall(), /*fReturnValue=*/ false); + } + else if (pnodeCallLhs->pnodeTarget->nop == knopImport) { ParseNodePtr args = pnodeCallLhs->pnodeArgs; Assert(CountArguments(args) == 2); // import() takes one argument diff --git a/lib/Runtime/ByteCode/ByteCodeGenerator.cpp b/lib/Runtime/ByteCode/ByteCodeGenerator.cpp index 8230046ea17..e2a0b15d1a2 100644 --- a/lib/Runtime/ByteCode/ByteCodeGenerator.cpp +++ b/lib/Runtime/ByteCode/ByteCodeGenerator.cpp @@ -1818,7 +1818,7 @@ FuncInfo *ByteCodeGenerator::FindEnclosingNonLambda() return nullptr; } -FuncInfo* GetParentFuncInfo(FuncInfo* child) +FuncInfo* ByteCodeGenerator::GetParentFuncInfo(FuncInfo* child) { for (Scope* scope = child->GetBodyScope(); scope; scope = scope->GetEnclosingScope()) { @@ -1831,6 +1831,19 @@ FuncInfo* GetParentFuncInfo(FuncInfo* child) return nullptr; } +FuncInfo* ByteCodeGenerator::GetEnclosingFuncInfo() +{ + FuncInfo* top = this->funcInfoStack->Pop(); + + Assert(!this->funcInfoStack->Empty()); + + FuncInfo* second = this->funcInfoStack->Top(); + + this->funcInfoStack->Push(top); + + return second; +} + bool ByteCodeGenerator::CanStackNestedFunc(FuncInfo * funcInfo, bool trace) { #if ENABLE_DEBUG_CONFIG_OPTIONS @@ -2605,7 +2618,7 @@ void AssignFuncSymRegister(ParseNodeFnc * pnodeFnc, ByteCodeGenerator * byteCode Assert(byteCodeGenerator->GetCurrentScope()->GetFunc() == sym->GetScope()->GetFunc()); if (byteCodeGenerator->GetCurrentScope()->GetFunc() != sym->GetScope()->GetFunc()) { - Assert(GetParentFuncInfo(byteCodeGenerator->GetCurrentScope()->GetFunc()) == sym->GetScope()->GetFunc()); + Assert(ByteCodeGenerator::GetParentFuncInfo(byteCodeGenerator->GetCurrentScope()->GetFunc()) == sym->GetScope()->GetFunc()); sym->GetScope()->SetMustInstantiate(true); byteCodeGenerator->ProcessCapturedSym(sym); sym->GetScope()->GetFunc()->SetHasLocalInClosure(true); diff --git a/lib/Runtime/ByteCode/ByteCodeGenerator.h b/lib/Runtime/ByteCode/ByteCodeGenerator.h index 6773d348622..0006d98b456 100644 --- a/lib/Runtime/ByteCode/ByteCodeGenerator.h +++ b/lib/Runtime/ByteCode/ByteCodeGenerator.h @@ -376,6 +376,8 @@ class ByteCodeGenerator void PopulateFormalsScope(uint beginOffset, FuncInfo *funcInfo, ParseNodeFnc *pnodeFnc); void InsertPropertyToDebuggerScope(FuncInfo* funcInfo, Js::DebuggerScope* debuggerScope, Symbol* sym); FuncInfo *FindEnclosingNonLambda(); + static FuncInfo* GetParentFuncInfo(FuncInfo* child); + FuncInfo* GetEnclosingFuncInfo(); bool CanStackNestedFunc(FuncInfo * funcInfo, bool trace = false); void CheckDeferParseHasMaybeEscapedNestedFunc(); diff --git a/lib/Runtime/ByteCode/FuncInfo.cpp b/lib/Runtime/ByteCode/FuncInfo.cpp index bddf0602548..111cb5837a5 100644 --- a/lib/Runtime/ByteCode/FuncInfo.cpp +++ b/lib/Runtime/ByteCode/FuncInfo.cpp @@ -341,16 +341,19 @@ void FuncInfo::ReleaseReference(ParseNode *pnode) } } // Now release the call target. - switch (pnode->AsParseNodeCall()->pnodeTarget->nop) + if (!pnode->AsParseNodeCall()->isSuperCall) { - case knopDot: - case knopIndex: - this->ReleaseReference(pnode->AsParseNodeCall()->pnodeTarget); - this->ReleaseLoc(pnode->AsParseNodeCall()->pnodeTarget); - break; - default: - this->ReleaseLoad(pnode->AsParseNodeCall()->pnodeTarget); + switch (pnode->AsParseNodeCall()->pnodeTarget->nop) + { + case knopDot: + case knopIndex: + this->ReleaseReference(pnode->AsParseNodeCall()->pnodeTarget); + this->ReleaseLoc(pnode->AsParseNodeCall()->pnodeTarget); + break; + default: + this->ReleaseLoad(pnode->AsParseNodeCall()->pnodeTarget); break; + } } break; default: diff --git a/lib/Runtime/ByteCode/Scope.h b/lib/Runtime/ByteCode/Scope.h index 5f9dc1ccb57..bcaca18f634 100644 --- a/lib/Runtime/ByteCode/Scope.h +++ b/lib/Runtime/ByteCode/Scope.h @@ -41,6 +41,7 @@ class Scope BYTE canMergeWithBodyScope : 1; BYTE hasLocalInClosure : 1; BYTE isBlockInLoop : 1; + BYTE hasNestedParamFunc : 1; public: #if DBG BYTE isRestored : 1; @@ -60,6 +61,7 @@ class Scope canMergeWithBodyScope(true), hasLocalInClosure(false), isBlockInLoop(false), + hasNestedParamFunc(false), location(Js::Constants::NoRegister), m_symList(nullptr), m_count(0), @@ -169,6 +171,15 @@ class Scope return enclosingScope; } + bool AncestorScopeIsParameter() const + { + // Check if the current scope is a parameter or a block which belongs to a parameter scope + // In such cases, certain asynchronous behavior is forbidden + const Scope *currentScope = this; + while(currentScope->GetScopeType() != ScopeType_Global && currentScope->GetScopeType() != ScopeType_FunctionBody && currentScope->GetScopeType() != ScopeType_Parameter) currentScope = currentScope->GetEnclosingScope(); + return (currentScope->GetScopeType() == ScopeType_Parameter); + } + void SetScopeInfo(Js::ScopeInfo * scopeInfo) { this->scopeInfo = scopeInfo; @@ -252,6 +263,9 @@ class Scope void SetIsBlockInLoop(bool is = true) { isBlockInLoop = is; } bool IsBlockInLoop() const { return isBlockInLoop; } + void SetHasNestedParamFunc(bool is = true) { hasNestedParamFunc = is; } + bool GetHasNestedParamFunc() const { return hasNestedParamFunc; } + bool HasInnerScopeIndex() const { return innerScopeIndex != (uint)-1; } uint GetInnerScopeIndex() const { return innerScopeIndex; } void SetInnerScopeIndex(uint index) { innerScopeIndex = index; } diff --git a/lib/Runtime/ByteCode/ScopeInfo.cpp b/lib/Runtime/ByteCode/ScopeInfo.cpp index 9f03d8dfbe8..eb64b4a411e 100644 --- a/lib/Runtime/ByteCode/ScopeInfo.cpp +++ b/lib/Runtime/ByteCode/ScopeInfo.cpp @@ -112,8 +112,17 @@ namespace Js ScopeInfo * ScopeInfo::SaveScopeInfo(ByteCodeGenerator* byteCodeGenerator, Scope * scope, ScriptContext * scriptContext) { // Advance past scopes that will be excluded from the closure environment. (But note that we always want the body scope.) - while (scope && (!scope->GetMustInstantiate() && scope != scope->GetFunc()->GetBodyScope())) + while (scope) { + FuncInfo* func = scope->GetFunc(); + + if (scope->GetMustInstantiate() || + func->GetBodyScope() == scope || + (func->GetParamScope() == scope && func->IsBodyAndParamScopeMerged() && scope->GetHasNestedParamFunc())) + { + break; + } + scope = scope->GetEnclosingScope(); } @@ -162,6 +171,21 @@ namespace Js Scope* currentScope = byteCodeGenerator->GetCurrentScope(); Assert(currentScope->GetFunc() == funcInfo); + if (funcInfo->root->IsDeclaredInParamScope()) + { + Assert(currentScope->GetScopeType() == ScopeType_FunctionBody); + Assert(currentScope->GetEnclosingScope()); + + FuncInfo* func = byteCodeGenerator->GetEnclosingFuncInfo(); + Assert(func); + + if (func->IsBodyAndParamScopeMerged()) + { + currentScope = func->GetParamScope(); + Assert(currentScope->GetScopeType() == ScopeType_Parameter); + } + } + while (currentScope->GetFunc() == funcInfo) { currentScope = currentScope->GetEnclosingScope(); diff --git a/lib/Runtime/Language/JavascriptOperators.cpp b/lib/Runtime/Language/JavascriptOperators.cpp index a71aac5e156..ad4ddc749e4 100644 --- a/lib/Runtime/Language/JavascriptOperators.cpp +++ b/lib/Runtime/Language/JavascriptOperators.cpp @@ -8417,7 +8417,7 @@ using namespace Js; { JIT_HELPER_REENTRANT_HEADER(Op_PatchPutValue); JIT_HELPER_SAME_ATTRIBUTES(Op_PatchPutValue, Op_PatchPutValueWithThisPtr); - return PatchPutValueWithThisPtr(functionBody, inlineCache, inlineCacheIndex, instance, propertyId, newValue, instance, flags); + PatchPutValueWithThisPtr(functionBody, inlineCache, inlineCacheIndex, instance, propertyId, newValue, instance, flags); JIT_HELPER_END(Op_PatchPutValue); } JIT_HELPER_TEMPLATE(Op_PatchPutValue, Op_PatchPutValuePolymorphic) @@ -8688,6 +8688,94 @@ using namespace Js; } } + template + inline bool JavascriptOperators::PatchPutValueCheckLayout(FunctionBody *const functionBody, TInlineCache *const inlineCache, const InlineCacheIndex inlineCacheIndex, Var instance, PropertyId propertyId, Var newValue, PropertyOperationFlags flags) + { + JIT_HELPER_REENTRANT_HEADER(Op_PatchPutValueCheckLayout); + JIT_HELPER_SAME_ATTRIBUTES(Op_PatchPutValueCheckLayout, Op_PatchPutValue); + + DynamicTypeHandler * oldTypeHandler = DynamicObject::Is(instance) ? DynamicObject::FromVar(instance)->GetTypeHandler() : nullptr; + PatchPutValueWithThisPtr(functionBody, inlineCache, inlineCacheIndex, instance, propertyId, newValue, instance, flags); + return (oldTypeHandler != nullptr && LayoutChanged(DynamicObject::FromVar(instance), oldTypeHandler)); + + JIT_HELPER_END(Op_PatchPutValueCheckLayout); + } + JIT_HELPER_TEMPLATE(Op_PatchPutValueCheckLayout, Op_PatchPutValuePolymorphicCheckLayout); + template bool JavascriptOperators::PatchPutValueCheckLayout(FunctionBody *const functionBody, InlineCache *const inlineCache, const InlineCacheIndex inlineCacheIndex, Var instance, PropertyId propertyId, Var newValue, PropertyOperationFlags flags); + template bool JavascriptOperators::PatchPutValueCheckLayout(FunctionBody *const functionBody, PolymorphicInlineCache *const inlineCache, const InlineCacheIndex inlineCacheIndex, Var instance, PropertyId propertyId, Var newValue, PropertyOperationFlags flags); + + template + inline bool JavascriptOperators::PatchPutValueWithThisPtrCheckLayout(FunctionBody *const functionBody, TInlineCache *const inlineCache, const InlineCacheIndex inlineCacheIndex, Var instance, PropertyId propertyId, Var newValue, Var thisInstance, PropertyOperationFlags flags) + { + JIT_HELPER_REENTRANT_HEADER(Op_PatchPutValueWithThisPtrCheckLayout); + JIT_HELPER_SAME_ATTRIBUTES(Op_PatchPutValueWithThisPtrCheckLayout, Op_PatchPutValueWithThisPtr); + + DynamicTypeHandler * oldTypeHandler = DynamicObject::Is(instance) ? DynamicObject::FromVar(instance)->GetTypeHandler() : nullptr; + PatchPutValueWithThisPtr(functionBody, inlineCache, inlineCacheIndex, instance, propertyId, newValue, thisInstance, flags); + return (oldTypeHandler != nullptr && LayoutChanged(DynamicObject::FromVar(instance), oldTypeHandler)); + + JIT_HELPER_END(Op_PatchPutValueWithThisPtrCheckLayout); + } + JIT_HELPER_TEMPLATE(Op_PatchPutValueWithThisPtrCheckLayout, Op_PatchPutValueWithThisPtrPolymorphicCheckLayout); + template bool JavascriptOperators::PatchPutValueWithThisPtrCheckLayout(FunctionBody *const functionBody, InlineCache *const inlineCache, const InlineCacheIndex inlineCacheIndex, Var instance, PropertyId propertyId, Var newValue, Var thisInstance, PropertyOperationFlags flags); + template bool JavascriptOperators::PatchPutValueWithThisPtrCheckLayout(FunctionBody *const functionBody, PolymorphicInlineCache *const inlineCache, const InlineCacheIndex inlineCacheIndex, Var instance, PropertyId propertyId, Var newValue, Var thisInstance, PropertyOperationFlags flags); + + template + inline bool JavascriptOperators::PatchPutValueNoLocalFastPathCheckLayout(FunctionBody *const functionBody, TInlineCache *const inlineCache, const InlineCacheIndex inlineCacheIndex, Var instance, PropertyId propertyId, Var newValue, PropertyOperationFlags flags) + { + JIT_HELPER_REENTRANT_HEADER(Op_PatchPutValueNoLocalFastPathCheckLayout); + JIT_HELPER_SAME_ATTRIBUTES(Op_PatchPutValueNoLocalFastPathCheckLayout, Op_PatchPutValueNoLocalFastPath); + + DynamicTypeHandler * oldTypeHandler = DynamicObject::Is(instance) ? DynamicObject::FromVar(instance)->GetTypeHandler() : nullptr; + PatchPutValueWithThisPtrNoLocalFastPath(functionBody, inlineCache, inlineCacheIndex, instance, propertyId, newValue, instance, flags); + return (oldTypeHandler != nullptr && LayoutChanged(DynamicObject::FromVar(instance), oldTypeHandler)); + + JIT_HELPER_END(Op_PatchPutValueNoLocalFastPathCheckLayout); + } + JIT_HELPER_TEMPLATE(Op_PatchPutValueNoLocalFastPathCheckLayout, Op_PatchPutValueNoLocalFastPathPolymorphicCheckLayout); + template bool JavascriptOperators::PatchPutValueNoLocalFastPathCheckLayout(FunctionBody *const functionBody, InlineCache *const inlineCache, const InlineCacheIndex inlineCacheIndex, Var instance, PropertyId propertyId, Var newValue, PropertyOperationFlags flags); + template bool JavascriptOperators::PatchPutValueNoLocalFastPathCheckLayout(FunctionBody *const functionBody, PolymorphicInlineCache *const inlineCache, const InlineCacheIndex inlineCacheIndex, Var instance, PropertyId propertyId, Var newValue, PropertyOperationFlags flags); + + template + inline bool JavascriptOperators::PatchPutValueWithThisPtrNoLocalFastPathCheckLayout(FunctionBody *const functionBody, TInlineCache *const inlineCache, const InlineCacheIndex inlineCacheIndex, Var instance, PropertyId propertyId, Var newValue, Var thisInstance, PropertyOperationFlags flags) + { + JIT_HELPER_REENTRANT_HEADER(Op_PatchPutValueWithThisPtrNoLocalFastPathCheckLayout); + JIT_HELPER_SAME_ATTRIBUTES(Op_PatchPutValueWithThisPtrNoLocalFastPathCheckLayout, Op_PatchPutValueWithThisPtrNoLocalFastPath); + + DynamicTypeHandler * oldTypeHandler = DynamicObject::Is(instance) ? DynamicObject::FromVar(instance)->GetTypeHandler() : nullptr; + PatchPutValueWithThisPtrNoLocalFastPath(functionBody, inlineCache, inlineCacheIndex, instance, propertyId, newValue, thisInstance, flags); + return (oldTypeHandler != nullptr && LayoutChanged(DynamicObject::FromVar(instance), oldTypeHandler)); + + JIT_HELPER_END(Op_PatchPutValueWithThisPtrNoLocalFastPathCheckLayout); + } + JIT_HELPER_TEMPLATE(Op_PatchPutValueWithThisPtrNoLocalFastPathCheckLayout, Op_PatchPutValueWithThisPtrNoLocalFastPathPolymorphicCheckLayout); + template bool JavascriptOperators::PatchPutValueWithThisPtrNoLocalFastPathCheckLayout(FunctionBody *const functionBody, InlineCache *const inlineCache, const InlineCacheIndex inlineCacheIndex, Var instance, PropertyId propertyId, Var newValue, Var thisInstance, PropertyOperationFlags flags); + template bool JavascriptOperators::PatchPutValueWithThisPtrNoLocalFastPathCheckLayout(FunctionBody *const functionBody, PolymorphicInlineCache *const inlineCache, const InlineCacheIndex inlineCacheIndex, Var instance, PropertyId propertyId, Var newValue, Var thisInstance, PropertyOperationFlags flags); + + template + inline bool JavascriptOperators::PatchInitValueCheckLayout(FunctionBody *const functionBody, TInlineCache *const inlineCache, const InlineCacheIndex inlineCacheIndex, RecyclableObject* object, PropertyId propertyId, Var newValue) + { + JIT_HELPER_REENTRANT_HEADER(Op_PatchInitValueCheckLayout); + JIT_HELPER_SAME_ATTRIBUTES(Op_PatchInitValueCheckLayout, Op_PatchInitValue); + + DynamicTypeHandler * oldTypeHandler = DynamicObject::Is(object) ? DynamicObject::FromVar(object)->GetTypeHandler() : nullptr; + PatchInitValue(functionBody, inlineCache, inlineCacheIndex, object, propertyId, newValue); + return (oldTypeHandler != nullptr && LayoutChanged(DynamicObject::FromVar(object), oldTypeHandler)); + + JIT_HELPER_END(Op_PatchInitValueCheckLayout); + } + JIT_HELPER_TEMPLATE(Op_PatchInitValueCheckLayout, Op_PatchInitValuePolymorphicCheckLayout); + template bool JavascriptOperators::PatchInitValueCheckLayout(FunctionBody *const functionBody, InlineCache *const inlineCache, const InlineCacheIndex inlineCacheIndex, RecyclableObject* object, PropertyId propertyId, Var newValue); + template bool JavascriptOperators::PatchInitValueCheckLayout(FunctionBody *const functionBody, PolymorphicInlineCache *const inlineCache, const InlineCacheIndex inlineCacheIndex, RecyclableObject* object, PropertyId propertyId, Var newValue); + + bool JavascriptOperators::LayoutChanged(DynamicObject *const instance, DynamicTypeHandler *const oldTypeHandler) + { + DynamicTypeHandler * newTypeHandler = instance->GetTypeHandler(); + return (oldTypeHandler != newTypeHandler && + (oldTypeHandler->GetInlineSlotCapacity() != newTypeHandler->GetInlineSlotCapacity() || + oldTypeHandler->GetOffsetOfInlineSlots() != newTypeHandler->GetOffsetOfInlineSlots())); + } + template inline void JavascriptOperators::PatchInitValue(FunctionBody *const functionBody, TInlineCache *const inlineCache, const InlineCacheIndex inlineCacheIndex, RecyclableObject* object, PropertyId propertyId, Var newValue) { diff --git a/lib/Runtime/Language/JavascriptOperators.h b/lib/Runtime/Language/JavascriptOperators.h index d87193f59fc..41f388e6ea4 100644 --- a/lib/Runtime/Language/JavascriptOperators.h +++ b/lib/Runtime/Language/JavascriptOperators.h @@ -575,6 +575,13 @@ namespace Js template static void PatchInitValue(FunctionBody *const functionBody, TInlineCache *const inlineCache, const InlineCacheIndex inlineCacheIndex, RecyclableObject* object, PropertyId propertyId, Var newValue); static void PatchInitValueNoFastPath(FunctionBody *const functionBody, InlineCache *const inlineCache, const InlineCacheIndex inlineCacheIndex, RecyclableObject* object, PropertyId propertyId, Var newValue); + template static bool PatchPutValueCheckLayout(FunctionBody *const functionBody, TInlineCache *const inlineCache, const InlineCacheIndex inlineCacheIndex, Var obj, PropertyId propertyId, Var newValue, PropertyOperationFlags flags = PropertyOperation_None); + template static bool PatchPutValueWithThisPtrCheckLayout(FunctionBody *const functionBody, TInlineCache *const inlineCache, const InlineCacheIndex inlineCacheIndex, Var obj, PropertyId propertyId, Var newValue, Var thisInstance, PropertyOperationFlags flags = PropertyOperation_None); + template static bool PatchPutValueNoLocalFastPathCheckLayout(FunctionBody *const functionBody, TInlineCache *const inlineCache, const InlineCacheIndex inlineCacheIndex, Var instance, PropertyId propertyId, Var newValue, PropertyOperationFlags flags = PropertyOperation_None); + template static bool PatchPutValueWithThisPtrNoLocalFastPathCheckLayout(FunctionBody *const functionBody, TInlineCache *const inlineCache, const InlineCacheIndex inlineCacheIndex, Var instance, PropertyId propertyId, Var newValue, Var thisInstance, PropertyOperationFlags flags = PropertyOperation_None); + template static bool PatchInitValueCheckLayout(FunctionBody *const functionBody, TInlineCache *const inlineCache, const InlineCacheIndex inlineCacheIndex, RecyclableObject* object, PropertyId propertyId, Var newValue); + static bool LayoutChanged(DynamicObject * instance, DynamicTypeHandler * oldTypeHandler); + template static Var PatchGetMethod(FunctionBody *const functionBody, TInlineCache *const inlineCache, const InlineCacheIndex inlineCacheIndex, Var instance, PropertyId propertyId); template static Var PatchGetRootMethod(FunctionBody *const functionBody, TInlineCache *const inlineCache, const InlineCacheIndex inlineCacheIndex, DynamicObject* object, PropertyId propertyId); template static Var PatchScopedGetMethod(FunctionBody *const functionBody, TInlineCache *const inlineCache, const InlineCacheIndex inlineCacheIndex, Var instance, PropertyId propertyId); diff --git a/test/Bugs/bug_OS18926499.js b/test/Bugs/bug_OS18926499.js new file mode 100644 index 00000000000..ef90089e24d --- /dev/null +++ b/test/Bugs/bug_OS18926499.js @@ -0,0 +1,132 @@ +//------------------------------------------------------------------------------------------------------- +// Copyright (C) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. +//------------------------------------------------------------------------------------------------------- + +let throwingFunctions = [{ + msg: "Split-scope parent, param-scope child capturing symbol from parent body scope", + body: function foo(a = (()=>+x)()) { + function bar() { eval(''); } + var x; + } +}, +{ + msg: "Split-scope parent, param-scope child capturing symbol from parent body scope", + body: function foo(a = (()=>+x)()) { + eval(''); + var x; + } +}, +{ + msg: "Merged-scope parent, param-scope child capturing symbol from parent body scope", + body: function foo(a = () => +x) { + var x = 1; + return a(); + } +}, +{ + msg: "Merged-scope parent, param-scope child capturing symbol from parent body scope", + body: function foo(a = (()=>+x)()) { + var x; + } +}, +{ + msg: "Func expr parent, param-scope func expr child capturing symbol from parent body scope", + body: foo3 = function foo3a(a = (function foo3b() { return +x; })()) { + var x = 123; + } +}, +{ + msg: "Func expr parent, param-scope func expr child capturing symbol from parent body scope", + body: foo3 = function foo3a(a = (function foo3b() { return +x; })()) { + eval(''); + var x = 123; + } +}, +{ + msg: "Func expr parent, param-scope func expr child capturing symbol from parent body scope", + body: foo3 = function foo3a(a = (function foo3b() { return +x; })()) { + function bar() { eval(''); } + var x = 123; + } +}, +{ + msg: "Param-scope func expr child with nested func expr capturing symbol from parent body scope", + body: foo5 = function foo5a(a = (function(){(function(b = 123) { +x; })()})()) { + function bar() { eval(''); } + var x; + } +}, +{ + msg: "Multiple nested func expr, inner param-scope function capturing outer func expr name", + body: foo3 = function foo3a(a = (function foo3b(b = (function foo3c(c = (function foo3d() { +x; })()){})()){})()){ var x;} +}]; + +let nonThrowingFunctions = [{ + msg: "Func expr parent, param-scope func expr child capturing parent func expr name", + body: foo3 = function foo3a(a = (function foo3b() { +foo3a; })()) { + return +a; + } +}, +{ + msg: "Func expr parent, param-scope func expr child capturing own func expr name", + body: foo3 = function foo3a(a = (function foo3b() { +foo3b; })()) { + return +a; + } +}, +{ + msg: "Func expr parent, param-scope func expr child capturing expression name hint", + body: foo3 = function foo3a(a = (function foo3b() { +foo3; })()) { + return +a; + } +}, +{ + msg: "Func expr parent, param-scope func expr child capturing parent argument name", + body: foo3 = function foo3a(b = 123, a = (function foo3b() { return +b; })()) { + if (123 !== a) throw 123; + } +}, +{ + msg: "Func expr parent, param-scope func expr child capturing symbol from parent body scope", + body: foo3 = function foo3a(b = 123, a = (function foo3b() { return +b; })()) { + if (123 !== a) throw 123; + } +}, +{ + msg: "Multiple nested func expr, inner param-scope function capturing outer func expr name", + body: foo3 = function foo3a(a = (function foo3b(b = (function foo3c(c = (function foo3d() { foo3d; })()){})()){})()){} +}, +{ + msg: "Multiple nested func expr, inner param-scope function capturing outer func expr name", + body: foo3 = function foo3a(a = (function foo3b(b = (function foo3c(c = (function foo3d() { foo3c; })()){})()){})()){} +}, +{ + msg: "Multiple nested func expr, inner param-scope function capturing outer func expr name", + body: foo3 = function foo3a(a = (function foo3b(b = (function foo3c(c = (function foo3d() { foo3b; })()){})()){})()){} +}, +{ + msg: "Multiple nested func expr, inner param-scope function capturing outer func expr name", + body: foo3 = function foo3a(a = (function foo3b(b = (function foo3c(c = (function foo3d() { foo3a; })()){})()){})()){} +}, +{ + msg: "Multiple nested func expr, inner param-scope function capturing outer func expr name", + body: foo3 = function foo3a(a = (function foo3b(b = (function foo3c(c = (function foo3d() { foo3; })()){})()){})()){} +}]; + +for (let fn of throwingFunctions) { + try { + fn.body(); + console.log(`fail: ${fn.msg}`); + } catch (e) { + console.log("pass"); + } +} + +for (let fn of nonThrowingFunctions) { + try { + fn.body(); + console.log("pass"); + } catch (e) { + console.log(`fail: ${fn.msg}`); + } +} diff --git a/test/Bugs/bug_OS23102586.js b/test/Bugs/bug_OS23102586.js new file mode 100644 index 00000000000..6440127f6c1 --- /dev/null +++ b/test/Bugs/bug_OS23102586.js @@ -0,0 +1,20 @@ +//------------------------------------------------------------------------------------------------------- +// Copyright (C) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. +//------------------------------------------------------------------------------------------------------- + +// force:deferparse + +function test0() { + var k; + + function foo(a = function() { +k; }) { + a(); + function bar() { a } + }; + + eval('') + foo(); +} +test0(); +console.log('pass') diff --git a/test/Bugs/rlexe.xml b/test/Bugs/rlexe.xml index 60e5d2eb838..851f06bce79 100644 --- a/test/Bugs/rlexe.xml +++ b/test/Bugs/rlexe.xml @@ -536,4 +536,16 @@ -esdynamicimport -mutehosterrormsg -args summary -endargs + + + bug_OS18926499.js + -force:deferparse + + + + + bug_OS23102586.js + -force:deferparse + + diff --git a/test/es7/misc_bugs.js b/test/es7/misc_bugs.js index 9937154cf2e..a1f794c9e27 100644 --- a/test/es7/misc_bugs.js +++ b/test/es7/misc_bugs.js @@ -26,6 +26,20 @@ var tests = [ }`); }); } }, + { + name: "Await in class body should not crash", + body: function () { + async function trigger() { + a=class b{ + [a = class b{ + [await 0](){} + }](){} + }; + } + + trigger(); + } + }, ];