Skip to content

Commit bd7e685

Browse files
LiedtkeV8-internal LUCI CQ
authored andcommitted
[wasm] Add all missing wasm-gc MVP abstract heap types
This change adds all the missing heap types defined by the wasm-gc MVP spec (and the exception-handling spec) but excludes newer specs like core stack switching ("wasm fx") or shared-everything-threads. Bug: 430198271 Change-Id: I964a5deca6537ce6eab915d31b948e17809068d9 Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/8440756 Commit-Queue: Matthias Liedtke <[email protected]> Reviewed-by: Carl Smith <[email protected]>
1 parent b68ac90 commit bd7e685

File tree

8 files changed

+193
-24
lines changed

8 files changed

+193
-24
lines changed

Sources/Fuzzilli/Base/ProgramBuilder.swift

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3738,6 +3738,8 @@ public class ProgramBuilder {
37383738

37393739
@discardableResult
37403740
public func wasmRefNull(type: ILType) -> Variable {
3741+
assert(type.isWasmReferenceType)
3742+
assert(type.wasmReferenceType!.isAbstract(), "index types must use .wasmRefNull(Variable)")
37413743
return b.emit(WasmRefNull(type: type)).output
37423744
}
37433745

@@ -3910,12 +3912,12 @@ public class ProgramBuilder {
39103912

39113913
public func randomWasmBlockOutputTypes(upTo n: Int) -> [ILType] {
39123914
// TODO(mliedtke): This should allow more types as well as non-nullable references for all
3913-
// // abstract heap types. To be able to emit them, generateRandomWasmVar() needs to be able
3915+
// abstract heap types. To be able to emit them, generateRandomWasmVar() needs to be able
39143916
// to generate a sequence that produces such a non-nullable value which might be difficult
39153917
// for some types as of now.
39163918
(0..<Int.random(in: 0...n)).map {_ in chooseUniform(from:
3917-
[.wasmi32, .wasmi64, .wasmf32, .wasmf64, .wasmExternRef, .wasmFuncRef, .wasmExnRef,
3918-
.wasmI31Ref, .wasmRefI31, .wasmSimd128])}
3919+
[.wasmi32, .wasmi64, .wasmf32, .wasmf64, .wasmSimd128, .wasmRefI31]
3920+
+ WasmAbstractHeapType.allCases.map {.wasmRef(.Abstract($0), nullability: true)})}
39193921
}
39203922

