diff --git a/compiler/optimizer/optimizations/expand_intrinsics.cpp b/compiler/optimizer/optimizations/expand_intrinsics.cpp index e0d7f33dd77c3c878f51788deebaa7ec699035e1..4b85ebc334ce1bfbf89b1b2afdf7fbc4b3fd3f8b 100644 --- a/compiler/optimizer/optimizations/expand_intrinsics.cpp +++ b/compiler/optimizer/optimizations/expand_intrinsics.cpp @@ -60,6 +60,8 @@ bool ExpandIntrinsics::Expand(IntrinsicInst *inst) return ExpandTryLdGlobalByName(inst); case RuntimeInterface::IntrinsicId::INTRINSIC_LDLEXENV_DYN: return ExpandLdlexenvDyn(inst); + case RuntimeInterface::IntrinsicId::INTRINSIC_POP_LEXENV_DYN: + return ExpandPopLexenvDyn(inst); default: return false; } @@ -559,6 +561,27 @@ bool ExpandIntrinsics::ExpandStLexVarDyn(IntrinsicInst *intrinsic) return true; } +bool ExpandIntrinsics::ExpandPopLexenvDyn(IntrinsicInst *intrinsic) +{ + InstAppender appender(intrinsic->GetBasicBlock(), intrinsic); + + auto pc = intrinsic->GetPc(); + auto *env_ref = GetGraph()->CreateInstCastAnyTypeValue(pc, AnyBaseType::ECMASCRIPT_ARRAY_TYPE); + env_ref->SetInput(0U, intrinsic->GetInput(0).GetInst()); + env_ref->SetFlag(inst_flags::NO_HOIST); + appender.Append(env_ref); + + auto *load_parent = GetGraph()->CreateInstLoadArray(DataType::ANY, pc); + load_parent->SetInput(0U, env_ref); + load_parent->SetInput(1U, + GetGraph()->FindOrCreateConstant(GetGraph()->GetRuntime()->GetLexicalEnvParentEnvIndex())); + appender.Append(load_parent); + + intrinsic->ReplaceUsers(load_parent); + intrinsic->GetBasicBlock()->RemoveInst(intrinsic); + return true; +} + bool ExpandIntrinsics::ExpandTryLdGlobalByName(IntrinsicInst *inst) { if (GetGraph()->IsAotMode()) { diff --git a/compiler/optimizer/optimizations/expand_intrinsics.h b/compiler/optimizer/optimizations/expand_intrinsics.h index 0d7bb3df0f075fb81ec9e74a7c73f570f0e46e0f..9538d4d01644f4ab4ee100c45356b66e7d0c976d 100644 --- a/compiler/optimizer/optimizations/expand_intrinsics.h +++ b/compiler/optimizer/optimizations/expand_intrinsics.h @@ -79,6 +79,7 @@ private: bool ExpandLdLexVarDyn(IntrinsicInst *intrinsic); bool ExpandLdlexenvDyn(IntrinsicInst *intrinsic); bool ExpandStLexVarDyn(IntrinsicInst *intrinsic); + bool ExpandPopLexenvDyn(IntrinsicInst *intrinsic); bool ExpandTryLdGlobalByName(IntrinsicInst *inst); template diff --git a/tests/checked/CMakeLists.txt b/tests/checked/CMakeLists.txt index 57facf57a4f7bd7ce5f9b0063d144e0c71ca999e..b467738e3fd78bba870d8fa342d985ad9c9c2c7e 100644 --- a/tests/checked/CMakeLists.txt +++ b/tests/checked/CMakeLists.txt @@ -119,6 +119,7 @@ if (NOT PANDA_TARGET_ARM32) panda_add_checked_test_ecma(FILE ${CMAKE_CURRENT_SOURCE_DIR}/functionimmediate_check.js SUPPORT_RELEASE true) panda_add_checked_test_ecma(FILE ${CMAKE_CURRENT_SOURCE_DIR}/string_equals.js SUPPORT_RELEASE true) panda_add_checked_test_ecma(FILE ${CMAKE_CURRENT_SOURCE_DIR}/stlex.js SUPPORT_RELEASE true) + panda_add_checked_test_ecma(FILE ${CMAKE_CURRENT_SOURCE_DIR}/poplexenv.js SUPPORT_RELEASE true) # there is flaky bug when turning on TSAN if (NOT PANDA_ENABLE_THREAD_SANITIZER) panda_add_checked_test_ecma(FILE ${CMAKE_CURRENT_SOURCE_DIR}/acc_after_deopt.js SUPPORT_RELEASE true) diff --git a/tests/checked/poplexenv.js b/tests/checked/poplexenv.js new file mode 100644 index 0000000000000000000000000000000000000000..147b65dbb025439ed51ed91f1a778a90bd54cb20 --- /dev/null +++ b/tests/checked/poplexenv.js @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2021-2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +//! CHECKER Expand PopLexenvDyn intrinsic +//! RUN options: "--compiler-hotness-threshold=0 --no-async-jit=true --compiler-regex='_GLOBAL::level1'", entry: "_GLOBAL::func_main_0" +//! METHOD "level1" +//! PASS_AFTER "IrBuilder" +//! INST "Intrinsic.PopLexenvDyn" +//! INST_NEXT "Intrinsic.LdLexDyn" +//! PASS_AFTER "ExpandIntrinsics" +//! INST_NOT "Intrinsic.PopLexenvDyn" +//! INST "CastAnyTypeValue ECMASCRIPT_ARRAY_TYPE" +//! INST_NEXT "LoadArray" + +function test() { + let x = 1; + return function level1() { + // function definition inside loop is needed for PopLexenv to be created + for (let i = 0; i < 5; i++) { + function level2() { return i } + } + // LdLexDyn with PopLexenvDyn input + return x; + } +} + +if (test()() !== 1) { + throw "Loaded wrong value from environment returned by Poplexenv"; +} diff --git a/tests/compiler/expand_intrinsics_ecma_test.cpp b/tests/compiler/expand_intrinsics_ecma_test.cpp index c85ac7ecf50111537cf714a8f10d572033c3bef4..eea116f26f5a3323a597bc6a7c1835d1f3d4763e 100644 --- a/tests/compiler/expand_intrinsics_ecma_test.cpp +++ b/tests/compiler/expand_intrinsics_ecma_test.cpp @@ -425,5 +425,48 @@ TEST_F(ExpandIntrinsicsTest, StLexVarDyn) graph_opt->RunPass(); ASSERT_TRUE(GraphComparator().Compare(graph, graph_opt)); } + +TEST_F(ExpandIntrinsicsTest, PopLexenvDyn) +{ + auto graph = CreateGraphDynStubWithDefaultRuntime(); + GRAPH(graph) + { + PARAMETER(0, 0).any(); + BASIC_BLOCK(2, -1) + { + INST(1, Opcode::LoadLexicalEnv).any().Inputs(0); + INST(2, Opcode::SaveState).NoVregs(); + INST(3, Opcode::Intrinsic) + .IntrinsicId(RuntimeInterface::IntrinsicId::INTRINSIC_POP_LEXENV_DYN) + .any() + .Inputs({{DataType::ANY, 1}, {DataType::NO_TYPE, 2}}); + INST(4, Opcode::Return).any().Inputs(3); + } + } + + ASSERT_TRUE(graph->RunPass()); + GraphChecker(graph).Check(); + + auto graph_opt = CreateGraphDynStubWithDefaultRuntime(); + GRAPH(graph_opt) + { + PARAMETER(0, 0).any(); + CONSTANT(5, graph_opt->GetRuntime()->GetLexicalEnvParentEnvIndex()); + BASIC_BLOCK(2, -1) + { + INST(1, Opcode::LoadLexicalEnv).any().Inputs(0); + INST(2, Opcode::SaveState).NoVregs(); + INST(4, Opcode::CastAnyTypeValue) + .ref() + .Inputs(1) + .AnyType(AnyBaseType::ECMASCRIPT_ARRAY_TYPE) + .SetFlag(inst_flags::NO_HOIST); + INST(6, Opcode::LoadArray).any().Inputs(4, 5); + INST(3, Opcode::Return).any().Inputs(6); + } + } + + ASSERT_TRUE(GraphComparator().Compare(graph, graph_opt)); +} // NOLINTEND(readability-magic-numbers) } // namespace panda::compiler