| // Copyright (c) 2026, the Dart project authors. Please see the AUTHORS file | |
| // for details. All rights reserved. Use of this source code is governed by a | |
| // BSD-style license that can be found in the LICENSE file. | |
| import 'package:cfg/ir/functions.dart'; | |
| import 'package:cfg/ir/instructions.dart'; | |
| import 'package:cfg/utils/misc.dart'; | |
| import 'package:native_compiler/back_end/locations.dart'; | |
| import 'package:native_compiler/back_end/safepoint.dart'; | |
| /// Base class for architecture-specific stack frame layout. | |
| abstract base class StackFrame { | |
| final CFunction function; | |
| int _usedSpillSlots = 0; | |
| int _maxArgumentsStackSlots = 0; | |
| bool _finalized = false; | |
| StackFrame(this.function); | |
| bool get isFinalized => _finalized; | |
| int get usedSpillSlots { | |
| assert(isFinalized); | |
| return _usedSpillSlots; | |
| } | |
| int get maxArgumentsStackSlots { | |
| assert(isFinalized); | |
| return _maxArgumentsStackSlots; | |
| } | |
| /// Size of the spill slot with given [registerClass]. | |
| int spillSlotSizeInWords(RegisterClass registerClass); | |
| /// Alignment of the spill slot with given [registerClass]. | |
| int spillSlotAlignmentInWords(RegisterClass registerClass); | |
| /// Number of arguments stack slots required for [instr]. | |
| int argumentsStackSlots(Instruction instr); | |
| /// Offset of [location] relative to the frame pointer, in bytes. | |
| /// Should be used only after the frame is finalized. | |
| int offsetFromFP(StackLocation location); | |
| /// Offset of the suspend state relative to the frame pointer, in bytes. | |
| int get suspendStateOffsetFromFP; | |
| /// Offset of the shadow parameter relative to the frame pointer, in bytes. | |
| /// Should be used only after the frame is finalized. | |
| int shadowParameterOffsetFromFP(int paramIndex); | |
| /// Location of the parameter in the stack frame. | |
| ParameterStackLocation getParameterSlot( | |
| int paramIndex, | |
| RegisterClass registerClass, | |
| ); | |
| /// Frame size to allocate, in stack slots (words). | |
| /// Should be used only after the frame is finalized. | |
| int get frameSizeInSlots; | |
| /// Reserve [numSlots] spill slots. | |
| void reserveSpillSlots(int numSlots) { | |
| assert(!_finalized); | |
| _usedSpillSlots += numSlots; | |
| } | |
| /// Record reserved stack slots in the safepoint. | |
| void recordReservedLocations(Safepoint safepoint); | |
| /// Allocate a new spill slot. | |
| SpillSlot allocateSpillSlot(RegisterClass registerClass) { | |
| assert(!_finalized); | |
| final size = spillSlotSizeInWords(registerClass); | |
| final alignment = spillSlotAlignmentInWords(registerClass); | |
| _usedSpillSlots = roundUp(_usedSpillSlots, alignment); | |
| final slot = SpillSlot(_usedSpillSlots); | |
| _usedSpillSlots += size; | |
| return slot; | |
| } | |
| /// Allocate outgoing argument slots for [instr]. | |
| void allocateArgumentsSlots(Instruction instr) { | |
| final stackSlots = argumentsStackSlots(instr); | |
| if (stackSlots > _maxArgumentsStackSlots) { | |
| _maxArgumentsStackSlots = stackSlots; | |
| } | |
| } | |
| /// Finish stack frame allocation. | |
| /// No new spill slots can be allocated past this point. | |
| void finalize() { | |
| _finalized = true; | |
| } | |
| } |