我来分析 OpenJDK HotSpot 中 PPC 架构下的 Shenandoah 垃圾回收器屏障汇编代码文件。

文件概述

shenandoahBarrierSetAssembler_ppc.cpp 是 Shenandoah GC 在 PPC(PowerPC)架构上的屏障汇编实现。Shenandoah 使用读屏障和写屏障来实现并发垃圾回收,该文件负责生成这些屏障的机器码。

核心功能

1. 屏障类型

Shenandoah 主要实现以下屏障:

  • 读屏障(Read Barrier):在对象引用加载时检查并处理
  • 写屏障(Write Barrier):在引用赋值时执行
  • SATB 屏障(Snapshot-at-the-Beginning):用于并发标记

关键函数分析

1. 读屏障实现

void ShenandoahBarrierSetAssembler::load_at(MacroAssembler* masm,
                                            DecoratorSet decorators,
                                            BasicType type,
                                            Register dst,
                                            Address src,
                                            Register tmp1,
                                            Register tmp_thread) {
    // 如果不是对象引用类型,直接加载
    if (!is_reference_type(type)) {
        BarrierSetAssembler::load_at(masm, decorators, type, dst, src, tmp1, tmp_thread);
        return;
    }
    
    // 加载对象引用
    BarrierSetAssembler::load_at(masm, decorators, type, dst, src, tmp1, tmp_thread);
    
    // 如果不在 GC 临界区,跳过屏障
    if (ShenandoahBarrierSet::skip_barrier_load(decorators)) {
        return;
    }
    
    // 生成读屏障代码
    Label done;
    Label resolve;
    
    // 检查是否需要处理
    __ ld(tmp1, in_bytes(ShenandoahRuntime::load_reference_barrier_weak()), dst);
    __ cmpdi(CCR0, tmp1, 0);
    __ beq(CCR0, done);
    
    // 调用运行时解析函数
    __ bind(resolve);
    __ mr(R3_ARG1, dst);  // 参数:对象引用
    __ call_VM_leaf(CAST_FROM_FN_PTR(address, ShenandoahRuntime::load_reference_barrier), 
                    R3_ARG1);
    __ mr(dst, R3_RET);   // 更新返回值
    
    __ bind(done);
}

2. 写屏障实现

void ShenandoahBarrierSetAssembler::store_at(MacroAssembler* masm,
                                             DecoratorSet decorators,
                                             BasicType type,
                                             Address dst,
                                             Register val,
                                             Register tmp1,
                                             Register tmp2,
                                             Register tmp3) {
    // 如果是对象引用类型,需要写屏障
    if (is_reference_type(type)) {
        // 前屏障(Pre-barrier):SATB 标记
        if (ShenandoahSATBBarrier) {
            pre_barrier(masm, decorators, dst, val, tmp1, tmp2, tmp3);
        }
        
        // 执行实际存储
        BarrierSetAssembler::store_at(masm, decorators, type, dst, val, tmp1, tmp2, tmp3);
        
        // 后屏障(Post-barrier):更新引用
        if (ShenandoahStoreValEnqueueBarrier) {
            post_barrier(masm, decorators, dst, val, tmp1, tmp2, tmp3);
        }
    } else {
        // 非引用类型,直接存储
        BarrierSetAssembler::store_at(masm, decorators, type, dst, val, tmp1, tmp2, tmp3);
    }
}

3. SATB 前屏障

void ShenandoahBarrierSetAssembler::pre_barrier(MacroAssembler* masm,
                                                DecoratorSet decorators,
                                                Address dst,
                                                Register val,
                                                Register tmp1,
                                                Register tmp2,
                                                Register tmp3) {
    // 如果值寄存器为空,需要先加载
    if (val == noreg) {
        val = tmp1;
        BarrierSetAssembler::load_at(masm, decorators, T_OBJECT, val, dst, tmp2, tmp3);
    }
    
    // 检查值是否为 NULL
    __ cmpdi(CCR0, val, 0);
    __ beq(CCR0, done);
    
    // 检查 GC 状态
    Register thread = tmp2;
    __ get_thread(thread);
    __ lbz(tmp3, in_bytes(ShenandoahThreadLocalData::gc_state_offset()), thread);
    __ andi_(tmp3, tmp3, ShenandoahHeap::HAS_FORWARDED);
    __ beq(CCR0, done);
    
    // 调用 SATB 标记函数
    __ mr(R3_ARG1, val);
    __ call_VM_leaf(CAST_FROM_FN_PTR(address, ShenandoahRuntime::satb_write_barrier_pre), 
                    R3_ARG1);
    
    __ bind(done);
}

4. 后屏障实现

