1 /*
2 +----------------------------------------------------------------------+
3 | PHP Version 7 |
4 +----------------------------------------------------------------------+
5 | Copyright (c) The PHP Group |
6 +----------------------------------------------------------------------+
7 | This source file is subject to version 2.00 of the Zend 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.zend.com/license/2_00.txt. |
11 | If you did not receive a copy of the Zend license and are unable to |
12 | obtain it through the world-wide-web, please send a note to |
13 | license@zend.com so we can mail you a copy immediately. |
14 +----------------------------------------------------------------------+
15 | Authors: krakjoe@php.net |
16 +----------------------------------------------------------------------+
17 */
18
19 #include "zend.h"
20 #include "zend_interfaces.h"
21 #include "zend_objects_API.h"
22 #include "zend_weakrefs.h"
23
24 typedef struct _zend_weakref {
25 zend_object *referent;
26 zend_object std;
27 } zend_weakref;
28
29 zend_class_entry *zend_ce_weakref;
30 static zend_object_handlers zend_weakref_handlers;
31
32 #define zend_weakref_from(o) ((zend_weakref*)(((char*) o) - XtOffsetOf(zend_weakref, std)))
33 #define zend_weakref_fetch(z) zend_weakref_from(Z_OBJ_P(z))
34
zend_weakref_unref(zval * zv)35 static void zend_weakref_unref(zval *zv) {
36 zend_weakref *wr = (zend_weakref*) Z_PTR_P(zv);
37
38 GC_DEL_FLAGS(wr->referent, IS_OBJ_WEAKLY_REFERENCED);
39
40 wr->referent = NULL;
41 }
42
zend_weakrefs_init()43 void zend_weakrefs_init() {
44 zend_hash_init(&EG(weakrefs), 8, NULL, zend_weakref_unref, 0);
45 }
46
zend_weakrefs_notify(zend_object * object)47 void zend_weakrefs_notify(zend_object *object) {
48 zend_hash_index_del(&EG(weakrefs), (zend_ulong) object);
49 }
50
zend_weakrefs_shutdown()51 void zend_weakrefs_shutdown() {
52 zend_hash_destroy(&EG(weakrefs));
53 }
54
zend_weakref_new(zend_class_entry * ce)55 static zend_object* zend_weakref_new(zend_class_entry *ce) {
56 zend_weakref *wr = zend_object_alloc(sizeof(zend_weakref), zend_ce_weakref);
57
58 zend_object_std_init(&wr->std, zend_ce_weakref);
59
60 wr->std.handlers = &zend_weakref_handlers;
61
62 return &wr->std;
63 }
64
zend_weakref_find(zval * referent,zval * return_value)65 static zend_always_inline zend_bool zend_weakref_find(zval *referent, zval *return_value) {
66 zend_weakref *wr = zend_hash_index_find_ptr(&EG(weakrefs), (zend_ulong) Z_OBJ_P(referent));
67
68 if (!wr) {
69 return 0;
70 }
71
72 GC_ADDREF(&wr->std);
73 ZVAL_OBJ(return_value, &wr->std);
74
75 return 1;
76 }
77
zend_weakref_create(zval * referent,zval * return_value)78 static zend_always_inline void zend_weakref_create(zval *referent, zval *return_value) {
79 zend_weakref *wr;
80
81 object_init_ex(return_value, zend_ce_weakref);
82
83 wr = zend_weakref_fetch(return_value);
84
85 wr->referent = Z_OBJ_P(referent);
86
87 zend_hash_index_add_ptr(&EG(weakrefs), (zend_ulong) wr->referent, wr);
88
89 GC_ADD_FLAGS(wr->referent, IS_OBJ_WEAKLY_REFERENCED);
90 }
91
zend_weakref_get(zval * weakref,zval * return_value)92 static zend_always_inline void zend_weakref_get(zval *weakref, zval *return_value) {
93 zend_weakref *wr = zend_weakref_fetch(weakref);
94
95 if (wr->referent) {
96 ZVAL_OBJ(return_value, wr->referent);
97 Z_ADDREF_P(return_value);
98 }
99 }
100
zend_weakref_free(zend_object * zo)101 static void zend_weakref_free(zend_object *zo) {
102 zend_weakref *wr = zend_weakref_from(zo);
103
104 if (wr->referent) {
105 zend_hash_index_del(
106 &EG(weakrefs), (zend_ulong) wr->referent);
107 }
108
109 zend_object_std_dtor(&wr->std);
110 }
111
112 #define zend_weakref_unsupported(thing) \
113 zend_throw_error(NULL, "WeakReference objects do not support " thing);
114
zend_weakref_no_write(zval * object,zval * member,zval * value,void ** rtc)115 static ZEND_COLD zval* zend_weakref_no_write(zval *object, zval *member, zval *value, void **rtc) {
116 zend_weakref_unsupported("properties");
117
118 return &EG(uninitialized_zval);
119 }
120
zend_weakref_no_read(zval * object,zval * member,int type,void ** rtc,zval * rv)121 static ZEND_COLD zval* zend_weakref_no_read(zval *object, zval *member, int type, void **rtc, zval *rv) {
122 if (!EG(exception)) {
123 zend_weakref_unsupported("properties");
124 }
125
126 return &EG(uninitialized_zval);
127 }
128
zend_weakref_no_read_ptr(zval * object,zval * member,int type,void ** rtc)129 static ZEND_COLD zval *zend_weakref_no_read_ptr(zval *object, zval *member, int type, void **rtc) {
130 zend_weakref_unsupported("property references");
131 return NULL;
132 }
133
zend_weakref_no_isset(zval * object,zval * member,int hse,void ** rtc)134 static ZEND_COLD int zend_weakref_no_isset(zval *object, zval *member, int hse, void **rtc) {
135 if (hse != 2) {
136 zend_weakref_unsupported("properties");
137 }
138 return 0;
139 }
140
zend_weakref_no_unset(zval * object,zval * member,void ** rtc)141 static ZEND_COLD void zend_weakref_no_unset(zval *object, zval *member, void **rtc) {
142 zend_weakref_unsupported("properties");
143 }
144
145 ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(zend_weakref_create_arginfo, 0, 1, WeakReference, 0)
146 ZEND_ARG_TYPE_INFO(0, referent, IS_OBJECT, 0)
ZEND_END_ARG_INFO()147 ZEND_END_ARG_INFO()
148
149 ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(zend_weakref_get_arginfo, 0, 0, IS_OBJECT, 1)
150 ZEND_END_ARG_INFO()
151
152 ZEND_COLD ZEND_METHOD(WeakReference, __construct)
153 {
154 zend_throw_error(NULL,
155 "Direct instantiation of 'WeakReference' is not allowed, "
156 "use WeakReference::create instead");
157 }
158
ZEND_METHOD(WeakReference,create)159 ZEND_METHOD(WeakReference, create)
160 {
161 zval *referent;
162
163 ZEND_PARSE_PARAMETERS_START_EX(ZEND_PARSE_PARAMS_THROW, 1,1)
164 Z_PARAM_OBJECT(referent)
165 ZEND_PARSE_PARAMETERS_END();
166
167 if (zend_weakref_find(referent, return_value)) {
168 return;
169 }
170
171 zend_weakref_create(referent, return_value);
172 }
173
ZEND_METHOD(WeakReference,get)174 ZEND_METHOD(WeakReference, get)
175 {
176 ZEND_PARSE_PARAMETERS_START_EX(ZEND_PARSE_PARAMS_THROW, 0, 0)
177 ZEND_PARSE_PARAMETERS_END();
178
179 zend_weakref_get(getThis(), return_value);
180 }
181
182 static const zend_function_entry zend_weakref_methods[] = {
183 ZEND_ME(WeakReference, __construct, NULL, ZEND_ACC_PUBLIC)
184 ZEND_ME(WeakReference, create, zend_weakref_create_arginfo, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
185 ZEND_ME(WeakReference, get, zend_weakref_get_arginfo, ZEND_ACC_PUBLIC)
186 ZEND_FE_END
187 };
188
zend_register_weakref_ce(void)189 void zend_register_weakref_ce(void) /* {{{ */
190 {
191 zend_class_entry ce;
192
193 INIT_CLASS_ENTRY(ce, "WeakReference", zend_weakref_methods);
194 zend_ce_weakref = zend_register_internal_class(&ce);
195 zend_ce_weakref->ce_flags |= ZEND_ACC_FINAL;
196
197 zend_ce_weakref->create_object = zend_weakref_new;
198 zend_ce_weakref->serialize = zend_class_serialize_deny;
199 zend_ce_weakref->unserialize = zend_class_unserialize_deny;
200
201 memcpy(&zend_weakref_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers));
202 zend_weakref_handlers.offset = XtOffsetOf(zend_weakref, std);
203
204 zend_weakref_handlers.free_obj = zend_weakref_free;
205 zend_weakref_handlers.read_property = zend_weakref_no_read;
206 zend_weakref_handlers.write_property = zend_weakref_no_write;
207 zend_weakref_handlers.has_property = zend_weakref_no_isset;
208 zend_weakref_handlers.unset_property = zend_weakref_no_unset;
209 zend_weakref_handlers.get_property_ptr_ptr = zend_weakref_no_read_ptr;
210 zend_weakref_handlers.clone_obj = NULL;
211 }
212 /* }}} */
213
214