@@ -1518,61 +1518,63 @@ struct InstructionTranslator<Context: TranslatorContext>: InstructionVisitor {
1518
1518
emit ( . callIndirect( operand) )
1519
1519
}
1520
1520
1521
- mutating func visitReturnCall( functionIndex: UInt32 ) throws {
1522
- let calleeType = try self . module. functionType ( functionIndex, interner: funcTypeInterner)
1523
- try validator. validateReturnCallLike ( calleeType: calleeType, callerType: type)
1524
-
1525
- guard let callee = self . module. resolveCallee ( functionIndex) else {
1526
- // Skip actual code emission if validation-only mode
1527
- return
1528
- }
1529
-
1521
+ /// Emit instructions to prepare the frame header for a return call to replace the
1522
+ /// current frame header with the callee's frame header layout.
1523
+ ///
1524
+ /// The frame header should have the callee's frame header layout and parameter
1525
+ /// slots are filled with arguments on the caller's stack.
1526
+ ///
1527
+ /// - Parameters:
1528
+ /// - calleeType: The type of the callee function.
1529
+ /// - stackTopHeightToCopy: The height of the stack top needed to be available at the
1530
+ /// return-call-like instruction point.
1531
+ private mutating func prepareFrameHeaderForReturnCall( calleeType: FunctionType , stackTopHeightToCopy: Int ) throws {
1530
1532
let calleeFrameHeader = FrameHeaderLayout ( type: calleeType)
1531
1533
if calleeType == self . type {
1532
1534
// Fast path: If the callee and the caller have the same signature, we can
1533
1535
// skip reconstructing the frame header and we can just copy the parameters.
1534
- try copyValuesIntoResultSlots ( calleeType. parameters, frameHeader: calleeFrameHeader)
1535
- emit ( . returnCall( Instruction . ReturnCallOperand ( callee: callee) ) )
1536
1536
} else {
1537
1537
// Ensure all parameters are on stack to avoid conflicting with the next resize.
1538
1538
preserveOnStack ( depth: calleeType. parameters. count)
1539
1539
// Resize the current frame header while moving stack slots after the header
1540
1540
// to the resized positions
1541
1541
let newHeaderSize = FrameHeaderLayout . size ( of: calleeType)
1542
1542
let delta = newHeaderSize - FrameHeaderLayout. size ( of: type)
1543
- let sizeToCopy = VReg ( FrameHeaderLayout . numberOfSavingSlots) + valueStack. stackRegBase + VReg( valueStack . height )
1543
+ let sizeToCopy = VReg ( FrameHeaderLayout . numberOfSavingSlots) + valueStack. stackRegBase + VReg( stackTopHeightToCopy )
1544
1544
emit ( . resizeFrameHeader( Instruction . ResizeFrameHeaderOperand ( delta: delta, sizeToCopy: sizeToCopy) ) )
1545
- try copyValuesIntoResultSlots ( calleeType. parameters, frameHeader: calleeFrameHeader)
1546
- emit ( . returnCall( Instruction . ReturnCallOperand ( callee: callee) ) )
1547
1545
}
1546
+ try copyValuesIntoResultSlots ( calleeType. parameters, frameHeader: calleeFrameHeader)
1547
+ }
1548
+
1549
+ mutating func visitReturnCall( functionIndex: UInt32 ) throws {
1550
+ let calleeType = try self . module. functionType ( functionIndex, interner: funcTypeInterner)
1551
+ try validator. validateReturnCallLike ( calleeType: calleeType, callerType: type)
1552
+
1553
+ guard let callee = self . module. resolveCallee ( functionIndex) else {
1554
+ // Skip actual code emission if validation-only mode
1555
+ return
1556
+ }
1557
+ try prepareFrameHeaderForReturnCall ( calleeType: calleeType, stackTopHeightToCopy: valueStack. height)
1558
+ emit ( . returnCall( Instruction . ReturnCallOperand ( callee: callee) ) )
1548
1559
try markUnreachable ( )
1549
1560
}
1550
1561
1551
1562
mutating func visitReturnCallIndirect( typeIndex: UInt32 , tableIndex: UInt32 ) throws {
1563
+ let stackTopHeightToCopy = valueStack. height
1552
1564
let addressType = try module. addressType ( tableIndex: tableIndex)
1553
1565
// Preserve function index slot on stack
1554
1566
let address = try popOnStackOperand ( addressType) // function address
1555
- let calleeType = try self . module. resolveType ( typeIndex)
1556
1567
guard let address = address else { return }
1568
+
1569
+ let calleeType = try self . module. resolveType ( typeIndex)
1557
1570
let internType = funcTypeInterner. intern ( calleeType)
1558
1571
1559
- let calleeFrameHeader = FrameHeaderLayout ( type: calleeType)
1560
- if calleeType == self . type {
1561
- // Fast path: If the callee and the caller have the same signature, we can
1562
- // skip reconstructing the frame header and we can just copy the parameters.
1563
- try copyValuesIntoResultSlots ( calleeType. parameters, frameHeader: calleeFrameHeader)
1564
- } else {
1565
- // Ensure all parameters are on stack to avoid conflicting with the next resize.
1566
- preserveOnStack ( depth: calleeType. parameters. count)
1567
- // Resize the current frame header while moving stack slots after the header
1568
- // to the resized positions
1569
- let newHeaderSize = FrameHeaderLayout . size ( of: calleeType)
1570
- let delta = newHeaderSize - FrameHeaderLayout. size ( of: type)
1571
- // +1 for address slot as it's used by return_call_indirect executed after resize_frame_header
1572
- let sizeToCopy = 1 + VReg( FrameHeaderLayout . numberOfSavingSlots) + valueStack. stackRegBase + VReg( valueStack. height)
1573
- emit ( . resizeFrameHeader( Instruction . ResizeFrameHeaderOperand ( delta: delta, sizeToCopy: sizeToCopy) ) )
1574
- try copyValuesIntoResultSlots ( calleeType. parameters, frameHeader: calleeFrameHeader)
1575
- }
1572
+ try prepareFrameHeaderForReturnCall (
1573
+ calleeType: calleeType,
1574
+ // Keep the stack space including the function index slot to be
1575
+ // accessible at the `return_call_indirect` instruction point.
1576
+ stackTopHeightToCopy: stackTopHeightToCopy
1577
+ )
1576
1578
1577
1579
let operand = Instruction . ReturnCallIndirectOperand (
1578
1580
tableIndex: tableIndex,
0 commit comments