[L] Change in dart/sdk[main]: [vm,dyn_modules] Handle compound returns from FfiCalls.

1 view
Skip to first unread message

Tess Strickland (Gerrit)

unread,
Jun 18, 2026, 11:37:14 AM (6 days ago) Jun 18
to Alexander Markov, rev...@dartlang.org, vm-...@dartlang.org
Attention needed from Alexander Markov

Tess Strickland voted Commit-Queue+1

Commit-Queue+1
Open in Gerrit

Related details

Attention is currently required from:
  • Alexander Markov
Submit Requirements:
  • requirement satisfiedCode-Owners
  • requirement is not satisfiedCode-Review
  • requirement satisfiedCommit-Message-Has-TEST
  • requirement is not satisfiedReview-Enforcement
Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. DiffyGerrit
Gerrit-MessageType: comment
Gerrit-Project: sdk
Gerrit-Branch: main
Gerrit-Change-Id: I3a81ee863b480d0a03c976639cfe094015b91e50
Gerrit-Change-Number: 514300
Gerrit-PatchSet: 13
Gerrit-Owner: Tess Strickland <sstr...@google.com>
Gerrit-Reviewer: Alexander Markov <alexm...@google.com>
Gerrit-Reviewer: Tess Strickland <sstr...@google.com>
Gerrit-Attention: Alexander Markov <alexm...@google.com>
Gerrit-Comment-Date: Thu, 18 Jun 2026 15:37:07 +0000
Gerrit-HasComments: No
Gerrit-Has-Labels: Yes
satisfied_requirement
unsatisfied_requirement
open
diffy

Tess Strickland (Gerrit)

unread,
Jun 19, 2026, 8:06:03 AM (5 days ago) Jun 19
to dart-...@luci-project-accounts.iam.gserviceaccount.com, Alexander Markov, rev...@dartlang.org, vm-...@dartlang.org
Attention needed from Alexander Markov

Tess Strickland added 1 comment

Patchset-level comments
File-level comment, Patchset 17 (Latest):
Tess Strickland . resolved

Okay, fixed the missing unimplemented/unused versions of the new FfiCallWithReturnedStructTrampoline, so PTAL.

Open in Gerrit

Related details

Attention is currently required from:
  • Alexander Markov
Submit Requirements:
  • requirement satisfiedCode-Owners
  • requirement is not satisfiedCode-Review
  • requirement satisfiedCommit-Message-Has-TEST
  • requirement is not satisfiedReview-Enforcement
Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. DiffyGerrit
Gerrit-MessageType: comment
Gerrit-Project: sdk
Gerrit-Branch: main
Gerrit-Change-Id: I3a81ee863b480d0a03c976639cfe094015b91e50
Gerrit-Change-Number: 514300
Gerrit-PatchSet: 17
Gerrit-Owner: Tess Strickland <sstr...@google.com>
Gerrit-Reviewer: Alexander Markov <alexm...@google.com>
Gerrit-Reviewer: Tess Strickland <sstr...@google.com>
Gerrit-Attention: Alexander Markov <alexm...@google.com>
Gerrit-Comment-Date: Fri, 19 Jun 2026 12:05:57 +0000
Gerrit-HasComments: Yes
Gerrit-Has-Labels: No
satisfied_requirement
unsatisfied_requirement
open
diffy

Alexander Markov (Gerrit)

unread,
Jun 22, 2026, 11:32:22 AM (2 days ago) Jun 22
to Tess Strickland, dart-...@luci-project-accounts.iam.gserviceaccount.com, Alexander Markov, rev...@dartlang.org, vm-...@dartlang.org
Attention needed from Tess Strickland

Alexander Markov added 1 comment

Commit Message
Line 18, Patchset 17 (Latest):FfiCallArguments.
Alexander Markov . unresolved

Could you explain why we need a new stub? Why we cannot simply set `x8` for `FfiCallTrampoline` to the area allocated in C++ code for returning a struct? Why do we need to copy returned struct value twice (in a stub and in C++ code)?

Also consider how simulator implements this with a single `SimulatorFfiCalloutTrampoline`.

Open in Gerrit

Related details

Attention is currently required from:
  • Tess Strickland
Submit Requirements:
  • requirement satisfiedCode-Owners
  • requirement is not satisfiedCode-Review
  • requirement satisfiedCommit-Message-Has-TEST
  • requirement is not satisfiedReview-Enforcement
Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. DiffyGerrit
Gerrit-MessageType: comment
Gerrit-Project: sdk
Gerrit-Branch: main
Gerrit-Change-Id: I3a81ee863b480d0a03c976639cfe094015b91e50
Gerrit-Change-Number: 514300
Gerrit-PatchSet: 17
Gerrit-Owner: Tess Strickland <sstr...@google.com>
Gerrit-Reviewer: Alexander Markov <alexm...@google.com>
Gerrit-Reviewer: Tess Strickland <sstr...@google.com>
Gerrit-Attention: Tess Strickland <sstr...@google.com>
Gerrit-Comment-Date: Mon, 22 Jun 2026 15:32:14 +0000
Gerrit-HasComments: Yes
Gerrit-Has-Labels: No
satisfied_requirement
unsatisfied_requirement
open
diffy

Tess Strickland (Gerrit)

unread,
Jun 23, 2026, 11:08:46 AM (24 hours ago) Jun 23
to dart-...@luci-project-accounts.iam.gserviceaccount.com, Alexander Markov, rev...@dartlang.org, vm-...@dartlang.org
Attention needed from Alexander Markov

Tess Strickland added 2 comments

Patchset-level comments
File-level comment, Patchset 24 (Latest):
Tess Strickland . resolved

Thanks, Alex, PTAL again!

Commit Message
Line 18, Patchset 17:FfiCallArguments.
Alexander Markov . resolved

Could you explain why we need a new stub? Why we cannot simply set `x8` for `FfiCallTrampoline` to the area allocated in C++ code for returning a struct? Why do we need to copy returned struct value twice (in a stub and in C++ code)?

Also consider how simulator implements this with a single `SimulatorFfiCalloutTrampoline`.

Tess Strickland

Because of my own confusion early on. I did figure out what I was missing later, but forgot to go back and take that into consideration.

I've cleaned this up and it now looks much more like you'd expect. I do copy back CallingConventions::kPointerToReturnStructRegisterReturn, which the simulator doesn't do, but I mostly do it to be sure that the C side is actually well-behaved and adhering to the expected ABI instead of returning an entirely different pointer than the one we passed in to the call.

Open in Gerrit

Related details

Attention is currently required from:
  • Alexander Markov
Submit Requirements:
  • requirement satisfiedCode-Owners
  • requirement is not satisfiedCode-Review
  • requirement satisfiedCommit-Message-Has-TEST
  • requirement is not satisfiedReview-Enforcement
Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. DiffyGerrit
Gerrit-MessageType: comment
Gerrit-Project: sdk
Gerrit-Branch: main
Gerrit-Change-Id: I3a81ee863b480d0a03c976639cfe094015b91e50
Gerrit-Change-Number: 514300
Gerrit-PatchSet: 24
Gerrit-Owner: Tess Strickland <sstr...@google.com>
Gerrit-Reviewer: Alexander Markov <alexm...@google.com>
Gerrit-Reviewer: Tess Strickland <sstr...@google.com>
Gerrit-Attention: Alexander Markov <alexm...@google.com>
Gerrit-Comment-Date: Tue, 23 Jun 2026 15:08:39 +0000
Gerrit-HasComments: Yes
Gerrit-Has-Labels: No
Comment-In-Reply-To: Alexander Markov <alexm...@google.com>
satisfied_requirement
unsatisfied_requirement
open
diffy

Alexander Markov (Gerrit)

unread,
Jun 23, 2026, 2:47:23 PM (20 hours ago) Jun 23
to Tess Strickland, dart-...@luci-project-accounts.iam.gserviceaccount.com, Alexander Markov, rev...@dartlang.org, vm-...@dartlang.org
Attention needed from Tess Strickland

Alexander Markov added 8 comments

