@@ -127,6 +127,17 @@ public interface ByValue { }
127
127
*/
128
128
public interface ByReference { }
129
129
130
+ /** A class to keep NativeString instances alive and avoid writing the same value again and again */
131
+ private static class NativeStringTracking {
132
+
133
+ private final Object value ;
134
+ private NativeString peer ;
135
+
136
+ NativeStringTracking (Object lastValue ) {
137
+ this .value = lastValue ;
138
+ }
139
+ }
140
+
130
141
/** Use the platform default alignment. */
131
142
public static final int ALIGN_DEFAULT = 0 ;
132
143
/** No alignment, place all fields on nearest 1-byte boundary */
@@ -157,7 +168,7 @@ public interface ByReference { }
157
168
private Map <String , StructField > structFields ;
158
169
// Keep track of native C strings which have been allocated,
159
170
// corresponding to String fields of this Structure
160
- private final Map <String , Object > nativeStrings = new HashMap <String , Object >( );
171
+ private final Map <String , NativeStringTracking > nativeStrings = new HashMap <String , NativeStringTracking >( 8 );
161
172
private TypeMapper typeMapper ;
162
173
// This field is accessed by native code
163
174
private long typeInfo ;
@@ -343,14 +354,15 @@ void useMemory(Pointer m, int offset, boolean force) {
343
354
this .memory .write (0 , buf , 0 , buf .length );
344
355
}
345
356
else {
346
- // Ensure our memory pointer is initialized, even if we can't
347
- // yet figure out a proper size/layout
348
- this .memory = m .share (offset );
349
357
if (size == CALCULATE_SIZE ) {
350
358
size = calculateSize (false );
351
359
}
352
360
if (size != CALCULATE_SIZE ) {
353
361
this .memory = m .share (offset , size );
362
+ } else {
363
+ // Ensure our memory pointer is initialized, even if we can't
364
+ // yet figure out a proper size/layout
365
+ this .memory = m .share (offset );
354
366
}
355
367
}
356
368
this .array = null ;
@@ -438,6 +450,8 @@ public int size() {
438
450
/** Clears the native memory associated with this Structure. */
439
451
public void clear () {
440
452
ensureAllocated ();
453
+ // ensure the memory is released and the values are written again
454
+ nativeStrings .clear ();
441
455
memory .clear (size ());
442
456
}
443
457
@@ -508,8 +522,9 @@ public boolean add(Structure o) {
508
522
if (!contains (o )) {
509
523
ensureCapacity (count +1 );
510
524
elements [count ++] = o ;
525
+ return true ;
511
526
}
512
- return true ;
527
+ return false ;
513
528
}
514
529
private int indexOf (Structure s1 ) {
515
530
for (int i =0 ;i < count ;i ++) {
@@ -579,10 +594,9 @@ public void read() {
579
594
ensureAllocated ();
580
595
581
596
// Avoid redundant reads
582
- if (busy ().contains (this )) {
597
+ if (! busy ().add (this )) {
583
598
return ;
584
599
}
585
- busy ().add (this );
586
600
if (this instanceof Structure .ByReference ) {
587
601
reading ().put (getPointer (), this );
588
602
}
@@ -593,7 +607,7 @@ public void read() {
593
607
}
594
608
finally {
595
609
busy ().remove (this );
596
- if (reading ().get (getPointer ()) == this ) {
610
+ if (this instanceof Structure . ByReference && reading ().get (getPointer ()) == this ) {
597
611
reading ().remove (getPointer ());
598
612
}
599
613
}
@@ -740,8 +754,18 @@ protected Object readField(StructField structField) {
740
754
741
755
if (fieldType .equals (String .class )
742
756
|| fieldType .equals (WString .class )) {
743
- nativeStrings .put (structField .name + ".ptr" , memory .getPointer (offset ));
744
- nativeStrings .put (structField .name + ".val" , result );
757
+ if (result != null ) {
758
+ NativeStringTracking current = new NativeStringTracking (result );
759
+ NativeStringTracking previous = nativeStrings .put (structField .name , current );
760
+
761
+ if (previous != null ) {
762
+ // regardless of value changed or not, keep the old native string alive
763
+ current .peer = previous .peer ;
764
+ }
765
+ } else {
766
+ // the value is cleared, we don't need to keep the native string alive
767
+ nativeStrings .remove (structField .name );
768
+ }
745
769
}
746
770
747
771
// Update the value on the Java field
@@ -769,10 +793,9 @@ public void write() {
769
793
}
770
794
771
795
// Avoid redundant writes
772
- if (busy ().contains (this )) {
796
+ if (! busy ().add (this )) {
773
797
return ;
774
798
}
775
- busy ().add (this );
776
799
try {
777
800
// Write all fields, except those marked 'volatile'
778
801
for (StructField sf : fields ().values ()) {
@@ -840,28 +863,29 @@ protected void writeField(StructField structField) {
840
863
// Java strings get converted to C strings, where a Pointer is used
841
864
if (String .class == fieldType
842
865
|| WString .class == fieldType ) {
843
- // Allocate a new string in memory
844
- boolean wide = fieldType == WString .class ;
845
866
if (value != null ) {
867
+ NativeStringTracking current = new NativeStringTracking (value );
868
+ NativeStringTracking previous = nativeStrings .put (structField .name , current );
869
+
846
870
// If we've already allocated a native string here, and the
847
871
// string value is unchanged, leave it alone
848
- if (nativeStrings .containsKey (structField .name + ".ptr" )
849
- && value .equals (nativeStrings .get (structField .name + ".val" ))) {
872
+ if (previous != null && value .equals (previous .value )) {
873
+ // value is unchanged, keep the old native string alive
874
+ current .peer = previous .peer ;
850
875
return ;
851
876
}
877
+ // Allocate a new string in memory
878
+ boolean wide = fieldType == WString .class ;
852
879
NativeString nativeString = wide
853
880
? new NativeString (value .toString (), true )
854
881
: new NativeString (value .toString (), encoding );
855
- // Keep track of allocated C strings to avoid
856
- // premature garbage collection of the memory.
857
- nativeStrings .put (structField .name , nativeString );
882
+ // value is changed, keep the new native string alive
883
+ current .peer = nativeString ;
858
884
value = nativeString .getPointer ();
859
885
}
860
886
else {
861
887
nativeStrings .remove (structField .name );
862
888
}
863
- nativeStrings .remove (structField .name + ".ptr" );
864
- nativeStrings .remove (structField .name + ".val" );
865
889
}
866
890
867
891
try {
0 commit comments