Skip to content

Conversation

@tmc
Copy link
Contributor

@tmc tmc commented Oct 28, 2025

Following on from #353 (this should be rebased once it's in), this changes the maximum allowable stack parameters to be based on actual size consumption.

There are some current C APIs that are non-addressable with purego with the current limitation, this solves for that.

Improves on ABI alignment noted in #352

tmc added 4 commits October 27, 2025 16:04
Adds extensive test coverage for Darwin ARM64 stack parameter handling
to document and verify known issues with int32/float32 parameter packing
when more than 8 parameters are passed to functions.

The tests cover:
- Uniform type parameter passing (8, 9, 11, 15 parameters)
- Mixed type scenarios with various combinations
- Bool, pointer, and float parameter handling
- Edge cases and regression scenarios

Tests are designed to pass on other platforms while documenting
expected failures on Darwin ARM64 due to known stack packing bugs.
Replaces the previous struct-based workaround for Darwin ARM64 stack
parameter handling with direct byte-level packing that correctly handles
type-specific alignment and size requirements.

The new implementation:
- Tracks stack byte offsets precisely for proper alignment
- Handles 1, 2, 4, and 8-byte types with their natural alignment
- Packs multiple 4-byte values into 8-byte stack slots correctly
- Manages float register allocation alongside stack placement
- Eliminates the struct reflection approach that caused packing issues

Updates comprehensive stack tests to expect correct results rather than
documenting known failures. Test expectations now match proper arithmetic
(e.g., sum of 1+2+...+11 = 66) instead of placeholder values.

This resolves the Darwin ARM64 stack parameter packing bugs that affected
int32, uint32, float32, and other sub-8-byte types when passed beyond
the available registers.
Fixes three critical issues with the Darwin ARM64 stack parameter packing:

1. Callbacks: Stack packing optimization now only applies to RegisterLibFunc
   (C library calls), not RegisterFunc (which may be callbacks). Callbacks
   use Go calling conventions and expect 8-byte stack slots. Added
   isLibraryFunction flag to distinguish library calls from callbacks.

2. Mixed int/float parameters: The packing trigger condition checked if ANY
   register type was exhausted, causing premature packing entry when the
   current parameter's register type was still available. Fixed by checking
   the specific register type for the current parameter.

3. Float register allocation: Removed incorrect float register checks inside
   the stack packing block. Once packing mode is entered, all subsequent
   parameters go to stack with proper alignment.

Additionally, updated test helpers to respect expectedFailOnDarwinARM64 flag,
logging known issues instead of failing tests.

All tests passing on Darwin ARM64.
Adds calculateStackBytesNeeded function to precisely calculate stack space
requirements with platform-specific alignment rules. On Darwin ARM64, this
respects Apple's ABI where arguments use natural size and alignment rather
than always assuming 8-byte slots.

Updates RegisterFunc argument validation to use smarter byte-based limit
checking on Darwin ARM64, allowing more efficient parameter packing while
maintaining safety. Provides detailed error messages showing actual vs
available stack space in both bytes and slots.

This enhancement builds upon the previous stack packing fix to provide
more accurate validation and better debugging information.
@tmc tmc force-pushed the smart-stack-limit-checking branch from 6101a5a to f269f59 Compare October 28, 2025 00:46
@tmc
Copy link
Contributor Author

tmc commented Oct 28, 2025

This is folded into #353

@tmc tmc closed this Oct 28, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant