?
u
m
/
p
1-9
0
`
内存一致性模型(或称 内存模型)规定了
内存模型以关系约束形式定义,这些约束作用于在求值过程中由对 SharedArrayBuffer 的
共享内存访问(读与写)分为两类:原子访问和数据访问(下文定义)。原子访问是顺序一致的,即存在一个所有代理都同意的
不支持比顺序一致更弱、比无序更强的次序(如 release-acquire)。
共享数据块事件 是 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]] | 一个读-改-写修改函数 | 从读取的 |
这些事件由
某些操作还可能引入 Synchronize 事件。一个 Synchronize 事件 没有字段,仅用于直接约束其他事件的允许顺序。
除共享数据块事件与 Synchronize 事件外,还存在
令 ReadSharedMemory、WriteSharedMemory 或 ReadModifyWriteSharedMemory 事件的范围为从其 [[ByteIndex]] 到 [[ByteIndex]] + [[ElementSize]] - 1 的连续整数集合。两个事件的范围相等当且仅当它们具有相同 [[Block]] 且范围逐元素相等。若两个事件有相同 [[Block]]、范围不等且交集非空则范围重叠。若两个事件没有相同 [[Block]] 或其范围既不相等也不重叠则范围不相交。
应考虑的postMessage
),代理的启动与停止,以及通过共享内存之外的通道在代理集群内通信。对于某次执行 execution,这些事件由
候选执行中的事件由下列定义的关系排序。
Agent Events Record 是具有以下字段的
字段名 | 取值 | 含义 |
---|---|---|
[[AgentSignifier]] | 一个代理标识符 | 其求值导致此排序的代理。 |
[[EventList]] | 一个事件的 |
求值过程中事件被追加到该列表。 |
[[AgentSynchronizesWith]] | 一对 |
由操作语义引入的同步关系。 |
Chosen Value Record 是具有以下字段的
字段名 | 取值 | 含义 |
---|---|---|
[[Event]] | 一个 |
为该选定值引入的 |
[[ChosenValue]] | 一个 |
求值过程中非确定性选出的字节。 |
代理集群求值的一个 candidate execution 是具有以下字段的
字段名 | 取值 | 含义 |
---|---|---|
[[EventsRecords]] | 映射一个代理到求值过程中追加的事件列表。 | |
[[ChosenValues]] | 将 |
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
以下关系与数学函数以特定候选执行为参数,对其事件排序。
对候选执行 execution,其 is-agent-order-before 关系是满足以下条件的事件上的最小关系。
对候选执行 execution,其 reads-bytes-from 函数是一个数学函数,将
对
一个候选执行总能容纳一个 reads-bytes-from 函数。
对候选执行 execution,其 reads-from 关系是满足以下条件的事件上的最小关系。
对候选执行 execution,其 host-synchronizes-with 关系是
对候选执行 execution 中两个
该关系允许postMessage
。
对候选执行 execution,其 synchronizes-with 关系是满足以下条件的事件上的最小关系:
按
并非所有通过
若
对候选执行 execution,其 happens-before 关系是满足以下条件的事件上的最小关系。
对事件 E 与 D,若以下任一成立则 E happens-before D:
因 happens-before 是 agent-order 的超集,候选执行与 ECMAScript 的单线程求值语义一致。
候选执行 execution 具有有效选定读取当且仅当以下算法返回
候选执行 execution 具有相干读取当且仅当以下算法返回
候选执行 execution 具有无撕裂读取当且仅当以下算法返回
事件的 [[NoTear]] 字段为
直观地,该要求表示当内存范围以整数
对候选执行 execution,is-memory-order-before 是
对 R 与 W(满足 R
此条款额外约束范围相等的
对
该条款与代理的前向进展保证一起确保:
若候选执行存在一个 is-memory-order-before 关系,则其具有顺序一致原子。
虽然 is-memory-order-before 包含
候选执行 execution 是合法执行(或简称执行)当且仅当以下各项均为真:
所有程序至少有一个合法执行。
对执行 execution 及其中
对执行 execution 及其中
执行 execution 是 data race free 当且仅当
若程序所有执行均数据竞争自由,则该程序为数据竞争自由程序。
以下是面向使用共享内存的 ECMAScript 程序员的指南。
推荐保持程序数据竞争自由,即使同一内存位置不可能同时发生并发非原子操作。数据竞争自由程序具有交错语义:每个代理的每一步求值语义互相交错。此时无需理解
更一般地,即便程序非数据竞争自由,也可能具可预测行为,只要原子操作不参与任何数据竞争,且竞争操作的访问大小一致。最简单方式是保证原子与非原子操作使用不同内存单元,且不同大小的原子访问不同时访问相同单元。实质上,程序应尽量将共享内存视为强类型。仍不可依赖竞争的非原子访问的顺序与时序,但若内存被强类型对待,竞争访问不会“撕裂”(其值的位不会混合)。
以下是面向为使用共享内存程序编写编译器变换的 ECMAScript 实现者的指南。
希望在多代理环境中允许大多数在单代理环境有效的程序变换,以确保多代理程序中每个代理的性能与单代理时一样。此类变换往往难以判定。我们概述若干应视为规范性的规则(由
令 agent-order slice 为
令读取事件的 possible read values 为该事件在所有合法执行中
在无共享内存时有效的任意 agent-order slice 变换在存在共享内存时亦有效,以下例外:
原子操作不可动摇:程序变换不得使 agent-order slice 中的
(实践中,该限制迫使编译器假设每个
读取必须稳定:任一共享内存读取在一次执行中只能观察到单一值。
(例如,若语义上单次读取被多次执行,则程序只能观察其中一个值;某些再物化变换可违反此规则。)
写入必须稳定:所有可观察写入必须源于该次执行的程序语义。
(例如,变换不能引入程序本不可能的写,如对更大位置的读改写来写较小数据,写入程序原本不可写的值,或将刚读取的值写回其位置且期间可能被他代理
可能读取值不得为空:程序变换不能使某共享内存读取的可能读取值集合为空。
(反直觉地,该规则实际限制对写的变换,因为写的作用仅在被读事件读取。例如写可移动、合并,有时在两个
仍然有效的变换示例:合并多个对同一位置的非原子读;重排非原子读;引入推测非原子读;合并多个对同一位置的非原子写;对不同位置的非原子写重排;将非原子读外提出循环(即使影响终止性)。注意别名
以下是面向为共享内存访问生成机器码的 ECMAScript 实现者的指南。
对LOCK
前缀指令,ARM 的 load-exclusive/store-exclusive,Power 的 load-link/store-conditional。
具体而言,
朴素代码生成模式:
该映射在原子操作与非原子写或不同大小原子不竞争下正确;若竞争,
局部优化在模型约束下也是允许的,例如: