xref: /PHP-7.4/Zend/zend_weakrefs.c (revision 1df9f238)
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