11/*
22 * Copyright (c) 2020, 2022, Oracle and/or its affiliates. All rights reserved.
3- * Copyright (c) 2019, 2021 , Arm Limited. All rights reserved.
3+ * Copyright (c) 2019, 2022 , Arm Limited. All rights reserved.
44 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
55 *
66 * This code is free software; you can redistribute it and/or modify it
@@ -186,21 +186,13 @@ public StorageCalculator(boolean forArguments) {
186186 this .forArguments = forArguments ;
187187 }
188188
189+ void alignStack (long alignment ) {
190+ stackOffset = Utils .alignUp (stackOffset , alignment );
191+ }
192+
189193 VMStorage stackAlloc (long size , long alignment ) {
190194 assert forArguments : "no stack returns" ;
191- // Implementation limit: each arg must take up at least an 8 byte stack slot (on the Java side)
192- // There is currently no way to address stack offsets that are not multiples of 8 bytes
193- // The VM can only address multiple-of-4-bytes offsets, which is also not good enough for some ABIs
194- // see JDK-8283462 and related issues
195- long stackSlotAlignment = Math .max (alignment , STACK_SLOT_SIZE );
196- long alignedStackOffset = Utils .alignUp (stackOffset , stackSlotAlignment );
197- // macos-aarch64 ABI potentially requires addressing stack offsets that are not multiples of 8 bytes
198- // Reject such call types here, to prevent undefined behavior down the line
199- // Reject if the above stack-slot-aligned offset does not match the offset the ABI really wants
200- // Except for variadic arguments, which _are_ passed at 8-byte-aligned offsets
201- if (requiresSubSlotStackPacking () && alignedStackOffset != Utils .alignUp (stackOffset , alignment )
202- && !forVarArgs ) // varargs are given a pass on all aarch64 ABIs
203- throw new UnsupportedOperationException ("Call type not supported on this platform" );
195+ long alignedStackOffset = Utils .alignUp (stackOffset , alignment );
204196
205197 short encodedSize = (short ) size ;
206198 assert (encodedSize & 0xFFFF ) == size ;
@@ -212,7 +204,10 @@ VMStorage stackAlloc(long size, long alignment) {
212204 }
213205
214206 VMStorage stackAlloc (MemoryLayout layout ) {
215- return stackAlloc (layout .byteSize (), layout .byteAlignment ());
207+ long stackSlotAlignment = requiresSubSlotStackPacking () && !forVarArgs
208+ ? layout .byteAlignment ()
209+ : Math .max (layout .byteAlignment (), STACK_SLOT_SIZE );
210+ return stackAlloc (layout .byteSize (), stackSlotAlignment );
216211 }
217212
218213 VMStorage [] regAlloc (int type , int count ) {
@@ -245,6 +240,26 @@ VMStorage nextStorage(int type, MemoryLayout layout) {
245240 return storage [0 ];
246241 }
247242
243+ VMStorage [] nextStorageForHFA (GroupLayout group ) {
244+ final int nFields = group .memberLayouts ().size ();
245+ VMStorage [] regs = regAlloc (StorageType .VECTOR , nFields );
246+ if (regs == null && requiresSubSlotStackPacking () && !forVarArgs ) {
247+ // For the ABI variants that pack arguments spilled to the
248+ // stack, HFA arguments are spilled as if their individual
249+ // fields had been allocated separately rather than as if the
250+ // struct had been spilled as a whole.
251+
252+ VMStorage [] slots = new VMStorage [nFields ];
253+ for (int i = 0 ; i < nFields ; i ++) {
254+ slots [i ] = stackAlloc (group .memberLayouts ().get (i ));
255+ }
256+
257+ return slots ;
258+ } else {
259+ return regs ;
260+ }
261+ }
262+
248263 void adjustForVarArgs () {
249264 // This system passes all variadic parameters on the stack. Ensure
250265 // no further arguments are allocated to registers.
@@ -280,6 +295,12 @@ protected void spillStructUnbox(Binding.Builder bindings, MemoryLayout layout) {
280295 .vmStore (storage , type );
281296 offset += STACK_SLOT_SIZE ;
282297 }
298+
299+ if (requiresSubSlotStackPacking ()) {
300+ // Pad to the next stack slot boundary instead of packing
301+ // additional arguments into the unused space.
302+ storageCalculator .alignStack (STACK_SLOT_SIZE );
303+ }
283304 }
284305
285306 protected void spillStructBox (Binding .Builder bindings , MemoryLayout layout ) {
@@ -299,6 +320,12 @@ protected void spillStructBox(Binding.Builder bindings, MemoryLayout layout) {
299320 .bufferStore (offset , type );
300321 offset += STACK_SLOT_SIZE ;
301322 }
323+
324+ if (requiresSubSlotStackPacking ()) {
325+ // Pad to the next stack slot boundary instead of packing
326+ // additional arguments into the unused space.
327+ storageCalculator .alignStack (STACK_SLOT_SIZE );
328+ }
302329 }
303330
304331 abstract List <Binding > getBindings (Class <?> carrier , MemoryLayout layout );
@@ -360,8 +387,7 @@ List<Binding> getBindings(Class<?> carrier, MemoryLayout layout) {
360387 case STRUCT_HFA : {
361388 assert carrier == MemorySegment .class ;
362389 GroupLayout group = (GroupLayout )layout ;
363- VMStorage [] regs = storageCalculator .regAlloc (
364- StorageType .VECTOR , group .memberLayouts ().size ());
390+ VMStorage [] regs = storageCalculator .nextStorageForHFA (group );
365391 if (regs != null ) {
366392 long offset = 0 ;
367393 for (int i = 0 ; i < group .memberLayouts ().size (); i ++) {
@@ -458,8 +484,7 @@ List<Binding> getBindings(Class<?> carrier, MemoryLayout layout) {
458484 assert carrier == MemorySegment .class ;
459485 bindings .allocate (layout );
460486 GroupLayout group = (GroupLayout ) layout ;
461- VMStorage [] regs = storageCalculator .regAlloc (
462- StorageType .VECTOR , group .memberLayouts ().size ());
487+ VMStorage [] regs = storageCalculator .nextStorageForHFA (group );
463488 if (regs != null ) {
464489 long offset = 0 ;
465490 for (int i = 0 ; i < group .memberLayouts ().size (); i ++) {
0 commit comments