Coverage Report

Created: 2022-02-19 20:29

/src/php-src/Zend/zend_weakrefs.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
   +----------------------------------------------------------------------+
3
   | Copyright (c) The PHP Group                                          |
4
   +----------------------------------------------------------------------+
5
   | This source file is subject to version 2.00 of the Zend license,     |
6
   | that is bundled with this package in the file LICENSE, and is        |
7
   | available through the world-wide-web at the following url:           |
8
   | http://www.zend.com/license/2_00.txt.                                |
9
   | If you did not receive a copy of the Zend license and are unable to  |
10
   | obtain it through the world-wide-web, please send a note to          |
11
   | license@zend.com so we can mail you a copy immediately.              |
12
   +----------------------------------------------------------------------+
13
   | Authors: krakjoe@php.net                                             |
14
   +----------------------------------------------------------------------+
15
*/
16
17
#include "zend.h"
18
#include "zend_interfaces.h"
19
#include "zend_objects_API.h"
20
#include "zend_weakrefs.h"
21
#include "zend_weakrefs_arginfo.h"
22
23
typedef struct _zend_weakref {
24
  zend_object *referent;
25
  zend_object std;
26
} zend_weakref;
27
28
typedef struct _zend_weakmap {
29
  HashTable ht;
30
  zend_object std;
31
} zend_weakmap;
32
33
typedef struct _zend_weakmap_iterator {
34
  zend_object_iterator it;
35
  uint32_t ht_iter;
36
} zend_weakmap_iterator;
37
38
/* The EG(weakrefs) ht is a map from object address a tagged pointer, that may be one of
39
 * zend_weakref*, zend_weakmap* or HashTable*. */
40
3.84k
#define ZEND_WEAKREF_TAG_REF 0
41
#define ZEND_WEAKREF_TAG_MAP 1
42
4.29k
#define ZEND_WEAKREF_TAG_HT  2
43
5.81k
#define ZEND_WEAKREF_GET_TAG(p) (((uintptr_t) (p)) & 3)
44
5.41k
#define ZEND_WEAKREF_GET_PTR(p) ((void *) (((uintptr_t) (p)) & ~3))
45
5.62k
#define ZEND_WEAKREF_ENCODE(p, t) ((void *) (((uintptr_t) (p)) | (t)))
46
47
zend_class_entry *zend_ce_weakref;
48
zend_class_entry *zend_ce_weakmap;
49
static zend_object_handlers zend_weakref_handlers;
50
static zend_object_handlers zend_weakmap_handlers;
51
52
1.75k
#define zend_weakref_from(o) ((zend_weakref*)(((char*) o) - XtOffsetOf(zend_weakref, std)))
53
1.14k
#define zend_weakref_fetch(z) zend_weakref_from(Z_OBJ_P(z))
54
55
22.5k
#define zend_weakmap_from(o) ((zend_weakmap*)(((char*) o) - XtOffsetOf(zend_weakmap, std)))
56
6.99k
#define zend_weakmap_fetch(z) zend_weakmap_from(Z_OBJ_P(z))
57
58
static inline void zend_weakref_unref_single(
59
    void *ptr, uintptr_t tag, zend_ulong obj_addr)
