|
63 | 63 | import com.oracle.graal.python.builtins.objects.cext.capi.CExtNodes.FromCharPointerNode; |
64 | 64 | import com.oracle.graal.python.builtins.objects.cext.capi.CExtNodes.PCallCapiFunction; |
65 | 65 | import com.oracle.graal.python.builtins.objects.cext.capi.NativeCAPISymbol; |
| 66 | +import com.oracle.graal.python.builtins.objects.cext.capi.PThreadState; |
66 | 67 | import com.oracle.graal.python.builtins.objects.cext.capi.PrimitiveNativeWrapper; |
67 | 68 | import com.oracle.graal.python.builtins.objects.cext.capi.PythonNativeWrapper; |
68 | 69 | import com.oracle.graal.python.builtins.objects.cext.capi.PythonNativeWrapper.PythonAbstractObjectNativeWrapper; |
|
85 | 86 | import com.oracle.graal.python.builtins.objects.cext.structs.CStructs; |
86 | 87 | import com.oracle.graal.python.builtins.objects.floats.PFloat; |
87 | 88 | import com.oracle.graal.python.builtins.objects.getsetdescriptor.DescriptorDeleteMarker; |
| 89 | +import com.oracle.graal.python.builtins.objects.traceback.LazyTraceback; |
88 | 90 | import com.oracle.graal.python.builtins.objects.tuple.PTuple; |
89 | 91 | import com.oracle.graal.python.nodes.PGuards; |
90 | 92 | import com.oracle.graal.python.nodes.PNodeWithContext; |
91 | 93 | import com.oracle.graal.python.nodes.PRaiseNode; |
92 | 94 | import com.oracle.graal.python.nodes.object.GetClassNode; |
93 | 95 | import com.oracle.graal.python.runtime.GilNode; |
94 | 96 | import com.oracle.graal.python.runtime.PythonContext; |
| 97 | +import com.oracle.graal.python.runtime.exception.PException; |
95 | 98 | import com.oracle.graal.python.runtime.sequence.storage.NativeSequenceStorage; |
96 | 99 | import com.oracle.graal.python.runtime.sequence.storage.SequenceStorage; |
97 | 100 | import com.oracle.graal.python.runtime.sequence.storage.SequenceStorage.StorageType; |
@@ -355,69 +358,99 @@ public static void registerNativeSequenceStorage(NativeSequenceStorage storage) |
355 | 358 | @TruffleBoundary |
356 | 359 | @SuppressWarnings("try") |
357 | 360 | public static void pollReferenceQueue() { |
358 | | - HandleContext context = getContext(); |
359 | | - if (!context.referenceQueuePollActive) { |
| 361 | + PythonContext context = PythonContext.get(null); |
| 362 | + HandleContext handleContext = context.nativeContext; |
| 363 | + if (!handleContext.referenceQueuePollActive) { |
360 | 364 | try (GilNode.UncachedAcquire ignored = GilNode.uncachedAcquire()) { |
361 | | - ReferenceQueue<Object> queue = context.referenceQueue; |
| 365 | + ReferenceQueue<Object> queue = handleContext.referenceQueue; |
362 | 366 | int count = 0; |
363 | 367 | long start = 0; |
364 | | - NativeObjectReferenceArrayWrapper referencesToBeFreed = context.referencesToBeFreed; |
365 | | - while (true) { |
366 | | - Object entry = queue.poll(); |
367 | | - if (entry == null) { |
368 | | - if (count > 0) { |
369 | | - assert context.referenceQueuePollActive; |
370 | | - releaseNativeObjects(referencesToBeFreed); |
371 | | - context.referenceQueuePollActive = false; |
372 | | - LOGGER.fine("collected " + count + " references from native reference queue in " + ((System.nanoTime() - start) / 1000000) + "ms"); |
373 | | - } |
374 | | - return; |
375 | | - } |
376 | | - if (count == 0) { |
377 | | - assert !context.referenceQueuePollActive; |
378 | | - context.referenceQueuePollActive = true; |
379 | | - start = System.nanoTime(); |
380 | | - } else { |
381 | | - assert context.referenceQueuePollActive; |
| 368 | + NativeObjectReferenceArrayWrapper referencesToBeFreed = handleContext.referencesToBeFreed; |
| 369 | + PythonContext.PythonThreadState threadState = context.getThreadState(context.getLanguage()); |
| 370 | + /* |
| 371 | + * There can be an active exception. Since we might be calling arbitary python, we |
| 372 | + * need to stash it. |
| 373 | + */ |
| 374 | + PException savedException = null; |
| 375 | + LazyTraceback savedTraceback = null; |
| 376 | + Object savedNativeException = null; |
| 377 | + if (threadState.getCurrentException() != null) { |
| 378 | + savedException = threadState.getCurrentException(); |
| 379 | + savedTraceback = threadState.getCurrentTraceback(); |
| 380 | + threadState.clearCurrentException(); |
| 381 | + Object nativeThreadState = PThreadState.getNativeThreadState(threadState); |
| 382 | + if (nativeThreadState != null) { |
| 383 | + savedNativeException = CStructAccess.ReadPointerNode.readUncached(nativeThreadState, CFields.PyThreadState__curexc_type); |
| 384 | + CStructAccess.WritePointerNode.writeUncached(nativeThreadState, CFields.PyThreadState__curexc_type, 0L); |
382 | 385 | } |
383 | | - count++; |
384 | | - if (entry instanceof PythonObjectReference reference) { |
385 | | - LOGGER.fine(() -> PythonUtils.formatJString("releasing %s", reference.toString())); |
386 | | - if (HandlePointerConverter.pointsToPyHandleSpace(reference.pointer)) { |
387 | | - assert nativeStubLookupGet(context, reference.pointer, reference.handleTableIndex) != null : Long.toHexString(reference.pointer); |
388 | | - nativeStubLookupRemove(context, reference); |
389 | | - /* |
390 | | - * We may only free native object stubs if their reference count is |
391 | | - * zero. We cannot free other structs (e.g. PyDateTime_CAPI) because we |
392 | | - * don't know if they are still used from native code. Those must be |
393 | | - * free'd at context finalization. |
394 | | - */ |
395 | | - long stubPointer = HandlePointerConverter.pointerToStub(reference.pointer); |
396 | | - if (subNativeRefCount(stubPointer, MANAGED_REFCNT) == 0) { |
397 | | - freeNativeStub(stubPointer); |
398 | | - } else { |
399 | | - /* |
400 | | - * In this case, the object is no longer referenced from managed but |
401 | | - * still from native code (since the reference count is greater 0). |
402 | | - * We therefore need to overwrite the 'CFields.GraalPyObject__id' |
403 | | - * field because there may be referenced from managed in the future |
404 | | - * and then we would incorrectly reuse the ID. |
405 | | - */ |
406 | | - CStructAccess.WriteIntNode.writeUncached(reference.pointer, CFields.GraalPyObject__handle_table_index, 0); |
| 386 | + } |
| 387 | + try { |
| 388 | + while (true) { |
| 389 | + Object entry = queue.poll(); |
| 390 | + if (entry == null) { |
| 391 | + if (count > 0) { |
| 392 | + assert handleContext.referenceQueuePollActive; |
| 393 | + releaseNativeObjects(referencesToBeFreed); |
| 394 | + handleContext.referenceQueuePollActive = false; |
| 395 | + LOGGER.fine("collected " + count + " references from native reference queue in " + ((System.nanoTime() - start) / 1000000) + "ms"); |
407 | 396 | } |
| 397 | + return; |
| 398 | + } |
| 399 | + if (count == 0) { |
| 400 | + assert !handleContext.referenceQueuePollActive; |
| 401 | + handleContext.referenceQueuePollActive = true; |
| 402 | + start = System.nanoTime(); |
408 | 403 | } else { |
409 | | - assert nativeLookupGet(context, reference.pointer) != null : Long.toHexString(reference.pointer); |
410 | | - nativeLookupRemove(context, reference.pointer); |
411 | | - if (reference.freeAtCollection) { |
412 | | - freeNativeStruct(reference); |
| 404 | + assert handleContext.referenceQueuePollActive; |
| 405 | + } |
| 406 | + count++; |
| 407 | + if (entry instanceof PythonObjectReference reference) { |
| 408 | + LOGGER.fine(() -> PythonUtils.formatJString("releasing %s", reference.toString())); |
| 409 | + if (HandlePointerConverter.pointsToPyHandleSpace(reference.pointer)) { |
| 410 | + assert nativeStubLookupGet(handleContext, reference.pointer, reference.handleTableIndex) != null : Long.toHexString(reference.pointer); |
| 411 | + nativeStubLookupRemove(handleContext, reference); |
| 412 | + /* |
| 413 | + * We may only free native object stubs if their reference count is |
| 414 | + * zero. We cannot free other structs (e.g. PyDateTime_CAPI) because |
| 415 | + * we don't know if they are still used from native code. Those must |
| 416 | + * be free'd at context finalization. |
| 417 | + */ |
| 418 | + long stubPointer = HandlePointerConverter.pointerToStub(reference.pointer); |
| 419 | + if (subNativeRefCount(stubPointer, MANAGED_REFCNT) == 0) { |
| 420 | + freeNativeStub(stubPointer); |
| 421 | + } else { |
| 422 | + /* |
| 423 | + * In this case, the object is no longer referenced from managed |
| 424 | + * but still from native code (since the reference count is |
| 425 | + * greater 0). We therefore need to overwrite the |
| 426 | + * 'CFields.GraalPyObject__id' field because there may be |
| 427 | + * referenced from managed in the future and then we would |
| 428 | + * incorrectly reuse the ID. |
| 429 | + */ |
| 430 | + CStructAccess.WriteIntNode.writeUncached(reference.pointer, CFields.GraalPyObject__handle_table_index, 0); |
| 431 | + } |
| 432 | + } else { |
| 433 | + assert nativeLookupGet(handleContext, reference.pointer) != null : Long.toHexString(reference.pointer); |
| 434 | + nativeLookupRemove(handleContext, reference.pointer); |
| 435 | + if (reference.freeAtCollection) { |
| 436 | + freeNativeStruct(reference); |
| 437 | + } |
413 | 438 | } |
| 439 | + } else if (entry instanceof NativeObjectReference reference) { |
| 440 | + nativeLookupRemove(handleContext, reference.pointer); |
| 441 | + processNativeObjectReference(reference, referencesToBeFreed); |
| 442 | + } else if (entry instanceof NativeStorageReference reference) { |
| 443 | + handleContext.nativeStorageReferences.remove(reference); |
| 444 | + processNativeStorageReference(reference); |
| 445 | + } |
| 446 | + } |
| 447 | + } finally { |
| 448 | + if (savedException != null) { |
| 449 | + threadState.setCurrentException(savedException, savedTraceback); |
| 450 | + Object nativeThreadState = PThreadState.getNativeThreadState(threadState); |
| 451 | + if (nativeThreadState != null) { |
| 452 | + CStructAccess.WritePointerNode.writeUncached(nativeThreadState, CFields.PyThreadState__curexc_type, savedNativeException); |
414 | 453 | } |
415 | | - } else if (entry instanceof NativeObjectReference reference) { |
416 | | - nativeLookupRemove(context, reference.pointer); |
417 | | - processNativeObjectReference(reference, referencesToBeFreed); |
418 | | - } else if (entry instanceof NativeStorageReference reference) { |
419 | | - context.nativeStorageReferences.remove(reference); |
420 | | - processNativeStorageReference(reference); |
421 | 454 | } |
422 | 455 | } |
423 | 456 | } |
|
0 commit comments