Skip to content

Commit

Permalink
Merge pull request #76 from swiftwasm/katei/flatten-opcodes
Browse files Browse the repository at this point in the history
Add simple translation step to internal ISeq
  • Loading branch information
kateinoigakukun authored Apr 7, 2024
2 parents e331658 + da053f2 commit 8956e15
Show file tree
Hide file tree
Showing 37 changed files with 5,473 additions and 829 deletions.
4 changes: 3 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,9 @@ update:
@swift package update

.PHONY: generate
generate: $(GENERATED_DIRS)
generate:
swift ./Utilities/generate_inst_visitor.swift
swift ./Utilities/generate_inst_dispatch.swift

GIT_STATUS = $(shell git status --porcelain)
ensure_clean:
Expand Down
2 changes: 2 additions & 0 deletions Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -39,10 +39,12 @@ let package = Package(
.target(
name: "WasmKit",
dependencies: [
"WasmParser",
"SystemExtras",
.product(name: "SystemPackage", package: "swift-system"),
]
),
.target(name: "WasmParser"),
.target(
name: "WASI",
dependencies: ["WasmKit", "SystemExtras"]
Expand Down
3 changes: 2 additions & 1 deletion Sources/Spectest/TestCase.swift
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import Foundation
import SystemPackage
import WasmKit
import WasmParser

struct TestCase {
enum Error: Swift.Error {
Expand Down Expand Up @@ -514,7 +515,7 @@ extension Array where Element == Value {

extension Swift.Error {
var text: String {
if let error = self as? WasmParserError {
if let error = self as? LegacyWasmParserError {
switch error {
case .invalidMagicNumber:
return "magic header not detected"
Expand Down
125 changes: 36 additions & 89 deletions Sources/WasmKit/Execution/Instructions/Control.swift
Original file line number Diff line number Diff line change
@@ -1,123 +1,70 @@
/// > Note:
/// <https://webassembly.github.io/spec/core/exec/instructions.html#control-instructions>
extension ExecutionState {
func unreachable(runtime: Runtime) throws {
func unreachable(runtime: Runtime, stack: inout Stack) throws {
throw Trap.unreachable
}
mutating func nop(runtime: Runtime) throws {
mutating func nop(runtime: Runtime, stack: inout Stack) throws {
programCounter += 1
}
private func getTypeSection(store: Store) -> [FunctionType] {
store.module(address: stack.currentFrame.module).types
}

typealias BlockType = Instruction.BlockType

mutating func block(runtime: Runtime, endRef: ExpressionRef, type: BlockType) {
enter(
jumpTo: programCounter + 1,
continuation: programCounter + endRef.relativeOffset,
arity: Int(type.results),
pushPopValues: Int(type.parameters)
)
}
mutating func loop(runtime: Runtime, type: BlockType) {
let paramSize = Int(type.parameters)
enter(jumpTo: programCounter + 1, continuation: programCounter, arity: paramSize, pushPopValues: paramSize)
}

mutating func ifThen(runtime: Runtime, endRef: ExpressionRef, type: BlockType) {
mutating func ifThen(runtime: Runtime, stack: inout Stack, elseOrEndRef: ExpressionRef) {
let isTrue = stack.popValue().i32 != 0
if isTrue {
enter(
jumpTo: programCounter + 1,
continuation: programCounter.advanced(by: endRef.relativeOffset),
arity: Int(type.results),
pushPopValues: Int(type.parameters)
)
programCounter += 1
} else {
programCounter += endRef.relativeOffset
programCounter += elseOrEndRef.relativeOffset
}
}

mutating func ifThenElse(runtime: Runtime, elseRef: ExpressionRef, endRef: ExpressionRef, type: BlockType) {
let isTrue = stack.popValue().i32 != 0
let addendToPC: Int
if isTrue {
addendToPC = 1
} else {
addendToPC = elseRef.relativeOffset
}
enter(
jumpTo: programCounter + addendToPC,
continuation: programCounter + endRef.relativeOffset,
arity: Int(type.results),
pushPopValues: Int(type.parameters)
)
mutating func end(runtime: Runtime, stack: inout Stack) {
fatalError()
}
mutating func end(runtime: Runtime) {
if let currentLabel = self.stack.currentLabel {
stack.exit(label: currentLabel)
}
programCounter += 1
}
mutating func `else`(runtime: Runtime) {
let label = self.stack.currentLabel!
stack.exit(label: label)
programCounter = label.continuation // if-then-else's continuation points the "end"
mutating func `else`(runtime: Runtime, stack: inout Stack, endRef: ExpressionRef) {
programCounter += endRef.relativeOffset // if-then-else's continuation points the "end"
}

private mutating func branch(labelIndex: Int, runtime: Runtime) throws {
if stack.numberOfLabelsInCurrentFrame() == labelIndex {
try self.return(runtime: runtime)
return
private mutating func branch(stack: inout Stack, offset: Int32, copyCount: UInt32, popCount: UInt32) throws {
if popCount > 0 { // TODO: Maybe worth to have a special instruction for popCount=0?
stack.copyValues(copyCount: Int(copyCount), popCount: Int(popCount))
}
let label = stack.getLabel(index: Int(labelIndex))
let values = stack.popValues(count: label.arity)

stack.unwindLabels(upto: labelIndex)

stack.push(values: values)
programCounter = label.continuation
programCounter += Int(offset)
}
mutating func br(runtime: Runtime, labelIndex: LabelIndex) throws {
try branch(labelIndex: Int(labelIndex), runtime: runtime)
mutating func br(runtime: Runtime, stack: inout Stack, offset: Int32, copyCount: UInt32, popCount: UInt32) throws {
try branch(stack: &stack, offset: offset, copyCount: copyCount, popCount: popCount)
}
mutating func brIf(runtime: Runtime, labelIndex: LabelIndex) throws {
mutating func brIf(runtime: Runtime, stack: inout Stack, offset: Int32, copyCount: UInt32, popCount: UInt32) throws {
guard stack.popValue().i32 != 0 else {
programCounter += 1
return
}
try br(runtime: runtime, labelIndex: labelIndex)
try branch(stack: &stack, offset: offset, copyCount: copyCount, popCount: popCount)
}
mutating func brTable(runtime: Runtime, brTable: Instruction.BrTable) throws {
let labelIndices = brTable.labelIndices
let defaultIndex = brTable.defaultIndex
let value = stack.popValue().i32
let labelIndex: LabelIndex
if labelIndices.indices.contains(Int(value)) {
labelIndex = labelIndices[Int(value)]
} else {
labelIndex = defaultIndex
}
mutating func brTable(runtime: Runtime, stack: inout Stack, brTable: Instruction.BrTable) throws {
let index = stack.popValue().i32
let normalizedOffset = min(Int(index), brTable.buffer.count - 1)
let entry = brTable.buffer[normalizedOffset]

try branch(labelIndex: Int(labelIndex), runtime: runtime)
try branch(
stack: &stack,
offset: entry.offset,
copyCount: UInt32(entry.copyCount), popCount: UInt32(entry.popCount)
)
}
mutating func `return`(runtime: Runtime) throws {
let currentFrame = stack.currentFrame!
_ = stack.exit(frame: currentFrame)
try endOfFunction(runtime: runtime, currentFrame: currentFrame)
mutating func `return`(runtime: Runtime, stack: inout Stack) throws {
try self.endOfFunction(runtime: runtime, stack: &stack)
}

mutating func endOfFunction(runtime: Runtime) throws {
try self.endOfFunction(runtime: runtime, currentFrame: stack.currentFrame)
mutating func endOfFunction(runtime: Runtime, stack: inout Stack) throws {
try self.endOfFunction(runtime: runtime, stack: &stack, currentFrame: stack.currentFrame)
}

mutating func endOfExecution(runtime: Runtime) throws {
mutating func endOfExecution(runtime: Runtime, stack: inout Stack) throws {
reachedEndOfExecution = true
}

private mutating func endOfFunction(runtime: Runtime, currentFrame: Frame) throws {
private mutating func endOfFunction(runtime: Runtime, stack: inout Stack, currentFrame: Frame) throws {
// When reached at "end" of function
#if DEBUG
if let address = currentFrame.address {
Expand All @@ -130,17 +77,17 @@ extension ExecutionState {
programCounter = currentFrame.returnPC
}

mutating func call(runtime: Runtime, functionIndex: UInt32) throws {
mutating func call(runtime: Runtime, stack: inout Stack, functionIndex: UInt32) throws {
let functionAddresses = runtime.store.module(address: stack.currentFrame.module).functionAddresses

guard functionAddresses.indices.contains(Int(functionIndex)) else {
throw Trap.invalidFunctionIndex(functionIndex)
}

try invoke(functionAddress: functionAddresses[Int(functionIndex)], runtime: runtime)
try invoke(functionAddress: functionAddresses[Int(functionIndex)], runtime: runtime, stack: &stack)
}

mutating func callIndirect(runtime: Runtime, tableIndex: TableIndex, typeIndex: TypeIndex) throws {
mutating func callIndirect(runtime: Runtime, stack: inout Stack, tableIndex: TableIndex, typeIndex: TypeIndex) throws {
let moduleInstance = runtime.store.module(address: stack.currentFrame.module)
let tableAddresses = moduleInstance.tableAddresses[Int(tableIndex)]
let tableInstance = runtime.store.tables[tableAddresses]
Expand All @@ -159,6 +106,6 @@ extension ExecutionState {
throw Trap.callIndirectFunctionTypeMismatch(actual: function.type, expected: expectedType)
}

try invoke(functionAddress: functionAddress, runtime: runtime)
try invoke(functionAddress: functionAddress, runtime: runtime, stack: &stack)
}
}
5 changes: 0 additions & 5 deletions Sources/WasmKit/Execution/Instructions/Expression.swift
Original file line number Diff line number Diff line change
@@ -1,8 +1,3 @@
struct BranchLabel: Equatable {
let label: Label
var index: LabelIndex
}

/// See spec's
/// [definition](https://webassembly.github.io/spec/core/text/instructions.html?highlight=pseudo#control-instructions).
/// > The `block`, `loop` and `if` instructions are structured instructions. They bracket nested sequences of
Expand Down
32 changes: 18 additions & 14 deletions Sources/WasmKit/Execution/Instructions/Instruction.swift
Original file line number Diff line number Diff line change
@@ -1,15 +1,17 @@
enum Instruction: Equatable {
case localGet(index: LocalIndex)
case localSet(index: LocalIndex)
case localTee(index: LocalIndex)
case globalGet(index: GlobalIndex)
case globalSet(index: GlobalIndex)
case unreachable
case nop
case block(endRef: ExpressionRef, type: BlockType)
case loop(type: BlockType)
case ifThen(endRef: ExpressionRef, type: BlockType)
case ifThenElse(elseRef: ExpressionRef, endRef: ExpressionRef, type: BlockType)
case ifThen(elseOrEndRef: ExpressionRef)
case end
case `else`
case br(labelIndex: LabelIndex)
case brIf(labelIndex: LabelIndex)
case brTable(BrTable)
case `else`(endRef: ExpressionRef)
case br(offset: Int32, copyCount: UInt32, popCount: UInt32)
case brIf(offset: Int32, copyCount: UInt32, popCount: UInt32)
case brTable(Instruction.BrTable)
case `return`
case call(functionIndex: UInt32)
case callIndirect(tableIndex: TableIndex, typeIndex: TypeIndex)
Expand Down Expand Up @@ -45,7 +47,6 @@ enum Instruction: Equatable {
case memoryCopy
case memoryFill
case numericConst(Value)
case numericIntUnary(NumericInstruction.IntUnary)
case numericFloatUnary(NumericInstruction.FloatUnary)
case numericIntBinary(NumericInstruction.IntBinary)
case numericFloatBinary(NumericInstruction.FloatBinary)
Expand Down Expand Up @@ -86,6 +87,14 @@ enum Instruction: Equatable {
case i64GeS
case i32GeU
case i64GeU
case i32Clz
case i64Clz
case i32Ctz
case i64Ctz
case i32Popcnt
case i64Popcnt
case i32Eqz
case i64Eqz
case drop
case select
case refNull(ReferenceType)
Expand All @@ -99,9 +108,4 @@ enum Instruction: Equatable {
case tableCopy(dest: TableIndex, src: TableIndex)
case tableInit(TableIndex, ElementIndex)
case tableElementDrop(ElementIndex)
case localGet(index: LocalIndex)
case localSet(index: LocalIndex)
case localTee(index: LocalIndex)
case globalGet(index: GlobalIndex)
case globalSet(index: GlobalIndex)
}
Loading

0 comments on commit 8956e15

Please sign in to comment.