@@ -811,7 +811,7 @@ struct InstructionTranslator: InstructionVisitor {
811811
812812 let allocator : ISeqAllocator
813813 let funcTypeInterner : Interner < FunctionType >
814- let module : InternalInstance
814+ var module : InternalInstance
815815 private var iseqBuilder : ISeqBuilder
816816 var controlStack : ControlStack
817817 var valueStack : ValueStack
@@ -825,6 +825,14 @@ struct InstructionTranslator: InstructionVisitor {
825825 var constantSlots : ConstSlots
826826 let validator : InstructionValidator
827827
828+ // Wasm debugging support.
829+
830+ /// Current offset to an instruction in the original Wasm binary processed by this translator.
831+ var binaryOffset : Int = 0
832+
833+ /// Mapping from `self.iseqBuilder.instructions` to Wasm instructions
834+ var iSeqToWasmMapping = [ Int: Int] ( )
835+
828836 init (
829837 allocator: ISeqAllocator ,
830838 engineConfiguration: EngineConfiguration ,
@@ -874,12 +882,14 @@ struct InstructionTranslator: InstructionVisitor {
874882 }
875883
876884 private mutating func emit( _ instruction: Instruction , resultRelink: ISeqBuilder . ResultRelink ? = nil ) {
885+ self . updateInstructionMapping ( )
877886 iseqBuilder. emit ( instruction, resultRelink: resultRelink)
878887 }
879888
880889 @discardableResult
881890 private mutating func emitCopyStack( from source: VReg , to dest: VReg ) -> Bool {
882891 guard source != dest else { return false }
892+ self . updateInstructionMapping ( )
883893 emit ( . copyStack( Instruction . CopyStackOperand ( source: LVReg ( source) , dest: LVReg ( dest) ) ) )
884894 return true
885895 }
@@ -1065,6 +1075,7 @@ struct InstructionTranslator: InstructionVisitor {
10651075 emit ( . onExit( functionIndex) )
10661076 }
10671077 try visitReturnLike ( )
1078+ self . updateInstructionMapping ( )
10681079 iseqBuilder. emit ( . _return)
10691080 }
10701081 private mutating func markUnreachable( ) throws {
@@ -1084,9 +1095,15 @@ struct InstructionTranslator: InstructionVisitor {
10841095 let instructions = iseqBuilder. finalize ( )
10851096 // TODO: Figure out a way to avoid the copy here while keeping the execution performance.
10861097 let buffer = allocator. allocateInstructions ( capacity: instructions. count)
1087- for (idx, instruction) in instructions. enumerated ( ) {
1088- buffer [ idx] = instruction
1098+ let initializedElementsIndex = buffer. initialize ( fromContentsOf: instructions)
1099+ assert ( initializedElementsIndex == instructions. endIndex)
1100+
1101+ for (iseq, wasm) in self . iSeqToWasmMapping {
1102+ self . module. withValue {
1103+ $0. iSeqToWasmMapping [ iseq + buffer. baseAddress. unsafelyUnwrapped] = wasm
1104+ }
10891105 }
1106+
10901107 let constants = allocator. allocateConstants ( self . constantSlots. values)
10911108 return InstructionSequence (
10921109 instructions: buffer,
@@ -1095,6 +1112,15 @@ struct InstructionTranslator: InstructionVisitor {
10951112 )
10961113 }
10971114
1115+ private mutating func updateInstructionMapping( ) {
1116+ // This is a hot path, so best to exclude the code altogether if the trait isn't enabled.
1117+ #if WasmDebuggingSupport
1118+ guard self . module. isDebuggable else { return }
1119+
1120+ self . iSeqToWasmMapping [ self . iseqBuilder. insertingPC. offsetFromHead] = self . binaryOffset
1121+ #endif
1122+ }
1123+
10981124 // MARK: Main entry point
10991125
11001126 /// Translate a Wasm expression into a sequence of instructions.
@@ -1122,7 +1148,9 @@ struct InstructionTranslator: InstructionVisitor {
11221148 emit ( . unreachable)
11231149 try markUnreachable ( )
11241150 }
1125- mutating func visitNop( ) -> Output { emit ( . nop) }
1151+ mutating func visitNop( ) -> Output {
1152+ emit ( . nop)
1153+ }
11261154
11271155 mutating func visitBlock( blockType: WasmParser . BlockType ) throws -> Output {
11281156 let blockType = try module. resolveBlockType ( blockType)
@@ -1169,6 +1197,7 @@ struct InstructionTranslator: InstructionVisitor {
11691197 )
11701198 )
11711199 guard let condition = condition else { return }
1200+ self . updateInstructionMapping ( )
11721201 iseqBuilder. emitWithLabel ( Instruction . brIfNot, endLabel) { iseqBuilder, selfPC, endPC in
11731202 let targetPC : MetaProgramCounter
11741203 if let elsePC = iseqBuilder. resolveLabel ( elseLabel) {
@@ -1189,6 +1218,8 @@ struct InstructionTranslator: InstructionVisitor {
11891218 preserveOnStack ( depth: valueStack. height - frame. stackHeight)
11901219 try controlStack. resetReachability ( )
11911220 iseqBuilder. resetLastEmission ( )
1221+
1222+ self . updateInstructionMapping ( )
11921223 iseqBuilder. emitWithLabel ( Instruction . br, endLabel) { _, selfPC, endPC in
11931224 let offset = endPC. offsetFromHead - selfPC. offsetFromHead
11941225 return Int32 ( offset)
@@ -1284,6 +1315,8 @@ struct InstructionTranslator: InstructionVisitor {
12841315 currentFrame: try controlStack. currentFrame ( ) ,
12851316 currentHeight: valueStack. height
12861317 )
1318+
1319+ self . updateInstructionMapping ( )
12871320 iseqBuilder. emitWithLabel ( makeInstruction, frame. continuation) { _, selfPC, continuation in
12881321 let relativeOffset = continuation. offsetFromHead - selfPC. offsetFromHead
12891322 return make ( Int32 ( relativeOffset) , UInt32 ( copyCount) , popCount)
@@ -1317,6 +1350,7 @@ struct InstructionTranslator: InstructionVisitor {
13171350 if frame. copyCount == 0 {
13181351 guard let condition else { return }
13191352 // Optimization where we don't need copying values when the branch taken
1353+ self . updateInstructionMapping ( )
13201354 iseqBuilder. emitWithLabel ( Instruction . brIf, frame. continuation) { _, selfPC, continuation in
13211355 let relativeOffset = continuation. offsetFromHead - selfPC. offsetFromHead
13221356 return Instruction . BrIfOperand (
@@ -1349,11 +1383,13 @@ struct InstructionTranslator: InstructionVisitor {
13491383 // [0x06] (local.get 1 reg:2) <----|---------+
13501384 // [0x07] ... <-------+
13511385 let onBranchNotTaken = iseqBuilder. allocLabel ( )
1386+ self . updateInstructionMapping ( )
13521387 iseqBuilder. emitWithLabel ( Instruction . brIfNot, onBranchNotTaken) { _, conditionCheckAt, continuation in
13531388 let relativeOffset = continuation. offsetFromHead - conditionCheckAt. offsetFromHead
13541389 return Instruction . BrIfOperand ( condition: LVReg ( condition) , offset: Int32 ( relativeOffset) )
13551390 }
13561391 try copyOnBranch ( targetFrame: frame)
1392+ self . updateInstructionMapping ( )
13571393 try emitBranch ( Instruction . br, relativeDepth: relativeDepth) { offset, copyCount, popCount in
13581394 return offset
13591395 }
@@ -1380,6 +1416,7 @@ struct InstructionTranslator: InstructionVisitor {
13801416 baseAddress: tableBuffer. baseAddress!,
13811417 count: UInt16 ( tableBuffer. count) , index: index
13821418 )
1419+ self . updateInstructionMapping ( )
13831420 iseqBuilder. emit ( . brTable( operand) )
13841421 let brTableAt = iseqBuilder. insertingPC
13851422
@@ -1429,6 +1466,7 @@ struct InstructionTranslator: InstructionVisitor {
14291466 }
14301467 let emittedCopy = try copyOnBranch ( targetFrame: frame)
14311468 if emittedCopy {
1469+ self . updateInstructionMapping ( )
14321470 iseqBuilder. emitWithLabel ( Instruction . br, frame. continuation) { _, brAt, continuation in
14331471 let relativeOffset = continuation. offsetFromHead - brAt. offsetFromHead
14341472 return Int32 ( relativeOffset)
0 commit comments