diff --git a/ecmascript/compiler/BUILD.gn b/ecmascript/compiler/BUILD.gn index bae6476c31fa6e17a7a1dac1d9c4a395f2a2d275..43c92ba50563605c951d948b89d16b3ca1be17da 100644 --- a/ecmascript/compiler/BUILD.gn +++ b/ecmascript/compiler/BUILD.gn @@ -158,6 +158,7 @@ libark_jsoptimizer_sources = [ "profiler_stub_builder.cpp", "range_analysis.cpp", "range_guard.cpp", + "read_barrier_state_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 0afb37c48292c8f1b7b97a3a9b5fb81966287387..08dd9fd4a1501cb3a06a901e110d787105ba9ff5 100644 --- a/ecmascript/compiler/circuit_builder.h +++ b/ecmascript/compiler/circuit_builder.h @@ -937,6 +937,11 @@ public: MemoryAttribute mAttr = MemoryAttribute::Default()); GateRef LoadWithoutBarrier(VariableType type, GateRef addr, MemoryAttribute mAttr = MemoryAttribute::Default()); + GateRef LoadBarrierState(GateRef glue); + + GateRef LoadWithBarrierState(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()); void StoreHClass(VariableType type, GateRef glue, GateRef base, GateRef offset, GateRef value, GateRef compValue, diff --git a/ecmascript/compiler/gate_accessor.cpp b/ecmascript/compiler/gate_accessor.cpp index 900c6243065508f720118d13628f6589d2b37781..1943832b6813247d1b58fa21db5d9ae67fb53579 100644 --- a/ecmascript/compiler/gate_accessor.cpp +++ b/ecmascript/compiler/gate_accessor.cpp @@ -139,6 +139,7 @@ MemoryAttribute GateAccessor::GetMemoryAttribute(GateRef gate) const switch (op) { case OpCode::LOAD_WITHOUT_BARRIER: case OpCode::LOAD: + case OpCode::LOAD_WITH_BARRIER_STATE: case OpCode::STORE_WITHOUT_BARRIER: case OpCode::STORE: { auto accessor = LoadStoreAccessor(gatePtr->GetOneParameterMetaData()->GetValue()); diff --git a/ecmascript/compiler/lcr_circuit_builder.cpp b/ecmascript/compiler/lcr_circuit_builder.cpp index 549495fd348cbb53be8579a115609ab62387ecd6..eed03b5874da62bf195e6e9da986ef7785932a91 100644 --- a/ecmascript/compiler/lcr_circuit_builder.cpp +++ b/ecmascript/compiler/lcr_circuit_builder.cpp @@ -14,6 +14,7 @@ */ #include "ecmascript/compiler/lcr_circuit_builder.h" +#include "common_interfaces/thread/base_thread.h" #include "ecmascript/compiler/circuit_builder-inl.h" namespace panda::ecmascript::kungfu { @@ -198,6 +199,38 @@ GateRef CircuitBuilder::LoadWithoutBarrier(VariableType type, GateRef addr, Memo return result; } +GateRef CircuitBuilder::LoadBarrierState(GateRef glue) +{ + GateRef bitOffset = circuit_->GetConstantGateWithoutCache( +#ifdef USE_CMC_GC + MachineType::I64, JSThread::GlueData::GetThreadHolderOffset(false), GateType::NJSValue()); +#else + MachineType::I64, JSThread::GlueData::GetStateAndFlagsOffset(false), GateType::NJSValue()); +#endif + GateRef bitAddr = PtrAdd(glue, bitOffset); + GateRef threadHolder = LoadWithoutBarrier(VariableType::NATIVE_POINTER(), bitAddr); + GateRef mutatorBase = LoadWithoutBarrier(VariableType::NATIVE_POINTER(), + threadHolder); // currently offset is zero + GateRef gcPhase = LoadWithoutBarrier(VariableType::INT8(), mutatorBase); // currently offset is zero + GateRef conditionValue = circuit_->GetConstantGateWithoutCache( + MachineType::I8, GCPhase::GC_PHASE_PRECOPY, GateType::NJSValue()); + GateRef condition = Int8GreaterThanOrEqual(gcPhase, conditionValue); + + return condition; +} + +GateRef CircuitBuilder::LoadWithBarrierState(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()->LoadWithBarrierState(bits), type.GetMachineType(), + { depend, glue, addr, condition}, type.GetGateType()); + label->SetDepend(result); + return result; +} + GateRef CircuitBuilder::DoubleTrunc(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 fc869fd238eb25e48f758002e31113d2cf0ada59..56347f2bad67a5d2788782cc7df5f0a2dce4efbd 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(LoadWithBarrierState, LOAD_WITH_BARRIER_STATE, 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 e3f17890a4365f011d4dda026fe7838c317221d7..75e02c3dbaa9d100074d8a3ea04fa2b1ecbb3f45 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_state_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}; @@ -685,6 +691,43 @@ public: } }; +class StubReadBarrierStateEliminationPass { +public: + bool Run(PassData *data) + { + TimeScope timescope("ReadBarrierStateEliminationPass", data->GetMethodName(), data->GetMethodOffset(), + data->GetLog()); + Chunk chunk(data->GetNativeAreaAllocator()); + bool enableLog = data->GetLog()->EnableMethodCIRLog(); + CombinedPassVisitor visitor(data->GetCircuit(), enableLog, data->GetMethodName(), &chunk); + ReadBarrierStateElimination ReadBarrierStateElimination(data->GetCircuit(), &visitor, &chunk); + visitor.AddPass(&ReadBarrierStateElimination); + visitor.VisitGraph(); + visitor.PrintLog("Read Barrier State Elimination"); + return true; + } +}; + +class ReadBarrierStateEliminationPass { +public: + bool Run(PassData *data) + { + JSRuntimeOptions runtimeOption = data->GetPassContext()->GetCompilationEnv()->GetJSOptions(); + if (runtimeOption.IsEnableReadBarrierElimination()) { + TimeScope timescope("ReadBarrierStateEliminationPass", data->GetMethodName(), data->GetMethodOffset(), + data->GetLog()); + Chunk chunk(data->GetNativeAreaAllocator()); + bool enableLog = data->GetLog()->EnableMethodCIRLog(); + CombinedPassVisitor visitor(data->GetCircuit(), enableLog, data->GetMethodName(), &chunk); + ReadBarrierStateElimination ReadBarrierStateElimination(data->GetCircuit(), &visitor, &chunk); + visitor.AddPass(&ReadBarrierStateElimination); + visitor.VisitGraph(); + visitor.PrintLog("Read Barrier State 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 26474d8eb6586682a6b63b2d6eb5f641f6de0fa9..c46e41a7e21537f9b0e2b0e61bb07622c65f67e3 100644 --- a/ecmascript/compiler/pass_manager.cpp +++ b/ecmascript/compiler/pass_manager.cpp @@ -183,6 +183,9 @@ bool JitPassManager::Compile(JSHandle &profileTypeInfo, } pipeline.RunPass(); pipeline.RunPass(); +#ifdef USE_READ_BARRIER + pipeline.RunPass(); +#endif pipeline.RunPass(); if (!compilationEnv_->GetJSOptions().IsEnableJitFastCompile() && compilationEnv_->GetJSOptions().IsEnableJitVerifyPass()) { @@ -348,6 +351,9 @@ bool PassManager::Compile(JSPandaFile *jsPandaFile, const std::string &fileName, pipeline.RunPass(); pipeline.RunPass(); pipeline.RunPass(); +#ifdef USE_READ_BARRIER + pipeline.RunPass(); +#endif pipeline.RunPass(); if (passOptions_->EnableVerifierPass()) { pipeline.RunPass(); diff --git a/ecmascript/compiler/post_schedule.cpp b/ecmascript/compiler/post_schedule.cpp index cb5335ce4ca79208fdbfa5ccd634da1d444d9e98..522733f11a48f7f289d22abffefde9192fb95bc7 100644 --- a/ecmascript/compiler/post_schedule.cpp +++ b/ecmascript/compiler/post_schedule.cpp @@ -15,9 +15,10 @@ #include "ecmascript/compiler/post_schedule.h" - +#include "common_interfaces/thread/base_thread.h" #include "ecmascript/compiler/circuit_builder-inl.h" + namespace panda::ecmascript::kungfu { void PostSchedule::Run(ControlFlowGraph &cfg) { @@ -62,6 +63,10 @@ void PostSchedule::GenerateExtraBB(ControlFlowGraph &cfg) needRetraverse = VisitLoad(current, cfg, bbIdx, instIdx); break; } + case OpCode::LOAD_WITH_BARRIER_STATE: { + needRetraverse = VisitLoadWithBarrierState(current, cfg, bbIdx, instIdx); + break; + } default: { break; } @@ -671,6 +676,28 @@ void PostSchedule::LoweringStoreUnknownBarrierAndPrepareScheduleGate(GateRef gat acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), Circuit::NullGate()); } +bool PostSchedule::VisitLoadWithBarrierState(GateRef gate, ControlFlowGraph &cfg, size_t bbIdx, size_t instIdx) +{ + std::vector currentBBGates; + std::vector successBBGates; + std::vector failBBGates; + std::vector endBBGates; +#ifdef USE_CMC_GC + LoweringLoadWithBarrierStateAndPrepareScheduleGate(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; +#else + LoweringLoadWithBarrierAndPrepareScheduleGate(gate, currentBBGates); + ReplaceGateDirectly(currentBBGates, cfg, bbIdx, instIdx); + return false; +#endif +} + bool PostSchedule::VisitLoad(GateRef gate, ControlFlowGraph &cfg, size_t bbIdx, size_t instIdx) { std::vector currentBBGates; @@ -714,6 +741,80 @@ bool PostSchedule::VisitLoad(GateRef gate, ControlFlowGraph &cfg, size_t bbIdx, } #ifdef USE_CMC_GC +void PostSchedule::LoweringLoadWithBarrierStateAndPrepareScheduleGate(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_UNLIKELY(condition, &callRuntime, &noBarrier); + { + GateRef ifBranch = currentLabel->GetControl(); + PrepareToScheduleNewGate(ifBranch, currentBBGates); + PrepareToScheduleNewGate(condition, currentBBGates); + PrepareToScheduleNewGate(hole, currentBBGates); + } + builder_.Bind(&callRuntime); + { + GateRef ifTrue = 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, successBBGates); + PrepareToScheduleNewGate(loadBarrier, successBBGates); + PrepareToScheduleNewGate(reservedPc, successBBGates); + PrepareToScheduleNewGate(reservedFrameArgs, successBBGates); + PrepareToScheduleNewGate(target, successBBGates); + PrepareToScheduleNewGate(ifTrue, successBBGates); + } + } + builder_.Bind(&noBarrier); + { + GateRef ifFalse = builder_.GetState(); + GateRef loadWithoutBarrier = builder_.LoadWithoutBarrier(type, addr, acc_.GetMemoryAttribute(gate)); + result = loadWithoutBarrier; + builder_.Jump(&exit); + { + GateRef ordinaryBlock = noBarrier.GetControl(); + PrepareToScheduleNewGate(ordinaryBlock, failBBGates); + PrepareToScheduleNewGate(loadWithoutBarrier, 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 8a3a1ba90b8489780a89eba3ef863dda46cea238..8375dafa612b870e66026cb2ba3bcd2e8efec4a8 100644 --- a/ecmascript/compiler/post_schedule.h +++ b/ecmascript/compiler/post_schedule.h @@ -50,6 +50,7 @@ private: bool VisitHeapAlloc(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 VisitLoadWithBarrierState(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); @@ -82,8 +83,13 @@ private: std::vector &successBBGates, std::vector &failBBGates, std::vector &endBBGates); + void LoweringLoadWithBarrierStateAndPrepareScheduleGate(GateRef gate, std::vector ¤tBBGates, + std::vector &successBBGates, + std::vector &failBBGates, + std::vector &endBBGates); #else void LoweringLoadWithBarrierAndPrepareScheduleGate(GateRef gate, std::vector ¤tBBGates); + void LoweringLoadWithBarrierStateAndPrepareScheduleGate(GateRef gate, std::vector ¤tBBGates); #endif void PrepareToScheduleNewGate(GateRef gate, std::vector &gates); diff --git a/ecmascript/compiler/read_barrier_state_elimination.cpp b/ecmascript/compiler/read_barrier_state_elimination.cpp new file mode 100644 index 0000000000000000000000000000000000000000..18639b08b3fd16f51d1ba23ff7108a8518bb5d43 --- /dev/null +++ b/ecmascript/compiler/read_barrier_state_elimination.cpp @@ -0,0 +1,240 @@ +/* + * 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_state_elimination.h" + +namespace panda::ecmascript::kungfu { + +void ReadBarrierStateElimination::SetBarrierState(GateRef gate, ReadBarrierStateElimination::BarrierState state) +{ + barrierStates_[gate] = state; + if (state != ReadBarrierStateElimination::BarrierState::AVAILABLE) { + SetBarrierGate(gate, Gate::InvalidGateRef); + } +} + +ReadBarrierStateElimination::BarrierState ReadBarrierStateElimination::GetBarrierState(GateRef gate) +{ + if (barrierStates_.find(gate) != barrierStates_.end()) { + return barrierStates_[gate]; + } + return ReadBarrierStateElimination::BarrierState::UNDEFINED; +} + +void ReadBarrierStateElimination::SetBarrierGate(GateRef gate, GateRef barrierGate) +{ + barrierGates_[gate] = barrierGate; +} + +GateRef ReadBarrierStateElimination::GetBarrierGate(GateRef gate) +{ + if (barrierGates_.find(gate) != barrierGates_.end()) { + return barrierGates_[gate]; + } + return Gate::InvalidGateRef; +} + +void ReadBarrierStateElimination::RevisitAllUses(GateRef gate) +{ + auto uses = acc_.Uses(gate); + for (auto use : uses) { + visitor_->ReVisitGate(use); + } +} + +GateRef ReadBarrierStateElimination::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 ReadBarrierStateElimination::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 ReadBarrierStateElimination::VisitDependEntry(GateRef gate) +{ + SetBarrierState(gate, ReadBarrierStateElimination::BarrierState::UNAVAILABLE); + return Circuit::NullGate(); +} + +GateRef ReadBarrierStateElimination::VisitLoadGate(GateRef gate) +{ + if (!acc_.IsGCRelated(gate)) { + return VisitGeneralGate(gate); + } + GateRef dep = acc_.GetDep(gate); + auto depBarrierState = GetBarrierState(dep); + if (depBarrierState != ReadBarrierStateElimination::BarrierState::AVAILABLE) { + if (GetBarrierState(gate) != ReadBarrierStateElimination::BarrierState::AVAILABLE || + GetBarrierGate(gate) != gate) { + SetBarrierGate(gate, gate); + SetBarrierState(gate, ReadBarrierStateElimination::BarrierState::AVAILABLE); + RevisitAllUses(gate); + } + } else { + return Propagate(gate, dep); + } + return Circuit::NullGate(); +} + +GateRef ReadBarrierStateElimination::VisitCheckSafePointGate(GateRef gate) +{ + if (GetBarrierState(gate) != ReadBarrierStateElimination::BarrierState::UNAVAILABLE) { + SetBarrierState(gate, ReadBarrierStateElimination::BarrierState::UNAVAILABLE); + RevisitAllUses(gate); + } + return Circuit::NullGate(); +} + +GateRef ReadBarrierStateElimination::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 == ReadBarrierStateElimination::BarrierState::UNDEFINED || + rBarrierState == ReadBarrierStateElimination::BarrierState::UNAVAILABLE) { + return rGate; + } + if (lBarrierState == ReadBarrierStateElimination::BarrierState::UNAVAILABLE || + rBarrierState == ReadBarrierStateElimination::BarrierState::UNDEFINED) { + return lGate; + } + if (lBarrierGate != rBarrierGate) { + return Gate::InvalidGateRef; + } + return lGate; +} + +GateRef ReadBarrierStateElimination::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) != ReadBarrierStateElimination::BarrierState::UNAVAILABLE) { + SetBarrierState(gate, ReadBarrierStateElimination::BarrierState::UNAVAILABLE); + RevisitAllUses(gate); + } + } else { + if (TryCopyBarrierState(gate, mergeTarget)) { + RevisitAllUses(gate); + } + } + return Circuit::NullGate(); +} + +bool ReadBarrierStateElimination::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 ReadBarrierStateElimination::Propagate(GateRef gate, GateRef dep) +{ + if (TryCopyBarrierState(gate, dep)) { + RevisitAllUses(gate); + } + return Circuit::NullGate(); +} + +GateRef ReadBarrierStateElimination::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 ReadBarrierStateElimination::Finalize() +{ + std::vector allGateList; + circuit_->GetAllGates(allGateList); + for (auto gate : allGateList) { + if (acc_.GetOpCode(gate) == OpCode::LOAD && acc_.IsGCRelated(gate)) { + ASSERT(GetBarrierState(gate) == ReadBarrierStateElimination::BarrierState::AVAILABLE); + if (GetBarrierGate(gate) == gate) { + Environment env(gate, circuit_, &builder_); + GateRef glue = acc_.GetValueIn(gate, 0); + GateRef addr = acc_.GetValueIn(gate, 1); + GateRef condition = builder_.LoadBarrierState(glue); + conditionGates_[gate] = condition; + VariableType type = VariableType(acc_.GetMachineType(gate), acc_.GetGateType(gate)); + GateRef loadWithBarrierState = builder_.LoadWithBarrierState(type, glue, addr, condition); + acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), loadWithBarrierState); + } + } + } + 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]]; + VariableType type = VariableType(acc_.GetMachineType(gate), acc_.GetGateType(gate)); + GateRef loadWithBarrierState = builder_.LoadWithBarrierState(type, glue, addr, condition); + acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), loadWithBarrierState); + } + } + } +} + +} // panda::ecmascript::kungfu \ No newline at end of file diff --git a/ecmascript/compiler/read_barrier_state_elimination.h b/ecmascript/compiler/read_barrier_state_elimination.h new file mode 100644 index 0000000000000000000000000000000000000000..c44226ea9d4c5a735b4c35f2dcb5b43c0a1774b8 --- /dev/null +++ b/ecmascript/compiler/read_barrier_state_elimination.h @@ -0,0 +1,67 @@ +/* + * 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 ReadBarrierStateElimination : public PassVisitor { +public: + enum class BarrierState { + UNDEFINED, + UNAVAILABLE, // UNAVAILABLE : no barrier state gate can be used by current gate + // AVAILABLE : a barrier state gate which is already generated can be used by + // current gate (maybe generated by current gate itself) + AVAILABLE, + }; + ReadBarrierStateElimination(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, ReadBarrierStateElimination::BarrierState state); + ReadBarrierStateElimination::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_; + // if barrier state is AVAILABLE, barrier gate indicates the barrier state gate that can be reused. + std::map barrierGates_; + 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 5ccf5b1a9c8d378c8286173ca6e1f4919cd7482c..850f0b12ab126eff64b80c6ca5a4924a0f5373ff 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(); +#ifdef USE_READ_BARRIER + pipeline.RunPass(); +#endif pipeline.RunPass(); pipeline.RunPass(); pipeline.RunPass(i); diff --git a/ecmascript/js_runtime_options.cpp b/ecmascript/js_runtime_options.cpp index 0fea01ed9874af63b927615f42a4451bb0f17ffe..416fd4ba92d772f554ea62a99b8e1c4647f64f9f 100644 --- a/ecmascript/js_runtime_options.cpp +++ b/ecmascript/js_runtime_options.cpp @@ -206,6 +206,7 @@ const std::string PUBLIC_API HELP_OPTION_MSG = " Default : 'false'\n" "--compiler-an-file-max-size: Max size of compiler .an file in MB. '0' means Default\n" " Default: No limit for Host, '100' for TargetCompilerMode\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"; @@ -357,6 +358,8 @@ bool JSRuntimeOptions::ParseCommand(const int argc, const char **argv) {"compiler-an-file-max-size", required_argument, nullptr, OPTION_COMPILER_AN_FILE_MAX_SIZE}, {"compiler-trace-builtins", required_argument, nullptr, OPTION_COMPILER_TRACE_BUILTINS}, {"mem-config", required_argument, nullptr, OPTION_MEM_CONFIG}, + {"compiler-enable-read-barrier-elimination", required_argument, nullptr, + OPTION_COMPILER_ENABLE_READ_BARRIER_ELIMINATION}, {nullptr, 0, nullptr, 0}, }; @@ -1409,6 +1412,13 @@ bool JSRuntimeOptions::ParseCommand(const int argc, const char **argv) break; case OPTION_MEM_CONFIG: SetMemConfigProperty(optarg); + 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"; diff --git a/ecmascript/js_runtime_options.h b/ecmascript/js_runtime_options.h index 8eeb84393b125e9e48bcbfc48727f9ea2c48128c..edc4423baac74bb240cae51b397f6f22e1bfad00 100644 --- a/ecmascript/js_runtime_options.h +++ b/ecmascript/js_runtime_options.h @@ -230,6 +230,7 @@ enum CommandValues { OPTION_COMPILER_ENABLE_DFX_HISYS_EVENT, OPTION_ENABLE_LOADING_STUBS_LOG, OPTION_MEM_CONFIG, + OPTION_COMPILER_ENABLE_READ_BARRIER_ELIMINATION, // OPTION_LAST should at the last OPTION_LAST, @@ -2096,6 +2097,15 @@ public: static bool ParseUint32(const std::string &arg, uint32_t* argUInt32); static bool ParseUint64(const std::string &arg, uint64_t* argUInt64); static bool ParseDouble(const std::string &arg, double* argDouble); + void SetEnableReadBarrierElimination(bool value) + { + enableReadBarrierElimination_ = value; + } + + bool IsEnableReadBarrierElimination() const + { + return enableReadBarrierElimination_; + } public: static constexpr int32_t MAX_APP_COMPILE_METHOD_SIZE = 4_KB; @@ -2394,6 +2404,7 @@ private: #else bool storeBarrierOpt_ {false}; #endif + bool enableReadBarrierElimination_ {true}; uint64_t CompilerAnFileMaxByteSize_ {0_MB}; bool enableJitVerifyPass_ {true}; size_t heapSize_ = {0};