From c65a94371a210e207e6e4cfa5aaa8537fdf20e42 Mon Sep 17 00:00:00 2001 From: xingshunxiang Date: Sat, 30 Aug 2025 10:32:21 +0800 Subject: [PATCH] Add Devitual flag to bytecode Issue: https://gitee.com/openharmony/arkcompiler_ets_frontend/issues/ICVJC2?from=project-issue Description: when call the instance method of a final class, an the instance method has the same name with the static method, bytecode optimizer crash in debug mode. Reason: CallVirtualShort was devirtualed to CallShort, for CallShort, now we will only find the related method in the staticMap to call; So we need add an flag to inform that if a Call is devirtualed, we should find the related mthod in the instance-method map. Tests: ninja tests passed tests/tests-u-runner/runner.sh --ets-cts --show-progress --build-dir x64.release --processes=all passed tests/tests-u-runner/runner.sh --ets-func-tests --show-progress --build-dir x64.release --processes=all passed tests/tests-u-runner/runner.sh --astchecker --no-js --show-progress --build-dir x64.release --processes=all passed tests/tests-u-runner/runner.sh --ets-runtime --show-progress --build-dir x64.release --processes=all passed tests/tests-u-runner/runner.sh --parser --no-js --show-progress --build-dir x64.release --processes=all passed Signed-off-by: xingshunxiang --- ets2panda/compiler/core/ETSGen.h | 57 ++++++++++++++++++- ets2panda/compiler/core/regAllocator.h | 16 ++++++ ets2panda/compiler/templates/isa.h.erb | 3 + ets2panda/ir/irnode.h | 10 ++++ .../ets/StaticAndInstanceMethodCall.ets | 30 ++++++++++ 5 files changed, 113 insertions(+), 3 deletions(-) create mode 100644 ets2panda/test/runtime/ets/StaticAndInstanceMethodCall.ets diff --git a/ets2panda/compiler/core/ETSGen.h b/ets2panda/compiler/core/ETSGen.h index 44062c41cc..27d3939b1e 100644 --- a/ets2panda/compiler/core/ETSGen.h +++ b/ets2panda/compiler/core/ETSGen.h @@ -387,11 +387,22 @@ public: Ra().Emit(node, AssemblerSignatureReference(name), arg0, dummyReg_); } + void CallExactDevirtual(const ir::AstNode *const node, const util::StringView name, const VReg arg0) + { + Ra().EmitDevirtual(node, name, arg0, dummyReg_); + } + void CallExact(const ir::AstNode *const node, const util::StringView name, const VReg arg0, const VReg arg1) { Ra().Emit(node, AssemblerSignatureReference(name), arg0, arg1); } + void CallExactDevirtual(const ir::AstNode *const node, const util::StringView name, const VReg arg0, + const VReg arg1) + { + Ra().EmitDevirtual(node, name, arg0, arg1); + } + void CallExact(const ir::AstNode *const node, const util::StringView name, const VReg arg0, const VReg arg1, const VReg arg2) { @@ -415,7 +426,7 @@ public: ES2PANDA_ASSERT(!signature->HasSignatureFlag(checker::SignatureFlags::STATIC)); ES2PANDA_ASSERT(!signature->Owner()->GetDeclNode()->IsFinal() || signature->IsFinal()); if (IsDevirtualizedSignature(signature)) { - CallArgStart(node, signature, athis, arguments); + CallArgStartDevirtual(node, signature, athis, arguments); } else { CallArgStart(node, signature, athis, arguments); } @@ -424,7 +435,7 @@ public: void CallVirtual(const ir::AstNode *const node, const checker::Signature *signature, const VReg athis) { if (IsDevirtualizedSignature(signature)) { - CallExact(node, signature->InternalName(), athis); + CallExactDevirtual(node, signature->InternalName(), athis); } else { CallVirtual(node, signature->InternalName(), athis); } @@ -434,7 +445,7 @@ public: const VReg arg0) { if (IsDevirtualizedSignature(signature)) { - CallExact(node, signature->InternalName(), athis, arg0); + CallExactDevirtual(node, signature->InternalName(), athis, arg0); } else { CallVirtual(node, signature->InternalName(), athis, arg0); } @@ -683,6 +694,46 @@ private: } } + template + void CallArgStartDevirtual(const ir::AstNode *const node, const checker::Signature *signature, const VReg argStart, + const ArenaVector &arguments) + { + RegScope rs(this); + const auto name = signature->InternalName(); + switch (arguments.size()) { + case 0U: { + Ra().EmitDevirtual(node, name, argStart, dummyReg_); + break; + } + case 1U: { + COMPILE_ARG(0); + Ra().EmitDevirtual(node, name, argStart, arg0); + break; + } + case 2U: { + COMPILE_ARG(0); + COMPILE_ARG(1); + Ra().EmitDevirtual(node, name, argStart, arg0, arg1, dummyReg_); + break; + } + case 3U: { + COMPILE_ARG(0); + COMPILE_ARG(1); + COMPILE_ARG(2); + Ra().EmitDevirtual(node, name, argStart, arg0, arg1, arg2); + break; + } + default: { + for (size_t idx = 0; idx < arguments.size(); idx++) { + COMPILE_ARG(idx); + } + + Rra().EmitDevirtual(node, argStart, arguments.size() + 1, name, argStart); + break; + } + } + } + template void CallImpl(const ir::AstNode *node, checker::Signature const *signature, const ArenaVector &arguments) diff --git a/ets2panda/compiler/core/regAllocator.h b/ets2panda/compiler/core/regAllocator.h index 2f48a9a674..469d255810 100644 --- a/ets2panda/compiler/core/regAllocator.h +++ b/ets2panda/compiler/core/regAllocator.h @@ -108,6 +108,14 @@ public: Run(ins, VALID_VREGS); } + template ::max(), typename... Args> + void EmitDevirtual(const ir::AstNode *const node, Args &&...args) + { + auto *const ins = Alloc(node, std::forward(args)...); + Run(ins, VALID_VREGS); + ins->SetDevirtual(); + } + private: void Run(IRNode *ins, int32_t spillMax); }; @@ -126,6 +134,14 @@ public: Run(ins, rangeStart, argCount); } + template + void EmitDevirtual(const ir::AstNode *const node, const VReg rangeStart, const std::size_t argCount, Args &&...args) + { + auto *const ins = Alloc(node, std::forward(args)...); + Run(ins, rangeStart, argCount); + ins->SetDevirtual(); + } + private: void Run(IRNode *ins, VReg rangeStart, size_t argCount); }; diff --git a/ets2panda/compiler/templates/isa.h.erb b/ets2panda/compiler/templates/isa.h.erb index 87789468d6..07104538a9 100644 --- a/ets2panda/compiler/templates/isa.h.erb +++ b/ets2panda/compiler/templates/isa.h.erb @@ -183,6 +183,9 @@ public: void Transform(pandasm::Ins *ins, [[maybe_unused]] ProgramElement *programElement, [[maybe_unused]] uint32_t totalRegs) const override { ins->opcode = pandasm::Opcode::<%= node_kind %>; + if (IsDevirtual()) { + ins->SetIsDevirtual(); + } % for reg in op_map['reg'] ins->EmplaceReg(MapRegister(<%= reg %>.GetIndex(), totalRegs)); % end diff --git a/ets2panda/ir/irnode.h b/ets2panda/ir/irnode.h index 84f269da1f..dc8e81cd3f 100644 --- a/ets2panda/ir/irnode.h +++ b/ets2panda/ir/irnode.h @@ -151,9 +151,19 @@ public: virtual size_t OutRegisters([[maybe_unused]] std::array *regs) const = 0; virtual void Transform(ark::pandasm::Ins *ins, [[maybe_unused]] ProgramElement *programElement, [[maybe_unused]] uint32_t totalRegs) const = 0; + bool IsDevirtual() const + { + return isDevirtual_; + } + + void SetDevirtual() + { + isDevirtual_ = true; + } private: const ir::AstNode *node_; + bool isDevirtual_ = false; }; } // namespace ark::es2panda::compiler diff --git a/ets2panda/test/runtime/ets/StaticAndInstanceMethodCall.ets b/ets2panda/test/runtime/ets/StaticAndInstanceMethodCall.ets new file mode 100644 index 0000000000..96417dd595 --- /dev/null +++ b/ets2panda/test/runtime/ets/StaticAndInstanceMethodCall.ets @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2025 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. + */ + +let res: string = ""; +final class AA { + getString(arg: number) { res = "instance" } + static getString(arg: number) { res = "static"; } +} + +function foo() { + let a = new AA() + let radix: number = 16 + a.getString(radix) +} + +foo(); +arktest.assertTrue(res == "instance"); + -- Gitee