60
3.74k
{
61
3.74k
  if (tag == ZEND_WEAKREF_TAG_REF) {
62
596
    zend_weakref *wr = ptr;
63
596
    wr->referent = NULL;
64
3.15k
  } else {
65
3.15k
    ZEND_ASSERT(tag == ZEND_WEAKREF_TAG_MAP);
66
3.15k
    zend_weakmap *wm = ptr;
67
3.15k
    zend_hash_index_del(&wm->ht, obj_addr);
68
3.15k
  }
69
3.74k
}
70
71
1.77k
static void zend_weakref_unref(zend_ulong obj_addr, void *tagged_ptr) {
72
1.77k
  void *ptr = ZEND_WEAKREF_GET_PTR(tagged_ptr);
73
1.77k
  uintptr_t tag = ZEND_WEAKREF_GET_TAG(tagged_ptr);
74
1.77k
  if (tag == ZEND_WEAKREF_TAG_HT) {
75
251
    HashTable *ht = ptr;
76
1.88k
    ZEND_HASH_FOREACH_PTR(ht, tagged_ptr) {
77
1.88k
      zend_weakref_unref_single(
78
741
        ZEND_WEAKREF_GET_PTR(tagged_ptr), ZEND_WEAKREF_GET_TAG(tagged_ptr), obj_addr);
79
741
    } ZEND_HASH_FOREACH_END();
80
251
    zend_hash_destroy(ht);
81
251
    FREE_HASHTABLE(ht);
82
1.52k
  } else {
83
1.52k
    zend_weakref_unref_single(ptr, tag, obj_addr);
84
1.52k
  }
85
1.77k
}
86
87
3.74k
static void zend_weakref_register(zend_object *object, void *payload) {
88
3.74k
  GC_ADD_FLAGS(object, IS_OBJ_WEAKLY_REFERENCED);
89
90
3.74k
  zend_ulong obj_addr = (zend_ulong) object;
91
3.74k
  zval *zv = zend_hash_index_find(&EG(weakrefs), obj_addr);
92
3.74k
  if (!zv) {
93
2.71k
    zend_hash_index_add_new_ptr(&EG(weakrefs), obj_addr, payload);
94
2.71k
    return;
95
2.71k
  }
96
97
1.03k
  void *tagged_ptr = Z_PTR_P(zv);
98
1.03k
  if (ZEND_WEAKREF_GET_TAG(tagged_ptr) == ZEND_WEAKREF_TAG_HT) {
99
639
    HashTable *ht = ZEND_WEAKREF_GET_PTR(tagged_ptr);
100
639
    zend_hash_index_add_new_ptr(ht, (zend_ulong) payload, payload);
101
639
    return;
102
639
  }
103
104
  /* Convert simple pointer to hashtable. */
105
395
  HashTable *ht = emalloc(sizeof(HashTable));
106
395
  zend_hash_init(ht, 0, NULL, NULL, 0);
107
395
  zend_hash_index_add_new_ptr(ht, (zend_ulong) tagged_ptr, tagged_ptr);
108
395
  zend_hash_index_add_new_ptr(ht, (zend_ulong) payload, payload);
109
395
  zend_hash_index_update_ptr(
110
395
    &EG(weakrefs), obj_addr, ZEND_WEAKREF_ENCODE(ht, ZEND_WEAKREF_TAG_HT));
111
395
}
112
113
1.47k
static void zend_weakref_unregister(zend_object *object, void *payload) {
114
1.47k
  zend_ulong obj_addr = (zend_ulong) object;
115
1.47k
  void *tagged_ptr = zend_hash_index_find_ptr(&EG(weakrefs), obj_addr);
116
1.47k
  ZEND_ASSERT(tagged_ptr && "Weakref not registered?");
117
118
1.47k
  void *ptr = ZEND_WEAKREF_GET_PTR(tagged_ptr);
119
1.47k
  uintptr_t tag = ZEND_WEAKREF_GET_TAG(tagged_ptr);
120
1.47k
  if (tag != ZEND_WEAKREF_TAG_HT) {
121
791
    ZEND_ASSERT(tagged_ptr == payload);
122
791
    zend_hash_index_del(&EG(weakrefs), obj_addr);
123
791
    GC_DEL_FLAGS(object, IS_OBJ_WEAKLY_REFERENCED);
124
125
    /* Do this last, as it may destroy the object. */
126
791
    zend_weakref_unref_single(ptr, tag, obj_addr);
127
791
    return;
128
791
  }
129
130
688
  HashTable *ht = ptr;
131
688
  tagged_ptr = zend_hash_index_find_ptr(ht, (zend_ulong) payload);
132
688
  ZEND_ASSERT(tagged_ptr && "Weakref not registered?");
133
688
  ZEND_ASSERT(tagged_ptr == payload);
134
688
  zend_hash_index_del(ht, (zend_ulong) payload);
135
688
  if (zend_hash_num_elements(ht) == 0) {
136
144
    GC_DEL_FLAGS(object, IS_OBJ_WEAKLY_REFERENCED);
137
144
    zend_hash_destroy(ht);
138
144
    FREE_HASHTABLE(ht);
139
144
    zend_hash_index_del(&EG(weakrefs), obj_addr);
140
144
  }
141
142
  /* Do this last, as it may destroy the object. */
143
688
  zend_weakref_unref_single(
144
688
    ZEND_WEAKREF_GET_PTR(payload), ZEND_WEAKREF_GET_TAG(payload), obj_addr);
145
688
}
146
147
613k
void zend_weakrefs_init(void) {
148
613k
  zend_hash_init(&EG(weakrefs), 8, NULL, NULL, 0);
149
613k
}
150
151
1.77k
void zend_weakrefs_notify(zend_object *object) {
152
  /* Annoyingly we can't use the HT destructor here, because we need access to the key (which
153
   * is the object address), which is not provided to the dtor. */
154
1.77k
  zend_ulong obj_addr = (zend_ulong) object;
155
1.77k
  void *tagged_ptr = zend_hash_index_find_ptr(&EG(weakrefs), obj_addr);
156
1.77k
#if ZEND_DEBUG
157
1.77k
  ZEND_ASSERT(tagged_ptr && "Tracking of the IS_OBJ_WEAKLY_REFERENCE flag should be precise");
158
1.77k
#endif
159
1.77k
  if (tagged_ptr) {
160
1.77k
    zend_weakref_unref(obj_addr, tagged_ptr);
161
1.77k
    zend_hash_index_del(&EG(weakrefs), obj_addr);
162
1.77k
  }
163
1.77k
}
164
165
610k
void zend_weakrefs_shutdown(void) {
166
610k
  zend_ulong obj_addr;
167
610k
  void *tagged_ptr;
168
610k
  ZEND_HASH_FOREACH_NUM_KEY_PTR(&EG(weakrefs), obj_addr, tagged_ptr) {
169
610k
    zend_weakref_unref(obj_addr, tagged_ptr);
170
0
  } ZEND_HASH_FOREACH_END();
171
610k
  zend_hash_destroy(&EG(weakrefs));
172
610k
}
173
174
614
static zend_object* zend_weakref_new(zend_class_entry *ce) {
175
614
  zend_weakref *wr = zend_object_alloc(sizeof(zend_weakref), zend_ce_weakref);
176
177
614
  zend_object_std_init(&wr->std, zend_ce_weakref);
178
179
614
  wr->std.handlers = &zend_weakref_handlers;
180
181
614
  return &wr->std;
182
614
}
183
184
679
static zend_always_inline zend_bool zend_weakref_find(zval *referent, zval *return_value) {
185
679
  void *tagged_ptr = zend_hash_index_find_ptr(&EG(weakrefs), (zend_ulong) Z_OBJ_P(referent));
186
679
  if (!tagged_ptr) {
187
593
    return 0;
188
593
  }
189
190
86
  void *ptr = ZEND_WEAKREF_GET_PTR(tagged_ptr);
191
86
  uintptr_t tag = ZEND_WEAKREF_GET_TAG(tagged_ptr);
192
86
  if (tag == ZEND_WEAKREF_TAG_REF) {
193
83
    zend_weakref *wr;
194
83
found_weakref:
195
83
    wr = ptr;
196
83
    RETVAL_OBJ_COPY(&wr->std);
197
83
    return 1;
198
3
  }
199
200
3
  if (tag == ZEND_WEAKREF_TAG_HT) {
201
9
    ZEND_HASH_FOREACH(ptr, tagged_ptr) {
202
6
      if (ZEND_WEAKREF_GET_TAG(tagged_ptr) == ZEND_WEAKREF_TAG_REF) {
203
0
        ptr = ZEND_WEAKREF_GET_PTR(tagged_ptr);
204
0
        goto found_weakref;
205
0
      }
206
6
    } ZEND_HASH_FOREACH_END();
207
3
  }
208
209
3
  return 0;
210
3
}
211
212
596
static zend_always_inline void zend_weakref_create(zval *referent, zval *return_value) {
213
596
  zend_weakref *wr;
214
215
596
  object_init_ex(return_value, zend_ce_weakref);
216
217
596
  wr = zend_weakref_fetch(return_value);
218
596
  wr->referent = Z_OBJ_P(referent);
219
220
596
  zend_weakref_register(wr->referent, ZEND_WEAKREF_ENCODE(wr, ZEND_WEAKREF_TAG_REF));
221
596
}
222
223
544
static zend_always_inline void zend_weakref_get(zval *weakref, zval *return_value) {
224
544
  zend_weakref *wr = zend_weakref_fetch(weakref);
225
226
544
  if (wr->referent) {
227
327
    RETVAL_OBJ_COPY(wr->referent);
228
327
  }
229
544
}
230
231
613
static void zend_weakref_free(zend_object *zo) {
232
613
  zend_weakref *wr = zend_weakref_from(zo);
233
234
613
  if (wr->referent) {
235
263
    zend_weakref_unregister(wr->referent, ZEND_WEAKREF_ENCODE(wr, ZEND_WEAKREF_TAG_REF));
236
263
  }
237
238
613
  zend_object_std_dtor(&wr->std);
239
613
}
240
241
ZEND_COLD ZEND_METHOD(WeakReference, __construct)
242
18
{
243
18
  zend_throw_error(NULL, "Direct instantiation of WeakReference is not allowed, use WeakReference::create instead");
244
18
}
245
246
ZEND_METHOD(WeakReference, create)
247
700
{
248
700
  zval *referent;
249
250
2.09k
  ZEND_PARSE_PARAMETERS_START(1,1)
251
699
    Z_PARAM_OBJECT(referent)
252
700
  ZEND_PARSE_PARAMETERS_END();
253
254
679
  if (zend_weakref_find(referent, return_value)) {
255
83
      return;
256
83
  }
257
258
596
  zend_weakref_create(referent, return_value);
259
596
}
260
261
ZEND_METHOD(WeakReference, get)
262
544
{
263
544
  ZEND_PARSE_PARAMETERS_NONE();
264
265
544
  zend_weakref_get(getThis(), return_value);
266
544
}
267
268
static zend_object *zend_weakmap_create_object(zend_class_entry *ce)
269
2.31k
{
270
2.31k
  zend_weakmap *wm = zend_object_alloc(sizeof(zend_weakmap), ce);
271
2.31k
  zend_object_std_init(&wm->std, ce);
272
2.31k
  wm->std.handlers = &zend_weakmap_handlers;
273
274
2.31k
  zend_hash_init(&wm->ht, 0, NULL, ZVAL_PTR_DTOR, 0);
275
2.31k
  return &wm->std;
276
2.31k
}
277
278
static void zend_weakmap_free_obj(zend_object *object)
279
2.31k
{
280
2.31k
  zend_weakmap *wm = zend_weakmap_from(object);
281
2.31k
  zend_ulong obj_addr;
282
4.63k
  ZEND_HASH_FOREACH_NUM_KEY(&wm->ht, obj_addr) {
283
4.63k
    zend_weakref_unregister(
284
1.01k
      (zend_object *) obj_addr, ZEND_WEAKREF_ENCODE(wm, ZEND_WEAKREF_TAG_MAP));
285
1.01k
  } ZEND_HASH_FOREACH_END();
286
2.31k
  zend_hash_destroy(&wm->ht);
287
2.31k
  zend_object_std_dtor(&wm->std);
288
2.31k
}
289
290
static zval *zend_weakmap_read_dimension(zend_object *object, zval *offset, int type, zval *rv)
291
1.43k
{
292
1.43k
  if (offset == NULL) {
293
40
    zend_throw_error(NULL, "Cannot append to WeakMap");
294
40
    return NULL;
295
40
  }
296
297
1.39k
  if (Z_TYPE_P(offset) != IS_OBJECT) {
298
73
    zend_type_error("WeakMap key must be an object");
299
73
    return NULL;
300
73
  }
301
302
1.32k
  zend_weakmap *wm = zend_weakmap_from(object);
303
1.32k
  zend_object *obj_key = Z_OBJ_P(offset);
304
1.32k
  zval *zv = zend_hash_index_find(&wm->ht, (zend_ulong) obj_key);
305
1.32k
  if (zv == NULL) {
306
171
    if (type != BP_VAR_IS) {
307
171
      zend_throw_error(NULL,
308
171
        "Object %s#%d not contained in WeakMap", ZSTR_VAL(obj_key->ce->name), obj_key->handle);
309
171
      return NULL;
310
171
    }
311
0
    return NULL;
312
0
  }
313
314
1.14k
  if (type == BP_VAR_W || type == BP_VAR_RW) {
315
188
    ZVAL_MAKE_REF(zv);
316
188
  }
317
1.14k
  return zv;
318
1.14k
}
319
320
static void zend_weakmap_write_dimension(zend_object *object, zval *offset, zval *value)
321
3.75k
{
322
3.75k
  if (offset == NULL) {
323
40
    zend_throw_error(NULL, "Cannot append to WeakMap");
324
40
    return;
325
40
  }
326
327
3.71k
  if (Z_TYPE_P(offset) != IS_OBJECT) {
328
84
    zend_type_error("WeakMap key must be an object");
329
84
    return;
330
84
  }
331
332
3.63k
  zend_weakmap *wm = zend_weakmap_from(object);
333
3.63k
  zend_object *obj_key = Z_OBJ_P(offset);
334
3.63k
  Z_TRY_ADDREF_P(value);
335
336
3.63k
  zval *zv = zend_hash_index_find(&wm->ht, (zend_ulong) obj_key);
337
3.63k
  if (zv) {
338
781
    zval_ptr_dtor(zv);
339
781
    ZVAL_COPY_VALUE(zv, value);
340
781
    return;
341
781
  }
342
343
2.85k
  zend_weakref_register(obj_key, ZEND_WEAKREF_ENCODE(wm, ZEND_WEAKREF_TAG_MAP));
344
2.85k
  zend_hash_index_add_new(&wm->ht, (zend_ulong) obj_key, value);
345
2.85k
}
346
347
/* int return and check_empty due to Object Handler API */
348
static int zend_weakmap_has_dimension(zend_object *object, zval *offset, int check_empty)
349
2.25k
{
350
2.25k
  if (Z_TYPE_P(offset) != IS_OBJECT) {
351
59
    zend_type_error("WeakMap key must be an object");
352
59
    return 0;
353
59
  }
354
355
2.19k
  zend_weakmap *wm = zend_weakmap_from(object);
356
2.19k
  zval *zv = zend_hash_index_find(&wm->ht, (zend_ulong) Z_OBJ_P(offset));
357
2.19k
  if (!zv) {
358
265
    return 0;
359
265
  }
360
361
1.92k
  if (check_empty) {
362
916
    return i_zend_is_true(zv);
363
916
  }
364
1.01k
  return Z_TYPE_P(zv) != IS_NULL;
365
1.01k
}
366
367
static void zend_weakmap_unset_dimension(zend_object *object, zval *offset)
368
364
{
369
364
  if (Z_TYPE_P(offset) != IS_OBJECT) {
370
50
    zend_type_error("WeakMap key must be an object");
371
50
    return;
372
50
  }
373
374
314
  zend_weakmap *wm = zend_weakmap_from(object);
375
314
  zend_object *obj_key = Z_OBJ_P(offset);
376
314
  if (!zend_hash_index_exists(&wm->ht, (zend_ulong) Z_OBJ_P(offset))) {
377
    /* Object not in WeakMap, do nothing. */
378
114
    return;
379
114
  }
380
381
200
  zend_weakref_unregister(obj_key, ZEND_WEAKREF_ENCODE(wm, ZEND_WEAKREF_TAG_MAP));
382
200
}
383
384
static int zend_weakmap_count_elements(zend_object *object, zend_long *count)
385
739
{
386
739
  zend_weakmap *wm = zend_weakmap_from(object);
387
739
  *count = zend_hash_num_elements(&wm->ht);
388
739
  return SUCCESS;
389
739
}
390
391
static HashTable *zend_weakmap_get_properties_for(zend_object *object, zend_prop_purpose purpose)
392
3.47k
{
393
3.47k
  if (purpose != ZEND_PROP_PURPOSE_DEBUG) {
394
0
    return NULL;
395
0
  }
396
397
3.47k
  zend_weakmap *wm = zend_weakmap_from(object);
398
3.47k
  HashTable *ht;
399
3.47k
  ALLOC_HASHTABLE(ht);
400
3.47k
  zend_hash_init(ht, zend_hash_num_elements(&wm->ht), NULL, ZVAL_PTR_DTOR, 0);
401
402
3.47k
  zend_ulong obj_addr;
403
3.47k
  zval *val;
404
8.54k
  ZEND_HASH_FOREACH_NUM_KEY_VAL(&wm->ht, obj_addr, val) {
405
8.54k
    zval pair;
406
8.54k
    zval obj_zv;
407
2.50k
    array_init(&pair);
408
409
2.50k
    ZVAL_OBJ_COPY(&obj_zv, (zend_object *) obj_addr);
410
2.50k
    add_assoc_zval(&pair, "key", &obj_zv);
411
2.50k
    Z_TRY_ADDREF_P(val);
412
2.50k
    add_assoc_zval(&pair, "value", val);
413
414
8.54k
    zend_hash_next_index_insert(ht, &pair);
415
2.50k
  } ZEND_HASH_FOREACH_END();
416
417
3.47k
  return ht;
418
3.47k
}
419
420
static HashTable *zend_weakmap_get_gc(zend_object *object, zval **table, int *n)
421
938
{
422
938
  zend_weakmap *wm = zend_weakmap_from(object);
423
938
  *table = NULL;
424
938
  *n = 0;
425
938
  return &wm->ht;
426
938
}
427
428
static zend_object *zend_weakmap_clone_obj(zend_object *old_object)
429
324
{
430
324
  zend_object *new_object = zend_weakmap_create_object(zend_ce_weakmap);
431
324
  zend_weakmap *old_wm = zend_weakmap_from(old_object);
432
324
  zend_weakmap *new_wm = zend_weakmap_from(new_object);
433
324
  zend_hash_copy(&new_wm->ht, &old_wm->ht, NULL);
434
435
324
  zend_ulong obj_addr;
436
324
  zval *val;
437
928
  ZEND_HASH_FOREACH_NUM_KEY_VAL(&new_wm->ht, obj_addr, val) {
438
928
    zend_weakref_register(
439
302
      (zend_object *) obj_addr, ZEND_WEAKREF_ENCODE(new_wm, ZEND_WEAKREF_TAG_MAP));
440
928
    zval_add_ref(val);
441
302
  } ZEND_HASH_FOREACH_END();
442
324
  return new_object;
443
324
}
444
445
6.26k
static HashPosition *zend_weakmap_iterator_get_pos_ptr(zend_weakmap_iterator *iter) {
446
6.26k
  ZEND_ASSERT(iter->ht_iter != (uint32_t) -1);
447
6.26k
  return &EG(ht_iterators)[iter->ht_iter].pos;
448
6.26k
}
449
450
static void zend_weakmap_iterator_dtor(zend_object_iterator *obj_iter)
451
731
{
452
731
  zend_weakmap_iterator *iter = (zend_weakmap_iterator *) obj_iter;
453
731
  zend_hash_iterator_del(iter->ht_iter);
454
731
  zval_ptr_dtor(&iter->it.data);
455
731
}
456
457
static int zend_weakmap_iterator_valid(zend_object_iterator *obj_iter)
458
1.90k
{
459
1.90k
  zend_weakmap_iterator *iter = (zend_weakmap_iterator *) obj_iter;
460
1.90k
  zend_weakmap *wm = zend_weakmap_fetch(&iter->it.data);
461
1.90k
  HashPosition *pos = zend_weakmap_iterator_get_pos_ptr(iter);
462
1.90k
  return zend_hash_has_more_elements_ex(&wm->ht, pos);
463
1.90k
}
464
465
static zval *zend_weakmap_iterator_get_current_data(zend_object_iterator *obj_iter)
466
1.23k
{
467
1.23k
  zend_weakmap_iterator *iter = (zend_weakmap_iterator *) obj_iter;
468
1.23k
  zend_weakmap *wm = zend_weakmap_fetch(&iter->it.data);
469
1.23k
  HashPosition *pos = zend_weakmap_iterator_get_pos_ptr(iter);
470
1.23k
  return zend_hash_get_current_data_ex(&wm->ht, pos);
471
1.23k
}
472
473
static void zend_weakmap_iterator_get_current_key(zend_object_iterator *obj_iter, zval *key)
474
1.22k
{
475
1.22k
  zend_weakmap_iterator *iter = (zend_weakmap_iterator *) obj_iter;
476
1.22k
  zend_weakmap *wm = zend_weakmap_fetch(&iter->it.data);
477
1.22k
  HashPosition *pos = zend_weakmap_iterator_get_pos_ptr(iter);
478
479
1.22k
  zend_string *string_key;
480
1.22k
  zend_ulong num_key;
481
1.22k
  int key_type = zend_hash_get_current_key_ex(&wm->ht, &string_key, &num_key, pos);
482
1.22k
  if (key_type != HASH_KEY_IS_LONG) {
483
0
    ZEND_ASSERT(0 && "Must have integer key");
484
0
  }
485
486
1.22k
  ZVAL_OBJ_COPY(key, (zend_object *) num_key);
487
1.22k
}
488
489
static void zend_weakmap_iterator_move_forward(zend_object_iterator *obj_iter)
490
1.17k
{
491
1.17k
  zend_weakmap_iterator *iter = (zend_weakmap_iterator *) obj_iter;
492
1.17k
  zend_weakmap *wm = zend_weakmap_fetch(&iter->it.data);
493
1.17k
  HashPosition *pos = zend_weakmap_iterator_get_pos_ptr(iter);
494
1.17k
  zend_hash_move_forward_ex(&wm->ht, pos);
495
1.17k
}
496
497
static void zend_weakmap_iterator_rewind(zend_object_iterator *obj_iter)
498
731
{
499
731
  zend_weakmap_iterator *iter = (zend_weakmap_iterator *) obj_iter;
500
731
  zend_weakmap *wm = zend_weakmap_fetch(&iter->it.data);
501
731
  HashPosition *pos = zend_weakmap_iterator_get_pos_ptr(iter);
502
731
  zend_hash_internal_pointer_reset_ex(&wm->ht, pos);
503
731
}
504
505
static const zend_object_iterator_funcs zend_weakmap_iterator_funcs = {
506
  zend_weakmap_iterator_dtor,
507
  zend_weakmap_iterator_valid,
508
  zend_weakmap_iterator_get_current_data,
509
  zend_weakmap_iterator_get_current_key,
510
  zend_weakmap_iterator_move_forward,
511
  zend_weakmap_iterator_rewind,
512
  NULL,
513
  NULL, /* get_gc */
514
};
515
516
/* by_ref is int due to Iterator API */
517
static zend_object_iterator *zend_weakmap_get_iterator(
518
    zend_class_entry *ce, zval *object, int by_ref)
