Skip to content

Commit a5e045d

Browse files
Merge pull request #67 from MaxDesiatov/maxd/extract-execution-state
Extract `ExecutionState` from the `Runtime` type
2 parents ff44b0a + 7353d2b commit a5e045d

File tree

12 files changed

+408
-373
lines changed

12 files changed

+408
-373
lines changed

Sources/Spectest/TestCase.swift

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -192,7 +192,6 @@ extension TestCase {
192192
) { command, result in
193193
handler(self, command, result)
194194
}
195-
assert(runtime.isStackEmpty)
196195
}
197196
}
198197
}

Sources/WasmKit/Component/CanonicalCall.swift

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,9 @@ public struct CanonicalCallContext {
3535
guard let realloc = options.realloc else {
3636
throw CanonicalABIError(description: "Missing required \"cabi_realloc\" export")
3737
}
38-
let results = try runtime.invoke(realloc, with: [.i32(old), .i32(oldSize), .i32(oldAlign), .i32(newSize)])
38+
let results = try realloc.invoke(
39+
[.i32(old), .i32(oldSize), .i32(oldAlign), .i32(newSize)], runtime: runtime
40+
)
3941
guard results.count == 1 else {
4042
throw CanonicalABIError(description: "\"cabi_realloc\" export should return a single value")
4143
}

Sources/WasmKit/Component/CanonicalOptions.swift

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,13 +18,13 @@ public struct CanonicalOptions {
1818
/// The string encoding used for lifting or lowering string values.
1919
public let stringEncoding: StringEncoding
2020
/// The realloc function address used for lifting or lowering values.
21-
public let realloc: FunctionAddress?
21+
public let realloc: Function?
2222
/// The function address called when a lifted/lowered function returns.
23-
public let postReturn: FunctionAddress?
23+
public let postReturn: Function?
2424

2525
public init(
2626
memory: MemoryAddress, stringEncoding: StringEncoding,
27-
realloc: FunctionAddress?, postReturn: FunctionAddress?
27+
realloc: Function?, postReturn: Function?
2828
) {
2929
self.memory = memory
3030
self.stringEncoding = stringEncoding

Sources/WasmKit/Execution/Instructions/Control.swift

Lines changed: 30 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -13,28 +13,28 @@ enum ControlInstruction: Equatable {
1313
case call(functionIndex: UInt32)
1414
case callIndirect(tableIndex: TableIndex, typeIndex: TypeIndex)
1515

16-
func execute(runtime: Runtime) throws {
16+
func execute(runtime: Runtime, execution: inout ExecutionState) throws {
1717
switch self {
1818
case .unreachable:
1919
throw Trap.unreachable
2020

2121
case .nop:
22-
runtime.programCounter += 1
22+
execution.programCounter += 1
2323

2424
case let .block(expression, type):
25-
let (paramSize, resultSize) = type.arity(typeSection: { runtime.stack.currentFrame.module.types })
26-
let values = try runtime.stack.popValues(count: paramSize)
27-
runtime.enter(expression, continuation: runtime.programCounter + 1, arity: resultSize)
28-
runtime.stack.push(values: values)
25+
let (paramSize, resultSize) = type.arity(typeSection: { execution.stack.currentFrame.module.types })
26+
let values = try execution.stack.popValues(count: paramSize)
27+
execution.enter(expression, continuation: execution.programCounter + 1, arity: resultSize)
28+
execution.stack.push(values: values)
2929

3030
case let .loop(expression, type):
31-
let (paramSize, _) = type.arity(typeSection: { runtime.stack.currentFrame.module.types })
32-
let values = try runtime.stack.popValues(count: paramSize)
33-
runtime.enter(expression, continuation: runtime.programCounter, arity: paramSize)
34-
runtime.stack.push(values: values)
31+
let (paramSize, _) = type.arity(typeSection: { execution.stack.currentFrame.module.types })
32+
let values = try execution.stack.popValues(count: paramSize)
33+
execution.enter(expression, continuation: execution.programCounter, arity: paramSize)
34+
execution.stack.push(values: values)
3535

3636
case let .if(then, `else`, type):
37-
let isTrue = try runtime.stack.popValue().i32 != 0
37+
let isTrue = try execution.stack.popValue().i32 != 0
3838

3939
let expression: Expression
4040
if isTrue {
@@ -45,62 +45,62 @@ enum ControlInstruction: Equatable {
4545

4646
if !expression.instructions.isEmpty {
4747
let derived = ControlInstruction.block(expression: expression, type: type)
48-
try derived.execute(runtime: runtime)
48+
try derived.execute(runtime: runtime, execution: &execution)
4949
} else {
50-
runtime.programCounter += 1
50+
execution.programCounter += 1
5151
}
5252

5353
case let .brIf(labelIndex):
54-
guard try runtime.stack.popValue().i32 != 0 else {
55-
runtime.programCounter += 1
54+
guard try execution.stack.popValue().i32 != 0 else {
55+
execution.programCounter += 1
5656
return
5757
}
5858

5959
fallthrough
6060

6161
case let .br(labelIndex):
62-
try runtime.branch(labelIndex: Int(labelIndex))
62+
try execution.branch(labelIndex: Int(labelIndex))
6363

6464
case let .brTable(labelIndices, defaultLabelIndex):
65-
let value = try runtime.stack.popValue().i32
65+
let value = try execution.stack.popValue().i32
6666
let labelIndex: LabelIndex
6767
if labelIndices.indices.contains(Int(value)) {
6868
labelIndex = labelIndices[Int(value)]
6969
} else {
7070
labelIndex = defaultLabelIndex
7171
}
7272

73-
try runtime.branch(labelIndex: Int(labelIndex))
73+
try execution.branch(labelIndex: Int(labelIndex))
7474

7575
case .return:
76-
let values = try runtime.stack.popValues(count: runtime.stack.currentFrame.arity)
76+
let values = try execution.stack.popValues(count: execution.stack.currentFrame.arity)
7777

78-
let currentFrame = Stack.Element.frame(runtime.stack.currentFrame)
78+
let currentFrame = Stack.Element.frame(execution.stack.currentFrame)
7979
var lastLabel: Label?
80-
while runtime.stack.top != currentFrame {
81-
runtime.stack.discardTopValues()
82-
lastLabel = try runtime.stack.popLabel()
80+
while execution.stack.top != currentFrame {
81+
execution.stack.discardTopValues()
82+
lastLabel = try execution.stack.popLabel()
8383
}
8484
if let lastLabel {
85-
runtime.programCounter = lastLabel.continuation
85+
execution.programCounter = lastLabel.continuation
8686
}
87-
runtime.stack.push(values: values)
87+
execution.stack.push(values: values)
8888

8989
case let .call(functionIndex):
90-
let functionAddresses = runtime.stack.currentFrame.module.functionAddresses
90+
let functionAddresses = execution.stack.currentFrame.module.functionAddresses
9191

9292
guard functionAddresses.indices.contains(Int(functionIndex)) else {
9393
throw Trap.invalidFunctionIndex(functionIndex)
9494
}
9595

96-
try runtime.invoke(functionAddress: functionAddresses[Int(functionIndex)])
96+
try execution.invoke(functionAddress: functionAddresses[Int(functionIndex)], runtime: runtime)
9797

9898
case let .callIndirect(tableIndex, typeIndex):
99-
let moduleInstance = runtime.stack.currentFrame.module
99+
let moduleInstance = execution.stack.currentFrame.module
100100
let tableAddresses = moduleInstance.tableAddresses[Int(tableIndex)]
101101
let tableInstance = runtime.store.tables[tableAddresses]
102102
let expectedType = moduleInstance.types[Int(typeIndex)]
103-
let value = try runtime.stack.popValue().i32
103+
let value = try execution.stack.popValue().i32
104104
let elementIndex = Int(value)
105105
guard elementIndex < tableInstance.elements.count else {
106106
throw Trap.undefinedElement
@@ -114,7 +114,7 @@ enum ControlInstruction: Equatable {
114114
throw Trap.callIndirectFunctionTypeMismatch(actual: function.type, expected: expectedType)
115115
}
116116

117-
try runtime.invoke(functionAddress: functionAddress)
117+
try execution.invoke(functionAddress: functionAddress, runtime: runtime)
118118
}
119119
}
120120
}

Sources/WasmKit/Execution/Instructions/Table.swift

Lines changed: 51 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -10,55 +10,55 @@ enum TableInstruction: Equatable {
1010
case `init`(TableIndex, ElementIndex)
1111
case elementDrop(ElementIndex)
1212

13-
func execute(runtime: Runtime) throws {
13+
func execute(runtime: Runtime, execution: inout ExecutionState) throws {
1414
switch self {
1515
case let .get(tableIndex):
16-
let (_, table) = try runtime.getTable(tableIndex)
16+
let (_, table) = try execution.getTable(tableIndex, store: runtime.store)
1717

18-
let elementIndex = try runtime.getElementIndex(table)
18+
let elementIndex = try execution.getElementIndex(table)
1919

2020
guard let reference = table.elements[Int(elementIndex)] else {
2121
throw Trap.readingDroppedReference(index: elementIndex)
2222
}
2323

24-
runtime.stack.push(value: .ref(reference))
24+
execution.stack.push(value: .ref(reference))
2525

2626
case let .set(tableIndex):
27-
let (tableAddress, table) = try runtime.getTable(tableIndex)
27+
let (tableAddress, table) = try execution.getTable(tableIndex, store: runtime.store)
2828

29-
let reference = try runtime.stack.getReference()
30-
let elementIndex = try runtime.getElementIndex(table)
31-
runtime.setTableElement(tableAddress: tableAddress, elementIndex, reference)
29+
let reference = try execution.stack.getReference()
30+
let elementIndex = try execution.getElementIndex(table)
31+
setTableElement(store: runtime.store, tableAddress: tableAddress, elementIndex, reference)
3232

3333
case let .size(tableIndex):
34-
let (_, table) = try runtime.getTable(tableIndex)
34+
let (_, table) = try execution.getTable(tableIndex, store: runtime.store)
3535

36-
runtime.stack.push(value: .i32(UInt32(table.elements.count)))
36+
execution.stack.push(value: .i32(UInt32(table.elements.count)))
3737

3838
case let .grow(tableIndex):
39-
let (tableAddress, table) = try runtime.getTable(tableIndex)
39+
let (tableAddress, table) = try execution.getTable(tableIndex, store: runtime.store)
4040

41-
let growthSize = try runtime.stack.popValue()
41+
let growthSize = try execution.stack.popValue()
4242

4343
guard case let .i32(growthSize) = growthSize else {
4444
fatalError("invalid value at the top of the stack \(growthSize)")
4545
}
4646

47-
let growthValue = try runtime.stack.getReference()
47+
let growthValue = try execution.stack.getReference()
4848

4949
let oldSize = UInt32(table.elements.count)
5050
guard runtime.store.tables[tableAddress].grow(by: growthSize, value: growthValue) else {
51-
runtime.stack.push(value: .i32(Int32(-1).unsigned))
51+
execution.stack.push(value: .i32(Int32(-1).unsigned))
5252
break
5353
}
5454

55-
runtime.stack.push(value: .i32(oldSize))
55+
execution.stack.push(value: .i32(oldSize))
5656

5757
case let .fill(tableIndex):
58-
let (tableAddress, table) = try runtime.getTable(tableIndex)
59-
let fillCounter = try runtime.stack.popValue().i32
60-
let fillValue = try runtime.stack.getReference()
61-
let startIndex = try runtime.stack.popValue().i32
58+
let (tableAddress, table) = try execution.getTable(tableIndex, store: runtime.store)
59+
let fillCounter = try execution.stack.popValue().i32
60+
let fillValue = try execution.stack.getReference()
61+
let startIndex = try execution.stack.popValue().i32
6262

6363
guard fillCounter > 0 else {
6464
break
@@ -69,16 +69,16 @@ enum TableInstruction: Equatable {
6969
}
7070

7171
for i in 0..<fillCounter {
72-
runtime.setTableElement(tableAddress: tableAddress, startIndex + i, fillValue)
72+
setTableElement(store: runtime.store, tableAddress: tableAddress, startIndex + i, fillValue)
7373
}
7474

7575
case let .copy(destinationTableIndex, sourceTableIndex):
76-
let (_, sourceTable) = try runtime.getTable(sourceTableIndex)
77-
let (destinationTableAddress, destinationTable) = try runtime.getTable(destinationTableIndex)
76+
let (_, sourceTable) = try execution.getTable(sourceTableIndex, store: runtime.store)
77+
let (destinationTableAddress, destinationTable) = try execution.getTable(destinationTableIndex, store: runtime.store)
7878

79-
let copyCounter = try runtime.stack.popValue().i32
80-
let sourceIndex = try runtime.stack.popValue().i32
81-
let destinationIndex = try runtime.stack.popValue().i32
79+
let copyCounter = try execution.stack.popValue().i32
80+
let sourceIndex = try execution.stack.popValue().i32
81+
let destinationIndex = try execution.stack.popValue().i32
8282

8383
guard copyCounter > 0 else {
8484
break
@@ -97,21 +97,22 @@ enum TableInstruction: Equatable {
9797
}
9898

9999
for i in 0..<copyCounter {
100-
runtime.setTableElement(
100+
setTableElement(
101+
store: runtime.store,
101102
tableAddress: destinationTableAddress,
102103
destinationIndex + i,
103104
sourceTable.elements[Int(sourceIndex + i)]
104105
)
105106
}
106107

107108
case let .`init`(tableIndex, elementIndex):
108-
let (destinationTableAddress, destinationTable) = try runtime.getTable(tableIndex)
109-
let elementAddress = runtime.stack.currentFrame.module.elementAddresses[Int(elementIndex)]
109+
let (destinationTableAddress, destinationTable) = try execution.getTable(tableIndex, store: runtime.store)
110+
let elementAddress = execution.stack.currentFrame.module.elementAddresses[Int(elementIndex)]
110111
let sourceElement = runtime.store.elements[elementAddress]
111112

112-
let copyCounter = try runtime.stack.popValue().i32
113-
let sourceIndex = try runtime.stack.popValue().i32
114-
let destinationIndex = try runtime.stack.popValue().i32
113+
let copyCounter = try execution.stack.popValue().i32
114+
let sourceIndex = try execution.stack.popValue().i32
115+
let destinationIndex = try execution.stack.popValue().i32
115116

116117
guard copyCounter > 0 else {
117118
break
@@ -133,23 +134,37 @@ enum TableInstruction: Equatable {
133134
for i in 0..<copyCounter {
134135
let reference = sourceElement.references[Int(sourceIndex + i)]
135136

136-
runtime.setTableElement(tableAddress: destinationTableAddress, destinationIndex + i, reference)
137+
setTableElement(
138+
store: runtime.store,
139+
tableAddress: destinationTableAddress,
140+
destinationIndex + i,
141+
reference
142+
)
137143
}
138144

139145
case let .elementDrop(elementIndex):
140-
let elementAddress = runtime.stack.currentFrame.module.elementAddresses[Int(elementIndex)]
146+
let elementAddress = execution.stack.currentFrame.module.elementAddresses[Int(elementIndex)]
141147
runtime.store.elements[elementAddress].drop()
142148
}
143149
}
150+
151+
fileprivate func setTableElement(
152+
store: Store,
153+
tableAddress: TableAddress,
154+
_ elementIndex: ElementIndex,
155+
_ reference: Reference?
156+
) {
157+
store.tables[tableAddress].elements[Int(elementIndex)] = reference
158+
}
144159
}
145160

146-
extension Runtime {
147-
fileprivate func getTable(_ tableIndex: UInt32) throws -> (TableAddress, TableInstance) {
161+
extension ExecutionState {
162+
fileprivate func getTable(_ tableIndex: UInt32, store: Store) throws -> (TableAddress, TableInstance) {
148163
let address = stack.currentFrame.module.tableAddresses[Int(tableIndex)]
149164
return (address, store.tables[address])
150165
}
151166

152-
fileprivate func getElementIndex(_ table: TableInstance) throws -> ElementIndex {
167+
fileprivate mutating func getElementIndex(_ table: TableInstance) throws -> ElementIndex {
153168
let elementIndex = try stack.popValue().i32
154169

155170
guard elementIndex < table.elements.count else {
@@ -158,10 +173,6 @@ extension Runtime {
158173

159174
return elementIndex
160175
}
161-
162-
fileprivate func setTableElement(tableAddress: TableAddress, _ elementIndex: ElementIndex, _ reference: Reference?) {
163-
store.tables[tableAddress].elements[Int(elementIndex)] = reference
164-
}
165176
}
166177

167178
extension Stack {

0 commit comments

Comments
 (0)