Skip to content

Commit 891214b

Browse files
pkk33V8-internal LUCI CQ
authored andcommitted
Add support for defining and droppining element segments.
Prepare code for using them in initialize and copy bulk instructions. Bug:427115604 Change-Id: I3f5a2b28e8116ead775306fecea55b5d23f82eca Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/8578256 Reviewed-by: Matthias Liedtke <mliedtke@google.com> Commit-Queue: Pawel Krawczyk <pawkra@google.com>
1 parent e5e324b commit 891214b

17 files changed

Lines changed: 503 additions & 10 deletions

Sources/Fuzzilli/Base/ProgramBuilder.swift

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3400,6 +3400,28 @@ public class ProgramBuilder {
34003400
b.emit(WasmDropDataSegment(), withInputs: [dataSegment], types: [.wasmDataSegment()])
34013401
}
34023402

3403+
public func wasmDropElementSegment(elementSegment: Variable) {
3404+
b.emit(WasmDropElementSegment(), withInputs: [elementSegment], types: [.wasmElementSegment()])
3405+
}
3406+
3407+
public func wasmTableInit(elementSegment: Variable, table: Variable, tableOffset: Variable, elementSegmentOffset: Variable, nrOfElementsToUpdate: Variable) {
3408+
// TODO: b/427115604 - assert that table.elemType IS_SUBTYPE_OF elementSegment.elemType (depending on refactor outcome).
3409+
let addrType = b.type(of: table).wasmTableType!.isTable64 ? ILType.wasmi64 : ILType.wasmi32
3410+
b.emit(WasmTableInit(), withInputs: [elementSegment, table, tableOffset, elementSegmentOffset, nrOfElementsToUpdate],
3411+
types: [.wasmElementSegment(), .object(ofGroup: "WasmTable"), addrType, addrType, addrType])
3412+
}
3413+
3414+
public func wasmTableCopy(dstTable: Variable, srcTable: Variable, dstOffset: Variable, srcOffset: Variable, count: Variable) {
3415+
// TODO: b/427115604 - assert that srcTable.elemType IS_SUBTYPE_OF dstTable.elemType (depending on refactor outcome).
3416+
let dstTableType = b.type(of: dstTable).wasmTableType!
3417+
let srcTableType = b.type(of: srcTable).wasmTableType!
3418+
assert(dstTableType.isTable64 == srcTableType.isTable64)
3419+
3420+
let addrType = dstTableType.isTable64 ? ILType.wasmi64 : ILType.wasmi32
3421+
b.emit(WasmTableCopy(), withInputs: [dstTable, srcTable, dstOffset, srcOffset, count],
3422+
types: [.object(ofGroup: "WasmTable"), .object(ofGroup: "WasmTable"), addrType, addrType, addrType])
3423+
}
3424+
34033425
public func wasmReassign(variable: Variable, to: Variable) {
34043426
assert(b.type(of: variable) == b.type(of: to))
34053427
b.emit(WasmReassign(variableType: b.type(of: variable)), withInputs: [variable, to])
@@ -3922,6 +3944,12 @@ public class ProgramBuilder {
39223944
withInputs: definedEntryValues, types: inputTypes).output
39233945
}
39243946

