|
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.getUncached().read(nativeThreadState, CFields.PyThreadState__curexc_type); |
| 384 | + CStructAccess.WritePointerNode.getUncached().write(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.getUncached().write(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