From a47a1323896ac6b5a2d6245204910dcb282a9117 Mon Sep 17 00:00:00 2001 From: xingshunxiang Date: Sat, 30 Aug 2025 10:25:56 +0800 Subject: [PATCH] Add Devitual flag to bytecode Issue: https://gitee.com/openharmony/arkcompiler_ets_frontend/issues/ICWPDS 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: anjiaqi --- static_core/assembler/assembly-emitter.cpp | 4 +++- static_core/assembler/assembly-emitter.h | 1 + static_core/assembler/assembly-ins.h | 11 +++++++++++ static_core/assembler/templates/ins_emit.h.erb | 2 +- static_core/bytecode_optimizer/codegen.cpp | 8 ++++++-- static_core/bytecode_optimizer/codegen.h | 2 +- static_core/bytecode_optimizer/ir_interface.h | 5 +++++ static_core/bytecode_optimizer/tests/common.h | 5 +++++ 8 files changed, 33 insertions(+), 5 deletions(-) diff --git a/static_core/assembler/assembly-emitter.cpp b/static_core/assembler/assembly-emitter.cpp index ae6d026c67..25f31136ee 100644 --- a/static_core/assembler/assembly-emitter.cpp +++ b/static_core/assembler/assembly-emitter.cpp @@ -841,7 +841,8 @@ static void AddBytecodeIndexDependencies(MethodItem *method, const Function &fun continue; } - if (insn.HasFlag(InstFlags::METHOD_ID)) { + bool isDevirtualCall = insn.IsDevirtual() && insn.HasFlag(InstFlags::STATIC_METHOD_ID); + if (insn.HasFlag(InstFlags::METHOD_ID) || isDevirtualCall) { AddBytecodeIndexDependencies(method, insn, entities.methodItems, entities); continue; } @@ -1628,6 +1629,7 @@ void AsmEmitter::FillMap(PandaFileToPandaAsmMaps *maps, AsmEmitter::AsmEntityCol for (const auto &[name, method] : entities.staticMethodItems) { maps->methods.insert({method->GetFileId().GetOffset(), std::string(name)}); + maps->staticMethods.insert(method->GetFileId().GetOffset()); } for (const auto &[name, field] : entities.fieldItems) { diff --git a/static_core/assembler/assembly-emitter.h b/static_core/assembler/assembly-emitter.h index 6fd030b3a3..c593327cde 100644 --- a/static_core/assembler/assembly-emitter.h +++ b/static_core/assembler/assembly-emitter.h @@ -39,6 +39,7 @@ public: std::unordered_map classes; std::unordered_map strings; std::unordered_map literalarrays; + std::unordered_set staticMethods; }; struct AsmEntityCollections { diff --git a/static_core/assembler/assembly-ins.h b/static_core/assembler/assembly-ins.h index c619582416..ca98780270 100644 --- a/static_core/assembler/assembly-ins.h +++ b/static_core/assembler/assembly-ins.h @@ -560,6 +560,16 @@ public: return insDebug.LineNumber() != 0U; } + bool IsDevirtual() const + { + return isDevirtual_; + } + + void SetIsDevirtual() + { + isDevirtual_ = true; + } + private: std::string OperandsToString(bool printArgs = false, size_t firstArgIdx = 0) const; std::string RegsToString(bool &first, bool printArgs = false, size_t firstArgIdx = 0) const; @@ -569,6 +579,7 @@ private: std::string IdToString(size_t idx, bool isFirst) const; std::string ImmToString(size_t idx, bool isFirst) const; std::string RegToString(size_t idx, bool isFirst, bool printArgs = false, size_t firstArgIdx = 0) const; + bool isDevirtual_ = false; }; // NOLINTEND(misc-non-private-member-variables-in-classes) diff --git a/static_core/assembler/templates/ins_emit.h.erb b/static_core/assembler/templates/ins_emit.h.erb index c80f200158..8bdfcc2ce9 100644 --- a/static_core/assembler/templates/ins_emit.h.erb +++ b/static_core/assembler/templates/ins_emit.h.erb @@ -137,7 +137,7 @@ bool Ins::Emit(BytecodeEmitter& emitter, panda_file::MethodItem *method, if (IDEmpty()) { return false; } - auto *foundMethod = GetMethodForHybridOpcode(GetID(0), staticMethods, methods); + auto *foundMethod = GetMethodForHybridOpcode(GetID(0), IsDevirtual() ? methods : staticMethods, methods); if (foundMethod == nullptr) { return false; } diff --git a/static_core/bytecode_optimizer/codegen.cpp b/static_core/bytecode_optimizer/codegen.cpp index 5cd4604fec..caf22b155c 100644 --- a/static_core/bytecode_optimizer/codegen.cpp +++ b/static_core/bytecode_optimizer/codegen.cpp @@ -493,7 +493,7 @@ static ark::compiler::CallInst *CastToCall(ark::compiler::Inst *inst) } } -void BytecodeGen::CallHandler(GraphVisitor *visitor, Inst *inst, std::string methodId) +void BytecodeGen::CallHandler(GraphVisitor *visitor, Inst *inst, std::string methodId, bool isDevirtual) { auto op = inst->GetOpcode(); ASSERT(op == compiler::Opcode::CallStatic || op == compiler::Opcode::CallVirtual || @@ -507,6 +507,9 @@ void BytecodeGen::CallHandler(GraphVisitor *visitor, Inst *inst, std::string met size_t start = op == compiler::Opcode::InitObject ? 1U : 0U; // exclude LoadAndInitClass auto nargs = sfCount - start; // exclude LoadAndInitClass pandasm::Ins ins {}; + if (isDevirtual) { + ins.SetIsDevirtual(); + } ins.opcode = ChooseCallOpcode(op, nargs); @@ -544,7 +547,8 @@ void BytecodeGen::CallHandler(GraphVisitor *visitor, Inst *inst) { auto *enc = static_cast(visitor); auto methodOffset = CastToCall(inst)->GetCallMethodId(); - CallHandler(visitor, inst, enc->irInterface_->GetMethodIdByOffset(methodOffset)); + bool isDevirtual = !enc->irInterface_->IsMethodStatic(methodOffset); + CallHandler(visitor, inst, enc->irInterface_->GetMethodIdByOffset(methodOffset), isDevirtual); } void BytecodeGen::VisitCallStatic(GraphVisitor *visitor, Inst *inst) diff --git a/static_core/bytecode_optimizer/codegen.h b/static_core/bytecode_optimizer/codegen.h index 5f7b32dd85..7c410e2096 100644 --- a/static_core/bytecode_optimizer/codegen.h +++ b/static_core/bytecode_optimizer/codegen.h @@ -125,7 +125,7 @@ public: static void IfImmNonZero(GraphVisitor *v, Inst *instBase); static void IfImm64(GraphVisitor *v, Inst *instBase); static void VisitIntrinsic(GraphVisitor *v, Inst *instBase); - static void CallHandler(GraphVisitor *visitor, Inst *inst, std::string methodId); + static void CallHandler(GraphVisitor *visitor, Inst *inst, std::string methodId, bool isDevirtual = false); static void CallHandler(GraphVisitor *visitor, Inst *inst); static void VisitStoreObject(GraphVisitor *v, Inst *instBase); static void VisitStoreStatic(GraphVisitor *v, Inst *instBase); diff --git a/static_core/bytecode_optimizer/ir_interface.h b/static_core/bytecode_optimizer/ir_interface.h index 428e0bc0ea..fa729b597a 100644 --- a/static_core/bytecode_optimizer/ir_interface.h +++ b/static_core/bytecode_optimizer/ir_interface.h @@ -33,6 +33,11 @@ public: NO_COPY_SEMANTIC(BytecodeOptIrInterface); NO_MOVE_SEMANTIC(BytecodeOptIrInterface); + virtual bool IsMethodStatic(uint32_t offset) const + { + return maps_->staticMethods.find(offset) != maps_->staticMethods.end(); + } + virtual std::string GetMethodIdByOffset(uint32_t offset) const { auto it = maps_->methods.find(offset); diff --git a/static_core/bytecode_optimizer/tests/common.h b/static_core/bytecode_optimizer/tests/common.h index fbe10b3088..980886aaca 100644 --- a/static_core/bytecode_optimizer/tests/common.h +++ b/static_core/bytecode_optimizer/tests/common.h @@ -103,6 +103,11 @@ public: { return ""; } + + bool IsMethodStatic(uint32_t offset) const override + { + return IsMapsSet() && BytecodeOptIrInterface::IsMethodStatic(offset); + } }; namespace test { -- Gitee