void ShenandoahBarrierSetAssembler::post_barrier(MacroAssembler* masm,
                                                 DecoratorSet decorators,
                                                 Address dst,
                                                 Register val,
                                                 Register tmp1,
                                                 Register tmp2,
                                                 Register tmp3) {
    // 检查是否需要屏障
    if (val == noreg) {
        return;
    }
    
    // 检查值是否为 NULL
    __ cmpdi(CCR0, val, 0);
    __ beq(CCR0, done);
    
    // 获取线程局部存储
    Register thread = tmp1;
    __ get_thread(thread);
    
    // 检查 GC 状态
    __ lbz(tmp2, in_bytes(ShenandoahThreadLocalData::gc_state_offset()), thread);
    __ andi_(tmp2, tmp2, ShenandoahHeap::HAS_FORWARDED);
    __ beq(CCR0, done);
    
    // 检查是否在集合中
    __ ld(tmp2, in_bytes(ShenandoahThreadLocalData::satb_mark_queue_active_offset()), thread);
    __ cmpdi(CCR0, tmp2, 0);
    __ beq(CCR0, done);
    
    // 将对象加入队列
    __ mr(R3_ARG1, val);
    __ call_VM_leaf(CAST_FROM_FN_PTR(address, ShenandoahRuntime::satb_write_barrier_post), 
                    R3_ARG1);
    
    __ bind(done);
}

5. 屏障优化

void ShenandoahBarrierSetAssembler::load_reference_barrier(MacroAssembler* masm,
                                                           Register dst,
                                                           Address src,
                                                           Register tmp1,
                                                           Register tmp2) {
    // 快速路径:检查是否需要转发
    Label not_forwarded;
    Label done;
    
    // 检查转发指针
    __ ld(tmp1, in_bytes(ShenandoahHeap::_base), R16_THREAD);
    __ ld(tmp2, in_bytes(ShenandoahHeap::_top), R16_THREAD);
    
    // 比较是否在转发范围内
    __ cmpld(CCR0, dst, tmp1);
    __ cmpld(CCR1, dst, tmp2);
    __ blt(CCR0, not_forwarded);
    __ bge(CCR1, not_forwarded);
    
    // 需要转发,调用运行时
    __ mr(R3_ARG1, dst);
    __ call_VM_leaf(CAST_FROM_FN_PTR(address, ShenandoahRuntime::load_reference_barrier), 
                    R3_ARG1);
    __ mr(dst, R3_RET);
    __ b(done);
    
    __ bind(not_forwarded);
    __ bind(done);
}

6. 原子操作屏障

void ShenandoahBarrierSetAssembler::atomic_xchg(MacroAssembler* masm,
                                                BasicType type,
                                                Register new_val,
                                                Address dest,
                                                Register tmp1,
                                                Register tmp2) {
    if (is_reference_type(type)) {
        // 对象引用的原子交换需要屏障
        __ mr(tmp1, new_val);
        
        // 执行原子交换
        BarrierSetAssembler::atomic_xchg(masm, type, new_val, dest, tmp2, noreg);
        
        // 后屏障
        post_barrier(masm, 0, dest, new_val, tmp2, noreg, noreg);
    } else {
        BarrierSetAssembler::atomic_xchg(masm, type, new_val, dest, tmp1, tmp2);
    }
}

PPC 架构特定考虑

1. 寄存器使用

// PPC 调用约定
#define R3_ARG1   R3   // 第一个参数寄存器
#define R3_RET    R3   // 返回值寄存器
#define R16_THREAD R16  // 线程指针寄存器

2. 内存屏障指令

// PPC 内存屏障指令
__ sync();    // 完全内存屏障
__ lwsync();  // 轻量级同步屏障
__ isync();   // 指令同步屏障

3. 条件寄存器使用

// 使用多个条件寄存器避免冲突
__ cmpdi(CCR0, val, 0);    // CCR0 用于 NULL 检查
__ cmpld(CCR1, dst, tmp1);  // CCR1 用于范围检查

性能优化技术

1. 快速路径检查

  • 先检查是否需要屏障,避免不必要的函数调用
  • 使用位测试快速判断 GC 状态
  • NULL 值快速返回

2. 内联汇编优化

  • 将简单屏障完全内联展开
  • 复杂情况才调用运行时函数
  • 最小化寄存器保存恢复开销

3. 分支预测

// 使用静态分支预测
__ bge(CCR0, slow_path);  // 假定大部分情况走快速路径
__ beq(CCR0, done);        // NULL 检查通常为假

与 GC 状态交互

// GC 状态位定义
enum GCState {
    NOT_IN_GC = 0,
    HAS_FORWARDED = 1 << 0,  // 对象已被转发
    MARKING = 1 << 1,         // 标记阶段
    EVACUATION = 1 << 2,      // 疏散阶段
    UPDATEREFS = 1 << 3       // 引用更新阶段
};

总结

shenandoahBarrierSetAssembler_ppc.cpp 实现了 Shenandoah GC 在 PPC 架构上的核心屏障机制:

  1. 读屏障:确保从堆读取的对象引用是最新的
  2. 写屏障:维护 SATB 队列和引用更新
  3. 架构优化:充分利用 PPC 的寄存器资源和内存模型
  4. 性能平衡:快速路径内联,慢速路径调用运行时

这个实现展示了如何将高级 GC 算法与特定 CPU 架构的底层特性结合,在保证正确性的同时达到高性能。

Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