Skip to content

Commit d722ef1

Browse files
Dominik KlembaV8-internal LUCI CQ
authored andcommitted
[wasm] Add support for atomic RMW operations
This introduces the WasmAtomicRMW operation to support various atomic Read-Modify-Write (RMW) operation instructions. The supported operations now include atomic: - Add - Sub - And - Or - Xor - Exchange These are available in various 8, 16, 32, and 64-bit versions. Bug: 427134598 Change-Id: I5fb2f2e1e77b27a782a46c84c67254cf80a23a4b Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/8462196 Reviewed-by: Matthias Liedtke <[email protected]> Commit-Queue: Dominik Klemba <[email protected]>
1 parent 675eccd commit d722ef1

16 files changed

+1057
-444
lines changed

Sources/Fuzzilli/Base/ProgramBuilder.swift

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3314,6 +3314,14 @@ public class ProgramBuilder {
33143314
b.emit(op, withInputs: [memory, address, value])
33153315
}
33163316

3317+
@discardableResult
3318+
func wasmAtomicRMW(memory: Variable, lhs: Variable, rhs: Variable, op: WasmAtomicRMWType, offset: Int64) -> Variable {
3319+
let op = WasmAtomicRMW(op: op, offset: offset)
3320+
let anyInt: ILType = .wasmi32 | .wasmi64
3321+
let valueType = op.op.type
3322+
return b.emit(op, withInputs: [memory, lhs, rhs], types: [.object(ofGroup: "WasmMemory"), anyInt, valueType]).output
3323+
}
3324+
33173325
@discardableResult
33183326
public func wasmMemorySize(memory: Variable) -> Variable {
33193327
return b.emit(WasmMemorySize(), withInputs: [memory],

Sources/Fuzzilli/CodeGen/CodeGeneratorWeights.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -220,6 +220,7 @@ public let codeGeneratorWeights = [
220220
"WasmMemoryStoreGenerator": 10,
221221
"WasmAtomicLoadGenerator": 10,
222222
"WasmAtomicStoreGenerator": 10,
223+
"WasmAtomicRMWGenerator": 10,
223224
"WasmMemorySizeGenerator": 5,
224225
"WasmMemoryGrowGenerator": 1,
225226
"WasmMemoryFillGenerator": 5,

Sources/Fuzzilli/CodeGen/WasmCodeGenerators.swift

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -371,6 +371,19 @@ public let WasmCodeGenerators: [CodeGenerator] = [
371371
function.wasmAtomicStore(memory: memory, address: address, value: value, storeType: storeType, offset: staticOffset)
372372
},
373373

374+
CodeGenerator("WasmAtomicRMWGenerator", inContext: .wasmFunction, inputs: .required(.object(ofGroup: "WasmMemory"))) { b, memory in
375+
let function = b.currentWasmModule.currentWasmFunction
376+
let op = chooseUniform(from: WasmAtomicRMWType.allCases)
377+
let valueType = op.type
378+
let alignment = op.naturalAlignment()
379+
380+
let rhs = function.findOrGenerateWasmVar(ofType: valueType)
381+
382+
let (lhs, staticOffset) = b.generateAlignedMemoryIndexes(forMemory: memory, alignment: alignment)
383+
384+
function.wasmAtomicRMW(memory: memory, lhs: lhs, rhs: rhs, op: op, offset: staticOffset)
385+
},
386+
374387
CodeGenerator("WasmMemorySizeGenerator", inContext: .wasmFunction, inputs: .required(.object(ofGroup: "WasmMemory"))) { b, memory in
375388
let function = b.currentWasmModule.currentWasmFunction
376389
function.wasmMemorySize(memory: memory)

Sources/Fuzzilli/FuzzIL/Instruction.swift

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1305,6 +1305,11 @@ extension Instruction: ProtobufConvertible {
13051305
$0.storeType = convertEnum(op.storeType, WasmAtomicStoreType.allCases)
13061306
$0.offset = op.offset
13071307
}
1308+
case .wasmAtomicRMW(let op):
1309+
$0.wasmAtomicRmw = Fuzzilli_Protobuf_WasmAtomicRMW.with {
1310+
$0.op = convertEnum(op.op, WasmAtomicRMWType.allCases)
1311+
$0.offset = op.offset
1312+
}
13081313
case .wasmMemorySize(_):
13091314
$0.wasmMemorySize = Fuzzilli_Protobuf_WasmMemorySize()
13101315
case .wasmMemoryGrow(_):
@@ -2499,6 +2504,8 @@ extension Instruction: ProtobufConvertible {
24992504
op = WasmAtomicLoad(loadType: try convertEnum(p.loadType, WasmAtomicLoadType.allCases), offset: p.offset)
25002505
case .wasmAtomicStore(let p):
25012506
op = WasmAtomicStore(storeType: try convertEnum(p.storeType, WasmAtomicStoreType.allCases), offset: p.offset)
2507+
case .wasmAtomicRmw(let p):
2508+
op = WasmAtomicRMW(op: try convertEnum(p.op, WasmAtomicRMWType.allCases), offset: p.offset)
25022509
case .wasmAnyConvertExtern(_):
25032510
op = WasmAnyConvertExtern()
25042511
case .wasmExternConvertAny(_):

Sources/Fuzzilli/FuzzIL/JSTyper.swift

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -694,6 +694,10 @@ public struct JSTyper: Analyzer {
694694
case .wasmAtomicStore(_):
695695
let definingInstruction = defUseAnalyzer.definition(of: instr.input(0))
696696
dynamicObjectGroupManager.addWasmMemory(withType: type(of: instr.input(0)), forDefinition: definingInstruction, forVariable: instr.input(0))
697+
case .wasmAtomicRMW(let op):
698+
let definingInstruction = defUseAnalyzer.definition(of: instr.input(0))
699+
dynamicObjectGroupManager.addWasmMemory(withType: type(of: instr.input(0)), forDefinition: definingInstruction, forVariable: instr.input(0))
700+
setType(of: instr.output, to: op.op.type)
697701
case .wasmMemorySize(_),
698702
.wasmMemoryGrow(_):
699703
let isMemory64 = type(of: instr.input(0)).wasmMemoryType?.isMemory64 ?? false

Sources/Fuzzilli/FuzzIL/Opcodes.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -285,6 +285,7 @@ enum Opcode {
285285
case wasmMemoryStore(WasmMemoryStore)
286286
case wasmAtomicLoad(WasmAtomicLoad)
287287
case wasmAtomicStore(WasmAtomicStore)
288+
case wasmAtomicRMW(WasmAtomicRMW)
288289
case wasmMemorySize(WasmMemorySize)
289290
case wasmMemoryGrow(WasmMemoryGrow)
290291
case wasmMemoryFill(WasmMemoryFill)

Sources/Fuzzilli/FuzzIL/WasmOperations.swift

Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -254,6 +254,105 @@ final class Wasmi64BinOp: WasmOperation {
254254
}
255255
}
256256

257+
public enum WasmAtomicRMWType: UInt8, CaseIterable {
258+
case i32Add = 0x1e
259+
case i64Add = 0x1f
260+
case i32Add8U = 0x20
261+
case i32Add16U = 0x21
262+
case i64Add8U = 0x22
263+
case i64Add16U = 0x23
264+
case i64Add32U = 0x24
265+
266+
case i32Sub = 0x25
267+
case i64Sub = 0x26
268+
case i32Sub8U = 0x27
269+
case i32Sub16U = 0x28
270+
case i64Sub8U = 0x29
271+
case i64Sub16U = 0x2a
272+
case i64Sub32U = 0x2b
273+
274+
case i32And = 0x2c
275+
case i64And = 0x2d
276+
case i32And8U = 0x2e
277+
case i32And16U = 0x2f
278+
case i64And8U = 0x30
279+
case i64And16U = 0x31
280+
case i64And32U = 0x32
281+
282+
case i32Or = 0x33
283+
case i64Or = 0x34
284+
case i32Or8U = 0x35
285+
case i32Or16U = 0x36
286+
case i64Or8U = 0x37
287+
case i64Or16U = 0x38
288+
case i64Or32U = 0x39
289+
290+
case i32Xor = 0x3a
291+
case i64Xor = 0x3b
292+
case i32Xor8U = 0x3c
293+
case i32Xor16U = 0x3d
294+
case i64Xor8U = 0x3e
295+
case i64Xor16U = 0x3f
296+
case i64Xor32U = 0x40
297+
298+
case i32Xchg = 0x41
299+
case i64Xchg = 0x42
300+
case i32Xchg8U = 0x43
301+
case i32Xchg16U = 0x44
302+
case i64Xchg8U = 0x45
303+
case i64Xchg16U = 0x46
304+
case i64Xchg32U = 0x47
305+
306+
var type: ILType {
307+
switch self {
308+
case .i32Add, .i32Add8U, .i32Add16U,
309+
.i32Sub, .i32Sub8U, .i32Sub16U,
310+
.i32And, .i32And8U, .i32And16U,
311+
.i32Or, .i32Or8U, .i32Or16U,
312+
.i32Xor, .i32Xor8U, .i32Xor16U,
313+
.i32Xchg, .i32Xchg8U, .i32Xchg16U:
314+
return .wasmi32
315+
case .i64Add, .i64Add8U, .i64Add16U, .i64Add32U,
316+
.i64Sub, .i64Sub8U, .i64Sub16U, .i64Sub32U,
317+
.i64And, .i64And8U, .i64And16U, .i64And32U,
318+
.i64Or, .i64Or8U, .i64Or16U, .i64Or32U,
319+
.i64Xor, .i64Xor8U, .i64Xor16U, .i64Xor32U,
320+
.i64Xchg, .i64Xchg8U, .i64Xchg16U, .i64Xchg32U:
321+
return .wasmi64
322+
}
323+
}
324+
325+
func naturalAlignment() -> Int64 {
326+
switch self {
327+
case .i32Add8U, .i64Add8U,
328+
.i32Sub8U, .i64Sub8U,
329+
.i32And8U, .i64And8U,
330+
.i32Or8U, .i64Or8U,
331+
.i32Xor8U, .i64Xor8U,
332+
.i32Xchg8U, .i64Xchg8U:
333+
return 1
334+
case .i32Add16U, .i64Add16U,
335+
.i32Sub16U, .i64Sub16U,
336+
.i32And16U, .i64And16U,
337+
.i32Or16U, .i64Or16U,
338+
.i32Xor16U, .i64Xor16U,
339+
.i32Xchg16U, .i64Xchg16U:
340+
return 2
341+
case .i32Add, .i64Add32U,
342+
.i32Sub, .i64Sub32U,
343+
.i32And, .i64And32U,
344+
.i32Or, .i64Or32U,
345+
.i32Xor, .i64Xor32U,
346+
.i32Xchg, .i64Xchg32U:
347+
return 4
348+
case .i64Add, .i64Sub,
349+
.i64And, .i64Or,
350+
.i64Xor, .i64Xchg:
351+
return 8
352+
}
353+
}
354+
}
355+
257356
final class Wasmi32UnOp: WasmOperation {
258357
override var opcode: Opcode { .wasmi32UnOp(self) }
259358
let unOpKind: WasmIntegerUnaryOpKind
@@ -2144,3 +2243,16 @@ final class WasmAtomicStore: WasmOperation {
21442243
super.init(numInputs: 3, numOutputs: 0, attributes: [.isMutable], requiredContext: [.wasmFunction])
21452244
}
21462245
}
2246+
2247+
final class WasmAtomicRMW: WasmOperation {
2248+
override var opcode: Opcode { .wasmAtomicRMW(self) }
2249+
2250+
let op: WasmAtomicRMWType
2251+
let offset: Int64
2252+
2253+
init(op: WasmAtomicRMWType, offset: Int64) {
2254+
self.op = op
2255+
self.offset = offset
2256+
super.init(numInputs: 3, numOutputs: 1, attributes: [.isMutable], requiredContext: [.wasmFunction])
2257+
}
2258+
}

Sources/Fuzzilli/Lifting/FuzzILLifter.swift

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -853,6 +853,9 @@ public class FuzzILLifter: Lifter {
853853
case .wasmAtomicStore(let op):
854854
w.emit("WasmAtomicStore \(input(0))[\(input(1)) + \(op.offset)] <- \(input(2)) [\(op.storeType)]")
855855

856+
case .wasmAtomicRMW(let op):
857+
w.emit("\(output()) <- WasmAtomicRMW \(input(0))[\(input(1)) + \(op.offset)] \(op.op) \(input(2))")
858+
856859
case .wasmMemorySize(_):
857860
w.emit("\(output()) <- WasmMemorySize \(input(0))")
858861

Sources/Fuzzilli/Lifting/JavaScriptLifter.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1637,6 +1637,7 @@ public class JavaScriptLifter: Lifter {
16371637
.wasmMemoryStore(_),
16381638
.wasmAtomicLoad(_),
16391639
.wasmAtomicStore(_),
1640+
.wasmAtomicRMW(_),
16401641
.wasmMemorySize(_),
16411642
.wasmMemoryGrow(_),
16421643
.wasmMemoryFill(_),

Sources/Fuzzilli/Lifting/WasmLifter.swift

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1754,6 +1754,10 @@ public class WasmLifter {
17541754
let opcode = [Prefix.Atomic.rawValue, op.storeType.rawValue]
17551755
let alignAndMemory = try alignmentAndMemoryBytes(wasmInstruction.input(0), alignment: op.storeType.naturalAlignment())
17561756
return Data(opcode) + alignAndMemory + Leb128.signedEncode(Int(op.offset))
1757+
case .wasmAtomicRMW(let op):
1758+
let opcode = [Prefix.Atomic.rawValue, op.op.rawValue]
1759+
let alignAndMemory = try alignmentAndMemoryBytes(wasmInstruction.input(0), alignment: op.op.naturalAlignment())
1760+
return Data(opcode) + alignAndMemory + Leb128.signedEncode(Int(op.offset))
17571761
case .wasmMemorySize(_):
17581762
let memoryIdx = try resolveIdx(ofType: .memory, for: wasmInstruction.input(0))
17591763
return Data([0x3F]) + Leb128.unsignedEncode(memoryIdx)

0 commit comments

Comments
 (0)