519
731
{
520
731
  zend_weakmap *wm = zend_weakmap_fetch(object);
521
731
  zend_weakmap_iterator *iter = emalloc(sizeof(zend_weakmap_iterator));
522
731
  zend_iterator_init(&iter->it);
523
731
  iter->it.funcs = &zend_weakmap_iterator_funcs;
524
731
  ZVAL_COPY(&iter->it.data, object);
525
731
  iter->ht_iter = zend_hash_iterator_add(&wm->ht, 0);
526
731
  return &iter->it;
527
731
}
528
529
ZEND_METHOD(WeakMap, offsetGet)
530
68
{
531
68
  zval *key;
532
533
68
  if (zend_parse_parameters(ZEND_NUM_ARGS(), "z", &key) == FAILURE) {
534
0
    return;
535
0
  }
536
537
68
  zval *zv = zend_weakmap_read_dimension(Z_OBJ_P(ZEND_THIS), key, BP_VAR_R, NULL);
538
68
  if (!zv) {
539
0
    return;
540
0
  }
541
542
68
  ZVAL_COPY(return_value, zv);
543
68
}
544
545
ZEND_METHOD(WeakMap, offsetSet)
546
77
{
547
77
  zval *key, *value;
548
549
77
  if (zend_parse_parameters(ZEND_NUM_ARGS(), "zz", &key, &value) == FAILURE) {
550
1
    return;
551
1
  }
552
553
76
  zend_weakmap_write_dimension(Z_OBJ_P(ZEND_THIS), key, value);
554
76
}
555
556
ZEND_METHOD(WeakMap, offsetExists)
557
65
{
558
65
  zval *key;
559
560
65
  if (zend_parse_parameters(ZEND_NUM_ARGS(), "z", &key) == FAILURE) {
561
0
    return;
562
0
  }
563
564
65
  RETURN_BOOL(zend_weakmap_has_dimension(Z_OBJ_P(ZEND_THIS), key, /* check_empty */ 0));
565
65
}
566
567
ZEND_METHOD(WeakMap, offsetUnset)
568
50
{
569
50
  zval *key;
570
571
50
  if (zend_parse_parameters(ZEND_NUM_ARGS(), "z", &key) == FAILURE) {
572
0
    return;
573
0
  }
574
575
50
  zend_weakmap_unset_dimension(Z_OBJ_P(ZEND_THIS), key);
576
50
}
577
578
ZEND_METHOD(WeakMap, count)
579
97
{
580
97
  if (zend_parse_parameters_none() == FAILURE) {
581
0
    return;
582
0
  }
583
584
97
  zend_long count;
585
97
  zend_weakmap_count_elements(Z_OBJ_P(ZEND_THIS), &count);
586
97
  RETURN_LONG(count);
587
97
}
588
589
ZEND_METHOD(WeakMap, getIterator)
590
0
{
591
0
  if (zend_parse_parameters_none() == FAILURE) {
592
0
    return;
593
0
  }
594
595
0
  zend_create_internal_iterator_zval(return_value, ZEND_THIS);
596
0
}
597
598
void zend_register_weakref_ce(void) /* {{{ */
599
6.27k
{
600
6.27k
  zend_class_entry ce;
601
602
6.27k
  INIT_CLASS_ENTRY(ce, "WeakReference", class_WeakReference_methods);
603
6.27k
  zend_ce_weakref = zend_register_internal_class(&ce);
604
6.27k
  zend_ce_weakref->ce_flags |= ZEND_ACC_FINAL | ZEND_ACC_NO_DYNAMIC_PROPERTIES;
605
606
6.27k
  zend_ce_weakref->create_object = zend_weakref_new;
607
6.27k
  zend_ce_weakref->serialize = zend_class_serialize_deny;
608
6.27k
  zend_ce_weakref->unserialize = zend_class_unserialize_deny;
609
610
6.27k
  memcpy(&zend_weakref_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers));
