?um/p1-90`内存一致性模型,或称内存模型,指定
内存模型被定义为对在求值期间由 SharedArrayBuffer 上的
共享内存访问(读和写)分为两组:原子访问和数据访问,定义如下。原子访问是顺序一致的,即,在一个
不支持弱于顺序一致且强于无序的排序,例如 release-acquire。
Shared Data Block event 是 ReadSharedMemory、WriteSharedMemory 或 ReadModifyWriteSharedMemory
| 字段名 | 值 | 含义 |
|---|---|---|
| [[Order]] | ||
| [[NoTear]] | Boolean | 此事件是否允许从与此事件 |
| [[Block]] | 该事件操作的块。 | |
| [[ByteIndex]] | 非负整数 | [[Block]] 中该读的字节地址。 |
| [[ElementSize]] | 非负整数 | 该读的大小。 |
| 字段名 | 值 | 含义 |
|---|---|---|
| [[Order]] | ||
| [[NoTear]] | Boolean | 此事件是否允许被与此事件 |
| [[Block]] | 该事件操作的块。 | |
| [[ByteIndex]] | 非负整数 | [[Block]] 中该写的字节地址。 |
| [[ElementSize]] | 非负整数 | 该写的大小。 |
| [[Payload]] | 将被其他事件读取的 |
| 字段名 | 值 | 含义 |
|---|---|---|
| [[Order]] | 读-改-写事件总是顺序一致的。 | |
| [[NoTear]] | 读-改-写事件不能撕裂。 | |
| [[Block]] | 该事件操作的块。 | |
| [[ByteIndex]] | 非负整数 | [[Block]] 中该读-改-写的字节地址。 |
| [[ElementSize]] | 非负整数 | 该读-改-写的大小。 |
| [[Payload]] | 要传给 [[ModifyOp]] 的 |
|
| [[ModifyOp]] | 一个 |
共享数据块事件由
令共享数据块事件 e 的内存范围为从 e.[[ByteIndex]](
应予以考虑的postMessage)、启动和停止代理,以及通过共享内存以外的通道在代理集群内进行通信。对于某个特定执行 execution,这些事件由
在候选执行内,事件按下面定义的关系排序。
Agent Events Record 是具有以下字段的
| 字段名 | 值 | 含义 |
|---|---|---|
| [[AgentSignifier]] | 其求值产生了此排序的 |
|
| [[EventList]] | Memory event 的 |
在求值期间,事件被追加到该 |
| [[AgentSynchronizesWith]] | 由操作语义引入的 |
Chosen Value Record 是具有以下字段的
| 字段名 | 值 | 含义 |
|---|---|---|
| [[Event]] | 为此 chosen value 引入的 |
|
| [[ChosenValue]] | 在求值期间非确定性选择的字节。 |
| 字段名 | 值 | 含义 |
|---|---|---|
| [[EventsRecords]] | 将 |
|
| [[ChosenValues]] | 将 |
空 candidate execution 是其字段为空
The abstract operation EventSet takes argument execution (a
The abstract operation SharedDataBlockEventSet takes argument execution (a
The abstract operation HostEventSet takes argument execution (a
The abstract operation ComposeWriteEventBytes takes arguments execution (a
读-改-写修改 [[ModifyOp]] 由 Atomics 对象上引入
此
The abstract operation ValueOfReadEvent takes arguments execution (a
以下关系和数学函数以特定
对于
对于
对于
对于
对于
对于
此关系允许postMessage。
对于
由于
在
在
对于
对于
对于事件 eventA 和 eventB,如果以下任一条件为真,则 eventA 在 execution 中 happens-before eventB。
因为 happens-before 是
如果以下算法返回
如果以下算法返回
如果以下算法返回
当
直观地说,此要求表示,当通过整数
对于
对于满足 readEvent 在 execution 中
此条款额外约束相等
对于
如果
虽然 is-memory-order-before
如果以下全部为真,则
所有程序至少有一个有效执行。
对于 execution execution,以及
对于 execution execution,以及
如果 execution execution 中不存在两个在
如果程序的所有执行都是数据竞争自由的,则该程序是数据竞争自由的。
以下是针对使用共享内存的 ECMAScript 程序员的指南。
我们建议保持程序
更一般地,即使程序不是
以下是针对为使用共享内存的程序编写编译器转换的 ECMAScript 实现者的指南。
最好允许大多数在单
令 agent-order slice 为与单个
令
在没有共享内存的情况下对 agent-order slice 有效的任何转换,在存在共享内存的情况下也是有效的,但有以下例外。
原子操作刻在石头上:程序转换不得导致任何 [[Order]] 为
(实践中,对重排序的禁止会迫使编译器假定每个
读必须稳定:任何给定的共享内存读在一次执行中只能观察到单个值。
(例如,如果程序中语义上单个读被执行多次,则随后允许程序只观察到所读取值中的一个。称为 rematerialization 的转换可能违反此规则。)
写必须稳定:所有对共享内存的可观察写都必须源自一次执行中的程序语义。
(例如,转换不得引入某些可观察写,例如通过在较大位置上使用读-改-写操作来写入较小数据、向内存写入程序不可能写入的值,或将刚读取的值写回其读取位置,而该位置在读取之后可能已被另一个
可能读取值必须非空:程序转换不能导致共享内存读的可能读取值变为空。
(反直觉地,此规则实际上限制了对写的转换,因为写在
仍然有效的转换示例包括:合并来自同一位置的多个非原子读、重排序非原子读、引入推测性非原子读、合并对同一位置的多个非原子写、重排序对不同位置的非原子写,以及即使影响终止也将非原子读提升出循环。通常要注意,别名化的
以下是针对为共享内存访问生成机器代码的 ECMAScript 实现者的指南。
对于LOCK 前缀的指令、ARM 上的 load-exclusive/store-exclusive 指令,以及 Power 上的 load-link/store-conditional 指令。
具体而言,
朴素代码生成使用以下模式:
只要某个
在遵守
LOCK 前缀的指令。在许多平台上存在几种强度的栅栏,并且可以在某些上下文中使用较弱栅栏而不破坏顺序一致性。