Skip to content

Commit 9d79c83

Browse files
committed
Fix DebuggerTests
1 parent d5d1600 commit 9d79c83

File tree

4 files changed

+97
-48
lines changed

4 files changed

+97
-48
lines changed

Sources/WasmKit/Execution/Debugger.swift

Lines changed: 44 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,45 @@
11
#if WasmDebuggingSupport
22

3+
extension [Int] {
4+
func binarySearch(nextClosestTo value: Int) -> Int? {
5+
switch self.count {
6+
case 0:
7+
return nil
8+
default:
9+
var slice = self[0..<self.count]
10+
while slice.count > 1 {
11+
let middle = (slice.endIndex - slice.startIndex) / 2
12+
if slice[middle] < value {
13+
// Not found anything in the lower half, assigning higher half to `slice`.
14+
slice = slice[(middle + 1)..<slice.endIndex]
15+
} else {
16+
// Not found anything in the higher half, assigning lower half to `slice`.
17+
slice = slice[slice.startIndex..<middle]
18+
}
19+
}
20+
21+
return self[slice.startIndex]
22+
}
23+
}
24+
}
25+
26+
extension Instance {
27+
func findIseq(forWasmAddress address: Int) throws(Debugger.Error) -> Pc {
28+
// Look in the main mapping first
29+
guard
30+
let iseq = handle.wasmToIseqMapping[address]
31+
// If nothing found, find the closest Wasm address using binary search
32+
?? handle.wasmMappings.binarySearch(nextClosestTo: address)
33+
// Look in the main mapping again with the next closest address if binary search produced anything
34+
.flatMap({ handle.wasmToIseqMapping[$0] })
35+
else {
36+
throw Debugger.Error.noInstructionMappingAvailable(address)
37+
}
38+
39+
return iseq
40+
}
41+
}
42+
343
package struct Debugger: ~Copyable {
444
package enum Error: Swift.Error {
545
case entrypointFunctionNotFound
@@ -60,17 +100,12 @@
60100
}
61101

62102
package mutating func enableBreakpoint(address: Int) throws(Error) {
63-
print("attempt to toggle a breakpoint at \(address)")
64-
print("available mapping: \(self.instance.handle.wasmToIseqMapping)")
65-
66103
guard self.breakpoints[address] == nil else {
67-
print("breakpoint at \(address) already enabled")
68104
return
69105
}
70106

71-
guard let iseq = self.instance.handle.wasmToIseqMapping[address] else {
72-
throw Error.noInstructionMappingAvailable(address)
73-
}
107+
let iseq = try self.instance.findIseq(forWasmAddress: address)
108+
74109
self.breakpoints[address] = iseq.pointee
75110
iseq.pointee = Instruction.breakpoint.headSlot(threadingModel: self.threadingModel)
76111
}
@@ -83,9 +118,8 @@
83118
return
84119
}
85120

86-
guard let iseq = self.instance.handle.wasmToIseqMapping[address] else {
87-
throw Error.noInstructionMappingAvailable(address)
88-
}
121+
let iseq = try self.instance.findIseq(forWasmAddress: address)
122+
89123
self.breakpoints[address] = nil
90124
iseq.pointee = oldCodeSlot
91125
}

