dart-lang/sdk

[vm/ffi] Unbox `Pointer`

Opened this issue · 2 comments

We should explore unboxing Pointer.

(I don't believe we had a tracking issue yet.)

We've stopped reifying the type argument of Pointer:

So, essentially the Pointer is now just an object with an unboxed integer as field.

Replacing it with a Dart int however does not exactly give the semantics that we want. We don't want to start boxing things in Mints again. So rather, it should be unboxed as an unboxed integer, and as an unboxed integer that has a different representation on 32 bit and 64 bit platforms.

Code such as this is not optimal:

 12:     v7 <- StaticCall:16( allocate<1> v2, v3, v4) T{*?}

[...]

 42:     PushArgument(v7 T{Pointer})
 44:     v54 <- StaticCall:12( get:address<0> v7 T{Pointer}, recognized_kind = FfiGetAddress) [-9223372036854775808, 9223372036854775807] T{int}
 46:     v140 <- UnboxInt64:14([non-speculative], v10) [1, 9] T{int}
 48:     v141 <- UnboxInt64:14([non-speculative], v54) [-9223372036854775808, 9223372036854775807] T{int}
 50:     v55 <- BinaryInt64Op:14(+ [tr], v141 T{int}, v140 T{_Smi}) [-9223372036854775808, 9223372036854775807] T{int}
 52:     v142 <- BoxInt64(v55 T{int}) [-9223372036854775808, 9223372036854775807] T{int}
 54:     PushArgument(v53)
 56:     PushArgument(v142 T{int})
 58:     v113 <- StaticCall:12( _fromAddress@8050071<1> v53, v142 T{int}, recognized_kind = FfiFromAddress) T{*?}
 60:     MemoryCopy(v7 T{Pointer}, v113 T{*?}, v16, v16, v139)
  • MemoryCopy + Pointer.fromAddress -> MemoryCopy should just take the address.
  • BoxInt + Pointer.fromAddress -> We box to unbox again within fromAddress. We would not have to box either if MemoryCopy would take unboxed address directly.
  • allocate + get:address -> if Pointer were unboxed we wouldn't have to box in allocate and unbox later.

We should consider using kUntagged as the representation of FFI pointers instead of kUnboxedFfiIntPtr, and only convert to/from kUnboxedFffiIntPtr explicitly when using the value of the address as a integer, now that kUntagged values are more understood by the flow graph compiler and aren't limited to being generated/killed within a single basic block. That is,

  • when performing arithmetic on the address internally (so untagged->uint32/int64, perform arithmetic, uint32/int64->untagged, similar to how BuildTypedDataViewFactoryConstructor in kernel_to_il.cc updates the inner pointer),
  • when returning the address as a Dart int in Pointer.address, and
  • when receiving a Dart int to turn into an address in Pointer.fromAddress.

This way, like in C++, using a pointer as an integer requires explicit conversion and is obvious in the IL.