39213923
public func randomWasmBlockArguments(upTo n: Int) -> [Variable] {

Sources/Fuzzilli/FuzzIL/Instruction.swift

Lines changed: 40 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -398,6 +398,23 @@ extension Instruction: ProtobufConvertible {
398398
Fuzzilli_Protobuf_WasmReferenceTypeKind.funcref
399399
case .WasmExtern:
400400
Fuzzilli_Protobuf_WasmReferenceTypeKind.externref
401+
case .WasmAny:
402+
Fuzzilli_Protobuf_WasmReferenceTypeKind.anyref
403+
case .WasmEq:
404+
Fuzzilli_Protobuf_WasmReferenceTypeKind.eqref
405+
case .WasmStruct:
406+
Fuzzilli_Protobuf_WasmReferenceTypeKind.structref
407+
case .WasmArray:
408+
Fuzzilli_Protobuf_WasmReferenceTypeKind.arrayref
409+
case .WasmNone:
410+
Fuzzilli_Protobuf_WasmReferenceTypeKind.noneref
411+
case .WasmNoExtern:
412+
Fuzzilli_Protobuf_WasmReferenceTypeKind.noexternref
413+
case .WasmNoFunc:
414+
Fuzzilli_Protobuf_WasmReferenceTypeKind.nofuncref
415+
case .WasmNoExn:
416+
Fuzzilli_Protobuf_WasmReferenceTypeKind.noexnref
417+
401418
}
402419
return Fuzzilli_Protobuf_WasmILType.with {
403420
$0.refType = Fuzzilli_Protobuf_WasmReferenceType.with {
@@ -1580,20 +1597,37 @@ extension Instruction: ProtobufConvertible {
15801597
fatalError("Unrecognized wasm value type \(value)")
15811598
}
15821599
case .refType(_):
1583-
switch wasmType.refType.kind {
1600+
let refKind: WasmReferenceType.Kind = switch wasmType.refType.kind {
15841601
case .index:
1585-
return .wasmRef(.Index(), nullability: wasmType.refType.nullability)
1602+
.Index()
15861603
case .externref:
1587-
return .wasmRef(.Abstract(.WasmExtern), nullability: wasmType.refType.nullability)
1604+
.Abstract(.WasmExtern)
15881605
case .funcref:
1589-
return .wasmRef(.Abstract(.WasmFunc), nullability: wasmType.refType.nullability)
1606+
.Abstract(.WasmFunc)
15901607
case .exnref:
1591-
return .wasmRef(.Abstract(.WasmExn), nullability: wasmType.refType.nullability)
1608+
.Abstract(.WasmExn)
15921609
case .i31Ref:
1593-
return .wasmRef(.Abstract(.WasmI31), nullability: wasmType.refType.nullability)
1610+
.Abstract(.WasmI31)
1611+
case .anyref:
1612+
.Abstract(.WasmAny)
1613+
case .eqref:
1614+
.Abstract(.WasmEq)
1615+
case .structref:
1616+
.Abstract(.WasmStruct)
1617+
case .arrayref:
1618+
.Abstract(.WasmArray)
1619+
case .noneref:
1620+
.Abstract(.WasmNone)
1621+
case .noexternref:
1622+
.Abstract(.WasmNoExtern)
1623+
case .nofuncref:
1624+
.Abstract(.WasmNoFunc)
1625+
case .noexnref:
1626+
.Abstract(.WasmNoExn)
15941627
case .UNRECOGNIZED(let value):
15951628
fatalError("Unrecognized wasm reference type \(value)")
15961629
}
1630+
return .wasmRef(refKind, nullability: wasmType.refType.nullability)
15971631
case .none:
15981632
fatalError("Absent wasm type")
15991633
}

Sources/Fuzzilli/FuzzIL/TypeSystem.swift

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1329,11 +1329,34 @@ public class WasmTypeDefinition: WasmTypeExtension {
13291329
}
13301330
}
13311331

1332+
// TODO: Add continuation types for core stack switching.
1333+
// TODO: Add shared bit for shared-everything-threads.
1334+
// TODO: Add internal string type for JS string builtins.
13321335
enum WasmAbstractHeapType: CaseIterable {
13331336
case WasmExtern
13341337
case WasmFunc
1335-
case WasmExn
1338+
case WasmAny
1339+
case WasmEq
13361340
case WasmI31
1341+
case WasmStruct
1342+
case WasmArray
1343+
case WasmExn
1344+
case WasmNone
1345+
case WasmNoExtern
1346+
case WasmNoFunc
1347+
case WasmNoExn
1348+
1349+
// True if the type can be used from JS, i.e. either passing the value from JS as a parameter or
1350+
// returning the value to JS as a result. (exnrefs cannot be passed from/to JS and throw
1351+
// runtime errors when trying to do so.)
1352+
func isUsableInJS() -> Bool {
1353+
switch self {
1354+
case .WasmExn, .WasmNoExn:
1355+
return false
1356+
default:
1357+
return true
1358+
}
1359+
}
13371360
}
13381361

13391362
// A wrapper around a WasmTypeDescription without owning the WasmTypeDescription.
@@ -1387,6 +1410,15 @@ public class WasmReferenceType: WasmTypeExtension {
13871410
self.nullability = nullability
13881411
}
13891412

1413+
func isAbstract() -> Bool {
1414+
switch self.kind {
1415+
case .Abstract(_):
1416+
return true
1417+
case .Index(_):
1418+
return false
1419+
}
1420+
}
1421+
13901422
override func isEqual(to other: WasmTypeExtension) -> Bool {
13911423
guard let other = other as? WasmReferenceType else { return false }
13921424
return kind == other.kind && self.nullability == other.nullability

Sources/Fuzzilli/Lifting/WasmLifter.swift

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -527,10 +527,26 @@ public class WasmLifter {
527527
return Data([0x6f])
528528
case .WasmFunc:
529529
return Data([0x70])
530+
case .WasmAny:
531+
return Data([0x6e])
532+
case .WasmEq:
533+
return Data([0x6d])
530534
case .WasmI31:
531535
return Data([0x6c])
536+
case .WasmStruct:
537+
return Data([0x6b])
538+
case .WasmArray:
539+
return Data([0x6a])
532540
case .WasmExn:
533541
return Data([0x69])
542+
case .WasmNone:
543+
return Data([0x71])
544+
case .WasmNoExtern:
545+
return Data([0x72])
546+
case .WasmNoFunc:
547+
return Data([0x73])
548+
case .WasmNoExn:
549+
return Data([0x74])
534550
}
535551
}
536552

Sources/Fuzzilli/Protobuf/operations.pb.swift

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -620,6 +620,14 @@ public enum Fuzzilli_Protobuf_WasmReferenceTypeKind: SwiftProtobuf.Enum, Swift.C
620620
case funcref // = 2
621621
case exnref // = 3
622622
case i31Ref // = 4
623+
case anyref // = 5
624+
case eqref // = 6
625+
case structref // = 7
626+
case arrayref // = 8
627+
case noneref // = 9
628+
case noexternref // = 10
629+
case nofuncref // = 11
630+
case noexnref // = 12
623631
case UNRECOGNIZED(Int)
624632

625633
public init() {
@@ -633,6 +641,14 @@ public enum Fuzzilli_Protobuf_WasmReferenceTypeKind: SwiftProtobuf.Enum, Swift.C
633641
case 2: self = .funcref
634642
case 3: self = .exnref
635643
case 4: self = .i31Ref
644+
case 5: self = .anyref
645+
case 6: self = .eqref
646+
case 7: self = .structref
647+
case 8: self = .arrayref
648+
case 9: self = .noneref
649+
case 10: self = .noexternref
650+
case 11: self = .nofuncref
651+
case 12: self = .noexnref
636652
default: self = .UNRECOGNIZED(rawValue)
637653
}
638654
}
@@ -644,6 +660,14 @@ public enum Fuzzilli_Protobuf_WasmReferenceTypeKind: SwiftProtobuf.Enum, Swift.C
644660
case .funcref: return 2
645661
case .exnref: return 3
646662
case .i31Ref: return 4
663+
case .anyref: return 5
664+
case .eqref: return 6
665+
case .structref: return 7
666+
case .arrayref: return 8
667+
case .noneref: return 9
668+
case .noexternref: return 10
669+
case .nofuncref: return 11
670+
case .noexnref: return 12
647671
case .UNRECOGNIZED(let i): return i
648672
}
649673
}
@@ -655,6 +679,14 @@ public enum Fuzzilli_Protobuf_WasmReferenceTypeKind: SwiftProtobuf.Enum, Swift.C
655679
.funcref,
656680
.exnref,
657681
.i31Ref,
682+
.anyref,
683+
.eqref,
684+
.structref,
685+
.arrayref,
686+
.noneref,
687+
.noexternref,
688+
.nofuncref,
689+
.noexnref,
658690
]
659691

660692
}
@@ -5546,6 +5578,14 @@ extension Fuzzilli_Protobuf_WasmReferenceTypeKind: SwiftProtobuf._ProtoNameProvi
55465578
2: .same(proto: "FUNCREF"),
55475579
3: .same(proto: "EXNREF"),
55485580
4: .same(proto: "I31REF"),
5581+
5: .same(proto: "ANYREF"),
5582+
6: .same(proto: "EQREF"),
5583+
7: .same(proto: "STRUCTREF"),
5584+
8: .same(proto: "ARRAYREF"),
5585+
9: .same(proto: "NONEREF"),
5586+
10: .same(proto: "NOEXTERNREF"),
5587+
11: .same(proto: "NOFUNCREF"),
5588+
12: .same(proto: "NOEXNREF"),
55495589
]
55505590
}
55515591

Sources/Fuzzilli/Protobuf/operations.proto

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -883,6 +883,14 @@ enum WasmReferenceTypeKind {
883883
FUNCREF = 2;
884884
EXNREF = 3;
885885
I31REF = 4;
886+
ANYREF = 5;
887+
EQREF = 6;
888+
STRUCTREF = 7;
889+
ARRAYREF = 8;
890+
NONEREF = 9;
891+
NOEXTERNREF = 10;
892+
NOFUNCREF = 11;
893+
NOEXNREF = 12;
886894
}
887895

