this repo has no description
at trunk 109 lines 4.1 kB view raw
1// Copyright (c) Facebook, Inc. and its affiliates. (http://www.facebook.com) 2#include "extension-object.h" 3 4#include "api-handle.h" 5#include "capi-state.h" 6#include "capi-typeslots.h" 7#include "capi.h" 8#include "linked-list.h" 9#include "object.h" 10#include "runtime.h" 11#include "scavenger.h" 12 13namespace py { 14 15void disposeExtensionObjects(Runtime* runtime) { 16 CAPIState* state = capiState(runtime); 17 while (ListEntry* entry = state->extension_objects) { 18 untrackExtensionObject(runtime, entry); 19 std::free(entry); 20 } 21} 22 23void finalizeExtensionObject(Thread* thread, RawObject object) { 24 HandleScope scope(thread); 25 Runtime* runtime = thread->runtime(); 26 NativeProxy proxy(&scope, object); 27 Type type(&scope, runtime->typeOf(*proxy)); 28 DCHECK(type.hasNativeData(), 29 "A native instance must come from an extension type"); 30 destructor tp_dealloc = 31 reinterpret_cast<destructor>(typeSlotAt(type, Py_tp_dealloc)); 32 DCHECK(tp_dealloc != nullptr, "Extension types must have a dealloc slot"); 33 ApiHandle* handle = ApiHandle::fromPyObject( 34 reinterpret_cast<PyObject*>(Int::cast(proxy.native()).asCPtr())); 35 CHECK(ApiHandle::refcnt(handle) == 1, 36 "The runtime must hold the last reference to the PyObject* (%p). " 37 "Expecting a refcount of 1, but found %ld\n", 38 reinterpret_cast<void*>(handle), ApiHandle::refcnt(handle)); 39 ApiHandle::setRefcnt(handle, 0); 40 ApiHandle::setBorrowedNoImmediate(handle); 41 (*tp_dealloc)(handle); 42 if (!proxy.native().isNoneType() && ApiHandle::refcnt(handle) == 0) { 43 // `proxy.native()` being `None` indicates the extension object memory was 44 // not freed. `ob_refcnt == 0` means the object was not resurrected. 45 // This typically indicates that the user maintains a free-list and wants to 46 // call `PyObject_Init` on the memory again, we have to untrack it! 47 ListEntry* entry = reinterpret_cast<ListEntry*>(handle) - 1; 48 untrackExtensionObject(runtime, entry); 49 } 50} 51 52PyObject* initializeExtensionObject(Thread* thread, PyObject* obj, 53 PyTypeObject* typeobj, 54 const Object& instance) { 55 Runtime* runtime = thread->runtime(); 56 HandleScope scope(thread); 57 58 NativeProxy proxy(&scope, *instance); 59 proxy.setNative(runtime->newIntFromCPtr(obj)); 60 trackExtensionObject(runtime, reinterpret_cast<ListEntry*>(obj) - 1); 61 62 // Initialize the native object 63 obj->reference_ = proxy.raw(); 64 Py_INCREF(typeobj); 65 obj->ob_refcnt = 2; 66 return obj; 67} 68 69word numExtensionObjects(Runtime* runtime) { 70 return capiState(runtime)->num_extension_objects; 71} 72 73bool trackExtensionObject(Runtime* runtime, ListEntry* entry) { 74 CAPIState* state = capiState(runtime); 75 bool did_insert = listEntryInsert(entry, &state->extension_objects); 76 if (did_insert) state->num_extension_objects++; 77 return did_insert; 78} 79 80bool untrackExtensionObject(Runtime* runtime, ListEntry* entry) { 81 CAPIState* state = capiState(runtime); 82 bool did_remove = listEntryRemove(entry, &state->extension_objects); 83 if (did_remove) state->num_extension_objects--; 84 return did_remove; 85} 86 87void visitExtensionObjects(Runtime* runtime, Scavenger* scavenger, 88 PointerVisitor* visitor) { 89 CAPIState* state = capiState(runtime); 90 for (ListEntry *next, *entry = state->extension_objects; entry != nullptr; 91 entry = next) { 92 next = entry->next; 93 void* native_instance = entry + 1; 94 ApiHandle* handle = reinterpret_cast<ApiHandle*>(native_instance); 95 RawObject object = ApiHandle::asObjectNoImmediate(handle); 96 bool alive = ApiHandle::refcnt(handle) > 1 || 97 !isWhiteObject(scavenger, HeapObject::cast(object)); 98 visitor->visitPointer(&object, PointerKind::kApiHandle); 99 handle->reference_ = reinterpret_cast<uintptr_t>(object.raw()); 100 101 // TODO(T58548736): Run safe dealloc slots here when possible rather than 102 // putting everything on the queue. 103 if (!alive) { 104 NativeProxy::enqueue(object, runtime->finalizableReferences()); 105 } 106 } 107} 108 109} // namespace py