4646import static com .oracle .graal .python .nodes .StringLiterals .J_GET_ ;
4747import static com .oracle .graal .python .nodes .StringLiterals .J_LLVM_LANGUAGE ;
4848import static com .oracle .graal .python .nodes .StringLiterals .J_TYPE_ID ;
49- import static com .oracle .graal .python .util .PythonUtils .EMPTY_TRUFFLESTRING_ARRAY ;
5049import static com .oracle .graal .python .util .PythonUtils .tsArray ;
5150
5251import java .io .IOException ;
53- import java .lang .ref .Reference ;
54- import java .lang .ref .ReferenceQueue ;
55- import java .lang .ref .WeakReference ;
5652import java .util .ArrayList ;
5753import java .util .Arrays ;
5854import java .util .HashMap ;
5955import java .util .HashSet ;
60- import java .util .List ;
6156import java .util .Map ;
6257import java .util .Objects ;
6358import java .util .concurrent .ConcurrentHashMap ;
6459import java .util .concurrent .atomic .AtomicLong ;
65- import java .util .logging .Level ;
6660
6761import org .graalvm .collections .EconomicMap ;
6862import org .graalvm .collections .Pair ;
7569import com .oracle .graal .python .builtins .modules .cext .PythonCextBuiltins .CApiCallPath ;
7670import com .oracle .graal .python .builtins .objects .PNone ;
7771import com .oracle .graal .python .builtins .objects .PNotImplemented ;
78- import com .oracle .graal .python .builtins .objects .cext .PythonAbstractNativeObject ;
7972import com .oracle .graal .python .builtins .objects .cext .capi .CExtNodes .PCallCapiFunction ;
8073import com .oracle .graal .python .builtins .objects .cext .capi .CExtNodesFactory .CreateModuleNodeGen ;
8174import com .oracle .graal .python .builtins .objects .cext .capi .CExtNodesFactory .ToJavaNodeGen ;
8275import com .oracle .graal .python .builtins .objects .cext .capi .CExtNodesFactory .ToNewRefNodeGen ;
8376import 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 ;
8677import com .oracle .graal .python .builtins .objects .cext .capi .transitions .CApiTransitions ;
8778import com .oracle .graal .python .builtins .objects .cext .capi .transitions .CApiTransitions .HandleTester ;
8879import com .oracle .graal .python .builtins .objects .cext .capi .transitions .CApiTransitions .JavaStringToTruffleString ;
9182import com .oracle .graal .python .builtins .objects .cext .common .CExtContext ;
9283import com .oracle .graal .python .builtins .objects .cext .common .LoadCExtException .ApiInitException ;
9384import com .oracle .graal .python .builtins .objects .cext .common .LoadCExtException .ImportException ;
94- import com .oracle .graal .python .builtins .objects .cext .common .ReferenceStack ;
9585import com .oracle .graal .python .builtins .objects .cext .hpy .GraalHPyContext ;
9686import com .oracle .graal .python .builtins .objects .dict .PDict ;
9787import com .oracle .graal .python .builtins .objects .ellipsis .PEllipsis ;
9888import 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 ;
10189import com .oracle .graal .python .builtins .objects .method .PBuiltinMethod ;
10290import com .oracle .graal .python .builtins .objects .module .PythonModule ;
10391import com .oracle .graal .python .builtins .objects .thread .PLock ;
10492import com .oracle .graal .python .nodes .ErrorMessages ;
10593import com .oracle .graal .python .nodes .IndirectCallNode ;
10694import com .oracle .graal .python .nodes .PRaiseNode ;
107- import com .oracle .graal .python .nodes .PRootNode ;
10895import com .oracle .graal .python .nodes .call .CallNode ;
109- import com .oracle .graal .python .nodes .call .GenericInvokeNode ;
11096import com .oracle .graal .python .nodes .object .InlinedGetClassNodeGen ;
111- import com .oracle .graal .python .runtime .AsyncHandler ;
112- import com .oracle .graal .python .runtime .ExecutionContext .CalleeContext ;
11397import com .oracle .graal .python .runtime .ExecutionContext .IndirectCallContext ;
11498import com .oracle .graal .python .runtime .PythonContext ;
11599import com .oracle .graal .python .runtime .PythonContext .GetThreadStateNode ;
@@ -157,24 +141,18 @@ public final class CApiContext extends CExtContext {
157141 */
158142 static final CApiContext LAZY_CONTEXT = new CApiContext ();
159143
160- public static final long REFERENCE_COUNT_BITS = Integer .SIZE ;
161- public static final long REFERENCE_COUNT_MARKER = (1L << REFERENCE_COUNT_BITS );
162144 /* a random number between 1 and 20 */
163145 private static final int MAX_COLLECTION_RETRIES = 17 ;
164146
165147 /** Total amount of allocated native memory (in bytes). */
166148 private long allocatedMemory = 0 ;
167149
168- private final ReferenceQueue <Object > nativeObjectsQueue ;
169150 private Map <Object , AllocInfo > allocatedNativeMemory ;
170- private final ReferenceStack <NativeObjectReference > nativeObjectWrapperList ;
171151 private TraceMallocDomain [] traceMallocDomains ;
172152
173153 /** Container of pointers that have seen to be free'd. */
174154 private Map <Object , AllocInfo > freedNativeMemory ;
175155
176- @ CompilationFinal private RootCallTarget referenceCleanerCallTarget ;
177-
178156 /**
179157 * This cache is used to cache native wrappers for frequently used primitives. This is strictly
180158 * defined to be the range {@code [-5, 256]}. CPython does exactly the same (see
@@ -226,20 +204,12 @@ public static TruffleLogger getLogger(Class<?> clazz) {
226204 */
227205 private CApiContext () {
228206 super (null , null , null );
229- nativeObjectsQueue = null ;
230- nativeObjectWrapperList = null ;
231207 primitiveNativeWrapperCache = null ;
232208 llvmTypeCache = null ;
233209 }
234210
235211 public CApiContext (PythonContext context , Object hpyLibrary ) {
236212 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 ;
243213
244214 // initialize primitive and pointer type cache
245215 llvmTypeCache = new Object [LLVMType .values ().length ];
@@ -251,34 +221,6 @@ public CApiContext(PythonContext context, Object hpyLibrary) {
251221 CApiTransitions .incRef (nativeWrapper , PythonNativeWrapper .IMMORTAL_REFCNT );
252222 primitiveNativeWrapperCache [i ] = nativeWrapper ;
253223 }
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- });
282224 }
283225
284226 public int getPyLongBitsInDigit () {
@@ -325,14 +267,6 @@ public static Object asPointer(Object ptr, InteropLibrary lib) {
325267 return ptr ;
326268 }
327269
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-
336270 public TraceMallocDomain getTraceMallocDomain (int domainIdx ) {
337271 return traceMallocDomains [domainIdx ];
338272 }
@@ -413,185 +347,6 @@ public Object getModuleByIndex(int i) {
413347 return null ;
414348 }
415349
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-
595350 @ TruffleBoundary
596351 public AllocInfo traceFree (Object ptr , @ SuppressWarnings ("unused" ) PFrame .Reference curFrame , @ SuppressWarnings ("unused" ) TruffleString clazzName ) {
597352 if (allocatedNativeMemory == null ) {
@@ -728,32 +483,6 @@ public void checkAccess(Object pointerObject, InteropLibrary lib) {
728483 }
729484 }
730485
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-
757486 public static final class AllocInfo {
758487 public final TruffleString typeName ;
759488 public final PFrame .Reference allocationSite ;
0 commit comments