888896
message WasmReferenceType {

Tests/FuzzilliTests/TypeSystemTest.swift

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1099,6 +1099,11 @@ class TypeSystemTests: XCTestCase {
10991099
// Test union of merged types
11001100
let strObjOrFuncObj = (ILType.string + ILType.object(withProperties: ["foo"])) | (ILType.function([.rest(.jsAnything)] => .float) + ILType.object(withProperties: ["foo"]))
11011101
XCTAssertEqual(strObjOrFuncObj.description, ".string + .object(withProperties: [\"foo\"]) | .object(withProperties: [\"foo\"]) + .function()")
1102+
1103+
let nullExn = ILType.wasmRef(.Abstract(.WasmExn), nullability: true)
1104+
let nonNullAny = ILType.wasmRef(.Abstract(.WasmAny), nullability: false)
1105+
XCTAssertEqual(nullExn.description, ".wasmRef(.Abstract(null WasmExn))")
1106+
XCTAssertEqual(nonNullAny.description, ".wasmRef(.Abstract(WasmAny))")
11021107
}
11031108

11041109
func testWasmSubsumptionRules() {
@@ -1147,7 +1152,7 @@ class TypeSystemTests: XCTestCase {
11471152
XCTAssertFalse(ILType.wasmGenericRef <= ILType.wasmRef(.Index(), nullability: true))
11481153

11491154
// Test nullability rules for abstract Wasm types.
1150-
for heapType: WasmAbstractHeapType in [.WasmExn, .WasmExtern, .WasmFunc, .WasmI31] {
1155+
for heapType: WasmAbstractHeapType in WasmAbstractHeapType.allCases {
11511156
let nullable = ILType.wasmRef(.Abstract(heapType), nullability: true)
11521157
let nonNullable = ILType.wasmRef(.Abstract(heapType), nullability: false)
11531158
XCTAssert(nonNullable.Is(nullable))

Tests/FuzzilliTests/WasmTests.swift

Lines changed: 45 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -4226,7 +4226,7 @@ class WasmGCTests: XCTestCase {
42264226
testForOutput(program: jsProg, runner: runner, outputString: "42\n")
42274227
}
42284228

4229-
func testRefNull() throws {
4229+
func testRefNullIndexTypes() throws {
42304230
let runner = try GetJavaScriptExecutorOrSkipTest()
42314231
let liveTestConfig = Configuration(logLevel: .error, enableInspection: true)
42324232
let fuzzer = makeMockFuzzer(config: liveTestConfig, environment: JavaScriptEnvironment())
@@ -4235,32 +4235,64 @@ class WasmGCTests: XCTestCase {
42354235
let arrayType = b.wasmDefineTypeGroup {[b.wasmDefineArrayType(elementType: .wasmi32, mutability: true)]}[0]
42364236

42374237
let module = b.buildWasmModule { wasmModule in
4238-
wasmModule.addWasmFunction(with: [] => [.wasmExternRef]) { function, args in
4239-
function.wasmReturn(function.wasmRefNull(type: .wasmExternRef))
4240-
}
4241-
wasmModule.addWasmFunction(with: [] => [.wasmFuncRef]) { function, args in
4242-
function.wasmReturn(function.wasmRefNull(type: .wasmFuncRef))
4243-
}
4244-
wasmModule.addWasmFunction(with: [] => [.wasmi32]) { function, args in
4238+
wasmModule.addWasmFunction(with: [] => [.wasmi32]) { function, label, args in
42454239
let refNull = function.wasmRefNull(typeDef: arrayType)
4246-
function.wasmRefIsNull(refNull)
4240+
return [function.wasmRefIsNull(refNull)]
42474241
}
4248-
wasmModule.addWasmFunction(with: [] => [.wasmi32]) { function, args in
4242+
wasmModule.addWasmFunction(with: [] => [.wasmi32]) { function, label, args in
42494243
let array = function.wasmArrayNewFixed(arrayType: arrayType, elements: [])
4250-
function.wasmRefIsNull(array)
4244+
return [function.wasmRefIsNull(array)]
42514245
}
42524246
}
42534247

42544248
let exports = module.loadExports()
42554249
let outputFunc = b.createNamedVariable(forBuiltin: "output")
4256-
for i in 0..<4 {
4250+
for i in 0..<2 {
42574251
let wasmOut = b.callMethod(module.getExportedMethod(at: i), on: exports, withArgs: [])
42584252
b.callFunction(outputFunc, withArgs: [wasmOut])
42594253
}
42604254

42614255
let prog = b.finalize()
42624256
let jsProg = fuzzer.lifter.lift(prog)
4263-
testForOutput(program: jsProg, runner: runner, outputString: "null\nnull\n1\n0\n")
4257+
testForOutput(program: jsProg, runner: runner, outputString: "1\n0\n")
4258+
}
4259+
4260+
func testRefNullAbstractTypes() throws {
4261+
let runner = try GetJavaScriptExecutorOrSkipTest()
4262+
let liveTestConfig = Configuration(logLevel: .error, enableInspection: true)
4263+
let fuzzer = makeMockFuzzer(config: liveTestConfig, environment: JavaScriptEnvironment())
4264+
let b = fuzzer.makeBuilder()
4265+
4266+
let module = b.buildWasmModule { wasmModule in
4267+
for heapType in WasmAbstractHeapType.allCases {
4268+
let valueType = ILType.wasmRef(.Abstract(heapType), nullability: true)
4269+
if heapType.isUsableInJS() {
4270+
// ref.null <heapType>
4271+
wasmModule.addWasmFunction(with: [] => [valueType]) { function, label, args in
4272+
[function.wasmRefNull(type: valueType)]
4273+
}
4274+
}
4275+
// ref.is_null(ref.null <heapType>)
4276+
wasmModule.addWasmFunction(with: [] => [.wasmi32]) { function, label, args in
4277+
[function.wasmRefIsNull(function.wasmRefNull(type: valueType))]
4278+
}
4279+
}
4280+
}
4281+
4282+
let exports = module.loadExports()
4283+
let outputFunc = b.createNamedVariable(forBuiltin: "output")
4284+
let exportedFctCount = WasmAbstractHeapType.allCases.count
4285+
+ WasmAbstractHeapType.allCases.count {$0.isUsableInJS()}
4286+
for i in 0..<exportedFctCount {
4287+
let wasmOut = b.callMethod(module.getExportedMethod(at: i), on: exports, withArgs: [])
4288+
b.callFunction(outputFunc, withArgs: [wasmOut])
4289+
}
4290+
4291+
let prog = b.finalize()
4292+
let jsProg = fuzzer.lifter.lift(prog)
4293+
// In JS all null values look the same (they are the same).
4294+
let expected = WasmAbstractHeapType.allCases.map {$0.isUsableInJS() ? "null\n1\n" : "1\n"}.joined()
4295+
testForOutput(program: jsProg, runner: runner, outputString: expected)
42644296
}
42654297

42664298
func testI31Ref() throws {

0 commit comments

Comments
 (0)