Sources/WasmKit/Execution/Instances.swift

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -87,11 +87,15 @@ struct InstanceEntity /* : ~Copyable */ {
8787

8888
/// Mapping from iSeq Pc to instruction addresses in the original binary.
8989
/// Used for handling current call stack requests issued by a ``Debugger`` instance.
90-
var iseqToWasmMapping: [Pc: Int]
90+
var iseqToWasmMapping = [Pc: Int]()
9191

9292
/// Mapping from Wasm instruction addresses in the original binary to iSeq instruction addresses.
9393
/// Used for handling breakpoint requests issued by a ``Debugger`` instance.
94-
var wasmToIseqMapping: [Int: Pc]
94+
var wasmToIseqMapping = [Int: Pc]()
95+
96+
/// Wasm addresses sorted in ascending order for binary search when of the next closest mapped
97+
/// instruction, when no key is found in `wasmToIseqMapping`.
98+
var wasmMappings = [Int]()
9599

96100
static var empty: InstanceEntity {
97101
InstanceEntity(

Sources/WasmKit/Translator.swift

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1110,6 +1110,7 @@ struct InstructionTranslator: InstructionVisitor {
11101110
if $0.wasmToIseqMapping[wasm] == nil {
11111111
$0.wasmToIseqMapping[wasm] = absoluteISeq
11121112
}
1113+
$0.wasmMappings.append(wasm)
11131114
}
11141115
}
11151116

@@ -1127,7 +1128,6 @@ struct InstructionTranslator: InstructionVisitor {
11271128
guard self.module.isDebuggable else { return }
11281129

11291130
self.iseqToWasmMapping.append((self.iseqBuilder.insertingPC.offsetFromHead, self.binaryOffset))
1130-
print("added iSeqToWasmMapping[\(self.iseqBuilder.insertingPC.offsetFromHead)] = \(self.binaryOffset)")
11311131
#endif
11321132
}
11331133

@@ -1902,8 +1902,6 @@ struct InstructionTranslator: InstructionVisitor {
19021902
}
19031903

19041904
private mutating func visitConst(_ type: ValueType, _ value: Value) {
1905-
print("in \(#function) self.binaryOffset is \(self.binaryOffset)")
1906-
19071905
// TODO: document this behavior
19081906
if let constSlotIndex = constantSlots.allocate(value) {
19091907
valueStack.pushConst(constSlotIndex, type: type)
@@ -1912,7 +1910,6 @@ struct InstructionTranslator: InstructionVisitor {
19121910
}
19131911
let value = UntypedValue(value)
19141912
let is32Bit = type == .i32 || type == .f32
1915-
print("emitting const \(value)")
19161913
if is32Bit {
19171914
pushEmit(
19181915
type,
Lines changed: 46 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,38 +1,52 @@
11
#if WasmDebuggingSupport
22

3-
import Testing
4-
import WAT
5-
@testable import WasmKit
6-
7-
private let trivialModuleWAT = """
8-
(module
9-
(func (export "_start") (result i32) (local $x i32)
10-
(i32.const 42)
11-
(i32.const 0)
12-
(i32.eqz)
13-
(drop)
14-
(local.set $x)
15-
(local.get $x)
16-
)
17-
)
18-
"""
19-
20-
@Suite
21-
struct DebuggerTests {
22-
@Test
23-
func stopAtEntrypoint() throws {
24-
let store = Store(engine: Engine())
25-
let bytes = try wat2wasm(trivialModuleWAT)
26-
print(bytes.count)
27-
let module = try parseWasm(bytes: bytes)
28-
var debugger = try Debugger(module: module, store: store, imports: [:])
29-
30-
try debugger.stopAtEntrypoint()
31-
32-
#expect(throws: Execution.Breakpoint.self) {
33-
try debugger.run()
3+
import Testing
4+
import WAT
5+
@testable import WasmKit
6+
7+
private let trivialModuleWAT = """
8+
(module
9+
(func (export "_start") (result i32) (local $x i32)
10+
(i32.const 42)
11+
(i32.const 0)
12+
(i32.eqz)
13+
(drop)
14+
(local.set $x)
15+
(local.get $x)
16+
)
17+
)
18+
"""
19+
20+
@Suite
21+
struct DebuggerTests {
22+
@Test
23+
func stopAtEntrypoint() throws {
24+
let store = Store(engine: Engine())
25+
let bytes = try wat2wasm(trivialModuleWAT)
26+
print(bytes.count)
27+
let module = try parseWasm(bytes: bytes)
28+
var debugger = try Debugger(module: module, store: store, imports: [:])
29+
30+
try debugger.stopAtEntrypoint()
31+
32+
#expect(throws: Execution.Breakpoint.self) {
33+
try debugger.run()
34+
}
35+
}
36+
37+
@Test
38+
func binarySearch() throws {
39+
#expect([Int]().binarySearch(nextClosestTo: 42) == nil)
40+
41+
var result = try #require([1].binarySearch(nextClosestTo: 8))
42+
#expect(result == 1)
43+
44+
result = try #require([9, 15, 37].binarySearch(nextClosestTo: 28))
45+
#expect(result == 37)
46+
47+
result = try #require([9, 15, 37].binarySearch(nextClosestTo: 0))
48+
#expect(result == 9)
3449
}
3550
}
36-
}
3751

3852
#endif

0 commit comments

Comments
 (0)