From f022e1cab7ed96755e2fd43dbda4b27203e56691 Mon Sep 17 00:00:00 2001 From: Ishin Pavel Date: Mon, 29 May 2023 19:01:50 +0300 Subject: [PATCH] Support intrinsics getunmappedargs in compiler Signed-off-by: Ishin Pavel --- compiler/codegen_intrinsics_ecmascript.cpp | 10 ++++ .../ecmascript_compiler_interface.h | 5 ++ compiler/intrinsics_graph_checker.h | 28 ++++++++++ .../ir_builder/ecmascript_inst_builder.cpp | 56 +++++++++++++++++++ .../ir_builder/ecmascript_inst_builder.h | 1 + .../ir_builder/ecmascript_inst_templates.yaml | 6 ++ ecmascript_plugin_options.yaml | 1 + isa/isa.yaml | 2 +- .../compiler/ecmascript_runtime_interface.h | 6 ++ runtime/ecma_runtime.yaml | 4 +- runtime/intrinsics-inl.h | 7 ++- tests/checked/CMakeLists.txt | 1 + tests/checked/getunmappedargs_test.js | 28 ++++++++++ 13 files changed, 151 insertions(+), 4 deletions(-) create mode 100644 compiler/intrinsics_graph_checker.h create mode 100644 tests/checked/getunmappedargs_test.js diff --git a/compiler/codegen_intrinsics_ecmascript.cpp b/compiler/codegen_intrinsics_ecmascript.cpp index 07a138f68..5b7178997 100644 --- a/compiler/codegen_intrinsics_ecmascript.cpp +++ b/compiler/codegen_intrinsics_ecmascript.cpp @@ -74,6 +74,16 @@ static void EncodeLoadParentLexEnv(Codegen *cg, IntrinsicInst *inst, uint32_t le } } +void Codegen::EncodeGetUnmappedArgs(IntrinsicInst *inst, [[maybe_unused]] Reg dst, [[maybe_unused]] SRCREGS src) +{ + auto *enc = GetEncoder(); + auto slot = GetRuntime()->GetNumMandatoryArgs(); + auto offset = GetStackOffset(Location(LocationType::STACK_PARAMETER, slot)); + Reg param_1 = GetTarget().GetParamReg(1); + enc->EncodeAdd(param_1, SpReg(), Imm(offset)); + CreateCallIntrinsic(inst); +} + void Codegen::LdLexVarDyn(IntrinsicInst *inst, Reg dst, SRCREGS src) { ASSERT(inst->HasImms() == (inst->GetInputsCount() == 1U)); diff --git a/compiler/ecmascript_extensions/ecmascript_compiler_interface.h b/compiler/ecmascript_extensions/ecmascript_compiler_interface.h index fa353f77b..a72ab4192 100644 --- a/compiler/ecmascript_extensions/ecmascript_compiler_interface.h +++ b/compiler/ecmascript_extensions/ecmascript_compiler_interface.h @@ -82,6 +82,11 @@ virtual size_t GetTaggedArrayElementSize() const return 0; } +virtual size_t GetNumMandatoryArgs() const +{ + return 3U; +} + struct GlobalVarInfo { enum class Type { DEFAULT = 0, // do not inline intrinsic diff --git a/compiler/intrinsics_graph_checker.h b/compiler/intrinsics_graph_checker.h new file mode 100644 index 000000000..f35a3afe2 --- /dev/null +++ b/compiler/intrinsics_graph_checker.h @@ -0,0 +1,28 @@ + /* + * Copyright (c) 2021 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. + */ + +case RuntimeInterface::IntrinsicId::INTRINSIC_GET_UNMAPPED_ARGS: { + auto ss = inst->GetSaveState(); + auto graph = inst->GetBasicBlock()->GetGraph(); + if (graph->IsBytecodeOptimizer()) { + return; + } + ASSERT(ss != nullptr); + if (ss->GetCallerInst() != nullptr) { + return; + } + ASSERT(!HasSaveStateBetween(graph->GetStartBlock()->GetFirstInst(), ss)); + return; +} \ No newline at end of file diff --git a/compiler/optimizer/ir_builder/ecmascript_inst_builder.cpp b/compiler/optimizer/ir_builder/ecmascript_inst_builder.cpp index e6e7b9177..ded19ba1d 100644 --- a/compiler/optimizer/ir_builder/ecmascript_inst_builder.cpp +++ b/compiler/optimizer/ir_builder/ecmascript_inst_builder.cpp @@ -154,6 +154,62 @@ void InstBuilder::BuildEcmaNewobjdynrange(const BytecodeInstruction *bc_inst) UpdateDefinitionAcc(inst); } +void InstBuilder::BuildEcmaGetunmappedargs(const BytecodeInstruction *bc_inst) +{ + // TODO(pishin) support for inlined graph + if (caller_inst_ != nullptr) { + failed_ = true; + return; + } + auto graph = GetGraph(); + // If more parameters are passed to the function than in its description, + // then the GC can move the "implicit" parameters. + // So we remove SafePoint from the start block and check SaveState instruction between + for (auto sp : graph->GetStartBlock()->AllInsts()) { + if (sp->GetOpcode() != Opcode::SafePoint) { + continue; + } + sp->ClearFlag(inst_flags::NO_DCE); + } + auto bb = GetCurrentBlock(); + // Conservative check that there is no GC call from beggining to the instruction + if (bb->GetPredsBlocks().size() != 1 || bb->GetPredecessor(0) != graph->GetStartBlock()) { + failed_ = true; + return; + } + auto curr_inst = bb->GetLastInst(); + while (curr_inst != nullptr) { + if (curr_inst->IsSaveState()) { + failed_ = true; + return; + } + curr_inst = curr_inst->GetPrev(); + } + auto bc_pc = GetPc(bc_inst->GetAddress()); + auto inst = graph->CreateInstIntrinsic(DataType::ANY, bc_pc); + inst->SetIntrinsicId(RuntimeInterface::IntrinsicId::INTRINSIC_GET_UNMAPPED_ARGS); + AdjustFlags(inst->GetIntrinsicId(), inst); + inst->SetFlag(inst_flags::CAN_THROW); + + auto save_state = CreateSaveState(Opcode::SaveState, bc_pc); + AddInstruction(save_state); + + // first input is actual num args, second save state + uint32_t constexpr FIXED_INPUTS = 2U; + inst->ReserveInputs(FIXED_INPUTS); + inst->AllocateInputTypes(graph->GetAllocator(), FIXED_INPUTS); + auto num_args_inst = graph->FindParameter(ParameterInst::DYNAMIC_NUM_ARGS); + ASSERT(num_args_inst != nullptr); + inst->AppendInput(num_args_inst); + inst->AddInputType(DataType::UINT32); + + inst->AppendInput(save_state); + inst->AddInputType(DataType::NO_TYPE); + inst->SetFlag(inst_flags::ACC_WRITE); + AddInstruction(inst); + UpdateDefinitionAcc(inst); +} + } // namespace panda::compiler #include "ecmascript_inst_builder_gen.cpp" diff --git a/compiler/optimizer/ir_builder/ecmascript_inst_builder.h b/compiler/optimizer/ir_builder/ecmascript_inst_builder.h index 587d8091e..3c92b6728 100644 --- a/compiler/optimizer/ir_builder/ecmascript_inst_builder.h +++ b/compiler/optimizer/ir_builder/ecmascript_inst_builder.h @@ -33,5 +33,6 @@ void BuildEcmaFnCall(const BytecodeInstruction *bc_inst, bool is_range, bool cal void FinalizeEcmaFnCall(SaveStateInst *save_state, CallInst *call_inst); void BuildEcmaNewobjdynrange(const BytecodeInstruction *bc_inst); +void BuildEcmaGetunmappedargs(const BytecodeInstruction *bc_inst); #endif // PLUGINS_ECMASCRIPT_COMPILER_OPTIMIZER_IR_BUILDER_ECMASCRIPT_INST_BUILDER_H diff --git a/compiler/optimizer/ir_builder/ecmascript_inst_templates.yaml b/compiler/optimizer/ir_builder/ecmascript_inst_templates.yaml index cb59a4eb5..46c3dba2e 100644 --- a/compiler/optimizer/ir_builder/ecmascript_inst_templates.yaml +++ b/compiler/optimizer/ir_builder/ecmascript_inst_templates.yaml @@ -122,6 +122,12 @@ } else { BuildEcmaNewobjdynrange(instruction); } + % when "GETUNMAPPEDARGS" + if (graph_->IsBytecodeOptimizer()) { + BuildEcma(instruction); + } else { + BuildEcmaGetunmappedargs(instruction); + } % else BuildEcma(instruction); % end diff --git a/ecmascript_plugin_options.yaml b/ecmascript_plugin_options.yaml index 63d3aac11..72cdf9c8a 100644 --- a/ecmascript_plugin_options.yaml +++ b/ecmascript_plugin_options.yaml @@ -73,6 +73,7 @@ Intrinsics: intrinsic_inline_inl: plugins/ecmascript/compiler/intrinsics_inline_ecmascript.inl intrinsic_type_resolving_inl_h: plugins/ecmascript/compiler/intrinsics_type_resolving_ecmascript.inl.h + intrinsics_graph_checker_inl: plugins/ecmascript/compiler/intrinsics_graph_checker.h Metadatas: - RecordMetadata: new_class_name: panda::pandasm::extensions::ecmascript::RecordMetadata diff --git a/isa/isa.yaml b/isa/isa.yaml index d382e2c0f..96605b85f 100644 --- a/isa/isa.yaml +++ b/isa/isa.yaml @@ -185,7 +185,7 @@ groups: acc: out:top prefix: ecma format: [pref_op_none] - properties: [not_compilable] + properties: [] intrinsic_name: INTRINSIC_GET_UNMAPPED_ARGS - sig: ecma.getpropiterator diff --git a/runtime/compiler/ecmascript_runtime_interface.h b/runtime/compiler/ecmascript_runtime_interface.h index f48cc8fd0..d6fefb599 100644 --- a/runtime/compiler/ecmascript_runtime_interface.h +++ b/runtime/compiler/ecmascript_runtime_interface.h @@ -20,6 +20,7 @@ #include "plugins/ecmascript/runtime/js_object.h" #include "plugins/ecmascript/runtime/js_tagged_value.h" #include "plugins/ecmascript/runtime/js_thread.h" +#include "plugins/ecmascript/runtime/ecma_call_params.h" #include "plugins/ecmascript/runtime/ecma_profiling.h" #include "runtime/mem/refstorage/reference.h" @@ -183,6 +184,11 @@ public: return HClass::GetCallableMask(); } + size_t GetNumMandatoryArgs() const override + { + return js_method_args::NUM_MANDATORY_ARGS; + } + private: JSFunction *GetJSFunctionByMethod(PandaRuntimeInterface::MethodPtr m) const; diff --git a/runtime/ecma_runtime.yaml b/runtime/ecma_runtime.yaml index 9b3b1ae45..026452f41 100644 --- a/runtime/ecma_runtime.yaml +++ b/runtime/ecma_runtime.yaml @@ -870,7 +870,9 @@ intrinsics: exception: true signature: ret: any - args: [] + args: [u32] + stackrange: true + codegen_func: EncodeGetUnmappedArgs impl: panda::ecmascript::intrinsics::GetUnmappedArgs - name: GetUnmappedArgsInterp diff --git a/runtime/intrinsics-inl.h b/runtime/intrinsics-inl.h index 5a24b73d0..8ba8a1a83 100644 --- a/runtime/intrinsics-inl.h +++ b/runtime/intrinsics-inl.h @@ -617,9 +617,12 @@ INLINE_ECMA_INTRINSICS uint64_t LdlexenvDyn([[maybe_unused]] JSThread *thread) } // NOLINTNEXTLINE(misc-definitions-in-headers) -INLINE_ECMA_INTRINSICS uint64_t GetUnmappedArgs([[maybe_unused]] JSThread *thread) +INLINE_ECMA_INTRINSICS uint64_t GetUnmappedArgs([[maybe_unused]] JSThread *thread, uint32_t num_args, void *args) { - UNREACHABLE(); + ASSERT(thread->IsCurrentFrameCompiled()); + uint32_t actual_num_args = num_args - js_method_args::NUM_MANDATORY_ARGS; + return SlowRuntimeStub::GetUnmappedArgs(thread, actual_num_args, reinterpret_cast(args)) + .GetRawData(); } // NOLINTNEXTLINE(misc-definitions-in-headers) diff --git a/tests/checked/CMakeLists.txt b/tests/checked/CMakeLists.txt index 57facf57a..10db0c26a 100644 --- a/tests/checked/CMakeLists.txt +++ b/tests/checked/CMakeLists.txt @@ -93,6 +93,7 @@ if (NOT PANDA_TARGET_ARM32) # Disable checked tests with sanitizers for arm64, since it takes too long time running. if (PANDA_TARGET_AMD64 OR NOT PANDA_ARM64_TESTS_WITH_SANITIZER) panda_add_checked_test_ecma(FILE ${CMAKE_CURRENT_SOURCE_DIR}/type_resolving.js SUPPORT_RELEASE true) + panda_add_checked_test_ecma(FILE ${CMAKE_CURRENT_SOURCE_DIR}/getunmappedargs_test.js SUPPORT_RELEASE true) panda_add_checked_test_ecma(FILE ${CMAKE_CURRENT_SOURCE_DIR}/global_var.js SUPPORT_RELEASE true) panda_add_checked_test_ecma(FILE ${CMAKE_CURRENT_SOURCE_DIR}/try_load_global_by_name.js SUPPORT_RELEASE true) panda_add_checked_test_ecma(FILE ${CMAKE_CURRENT_SOURCE_DIR}/ecma_profiling.js SUPPORT_RELEASE true) diff --git a/tests/checked/getunmappedargs_test.js b/tests/checked/getunmappedargs_test.js new file mode 100644 index 000000000..474386e40 --- /dev/null +++ b/tests/checked/getunmappedargs_test.js @@ -0,0 +1,28 @@ +/* + * 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 Chech GetUnmappedArgs intrinsic +//! RUN force_jit: true, options: " --compiler-regex _GLOBAL::foo", entry: "_GLOBAL::func_main_0" +//! METHOD "foo" +//! PASS_AFTER "IrBuilder" +//! INST /Intrinsic.GetUnmappedArgs.*/ + +function foo() { + return arguments[2]; +} + +if (foo(1, 2, 3, 4, 5) != 3) { + throw "wrong value"; +} \ No newline at end of file -- Gitee