2 +----------------------------------------------------------------------+
4 +----------------------------------------------------------------------+
5 | Copyright (c) 2010-present Facebook, Inc. (http://www.facebook.com) |
6 +----------------------------------------------------------------------+
7 | This source file is subject to version 3.01 of the PHP license, |
8 | that is bundled with this package in the file LICENSE, and is |
9 | available through the world-wide-web at the following url: |
10 | http://www.php.net/license/3_01.txt |
11 | If you did not receive a copy of the PHP license and are unable to |
12 | obtain it through the world-wide-web, please send a note to |
13 | license@php.net so we can mail you a copy immediately. |
14 +----------------------------------------------------------------------+
16 #include "hphp/runtime/base/weakref-data.h"
18 #include "hphp/runtime/base/string-hash-map.h"
19 #include "hphp/runtime/base/tv-refcount.h"
20 #include "hphp/runtime/base/type-object.h"
21 #include "hphp/runtime/base/type-variant.h"
22 #include "hphp/system/systemlib.h"
23 #include "hphp/util/rds-local.h"
27 // Maps object ids to the WeakRefData associated to them.
28 using weakref_data_map
= req::fast_map
<uintptr_t, req::weak_ptr
<WeakRefData
>>;
29 RDS_LOCAL(weakref_data_map
, s_weakref_data
);
31 void weakref_cleanup() {
32 s_weakref_data
.destroy();
35 void WeakRefData::invalidateWeakRef(uintptr_t ptr
) {
36 auto weakmap
= s_weakref_data
.get();
37 auto map_entry
= weakmap
->find(ptr
);
38 if (map_entry
!= weakmap
->end()) {
39 map_entry
->second
.lock()->pointee
= make_tv
<KindOfUninit
>();
40 weakmap
->erase(map_entry
);
44 req::shared_ptr
<WeakRefData
> WeakRefData::forObject(Object obj
) {
45 req::shared_ptr
<WeakRefData
> wr_data
;
47 auto weakmap
= s_weakref_data
.get();
49 auto map_entry
= weakmap
->find((uintptr_t)obj
.get());
50 if (map_entry
!= weakmap
->end()) {
51 wr_data
= map_entry
->second
.lock();
53 wr_data
= req::make_shared
<WeakRefData
>(make_tv
<KindOfObject
>(obj
.get()));
56 req::weak_ptr
<WeakRefData
> weak_data
= req::weak_ptr
<WeakRefData
>(wr_data
);
57 auto const DEBUG_ONLY result
= weakmap
->emplace(
58 reinterpret_cast<uintptr_t>(obj
.get()),
61 // Failure. Key should be unique. We just checked.
62 assertx(result
.second
);
67 WeakRefData::~WeakRefData() {
68 if (type(pointee
) != KindOfUninit
) {
69 s_weakref_data
.get()->erase(reinterpret_cast<uintptr_t>(val(pointee
).pobj
));
74 * The problem this logic tries to solve:
75 * - We have a weakref object that points to an object.
76 * - We use DecRefNZ to get the reference count of the object down to 0 but it
77 * hasn't been destructed or sweeped yet. But the GC could sweep it at any
79 * - Some code now call valid() or get() which without the refcount check would
80 * return true or the object.
81 * - Because we know that if the sweep or destructor had run the pointer would
82 * have been cleaned up so if we have a pointer it is safe to look at the
84 * - So we look at the refcount of the object and make sure it is > 0.
86 bool WeakRefData::isValid() const {
87 auto const ty
= type(pointee
);
88 return LIKELY(isRefcountedType(ty
))
89 ? tvGetCount(pointee
) > 0