目录
- 结论
- 字节码解释器的源码分析验证
- 模板解释器的源码分析验证
- Intel lock前缀指令
- 概述
- lock前缀指令能修饰哪些指令
- lock前缀指原子性的理解实现
- 理解单操作原子性
- 实现单操作原子性
- Java volatile是否支持原子性
- 实例属性
- 静态变量
零、结论
hotspot x86平台上的内存屏障的实现依赖于lock指令,而Intel的lock指令的实现依赖于缓存一致性协议(例如MESI)。
本文只介绍hotspot X86平台的内存屏障的实现,没有任何关于其他平台是怎么实现内存屏障的内容。
一、字节码解释器源码分析验证
hotspot字节码解释器在处理putfield/putstatic的时候,如果要处理的结果是volatile修饰的,那么在处理完成之后还需要调用内存屏障指令OrderAccess::storeload();
源码地址:jdk/bytecodeInterpreter.cpp at master · openjdk/jdk · GitHub
CASE(_putfield):
CASE(_putstatic):
{
u2 index = Bytes::get_native_u2(pc+1);
ConstantPoolCacheEntry* cache = cp->entry_at(index);
if (!cache->is_resolved((Bytecodes::Code)opcode)) {
CALL_VM(InterpreterRuntime::resolve_from_cache(THREAD, (Bytecodes::Code)opcode),
handle_exception);
cache = cp->entry_at(index);
}
// 省略一些代码
//
// Now store the result
//
int field_offset = cache->f2_as_index();
if (cache->is_volatile()) {
switch (tos_type) {
......
// 省略很多代码
}
OrderAccess::storeload();
}
// 省略很多代码
这里cache->is_volatile()中的cache并不是指CPU cache,而是ConstantPoolCacheEntry。
以32bit机器为例,如果ConstantPoolCacheEntry表示的是字段,那么ConstantPoolCacheEntry的字段信息如下(参考:类的连接之重写(2) - 鸠摩(马智) - 博客园 (cnblogs.com)):
所以,这只是用来判断putfield/putstatic操作的属性是否有volatile修饰(对应的比特位是否置位,即标志有无volatile修饰该字段)。
这有点题外话,当然我们要关注的是最后调用内存屏障指令的代码OrderAccess::storeload()。
先转到OrderAccess.hpp头文件中看看x86平台内存屏障实现的注释,这段注释值得好好读一读《Memory Access Ordering Model》。
源码地址:jdk/orderAccess.hpp at master · openjdk/jdk · GitHub
x86平台,fence的实现依赖于lock前缀指令。
查看fence()函数,要转到OrderAccess的x86文件中。
源码地址:jdk/orderAccess_linux_x86.hpp at master · openjdk/jdk · GitHub
storeload内存屏障的实现是fence()函数,fence()函数的函数体是AT&T的内联汇编,内联汇编的指令是lock前缀指令。
其他内存屏障的实现依赖于C++的编译器屏障,也是一个AT&T的内联汇编,不过这句内联汇编的指令的含义是A compiler barrier, f