@@ -243,7 +243,7 @@ struct StackLayout {
243243 func dump< Target: TextOutputStream > ( to target: inout Target , iseq: InstructionSequence ) {
244244 let frameHeaderSize = FrameHeaderLayout . size ( of: frameHeader. type)
245245 let slotMinIndex = VReg ( - frameHeaderSize)
246- let slotMaxIndex = VReg ( numberOfLocals - 1 )
246+ let slotMaxIndex = VReg ( stackRegBase - 1 )
247247 let slotIndexWidth = max ( String ( slotMinIndex) . count, String ( slotMaxIndex) . count)
248248 func writeSlot( _ target: inout Target , _ index: VReg , _ description: String ) {
249249 var index = String ( index)
@@ -718,6 +718,27 @@ struct InstructionTranslator<Context: TranslatorContext>: InstructionVisitor {
718718 self . labels [ ref] = . unpinned( users: users)
719719 }
720720 }
721+
722+ /// Schedule to fill a br_table entry with the resolved label position
723+ /// - Parameters:
724+ /// - ref: Label reference to be resolved
725+ /// - table: Building br_table buffer
726+ /// - index: Index of the entry to fill
727+ /// - make: Factory closure to make an br_table entry
728+ mutating func fillBrTableEntry(
729+ _ ref: LabelRef ,
730+ table: BuildingBrTable ,
731+ index: Int , line: UInt = #line,
732+ make: @escaping BrTableEntryFactory
733+ ) {
734+ switch self . labels [ ref] {
735+ case . pinned( let pc) :
736+ table [ index] = make ( self , pc)
737+ case . unpinned( var users) :
738+ users. append ( LabelUser ( action: . fillBrTableEntry( buildingTable: table, index: index, make: make) , sourceLine: line) )
739+ self . labels [ ref] = . unpinned( users: users)
740+ }
741+ }
721742 }
722743
723744 struct Locals {
@@ -825,9 +846,11 @@ struct InstructionTranslator<Context: TranslatorContext>: InstructionVisitor {
825846 iseqBuilder. emit ( instruction, resultRelink: resultRelink)
826847 }
827848
828- private mutating func emitCopyStack( from source: VReg , to dest: VReg ) {
829- guard source != dest else { return }
849+ @discardableResult
850+ private mutating func emitCopyStack( from source: VReg , to dest: VReg ) -> Bool {
851+ guard source != dest else { return false }
830852 emit ( . copyStack( Instruction . CopyStackOperand ( source: Int32 ( source) , dest: Int32 ( dest) ) ) )
853+ return true
831854 }
832855
833856 private mutating func preserveOnStack( depth: Int ) {
@@ -933,11 +956,13 @@ struct InstructionTranslator<Context: TranslatorContext>: InstructionVisitor {
933956 }
934957 }
935958
936- private mutating func copyOnBranch( targetFrame frame: ControlStack . ControlFrame ) throws {
959+ @discardableResult
960+ private mutating func copyOnBranch( targetFrame frame: ControlStack . ControlFrame ) throws -> Bool {
937961 preserveOnStack ( depth: min ( Int ( frame. copyCount) , valueStack. height - frame. stackHeight) )
938962 let copyCount = VReg ( frame. copyCount)
939963 let sourceBase = valueStack. stackRegBase + VReg( valueStack. height)
940964 let destBase = valueStack. stackRegBase + VReg( frame. stackHeight)
965+ var emittedCopy = false
941966 for i in ( 0 ..< copyCount) . reversed ( ) {
942967 let source = sourceBase - 1 - VReg( i)
943968 let dest : VReg
@@ -946,8 +971,10 @@ struct InstructionTranslator<Context: TranslatorContext>: InstructionVisitor {
946971 } else {
947972 dest = destBase + copyCount - 1 - VReg( i)
948973 }
949- emitCopyStack ( from: source, to: dest)
974+ let copied = emitCopyStack ( from: source, to: dest)
975+ emittedCopy = emittedCopy || copied
950976 }
977+ return emittedCopy
951978 }
952979 private mutating func translateReturn( ) throws {
953980 if intercepting {
@@ -1258,7 +1285,6 @@ struct InstructionTranslator<Context: TranslatorContext>: InstructionVisitor {
12581285 iseqBuilder. emit ( . brTable( operand) )
12591286 let brTableAt = iseqBuilder. insertingPC
12601287
1261- // TODO(optimize): Eliminate landing pads when copyCount of a destination is 0
12621288 //
12631289 // (block $l1 (result i32)
12641290 // (i32.const 63)
@@ -1296,10 +1322,17 @@ struct InstructionTranslator<Context: TranslatorContext>: InstructionVisitor {
12961322 offset: Int32 ( relativeOffset)
12971323 )
12981324 }
1299- try copyOnBranch ( targetFrame: frame)
1300- iseqBuilder. emitWithLabel ( frame. continuation) { _, brAt, continuation in
1301- let relativeOffset = continuation. offsetFromHead - brAt. offsetFromHead
1302- return . br( offset: Int32 ( relativeOffset) )
1325+ let emittedCopy = try copyOnBranch ( targetFrame: frame)
1326+ if emittedCopy {
1327+ iseqBuilder. emitWithLabel ( frame. continuation) { _, brAt, continuation in
1328+ let relativeOffset = continuation. offsetFromHead - brAt. offsetFromHead
1329+ return . br( offset: Int32 ( relativeOffset) )
1330+ }
1331+ } else {
1332+ // Optimization: If no value is copied, we can directly jump to the target
1333+ iseqBuilder. fillBrTableEntry ( frame. continuation, table: tableBuffer, index: entryIndex) { _, continuation in
1334+ return Instruction . BrTable. Entry ( offset: Int32 ( continuation. offsetFromHead - brTableAt. offsetFromHead) )
1335+ }
13031336 }
13041337 }
13051338 try markUnreachable ( )
0 commit comments