File runtime/vm/ffi_trampolines_arm64.S
Line 57, Patchset 25 (Latest): ldr x8, [x19, #80] // FfiCallArguments.cpu_registers[8]
Alexander Markov . unresolved

Nit: why is this load moved and not loaded among other CPU registers?

Line 67, Patchset 25 (Latest): str x8, [x19, #80] // FfiCallArguments.cpu_registers[8]
Alexander Markov . unresolved

x8 is not guaranteed to be preserved and doesn't contain any useful information, so there is no point in copying it back.

File runtime/vm/runtime_entry.cc
Line 1226, Patchset 25 (Latest): for (; current <= end; ++current) {
Alexander Markov . unresolved

Should this be `<` to avoid out of bounds memory access?

Line 1232, Patchset 25 (Latest): buffer.Printf("%2x", *current);
Alexander Markov . unresolved

Nit: `%02x` to pad with zeros

Line 1388, Patchset 25 (Latest): const Register reg = pointer_loc.AsRegisters().reg_at(0);
Alexander Markov . unresolved

Nit: add `ASSERT((reg >= 0) && (reg < kNumberOfCpuRegisters));`

Line 1414, Patchset 25 (Latest): UNIMPLEMENTED();
Alexander Markov . unresolved

Nit: is this really a possible but unimplemented case? Maybe turn it into an assertion?

Line 1418, Patchset 25 (Latest): // The pointer returned should be the same one that was passed in.
ASSERT_EQUAL(
args.stack_area + marshaller.PassByPointerStackOffset(arg_index),
args.cpu_registers[reg]);
Alexander Markov . unresolved

ABI does not guarantee that R8 is preserved. So we should just use `args.stack_area + marshaller.PassByPointerStackOffset(arg_index)` as a `src`.

Line 1434, Patchset 25 (Latest): if (portion.IsStack()) {
Alexander Markov . unresolved

Can this really happen according to the ABI? We're not copying stack back to `args.stack_area` after the call, so this code will likely copy garbage.

I would suggest to make this case UNREACHABLE or UNIMPLEMENTED.

Open in Gerrit

Related details

Attention is currently required from:
  • Tess Strickland
Submit Requirements:
  • requirement satisfiedCode-Owners
  • requirement is not satisfiedCode-Review
  • requirement satisfiedCommit-Message-Has-TEST
  • requirement is not satisfiedReview-Enforcement
Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. DiffyGerrit
Gerrit-MessageType: comment
Gerrit-Project: sdk
Gerrit-Branch: main
Gerrit-Change-Id: I3a81ee863b480d0a03c976639cfe094015b91e50
Gerrit-Change-Number: 514300
Gerrit-PatchSet: 25
Gerrit-Owner: Tess Strickland <sstr...@google.com>
Gerrit-Reviewer: Alexander Markov <alexm...@google.com>
Gerrit-Reviewer: Tess Strickland <sstr...@google.com>
Gerrit-Attention: Tess Strickland <sstr...@google.com>
Gerrit-Comment-Date: Tue, 23 Jun 2026 18:47:20 +0000
Gerrit-HasComments: Yes
Gerrit-Has-Labels: No
satisfied_requirement
unsatisfied_requirement
open
diffy

Tess Strickland (Gerrit)

unread,
5:46 AM (5 hours ago) 5:46 AM
to dart-...@luci-project-accounts.iam.gserviceaccount.com, Alexander Markov, rev...@dartlang.org, vm-...@dartlang.org
Attention needed from Alexander Markov

Tess Strickland added 9 comments

Patchset-level comments
File-level comment, Patchset 25:
Tess Strickland . resolved

Thanks, Alex!

File runtime/vm/ffi_trampolines_arm64.S
Line 57, Patchset 25: ldr x8, [x19, #80] // FfiCallArguments.cpu_registers[8]
Alexander Markov . resolved

Nit: why is this load moved and not loaded among other CPU registers?

Tess Strickland

I was just copying it to the same place as in the simulator version to keep them consistent (and wasn't sure if sticking a `ldr` in the middle of a block of `ldp`s has some effect on performance which is why it was written afterwards in the simulator version).

Line 67, Patchset 25: str x8, [x19, #80] // FfiCallArguments.cpu_registers[8]
Alexander Markov . resolved

x8 is not guaranteed to be preserved and doesn't contain any useful information, so there is no point in copying it back.

Tess Strickland

See the comment on `runtime_entry.cc:1421`, but as mentioned there, removing it for now.

File runtime/vm/runtime_entry.cc
Line 1226, Patchset 25: for (; current <= end; ++current) {
Alexander Markov . resolved

Should this be `<` to avoid out of bounds memory access?

Tess Strickland

Done

Line 1232, Patchset 25: buffer.Printf("%2x", *current);
Alexander Markov . resolved

Nit: `%02x` to pad with zeros

Tess Strickland

Done

Line 1388, Patchset 25: const Register reg = pointer_loc.AsRegisters().reg_at(0);
Alexander Markov . resolved

Nit: add `ASSERT((reg >= 0) && (reg < kNumberOfCpuRegisters));`

Tess Strickland

Done

Line 1414, Patchset 25: UNIMPLEMENTED();
Alexander Markov . resolved

Nit: is this really a possible but unimplemented case? Maybe turn it into an assertion?

Tess Strickland

Done

Line 1418, Patchset 25: // The pointer returned should be the same one that was passed in.

ASSERT_EQUAL(
args.stack_area + marshaller.PassByPointerStackOffset(arg_index),
args.cpu_registers[reg]);
Alexander Markov . resolved

ABI does not guarantee that R8 is preserved. So we should just use `args.stack_area + marshaller.PassByPointerStackOffset(arg_index)` as a `src`.

Tess Strickland

Does it not? In `constants_arm64.h`:

```
// The native ABI uses R8 to pass the pointer to the memory preallocated for
// struct return values. Arm64 is the only ABI in which this pointer is _not_
// in ArgumentRegisters[0] or on the stack.
static constexpr Register kPointerToReturnStructRegisterCall = R8;
static constexpr Register kPointerToReturnStructRegisterReturn = R8;
```

I would assume there would be a `kNoRegister` definition for `CallingConventions:: kPointerToReturnStructRegisterReturn` if the ABI didn't specify that the pointer to the compound value must be passed back to the calling function via `R8`. That's why I figured that just using the information from the location would be sufficient (and the code looks the same as how the argument case is handled, outside of using `pointer_return_location()` instead of `pointer_location()`).

(All the expected tests pass on `vm-dyn-mac-debug-arm64` in the followup CL that also includes arguments handling, so I'd expect it must be appropriately preserved, but it could also just be that those tests just happen not to generate any uses of `R8` in the native function.)

I'm not averse to using the marshaller methods here to retrieve the information, so I'll make the change you suggest and remove the use of `pointer_return_location()` and the copying back of `x8` in the trampoline, I'm just surprised the marshaller claims that's where the info is located if it isn't.

Line 1434, Patchset 25: if (portion.IsStack()) {
Alexander Markov . resolved

Can this really happen according to the ABI? We're not copying stack back to `args.stack_area` after the call, so this code will likely copy garbage.

I would suggest to make this case UNREACHABLE or UNIMPLEMENTED.

Tess Strickland

Ah, thank you, _that's_ why my earlier versions of this were copying the stack back, because I'd thought this case needed to be handled and swore it showed up (that's probably from it showing up in arguments, and me just backporting the changes there).

Looking at the `CompoundResultLocation` definitions in `native_calling_convention.cc`, any `Stack` locations generated for the return case get replaced with `PointertoMemory` locations instead, and the only multiple cases are CPU/FPU register-related, so I'll mark any non-`Registers`/`FpuRegisters` case as `UNIMPLEMENTED` then.

Open in Gerrit

Related details

Attention is currently required from:
  • Alexander Markov
Submit Requirements:
  • requirement satisfiedCode-Owners
  • requirement is not satisfiedCode-Review
  • requirement satisfiedCommit-Message-Has-TEST
  • requirement is not satisfiedReview-Enforcement
Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. DiffyGerrit
Gerrit-MessageType: comment
Gerrit-Project: sdk
Gerrit-Branch: main
Gerrit-Change-Id: I3a81ee863b480d0a03c976639cfe094015b91e50
Gerrit-Change-Number: 514300
Gerrit-PatchSet: 25
Gerrit-Owner: Tess Strickland <sstr...@google.com>
Gerrit-Reviewer: Alexander Markov <alexm...@google.com>
Gerrit-Reviewer: Tess Strickland <sstr...@google.com>
Gerrit-Attention: Alexander Markov <alexm...@google.com>
Gerrit-Comment-Date: Wed, 24 Jun 2026 09:46:41 +0000
Gerrit-HasComments: Yes
Gerrit-Has-Labels: No
Comment-In-Reply-To: Alexander Markov <alexm...@google.com>
satisfied_requirement
unsatisfied_requirement
open
diffy
Reply all
Reply to author
Forward
0 new messages