20
20
import org .truffleruby .cext .ValueWrapperManagerFactory .AllocateHandleNodeGen ;
21
21
import org .truffleruby .cext .ValueWrapperManagerFactory .GetHandleBlockHolderNodeGen ;
22
22
import org .truffleruby .extra .ffi .Pointer ;
23
+ import org .truffleruby .language .ImmutableRubyObject ;
23
24
import org .truffleruby .language .NotProvided ;
24
25
import org .truffleruby .language .RubyBaseNode ;
25
26
26
27
import com .oracle .truffle .api .CompilerDirectives .TruffleBoundary ;
27
28
import com .oracle .truffle .api .dsl .Cached ;
28
29
import com .oracle .truffle .api .dsl .CachedContext ;
30
+ import com .oracle .truffle .api .dsl .CachedLanguage ;
29
31
import com .oracle .truffle .api .dsl .GenerateUncached ;
30
32
import com .oracle .truffle .api .dsl .Specialization ;
31
33
import com .oracle .truffle .api .interop .InteropLibrary ;
37
39
public class ValueWrapperManager {
38
40
39
41
static final long UNSET_HANDLE = -2L ;
40
- static final HandleBlockAllocator allocator = new HandleBlockAllocator ();
41
42
42
43
/* These constants are taken from ruby.h, and are based on us not tagging doubles. */
43
44
@@ -74,6 +75,7 @@ public HandleThreadData makeThreadData() {
74
75
HandleThreadData threadData = new HandleThreadData ();
75
76
HandleBlockHolder holder = threadData .holder ;
76
77
context .getFinalizationService ().addFinalizer (
78
+ context ,
77
79
threadData ,
78
80
ValueWrapperManager .class ,
79
81
() -> context .getMarkingService ().queueForMarking (holder .handleBlock ),
@@ -102,46 +104,88 @@ public ValueWrapper doubleWrapper(double value) {
102
104
}
103
105
104
106
@ TruffleBoundary
105
- public synchronized void addToBlockMap (HandleBlock block ) {
107
+ public synchronized void addToBlockMap (HandleBlock block , RubyLanguage language ) {
106
108
int blockIndex = block .getIndex ();
107
109
long blockBase = block .getBase ();
108
- HandleBlockWeakReference [] map = blockMap ;
109
- HandleBlockAllocator allocator = ValueWrapperManager .allocator ;
110
- boolean grow = false ;
111
- if (blockIndex + 1 > map .length ) {
112
- final HandleBlockWeakReference [] copy = new HandleBlockWeakReference [blockIndex + 1 ];
113
- System .arraycopy (map , 0 , copy , 0 , map .length );
114
- map = copy ;
115
- grow = true ;
116
- }
110
+ HandleBlockAllocator allocator = language .handleBlockAllocator ;
111
+ HandleBlockWeakReference [] map = growMapIfRequired (blockMap , blockIndex );
112
+ blockMap = map ;
117
113
map [blockIndex ] = new HandleBlockWeakReference (block );
118
- if (grow ) {
119
- blockMap = map ;
120
- }
121
114
122
- context .getFinalizationService ().addFinalizer (block , ValueWrapperManager .class , () -> {
115
+ context .getFinalizationService ().addFinalizer (context , block , ValueWrapperManager .class , () -> {
123
116
this .blockMap [blockIndex ] = null ;
124
117
allocator .addFreeBlock (blockBase );
125
118
}, null );
126
119
}
127
120
128
- public ValueWrapper getWrapperFromHandleMap (long handle ) {
121
+ @ TruffleBoundary
122
+ public void addToSharedBlockMap (HandleBlock block , RubyLanguage language ) {
123
+ synchronized (language ) {
124
+ int blockIndex = block .getIndex ();
125
+ long blockBase = block .getBase ();
126
+ HandleBlockAllocator allocator = language .handleBlockAllocator ;
127
+ HandleBlockWeakReference [] map = growMapIfRequired (language .handleBlockSharedMap , blockIndex );
128
+ language .handleBlockSharedMap = map ;
129
+ map [blockIndex ] = new HandleBlockWeakReference (block );
130
+
131
+ language .sharedFinzationService .addFinalizer (context , block , ValueWrapperManager .class , () -> {
132
+ language .handleBlockSharedMap [blockIndex ] = null ;
133
+ allocator .addFreeBlock (blockBase );
134
+ }, null );
135
+ }
136
+ }
137
+
138
+ private static HandleBlockWeakReference [] growMapIfRequired (HandleBlockWeakReference [] map , int blockIndex ) {
139
+ if (blockIndex + 1 > map .length ) {
140
+ final HandleBlockWeakReference [] copy = new HandleBlockWeakReference [blockIndex + 1 ];
141
+ System .arraycopy (map , 0 , copy , 0 , map .length );
142
+ map = copy ;
143
+ }
144
+ return map ;
145
+ }
146
+
147
+ public ValueWrapper getWrapperFromHandleMap (long handle , RubyLanguage language ) {
129
148
final int index = HandleBlock .getHandleIndex (handle );
149
+ final HandleBlock block = getBlockFromMap (index , language );
150
+ if (block == null ) {
151
+ return null ;
152
+ }
153
+ return block .getWrapper (handle );
154
+ }
155
+
156
+ private HandleBlock getBlockFromMap (int index , RubyLanguage language ) {
130
157
final HandleBlockWeakReference [] blockMap = this .blockMap ;
131
- final HandleBlockWeakReference ref ;
158
+ final HandleBlockWeakReference [] sharedMap = language .handleBlockSharedMap ;
159
+ HandleBlockWeakReference ref = null ;
160
+ // First try getting the block from the context's map
132
161
if (index >= 0 && index < blockMap .length ) {
133
162
ref = blockMap [index ];
134
- } else {
135
- return null ;
163
+ }
164
+ // If no block was found in the context's map then look in the
165
+ // shared map. If there is a block in a context's map then the
166
+ // same block will not be in the shared map and vice versa.
167
+ if (ref == null && index >= 0 && index < sharedMap .length ) {
168
+ ref = sharedMap [index ];
136
169
}
137
170
if (ref == null ) {
138
171
return null ;
139
172
}
140
- final HandleBlock block = ref .get ();
141
- if (block == null ) {
142
- return null ;
173
+ return ref .get ();
174
+ }
175
+
176
+ public void freeAllBlocksInMap (RubyLanguage language ) {
177
+ HandleBlockWeakReference [] map = blockMap ;
178
+ HandleBlockAllocator allocator = language .handleBlockAllocator ;
179
+
180
+ for (HandleBlockWeakReference ref : map ) {
181
+ if (ref == null ) {
182
+ continue ;
183
+ }
184
+ HandleBlock block = ref .get ();
185
+ if (block != null ) {
186
+ allocator .addFreeBlock (block .base );
187
+ }
143
188
}
144
- return block .getWrapper (handle );
145
189
}
146
190
147
191
protected static class FreeHandleBlock {
@@ -171,7 +215,7 @@ public long totalHandleAllocations() {
171
215
private static final long OFFSET_MASK = ~BLOCK_MASK ;
172
216
public static final long ALLOCATION_BASE = 0x0badL << 48 ;
173
217
174
- protected static class HandleBlockAllocator {
218
+ public static class HandleBlockAllocator {
175
219
176
220
private long nextBlock = ALLOCATION_BASE ;
177
221
private FreeHandleBlock firstFreeBlock = null ;
@@ -203,7 +247,7 @@ public static class HandleBlock {
203
247
@ SuppressWarnings ("rawtypes" ) private final ValueWrapper [] wrappers ;
204
248
private int count ;
205
249
206
- public HandleBlock (RubyContext context ) {
250
+ public HandleBlock (RubyContext context , HandleBlockAllocator allocator ) {
207
251
this (context , allocator .getFreeBlock (), new ValueWrapper [BLOCK_SIZE ]);
208
252
}
209
253
@@ -251,14 +295,15 @@ public static int getHandleIndex(long handle) {
251
295
}
252
296
}
253
297
254
- protected static final class HandleBlockWeakReference extends WeakReference <HandleBlock > {
298
+ public static final class HandleBlockWeakReference extends WeakReference <HandleBlock > {
255
299
HandleBlockWeakReference (HandleBlock referent ) {
256
300
super (referent );
257
301
}
258
302
}
259
303
260
304
protected static class HandleBlockHolder {
261
305
protected HandleBlock handleBlock = null ;
306
+ protected HandleBlock sharedHandleBlock = null ;
262
307
}
263
308
264
309
protected static class HandleThreadData {
@@ -269,8 +314,16 @@ public HandleBlock currentBlock() {
269
314
return holder .handleBlock ;
270
315
}
271
316
272
- public HandleBlock makeNewBlock (RubyContext context ) {
273
- return (holder .handleBlock = new HandleBlock (context ));
317
+ public HandleBlock currentSharedBlock () {
318
+ return holder .sharedHandleBlock ;
319
+ }
320
+
321
+ public HandleBlock makeNewBlock (RubyContext context , HandleBlockAllocator allocator ) {
322
+ return (holder .handleBlock = new HandleBlock (context , allocator ));
323
+ }
324
+
325
+ public HandleBlock makeNewSharedBlock (RubyContext context , HandleBlockAllocator allocator ) {
326
+ return (holder .sharedHandleBlock = new HandleBlock (context , allocator ));
274
327
}
275
328
}
276
329
@@ -311,12 +364,31 @@ public abstract static class AllocateHandleNode extends RubyBaseNode {
311
364
312
365
public abstract long execute (ValueWrapper wrapper );
313
366
314
- @ Specialization
367
+ @ Specialization ( guards = "!isSharedObject(wrapper)" )
315
368
protected long allocateHandleOnKnownThread (ValueWrapper wrapper ,
316
369
@ CachedContext (RubyLanguage .class ) RubyContext context ,
370
+ @ CachedLanguage RubyLanguage language ,
317
371
@ Cached GetHandleBlockHolderNode getBlockHolderNode ) {
318
- HandleThreadData threadData = getBlockHolderNode .execute (wrapper );
319
- HandleBlock block = threadData .holder .handleBlock ;
372
+ return allocateHandle (wrapper , context , language , getBlockHolderNode .execute (wrapper ), false );
373
+ }
374
+
375
+ @ Specialization (guards = "isSharedObject(wrapper)" )
376
+ protected long allocateSharedHandleOnKnownThread (ValueWrapper wrapper ,
377
+ @ CachedContext (RubyLanguage .class ) RubyContext context ,
378
+ @ CachedLanguage RubyLanguage language ,
379
+ @ Cached GetHandleBlockHolderNode getBlockHolderNode ) {
380
+ return allocateHandle (wrapper , context , language , getBlockHolderNode .execute (wrapper ), true );
381
+ }
382
+
383
+ protected static long allocateHandle (ValueWrapper wrapper , RubyContext context , RubyLanguage language ,
384
+ HandleThreadData threadData , boolean shared ) {
385
+ HandleBlock block ;
386
+ if (shared ) {
387
+ block = threadData .holder .sharedHandleBlock ;
388
+ } else {
389
+ block = threadData .holder .handleBlock ;
390
+ }
391
+
320
392
if (context .getOptions ().CEXTS_TO_NATIVE_STATS ) {
321
393
context .getValueWrapperManager ().recordHandleAllocation ();
322
394
}
@@ -325,12 +397,24 @@ protected long allocateHandleOnKnownThread(ValueWrapper wrapper,
325
397
if (block != null ) {
326
398
context .getMarkingService ().queueForMarking (block );
327
399
}
328
- block = threadData .makeNewBlock (context );
329
- context .getValueWrapperManager ().addToBlockMap (block );
400
+ if (shared ) {
401
+ block = threadData
402
+ .makeNewSharedBlock (context , language .handleBlockAllocator );
403
+ context .getValueWrapperManager ().addToSharedBlockMap (block , language );
404
+ } else {
405
+ block = threadData
406
+ .makeNewBlock (context , language .handleBlockAllocator );
407
+ context .getValueWrapperManager ().addToBlockMap (block , language );
408
+ }
409
+
330
410
}
331
411
return block .setHandleOnWrapper (wrapper );
332
412
}
333
413
414
+ protected static boolean isSharedObject (ValueWrapper wrapper ) {
415
+ return wrapper .getObject () instanceof ImmutableRubyObject ;
416
+ }
417
+
334
418
public static AllocateHandleNode create () {
335
419
return AllocateHandleNodeGen .create ();
336
420
}
0 commit comments