From aad911811f4b4e425fd4437ecd30b6cbfdd27ba1 Mon Sep 17 00:00:00 2001 From: yycc Date: Thu, 17 Jul 2025 15:19:10 +0800 Subject: [PATCH] Read Barrier Elimination Issue: https://gitee.com/openharmony/arkcompiler_ets_runtime/issues/ICANGI Description: Implement ReadBarrierEliminationPass to eliminate redundant GC State. Signed-off-by: yycc Change-Id: I88ec15b85a3ed4caf99c0a512b74baef86d8515d --- ecmascript/compiler/BUILD.gn | 1 + ecmascript/compiler/circuit_builder.h | 4 + ecmascript/compiler/gate_accessor.cpp | 1 + ecmascript/compiler/lcr_circuit_builder.cpp | 26 ++ ecmascript/compiler/lcr_opcodes.h | 1 + ecmascript/compiler/pass.h | 43 ++++ ecmascript/compiler/pass_manager.cpp | 6 + ecmascript/compiler/post_schedule.cpp | 95 +++++++ ecmascript/compiler/post_schedule.h | 6 + .../compiler/read_barrier_elimination.cpp | 242 ++++++++++++++++++ .../compiler/read_barrier_elimination.h | 64 +++++ ecmascript/compiler/stub_compiler.cpp | 13 +- ecmascript/js_runtime_options.cpp | 11 + ecmascript/js_runtime_options.h | 12 + 14 files changed, 522 insertions(+), 3 deletions(-) create mode 100644 ecmascript/compiler/read_barrier_elimination.cpp create mode 100644 ecmascript/compiler/read_barrier_elimination.h diff --git a/ecmascript/compiler/BUILD.gn b/ecmascript/compiler/BUILD.gn index f8fc059caa..2db30112eb 100644 --- a/ecmascript/compiler/BUILD.gn +++ b/ecmascript/compiler/BUILD.gn @@ -163,6 +163,7 @@ libark_jsoptimizer_sources = [ "profiler_stub_builder.cpp", "range_analysis.cpp", "range_guard.cpp", + "read_barrier_elimination.cpp", "rt_call_signature.cpp", "scheduler.cpp", "share_gate_meta_data.cpp", diff --git a/ecmascript/compiler/circuit_builder.h b/ecmascript/compiler/circuit_builder.h index 80b1e7ff8e..874b50a56c 100644 --- a/ecmascript/compiler/circuit_builder.h +++ b/ecmascript/compiler/circuit_builder.h @@ -985,6 +985,10 @@ public: GateRef LoadFromAddressWithoutBarrier(VariableType type, GateRef addr, MemoryAttribute mAttr = MemoryAttribute::Default()); + GateRef LoadBarrierCondition(GateRef glue); + GateRef LoadWithCondition(VariableType type, GateRef glue, GateRef addr, GateRef condition, + MemoryAttribute mAttr = MemoryAttribute::Default()); + void Store(VariableType type, GateRef glue, GateRef base, GateRef offset, GateRef value, MemoryAttribute mAttr = MemoryAttribute::Default()); GateRef FetchOr(GateRef ptr, GateRef value, MemoryAttribute mAttr); diff --git a/ecmascript/compiler/gate_accessor.cpp b/ecmascript/compiler/gate_accessor.cpp index 230cc03a32..06b9b632bd 100644 --- a/ecmascript/compiler/gate_accessor.cpp +++ b/ecmascript/compiler/gate_accessor.cpp @@ -141,6 +141,7 @@ MemoryAttribute GateAccessor::GetMemoryAttribute(GateRef gate) const case OpCode::FETCH_OR: case OpCode::LOAD_WITHOUT_BARRIER: case OpCode::LOAD: + case OpCode::LOAD_WITH_CONDITION: case OpCode::LOAD_HCLASS_OPCODE: case OpCode::STORE_WITHOUT_BARRIER: case OpCode::STORE: { diff --git a/ecmascript/compiler/lcr_circuit_builder.cpp b/ecmascript/compiler/lcr_circuit_builder.cpp index 5253932611..c66ebcb1ec 100644 --- a/ecmascript/compiler/lcr_circuit_builder.cpp +++ b/ecmascript/compiler/lcr_circuit_builder.cpp @@ -209,6 +209,32 @@ GateRef CircuitBuilder::LoadFromAddressWithoutBarrier(VariableType type, GateRef return result; } +GateRef CircuitBuilder::LoadBarrierCondition(GateRef glue) +{ + GateRef bitOffset = circuit_->GetConstantGateWithoutCache( + MachineType::I64, JSThread::GlueData::GetSharedGCStateBitFieldOffset(false), GateType::NJSValue()); + GateRef bitAddr = PtrAdd(glue, bitOffset); + GateRef gcStateBitField = LoadFromAddressWithoutBarrier(VariableType::INT64(), bitAddr); + GateRef readBarrierStateMask = circuit_->GetConstantGateWithoutCache( + MachineType::I64, JSThread::READ_BARRIER_STATE_BITFIELD_MASK, GateType::NJSValue()); + GateRef readBarrierStateBit = Int64And(gcStateBitField, readBarrierStateMask); + GateRef conditionValue = circuit_->GetConstantGateWithoutCache(MachineType::I64, 0, GateType::NJSValue()); + GateRef condition = Equal(readBarrierStateBit, conditionValue); + + return condition; +} + +GateRef CircuitBuilder::LoadWithCondition(VariableType type, GateRef glue, GateRef addr, GateRef condition, MemoryAttribute mAttr) +{ + auto label = GetCurrentLabel(); + auto depend = label->GetDepend(); + auto bits = LoadStoreAccessor::ToValue(mAttr); + GateRef result = GetCircuit()->NewGate(GetCircuit()->LoadWithCondition(bits), type.GetMachineType(), + { depend, glue, addr, condition}, type.GetGateType()); + label->SetDepend(result); + return result; +} + GateRef CircuitBuilder::DoubleTrunc(GateRef glue, GateRef gate, GateRef value, const char* comment) { if (GetCompilationConfig()->IsAArch64()) { diff --git a/ecmascript/compiler/lcr_opcodes.h b/ecmascript/compiler/lcr_opcodes.h index 2961a55bf8..d9e88d058d 100644 --- a/ecmascript/compiler/lcr_opcodes.h +++ b/ecmascript/compiler/lcr_opcodes.h @@ -76,6 +76,7 @@ namespace panda::ecmascript::kungfu { V(Fcmp, FCMP, GateFlags::NONE_FLAG, 0, 0, 2) \ V(Load, LOAD, GateFlags::NO_WRITE, 0, 1, 2) \ V(LoadWithoutBarrier, LOAD_WITHOUT_BARRIER, GateFlags::NO_WRITE, 0, 1, 1) \ + V(LoadWithCondition, LOAD_WITH_CONDITION, GateFlags::NO_WRITE, 0, 1, 3) \ V(Store, STORE, GateFlags::NONE_FLAG, 0, 1, 5) \ V(StoreWithoutBarrier, STORE_WITHOUT_BARRIER, GateFlags::NONE_FLAG, 0, 1, 2) \ V(Alloca, ALLOCA, GateFlags::NONE_FLAG, 0, 0, 0) \ diff --git a/ecmascript/compiler/pass.h b/ecmascript/compiler/pass.h index e36c9c3ded..d88fd2cb84 100644 --- a/ecmascript/compiler/pass.h +++ b/ecmascript/compiler/pass.h @@ -42,6 +42,7 @@ #include "ecmascript/compiler/number_speculative_runner.h" #include "ecmascript/compiler/post_schedule.h" #include "ecmascript/compiler/precompile_checker.h" +#include "ecmascript/compiler/read_barrier_elimination.h" #include "ecmascript/compiler/scheduler.h" #include "ecmascript/compiler/string_builder_optimizer.h" #include "ecmascript/compiler/slowpath_lowering.h" @@ -202,6 +203,11 @@ public: methodInfo_->SetIsCompiled(false); } + void SetAllocator(NativeAreaAllocator *allocator) + { + allocator_ = allocator; + } + private: BytecodeCircuitBuilder *builder_ {nullptr}; Circuit *circuit_ {nullptr}; @@ -696,6 +702,43 @@ public: } }; +class StubReadBarrierEliminationPass { +public: + bool Run(PassData *data) + { + TimeScope timescope("ReadBarrierEliminationPass", data->GetMethodName(), data->GetMethodOffset(), + data->GetLog()); + Chunk chunk(data->GetNativeAreaAllocator()); + bool enableLog = data->GetLog()->EnableMethodCIRLog(); + CombinedPassVisitor visitor(data->GetCircuit(), enableLog, data->GetMethodName(), &chunk); + ReadBarrierElimination readBarrierElimination(data->GetCircuit(), &visitor, &chunk); + visitor.AddPass(&readBarrierElimination); + visitor.VisitGraph(); + visitor.PrintLog("Read Barrier Elimination"); + return true; + } +}; + +class ReadBarrierEliminationPass { +public: + bool Run(PassData *data) + { + JSRuntimeOptions runtimeOption = data->GetPassContext()->GetCompilationEnv()->GetJSOptions(); + if (runtimeOption.IsEnableReadBarrierElimination()) { + TimeScope timescope("ReadBarrierEliminationPass", data->GetMethodName(), data->GetMethodOffset(), + data->GetLog()); + Chunk chunk(data->GetNativeAreaAllocator()); + bool enableLog = data->GetLog()->EnableMethodCIRLog(); + CombinedPassVisitor visitor(data->GetCircuit(), enableLog, data->GetMethodName(), &chunk); + ReadBarrierElimination readBarrierElimination(data->GetCircuit(), &visitor, &chunk); + visitor.AddPass(&readBarrierElimination); + visitor.VisitGraph(); + visitor.PrintLog("Read Barrier Elimination"); + } + return true; + } +}; + class UselessGateEliminationPass { public: bool Run(PassData* data) diff --git a/ecmascript/compiler/pass_manager.cpp b/ecmascript/compiler/pass_manager.cpp index 280589e152..b625f93e03 100644 --- a/ecmascript/compiler/pass_manager.cpp +++ b/ecmascript/compiler/pass_manager.cpp @@ -185,6 +185,9 @@ bool JitPassManager::Compile(JSHandle &profileTypeInfo, } pipeline.RunPass(); pipeline.RunPass(); + if (g_isEnableCMCGC) { + pipeline.RunPass(); + } pipeline.RunPass(); if (!compilationEnv_->GetJSOptions().IsEnableJitFastCompile() && compilationEnv_->GetJSOptions().IsEnableJitVerifyPass()) { @@ -350,6 +353,9 @@ bool PassManager::Compile(JSPandaFile *jsPandaFile, const std::string &fileName, pipeline.RunPass(); pipeline.RunPass(); pipeline.RunPass(); + if (g_isEnableCMCGC) { + pipeline.RunPass(); + } pipeline.RunPass(); if (passOptions_->EnableVerifierPass()) { pipeline.RunPass(); diff --git a/ecmascript/compiler/post_schedule.cpp b/ecmascript/compiler/post_schedule.cpp index d05772ca16..c754599e0b 100644 --- a/ecmascript/compiler/post_schedule.cpp +++ b/ecmascript/compiler/post_schedule.cpp @@ -68,6 +68,10 @@ void PostSchedule::GenerateExtraBB(ControlFlowGraph &cfg) needRetraverse = VisitLoad(current, cfg, bbIdx, instIdx); break; } + case OpCode::LOAD_WITH_CONDITION: { + needRetraverse = VisitLoadWithCondition(current, cfg, bbIdx, instIdx); + break; + } case OpCode::LOAD_HCLASS_OPCODE: { needRetraverse = VisitLoad(current, cfg, bbIdx, instIdx, true); break; @@ -894,6 +898,97 @@ bool PostSchedule::VisitLoad(GateRef gate, ControlFlowGraph &cfg, size_t bbIdx, return false; } +bool PostSchedule::VisitLoadWithCondition(GateRef gate, ControlFlowGraph &cfg, size_t bbIdx, size_t instIdx) +{ + std::vector currentBBGates; + std::vector successBBGates; + std::vector failBBGates; + std::vector endBBGates; + MemoryAttribute::Barrier kind = GetBarrierKind(gate); + ASSERT(!isStwCopyStub_); + LoweringLoadWithConditionAndPrepareScheduleGate(gate, currentBBGates, successBBGates, + failBBGates, endBBGates); + ReplaceBBState(cfg, bbIdx, currentBBGates, endBBGates); + ScheduleEndBB(endBBGates, cfg, bbIdx, instIdx); + ScheduleNewBB(successBBGates, cfg, bbIdx); + ScheduleNewBB(failBBGates, cfg, bbIdx); + ScheduleCurrentBB(currentBBGates, cfg, bbIdx, instIdx); + return true; +} + +void PostSchedule::LoweringLoadWithConditionAndPrepareScheduleGate(GateRef gate, + std::vector ¤tBBGates, + std::vector &successBBGates, + std::vector &failBBGates, + std::vector &endBBGates) +{ + Environment env(gate, circuit_, &builder_); + Label exit(&builder_); + GateRef glue = acc_.GetValueIn(gate, 0); + GateRef addr = acc_.GetValueIn(gate, 1); + VariableType type = VariableType(acc_.GetMachineType(gate), acc_.GetGateType(gate)); + + GateRef hole = circuit_->GetConstantGateWithoutCache( + MachineType::I64, JSTaggedValue::VALUE_HOLE, GateType::TaggedValue()); + DEFVALUE(result, (&builder_), type, hole); + + Label callRuntime(&builder_); + Label noBarrier(&builder_); + GateRef condition = acc_.GetValueIn(gate, 2); + Label *currentLabel = env.GetCurrentLabel(); + BRANCH_CIR_LIKELY(condition, &noBarrier, &callRuntime); + { + GateRef ifBranch = currentLabel->GetControl(); + PrepareToScheduleNewGate(ifBranch, currentBBGates); + PrepareToScheduleNewGate(hole, currentBBGates); + } + builder_.Bind(&noBarrier); + { + GateRef ifTrue = builder_.GetState(); + GateRef loadWithoutBarrier = builder_.LoadFromAddressWithoutBarrier(type, addr, acc_.GetMemoryAttribute(gate)); + result = loadWithoutBarrier; + builder_.Jump(&exit); + { + GateRef ordinaryBlock = noBarrier.GetControl(); + PrepareToScheduleNewGate(ordinaryBlock, successBBGates); + PrepareToScheduleNewGate(loadWithoutBarrier, successBBGates); + PrepareToScheduleNewGate(ifTrue, successBBGates); + } + } + builder_.Bind(&callRuntime); + { + GateRef ifFalse = builder_.GetState(); + int index = CommonStubCSigns::GetValueWithBarrier; + const CallSignature *cs = CommonStubCSigns::Get(index); + ASSERT(cs->IsCommonStub()); + GateRef target = circuit_->GetConstantGateWithoutCache(MachineType::ARCH, index, GateType::NJSValue()); + GateRef reservedFrameArgs = circuit_->GetConstantGateWithoutCache(MachineType::I64, 0, GateType::NJSValue()); + GateRef reservedPc = circuit_->GetConstantGateWithoutCache(MachineType::I64, 0, GateType::NJSValue()); + GateRef loadBarrier = builder_.Call(cs, glue, target, builder_.GetDepend(), + { glue, addr, reservedFrameArgs, reservedPc }, + Circuit::NullGate(), "load barrier"); + result = loadBarrier; + builder_.Jump(&exit); + { + GateRef ordinaryBlock = callRuntime.GetControl(); + PrepareToScheduleNewGate(ordinaryBlock, failBBGates); + PrepareToScheduleNewGate(loadBarrier, failBBGates); + PrepareToScheduleNewGate(reservedPc, failBBGates); + PrepareToScheduleNewGate(reservedFrameArgs, failBBGates); + PrepareToScheduleNewGate(target, failBBGates); + PrepareToScheduleNewGate(ifFalse, failBBGates); + } + } + builder_.Bind(&exit); + { + GateRef merge = builder_.GetState(); + GateRef phi = *result; + PrepareToScheduleNewGate(merge, endBBGates); + PrepareToScheduleNewGate(phi, endBBGates); + } + acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), *result); +} + void PostSchedule::LoweringLoadWithBarrierAndPrepareScheduleGate(GateRef gate, std::vector ¤tBBGates, std::vector &successBBGates, diff --git a/ecmascript/compiler/post_schedule.h b/ecmascript/compiler/post_schedule.h index 61e928377e..739e707eda 100644 --- a/ecmascript/compiler/post_schedule.h +++ b/ecmascript/compiler/post_schedule.h @@ -53,6 +53,7 @@ private: bool VisitHeapAllocForCMCGC(GateRef gate, ControlFlowGraph &cfg, size_t bbIdx, size_t instIdx); bool VisitStore(GateRef gate, ControlFlowGraph &cfg, size_t bbIdx, size_t instIdx); bool VisitLoad(GateRef gate, ControlFlowGraph &cfg, size_t bbIdx, size_t instIdx, bool isLoadHClass = false); + bool VisitLoadWithCondition(GateRef gate, ControlFlowGraph &cfg, size_t bbIdx, size_t instIdx); void ReplaceGateDirectly(std::vector &gates, ControlFlowGraph &cfg, size_t bbIdx, size_t instIdx); void ScheduleEndBB(std::vector &gates, ControlFlowGraph &cfg, size_t bbIdx, size_t instIdx); @@ -71,6 +72,10 @@ private: std::vector &failBBGates, std::vector &endBBGates, [[maybe_unused]] int64_t flag); + void LoweringLoadWithConditionAndPrepareScheduleGate(GateRef gate, std::vector ¤tBBGates, + std::vector &successBBGates, + std::vector &failBBGates, + std::vector &endBBGates); void LoweringHeapAllocate(GateRef gate, std::vector ¤tBBGates, std::vector &successBBGates, @@ -90,6 +95,7 @@ private: std::vector &successBBGates, std::vector &failBBGates, std::vector &endBBGates); + void LoweringLoadWithConditionAndPrepareScheduleGate(GateRef gate, std::vector ¤tBBGates); void LoweringLoadHClassAndPrepareScheduleGate(GateRef gate, std::vector ¤tBBGates); void PrepareToScheduleNewGate(GateRef gate, std::vector &gates); diff --git a/ecmascript/compiler/read_barrier_elimination.cpp b/ecmascript/compiler/read_barrier_elimination.cpp new file mode 100644 index 0000000000..8be6fc260f --- /dev/null +++ b/ecmascript/compiler/read_barrier_elimination.cpp @@ -0,0 +1,242 @@ +/* + * 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. + */ + +#include "ecmascript/compiler/read_barrier_elimination.h" + +namespace panda::ecmascript::kungfu { + +void ReadBarrierElimination::SetBarrierState(GateRef gate, ReadBarrierElimination::BarrierState state) +{ + barrierStates_[gate] = state; + if (state != ReadBarrierElimination::BarrierState::NOT_NEED_BARRIER) { + SetBarrierGate(gate, Gate::InvalidGateRef); + } +} + +ReadBarrierElimination::BarrierState ReadBarrierElimination::GetBarrierState(GateRef gate) +{ + if (barrierStates_.find(gate) != barrierStates_.end()) { + return barrierStates_[gate]; + } + return ReadBarrierElimination::BarrierState::UNDEFINED; +} + +void ReadBarrierElimination::SetBarrierGate(GateRef gate, GateRef barrierGate) +{ + barrierGates_[gate] = barrierGate; +} + +GateRef ReadBarrierElimination::GetBarrierGate(GateRef gate) +{ + if (barrierGates_.find(gate) != barrierGates_.end()) { + return barrierGates_[gate]; + } + return Gate::InvalidGateRef; +} + +void ReadBarrierElimination::RevisitAllUses(GateRef gate) +{ + auto uses = acc_.Uses(gate); + for (auto use : uses) { + visitor_->ReVisitGate(use); + } +} + +GateRef ReadBarrierElimination::VisitGate(GateRef gate) +{ + OpCode op = acc_.GetOpCode(gate); + switch (op) { + case OpCode::LOAD: + return VisitLoadGate(gate); + case OpCode::CALL: + case OpCode::BUILTINS_CALL: + case OpCode::BUILTINS_CALL_WITH_ARGV: + case OpCode::CALL_OPTIMIZED: + case OpCode::FAST_CALL_OPTIMIZED: + case OpCode::RUNTIME_CALL: + case OpCode::RUNTIME_CALL_WITH_ARGV: + case OpCode::BASELINE_CALL: + return VisitCheckSafePointGate(gate); + case OpCode::NOGC_RUNTIME_CALL: + return VisitNoGCRuntimeCall(gate); + case OpCode::DEPEND_SELECTOR: + return VisitDependSelector(gate); + case OpCode::DEPEND_ENTRY: + return VisitDependEntry(gate); + default: + return VisitGeneralGate(gate); + } +} + +GateRef ReadBarrierElimination::VisitNoGCRuntimeCall(GateRef gate) { + GateRef indexGate = acc_.GetValueIn(gate, 0); + size_t index = acc_.GetConstantValue(indexGate); + if (RuntimeStubCSigns::IsAsmStub(index)) { + return VisitCheckSafePointGate(gate); + } else { + return VisitGeneralGate(gate); + } +} + +GateRef ReadBarrierElimination::VisitDependEntry(GateRef gate) +{ + SetBarrierState(gate, ReadBarrierElimination::BarrierState::NEED_BARRIER); + return Circuit::NullGate(); +} + +GateRef ReadBarrierElimination::VisitLoadGate(GateRef gate) +{ + if (!acc_.IsGCRelated(gate)) { + return VisitGeneralGate(gate); + } + GateRef dep = acc_.GetDep(gate); + auto depBarrierState = GetBarrierState(dep); + if (depBarrierState != ReadBarrierElimination::BarrierState::NOT_NEED_BARRIER) { + if (GetBarrierState(gate) != ReadBarrierElimination::BarrierState::NOT_NEED_BARRIER || + GetBarrierGate(gate) != gate) { + SetBarrierGate(gate, gate); + SetBarrierState(gate, ReadBarrierElimination::BarrierState::NOT_NEED_BARRIER); + RevisitAllUses(gate); + } + } else { + return Propagate(gate, dep); + } + return Circuit::NullGate(); +} + +GateRef ReadBarrierElimination::VisitCheckSafePointGate(GateRef gate) +{ + if (GetBarrierState(gate) != ReadBarrierElimination::BarrierState::NEED_BARRIER) { + SetBarrierState(gate, ReadBarrierElimination::BarrierState::NEED_BARRIER); + RevisitAllUses(gate); + } + return Circuit::NullGate(); +} + +GateRef ReadBarrierElimination::MergeBarrierState(GateRef lGate, GateRef rGate) +{ + if (lGate == Gate::InvalidGateRef || rGate == Gate::InvalidGateRef) { + return Gate::InvalidGateRef; + } + + auto lBarrierState = GetBarrierState(lGate); + auto rBarrierState = GetBarrierState(rGate); + auto lBarrierGate = GetBarrierGate(lGate); + auto rBarrierGate = GetBarrierGate(rGate); + + if (lBarrierState == ReadBarrierElimination::BarrierState::UNDEFINED || + rBarrierState == ReadBarrierElimination::BarrierState::NEED_BARRIER) { + return rGate; + } + if (lBarrierState == ReadBarrierElimination::BarrierState::NEED_BARRIER || + rBarrierState == ReadBarrierElimination::BarrierState::UNDEFINED) { + return lGate; + } + if (lBarrierGate != rBarrierGate) { + return Gate::InvalidGateRef; + } + return lGate; +} + +GateRef ReadBarrierElimination::VisitDependSelector(GateRef gate) +{ + size_t numIn = acc_.GetDependCount(gate); + GateRef mergeTarget = acc_.GetDep(gate, 0); + for (size_t i = 1; i < numIn; i++) { + mergeTarget = MergeBarrierState(mergeTarget, acc_.GetDep(gate, i)); + } + if (mergeTarget == Gate::InvalidGateRef) { + if (GetBarrierState(gate) != ReadBarrierElimination::BarrierState::NEED_BARRIER) { + SetBarrierState(gate, ReadBarrierElimination::BarrierState::NEED_BARRIER); + RevisitAllUses(gate); + } + } else { + if (TryCopyBarrierState(gate, mergeTarget)) { + RevisitAllUses(gate); + } + } + return Circuit::NullGate(); +} + +bool ReadBarrierElimination::TryCopyBarrierState(GateRef gate, GateRef dep) +{ + auto gateBarrierState = GetBarrierState(gate); + auto depBarrierState = GetBarrierState(dep); + auto gateBarrierGate = GetBarrierGate(gate); + auto depBarrierGate = GetBarrierGate(dep); + if (gateBarrierState == depBarrierState && gateBarrierGate == depBarrierGate) { + return false; + } + SetBarrierGate(gate, depBarrierGate); + SetBarrierState(gate, depBarrierState); + return true; +} + +GateRef ReadBarrierElimination::Propagate(GateRef gate, GateRef dep) +{ + if (TryCopyBarrierState(gate, dep)) { + RevisitAllUses(gate); + } + return Circuit::NullGate(); +} + +GateRef ReadBarrierElimination::VisitGeneralGate(GateRef gate) +{ + if (acc_.GetDependCount(gate) == 0) { + return Circuit::NullGate(); + } + ASSERT(acc_.GetDependCount(gate) == 1); + auto dep = acc_.GetDep(gate); + return Propagate(gate, dep); +} + +void ReadBarrierElimination::Finalize() +{ + std::vector allGateList; + circuit_->GetAllGates(allGateList); + for (auto gate : allGateList) { + + if (acc_.GetOpCode(gate) == OpCode::LOAD && acc_.IsGCRelated(gate)) { + ASSERT(GetBarrierState(gate) == ReadBarrierElimination::BarrierState::NOT_NEED_BARRIER); + if (GetBarrierGate(gate) == gate) { + Environment env(gate, circuit_, &builder_); + GateRef glue = acc_.GetValueIn(gate, 0); + GateRef addr = acc_.GetValueIn(gate, 1); + GateRef condition = builder_.LoadBarrierCondition(glue); + conditionGates_[gate] = condition; + LOG_COMPILER(INFO) << acc_.GetId(gate) << " -> " << acc_.GetId(gate); + VariableType type = VariableType(acc_.GetMachineType(gate), acc_.GetGateType(gate)); + GateRef loadWithCondition = builder_.LoadWithCondition(type, glue, addr, condition); + acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), loadWithCondition); + } + } + } + for (auto gate : allGateList) { + if (acc_.GetOpCode(gate) == OpCode::LOAD && acc_.IsGCRelated(gate)) { + if (GetBarrierGate(gate) != gate) { + Environment env(gate, circuit_, &builder_); + GateRef glue = acc_.GetValueIn(gate, 0); + GateRef addr = acc_.GetValueIn(gate, 1); + GateRef condition = conditionGates_[barrierGates_[gate]]; + LOG_COMPILER(INFO) << acc_.GetId(gate) << " -> " << acc_.GetId(GetBarrierGate(gate)); + VariableType type = VariableType(acc_.GetMachineType(gate), acc_.GetGateType(gate)); + GateRef loadWithCondition = builder_.LoadWithCondition(type, glue, addr, condition); + acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), loadWithCondition); + } + } + } +} + +} // panda::ecmascript::kungfu \ No newline at end of file diff --git a/ecmascript/compiler/read_barrier_elimination.h b/ecmascript/compiler/read_barrier_elimination.h new file mode 100644 index 0000000000..810fe1302e --- /dev/null +++ b/ecmascript/compiler/read_barrier_elimination.h @@ -0,0 +1,64 @@ +/* + * 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. + */ + +#ifndef ECMASCRIPT_COMPILER_READ_BARRIER_ELIMINATION_H +#define ECMASCRIPT_COMPILER_READ_BARRIER_ELIMINATION_H + +#include "ecmascript/compiler/circuit_builder.h" +#include "ecmascript/compiler/circuit_builder-inl.h" +#include "ecmascript/compiler/combined_pass_visitor.h" +#include "ecmascript/compiler/gate_accessor.h" + + +namespace panda::ecmascript::kungfu { + +class ReadBarrierElimination : public PassVisitor { +public: + enum class BarrierState { + UNDEFINED, + NEED_BARRIER, // NEED_BARRIER means this gate can't find a barrier gate that already exist + NOT_NEED_BARRIER, // NOT_NEED_BARRIER means an old barrier gate can be used by this gate (maybe generated by itself) + }; + ReadBarrierElimination(Circuit* circuit, RPOVisitor *visitor, Chunk *chunk) + : PassVisitor(circuit, chunk, visitor), builder_(circuit) {} + GateRef VisitGate(GateRef gate) override; + void Finalize() override; +private: + void Init(); + void SetBarrierState(GateRef gate, ReadBarrierElimination::BarrierState state); + ReadBarrierElimination::BarrierState GetBarrierState(GateRef gate); + void SetBarrierGate(GateRef gate, GateRef barrierGate); + GateRef GetBarrierGate(GateRef gate); + GateRef MergeBarrierState(GateRef lGate, GateRef rGate); + bool TryCopyBarrierState(GateRef gate, GateRef dep); + GateRef Propagate(GateRef gate, GateRef dep); + GateRef VisitDependEntry(GateRef gate); + GateRef VisitGeneralGate(GateRef gate); + GateRef VisitDependSelector(GateRef gate); + GateRef VisitCheckSafePointGate(GateRef gate); + GateRef VisitNoGCRuntimeCall(GateRef gate); + GateRef VisitLoadGate(GateRef gate); + void RevisitAllUses(GateRef gate); + + CircuitBuilder builder_; + std::map barrierStates_; + std::map barrierGates_; // if barrier state is NOT_NEED_BARRIER, barrier gate indicates the gate that can be reused. + std::map needBarrierDepNums_; + std::map conditionGates_; + std::queue workList_; +}; +}; // namespace panda::ecmascript::kungfu + +#endif \ No newline at end of file diff --git a/ecmascript/compiler/stub_compiler.cpp b/ecmascript/compiler/stub_compiler.cpp index 322f97386b..b8289301db 100644 --- a/ecmascript/compiler/stub_compiler.cpp +++ b/ecmascript/compiler/stub_compiler.cpp @@ -22,11 +22,15 @@ namespace panda::ecmascript::kungfu { class StubPassData : public PassData { public: - StubPassData(Stub *stub, LLVMModule *module, CompilerLog *log) + StubPassData(Stub *stub, LLVMModule *module, CompilerLog *log, NativeAreaAllocator *allocator) : PassData(nullptr, nullptr, nullptr, log, "stubs"), cfg_(module->GetTripleStr()), module_(module), - stub_(stub) {} + stub_(stub) + { + SetAllocator(allocator); + } + ~StubPassData() = default; const CompilationConfig *GetCompilationConfig() const @@ -96,9 +100,12 @@ void StubCompiler::RunPipeline(LLVMModule *module, NativeAreaAllocator *allocato Stub stub(cs, &circuit); log->SetStubLog(stub.GetMethodName(), GetLogList()); - StubPassData data(&stub, module, log); + StubPassData data(&stub, module, log, allocator); PassRunner pipeline(&data); pipeline.RunPass(); + if (!cs->IsStwCopyStub()) { + pipeline.RunPass(); + } pipeline.RunPass(); pipeline.RunPass(cs->IsStwCopyStub()); pipeline.RunPass(i); diff --git a/ecmascript/js_runtime_options.cpp b/ecmascript/js_runtime_options.cpp index 5ee5fdccf6..1cbf317d71 100644 --- a/ecmascript/js_runtime_options.cpp +++ b/ecmascript/js_runtime_options.cpp @@ -221,6 +221,7 @@ const std::string PUBLIC_API HELP_OPTION_MSG = " 'filter': only compile specified methods during JIT runtime.\n" "--compiler-jit-method-path: Store method names for jit method dichotomy.\n" " Default: 'method_compiled_by_jit.cfg'\n" + "--compiler-enable-read-barrier-elimination: Enable read barrier elimination. Default: 'true'\n" // Please add new options above this line for keep a blank line after help message. "\n"; @@ -385,6 +386,8 @@ bool JSRuntimeOptions::ParseCommand(const int argc, const char **argv) {"compiler-jit-method-path", required_argument, nullptr, OPTION_COMPILER_JIT_METHOD_PATH}, {"mem-config", required_argument, nullptr, OPTION_MEM_CONFIG}, {"multi-context", required_argument, nullptr, OPTION_MULTI_CONTEXT}, + {"compiler-enable-read-barrier-elimination", required_argument, nullptr, + OPTION_COMPILER_ENABLE_READ_BARRIER_ELIMINATION}, {nullptr, 0, nullptr, 0}, }; @@ -1507,6 +1510,14 @@ bool JSRuntimeOptions::ParseCommand(const int argc, const char **argv) return false; } break; + case OPTION_COMPILER_ENABLE_READ_BARRIER_ELIMINATION: + ret = ParseBoolParam(&argBool); + if (ret) { + SetEnableReadBarrierElimination(argBool); + } else { + return false; + } + break; default: LOG_ECMA(ERROR) << "Invalid option\n"; return false; diff --git a/ecmascript/js_runtime_options.h b/ecmascript/js_runtime_options.h index cb78d4b375..d626df14ab 100644 --- a/ecmascript/js_runtime_options.h +++ b/ecmascript/js_runtime_options.h @@ -246,6 +246,7 @@ enum CommandValues { OPTION_COMPILER_JIT_METHOD_PATH, OPTION_MEM_CONFIG, OPTION_MULTI_CONTEXT, + OPTION_COMPILER_ENABLE_READ_BARRIER_ELIMINATION, // OPTION_LAST should at the last OPTION_LAST, @@ -2249,6 +2250,16 @@ public: { return disableModuleSnapshot_; } + + void SetEnableReadBarrierElimination(bool value) + { + enableReadBarrierElimination_ = value; + } + + bool IsEnableReadBarrierElimination() const + { + return enableReadBarrierElimination_; + } void DisableGCTimeoutCheck() { @@ -2581,6 +2592,7 @@ private: bool enableWarmStartupSmartGC_ {false}; bool disableModuleSnapshot_ { false }; bool enableGCTimeoutCheck_ {true}; + bool enableReadBarrierElimination_ {true}; }; } // namespace panda::ecmascript -- Gitee