@@ -20,11 +20,13 @@ public final class Pointer {
2020 private static final AtomicInteger NEXT_ADDRESS = new AtomicInteger (0x1000 );
2121 private static final Map <Object , Integer > ALLOCATION_BASES = new WeakHashMap <>();
2222 private static final Map <Object , Integer > ALLOCATION_ELEMENT_SIZES = new WeakHashMap <>();
23+ private static final Map <Object , Integer > ALLOCATION_ALIGNMENTS = new WeakHashMap <>();
2324 private static final Map <Object , String > ALLOCATION_CODECS = new WeakHashMap <>();
2425 private static final Map <Integer , ExposedTarget > EXPOSED_ADDRESSES = new HashMap <>();
2526 private static final Map <String , Method []> CODEC_METHODS = new HashMap <>();
2627 private static final Map <Object , Integer > MANAGED_OBJECT_ADDRESSES = new IdentityHashMap <>();
2728 private static final Map <Integer , WeakReference <Object >> MANAGED_OBJECTS = new HashMap <>();
29+ private static final Map <String , Pointer > TRAIT_METADATA_MARKERS = new HashMap <>();
2830
2931 private static final class Cell {
3032 private Object value ;
@@ -41,20 +43,23 @@ private static final class ExposedTarget {
4143 private final String codecClassName ;
4244 private final int viewSize ;
4345 private final String viewCodecClassName ;
46+ private final int metadata ;
4447
4548 private ExposedTarget (
4649 Object allocation ,
4750 int allocationElementSize ,
4851 int byteOffset ,
4952 String codecClassName ,
5053 int viewSize ,
51- String viewCodecClassName ) {
54+ String viewCodecClassName ,
55+ int metadata ) {
5256 this .allocation = new WeakReference <>(allocation );
5357 this .allocationElementSize = allocationElementSize ;
5458 this .byteOffset = byteOffset ;
5559 this .codecClassName = codecClassName ;
5660 this .viewSize = viewSize ;
5761 this .viewCodecClassName = viewCodecClassName ;
62+ this .metadata = metadata ;
5863 }
5964 }
6065
@@ -65,6 +70,7 @@ private ExposedTarget(
6570 private final String allocationCodecClassName ;
6671 private final String viewCodecClassName ;
6772 private final int exposedAddress ;
73+ private int metadata = -1 ;
6874 private int zeroSizedSourceViewSize = -1 ;
6975 private String zeroSizedSourceViewCodecClassName ;
7076
@@ -113,7 +119,22 @@ private Pointer(
113119 }
114120
115121 public static Pointer cell (Object value , int size , String codecClassName ) {
116- return new Pointer (new Cell (value ), size , 0 , size , codecClassName );
122+ return cellAligned (value , size , codecClassName , 16 );
123+ }
124+
125+ public static Pointer cellAligned (
126+ Object value ,
127+ int size ,
128+ String codecClassName ,
129+ int alignment ) {
130+ if (alignment <= 0 || (alignment & (alignment - 1 )) != 0 ) {
131+ throw new IllegalArgumentException ("Rust allocation alignment must be a power of two" );
132+ }
133+ Cell cell = new Cell (value );
134+ synchronized (ALLOCATION_BASES ) {
135+ ALLOCATION_ALIGNMENTS .put (cell , alignment );
136+ }
137+ return new Pointer (cell , size , 0 , size , codecClassName );
117138 }
118139
119140 public static Pointer cell (Object value , int size ) {
@@ -158,19 +179,22 @@ public static Pointer fromSlice(
158179 try {
159180 Field arrayField = sliceView .getClass ().getField ("array" );
160181 Field offsetField = sliceView .getClass ().getField ("offset" );
182+ Field lengthField = sliceView .getClass ().getField ("length" );
161183 Object backing = arrayField .get (sliceView );
162184 int offset = offsetField .getInt (sliceView );
185+ int length = lengthField .getInt (sliceView );
163186 if (backing instanceof Pointer ) {
164187 return ((Pointer ) backing )
165188 .sliceStorageView ()
166189 .add (offset )
167- .retype (elementSize , codecClassName );
190+ .retype (elementSize , codecClassName )
191+ .withMetadata (length );
168192 }
169193 return array (
170194 backing ,
171195 offset ,
172196 elementSize ,
173- codecClassName );
197+ codecClassName ). withMetadata ( length ) ;
174198 } catch (ReflectiveOperationException error ) {
175199 throw new IllegalArgumentException ("invalid Rust slice view" , error );
176200 }
@@ -201,6 +225,17 @@ public static Pointer nullPointer() {
201225 return nullPointer (1 );
202226 }
203227
228+ public static Pointer traitMetadataMarker (Pointer pointer , String metadataClassName ) {
229+ Object value = pointer == null ? null : pointer .getObject ();
230+ String concreteClassName = value == null ? "<null>" : value .getClass ().getName ();
231+ String key = metadataClassName + '\0' + concreteClassName ;
232+ synchronized (TRAIT_METADATA_MARKERS ) {
233+ return TRAIT_METADATA_MARKERS .computeIfAbsent (
234+ key ,
235+ ignored -> cell (null , 0 , null ));
236+ }
237+ }
238+
204239 public static Pointer fromAddress (int address , int viewSize ) {
205240 return fromAddress (address , viewSize , null );
206241 }
@@ -218,7 +253,7 @@ public static Pointer fromAddress(int address, int viewSize, String viewCodecCla
218253 viewSize ,
219254 target .codecClassName ,
220255 viewCodecClassName ,
221- -1 );
256+ -1 ). withMetadata ( target . metadata ) ;
222257 }
223258 EXPOSED_ADDRESSES .remove (address );
224259 }
@@ -255,7 +290,7 @@ public static int managedObjectAddress(Object value) {
255290 if (existing != null ) {
256291 return existing .intValue ();
257292 }
258- int address = NEXT_ADDRESS . getAndAdd ( 16 );
293+ int address = allocateAddress ( 16 , 16 );
259294 MANAGED_OBJECT_ADDRESSES .put (value , address );
260295 MANAGED_OBJECTS .put (address , new WeakReference <>(value ));
261296 return address ;
@@ -295,7 +330,7 @@ private static Pointer pointerObjectFromAddress(int address) {
295330 target .viewSize ,
296331 target .codecClassName ,
297332 target .viewCodecClassName ,
298- -1 );
333+ -1 ). withMetadata ( target . metadata ) ;
299334 }
300335 EXPOSED_ADDRESSES .remove (address );
301336 }
@@ -329,7 +364,7 @@ public Pointer retype(int newViewSize, String newViewCodecClassName) {
329364 newViewSize ,
330365 allocationCodecClassName ,
331366 newViewCodecClassName ,
332- exposedAddress );
367+ exposedAddress ). withMetadata ( metadata ) ;
333368 if (newViewSize == 0 && newViewCodecClassName == null ) {
334369 if (viewSize == 0 && zeroSizedSourceViewSize >= 0 ) {
335370 result .zeroSizedSourceViewSize = zeroSizedSourceViewSize ;
@@ -360,7 +395,23 @@ public static Pointer restoreAllocationView(Pointer pointer) {
360395 pointer .allocationElementSize ,
361396 pointer .allocationCodecClassName ,
362397 pointer .allocationCodecClassName ,
363- pointer .exposedAddress );
398+ pointer .exposedAddress ).withMetadata (pointer .metadata );
399+ }
400+
401+ private Pointer withMetadata (int metadata ) {
402+ this .metadata = metadata ;
403+ return this ;
404+ }
405+
406+ public static Pointer withMetadata (Pointer pointer , int metadata ) {
407+ return pointer .withMetadata (metadata );
408+ }
409+
410+ public int metadata () {
411+ if (metadata < 0 ) {
412+ throw new IllegalStateException ("pointer does not carry dynamically sized metadata" );
413+ }
414+ return metadata ;
364415 }
365416
366417 public Pointer offset (int elementCount ) {
@@ -373,7 +424,7 @@ public Pointer offset(int elementCount) {
373424 viewSize ,
374425 allocationCodecClassName ,
375426 viewCodecClassName ,
376- Math .addExact (exposedAddress , delta ));
427+ Math .addExact (exposedAddress , delta )). withMetadata ( metadata ) ;
377428 }
378429 return new Pointer (
379430 allocation ,
@@ -382,7 +433,7 @@ public Pointer offset(int elementCount) {
382433 viewSize ,
383434 allocationCodecClassName ,
384435 viewCodecClassName ,
385- -1 );
436+ -1 ). withMetadata ( metadata ) ;
386437 }
387438
388439 public Pointer add (int elementCount ) {
@@ -414,7 +465,7 @@ public Pointer byte_offset(int byteCount) {
414465 viewSize ,
415466 allocationCodecClassName ,
416467 viewCodecClassName ,
417- Math .addExact (exposedAddress , byteCount ));
468+ Math .addExact (exposedAddress , byteCount )). withMetadata ( metadata ) ;
418469 }
419470 return new Pointer (
420471 allocation ,
@@ -423,7 +474,7 @@ public Pointer byte_offset(int byteCount) {
423474 viewSize ,
424475 allocationCodecClassName ,
425476 viewCodecClassName ,
426- -1 );
477+ -1 ). withMetadata ( metadata ) ;
427478 }
428479
429480 public static Pointer byte_offset (Pointer pointer , int byteCount ) {
@@ -459,7 +510,7 @@ private Pointer wrappingByteOffset(int byteCount) {
459510 viewSize ,
460511 allocationCodecClassName ,
461512 viewCodecClassName ,
462- exposedAddress + byteCount );
513+ exposedAddress + byteCount ). withMetadata ( metadata ) ;
463514 }
464515 return new Pointer (
465516 allocation ,
@@ -468,7 +519,7 @@ private Pointer wrappingByteOffset(int byteCount) {
468519 viewSize ,
469520 allocationCodecClassName ,
470521 viewCodecClassName ,
471- -1 );
522+ -1 ). withMetadata ( metadata ) ;
472523 }
473524
474525 public int align_offset (int alignment ) {
@@ -514,7 +565,7 @@ public Pointer with_addr(int address) {
514565 viewSize ,
515566 allocationCodecClassName ,
516567 viewCodecClassName ,
517- address );
568+ address ). withMetadata ( metadata ) ;
518569 }
519570 int base = address () - byteOffset ;
520571 return new Pointer (
@@ -524,7 +575,7 @@ public Pointer with_addr(int address) {
524575 viewSize ,
525576 allocationCodecClassName ,
526577 viewCodecClassName ,
527- -1 );
578+ -1 ). withMetadata ( metadata ) ;
528579 }
529580
530581 public static Pointer with_addr (Pointer pointer , int address ) {
@@ -572,7 +623,7 @@ private Pointer wrappingOffset(int elementCount) {
572623 viewSize ,
573624 allocationCodecClassName ,
574625 viewCodecClassName ,
575- exposedAddress + delta );
626+ exposedAddress + delta ). withMetadata ( metadata ) ;
576627 }
577628 return new Pointer (
578629 allocation ,
@@ -581,7 +632,7 @@ private Pointer wrappingOffset(int elementCount) {
581632 viewSize ,
582633 allocationCodecClassName ,
583634 viewCodecClassName ,
584- -1 );
635+ -1 ). withMetadata ( metadata ) ;
585636 }
586637
587638 public int offsetFrom (Pointer origin ) {
@@ -713,7 +764,8 @@ public int address() {
713764 : allocationElementSize ;
714765 int requiredSpan = Math .addExact (byteCapacity , 1 );
715766 int span = Math .max (16 , Math .addExact (requiredSpan , 15 ) & ~15 );
716- base = NEXT_ADDRESS .getAndAdd (span );
767+ int alignment = ALLOCATION_ALIGNMENTS .getOrDefault (allocation , 16 );
768+ base = allocateAddress (span , alignment );
717769 ALLOCATION_BASES .put (allocation , base );
718770 ALLOCATION_ELEMENT_SIZES .put (allocation , allocationElementSize );
719771 ALLOCATION_CODECS .put (allocation , allocationCodecClassName );
@@ -727,11 +779,23 @@ public int address() {
727779 byteOffset ,
728780 allocationCodecClassName ,
729781 viewSize ,
730- viewCodecClassName ));
782+ viewCodecClassName ,
783+ metadata ));
731784 return address ;
732785 }
733786 }
734787
788+ private static int allocateAddress (int span , int alignment ) {
789+ while (true ) {
790+ int current = NEXT_ADDRESS .get ();
791+ int aligned = Math .addExact (current , alignment - 1 ) & -alignment ;
792+ int next = Math .addExact (aligned , span );
793+ if (NEXT_ADDRESS .compareAndSet (current , next )) {
794+ return aligned ;
795+ }
796+ }
797+ }
798+
735799 private Object readAlignedElement () {
736800 if (allocation == null ) {
737801 throw new NullPointerException ("attempted to dereference a null Rust pointer" );
@@ -909,7 +973,7 @@ public Object getObject() {
909973 zeroSizedSourceViewSize ,
910974 allocationCodecClassName ,
911975 zeroSizedSourceViewCodecClassName ,
912- exposedAddress )
976+ exposedAddress ). withMetadata ( metadata )
913977 .getObject ();
914978 }
915979 if (MANAGED_OBJECT_VIEW_CODEC .equals (viewCodecClassName )
0 commit comments