611
6.27k
  zend_weakref_handlers.offset = XtOffsetOf(zend_weakref, std);
612
613
6.27k
  zend_weakref_handlers.free_obj = zend_weakref_free;
614
6.27k
  zend_weakref_handlers.clone_obj = NULL;
615
616
6.27k
  INIT_CLASS_ENTRY(ce, "WeakMap", class_WeakMap_methods);
617
6.27k
  zend_ce_weakmap = zend_register_internal_class(&ce);
618
6.27k
  zend_ce_weakmap->ce_flags |= ZEND_ACC_FINAL | ZEND_ACC_NO_DYNAMIC_PROPERTIES;
619
6.27k
  zend_class_implements(
620
6.27k
    zend_ce_weakmap, 3, zend_ce_arrayaccess, zend_ce_countable, zend_ce_aggregate);
621
622
6.27k
  zend_ce_weakmap->create_object = zend_weakmap_create_object;
623
6.27k
  zend_ce_weakmap->get_iterator = zend_weakmap_get_iterator;
624
6.27k
  zend_ce_weakmap->serialize = zend_class_serialize_deny;
625
6.27k
  zend_ce_weakmap->unserialize = zend_class_unserialize_deny;
626
627
6.27k
  memcpy(&zend_weakmap_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers));
628
6.27k
  zend_weakmap_handlers.offset = XtOffsetOf(zend_weakmap, std);
629
6.27k
  zend_weakmap_handlers.free_obj = zend_weakmap_free_obj;
630
6.27k
  zend_weakmap_handlers.read_dimension = zend_weakmap_read_dimension;
631
6.27k
  zend_weakmap_handlers.write_dimension = zend_weakmap_write_dimension;
632
6.27k
  zend_weakmap_handlers.has_dimension = zend_weakmap_has_dimension;
633
6.27k
  zend_weakmap_handlers.unset_dimension = zend_weakmap_unset_dimension;
634
6.27k
  zend_weakmap_handlers.count_elements = zend_weakmap_count_elements;
635
6.27k
  zend_weakmap_handlers.get_properties_for = zend_weakmap_get_properties_for;
636
6.27k
  zend_weakmap_handlers.get_gc = zend_weakmap_get_gc;
637
6.27k
  zend_weakmap_handlers.clone_obj = zend_weakmap_clone_obj;
638
6.27k
}
639
/* }}} */
640