Skip to content

reachabilityFence and AOT #49662

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
blaugold opened this issue Aug 15, 2022 · 5 comments
Closed

reachabilityFence and AOT #49662

blaugold opened this issue Aug 15, 2022 · 5 comments
Labels
area-vm Use area-vm for VM related issues, including code coverage, and the AOT and JIT backends. library-ffi

Comments

@blaugold
Copy link
Contributor

@dcharkes A while back, I asked whether there is a difference between the two reachability fences below (#48704 (comment)):

@pragma('vm:never-inline')
void reachabilityFence0(Object? object) => object;

@pragma('vm:never-inline')
void reachabilityFence1(Object? object) {}

void main(List<String> args) {
  reachabilityFence0(args);
  reachabilityFence1(args);
}

At least in AOT, it seems that the argument to reachabilityFence1 is replaced with a constant, rendering the fence ineffective:

*** BEGIN CFG
After AllocateRegisters
==== file:///Users/gabriel/Dev/cbl-dart/foo.dart_::_reachabilityFence1 (RegularFunction)
  0: B0[graph]:0 {
      v0 <- Constant(#null) T{Null?}
}
  2: B1[function entry]:2
  3:     ParallelMove r0 <- C
  4:     Return:10(v0)
*** END CFG
Code for optimized function 'file:///Users/gabriel/Dev/cbl-dart/foo.dart_::_reachabilityFence1' (RegularFunction) {
0x1019b65c0    aa1603e0               mov r0, nr
0x1019b65c4    d65f03c0               ret
}

*** BEGIN CFG
After AllocateRegisters
==== file:///Users/gabriel/Dev/cbl-dart/foo.dart_::_reachabilityFence0 (RegularFunction)
  0: B0[graph]:0 {
}
  2: B1[function entry]:2 {
      v2 <- Parameter(0) T{Object}
}
  3:     ParallelMove r0 <- S+0
  4:     Return:10(v2)
*** END CFG
Code for optimized function 'file:///Users/gabriel/Dev/cbl-dart/foo.dart_::_reachabilityFence0' (RegularFunction) {
0x1019b65e0    f94001e0               ldr r0, [sp]
0x1019b65e4    d65f03c0               ret
}

It might be a good idea to expose the reachabilityFence that is currently internal to the SDK, so that people don't run into this subtle difference.

@dcharkes dcharkes added area-vm Use area-vm for VM related issues, including code coverage, and the AOT and JIT backends. library-ffi labels Aug 15, 2022
@dcharkes
Copy link
Contributor

We might want to revive https://dart-review.googlesource.com/c/sdk/+/229901 in that case.

What is the use case where you need the fence? What is the use case in which implementing Finalizable does not suffice?

@blaugold
Copy link
Contributor Author

blaugold commented Aug 15, 2022

I have an externally allocated, reference-counted block of memory. A Dart object is handling the reference counting in its constructor and finalizer and serves as a handle. The memory contains a persisted data structure that can be navigated without fully reading it, through C functions, which know how to traverse it. I only read the parts that are requested, when they are requested, and I store pointers into the data structure to where I might need to continue reading. Whenever I read from the data structure through the C functions, I use a reachability fence to ensure that the handle stays alive and transitively the block of memory.

I implemented this before Finalizable existed and didn't design it with that option in mind, but thinking about it now, I could expand the handle class so that all reads go through an instance.

@dcharkes
Copy link
Contributor

I implemented this before Finalizable existed and didn't design it with that option in mind, but thinking about it now, I could expand the handle class so that all reads go through an instance.

Please let us know if this works for you. We believe Finalizables have better usability then sprinkling reachability fences everywhere.

@blaugold
Copy link
Contributor Author

blaugold commented Aug 17, 2022

We believe Finalizables have better usability then sprinkling reachability fences everywhere.

I agree, and was able to eliminate all fences by using Finalizable.

Maybe you could quickly answer this question: All the C functions to decode the mentioned data structure are in a dynamic library. Fully traversing some larger example data is ~8x faster from C as opposed to from Dart. This makes decoding that data into Dart objects about as fast as decoding an equivalent JSON string with json.decode, which is not that bad. The pointers that are passed to and returned from the C functions are just opaque handles. Is there any benefit to using UintPtr instead of Pointer to avoid allocation of Pointer objects, and do you have any advice for making FFI calls as fast as possible? Thanks!

@dcharkes
Copy link
Contributor

Maybe you could quickly answer this question

It's better to open new issues or StackOverflow questions.

But since I'm at it.

Is there any benefit to using UintPtr instead of Pointer to avoid allocation of Pointer objects

Right now probably yes, but eventually we'd like to fully unbox Pointer.

do you have any advice for making FFI calls as fast as possible?

Use isLeaf: true for functions that are guaranteed to not be calling back into Dart and are guaranteed to not be long running (the GC cannot run during leaf functions).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area-vm Use area-vm for VM related issues, including code coverage, and the AOT and JIT backends. library-ffi
Projects
None yet
Development

No branches or pull requests

2 participants