3947+
@discardableResult
3948+
public func addElementSegment(elementsType: ILType, elements: [Variable]) -> Variable {
3949+
let inputTypes = Array(repeating: elementsType, count: elements.count)
3950+
return b.emit(WasmDefineElementSegment(size: UInt32(elements.count)), withInputs: elements, types: inputTypes).output
3951+
}
3952+
39253953
// This result can be ignored right now, as we can only define one memory per module
39263954
// Also this should be tracked like a global / table.
39273955
@discardableResult
@@ -4292,7 +4320,8 @@ public class ProgramBuilder {
42924320
case .wasmDefineGlobal(_),
42934321
.wasmDefineTable(_),
42944322
.wasmDefineMemory(_),
4295-
.wasmDefineDataSegment(_):
4323+
.wasmDefineDataSegment(_),
4324+
.wasmDefineElementSegment(_):
42964325
break
42974326
case .wasmDefineTag(_):
42984327
break

Sources/Fuzzilli/CodeGen/CodeGeneratorWeights.swift

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -235,6 +235,10 @@ public let codeGeneratorWeights = [
235235
"WasmMemoryInitGenerator": 5,
236236
"WasmDefineGlobalGenerator": 2,
237237
"WasmDefineTableGenerator": 2,
238+
// TODO(427115604): update onece both init and copy instructions are implemented.
239+
"WasmDefineElementSegmentGenerator": 1,
240+
// TODO(427115604): update onece both init and copy instructions are implemented.
241+
"WasmDropElementSegmentGenerator": 1,
238242
"WasmTableSizeGenerator": 5,
239243
"WasmTableGrowGenerator": 1,
240244
"WasmGlobalStoreGenerator": 2,

Sources/Fuzzilli/CodeGen/WasmCodeGenerators.swift

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -528,6 +528,20 @@ public let WasmCodeGenerators: [CodeGenerator] = [
528528
module.addTable(elementType: elementType, minSize: minSize, maxSize: maxSize, definedEntries: definedEntries, definedEntryValues: definedEntryValues, isTable64: probability(0.5))
529529
},
530530

531+
CodeGenerator("WasmDefineElementSegmentGenerator", inContext: .wasm) { b in
532+
let elementsType: ILType = .wasmFunctionDef() | .function()
533+
if b.randomVariable(ofType: elementsType) == nil {
534+
return
535+
}
536+
537+
var elements: [Variable] = (0...Int.random(in: 0...8)).map {_ in b.randomVariable(ofType: elementsType)!}
538+
b.currentWasmModule.addElementSegment(elementsType: elementsType, elements: elements)
539+
},
540+
541+
CodeGenerator("WasmDropElementSegmentGenerator", inContext: .wasmFunction, inputs: .required(.wasmElementSegment())) { b, elementSegment in
542+
b.currentWasmFunction.wasmDropElementSegment(elementSegment: elementSegment)
543+
},
544+
531545
CodeGenerator("WasmTableSizeGenerator", inContext: .wasmFunction, inputs: .required(.object(ofGroup: "WasmTable"))) { b, table in
532546
let function = b.currentWasmModule.currentWasmFunction
533547
function.wasmTableSize(table: table)

Sources/Fuzzilli/FuzzIL/Instruction.swift

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1231,6 +1231,16 @@ extension Instruction: ProtobufConvertible {
12311231
}
12321232
$0.isTable64 = op.isTable64
12331233
}
1234+
case .wasmDefineElementSegment(let op):
1235+
$0.wasmDefineElementSegment = Fuzzilli_Protobuf_WasmDefineElementSegment.with {
1236+
$0.size = op.size
1237+
}
1238+
case .wasmDropElementSegment(_):
1239+
$0.wasmDropElementSegment = Fuzzilli_Protobuf_WasmDropElementSegment()
1240+
case .wasmTableCopy(_):
1241+
$0.wasmTableCopy = Fuzzilli_Protobuf_WasmTableCopy()
1242+
case .wasmTableInit(_):
1243+
$0.wasmTableInit = Fuzzilli_Protobuf_WasmTableInit()
12341244
case .wasmDefineMemory(let op):
12351245
assert(op.wasmMemory.isWasmMemoryType)
12361246
let mem = op.wasmMemory.wasmMemoryType!
@@ -2322,6 +2332,14 @@ extension Instruction: ProtobufConvertible {
23222332
WasmTableType.IndexInTableAndWasmSignature(indexInTable: Int(entry.index), signature: WasmSignatureFromProto(entry.signature))
23232333
},
23242334
isTable64: p.isTable64)
2335+
case .wasmDefineElementSegment(let p):
2336+
op = WasmDefineElementSegment(size: p.size)
2337+
case .wasmDropElementSegment(_):
2338+
op = WasmDropElementSegment()
2339+
case .wasmTableInit(_):
2340+
op = WasmTableInit()
2341+
case .wasmTableCopy(_):
2342+
op = WasmTableCopy()
23252343
case .wasmDefineMemory(let p):
23262344
let maxPages = p.wasmMemory.hasMaxPages ? Int(p.wasmMemory.maxPages) : nil
23272345
op = WasmDefineMemory(limits: Limits(min: Int(p.wasmMemory.minPages), max: maxPages), isShared: p.wasmMemory.isShared, isMemory64: p.wasmMemory.isMemory64)

Sources/Fuzzilli/FuzzIL/JSTyper.swift

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -673,6 +673,14 @@ public struct JSTyper: Analyzer {
673673
let jsSignature = ProgramBuilder.convertWasmSignatureToJsSignature(entry.signature)
674674
dynamicObjectGroupManager.addWasmFunction(withSignature: jsSignature, forDefinition: definingInstruction, forVariable: instr.input(idx))
675675
}
676+
case .wasmDefineElementSegment(let op):
677+
setType(of: instr.output, to: .wasmElementSegment(segmentLength: Int(op.size)))
678+
case .wasmDropElementSegment(_):
679+
type(of: instr.input(0)).wasmElementSegmentType!.markAsDropped()
680+
case .wasmTableInit(_),
681+
.wasmTableCopy(_):
682+
// TODO(427115604): - implement both init and copy instructions.
683+
break
676684
case .wasmDefineMemory(let op):
677685
setType(of: instr.output, to: op.wasmMemory)
678686
registerWasmMemoryUse(for: instr.output)

Sources/Fuzzilli/FuzzIL/Opcodes.swift

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -352,4 +352,8 @@ enum Opcode {
352352
case wasmAnyConvertExtern(WasmAnyConvertExtern)
353353
case wasmExternConvertAny(WasmExternConvertAny)
354354
case wasmMemoryCopy(WasmMemoryCopy)
355+
case wasmDefineElementSegment(WasmDefineElementSegment)
356+
case wasmDropElementSegment(WasmDropElementSegment)
357+
case wasmTableInit(WasmTableInit)
358+
case wasmTableCopy(WasmTableCopy)
355359
}

Sources/Fuzzilli/FuzzIL/TypeSystem.swift

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -212,6 +212,12 @@ public struct ILType: Hashable {
212212
return ILType(definiteType: .wasmDataSegment, ext: typeExtension)
213213
}
214214

215+
public static func wasmElementSegment(segmentLength: Int? = nil) -> ILType {
216+
let maybeWasmExtention = segmentLength.map { WasmElementSegmentType(segmentLength: $0) }
217+
let typeExtension = TypeExtension(group: "WasmElementSegment", properties: Set(), methods: Set(), signature: nil, wasmExt: maybeWasmExtention)
218+
return ILType(definiteType: .wasmElementSegment, ext: typeExtension)
219+
}
220+
215221
public static func wasmTable(wasmTableType: WasmTableType) -> ILType {
216222
return .object(ofGroup: "WasmTable", withProperties: ["length"], withMethods: ["get", "grow", "set"], withWasmType: wasmTableType)
217223
}
@@ -518,6 +524,14 @@ public struct ILType: Hashable {
518524
return wasmDataSegmentType != nil
519525
}
520526

527+
public var wasmElementSegmentType: WasmElementSegmentType? {
528+
return ext?.wasmExt as? WasmElementSegmentType
529+
}
530+
531+
public var isWasmElementSegmentType: Bool {
532+
return wasmElementSegmentType != nil
533+
}
534+
521535

522536
public var wasmTableType: WasmTableType? {
523537
return ext?.wasmExt as? WasmTableType
@@ -1082,6 +1096,8 @@ extension ILType: CustomStringConvertible {
10821096
return ".exceptionLabel"
10831097
case .wasmDataSegment:
10841098
return ".wasmDataSegment"
1099+
case .wasmElementSegment:
1100+
return ".wasmElementSegment"
10851101
default:
10861102
break
10871103
}
@@ -1157,6 +1173,7 @@ struct BaseType: OptionSet, Hashable {
11571173
static let wasmPackedI16 = BaseType(rawValue: 1 << 23)
11581174

11591175
static let wasmDataSegment = BaseType(rawValue: 1 << 24)
1176+
static let wasmElementSegment = BaseType(rawValue: 1 << 25)
11601177

11611178
static let jsAnything = BaseType([.undefined, .integer, .float, .string, .boolean, .object, .function, .constructor, .unboundFunction, .bigint, .regexp, .iterable])
11621179

@@ -1659,6 +1676,30 @@ public class WasmDataSegmentType: WasmTypeExtension {
16591676
}
16601677
}
16611678

1679+
public class WasmElementSegmentType: WasmTypeExtension {
1680+
let segmentLength: Int
1681+
private(set) var isDropped: Bool
1682+
1683+
override func isEqual(to other: WasmTypeExtension) -> Bool {
1684+
guard let other = other as? WasmElementSegmentType else { return false }
1685+
return self.segmentLength == other.segmentLength && self.isDropped == other.isDropped
1686+
}
1687+
1688+
override public func hash(into hasher: inout Hasher) {
1689+
hasher.combine(segmentLength)
1690+
hasher.combine(isDropped)
1691+
}
1692+
1693+
init(segmentLength: Int) {
1694+
self.segmentLength = segmentLength
1695+
self.isDropped = false
1696+
}
1697+
1698+
public func markAsDropped() {
1699+
self.isDropped = true
1700+
}
1701+
}
1702+
16621703
public class WasmTableType: WasmTypeExtension {
16631704
public struct IndexInTableAndWasmSignature: Hashable {
16641705
let indexInTable: Int

Sources/Fuzzilli/FuzzIL/WasmOperations.swift

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -810,6 +810,44 @@ final class WasmDefineTable: WasmOperation {
810810
}
811811
}
812812

813+
final class WasmDefineElementSegment: WasmOperation {
814+
override var opcode: Opcode { .wasmDefineElementSegment(self) }
815+
816+
public let size: UInt32
817+
818+
init(size: UInt32) {
819+
self.size = size
820+
super.init(numInputs: Int(size), numOutputs: 1, requiredContext: [.wasm])
821+
}
822+
}
823+
824+
class WasmDropElementSegment: WasmOperation {
825+
override var opcode: Opcode { .wasmDropElementSegment(self) }
826+
827+
init() {
828+
super.init(
829+
numInputs: 1, numOutputs: 0, requiredContext: [.wasmFunction])
830+
}
831+
}
832+
833+
class WasmTableInit: WasmOperation {
834+
override var opcode: Opcode { .wasmTableInit(self) }
835+
836+
init() {
837+
super.init(
838+
numInputs: 5, numOutputs: 0, requiredContext: [.wasmFunction])
839+
}
840+
}
841+
842+
class WasmTableCopy: WasmOperation {
843+
override var opcode: Opcode { .wasmTableCopy(self) }
844+
845+
init() {
846+
super.init(
847+
numInputs: 5, numOutputs: 0, requiredContext: [.wasmFunction])
848+
}
849+
}
850+
813851
// TODO: Wasm memory can be initialized in the data segment, theoretically one could initialize them with this instruction as well.
814852
// Currently they are by default zero initialized and fuzzilli should then just store or load from there.
815853
// Also note: https://webassembly.github.io/spec/core/syntax/modules.html#memories
@@ -2355,4 +2393,3 @@ final class WasmAtomicCmpxchg: WasmOperation {
23552393
super.init(numInputs: 4, numOutputs: 1, attributes: [.isMutable], requiredContext: [.wasmFunction])
23562394
}
23572395
}
2358-

Sources/Fuzzilli/Lifting/FuzzILLifter.swift

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -822,6 +822,18 @@ public class FuzzILLifter: Lifter {
822822
let isTable64Str = op.isTable64 ? ", table64" : ""
823823
w.emit("\(output()) <- WasmDefineTable \(op.elementType)\(isTable64Str), (\(op.limits.min), \(String(describing: op.limits.max))), [\(entries)]")
824824

825+
case .wasmDefineElementSegment(_):
826+
w.emit("\(output()) <- WasmDefineElementSegment [...]")
827+
828+
case .wasmDropElementSegment:
829+
w.emit("WasmDropElementSegment \(input(0))")
830+
831+
case .wasmTableInit:
832+
w.emit("WasmTableInit \(input(0)), \(input(1)), \(input(2)), \(input(3)), \(input(4))")
833+
834+
case .wasmTableCopy:
835+
w.emit("WasmTableCopy \(input(0)), \(input(1)), \(input(2)), \(input(3)), \(input(4))")
836+
825837
case .wasmDefineMemory(let op):
826838
assert(op.wasmMemory.isWasmMemoryType)
827839
let mem = op.wasmMemory.wasmMemoryType!

Sources/Fuzzilli/Lifting/JavaScriptLifter.swift

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1624,6 +1624,10 @@ public class JavaScriptLifter: Lifter {
16241624
.wasmReassign(_),
16251625
.wasmDefineGlobal(_),
16261626
.wasmDefineTable(_),
1627+
.wasmDefineElementSegment(_),
1628+
.wasmDropElementSegment(_),
1629+
.wasmTableInit(_),
1630+
.wasmTableCopy(_),
16271631
.wasmDefineMemory(_),
16281632
.wasmDefineDataSegment(_),
16291633
.wasmLoadGlobal(_),

0 commit comments

Comments
 (0)