46
46
import static com .oracle .graal .python .nodes .StringLiterals .J_GET_ ;
47
47
import static com .oracle .graal .python .nodes .StringLiterals .J_LLVM_LANGUAGE ;
48
48
import static com .oracle .graal .python .nodes .StringLiterals .J_TYPE_ID ;
49
- import static com .oracle .graal .python .util .PythonUtils .EMPTY_TRUFFLESTRING_ARRAY ;
50
49
import static com .oracle .graal .python .util .PythonUtils .tsArray ;
51
50
52
51
import java .io .IOException ;
53
- import java .lang .ref .Reference ;
54
- import java .lang .ref .ReferenceQueue ;
55
- import java .lang .ref .WeakReference ;
56
52
import java .util .ArrayList ;
57
53
import java .util .Arrays ;
58
54
import java .util .HashMap ;
59
55
import java .util .HashSet ;
60
- import java .util .List ;
61
56
import java .util .Map ;
62
57
import java .util .Objects ;
63
58
import java .util .concurrent .ConcurrentHashMap ;
64
59
import java .util .concurrent .atomic .AtomicLong ;
65
- import java .util .logging .Level ;
66
60
67
61
import org .graalvm .collections .EconomicMap ;
68
62
import org .graalvm .collections .Pair ;
75
69
import com .oracle .graal .python .builtins .modules .cext .PythonCextBuiltins .CApiCallPath ;
76
70
import com .oracle .graal .python .builtins .objects .PNone ;
77
71
import com .oracle .graal .python .builtins .objects .PNotImplemented ;
78
- import com .oracle .graal .python .builtins .objects .cext .PythonAbstractNativeObject ;
79
72
import com .oracle .graal .python .builtins .objects .cext .capi .CExtNodes .PCallCapiFunction ;
80
73
import com .oracle .graal .python .builtins .objects .cext .capi .CExtNodesFactory .CreateModuleNodeGen ;
81
74
import com .oracle .graal .python .builtins .objects .cext .capi .CExtNodesFactory .ToJavaNodeGen ;
82
75
import com .oracle .graal .python .builtins .objects .cext .capi .CExtNodesFactory .ToNewRefNodeGen ;
83
76
import com .oracle .graal .python .builtins .objects .cext .capi .DynamicObjectNativeWrapper .PrimitiveNativeWrapper ;
84
- import com .oracle .graal .python .builtins .objects .cext .capi .NativeObjectReferenceArrayWrapper .PointerArrayWrapper ;
85
- import com .oracle .graal .python .builtins .objects .cext .capi .NativeObjectReferenceArrayWrapper .RefCountArrayWrapper ;
86
77
import com .oracle .graal .python .builtins .objects .cext .capi .transitions .CApiTransitions ;
87
78
import com .oracle .graal .python .builtins .objects .cext .capi .transitions .CApiTransitions .HandleTester ;
88
79
import com .oracle .graal .python .builtins .objects .cext .capi .transitions .CApiTransitions .JavaStringToTruffleString ;
91
82
import com .oracle .graal .python .builtins .objects .cext .common .CExtContext ;
92
83
import com .oracle .graal .python .builtins .objects .cext .common .LoadCExtException .ApiInitException ;
93
84
import com .oracle .graal .python .builtins .objects .cext .common .LoadCExtException .ImportException ;
94
- import com .oracle .graal .python .builtins .objects .cext .common .ReferenceStack ;
95
85
import com .oracle .graal .python .builtins .objects .cext .hpy .GraalHPyContext ;
96
86
import com .oracle .graal .python .builtins .objects .dict .PDict ;
97
87
import com .oracle .graal .python .builtins .objects .ellipsis .PEllipsis ;
98
88
import com .oracle .graal .python .builtins .objects .frame .PFrame ;
99
- import com .oracle .graal .python .builtins .objects .function .PArguments ;
100
- import com .oracle .graal .python .builtins .objects .function .Signature ;
101
89
import com .oracle .graal .python .builtins .objects .method .PBuiltinMethod ;
102
90
import com .oracle .graal .python .builtins .objects .module .PythonModule ;
103
91
import com .oracle .graal .python .builtins .objects .thread .PLock ;
104
92
import com .oracle .graal .python .nodes .ErrorMessages ;
105
93
import com .oracle .graal .python .nodes .IndirectCallNode ;
106
94
import com .oracle .graal .python .nodes .PRaiseNode ;
107
- import com .oracle .graal .python .nodes .PRootNode ;
108
95
import com .oracle .graal .python .nodes .call .CallNode ;
109
- import com .oracle .graal .python .nodes .call .GenericInvokeNode ;
110
96
import com .oracle .graal .python .nodes .object .InlinedGetClassNodeGen ;
111
- import com .oracle .graal .python .runtime .AsyncHandler ;
112
- import com .oracle .graal .python .runtime .ExecutionContext .CalleeContext ;
113
97
import com .oracle .graal .python .runtime .ExecutionContext .IndirectCallContext ;
114
98
import com .oracle .graal .python .runtime .PythonContext ;
115
99
import com .oracle .graal .python .runtime .PythonContext .GetThreadStateNode ;
@@ -157,24 +141,18 @@ public final class CApiContext extends CExtContext {
157
141
*/
158
142
static final CApiContext LAZY_CONTEXT = new CApiContext ();
159
143
160
- public static final long REFERENCE_COUNT_BITS = Integer .SIZE ;
161
- public static final long REFERENCE_COUNT_MARKER = (1L << REFERENCE_COUNT_BITS );
162
144
/* a random number between 1 and 20 */
163
145
private static final int MAX_COLLECTION_RETRIES = 17 ;
164
146
165
147
/** Total amount of allocated native memory (in bytes). */
166
148
private long allocatedMemory = 0 ;
167
149
168
- private final ReferenceQueue <Object > nativeObjectsQueue ;
169
150
private Map <Object , AllocInfo > allocatedNativeMemory ;
170
- private final ReferenceStack <NativeObjectReference > nativeObjectWrapperList ;
171
151
private TraceMallocDomain [] traceMallocDomains ;
172
152
173
153
/** Container of pointers that have seen to be free'd. */
174
154
private Map <Object , AllocInfo > freedNativeMemory ;
175
155
176
- @ CompilationFinal private RootCallTarget referenceCleanerCallTarget ;
177
-
178
156
/**
179
157
* This cache is used to cache native wrappers for frequently used primitives. This is strictly
180
158
* defined to be the range {@code [-5, 256]}. CPython does exactly the same (see
@@ -226,20 +204,12 @@ public static TruffleLogger getLogger(Class<?> clazz) {
226
204
*/
227
205
private CApiContext () {
228
206
super (null , null , null );
229
- nativeObjectsQueue = null ;
230
- nativeObjectWrapperList = null ;
231
207
primitiveNativeWrapperCache = null ;
232
208
llvmTypeCache = null ;
233
209
}
234
210
235
211
public CApiContext (PythonContext context , Object hpyLibrary ) {
236
212
super (context , hpyLibrary , CAPIConversionNodeSupplier .INSTANCE );
237
- nativeObjectsQueue = new ReferenceQueue <>();
238
- nativeObjectWrapperList = new ReferenceStack <>();
239
-
240
- // avoid 0 to be used as ID
241
- int nullID = nativeObjectWrapperList .reserve ();
242
- assert nullID == 0 ;
243
213
244
214
// initialize primitive and pointer type cache
245
215
llvmTypeCache = new Object [LLVMType .values ().length ];
@@ -251,34 +221,6 @@ public CApiContext(PythonContext context, Object hpyLibrary) {
251
221
CApiTransitions .incRef (nativeWrapper , PythonNativeWrapper .IMMORTAL_REFCNT );
252
222
primitiveNativeWrapperCache [i ] = nativeWrapper ;
253
223
}
254
-
255
- context .registerAsyncAction (() -> {
256
- Reference <?> reference = null ;
257
- if (PythonOptions .AUTOMATIC_ASYNC_ACTIONS ) {
258
- try {
259
- reference = nativeObjectsQueue .remove ();
260
- } catch (InterruptedException e ) {
261
- Thread .currentThread ().interrupt ();
262
- }
263
- } else {
264
- reference = nativeObjectsQueue .poll ();
265
- }
266
-
267
- ArrayList <NativeObjectReference > refs = new ArrayList <>();
268
- do {
269
- if (reference instanceof NativeObjectReference ) {
270
- refs .add ((NativeObjectReference ) reference );
271
- }
272
- // consume all
273
- reference = nativeObjectsQueue .poll ();
274
- } while (reference != null );
275
-
276
- if (!refs .isEmpty ()) {
277
- return new CApiReferenceCleanerAction (refs .toArray (new NativeObjectReference [0 ]));
278
- }
279
-
280
- return null ;
281
- });
282
224
}
283
225
284
226
public int getPyLongBitsInDigit () {
@@ -325,14 +267,6 @@ public static Object asPointer(Object ptr, InteropLibrary lib) {
325
267
return ptr ;
326
268
}
327
269
328
- private RootCallTarget getReferenceCleanerCallTarget () {
329
- if (referenceCleanerCallTarget == null ) {
330
- CompilerDirectives .transferToInterpreterAndInvalidate ();
331
- referenceCleanerCallTarget = PythonLanguage .get (null ).createCachedCallTarget (l -> new CApiReferenceCleanerRootNode (l ), CApiReferenceCleanerRootNode .class );
332
- }
333
- return referenceCleanerCallTarget ;
334
- }
335
-
336
270
public TraceMallocDomain getTraceMallocDomain (int domainIdx ) {
337
271
return traceMallocDomains [domainIdx ];
338
272
}
@@ -413,185 +347,6 @@ public Object getModuleByIndex(int i) {
413
347
return null ;
414
348
}
415
349
416
- static class NativeObjectReference extends WeakReference <PythonAbstractNativeObject > {
417
-
418
- /**
419
- * The associated native pointer object that needs to be released if this reference dies.
420
- */
421
- final Object ptrObject ;
422
-
423
- /** The ID of this reference, i.e., the index of the ref in the global reference list. */
424
- final int id ;
425
-
426
- /**
427
- * If {@code true}, the native object should not be released because a new managed ref was
428
- * created.
429
- */
430
- boolean resurrect ;
431
-
432
- /**
433
- * When stealing references, this is the number of stolen reference counts (need to be
434
- * subtracted in the end).
435
- */
436
- long managedRefCount ;
437
-
438
- public NativeObjectReference (PythonAbstractNativeObject referent , ReferenceQueue <? super PythonAbstractNativeObject > q , long managedRefCount , int id ) {
439
- super (referent , q );
440
- this .ptrObject = referent .getPtr ();
441
- this .managedRefCount = managedRefCount ;
442
- this .id = id ;
443
- }
444
-
445
- public Object getPtrObject () {
446
- return ptrObject ;
447
- }
448
-
449
- public void markAsResurrected () {
450
- resurrect = true ;
451
- }
452
- }
453
-
454
- /**
455
- * Simple root node that executes a reference decrease.
456
- */
457
- private static final class CApiReferenceCleanerRootNode extends PRootNode {
458
- private static final Signature SIGNATURE = new Signature (-1 , false , -1 , false , tsArray ("ptr" , "managedRefCount" ), EMPTY_TRUFFLESTRING_ARRAY );
459
- private static final TruffleLogger LOGGER = CApiContext .getLogger (CApiReferenceCleanerRootNode .class );
460
-
461
- @ Child private CalleeContext calleeContext ;
462
- @ Child private InteropLibrary pointerObjectLib ;
463
- @ Child private PCallCapiFunction callBulkSubref ;
464
-
465
- protected CApiReferenceCleanerRootNode (PythonLanguage language ) {
466
- super (language );
467
- this .calleeContext = CalleeContext .create ();
468
- this .callBulkSubref = PCallCapiFunction .create ();
469
- }
470
-
471
- @ Override
472
- public Object execute (VirtualFrame frame ) {
473
- calleeContext .enter (frame );
474
- try {
475
- NativeObjectReference [] nativeObjectReferences = (NativeObjectReference []) PArguments .getArgument (frame , 0 );
476
- int cleaned = 0 ;
477
- CApiContext cApiContext = PythonContext .get (this ).getCApiContext ();
478
- long allocatedNativeMem = cApiContext .allocatedMemory ;
479
- long startTime = 0 ;
480
- long middleTime = 0 ;
481
- final int n = nativeObjectReferences .length ;
482
- boolean loggable = LOGGER .isLoggable (Level .FINE );
483
-
484
- if (loggable ) {
485
- startTime = System .currentTimeMillis ();
486
- }
487
-
488
- /*
489
- * Note about the order of operations - we need to call the finalizers first before
490
- * removing the objects from the wrapper list because the finalizers may still make
491
- * upcalls and those need the wrappers to work correctly.
492
- */
493
-
494
- callBulkSubref .call (NativeCAPISymbol .FUN_BULK_SUBREF , new PointerArrayWrapper (nativeObjectReferences ), new RefCountArrayWrapper (nativeObjectReferences ), (long ) n );
495
-
496
- if (loggable ) {
497
- middleTime = System .currentTimeMillis ();
498
- }
499
-
500
- if (LOGGER .isLoggable (Level .FINER )) {
501
- // it's not an OSR loop, so we do this before the loop
502
- if (n > 0 && pointerObjectLib == null ) {
503
- CompilerDirectives .transferToInterpreterAndInvalidate ();
504
- pointerObjectLib = insert (InteropLibrary .getFactory ().create (nativeObjectReferences [0 ].ptrObject ));
505
- }
506
-
507
- for (int i = 0 ; i < n ; i ++) {
508
- NativeObjectReference nativeObjectReference = nativeObjectReferences [i ];
509
- Object pointerObject = nativeObjectReference .ptrObject ;
510
- if (!nativeObjectReference .resurrect ) {
511
- cApiContext .nativeObjectWrapperList .remove (nativeObjectReference .id );
512
- if (!nativeObjectReference .resurrect && !pointerObjectLib .isNull (pointerObject )) {
513
- cApiContext .checkAccess (pointerObject , pointerObjectLib );
514
- LOGGER .finer (() -> "Cleaning native object reference to " + CApiContext .asHex (pointerObject ));
515
- cleaned ++;
516
- }
517
- }
518
- }
519
- } else {
520
- for (int i = 0 ; i < n ; i ++) {
521
- NativeObjectReference nativeObjectReference = nativeObjectReferences [i ];
522
- if (!nativeObjectReference .resurrect ) {
523
- cApiContext .nativeObjectWrapperList .remove (nativeObjectReference .id );
524
- }
525
- }
526
- }
527
-
528
- if (loggable ) {
529
- final long countDuration = System .currentTimeMillis () - middleTime ;
530
- final long duration = middleTime - startTime ;
531
- final int finalCleaned = cleaned ;
532
- final long freedNativeMemory = allocatedNativeMem - cApiContext .allocatedMemory ;
533
- LOGGER .fine (() -> "Total queued references: " + n );
534
- LOGGER .fine (() -> "Cleaned references: " + finalCleaned );
535
- LOGGER .fine (() -> "Free'd native memory: " + freedNativeMemory );
536
- LOGGER .fine (() -> "Count duration: " + countDuration );
537
- LOGGER .fine (() -> "Duration: " + duration );
538
- }
539
- } finally {
540
- calleeContext .exit (frame , this );
541
- }
542
- return PNone .NONE ;
543
- }
544
-
545
- @ Override
546
- public Signature getSignature () {
547
- return SIGNATURE ;
548
- }
549
-
550
- @ Override
551
- public String getName () {
552
- return "native_reference_cleaner" ;
553
- }
554
-
555
- @ Override
556
- public boolean isInternal () {
557
- return false ;
558
- }
559
-
560
- @ Override
561
- public boolean isPythonInternal () {
562
- return false ;
563
- }
564
- }
565
-
566
- /**
567
- * Reference cleaner action that will be executed by the {@link AsyncHandler}.
568
- */
569
- private static final class CApiReferenceCleanerAction implements AsyncHandler .AsyncAction {
570
-
571
- private final NativeObjectReference [] nativeObjectReferences ;
572
-
573
- public CApiReferenceCleanerAction (NativeObjectReference [] nativeObjectReferences ) {
574
- this .nativeObjectReferences = nativeObjectReferences ;
575
- }
576
-
577
- @ Override
578
- public void execute (PythonContext context ) {
579
- Object [] pArguments = PArguments .create (1 );
580
- PArguments .setArgument (pArguments , 0 , nativeObjectReferences );
581
- GenericInvokeNode .getUncached ().execute (context .getCApiContext ().getReferenceCleanerCallTarget (), pArguments );
582
- }
583
- }
584
-
585
- public NativeObjectReference lookupNativeObjectReference (int idx ) {
586
- return nativeObjectWrapperList .get (idx );
587
- }
588
-
589
- static long idToRefCnt (int id ) {
590
- long nativeRefCnt = (long ) id << REFERENCE_COUNT_BITS ;
591
- assert nativeRefCnt >= REFERENCE_COUNT_MARKER ;
592
- return nativeRefCnt ;
593
- }
594
-
595
350
@ TruffleBoundary
596
351
public AllocInfo traceFree (Object ptr , @ SuppressWarnings ("unused" ) PFrame .Reference curFrame , @ SuppressWarnings ("unused" ) TruffleString clazzName ) {
597
352
if (allocatedNativeMemory == null ) {
@@ -728,32 +483,6 @@ public void checkAccess(Object pointerObject, InteropLibrary lib) {
728
483
}
729
484
}
730
485
731
- /**
732
- * Internal method for debugging purposes. This method looks up how many phantom references are
733
- * currently in the escaped references list. This is useful to check if the current reference
734
- * count of a native object is consistent with the upcoming decrements.
735
- */
736
- @ SuppressWarnings ("unused" )
737
- public List <Integer > containsAddress (long l ) {
738
- CompilerAsserts .neverPartOfCompilation ();
739
- int i = 0 ;
740
- List <Integer > indx = new ArrayList <>();
741
- InteropLibrary lib = InteropLibrary .getFactory ().getUncached ();
742
- for (NativeObjectReference nor : nativeObjectWrapperList ) {
743
- Object obj = nor .ptrObject ;
744
-
745
- try {
746
- if (lib .isPointer (obj ) && lib .asPointer (obj ) == l ) {
747
- indx .add (i );
748
- }
749
- } catch (UnsupportedMessageException e ) {
750
- // ignore
751
- }
752
- i ++;
753
- }
754
- return indx ;
755
- }
756
-
757
486
public static final class AllocInfo {
758
487
public final TruffleString typeName ;
759
488
public final PFrame .Reference allocationSite ;
0 commit comments