Coverage Report

Created: 2026-06-02 06:40

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/php-src/ext/opcache/jit/zend_jit_helpers.c
Line
Count
Source
1
/*
2
   +----------------------------------------------------------------------+
3
   | Zend JIT                                                             |
4
   +----------------------------------------------------------------------+
5
   | Copyright © The PHP Group and Contributors.                          |
6
   +----------------------------------------------------------------------+
7
   | This source file is subject to the Modified BSD License that is      |
8
   | bundled with this package in the file LICENSE, and is available      |
9
   | through the World Wide Web at <https://www.php.net/license/>.        |
10
   |                                                                      |
11
   | SPDX-License-Identifier: BSD-3-Clause                                |
12
   +----------------------------------------------------------------------+
13
   | Authors: Dmitry Stogov <dmitry@php.net>                              |
14
   +----------------------------------------------------------------------+
15
*/
16
17
#include "Zend/zend_portability.h"
18
#include "Zend/zend_types.h"
19
#include "Zend/zend_API.h"
20
21
0
static ZEND_COLD void undef_result_after_exception(void) {
22
0
  const zend_op *opline = EG(opline_before_exception);
23
0
  ZEND_ASSERT(EG(exception));
24
0
  if (opline && opline->result_type & (IS_VAR | IS_TMP_VAR)) {
25
0
    zend_execute_data *execute_data = EG(current_execute_data);
26
0
    ZVAL_UNDEF(EX_VAR(opline->result.var));
27
0
  }
28
0
}
29
30
static zend_never_inline zend_function* ZEND_FASTCALL _zend_jit_init_func_run_time_cache(zend_op_array *op_array) /* {{{ */
31
0
{
32
0
  void **run_time_cache;
33
34
0
  run_time_cache = zend_arena_alloc(&CG(arena), op_array->cache_size);
35
0
  memset(run_time_cache, 0, op_array->cache_size);
36
0
  ZEND_MAP_PTR_SET(op_array->run_time_cache, run_time_cache);
37
0
  return (zend_function*)op_array;
38
0
}
39
/* }}} */
40
41
static zend_never_inline zend_op_array* ZEND_FASTCALL zend_jit_init_func_run_time_cache_helper(zend_op_array *op_array) /* {{{ */
42
0
{
43
0
  void **run_time_cache;
44
45
0
  if (!RUN_TIME_CACHE(op_array)) {
46
0
    run_time_cache = zend_arena_alloc(&CG(arena), op_array->cache_size);
47
0
    memset(run_time_cache, 0, op_array->cache_size);
48
0
    ZEND_MAP_PTR_SET(op_array->run_time_cache, run_time_cache);
49
0
  }
50
0
  return op_array;
51
0
}
52
/* }}} */
53
54
static zend_function* ZEND_FASTCALL zend_jit_find_func_helper(zend_string *name, void **cache_slot)
55
0
{
56
0
  zval *func = zend_hash_find_known_hash(EG(function_table), name);
57
0
  zend_function *fbc;
58
59
0
  if (UNEXPECTED(func == NULL)) {
60
0
    return NULL;
61
0
  }
62
0
  fbc = Z_FUNC_P(func);
63
0
  if (EXPECTED(fbc->type == ZEND_USER_FUNCTION) && UNEXPECTED(!RUN_TIME_CACHE(&fbc->op_array))) {
64
0
    fbc = _zend_jit_init_func_run_time_cache(&fbc->op_array);
65
0
  }
66
0
  *cache_slot = fbc;
67
0
  return fbc;
68
0
}
69
70
static uint32_t ZEND_FASTCALL zend_jit_jmp_frameless_helper(zval *func_name, void **cache_slot)
71
0
{
72
0
  zval *func = zend_hash_find_known_hash(EG(function_table), Z_STR_P(func_name));
73
0
  zend_jmp_fl_result result = (func == NULL) + 1;
74
0
  *cache_slot = (void *)(uintptr_t)result;
75
0
  return result;
76
0
}
77
78
static zend_function* ZEND_FASTCALL zend_jit_find_ns_func_helper(zval *func_name, void **cache_slot)
79
0
{
80
0
  zval *func = zend_hash_find_known_hash(EG(function_table), Z_STR_P(func_name + 1));
81
0
  zend_function *fbc;
82
83
0
  if (func == NULL) {
84
0
    func = zend_hash_find_known_hash(EG(function_table), Z_STR_P(func_name + 2));
85
0
    if (UNEXPECTED(func == NULL)) {
86
0
      return NULL;
87
0
    }
88
0
  }
89
0
  fbc = Z_FUNC_P(func);
90
0
  if (EXPECTED(fbc->type == ZEND_USER_FUNCTION) && UNEXPECTED(!RUN_TIME_CACHE(&fbc->op_array))) {
91
0
    fbc = _zend_jit_init_func_run_time_cache(&fbc->op_array);
92
0
  }
93
0
  *cache_slot = fbc;
94
0
  return fbc;
95
0
}
96
97
static ZEND_COLD void ZEND_FASTCALL zend_jit_invalid_method_call(zval *object)
98
0
{
99
0
  zend_execute_data *execute_data = EG(current_execute_data);
100
0
  const zend_op *opline = EX(opline);
101
0
  zval *function_name = RT_CONSTANT(opline, opline->op2);
102
103
0
  if (Z_TYPE_P(object) == IS_UNDEF && opline->op1_type == IS_CV) {
104
0
    zend_string *cv = EX(func)->op_array.vars[EX_VAR_TO_NUM(opline->op1.var)];
105
106
0
    zend_error_unchecked(E_WARNING, "Undefined variable $%S", cv);
107
0
    if (UNEXPECTED(EG(exception) != NULL)) {
108
0
      return;
109
0
    }
110
0
    object = &EG(uninitialized_zval);
111
0
  }
112
0
  zend_throw_error(NULL, "Call to a member function %s() on %s",
113
0
    Z_STRVAL_P(function_name), zend_zval_value_name(object));
114
0
}
115
116
static ZEND_COLD void ZEND_FASTCALL zend_jit_invalid_method_call_tmp(zval *object)
117
0
{
118
0
  zend_execute_data *execute_data = EG(current_execute_data);
119
0
  const zend_op *opline = EX(opline);
120
121
0
  zend_jit_invalid_method_call(object);
122
0
  zval_ptr_dtor_nogc(EX_VAR(opline->op1.var));
123
0
}
124
125
static void ZEND_FASTCALL zend_jit_unref_helper(zval *zv)
126
0
{
127
0
  zend_reference *ref;
128
129
0
  ZEND_ASSERT(Z_ISREF_P(zv));
130
0
  ref = Z_REF_P(zv);
131
0
  ZVAL_COPY_VALUE(zv, &ref->val);
132
0
  if (GC_DELREF(ref) == 0) {
133
0
    efree_size(ref, sizeof(zend_reference));
134
0
  } else {
135
0
    Z_TRY_ADDREF_P(zv);
136
0
  }
137
0
}
138
139
static zend_function* ZEND_FASTCALL zend_jit_find_method_helper(zend_object *obj, zval *function_name, zend_object **obj_ptr)
140
0
{
141
0
  zend_execute_data *execute_data = EG(current_execute_data);
142
0
  const zend_op *opline = EX(opline);
143
0
  zend_class_entry *called_scope = obj->ce;
144
0
  zend_function *fbc;
145
146
0
  fbc = obj->handlers->get_method(obj_ptr, Z_STR_P(function_name), function_name + 1);
147
0
  if (UNEXPECTED(fbc == NULL)) {
148
0
    if (EXPECTED(!EG(exception))) {
149
0
      zend_undefined_method(called_scope, Z_STR_P(function_name));
150
0
    }
151
0
    return NULL;
152
0
  }
153
154
0
  if (EXPECTED(fbc->type == ZEND_USER_FUNCTION) && UNEXPECTED(!RUN_TIME_CACHE(&fbc->op_array))) {
155
0
    zend_init_func_run_time_cache(&fbc->op_array);
156
0
  }
157
158
0
  if (UNEXPECTED(obj != *obj_ptr)) {
159
0
    return fbc;
160
0
  }
161
162
0
  if (EXPECTED(!(fbc->common.fn_flags & (ZEND_ACC_CALL_VIA_TRAMPOLINE|ZEND_ACC_NEVER_CACHE)))) {
163
0
    CACHE_POLYMORPHIC_PTR(opline->result.num, called_scope, fbc);
164
0
  }
165
166
0
  return fbc;
167
0
}
168
169
static zend_function* ZEND_FASTCALL zend_jit_find_method_tmp_helper(zend_object *obj, zval *function_name, zend_object **obj_ptr)
170
0
{
171
0
  zend_function *fbc;
172
173
0
  fbc = zend_jit_find_method_helper(obj, function_name, obj_ptr);
174
0
  if (!fbc) {
175
0
    if (GC_DELREF(obj) == 0) {
176
0
      zend_objects_store_del(obj);
177
0
    }
178
0
  } else if (obj != *obj_ptr) {
179
0
    GC_ADDREF(*obj_ptr);
180
0
    if (GC_DELREF(obj) == 0) {
181
0
      zend_objects_store_del(obj);
182
0
    }
183
0
  }
184
0
  return fbc;
185
0
}
186
187
188
static zend_class_entry* ZEND_FASTCALL zend_jit_find_class_helper(zend_execute_data *execute_data)
189
0
{
190
0
  const zend_op *opline = EX(opline);
191
0
  zend_class_entry *ce;
192
193
0
  if (opline->op1_type == IS_CONST) {
194
    /* no function found. try a static method in class */
195
0
    ce = CACHED_PTR(opline->result.num);
196
0
    if (UNEXPECTED(ce == NULL)) {
197
0
      ce = zend_fetch_class_by_name(Z_STR_P(RT_CONSTANT(opline, opline->op1)), Z_STR_P(RT_CONSTANT(opline, opline->op1) + 1), ZEND_FETCH_CLASS_DEFAULT | ZEND_FETCH_CLASS_EXCEPTION);
198
0
    }
199
0
  } else if (opline->op1_type == IS_UNUSED) {
200
0
    ce = zend_fetch_class(NULL, opline->op1.num);
201
0
  } else {
202
0
    ce = Z_CE_P(EX_VAR(opline->op1.var));
203
0
  }
204
0
  return ce;
205
0
}
206
207
static zend_function* ZEND_FASTCALL zend_jit_find_static_method_helper(zend_execute_data *execute_data, zend_class_entry *ce)
208
0
{
209
0
  const zend_op *opline = EX(opline);
210
0
  zend_function *fbc;
211
212
0
  ZEND_ASSERT(opline->op2_type == IS_CONST);
213
214
0
  if (opline->op1_type == IS_CONST &&
215
0
      EXPECTED((fbc = CACHED_PTR(opline->result.num + sizeof(void*))) != NULL)) {
216
    /* nothing to do */
217
0
  } else if (opline->op1_type != IS_CONST &&
218
0
             EXPECTED(CACHED_PTR(opline->result.num) == ce)) {
219
0
    fbc = CACHED_PTR(opline->result.num + sizeof(void*));
220
0
  } else if (opline->op2_type != IS_UNUSED) {
221
0
    zval *function_name = RT_CONSTANT(opline, opline->op2);
222
223
0
    ZEND_ASSERT(Z_TYPE_P(function_name) == IS_STRING);
224
0
    if (ce->get_static_method) {
225
0
      fbc = ce->get_static_method(ce, Z_STR_P(function_name));
226
0
    } else {
227
0
      fbc = zend_std_get_static_method(ce, Z_STR_P(function_name), RT_CONSTANT(opline, opline->op2) + 1);
228
0
    }
229
0
    if (UNEXPECTED(fbc == NULL)) {
230
0
      if (EXPECTED(!EG(exception))) {
231
0
        zend_undefined_method(ce, Z_STR_P(function_name));
232
0
      }
233
0
      return NULL;
234
0
    }
235
0
    if (EXPECTED(!(fbc->common.fn_flags & (ZEND_ACC_CALL_VIA_TRAMPOLINE|ZEND_ACC_NEVER_CACHE))) &&
236
0
      EXPECTED(!(fbc->common.scope->ce_flags & ZEND_ACC_TRAIT))) {
237
0
      CACHE_POLYMORPHIC_PTR(opline->result.num, ce, fbc);
238
0
    }
239
0
    if (EXPECTED(fbc->type == ZEND_USER_FUNCTION) && UNEXPECTED(!RUN_TIME_CACHE(&fbc->op_array))) {
240
0
      zend_init_func_run_time_cache(&fbc->op_array);
241
0
    }
242
0
  } else {
243
0
    if (UNEXPECTED(ce->constructor == NULL)) {
244
0
      zend_throw_error(NULL, "Cannot call constructor");
245
0
      return NULL;
246
0
    }
247
0
    if (Z_TYPE(EX(This)) == IS_OBJECT && Z_OBJ(EX(This))->ce != ce->constructor->common.scope && (ce->constructor->common.fn_flags & ZEND_ACC_PRIVATE)) {
248
0
      zend_throw_error(NULL, "Cannot call private %s::__construct()", ZSTR_VAL(ce->name));
249
0
      return NULL;;
250
0
    }
251
0
    fbc = ce->constructor;
252
0
    if (EXPECTED(fbc->type == ZEND_USER_FUNCTION) && UNEXPECTED(!RUN_TIME_CACHE(&fbc->op_array))) {
253
0
      zend_init_func_run_time_cache(&fbc->op_array);
254
0
    }
255
0
  }
256
257
0
  return fbc;
258
0
}
259
260
static zend_execute_data* ZEND_FASTCALL zend_jit_push_this_method_call_frame(zend_class_entry *scope, zend_function *fbc, uint32_t num_args)
261
0
{
262
0
  zend_execute_data *execute_data = EG(current_execute_data);
263
264
0
  if (Z_TYPE(EX(This)) != IS_OBJECT || !instanceof_function(Z_OBJCE(EX(This)), scope)) {
265
0
    zend_non_static_method_call(fbc);
266
0
    return NULL;
267
0
  }
268
269
0
  scope = (zend_class_entry*)Z_OBJ(EX(This));
270
0
  return zend_vm_stack_push_call_frame(ZEND_CALL_NESTED_FUNCTION | ZEND_CALL_HAS_THIS, fbc, num_args, scope);
271
0
}
272
273
static zend_execute_data* ZEND_FASTCALL zend_jit_push_static_method_call_frame(zend_object *obj, zend_function *fbc, uint32_t num_args)
274
0
{
275
0
  zend_class_entry *scope = obj->ce;
276
277
0
  return zend_vm_stack_push_call_frame(ZEND_CALL_NESTED_FUNCTION, fbc, num_args, scope);
278
0
}
279
280
static zend_execute_data* ZEND_FASTCALL zend_jit_push_static_method_call_frame_tmp(zend_object *obj, zend_function *fbc, uint32_t num_args)
281
0
{
282
0
  zend_class_entry *scope = obj->ce;
283
284
0
  if (GC_DELREF(obj) == 0) {
285
0
    zend_objects_store_del(obj);
286
0
    if (UNEXPECTED(EG(exception))) {
287
0
      return NULL;
288
0
    }
289
0
  }
290
291
0
  return zend_vm_stack_push_call_frame(ZEND_CALL_NESTED_FUNCTION, fbc, num_args, scope);
292
0
}
293
294
static zend_execute_data* ZEND_FASTCALL zend_jit_extend_stack_helper(uint32_t used_stack, zend_function *fbc)
295
0
{
296
0
  zend_execute_data *call = (zend_execute_data*)zend_vm_stack_extend(used_stack);
297
0
  call->func = fbc;
298
0
  ZEND_CALL_INFO(call) = ZEND_CALL_NESTED_FUNCTION | ZEND_CALL_ALLOCATED;
299
0
  return call;
300
0
}
301
302
static zend_execute_data* ZEND_FASTCALL zend_jit_int_extend_stack_helper(uint32_t used_stack)
303
0
{
304
0
  zend_execute_data *call = (zend_execute_data*)zend_vm_stack_extend(used_stack);
305
0
  ZEND_CALL_INFO(call) = ZEND_CALL_NESTED_FUNCTION | ZEND_CALL_ALLOCATED;
306
0
  return call;
307
0
}
308
309
static zval* ZEND_FASTCALL zend_jit_symtable_find(HashTable *ht, zend_string *str)
310
0
{
311
0
  zend_ulong idx;
312
0
  register const char *tmp = str->val;
313
314
0
  do {
315
0
    if (*tmp > '9') {
316
0
      break;
317
0
    } else if (*tmp < '0') {
318
0
      if (*tmp != '-') {
319
0
        break;
320
0
      }
321
0
      tmp++;
322
0
      if (*tmp > '9' || *tmp < '0') {
323
0
        break;
324
0
      }
325
0
    }
326
0
    if (_zend_handle_numeric_str_ex(str->val, str->len, &idx)) {
327
0
      return zend_hash_index_find(ht, idx);
328
0
    }
329
0
  } while (0);
330
331
0
  return zend_hash_find(ht, str);
332
0
}
333
334
static zval* ZEND_FASTCALL zend_jit_hash_index_lookup_rw_no_packed(HashTable *ht, zend_long idx)
335
0
{
336
0
  zval *retval = NULL;
337
338
0
  if (!HT_IS_PACKED(ht)) {
339
0
    retval = _zend_hash_index_find(ht, idx);
340
0
  }
341
0
  if (!retval) {
342
0
    retval = zend_undefined_offset_write(ht, idx);
343
0
  }
344
0
  return retval;
345
0
}
346
347
static zval* ZEND_FASTCALL zend_jit_hash_index_lookup_rw(HashTable *ht, zend_long idx)
348
0
{
349
0
  zval *retval = zend_hash_index_find(ht, idx);
350
351
0
  if (!retval) {
352
0
    retval = zend_undefined_offset_write(ht, idx);
353
0
  }
354
0
  return retval;
355
0
}
356
357
static zval* ZEND_FASTCALL zend_jit_hash_lookup_rw(HashTable *ht, zend_string *str)
358
0
{
359
0
  zval *retval = zend_hash_find_known_hash(ht, str);
360
0
  if (!retval) {
361
    /* Key may be released while throwing the undefined index warning. */
362
0
    retval = zend_undefined_index_write(ht, str);
363
0
  }
364
0
  return retval;
365
0
}
366
367
static zval* ZEND_FASTCALL zend_jit_symtable_lookup_rw(HashTable *ht, zend_string *str)
368
0
{
369
0
  zend_ulong idx;
370
0
  register const char *tmp = str->val;
371
0
  zval *retval;
372
373
0
  do {
374
0
    if (*tmp > '9') {
375
0
      break;
376
0
    } else if (*tmp < '0') {
377
0
      if (*tmp != '-') {
378
0
        break;
379
0
      }
380
0
      tmp++;
381
0
      if (*tmp > '9' || *tmp < '0') {
382
0
        break;
383
0
      }
384
0
    }
385
0
    if (_zend_handle_numeric_str_ex(str->val, str->len, &idx)) {
386
0
      retval = zend_hash_index_find(ht, idx);
387
0
      if (!retval) {
388
0
        retval = zend_undefined_offset_write(ht, idx);
389
0
      }
390
0
      return retval;
391
0
    }
392
0
  } while (0);
393
394
0
  retval = zend_hash_find(ht, str);
395
0
  if (!retval) {
396
    /* Key may be released while throwing the undefined index warning. */
397
0
    retval = zend_undefined_index_write(ht, str);
398
0
  }
399
0
  return retval;
400
0
}
401
402
static zval* ZEND_FASTCALL zend_jit_symtable_lookup_w(HashTable *ht, zend_string *str)
403
0
{
404
0
  zend_ulong idx;
405
0
  register const char *tmp = str->val;
406
407
0
  do {
408
0
    if (*tmp > '9') {
409
0
      break;
410
0
    } else if (*tmp < '0') {
411
0
      if (*tmp != '-') {
412
0
        break;
413
0
      }
414
0
      tmp++;
415
0
      if (*tmp > '9' || *tmp < '0') {
416
0
        break;
417
0
      }
418
0
    }
419
0
    if (_zend_handle_numeric_str_ex(str->val, str->len, &idx)) {
420
0
      return zend_hash_index_lookup(ht, idx);
421
0
    }
422
0
  } while (0);
423
424
0
  return zend_hash_lookup(ht, str);
425
0
}
426
427
static int ZEND_FASTCALL zend_jit_undefined_op_helper(uint32_t var)
428
0
{
429
0
  const zend_execute_data *execute_data = EG(current_execute_data);
430
0
  zend_string *cv = EX(func)->op_array.vars[EX_VAR_TO_NUM(var)];
431
432
0
  zend_error_unchecked(E_WARNING, "Undefined variable $%S", cv);
433
0
  return EG(exception) == NULL;
434
0
}
435
436
static int ZEND_FASTCALL zend_jit_undefined_op_helper_write(HashTable *ht, uint32_t var)
437
0
{
438
0
  const zend_execute_data *execute_data = EG(current_execute_data);
439
0
  zend_string *cv = EX(func)->op_array.vars[EX_VAR_TO_NUM(var)];
440
441
  /* The array may be destroyed while throwing the notice.
442
   * Temporarily increase the refcount to detect this situation. */
443
0
  if (!(GC_FLAGS(ht) & IS_ARRAY_IMMUTABLE)) {
444
0
    GC_ADDREF(ht);
445
0
  }
446
0
  zend_error_unchecked(E_WARNING, "Undefined variable $%S", cv);
447
0
  if (!(GC_FLAGS(ht) & IS_ARRAY_IMMUTABLE) && GC_DELREF(ht) != 1) {
448
0
    if (!GC_REFCOUNT(ht)) {
449
0
      zend_array_destroy(ht);
450
0
    }
451
0
    return 0;
452
0
  }
453
0
  return EG(exception) == NULL;
454
0
}
455
456
static void ZEND_FASTCALL zend_jit_fetch_dim_r_helper(zend_array *ht, zval *dim, zval *result)
457
0
{
458
0
  zend_ulong hval;
459
0
  zend_string *offset_key;
460
0
  zval *retval;
461
0
  zend_execute_data *execute_data;
462
0
  const zend_op *opline;
463
464
0
  if (Z_TYPE_P(dim) == IS_REFERENCE) {
465
0
    dim = Z_REFVAL_P(dim);
466
0
  }
467
468
0
  switch (Z_TYPE_P(dim)) {
469
0
    case IS_LONG:
470
0
      hval = Z_LVAL_P(dim);
471
0
      goto num_index;
472
0
    case IS_STRING:
473
0
      offset_key = Z_STR_P(dim);
474
0
      goto str_index;
475
0
    case IS_UNDEF:
476
      /* The array may be destroyed while throwing the notice.
477
       * Temporarily increase the refcount to detect this situation. */
478
0
      if (!(GC_FLAGS(ht) & IS_ARRAY_IMMUTABLE)) {
479
0
        GC_ADDREF(ht);
480
0
      }
481
0
      execute_data = EG(current_execute_data);
482
0
      opline = EX(opline);
483
0
      zend_jit_undefined_op_helper(EG(current_execute_data)->opline->op2.var);
484
0
      if (!(GC_FLAGS(ht) & IS_ARRAY_IMMUTABLE) && !GC_DELREF(ht)) {
485
0
        zend_array_destroy(ht);
486
0
        if (opline->result_type & (IS_VAR | IS_TMP_VAR)) {
487
0
          if (EG(exception)) {
488
0
            ZVAL_UNDEF(EX_VAR(opline->result.var));
489
0
          } else {
490
0
            ZVAL_NULL(EX_VAR(opline->result.var));
491
0
          }
492
0
        }
493
0
        return;
494
0
      }
495
0
      if (EG(exception)) {
496
0
        if (opline->result_type & (IS_VAR | IS_TMP_VAR)) {
497
0
          ZVAL_UNDEF(EX_VAR(opline->result.var));
498
0
        }
499
0
        return;
500
0
      }
501
0
      ZEND_FALLTHROUGH;
502
0
    case IS_NULL:
503
0
      retval = zend_hash_find(ht, ZSTR_EMPTY_ALLOC());
504
0
      if (!retval) {
505
0
        ZVAL_NULL(result);
506
0
      } else {
507
0
        ZVAL_COPY_DEREF(result, retval);
508
0
      }
509
0
      zend_error(E_DEPRECATED, "Using null as an array offset is deprecated, use an empty string instead");
510
0
      if (!retval) {
511
0
        zend_error(E_WARNING, "Undefined array key \"\"");
512
0
      }
513
0
      return;
514
0
    case IS_DOUBLE:
515
      /* The array may be destroyed while throwing the notice.
516
       * Temporarily increase the refcount to detect this situation. */
517
0
      if (!(GC_FLAGS(ht) & IS_ARRAY_IMMUTABLE)) {
518
0
        GC_ADDREF(ht);
519
0
      }
520
0
      execute_data = EG(current_execute_data);
521
0
      opline = EX(opline);
522
0
      hval = zend_dval_to_lval_safe(Z_DVAL_P(dim));
523
0
      if (!(GC_FLAGS(ht) & IS_ARRAY_IMMUTABLE) && !GC_DELREF(ht)) {
524
0
        zend_array_destroy(ht);
525
0
        if (opline->result_type & (IS_VAR | IS_TMP_VAR)) {
526
0
          if (EG(exception)) {
527
0
            ZVAL_UNDEF(EX_VAR(opline->result.var));
528
0
          } else {
529
0
            ZVAL_NULL(EX_VAR(opline->result.var));
530
0
          }
531
0
        }
532
0
        return;
533
0
      }
534
0
      if (EG(exception)) {
535
0
        if (opline->result_type & (IS_VAR | IS_TMP_VAR)) {
536
0
          ZVAL_UNDEF(EX_VAR(opline->result.var));
537
0
        }
538
0
        return;
539
0
      }
540
0
      goto num_index;
541
0
    case IS_RESOURCE:
542
      /* The array may be destroyed while throwing the notice.
543
       * Temporarily increase the refcount to detect this situation. */
544
0
      if (!(GC_FLAGS(ht) & IS_ARRAY_IMMUTABLE)) {
545
0
        GC_ADDREF(ht);
546
0
      }
547
0
      execute_data = EG(current_execute_data);
548
0
      opline = EX(opline);
549
0
      zend_use_resource_as_offset(dim);
550
0
      if (!(GC_FLAGS(ht) & IS_ARRAY_IMMUTABLE) && !GC_DELREF(ht)) {
551
0
        zend_array_destroy(ht);
552
0
        if (opline->result_type & (IS_VAR | IS_TMP_VAR)) {
553
0
          if (EG(exception)) {
554
0
            ZVAL_UNDEF(EX_VAR(opline->result.var));
555
0
          } else {
556
0
            ZVAL_NULL(EX_VAR(opline->result.var));
557
0
          }
558
0
        }
559
0
        return;
560
0
      }
561
0
      if (EG(exception)) {
562
0
        if (opline->result_type & (IS_VAR | IS_TMP_VAR)) {
563
0
          ZVAL_UNDEF(EX_VAR(opline->result.var));
564
0
        }
565
0
        return;
566
0
      }
567
0
      hval = Z_RES_HANDLE_P(dim);
568
0
      goto num_index;
569
0
    case IS_FALSE:
570
0
      hval = 0;
571
0
      goto num_index;
572
0
    case IS_TRUE:
573
0
      hval = 1;
574
0
      goto num_index;
575
0
    default:
576
0
      zend_illegal_container_offset(ZSTR_KNOWN(ZEND_STR_ARRAY), dim, BP_VAR_R);
577
0
      undef_result_after_exception();
578
0
      return;
579
0
  }
580
581
0
str_index:
582
0
  if (ZEND_HANDLE_NUMERIC(offset_key, hval)) {
583
0
    goto num_index;
584
0
  }
585
0
  retval = zend_hash_find(ht, offset_key);
586
0
  if (!retval) {
587
0
    zend_error(E_WARNING, "Undefined array key \"%s\"", ZSTR_VAL(offset_key));
588
0
    ZVAL_NULL(result);
589
0
    return;
590
0
  }
591
0
  ZVAL_COPY_DEREF(result, retval);
592
0
  return;
593
594
0
num_index:
595
0
  ZEND_HASH_INDEX_FIND(ht, hval, retval, num_undef);
596
0
  ZVAL_COPY_DEREF(result, retval);
597
0
  return;
598
599
0
num_undef:
600
0
  zend_error(E_WARNING, "Undefined array key " ZEND_LONG_FMT, hval);
601
0
  ZVAL_NULL(result);
602
0
}
603
604
static void ZEND_FASTCALL zend_jit_fetch_dim_is_helper(zend_array *ht, zval *dim, zval *result)
605
0
{
606
0
  zend_ulong hval;
607
0
  zend_string *offset_key;
608
0
  zval *retval;
609
0
  zend_execute_data *execute_data;
610
0
  const zend_op *opline;
611
612
0
  if (Z_TYPE_P(dim) == IS_REFERENCE) {
613
0
    dim = Z_REFVAL_P(dim);
614
0
  }
615
616
0
  switch (Z_TYPE_P(dim)) {
617
0
    case IS_LONG:
618
0
      hval = Z_LVAL_P(dim);
619
0
      goto num_index;
620
0
    case IS_STRING:
621
0
      offset_key = Z_STR_P(dim);
622
0
      goto str_index;
623
0
    case IS_UNDEF:
624
      /* The array may be destroyed while throwing the notice.
625
       * Temporarily increase the refcount to detect this situation. */
626
0
      if (!(GC_FLAGS(ht) & IS_ARRAY_IMMUTABLE)) {
627
0
        GC_ADDREF(ht);
628
0
      }
629
0
      execute_data = EG(current_execute_data);
630
0
      opline = EX(opline);
631
0
      zend_jit_undefined_op_helper(EG(current_execute_data)->opline->op2.var);
632
0
      if (!(GC_FLAGS(ht) & IS_ARRAY_IMMUTABLE) && !GC_DELREF(ht)) {
633
0
        zend_array_destroy(ht);
634
0
        if (opline->result_type & (IS_VAR | IS_TMP_VAR)) {
635
0
          if (EG(exception)) {
636
0
            ZVAL_UNDEF(EX_VAR(opline->result.var));
637
0
          } else {
638
0
            ZVAL_NULL(EX_VAR(opline->result.var));
639
0
          }
640
0
        }
641
0
        return;
642
0
      }
643
0
      if (EG(exception)) {
644
0
        if (opline->result_type & (IS_VAR | IS_TMP_VAR)) {
645
0
          ZVAL_UNDEF(EX_VAR(opline->result.var));
646
0
        }
647
0
        return;
648
0
      }
649
0
      ZEND_FALLTHROUGH;
650
0
    case IS_NULL:
651
0
      retval = zend_hash_find(ht, ZSTR_EMPTY_ALLOC());
652
0
      if (!retval) {
653
0
        ZVAL_NULL(result);
654
0
      } else {
655
0
        ZVAL_COPY_DEREF(result, retval);
656
0
      }
657
658
0
      zend_error(E_DEPRECATED, "Using null as an array offset is deprecated, use an empty string instead");
659
660
0
      return;
661
0
    case IS_DOUBLE:
662
      /* The array may be destroyed while throwing the notice.
663
       * Temporarily increase the refcount to detect this situation. */
664
0
      if (!(GC_FLAGS(ht) & IS_ARRAY_IMMUTABLE)) {
665
0
        GC_ADDREF(ht);
666
0
      }
667
0
      execute_data = EG(current_execute_data);
668
0
      opline = EX(opline);
669
0
      hval = zend_dval_to_lval_safe(Z_DVAL_P(dim));
670
0
      if (!(GC_FLAGS(ht) & IS_ARRAY_IMMUTABLE) && !GC_DELREF(ht)) {
671
0
        zend_array_destroy(ht);
672
0
        if (opline->result_type & (IS_VAR | IS_TMP_VAR)) {
673
0
          if (EG(exception)) {
674
0
            ZVAL_UNDEF(EX_VAR(opline->result.var));
675
0
          } else {
676
0
            ZVAL_NULL(EX_VAR(opline->result.var));
677
0
          }
678
0
        }
679
0
        return;
680
0
      }
681
0
      if (EG(exception)) {
682
0
        if (opline->result_type & (IS_VAR | IS_TMP_VAR)) {
683
0
          ZVAL_UNDEF(EX_VAR(opline->result.var));
684
0
        }
685
0
        return;
686
0
      }
687
0
      goto num_index;
688
0
    case IS_RESOURCE:
689
      /* The array may be destroyed while throwing the notice.
690
       * Temporarily increase the refcount to detect this situation. */
691
0
      if (!(GC_FLAGS(ht) & IS_ARRAY_IMMUTABLE)) {
692
0
        GC_ADDREF(ht);
693
0
      }
694
0
      execute_data = EG(current_execute_data);
695
0
      opline = EX(opline);
696
0
      zend_use_resource_as_offset(dim);
697
0
      if (!(GC_FLAGS(ht) & IS_ARRAY_IMMUTABLE) && !GC_DELREF(ht)) {
698
0
        zend_array_destroy(ht);
699
0
        if (opline->result_type & (IS_VAR | IS_TMP_VAR)) {
700
0
          if (EG(exception)) {
701
0
            ZVAL_UNDEF(EX_VAR(opline->result.var));
702
0
          } else {
703
0
            ZVAL_NULL(EX_VAR(opline->result.var));
704
0
          }
705
0
        }
706
0
        return;
707
0
      }
708
0
      if (EG(exception)) {
709
0
        if (opline->result_type & (IS_VAR | IS_TMP_VAR)) {
710
0
          ZVAL_UNDEF(EX_VAR(opline->result.var));
711
0
        }
712
0
        return;
713
0
      }
714
0
      hval = Z_RES_HANDLE_P(dim);
715
0
      goto num_index;
716
0
    case IS_FALSE:
717
0
      hval = 0;
718
0
      goto num_index;
719
0
    case IS_TRUE:
720
0
      hval = 1;
721
0
      goto num_index;
722
0
    default:
723
0
      zend_illegal_container_offset(ZSTR_KNOWN(ZEND_STR_ARRAY), dim,
724
0
        EG(current_execute_data)->opline->opcode == ZEND_ISSET_ISEMPTY_DIM_OBJ ?
725
0
          BP_VAR_IS : BP_VAR_RW);
726
0
      undef_result_after_exception();
727
0
      return;
728
0
  }
729
730
0
str_index:
731
0
  if (ZEND_HANDLE_NUMERIC(offset_key, hval)) {
732
0
    goto num_index;
733
0
  }
734
0
  retval = zend_hash_find(ht, offset_key);
735
0
  if (!retval) {
736
0
    ZVAL_NULL(result);
737
0
    return;
738
0
  }
739
0
  ZVAL_COPY_DEREF(result, retval);
740
0
  return;
741
742
0
num_index:
743
0
  ZEND_HASH_INDEX_FIND(ht, hval, retval, num_undef);
744
0
  ZVAL_COPY_DEREF(result, retval);
745
0
  return;
746
747
0
num_undef:
748
0
  ZVAL_NULL(result);
749
0
}
750
751
static int ZEND_FASTCALL zend_jit_fetch_dim_isset_helper(zend_array *ht, zval *dim)
752
0
{
753
0
  zend_ulong hval;
754
0
  zend_string *offset_key;
755
0
  zval *retval;
756
757
0
  if (Z_TYPE_P(dim) == IS_REFERENCE) {
758
0
    dim = Z_REFVAL_P(dim);
759
0
  }
760
761
0
  switch (Z_TYPE_P(dim)) {
762
0
    case IS_LONG:
763
0
      hval = Z_LVAL_P(dim);
764
0
      goto num_index;
765
0
    case IS_STRING:
766
0
      offset_key = Z_STR_P(dim);
767
0
      goto str_index;
768
0
    case IS_UNDEF:
769
      /* The array may be destroyed while throwing the notice.
770
       * Temporarily increase the refcount to detect this situation. */
771
0
      if (!(GC_FLAGS(ht) & IS_ARRAY_IMMUTABLE)) {
772
0
        GC_ADDREF(ht);
773
0
      }
774
0
      zend_jit_undefined_op_helper(EG(current_execute_data)->opline->op2.var);
775
0
      if (!(GC_FLAGS(ht) & IS_ARRAY_IMMUTABLE) && !GC_DELREF(ht)) {
776
0
        zend_array_destroy(ht);
777
0
        return 0;
778
0
      }
779
0
      if (EG(exception)) {
780
0
        return 0;
781
0
      }
782
0
      ZEND_FALLTHROUGH;
783
0
    case IS_NULL: {
784
0
      int result = 0;
785
0
      retval = zend_hash_find(ht, ZSTR_EMPTY_ALLOC());
786
0
      if (retval) {
787
0
        result = Z_TYPE_P(retval) > IS_NULL;
788
0
      }
789
790
0
      zend_error(E_DEPRECATED, "Using null as an array offset is deprecated, use an empty string instead");
791
792
0
      return result;
793
0
    }
794
0
    case IS_DOUBLE:
795
      /* The array may be destroyed while throwing the notice.
796
       * Temporarily increase the refcount to detect this situation. */
797
0
      if (!(GC_FLAGS(ht) & IS_ARRAY_IMMUTABLE)) {
798
0
        GC_ADDREF(ht);
799
0
      }
800
0
      hval = zend_dval_to_lval_safe(Z_DVAL_P(dim));
801
0
      if (!(GC_FLAGS(ht) & IS_ARRAY_IMMUTABLE) && !GC_DELREF(ht)) {
802
0
        zend_array_destroy(ht);
803
0
        return 0;
804
0
      }
805
0
      if (EG(exception)) {
806
0
        return 0;
807
0
      }
808
0
      goto num_index;
809
0
    case IS_RESOURCE:
810
      /* The array may be destroyed while throwing the notice.
811
       * Temporarily increase the refcount to detect this situation. */
812
0
      if (!(GC_FLAGS(ht) & IS_ARRAY_IMMUTABLE)) {
813
0
        GC_ADDREF(ht);
814
0
      }
815
0
      zend_use_resource_as_offset(dim);
816
0
      if (!(GC_FLAGS(ht) & IS_ARRAY_IMMUTABLE) && !GC_DELREF(ht)) {
817
0
        zend_array_destroy(ht);
818
0
        return 0;
819
0
      }
820
0
      if (EG(exception)) {
821
0
        return 0;
822
0
      }
823
0
      hval = Z_RES_HANDLE_P(dim);
824
0
      goto num_index;
825
0
    case IS_FALSE:
826
0
      hval = 0;
827
0
      goto num_index;
828
0
    case IS_TRUE:
829
0
      hval = 1;
830
0
      goto num_index;
831
0
    default:
832
0
      zend_illegal_container_offset(ZSTR_KNOWN(ZEND_STR_ARRAY), dim, BP_VAR_IS);
833
0
      return 0;
834
0
  }
835
836
0
str_index:
837
0
  if (ZEND_HANDLE_NUMERIC(offset_key, hval)) {
838
0
    goto num_index;
839
0
  }
840
0
  retval = zend_hash_find(ht, offset_key);
841
0
  if (!retval) {
842
0
    return 0;
843
0
  }
844
0
  if (UNEXPECTED(Z_TYPE_P(retval) == IS_REFERENCE)) {
845
0
    retval = Z_REFVAL_P(retval);
846
0
  }
847
0
  return Z_TYPE_P(retval) > IS_NULL;
848
849
0
num_index:
850
0
  ZEND_HASH_INDEX_FIND(ht, hval, retval, num_undef);
851
0
  if (UNEXPECTED(Z_TYPE_P(retval) == IS_REFERENCE)) {
852
0
    retval = Z_REFVAL_P(retval);
853
0
  }
854
0
  return (Z_TYPE_P(retval) > IS_NULL);
855
856
0
num_undef:
857
0
  return 0;
858
0
}
859
860
static zval* ZEND_FASTCALL zend_jit_fetch_dim_rw_helper(zend_array *ht, zval *dim)
861
0
{
862
0
  zend_ulong hval;
863
0
  zend_string *offset_key;
864
0
  zval *retval;
865
0
  zend_execute_data *execute_data;
866
0
  const zend_op *opline;
867
868
0
  if (Z_TYPE_P(dim) == IS_REFERENCE) {
869
0
    dim = Z_REFVAL_P(dim);
870
0
  }
871
872
0
  switch (Z_TYPE_P(dim)) {
873
0
    case IS_LONG:
874
0
      hval = Z_LVAL_P(dim);
875
0
      goto num_index;
876
0
    case IS_STRING:
877
0
      offset_key = Z_STR_P(dim);
878
0
      goto str_index;
879
0
    case IS_UNDEF:
880
0
      execute_data = EG(current_execute_data);
881
0
      opline = EX(opline);
882
0
      if (UNEXPECTED(opline->opcode == ZEND_HANDLE_EXCEPTION)) {
883
0
        opline = EG(opline_before_exception);
884
0
      }
885
0
      if (opline && !zend_jit_undefined_op_helper_write(ht, opline->op2.var)) {
886
0
        if (opline->result_type & (IS_VAR | IS_TMP_VAR)) {
887
0
          if (EG(exception)) {
888
0
            ZVAL_UNDEF(EX_VAR(opline->result.var));
889
0
          } else {
890
0
            ZVAL_NULL(EX_VAR(opline->result.var));
891
0
          }
892
0
        }
893
0
        return NULL;
894
0
      }
895
0
      ZEND_FALLTHROUGH;
896
0
    case IS_NULL:
897
      /* The array may be destroyed while throwing the notice.
898
       * Temporarily increase the refcount to detect this situation. */
899
0
      GC_TRY_ADDREF(ht);
900
901
0
      execute_data = EG(current_execute_data);
902
0
      opline = EX(opline);
903
0
      zend_error(E_DEPRECATED, "Using null as an array offset is deprecated, use an empty string instead");
904
0
      if (!(GC_FLAGS(ht) & IS_ARRAY_IMMUTABLE) && GC_DELREF(ht) != 1) {
905
0
        if (!GC_REFCOUNT(ht)) {
906
0
          zend_array_destroy(ht);
907
0
        }
908
0
        if (opline->result_type & (IS_VAR | IS_TMP_VAR)) {
909
0
          if (EG(exception)) {
910
0
            ZVAL_UNDEF(EX_VAR(opline->result.var));
911
0
          } else {
912
0
            ZVAL_NULL(EX_VAR(opline->result.var));
913
0
          }
914
0
        }
915
0
        return NULL;
916
0
      }
917
0
      if (EG(exception)) {
918
0
        if (opline->result_type & (IS_VAR | IS_TMP_VAR)) {
919
0
          ZVAL_UNDEF(EX_VAR(opline->result.var));
920
0
        }
921
0
        return NULL;
922
0
      }
923
0
      offset_key = ZSTR_EMPTY_ALLOC();
924
0
      goto str_index;
925
0
    case IS_DOUBLE:
926
      /* The array may be destroyed while throwing the notice.
927
       * Temporarily increase the refcount to detect this situation. */
928
0
      if (!(GC_FLAGS(ht) & IS_ARRAY_IMMUTABLE)) {
929
0
        GC_ADDREF(ht);
930
0
      }
931
0
      execute_data = EG(current_execute_data);
932
0
      opline = EX(opline);
933
0
      hval = zend_dval_to_lval_safe(Z_DVAL_P(dim));
934
0
      if (!(GC_FLAGS(ht) & IS_ARRAY_IMMUTABLE) && GC_DELREF(ht) != 1) {
935
0
        if (!GC_REFCOUNT(ht)) {
936
0
          zend_array_destroy(ht);
937
0
        }
938
0
        if (opline->result_type & (IS_VAR | IS_TMP_VAR)) {
939
0
          if (EG(exception)) {
940
0
            ZVAL_UNDEF(EX_VAR(opline->result.var));
941
0
          } else {
942
0
            ZVAL_NULL(EX_VAR(opline->result.var));
943
0
          }
944
0
        }
945
0
        return NULL;
946
0
      }
947
0
      if (EG(exception)) {
948
0
        if (opline->result_type & (IS_VAR | IS_TMP_VAR)) {
949
0
          ZVAL_UNDEF(EX_VAR(opline->result.var));
950
0
        }
951
0
        return NULL;
952
0
      }
953
0
      goto num_index;
954
0
    case IS_RESOURCE:
955
      /* The array may be destroyed while throwing the notice.
956
       * Temporarily increase the refcount to detect this situation. */
957
0
      if (!(GC_FLAGS(ht) & IS_ARRAY_IMMUTABLE)) {
958
0
        GC_ADDREF(ht);
959
0
      }
960
0
      execute_data = EG(current_execute_data);
961
0
      opline = EX(opline);
962
0
      zend_use_resource_as_offset(dim);
963
0
      if (!(GC_FLAGS(ht) & IS_ARRAY_IMMUTABLE) && GC_DELREF(ht) != 1) {
964
0
        if (!GC_REFCOUNT(ht)) {
965
0
          zend_array_destroy(ht);
966
0
        }
967
0
        if (opline->result_type & (IS_VAR | IS_TMP_VAR)) {
968
0
          if (EG(exception)) {
969
0
            ZVAL_UNDEF(EX_VAR(opline->result.var));
970
0
          } else {
971
0
            ZVAL_NULL(EX_VAR(opline->result.var));
972
0
          }
973
0
        }
974
0
        return NULL;
975
0
      }
976
0
      if (EG(exception)) {
977
0
        if (opline->result_type & (IS_VAR | IS_TMP_VAR)) {
978
0
          ZVAL_UNDEF(EX_VAR(opline->result.var));
979
0
        }
980
0
        return NULL;
981
0
      }
982
0
      hval = Z_RES_HANDLE_P(dim);
983
0
      goto num_index;
984
0
    case IS_FALSE:
985
0
      hval = 0;
986
0
      goto num_index;
987
0
    case IS_TRUE:
988
0
      hval = 1;
989
0
      goto num_index;
990
0
    default:
991
0
      zend_illegal_container_offset(ZSTR_KNOWN(ZEND_STR_ARRAY), dim, BP_VAR_RW);
992
0
      undef_result_after_exception();
993
0
      return NULL;
994
0
  }
995
996
0
str_index:
997
0
  if (ZEND_HANDLE_NUMERIC(offset_key, hval)) {
998
0
    goto num_index;
999
0
  }
1000
0
  retval = zend_hash_find(ht, offset_key);
1001
0
  if (!retval) {
1002
    /* Key may be released while throwing the undefined index warning. */
1003
0
    retval = zend_undefined_index_write(ht, offset_key);
1004
0
  }
1005
0
  return retval;
1006
1007
0
num_index:
1008
0
  ZEND_HASH_INDEX_FIND(ht, hval, retval, num_undef);
1009
0
  return retval;
1010
1011
0
num_undef:
1012
0
  return zend_undefined_offset_write(ht, hval);
1013
0
}
1014
1015
static zval* ZEND_FASTCALL zend_jit_fetch_dim_w_helper(zend_array *ht, zval *dim)
1016
0
{
1017
0
  zend_ulong hval;
1018
0
  zend_string *offset_key;
1019
0
  zval *retval;
1020
0
  zend_execute_data *execute_data;
1021
0
  const zend_op *opline;
1022
1023
0
  if (Z_TYPE_P(dim) == IS_REFERENCE) {
1024
0
    dim = Z_REFVAL_P(dim);
1025
0
  }
1026
1027
0
  switch (Z_TYPE_P(dim)) {
1028
0
    case IS_LONG:
1029
0
      hval = Z_LVAL_P(dim);
1030
0
      goto num_index;
1031
0
    case IS_STRING:
1032
0
      offset_key = Z_STR_P(dim);
1033
0
      goto str_index;
1034
0
    case IS_UNDEF:
1035
0
      execute_data = EG(current_execute_data);
1036
0
      opline = EX(opline);
1037
0
      if (!zend_jit_undefined_op_helper_write(ht, opline->op2.var)) {
1038
0
        if (opline->result_type & (IS_VAR | IS_TMP_VAR)) {
1039
0
          if (EG(exception)) {
1040
0
            ZVAL_UNDEF(EX_VAR(opline->result.var));
1041
0
          } else {
1042
0
            ZVAL_NULL(EX_VAR(opline->result.var));
1043
0
          }
1044
0
        }
1045
0
        if (opline->opcode == ZEND_ASSIGN_DIM
1046
0
         && ((opline+1)->op1_type & (IS_VAR | IS_TMP_VAR))) {
1047
0
          zval_ptr_dtor_nogc(EX_VAR((opline+1)->op1.var));
1048
0
        }
1049
0
        return NULL;
1050
0
      }
1051
0
      ZEND_FALLTHROUGH;
1052
0
    case IS_NULL:
1053
      /* The array may be destroyed while throwing the notice.
1054
       * Temporarily increase the refcount to detect this situation. */
1055
0
      GC_TRY_ADDREF(ht);
1056
1057
0
      execute_data = EG(current_execute_data);
1058
0
      opline = EX(opline);
1059
0
      zend_error(E_DEPRECATED, "Using null as an array offset is deprecated, use an empty string instead");
1060
0
      if (!(GC_FLAGS(ht) & IS_ARRAY_IMMUTABLE) && GC_DELREF(ht) != 1) {
1061
0
        if (!GC_REFCOUNT(ht)) {
1062
0
          zend_array_destroy(ht);
1063
0
        }
1064
0
        if (opline->result_type & (IS_VAR | IS_TMP_VAR)) {
1065
0
          if (EG(exception)) {
1066
0
            ZVAL_UNDEF(EX_VAR(opline->result.var));
1067
0
          } else {
1068
0
            ZVAL_NULL(EX_VAR(opline->result.var));
1069
0
          }
1070
0
        }
1071
0
        if (opline->opcode == ZEND_ASSIGN_DIM
1072
0
         && ((opline+1)->op1_type & (IS_VAR | IS_TMP_VAR))) {
1073
0
          zval_ptr_dtor_nogc(EX_VAR((opline+1)->op1.var));
1074
0
        }
1075
0
        return NULL;
1076
0
      }
1077
0
      if (EG(exception)) {
1078
0
        if (opline->result_type & (IS_VAR | IS_TMP_VAR)) {
1079
0
          ZVAL_UNDEF(EX_VAR(opline->result.var));
1080
0
        }
1081
0
        return NULL;
1082
0
      }
1083
0
      offset_key = ZSTR_EMPTY_ALLOC();
1084
0
      goto str_index;
1085
0
    case IS_DOUBLE:
1086
      /* The array may be destroyed while throwing the notice.
1087
       * Temporarily increase the refcount to detect this situation. */
1088
0
      if (!(GC_FLAGS(ht) & IS_ARRAY_IMMUTABLE)) {
1089
0
        GC_ADDREF(ht);
1090
0
      }
1091
0
      execute_data = EG(current_execute_data);
1092
0
      opline = EX(opline);
1093
0
      hval = zend_dval_to_lval_safe(Z_DVAL_P(dim));
1094
0
      if (!(GC_FLAGS(ht) & IS_ARRAY_IMMUTABLE) && GC_DELREF(ht) != 1) {
1095
0
        if (!GC_REFCOUNT(ht)) {
1096
0
          zend_array_destroy(ht);
1097
0
        }
1098
0
        if (opline->result_type & (IS_VAR | IS_TMP_VAR)) {
1099
0
          if (EG(exception)) {
1100
0
            ZVAL_UNDEF(EX_VAR(opline->result.var));
1101
0
          } else {
1102
0
            ZVAL_NULL(EX_VAR(opline->result.var));
1103
0
          }
1104
0
        }
1105
0
        return NULL;
1106
0
      }
1107
0
      if (EG(exception)) {
1108
0
        if (opline->result_type & (IS_VAR | IS_TMP_VAR)) {
1109
0
          ZVAL_UNDEF(EX_VAR(opline->result.var));
1110
0
        }
1111
0
        return NULL;
1112
0
      }
1113
0
      goto num_index;
1114
0
    case IS_RESOURCE:
1115
      /* The array may be destroyed while throwing the notice.
1116
       * Temporarily increase the refcount to detect this situation. */
1117
0
      if (!(GC_FLAGS(ht) & IS_ARRAY_IMMUTABLE)) {
1118
0
        GC_ADDREF(ht);
1119
0
      }
1120
0
      execute_data = EG(current_execute_data);
1121
0
      opline = EX(opline);
1122
0
      zend_use_resource_as_offset(dim);
1123
0
      if (!(GC_FLAGS(ht) & IS_ARRAY_IMMUTABLE) && GC_DELREF(ht) != 1) {
1124
0
        if (!GC_REFCOUNT(ht)) {
1125
0
          zend_array_destroy(ht);
1126
0
        }
1127
0
        if (opline->result_type & (IS_VAR | IS_TMP_VAR)) {
1128
0
          if (EG(exception)) {
1129
0
            ZVAL_UNDEF(EX_VAR(opline->result.var));
1130
0
          } else {
1131
0
            ZVAL_NULL(EX_VAR(opline->result.var));
1132
0
          }
1133
0
        }
1134
0
        return NULL;
1135
0
      }
1136
0
      if (EG(exception)) {
1137
0
        if (opline->result_type & (IS_VAR | IS_TMP_VAR)) {
1138
0
          ZVAL_UNDEF(EX_VAR(opline->result.var));
1139
0
        }
1140
0
        return NULL;
1141
0
      }
1142
0
      hval = Z_RES_HANDLE_P(dim);
1143
0
      goto num_index;
1144
0
    case IS_FALSE:
1145
0
      hval = 0;
1146
0
      goto num_index;
1147
0
    case IS_TRUE:
1148
0
      hval = 1;
1149
0
      goto num_index;
1150
0
    default:
1151
0
      zend_illegal_container_offset(ZSTR_KNOWN(ZEND_STR_ARRAY), dim, BP_VAR_R);
1152
0
      undef_result_after_exception();
1153
0
      if (EG(opline_before_exception)
1154
0
       && (EG(opline_before_exception)+1)->opcode == ZEND_OP_DATA
1155
0
       && ((EG(opline_before_exception)+1)->op1_type & (IS_VAR|IS_TMP_VAR))) {
1156
0
        zend_execute_data *execute_data = EG(current_execute_data);
1157
1158
0
        zval_ptr_dtor_nogc(EX_VAR((EG(opline_before_exception)+1)->op1.var));
1159
0
      }
1160
0
      return NULL;
1161
0
  }
1162
1163
0
str_index:
1164
0
  if (ZEND_HANDLE_NUMERIC(offset_key, hval)) {
1165
0
    goto num_index;
1166
0
  }
1167
0
  return zend_hash_lookup(ht, offset_key);
1168
1169
0
num_index:
1170
0
  ZEND_HASH_INDEX_LOOKUP(ht, hval, retval);
1171
0
  return retval;
1172
0
}
1173
1174
/* type is one of the BP_VAR_* constants */
1175
static zend_never_inline zend_long zend_check_string_offset(zval *dim, int type)
1176
0
{
1177
0
  zend_long offset;
1178
1179
0
try_again:
1180
0
  switch(Z_TYPE_P(dim)) {
1181
0
    case IS_LONG:
1182
0
      return Z_LVAL_P(dim);
1183
0
    case IS_STRING:
1184
0
    {
1185
0
      bool trailing_data = false;
1186
      /* For BC reasons we allow errors so that we can warn on leading numeric string */
1187
0
      if (IS_LONG == is_numeric_string_ex(Z_STRVAL_P(dim), Z_STRLEN_P(dim), &offset, NULL,
1188
0
          /* allow errors */ true, NULL, &trailing_data)) {
1189
0
        if (UNEXPECTED(trailing_data)
1190
0
         && EG(current_execute_data)->opline->opcode != ZEND_FETCH_DIM_UNSET) {
1191
0
          zend_error(E_WARNING, "Illegal string offset \"%s\"", Z_STRVAL_P(dim));
1192
0
        }
1193
0
        return offset;
1194
0
      }
1195
0
      zend_illegal_container_offset(ZSTR_KNOWN(ZEND_STR_STRING), dim, BP_VAR_R);
1196
0
      return 0;
1197
0
    }
1198
0
    case IS_DOUBLE:
1199
      /* Suppress potential double warning */
1200
0
      zend_error(E_WARNING, "String offset cast occurred");
1201
0
      return zend_dval_to_lval_silent(Z_DVAL_P(dim));
1202
0
    case IS_UNDEF:
1203
0
      zend_jit_undefined_op_helper(EG(current_execute_data)->opline->op2.var);
1204
0
      ZEND_FALLTHROUGH;
1205
0
    case IS_NULL:
1206
0
    case IS_FALSE:
1207
0
    case IS_TRUE:
1208
0
      zend_error(E_WARNING, "String offset cast occurred");
1209
0
      break;
1210
0
    case IS_REFERENCE:
1211
0
      dim = Z_REFVAL_P(dim);
1212
0
      goto try_again;
1213
0
    default:
1214
0
      zend_illegal_container_offset(ZSTR_KNOWN(ZEND_STR_STRING), dim, type);
1215
0
      return 0;
1216
0
  }
1217
1218
0
  return zval_get_long_func(dim, /* is_strict */ false);
1219
0
}
1220
1221
static zend_always_inline zend_string* zend_jit_fetch_dim_str_offset(zend_string *str, zend_long offset)
1222
0
{
1223
0
  if (UNEXPECTED((zend_ulong)offset >= (zend_ulong)ZSTR_LEN(str))) {
1224
0
    if (EXPECTED(offset < 0)) {
1225
      /* Handle negative offset */
1226
0
      zend_long real_offset = (zend_long)ZSTR_LEN(str) + offset;
1227
1228
0
      if (EXPECTED(real_offset >= 0)) {
1229
0
        return ZSTR_CHAR((uint8_t)ZSTR_VAL(str)[real_offset]);
1230
0
      }
1231
0
    }
1232
0
    zend_error(E_WARNING, "Uninitialized string offset " ZEND_LONG_FMT, offset);
1233
0
    return ZSTR_EMPTY_ALLOC();
1234
0
  } else {
1235
0
    return ZSTR_CHAR((uint8_t)ZSTR_VAL(str)[offset]);
1236
0
  }
1237
0
}
1238
1239
static zend_string* ZEND_FASTCALL zend_jit_fetch_dim_str_offset_r_helper(zend_string *str, zend_long offset)
1240
0
{
1241
0
  return zend_jit_fetch_dim_str_offset(str, offset);
1242
0
}
1243
1244
static zend_string* ZEND_FASTCALL zend_jit_fetch_dim_str_r_helper(zend_string *str, zval *dim)
1245
0
{
1246
0
  zend_long offset;
1247
1248
0
  if (UNEXPECTED(Z_TYPE_P(dim) != IS_LONG)) {
1249
0
    if (!(GC_FLAGS(str) & IS_STR_INTERNED)) {
1250
0
      GC_ADDREF(str);
1251
0
    }
1252
0
    offset = zend_check_string_offset(dim, BP_VAR_R);
1253
0
    if (!(GC_FLAGS(str) & IS_STR_INTERNED) && UNEXPECTED(GC_DELREF(str) == 0)) {
1254
0
      zend_string *ret = zend_jit_fetch_dim_str_offset(str, offset);
1255
0
      zend_string_efree(str);
1256
0
      return ret;
1257
0
    }
1258
0
  } else {
1259
0
    offset = Z_LVAL_P(dim);
1260
0
  }
1261
0
  if (UNEXPECTED(EG(exception) != NULL)) {
1262
0
    return ZSTR_EMPTY_ALLOC();
1263
0
  }
1264
0
  return zend_jit_fetch_dim_str_offset(str, offset);
1265
0
}
1266
1267
static void ZEND_FASTCALL zend_jit_fetch_dim_str_is_helper(zend_string *str, zval *dim, zval *result)
1268
0
{
1269
0
  zend_long offset;
1270
1271
0
try_string_offset:
1272
0
  if (UNEXPECTED(Z_TYPE_P(dim) != IS_LONG)) {
1273
0
    switch (Z_TYPE_P(dim)) {
1274
      /* case IS_LONG: */
1275
0
      case IS_STRING:
1276
0
        if (IS_LONG == is_numeric_string(Z_STRVAL_P(dim), Z_STRLEN_P(dim), &offset, NULL, false)) {
1277
0
          goto out;
1278
0
        }
1279
0
        ZVAL_NULL(result);
1280
0
        return;
1281
0
      case IS_DOUBLE:
1282
0
        offset = zend_dval_to_lval_silent(Z_DVAL_P(dim));
1283
0
        goto out;
1284
0
      case IS_UNDEF:
1285
0
        zend_jit_undefined_op_helper(EG(current_execute_data)->opline->op2.var);
1286
0
        ZEND_FALLTHROUGH;
1287
0
      case IS_NULL:
1288
0
      case IS_FALSE:
1289
0
      case IS_TRUE:
1290
0
        break;
1291
0
      case IS_REFERENCE:
1292
0
        dim = Z_REFVAL_P(dim);
1293
0
        goto try_string_offset;
1294
0
      default:
1295
0
        zend_illegal_container_offset(ZSTR_KNOWN(ZEND_STR_STRING), dim,
1296
0
          EG(current_execute_data)->opline->opcode == ZEND_ISSET_ISEMPTY_DIM_OBJ ?
1297
0
            BP_VAR_IS : BP_VAR_RW);
1298
0
        ZVAL_NULL(result);
1299
0
        return;
1300
0
    }
1301
1302
0
    offset = zval_get_long_func(dim, /* is_strict */ false);
1303
0
  } else {
1304
0
    offset = Z_LVAL_P(dim);
1305
0
  }
1306
1307
0
out:
1308
0
  if ((zend_ulong)offset >= (zend_ulong)ZSTR_LEN(str)) {
1309
0
    if (offset < 0) {
1310
      /* Handle negative offset */
1311
0
      zend_long real_offset = (zend_long)ZSTR_LEN(str) + offset;
1312
1313
0
      if (real_offset >= 0) {
1314
0
        ZVAL_CHAR(result, (uint8_t)ZSTR_VAL(str)[real_offset]);
1315
0
        return;
1316
0
      }
1317
0
    }
1318
0
    ZVAL_NULL(result);
1319
0
  } else {
1320
0
    ZVAL_CHAR(result, (uint8_t)ZSTR_VAL(str)[offset]);
1321
0
  }
1322
0
}
1323
1324
static void ZEND_FASTCALL zend_jit_fetch_dim_obj_r_helper(zval *container, zval *dim, zval *result)
1325
0
{
1326
0
  zval *retval;
1327
0
  zend_object *obj = Z_OBJ_P(container);
1328
1329
0
  GC_ADDREF(obj);
1330
0
  if (UNEXPECTED(Z_TYPE_P(dim) == IS_UNDEF)) {
1331
0
    zend_jit_undefined_op_helper(EG(current_execute_data)->opline->op2.var);
1332
0
    dim = &EG(uninitialized_zval);
1333
0
  }
1334
1335
0
  retval = obj->handlers->read_dimension(obj, dim, BP_VAR_R, result);
1336
1337
0
  if (retval) {
1338
0
    if (result != retval) {
1339
0
      ZVAL_COPY_DEREF(result, retval);
1340
0
    } else if (UNEXPECTED(Z_ISREF_P(retval))) {
1341
0
      zend_unwrap_reference(retval);
1342
0
    }
1343
0
  } else {
1344
0
    ZVAL_NULL(result);
1345
0
  }
1346
0
  if (UNEXPECTED(GC_DELREF(obj) == 0)) {
1347
0
    zend_objects_store_del(obj);
1348
0
  }
1349
0
}
1350
1351
static void ZEND_FASTCALL zend_jit_fetch_dim_obj_is_helper(zval *container, zval *dim, zval *result)
1352
0
{
1353
0
  zval *retval;
1354
0
  zend_object *obj = Z_OBJ_P(container);
1355
1356
0
  GC_ADDREF(obj);
1357
0
  if (UNEXPECTED(Z_TYPE_P(dim) == IS_UNDEF)) {
1358
0
    zend_jit_undefined_op_helper(EG(current_execute_data)->opline->op2.var);
1359
0
    dim = &EG(uninitialized_zval);
1360
0
  }
1361
1362
0
  retval = obj->handlers->read_dimension(obj, dim, BP_VAR_IS, result);
1363
1364
0
  if (retval) {
1365
0
    if (result != retval) {
1366
0
      ZVAL_COPY_DEREF(result, retval);
1367
0
    } else if (UNEXPECTED(Z_ISREF_P(retval))) {
1368
0
      zend_unwrap_reference(result);
1369
0
    }
1370
0
  } else {
1371
0
    ZVAL_NULL(result);
1372
0
  }
1373
0
  if (UNEXPECTED(GC_DELREF(obj) == 0)) {
1374
0
    zend_objects_store_del(obj);
1375
0
  }
1376
0
}
1377
1378
static zend_never_inline void zend_assign_to_string_offset(zval *str, zval *dim, zval *value, zval *result)
1379
0
{
1380
0
  uint8_t c;
1381
0
  size_t string_len;
1382
0
  zend_long offset;
1383
0
  zend_string *s;
1384
1385
  /* separate string */
1386
0
  if (Z_REFCOUNTED_P(str) && Z_REFCOUNT_P(str) == 1) {
1387
0
    s = Z_STR_P(str);
1388
0
  } else {
1389
0
    s = zend_string_init(Z_STRVAL_P(str), Z_STRLEN_P(str), 0);
1390
0
    ZSTR_H(s) = ZSTR_H(Z_STR_P(str));
1391
0
    if (Z_REFCOUNTED_P(str)) {
1392
0
      GC_DELREF(Z_STR_P(str));
1393
0
    }
1394
0
    ZVAL_NEW_STR(str, s);
1395
0
  }
1396
1397
0
  if (UNEXPECTED(Z_TYPE_P(dim) != IS_LONG)) {
1398
    /* The string may be destroyed while throwing the notice.
1399
     * Temporarily increase the refcount to detect this situation. */
1400
0
    GC_ADDREF(s);
1401
0
    offset = zend_check_string_offset(dim, BP_VAR_W);
1402
0
    if (UNEXPECTED(GC_DELREF(s) == 0)) {
1403
0
      zend_string_efree(s);
1404
0
      if (result) {
1405
0
        ZVAL_NULL(result);
1406
0
      }
1407
0
      return;
1408
0
    }
1409
0
    if (UNEXPECTED(EG(exception) != NULL)) {
1410
0
      if (UNEXPECTED(result)) {
1411
0
        ZVAL_UNDEF(result);
1412
0
      }
1413
0
      return;
1414
0
    }
1415
0
  } else {
1416
0
    offset = Z_LVAL_P(dim);
1417
0
  }
1418
0
  if (offset < -(zend_long)ZSTR_LEN(s)) {
1419
    /* Error on negative offset */
1420
0
    zend_error(E_WARNING, "Illegal string offset " ZEND_LONG_FMT, offset);
1421
0
    if (result) {
1422
0
      ZVAL_NULL(result);
1423
0
    }
1424
0
    return;
1425
0
  }
1426
1427
0
  if (Z_TYPE_P(value) != IS_STRING) {
1428
0
    zend_string *tmp;
1429
1430
    /* The string may be destroyed while throwing the notice.
1431
     * Temporarily increase the refcount to detect this situation. */
1432
0
    GC_ADDREF(s);
1433
1434
0
    if (UNEXPECTED(Z_TYPE_P(value) == IS_UNDEF)) {
1435
0
      const zend_op *op_data = EG(current_execute_data)->opline + 1;
1436
0
      ZEND_ASSERT(op_data->opcode == ZEND_OP_DATA && op_data->op1_type == IS_CV);
1437
0
      zend_jit_undefined_op_helper(op_data->op1.var);
1438
0
      value = &EG(uninitialized_zval);
1439
0
    }
1440
1441
    /* Convert to string, just the time to pick the 1st byte */
1442
0
    tmp = zval_try_get_string_func(value);
1443
1444
0
    if (UNEXPECTED(GC_DELREF(s) == 0)) {
1445
0
      zend_string_efree(s);
1446
0
      if (tmp) {
1447
0
        zend_string_release_ex(tmp, 0);
1448
0
      }
1449
0
      if (result) {
1450
0
        ZVAL_NULL(result);
1451
0
      }
1452
0
      return;
1453
0
    }
1454
0
    if (UNEXPECTED(!tmp)) {
1455
0
      if (result) {
1456
0
        ZVAL_UNDEF(result);
1457
0
      }
1458
0
      return;
1459
0
    }
1460
1461
0
    string_len = ZSTR_LEN(tmp);
1462
0
    c = (uint8_t)ZSTR_VAL(tmp)[0];
1463
0
    zend_string_release(tmp);
1464
0
  } else {
1465
0
    string_len = Z_STRLEN_P(value);
1466
0
    c = (uint8_t)Z_STRVAL_P(value)[0];
1467
0
  }
1468
1469
1470
0
  if (string_len != 1) {
1471
0
    if (string_len == 0) {
1472
      /* Error on empty input string */
1473
0
      zend_throw_error(NULL, "Cannot assign an empty string to a string offset");
1474
0
      if (result) {
1475
0
        ZVAL_NULL(result);
1476
0
      }
1477
0
      return;
1478
0
    }
1479
1480
    /* The string may be destroyed while throwing the notice.
1481
     * Temporarily increase the refcount to detect this situation. */
1482
0
    GC_ADDREF(s);
1483
0
    zend_error(E_WARNING, "Only the first byte will be assigned to the string offset");
1484
0
    if (UNEXPECTED(GC_DELREF(s) == 0)) {
1485
0
      zend_string_efree(s);
1486
0
      if (result) {
1487
0
        ZVAL_NULL(result);
1488
0
      }
1489
0
      return;
1490
0
    }
1491
    /* Illegal offset assignment */
1492
0
    if (UNEXPECTED(EG(exception) != NULL)) {
1493
0
      if (result) {
1494
0
        ZVAL_UNDEF(result);
1495
0
      }
1496
0
      return;
1497
0
    }
1498
0
  }
1499
1500
0
  if (offset < 0) { /* Handle negative offset */
1501
0
    offset += (zend_long)ZSTR_LEN(s);
1502
0
  }
1503
1504
0
  if ((size_t)offset >= ZSTR_LEN(s)) {
1505
    /* Extend string if needed */
1506
0
    zend_long old_len = ZSTR_LEN(s);
1507
0
    ZVAL_NEW_STR(str, zend_string_extend(s, (size_t)offset + 1, 0));
1508
0
    memset(Z_STRVAL_P(str) + old_len, ' ', offset - old_len);
1509
0
    Z_STRVAL_P(str)[offset+1] = 0;
1510
0
  } else {
1511
0
    zend_string_forget_hash_val(Z_STR_P(str));
1512
0
  }
1513
1514
0
  Z_STRVAL_P(str)[offset] = c;
1515
1516
0
  if (result) {
1517
    /* Return the new character */
1518
0
    ZVAL_CHAR(result, c);
1519
0
  }
1520
0
}
1521
1522
static zend_always_inline void ZEND_FASTCALL zend_jit_fetch_dim_obj_helper(zval *object_ptr, zval *dim, zval *result, int type)
1523
0
{
1524
0
  zval *retval;
1525
1526
0
  if (EXPECTED(Z_TYPE_P(object_ptr) == IS_OBJECT)) {
1527
0
    zend_object *obj = Z_OBJ_P(object_ptr);
1528
1529
0
    GC_ADDREF(obj);
1530
0
    if (dim && UNEXPECTED(Z_ISUNDEF_P(dim))) {
1531
0
      const zend_op *opline = EG(current_execute_data)->opline;
1532
0
      zend_jit_undefined_op_helper(opline->op2.var);
1533
0
      dim = &EG(uninitialized_zval);
1534
0
    }
1535
1536
0
    retval = obj->handlers->read_dimension(obj, dim, type, result);
1537
0
    if (UNEXPECTED(retval == &EG(uninitialized_zval))) {
1538
0
      zend_class_entry *ce = obj->ce;
1539
1540
0
      ZVAL_NULL(result);
1541
0
      zend_error(E_NOTICE, "Indirect modification of overloaded element of %s has no effect", ZSTR_VAL(ce->name));
1542
0
    } else if (EXPECTED(retval && Z_TYPE_P(retval) != IS_UNDEF)) {
1543
0
      if (!Z_ISREF_P(retval)) {
1544
0
        if (result != retval) {
1545
0
          ZVAL_COPY(result, retval);
1546
0
          retval = result;
1547
0
        }
1548
0
        if (Z_TYPE_P(retval) != IS_OBJECT) {
1549
0
          zend_class_entry *ce = obj->ce;
1550
0
          zend_error(E_NOTICE, "Indirect modification of overloaded element of %s has no effect", ZSTR_VAL(ce->name));
1551
0
        }
1552
0
      } else if (UNEXPECTED(Z_REFCOUNT_P(retval) == 1)) {
1553
0
        ZVAL_UNREF(retval);
1554
0
      }
1555
0
      if (result != retval) {
1556
0
        ZVAL_INDIRECT(result, retval);
1557
0
      }
1558
0
    } else {
1559
0
      ZEND_ASSERT(EG(exception) && "read_dimension() returned NULL without exception");
1560
0
      ZVAL_UNDEF(result);
1561
0
    }
1562
0
    if (UNEXPECTED(GC_DELREF(obj) == 0)) {
1563
0
      zend_objects_store_del(obj);
1564
0
    }
1565
0
  } else if (EXPECTED(Z_TYPE_P(object_ptr) == IS_STRING)) {
1566
0
    if (!dim) {
1567
0
      zend_throw_error(NULL, "[] operator not supported for strings");
1568
0
    } else {
1569
0
      if (UNEXPECTED(Z_TYPE_P(dim) != IS_LONG)) {
1570
0
        zend_check_string_offset(dim, BP_VAR_RW);
1571
0
      }
1572
0
      zend_wrong_string_offset_error();
1573
0
    }
1574
0
    ZVAL_UNDEF(result);
1575
0
  } else if (Z_TYPE_P(object_ptr) == IS_FALSE) {
1576
0
    zend_array *arr = zend_new_array(0);
1577
0
    ZVAL_ARR(object_ptr, arr);
1578
0
    GC_ADDREF(arr);
1579
0
    zend_false_to_array_deprecated();
1580
0
    if (UNEXPECTED(GC_DELREF(arr) == 0)) {
1581
0
      zend_array_destroy(arr);
1582
0
      ZVAL_NULL(result);
1583
0
      return;
1584
0
    }
1585
0
    SEPARATE_ARRAY(object_ptr);
1586
0
    arr = Z_ARRVAL_P(object_ptr);
1587
0
    zval *var;
1588
0
    if (dim) {
1589
0
      if (type == BP_VAR_W) {
1590
0
        var = zend_jit_fetch_dim_w_helper(arr, dim);
1591
0
      } else {
1592
0
        ZEND_ASSERT(type == BP_VAR_RW);
1593
0
        var = zend_jit_fetch_dim_rw_helper(arr, dim);
1594
0
      }
1595
0
    } else {
1596
0
      var = zend_hash_next_index_insert_new(arr, &EG(uninitialized_zval));
1597
0
    }
1598
0
    if (var) {
1599
0
      ZVAL_INDIRECT(result, var);
1600
0
    } else {
1601
0
      ZVAL_UNDEF(result);
1602
0
    }
1603
0
  } else {
1604
0
    if (type == BP_VAR_UNSET) {
1605
0
      zend_throw_error(NULL, "Cannot unset offset in a non-array variable");
1606
0
      ZVAL_UNDEF(result);
1607
0
    } else {
1608
0
      zend_throw_error(NULL, "Cannot use a scalar value as an array");
1609
0
      ZVAL_UNDEF(result);
1610
0
    }
1611
0
  }
1612
0
}
1613
1614
static void ZEND_FASTCALL zend_jit_fetch_dim_obj_w_helper(zval *object_ptr, zval *dim, zval *result)
1615
0
{
1616
0
  zend_jit_fetch_dim_obj_helper(object_ptr, dim, result, BP_VAR_W);
1617
0
}
1618
1619
static void ZEND_FASTCALL zend_jit_fetch_dim_obj_rw_helper(zval *object_ptr, zval *dim, zval *result)
1620
0
{
1621
0
  zend_jit_fetch_dim_obj_helper(object_ptr, dim, result, BP_VAR_RW);
1622
0
}
1623
1624
//static void ZEND_FASTCALL zend_jit_fetch_dim_obj_unset_helper(zval *object_ptr, zval *dim, zval *result)
1625
//{
1626
//  zend_jit_fetch_dim_obj_helper(object_ptr, dim, result, BP_VAR_UNSET);
1627
//}
1628
1629
static void ZEND_FASTCALL zend_jit_assign_dim_helper(zval *object_ptr, zval *dim, zval *value, zval *result)
1630
0
{
1631
0
  if (EXPECTED(Z_TYPE_P(object_ptr) == IS_OBJECT)) {
1632
0
    zend_object *obj = Z_OBJ_P(object_ptr);
1633
1634
0
    GC_ADDREF(obj);
1635
0
    if (dim && UNEXPECTED(Z_TYPE_P(dim) == IS_UNDEF)) {
1636
0
      const zend_op *opline = EG(current_execute_data)->opline;
1637
0
      zend_jit_undefined_op_helper(opline->op2.var);
1638
0
      dim = &EG(uninitialized_zval);
1639
0
    }
1640
1641
0
    if (UNEXPECTED(Z_TYPE_P(value) == IS_UNDEF)) {
1642
0
      const zend_op *op_data = EG(current_execute_data)->opline + 1;
1643
0
      ZEND_ASSERT(op_data->opcode == ZEND_OP_DATA && op_data->op1_type == IS_CV);
1644
0
      zend_jit_undefined_op_helper(op_data->op1.var);
1645
0
      value = &EG(uninitialized_zval);
1646
0
    } else {
1647
0
      ZVAL_DEREF(value);
1648
0
    }
1649
1650
0
    obj->handlers->write_dimension(obj, dim, value);
1651
0
    if (result) {
1652
0
      if (EXPECTED(!EG(exception))) {
1653
0
        ZVAL_COPY(result, value);
1654
0
      } else {
1655
0
        ZVAL_UNDEF(result);
1656
0
      }
1657
0
    }
1658
0
    if (UNEXPECTED(GC_DELREF(obj) == 0)) {
1659
0
      zend_objects_store_del(obj);
1660
0
    }
1661
0
    return;
1662
0
  } else if (EXPECTED(Z_TYPE_P(object_ptr) == IS_STRING) && EXPECTED(dim != NULL)) {
1663
0
    zend_assign_to_string_offset(object_ptr, dim, value, result);
1664
0
    return;
1665
0
  }
1666
1667
0
  if (UNEXPECTED(Z_TYPE_P(value) == IS_UNDEF)) {
1668
0
    const zend_op *op_data = EG(current_execute_data)->opline + 1;
1669
0
    ZEND_ASSERT(op_data->opcode == ZEND_OP_DATA && op_data->op1_type == IS_CV);
1670
0
    zend_jit_undefined_op_helper(op_data->op1.var);
1671
0
    value = &EG(uninitialized_zval);
1672
0
  }
1673
1674
0
  if (EXPECTED(Z_TYPE_P(object_ptr) == IS_STRING)) {
1675
0
    zend_throw_error(NULL, "[] operator not supported for strings");
1676
0
    if (result) {
1677
0
      ZVAL_UNDEF(result);
1678
0
    }
1679
0
  } else if (Z_TYPE_P(object_ptr) == IS_FALSE) {
1680
0
    zend_array *arr = zend_new_array(0);
1681
0
    ZVAL_ARR(object_ptr, arr);
1682
0
    GC_ADDREF(arr);
1683
0
    zend_false_to_array_deprecated();
1684
0
    if (UNEXPECTED(GC_DELREF(arr) == 0)) {
1685
0
      zend_array_destroy(arr);
1686
0
      if (result) {
1687
0
        ZVAL_NULL(result);
1688
0
      }
1689
0
      return;
1690
0
    }
1691
0
    SEPARATE_ARRAY(object_ptr);
1692
0
    arr = Z_ARRVAL_P(object_ptr);
1693
0
    zval *var = dim
1694
0
      ? zend_jit_fetch_dim_w_helper(arr, dim)
1695
0
      : zend_hash_next_index_insert_new(arr, &EG(uninitialized_zval));
1696
0
    if (!var) {
1697
0
      if (result) {
1698
0
        ZVAL_UNDEF(result);
1699
0
      }
1700
0
      return;
1701
0
    }
1702
1703
0
    ZVAL_COPY_DEREF(var, value);
1704
0
    if (result) {
1705
0
      ZVAL_COPY(result, var);
1706
0
    }
1707
0
  } else {
1708
0
    if (dim && UNEXPECTED(Z_TYPE_P(dim) == IS_UNDEF)) {
1709
0
      const zend_op *opline = EG(current_execute_data)->opline;
1710
0
      zend_jit_undefined_op_helper(opline->op2.var);
1711
0
      dim = &EG(uninitialized_zval);
1712
0
    }
1713
0
    zend_throw_error(NULL, "Cannot use a scalar value as an array");
1714
0
    if (result) {
1715
0
      ZVAL_UNDEF(result);
1716
0
    }
1717
0
  }
1718
0
}
1719
1720
static void ZEND_FASTCALL zend_jit_assign_dim_op_helper(zval *container, zval *dim, zval *value, binary_op_type binary_op)
1721
0
{
1722
0
  if (EXPECTED(Z_TYPE_P(container) == IS_OBJECT)) {
1723
0
    zend_object *obj = Z_OBJ_P(container);
1724
0
    zval *z;
1725
0
    zval rv, res;
1726
1727
0
    GC_ADDREF(obj);
1728
0
    if (dim && UNEXPECTED(Z_ISUNDEF_P(dim))) {
1729
0
      const zend_op *opline = EG(current_execute_data)->opline;
1730
0
      zend_jit_undefined_op_helper(opline->op2.var);
1731
0
      dim = &EG(uninitialized_zval);
1732
0
    }
1733
1734
0
    z = obj->handlers->read_dimension(obj, dim, BP_VAR_R, &rv);
1735
0
    if (z != NULL) {
1736
1737
0
      if (binary_op(&res, Z_ISREF_P(z) ? Z_REFVAL_P(z) : z, value) == SUCCESS) {
1738
0
        obj->handlers->write_dimension(obj, dim, &res);
1739
0
      }
1740
0
      if (z == &rv) {
1741
0
        zval_ptr_dtor(&rv);
1742
0
      }
1743
0
      zval_ptr_dtor(&res);
1744
0
    } else {
1745
      /* Exception is thrown in this case */
1746
0
      GC_DELREF(obj);
1747
0
      return;
1748
0
    }
1749
0
    if (UNEXPECTED(GC_DELREF(obj) == 0)) {
1750
0
      zend_objects_store_del(obj);
1751
//???   if (retval) {
1752
//???     ZVAL_NULL(retval);
1753
//???   }
1754
0
    }
1755
0
  } else if (UNEXPECTED(Z_TYPE_P(container) == IS_STRING)) {
1756
0
    if (!dim) {
1757
0
      zend_throw_error(NULL, "[] operator not supported for strings");
1758
0
    } else {
1759
0
      if (UNEXPECTED(Z_TYPE_P(dim) != IS_LONG)) {
1760
0
        zend_check_string_offset(dim, BP_VAR_RW);
1761
0
      }
1762
0
      zend_wrong_string_offset_error();
1763
0
    }
1764
0
  } else if (Z_TYPE_P(container) == IS_FALSE) {
1765
0
    zend_array *arr = zend_new_array(0);
1766
0
    ZVAL_ARR(container, arr);
1767
0
    GC_ADDREF(arr);
1768
0
    zend_false_to_array_deprecated();
1769
0
    if (UNEXPECTED(GC_DELREF(arr) == 0)) {
1770
0
      zend_array_destroy(arr);
1771
0
      return;
1772
0
    }
1773
0
    SEPARATE_ARRAY(container);
1774
0
    arr = Z_ARRVAL_P(container);
1775
0
    zval *var = dim
1776
0
      ? zend_jit_fetch_dim_rw_helper(arr, dim)
1777
0
      : zend_hash_next_index_insert_new(arr, &EG(uninitialized_zval));
1778
0
    if (var) {
1779
0
      binary_op(var, var, value);
1780
0
    }
1781
0
  } else {
1782
0
    zend_throw_error(NULL, "Cannot use a scalar value as an array");
1783
0
  }
1784
0
}
1785
1786
static void ZEND_FASTCALL zend_jit_fast_assign_concat_helper(zval *op1, zval *op2)
1787
0
{
1788
0
  size_t op1_len = Z_STRLEN_P(op1);
1789
0
  size_t op2_len = Z_STRLEN_P(op2);
1790
0
  size_t result_len = op1_len + op2_len;
1791
0
  zend_string *result_str;
1792
0
  uint32_t flags = ZSTR_GET_COPYABLE_CONCAT_PROPERTIES_BOTH(Z_STR_P(op1), Z_STR_P(op2));
1793
1794
0
  if (UNEXPECTED(op1_len > ZSTR_MAX_LEN - op2_len)) {
1795
0
    zend_throw_error(NULL, "String size overflow");
1796
0
    return;
1797
0
  }
1798
1799
0
  do {
1800
0
    if (Z_REFCOUNTED_P(op1)) {
1801
0
      if (GC_REFCOUNT(Z_STR_P(op1)) == 1) {
1802
0
        result_str = perealloc(Z_STR_P(op1), ZEND_MM_ALIGNED_SIZE(_ZSTR_STRUCT_SIZE(result_len)), 0);
1803
0
        ZSTR_LEN(result_str) = result_len;
1804
0
        zend_string_forget_hash_val(result_str);
1805
0
        if (UNEXPECTED(Z_STR_P(op1) == Z_STR_P(op2))) {
1806
0
          ZVAL_NEW_STR(op2, result_str);
1807
0
        }
1808
0
        break;
1809
0
      }
1810
0
      GC_DELREF(Z_STR_P(op1));
1811
0
    }
1812
0
    result_str = zend_string_alloc(result_len, 0);
1813
0
    memcpy(ZSTR_VAL(result_str), Z_STRVAL_P(op1), op1_len);
1814
0
  } while(0);
1815
1816
0
  GC_ADD_FLAGS(result_str, flags);
1817
0
  ZVAL_NEW_STR(op1, result_str);
1818
0
  memcpy(ZSTR_VAL(result_str) + op1_len, Z_STRVAL_P(op2), op2_len);
1819
0
  ZSTR_VAL(result_str)[result_len] = '\0';
1820
0
}
1821
1822
static void ZEND_FASTCALL zend_jit_fast_concat_helper(zval *result, zval *op1, zval *op2)
1823
0
{
1824
0
  size_t op1_len = Z_STRLEN_P(op1);
1825
0
  size_t op2_len = Z_STRLEN_P(op2);
1826
0
  size_t result_len = op1_len + op2_len;
1827
0
  zend_string *result_str;
1828
0
  uint32_t flags = ZSTR_GET_COPYABLE_CONCAT_PROPERTIES_BOTH(Z_STR_P(op1), Z_STR_P(op2));
1829
1830
0
  if (UNEXPECTED(op1_len > ZSTR_MAX_LEN - op2_len)) {
1831
0
    zend_throw_error(NULL, "String size overflow");
1832
0
    return;
1833
0
  }
1834
1835
0
  result_str = zend_string_alloc(result_len, 0);
1836
0
  GC_ADD_FLAGS(result_str, flags);
1837
0
  memcpy(ZSTR_VAL(result_str), Z_STRVAL_P(op1), op1_len);
1838
1839
0
  ZVAL_NEW_STR(result, result_str);
1840
1841
0
  memcpy(ZSTR_VAL(result_str) + op1_len, Z_STRVAL_P(op2), op2_len);
1842
0
  ZSTR_VAL(result_str)[result_len] = '\0';
1843
0
}
1844
1845
static void ZEND_FASTCALL zend_jit_fast_concat_tmp_helper(zval *result, zval *op1, zval *op2)
1846
0
{
1847
0
  zend_string *op1_str = Z_STR_P(op1);
1848
0
  size_t op1_len = ZSTR_LEN(op1_str);
1849
0
  size_t op2_len = Z_STRLEN_P(op2);
1850
0
  size_t result_len = op1_len + op2_len;
1851
0
  zend_string *result_str;
1852
0
  uint32_t flags = ZSTR_GET_COPYABLE_CONCAT_PROPERTIES_BOTH(Z_STR_P(op1), Z_STR_P(op2));
1853
1854
0
  if (UNEXPECTED(op1_len > ZSTR_MAX_LEN - op2_len)) {
1855
0
    zend_throw_error(NULL, "String size overflow");
1856
0
    return;
1857
0
  }
1858
1859
0
  do {
1860
0
    if (!ZSTR_IS_INTERNED(op1_str)) {
1861
0
      if (GC_REFCOUNT(op1_str) == 1) {
1862
0
        Z_STR_P(op1) = result_str =
1863
0
          perealloc(op1_str, ZEND_MM_ALIGNED_SIZE(_ZSTR_STRUCT_SIZE(result_len)), 0);
1864
0
        ZSTR_LEN(result_str) = result_len;
1865
0
        zend_string_forget_hash_val(result_str);
1866
0
        break;
1867
0
      }
1868
0
      GC_DELREF(op1_str);
1869
0
    }
1870
0
    result_str = zend_string_alloc(result_len, 0);
1871
0
    memcpy(ZSTR_VAL(result_str), ZSTR_VAL(op1_str), op1_len);
1872
0
  } while (0);
1873
1874
0
  GC_ADD_FLAGS(result_str, flags);
1875
0
  ZVAL_NEW_STR(result, result_str);
1876
1877
0
  memcpy(ZSTR_VAL(result_str) + op1_len, Z_STRVAL_P(op2), op2_len);
1878
0
  ZSTR_VAL(result_str)[result_len] = '\0';
1879
0
}
1880
1881
static int ZEND_FASTCALL zend_jit_isset_dim_helper(zval *container, zval *offset)
1882
0
{
1883
0
  if (UNEXPECTED(Z_TYPE_P(offset) == IS_UNDEF)) {
1884
0
    zend_jit_undefined_op_helper(EG(current_execute_data)->opline->op2.var);
1885
0
    offset = &EG(uninitialized_zval);
1886
0
  }
1887
1888
0
  if (EXPECTED(Z_TYPE_P(container) == IS_OBJECT)) {
1889
0
    return Z_OBJ_HT_P(container)->has_dimension(Z_OBJ_P(container), offset, 0);
1890
0
  } else if (EXPECTED(Z_TYPE_P(container) == IS_STRING)) { /* string offsets */
1891
0
    zend_long lval;
1892
1893
0
    if (EXPECTED(Z_TYPE_P(offset) == IS_LONG)) {
1894
0
      lval = Z_LVAL_P(offset);
1895
0
isset_str_offset:
1896
0
      if (UNEXPECTED(lval < 0)) { /* Handle negative offset */
1897
0
        lval += (zend_long)Z_STRLEN_P(container);
1898
0
      }
1899
0
      if (EXPECTED(lval >= 0) && (size_t)lval < Z_STRLEN_P(container)) {
1900
0
        return 1;
1901
0
      }
1902
0
    } else {
1903
0
      ZVAL_DEREF(offset);
1904
0
      if (Z_TYPE_P(offset) < IS_STRING /* simple scalar types */
1905
0
          || (Z_TYPE_P(offset) == IS_STRING /* or numeric string */
1906
0
            && IS_LONG == is_numeric_string(Z_STRVAL_P(offset), Z_STRLEN_P(offset), NULL, NULL, false))) {
1907
0
        lval = zval_get_long_ex(offset, /* is_strict */ true);
1908
0
        goto isset_str_offset;
1909
0
      }
1910
0
    }
1911
0
  }
1912
0
  return 0;
1913
0
}
1914
1915
static void ZEND_FASTCALL zend_jit_free_call_frame(zend_execute_data *call)
1916
0
{
1917
0
  zend_vm_stack_free_call_frame(call);
1918
0
}
1919
1920
static zend_reference* ZEND_FASTCALL zend_jit_fetch_global_helper(zend_string *varname, void **cache_slot)
1921
0
{
1922
0
  zval *value;
1923
0
  uintptr_t idx;
1924
0
  zend_reference *ref;
1925
1926
  /* We store "hash slot index" + 1 (NULL is a mark of uninitialized cache slot) */
1927
0
  idx = (uintptr_t)CACHED_PTR_EX(cache_slot) - 1;
1928
0
  if (EXPECTED(idx < EG(symbol_table).nNumUsed * sizeof(Bucket))) {
1929
0
    Bucket *p = (Bucket*)((char*)EG(symbol_table).arData + idx);
1930
1931
0
    if (EXPECTED(p->key == varname) ||
1932
0
          (EXPECTED(p->h == ZSTR_H(varname)) &&
1933
0
           EXPECTED(p->key != NULL) &&
1934
0
           EXPECTED(zend_string_equal_content(p->key, varname)))) {
1935
1936
0
      value = (zval*)p; /* value = &p->val; */
1937
0
      goto check_indirect;
1938
0
    }
1939
0
  }
1940
1941
0
  value = zend_hash_find_known_hash(&EG(symbol_table), varname);
1942
0
  if (UNEXPECTED(value == NULL)) {
1943
0
    value = zend_hash_add_new(&EG(symbol_table), varname, &EG(uninitialized_zval));
1944
0
    idx = (char*)value - (char*)EG(symbol_table).arData;
1945
    /* Store "hash slot index" + 1 (NULL is a mark of uninitialized cache slot) */
1946
0
    CACHE_PTR_EX(cache_slot, (void*)(idx + 1));
1947
0
  } else {
1948
0
    idx = (char*)value - (char*)EG(symbol_table).arData;
1949
    /* Store "hash slot index" + 1 (NULL is a mark of uninitialized cache slot) */
1950
0
    CACHE_PTR_EX(cache_slot, (void*)(idx + 1));
1951
0
check_indirect:
1952
    /* GLOBAL variable may be an INDIRECT pointer to CV */
1953
0
    if (UNEXPECTED(Z_TYPE_P(value) == IS_INDIRECT)) {
1954
0
      value = Z_INDIRECT_P(value);
1955
0
      if (UNEXPECTED(Z_TYPE_P(value) == IS_UNDEF)) {
1956
0
        ZVAL_NULL(value);
1957
0
      }
1958
0
    }
1959
0
  }
1960
1961
0
  if (UNEXPECTED(!Z_ISREF_P(value))) {
1962
0
    ZVAL_MAKE_REF_EX(value, 2);
1963
0
    ref = Z_REF_P(value);
1964
0
  } else {
1965
0
    ref = Z_REF_P(value);
1966
0
    GC_ADDREF(ref);
1967
0
  }
1968
1969
0
  return ref;
1970
0
}
1971
1972
static bool ZEND_FASTCALL zend_jit_verify_arg_slow(zval *arg, zend_arg_info *arg_info)
1973
0
{
1974
0
  zend_execute_data *execute_data = EG(current_execute_data);
1975
0
  const zend_op *opline = EX(opline);
1976
0
  bool ret = zend_check_user_type_slow(
1977
0
    &arg_info->type, arg, /* ref */ NULL, /* is_return_type */ false);
1978
0
  if (UNEXPECTED(!ret)) {
1979
0
    zend_verify_arg_error(EX(func), arg_info, opline->op1.num, arg);
1980
0
    return false;
1981
0
  }
1982
0
  return ret;
1983
0
}
1984
1985
static void ZEND_FASTCALL zend_jit_verify_return_slow(zval *arg, const zend_op_array *op_array, zend_arg_info *arg_info)
1986
0
{
1987
0
    if (Z_TYPE_P(arg) == IS_NULL) {
1988
0
    ZEND_ASSERT(ZEND_TYPE_IS_SET(arg_info->type));
1989
0
    if (EXPECTED(ZEND_TYPE_CONTAINS_CODE(arg_info->type, IS_NULL))) {
1990
0
      return;
1991
0
    }
1992
0
  }
1993
0
  if (UNEXPECTED(!zend_check_user_type_slow(
1994
0
      &arg_info->type, arg, /* ref */ NULL, /* is_return_type */ true))) {
1995
0
    zend_verify_return_error((zend_function*)op_array, arg);
1996
0
  }
1997
0
}
1998
1999
static void ZEND_FASTCALL zend_jit_fetch_obj_r_slow(zend_object *zobj)
2000
0
{
2001
0
  zval *retval;
2002
0
  zend_execute_data *execute_data = EG(current_execute_data);
2003
0
  const zend_op *opline = EX(opline);
2004
0
  zend_string *name = Z_STR_P(RT_CONSTANT(opline, opline->op2));
2005
0
  zval *result = EX_VAR(opline->result.var);
2006
0
  void **cache_slot = CACHE_ADDR(opline->extended_value & ~ZEND_FETCH_OBJ_FLAGS);
2007
2008
0
  retval = zobj->handlers->read_property(zobj, name, BP_VAR_R, cache_slot, result);
2009
0
  if (retval != result) {
2010
0
    ZVAL_COPY_DEREF(result, retval);
2011
0
  } else if (UNEXPECTED(Z_ISREF_P(retval))) {
2012
0
    zend_unwrap_reference(retval);
2013
0
  }
2014
0
}
2015
2016
static void ZEND_FASTCALL zend_jit_fetch_obj_r_dynamic(zend_object *zobj, intptr_t prop_offset)
2017
0
{
2018
0
  if (zobj->properties && !IS_HOOKED_PROPERTY_OFFSET(prop_offset)) {
2019
0
    zval *retval;
2020
0
    zend_execute_data *execute_data = EG(current_execute_data);
2021
0
    const zend_op *opline = EX(opline);
2022
0
    zend_string *name = Z_STR_P(RT_CONSTANT(opline, opline->op2));
2023
0
    zval *result = EX_VAR(opline->result.var);
2024
0
    void **cache_slot = CACHE_ADDR(opline->extended_value & ~ZEND_FETCH_OBJ_FLAGS);
2025
2026
0
    if (!IS_UNKNOWN_DYNAMIC_PROPERTY_OFFSET(prop_offset)) {
2027
0
      intptr_t idx = ZEND_DECODE_DYN_PROP_OFFSET(prop_offset);
2028
2029
0
      if (EXPECTED(idx < zobj->properties->nNumUsed * sizeof(Bucket))) {
2030
0
        Bucket *p = (Bucket*)((char*)zobj->properties->arData + idx);
2031
2032
0
        if (EXPECTED(p->key == name) ||
2033
0
              (EXPECTED(p->h == ZSTR_H(name)) &&
2034
0
               EXPECTED(p->key != NULL) &&
2035
0
               EXPECTED(zend_string_equal_content(p->key, name)))) {
2036
0
          ZVAL_COPY_DEREF(result, &p->val);
2037
0
          return;
2038
0
        }
2039
0
      }
2040
0
      CACHE_PTR_EX(cache_slot + 1, (void*)ZEND_DYNAMIC_PROPERTY_OFFSET);
2041
0
    }
2042
2043
0
    retval = zend_hash_find_known_hash(zobj->properties, name);
2044
2045
0
    if (EXPECTED(retval)) {
2046
0
      intptr_t idx = (char*)retval - (char*)zobj->properties->arData;
2047
0
      CACHE_PTR_EX(cache_slot + 1, (void*)ZEND_ENCODE_DYN_PROP_OFFSET(idx));
2048
0
      ZVAL_COPY_DEREF(result, retval);
2049
0
      return;
2050
0
    }
2051
0
  }
2052
0
  zend_jit_fetch_obj_r_slow(zobj);
2053
0
}
2054
2055
static void ZEND_FASTCALL zend_jit_fetch_obj_is_slow(zend_object *zobj)
2056
0
{
2057
0
  zval *retval;
2058
0
  zend_execute_data *execute_data = EG(current_execute_data);
2059
0
  const zend_op *opline = EX(opline);
2060
0
  zend_string *name = Z_STR_P(RT_CONSTANT(opline, opline->op2));
2061
0
  zval *result = EX_VAR(opline->result.var);
2062
0
  void **cache_slot = CACHE_ADDR(opline->extended_value & ~ZEND_FETCH_OBJ_FLAGS);
2063
2064
0
  retval = zobj->handlers->read_property(zobj, name, BP_VAR_IS, cache_slot, result);
2065
0
  if (retval != result) {
2066
0
    ZVAL_COPY_DEREF(result, retval);
2067
0
  } else if (UNEXPECTED(Z_ISREF_P(retval))) {
2068
0
    zend_unwrap_reference(retval);
2069
0
  }
2070
0
}
2071
2072
static void ZEND_FASTCALL zend_jit_fetch_obj_is_dynamic(zend_object *zobj, intptr_t prop_offset)
2073
0
{
2074
0
  if (zobj->properties && !IS_HOOKED_PROPERTY_OFFSET(prop_offset)) {
2075
0
    zval *retval;
2076
0
    zend_execute_data *execute_data = EG(current_execute_data);
2077
0
    const zend_op *opline = EX(opline);
2078
0
    zend_string *name = Z_STR_P(RT_CONSTANT(opline, opline->op2));
2079
0
    zval *result = EX_VAR(opline->result.var);
2080
0
    void **cache_slot = CACHE_ADDR(opline->extended_value & ~ZEND_FETCH_OBJ_FLAGS);
2081
2082
0
    if (!IS_UNKNOWN_DYNAMIC_PROPERTY_OFFSET(prop_offset)) {
2083
0
      intptr_t idx = ZEND_DECODE_DYN_PROP_OFFSET(prop_offset);
2084
2085
0
      if (EXPECTED(idx < zobj->properties->nNumUsed * sizeof(Bucket))) {
2086
0
        Bucket *p = (Bucket*)((char*)zobj->properties->arData + idx);
2087
2088
0
        if (EXPECTED(p->key == name) ||
2089
0
              (EXPECTED(p->h == ZSTR_H(name)) &&
2090
0
               EXPECTED(p->key != NULL) &&
2091
0
               EXPECTED(zend_string_equal_content(p->key, name)))) {
2092
0
          ZVAL_COPY_DEREF(result, &p->val);
2093
0
          return;
2094
0
        }
2095
0
      }
2096
0
      CACHE_PTR_EX(cache_slot + 1, (void*)ZEND_DYNAMIC_PROPERTY_OFFSET);
2097
0
    }
2098
2099
0
    retval = zend_hash_find_known_hash(zobj->properties, name);
2100
2101
0
    if (EXPECTED(retval)) {
2102
0
      intptr_t idx = (char*)retval - (char*)zobj->properties->arData;
2103
0
      CACHE_PTR_EX(cache_slot + 1, (void*)ZEND_ENCODE_DYN_PROP_OFFSET(idx));
2104
0
      ZVAL_COPY_DEREF(result, retval);
2105
0
      return;
2106
0
    }
2107
0
  }
2108
0
  zend_jit_fetch_obj_is_slow(zobj);
2109
0
}
2110
2111
static zval* ZEND_FASTCALL zend_jit_fetch_obj_r_slow_ex(zend_object *zobj)
2112
0
{
2113
0
  zval *retval;
2114
0
  zend_execute_data *execute_data = EG(current_execute_data);
2115
0
  const zend_op *opline = EX(opline);
2116
0
  zend_string *name = Z_STR_P(RT_CONSTANT(opline, opline->op2));
2117
0
  zval *result = EX_VAR(opline->result.var);
2118
0
  void **cache_slot = CACHE_ADDR(opline->extended_value & ~ZEND_FETCH_OBJ_FLAGS);
2119
2120
0
  retval = zobj->handlers->read_property(zobj, name, BP_VAR_R, cache_slot, result);
2121
0
  if (UNEXPECTED(Z_ISREF_P(retval))) {
2122
0
    if (retval == result) {
2123
0
      zend_unwrap_reference(retval);
2124
0
    } else {
2125
0
      retval = Z_REFVAL_P(retval);
2126
0
    }
2127
0
    ZEND_ASSERT(!Z_REFCOUNTED_P(retval));
2128
0
  }
2129
0
  return retval;
2130
0
}
2131
2132
static zval* ZEND_FASTCALL zend_jit_fetch_obj_r_dynamic_ex(zend_object *zobj, intptr_t prop_offset)
2133
0
{
2134
0
  if (zobj->properties && !IS_HOOKED_PROPERTY_OFFSET(prop_offset)) {
2135
0
    zval *retval;
2136
0
    zend_execute_data *execute_data = EG(current_execute_data);
2137
0
    const zend_op *opline = EX(opline);
2138
0
    zend_string *name = Z_STR_P(RT_CONSTANT(opline, opline->op2));
2139
0
    void **cache_slot = CACHE_ADDR(opline->extended_value & ~ZEND_FETCH_OBJ_FLAGS);
2140
2141
0
    if (!IS_UNKNOWN_DYNAMIC_PROPERTY_OFFSET(prop_offset)) {
2142
0
      intptr_t idx = ZEND_DECODE_DYN_PROP_OFFSET(prop_offset);
2143
2144
0
      if (EXPECTED(idx < zobj->properties->nNumUsed * sizeof(Bucket))) {
2145
0
        Bucket *p = (Bucket*)((char*)zobj->properties->arData + idx);
2146
2147
0
        if (EXPECTED(p->key == name) ||
2148
0
              (EXPECTED(p->h == ZSTR_H(name)) &&
2149
0
               EXPECTED(p->key != NULL) &&
2150
0
               EXPECTED(zend_string_equal_content(p->key, name)))) {
2151
0
          return &p->val;
2152
0
        }
2153
0
      }
2154
0
      CACHE_PTR_EX(cache_slot + 1, (void*)ZEND_DYNAMIC_PROPERTY_OFFSET);
2155
0
    }
2156
2157
0
    retval = zend_hash_find_known_hash(zobj->properties, name);
2158
2159
0
    if (EXPECTED(retval)) {
2160
0
      intptr_t idx = (char*)retval - (char*)zobj->properties->arData;
2161
0
      CACHE_PTR_EX(cache_slot + 1, (void*)ZEND_ENCODE_DYN_PROP_OFFSET(idx));
2162
0
      return retval;
2163
0
    }
2164
0
  }
2165
0
  return zend_jit_fetch_obj_r_slow_ex(zobj);
2166
0
}
2167
2168
static zval* ZEND_FASTCALL zend_jit_fetch_obj_is_slow_ex(zend_object *zobj)
2169
0
{
2170
0
  zval *retval;
2171
0
  zend_execute_data *execute_data = EG(current_execute_data);
2172
0
  const zend_op *opline = EX(opline);
2173
0
  zend_string *name = Z_STR_P(RT_CONSTANT(opline, opline->op2));
2174
0
  zval *result = EX_VAR(opline->result.var);
2175
0
  void **cache_slot = CACHE_ADDR(opline->extended_value & ~ZEND_FETCH_OBJ_FLAGS);
2176
2177
0
  retval = zobj->handlers->read_property(zobj, name, BP_VAR_IS, cache_slot, result);
2178
0
  if (retval == result && UNEXPECTED(Z_ISREF_P(retval))) {
2179
0
    zend_unwrap_reference(retval);
2180
0
  }
2181
0
  return retval;
2182
0
}
2183
2184
static zval* ZEND_FASTCALL zend_jit_fetch_obj_is_dynamic_ex(zend_object *zobj, intptr_t prop_offset)
2185
0
{
2186
0
  if (zobj->properties && !IS_HOOKED_PROPERTY_OFFSET(prop_offset)) {
2187
0
    zval *retval;
2188
0
    zend_execute_data *execute_data = EG(current_execute_data);
2189
0
    const zend_op *opline = EX(opline);
2190
0
    zend_string *name = Z_STR_P(RT_CONSTANT(opline, opline->op2));
2191
0
    void **cache_slot = CACHE_ADDR(opline->extended_value & ~ZEND_FETCH_OBJ_FLAGS);
2192
2193
0
    if (!IS_UNKNOWN_DYNAMIC_PROPERTY_OFFSET(prop_offset)) {
2194
0
      intptr_t idx = ZEND_DECODE_DYN_PROP_OFFSET(prop_offset);
2195
2196
0
      if (EXPECTED(idx < zobj->properties->nNumUsed * sizeof(Bucket))) {
2197
0
        Bucket *p = (Bucket*)((char*)zobj->properties->arData + idx);
2198
2199
0
        if (EXPECTED(p->key == name) ||
2200
0
              (EXPECTED(p->h == ZSTR_H(name)) &&
2201
0
               EXPECTED(p->key != NULL) &&
2202
0
               EXPECTED(zend_string_equal_content(p->key, name)))) {
2203
0
          return &p->val;
2204
0
        }
2205
0
      }
2206
0
      CACHE_PTR_EX(cache_slot + 1, (void*)ZEND_DYNAMIC_PROPERTY_OFFSET);
2207
0
    }
2208
2209
0
    retval = zend_hash_find_known_hash(zobj->properties, name);
2210
2211
0
    if (EXPECTED(retval)) {
2212
0
      intptr_t idx = (char*)retval - (char*)zobj->properties->arData;
2213
0
      CACHE_PTR_EX(cache_slot + 1, (void*)ZEND_ENCODE_DYN_PROP_OFFSET(idx));
2214
0
      return retval;
2215
0
    }
2216
0
  }
2217
0
  return zend_jit_fetch_obj_is_slow_ex(zobj);
2218
0
}
2219
2220
0
static zend_always_inline bool promotes_to_array(zval *val) {
2221
0
  return Z_TYPE_P(val) <= IS_FALSE
2222
0
    || (Z_ISREF_P(val) && Z_TYPE_P(Z_REFVAL_P(val)) <= IS_FALSE);
2223
0
}
2224
2225
0
static zend_always_inline bool check_type_array_assignable(zend_type type) {
2226
0
  if (!ZEND_TYPE_IS_SET(type)) {
2227
0
    return 1;
2228
0
  }
2229
0
  return (ZEND_TYPE_FULL_MASK(type) & MAY_BE_ARRAY) != 0;
2230
0
}
2231
2232
0
static zend_never_inline ZEND_COLD void zend_throw_auto_init_in_prop_error(zend_property_info *prop, const char *type) {
2233
0
  zend_string *type_str = zend_type_to_string(prop->type);
2234
0
  zend_type_error(
2235
0
    "Cannot auto-initialize an %s inside property %s::$%s of type %s",
2236
0
    type,
2237
0
    ZSTR_VAL(prop->ce->name), zend_get_unmangled_property_name(prop->name),
2238
0
    ZSTR_VAL(type_str)
2239
0
  );
2240
0
  zend_string_release(type_str);
2241
0
}
2242
2243
static zend_never_inline ZEND_COLD void zend_throw_access_uninit_prop_by_ref_error(
2244
0
    zend_property_info *prop) {
2245
0
  zend_throw_error(NULL,
2246
0
    "Cannot access uninitialized non-nullable property %s::$%s by reference",
2247
0
    ZSTR_VAL(prop->ce->name),
2248
0
    zend_get_unmangled_property_name(prop->name));
2249
0
}
2250
2251
static zend_never_inline bool zend_handle_fetch_obj_flags(
2252
    zval *result, zval *ptr, zend_object *obj, zend_property_info *prop_info, uint32_t flags)
2253
0
{
2254
0
  switch (flags) {
2255
0
    case ZEND_FETCH_DIM_WRITE:
2256
0
      if (promotes_to_array(ptr)) {
2257
0
        if (!prop_info) {
2258
0
          break;
2259
0
        }
2260
0
        if (!check_type_array_assignable(prop_info->type)) {
2261
0
          zend_throw_auto_init_in_prop_error(prop_info, "array");
2262
0
          if (result) ZVAL_ERROR(result);
2263
0
          return 0;
2264
0
        }
2265
0
      }
2266
0
      break;
2267
0
    case ZEND_FETCH_REF:
2268
0
      if (Z_TYPE_P(ptr) != IS_REFERENCE) {
2269
0
        if (!prop_info) {
2270
0
          break;
2271
0
        }
2272
0
        if (Z_TYPE_P(ptr) == IS_UNDEF) {
2273
0
          if (!ZEND_TYPE_ALLOW_NULL(prop_info->type)) {
2274
0
            zend_throw_access_uninit_prop_by_ref_error(prop_info);
2275
0
            if (result) ZVAL_ERROR(result);
2276
0
            return 0;
2277
0
          }
2278
0
          ZVAL_NULL(ptr);
2279
0
        }
2280
0
        if (ZEND_TYPE_IS_SET(prop_info->type)) {
2281
0
          ZVAL_NEW_REF(ptr, ptr);
2282
0
          ZEND_REF_ADD_TYPE_SOURCE(Z_REF_P(ptr), prop_info);
2283
0
        }
2284
0
      }
2285
0
      break;
2286
0
    default: ZEND_UNREACHABLE();
2287
0
  }
2288
0
  return 1;
2289
0
}
2290
2291
static void ZEND_FASTCALL zend_jit_fetch_obj_w_slow(zend_object *zobj)
2292
0
{
2293
0
  zval *retval;
2294
0
  zend_execute_data *execute_data = EG(current_execute_data);
2295
0
  const zend_op *opline = EX(opline);
2296
0
  zend_string *name = Z_STR_P(RT_CONSTANT(opline, opline->op2));
2297
0
  zval *result = EX_VAR(opline->result.var);
2298
0
  void **cache_slot = CACHE_ADDR(opline->extended_value & ~ZEND_FETCH_OBJ_FLAGS);
2299
0
  ZEND_ASSERT(cache_slot);
2300
2301
0
  retval = zobj->handlers->get_property_ptr_ptr(zobj, name, BP_VAR_W, cache_slot);
2302
0
  if (NULL == retval) {
2303
0
    retval = zobj->handlers->read_property(zobj, name, BP_VAR_W, cache_slot, result);
2304
0
    if (retval == result) {
2305
0
      if (UNEXPECTED(Z_ISREF_P(retval) && Z_REFCOUNT_P(retval) == 1)) {
2306
0
        ZVAL_UNREF(retval);
2307
0
      }
2308
0
      return;
2309
0
    }
2310
0
    if (UNEXPECTED(EG(exception))) {
2311
0
      ZVAL_ERROR(result);
2312
0
      return;
2313
0
    }
2314
0
  } else if (UNEXPECTED(Z_ISERROR_P(retval))) {
2315
0
    ZVAL_ERROR(result);
2316
0
    return;
2317
0
  }
2318
2319
0
  ZVAL_INDIRECT(result, retval);
2320
2321
  /* Support for typed properties */
2322
0
  do {
2323
0
    uint32_t flags = opline->extended_value & ZEND_FETCH_OBJ_FLAGS;
2324
2325
0
    if (flags) {
2326
0
      zend_property_info *prop_info = CACHED_PTR_EX(cache_slot + 2);
2327
2328
0
      if (!prop_info) {
2329
0
        break;
2330
0
      }
2331
0
      if (UNEXPECTED(!zend_handle_fetch_obj_flags(result, retval, zobj, prop_info, flags))) {
2332
0
        return;
2333
0
      }
2334
0
    }
2335
0
  } while (0);
2336
2337
0
  if (UNEXPECTED(Z_TYPE_P(retval) == IS_UNDEF)) {
2338
0
    ZVAL_NULL(retval);
2339
0
  }
2340
0
}
2341
2342
static void ZEND_FASTCALL zend_jit_check_array_promotion(zval *val, zend_property_info *prop)
2343
0
{
2344
0
  zend_execute_data *execute_data = EG(current_execute_data);
2345
0
  const zend_op *opline = execute_data->opline;
2346
0
  zval *result = EX_VAR(opline->result.var);
2347
2348
0
  if ((Z_TYPE_P(val) <= IS_FALSE
2349
0
    || (Z_ISREF_P(val) && Z_TYPE_P(Z_REFVAL_P(val)) <= IS_FALSE))
2350
0
    && ZEND_TYPE_IS_SET(prop->type)
2351
0
    && (ZEND_TYPE_FULL_MASK(prop->type) & MAY_BE_ARRAY) == 0) {
2352
0
    zend_string *type_str = zend_type_to_string(prop->type);
2353
0
    zend_type_error(
2354
0
      "Cannot auto-initialize an array inside property %s::$%s of type %s",
2355
0
      ZSTR_VAL(prop->ce->name), zend_get_unmangled_property_name(prop->name),
2356
0
      ZSTR_VAL(type_str)
2357
0
    );
2358
0
    zend_string_release(type_str);
2359
0
    ZVAL_ERROR(result);
2360
0
  } else {
2361
0
    ZVAL_INDIRECT(result, val);
2362
0
  }
2363
0
}
2364
2365
static void ZEND_FASTCALL zend_jit_create_typed_ref(zval *val, zend_property_info *prop, zval *result)
2366
0
{
2367
0
  if (!Z_ISREF_P(val)) {
2368
0
    ZVAL_NEW_REF(val, val);
2369
0
    ZEND_REF_ADD_TYPE_SOURCE(Z_REF_P(val), prop);
2370
0
  }
2371
0
  ZVAL_INDIRECT(result, val);
2372
0
}
2373
2374
static void ZEND_FASTCALL zend_jit_extract_helper(zend_refcounted *garbage)
2375
0
{
2376
0
  zend_execute_data *execute_data = EG(current_execute_data);
2377
0
  const zend_op *opline = execute_data->opline;
2378
0
  zval *zv = EX_VAR(opline->result.var);
2379
2380
0
  if (EXPECTED(Z_TYPE_P(zv) == IS_INDIRECT)) {
2381
0
    ZVAL_COPY(zv, Z_INDIRECT_P(zv));
2382
0
  }
2383
0
  rc_dtor_func(garbage);
2384
0
}
2385
2386
static void ZEND_FASTCALL zend_jit_vm_stack_free_args_helper(zend_execute_data *call)
2387
0
{
2388
0
  zend_vm_stack_free_args(call);
2389
0
}
2390
2391
static zend_always_inline zval* zend_jit_assign_to_typed_ref_helper(zend_reference *ref, zval *value, uint8_t value_type)
2392
0
{
2393
0
  zval variable;
2394
2395
0
  ZVAL_REF(&variable, ref);
2396
0
  return zend_assign_to_variable(&variable, value, value_type, ZEND_CALL_USES_STRICT_TYPES(EG(current_execute_data)));
2397
0
}
2398
2399
static zval* ZEND_FASTCALL zend_jit_assign_const_to_typed_ref(zend_reference *ref, zval *value)
2400
0
{
2401
0
  return zend_jit_assign_to_typed_ref_helper(ref, value, IS_CONST);
2402
0
}
2403
2404
static zval* ZEND_FASTCALL zend_jit_assign_tmp_to_typed_ref(zend_reference *ref, zval *value)
2405
0
{
2406
0
  return zend_jit_assign_to_typed_ref_helper(ref, value, IS_TMP_VAR);
2407
0
}
2408
2409
static zval* ZEND_FASTCALL zend_jit_assign_var_to_typed_ref(zend_reference *ref, zval *value)
2410
0
{
2411
0
  return zend_jit_assign_to_typed_ref_helper(ref, value, IS_VAR);
2412
0
}
2413
2414
static zval* ZEND_FASTCALL zend_jit_assign_cv_to_typed_ref(zend_reference *ref, zval *value)
2415
0
{
2416
0
  if (UNEXPECTED(Z_TYPE_P(value) == IS_UNDEF)) {
2417
0
    const zend_op *opline = EG(current_execute_data)->opline;
2418
0
    uint32_t var;
2419
0
    if (opline->opcode == ZEND_ASSIGN) {
2420
0
      var = opline->op2.var;
2421
0
    } else {
2422
0
      ZEND_ASSERT((opline + 1)->opcode == ZEND_OP_DATA);
2423
0
      var = (opline + 1)->op1.var;
2424
0
    }
2425
0
    zend_jit_undefined_op_helper(var);
2426
0
    value = &EG(uninitialized_zval);
2427
0
  }
2428
0
  return zend_jit_assign_to_typed_ref_helper(ref, value, IS_CV);
2429
0
}
2430
2431
static zend_always_inline zval* zend_jit_assign_to_typed_ref2_helper(zend_reference *ref, zval *value, zval *result, uint8_t value_type)
2432
0
{
2433
0
  zval variable, *ret;
2434
0
  zend_refcounted *garbage = NULL;
2435
2436
0
  ZVAL_REF(&variable, ref);
2437
0
  ret = zend_assign_to_variable_ex(&variable, value, value_type, ZEND_CALL_USES_STRICT_TYPES(EG(current_execute_data)), &garbage);
2438
0
  ZVAL_COPY(result, ret);
2439
0
  if (garbage) {
2440
0
    GC_DTOR(garbage);
2441
0
  }
2442
0
  return ret;
2443
0
}
2444
2445
static zval* ZEND_FASTCALL zend_jit_assign_const_to_typed_ref2(zend_reference *ref, zval *value, zval *result)
2446
0
{
2447
0
  return zend_jit_assign_to_typed_ref2_helper(ref, value, result, IS_CONST);
2448
0
}
2449
2450
static zval* ZEND_FASTCALL zend_jit_assign_tmp_to_typed_ref2(zend_reference *ref, zval *value, zval *result)
2451
0
{
2452
0
  return zend_jit_assign_to_typed_ref2_helper(ref, value, result, IS_TMP_VAR);
2453
0
}
2454
2455
static zval* ZEND_FASTCALL zend_jit_assign_var_to_typed_ref2(zend_reference *ref, zval *value, zval *result)
2456
0
{
2457
0
  return zend_jit_assign_to_typed_ref2_helper(ref, value, result, IS_VAR);
2458
0
}
2459
2460
static zval* ZEND_FASTCALL zend_jit_assign_cv_to_typed_ref2(zend_reference *ref, zval *value, zval *result)
2461
0
{
2462
0
  if (UNEXPECTED(Z_TYPE_P(value) == IS_UNDEF)) {
2463
0
    const zend_op *opline = EG(current_execute_data)->opline;
2464
0
    uint32_t var;
2465
0
    if (opline->opcode == ZEND_ASSIGN) {
2466
0
      var = opline->op2.var;
2467
0
    } else {
2468
0
      ZEND_ASSERT((opline + 1)->opcode == ZEND_OP_DATA);
2469
0
      var = (opline + 1)->op1.var;
2470
0
    }
2471
0
    zend_jit_undefined_op_helper(var);
2472
0
    value = &EG(uninitialized_zval);
2473
0
  }
2474
0
  return zend_jit_assign_to_typed_ref2_helper(ref, value, result, IS_CV);
2475
0
}
2476
2477
static zend_property_info *zend_jit_get_prop_not_accepting_double(zend_reference *ref)
2478
0
{
2479
0
  zend_property_info *prop;
2480
0
  ZEND_REF_FOREACH_TYPE_SOURCES(ref, prop) {
2481
0
    if (!(ZEND_TYPE_FULL_MASK(prop->type) & MAY_BE_DOUBLE)) {
2482
0
      return prop;
2483
0
    }
2484
0
  } ZEND_REF_FOREACH_TYPE_SOURCES_END();
2485
0
  return NULL;
2486
0
}
2487
2488
static ZEND_COLD void zend_jit_throw_inc_ref_error(zend_reference *ref, zend_property_info *error_prop)
2489
0
{
2490
0
  zend_string *type_str = zend_type_to_string(error_prop->type);
2491
2492
0
  zend_type_error(
2493
0
    "Cannot increment a reference held by property %s::$%s of type %s past its maximal value",
2494
0
    ZSTR_VAL(error_prop->ce->name),
2495
0
    zend_get_unmangled_property_name(error_prop->name),
2496
0
    ZSTR_VAL(type_str));
2497
0
  zend_string_release(type_str);
2498
0
}
2499
2500
static ZEND_COLD void zend_jit_throw_dec_ref_error(zend_reference *ref, zend_property_info *error_prop)
2501
0
{
2502
0
  zend_string *type_str = zend_type_to_string(error_prop->type);
2503
2504
0
  zend_type_error(
2505
0
    "Cannot decrement a reference held by property %s::$%s of type %s past its minimal value",
2506
0
    ZSTR_VAL(error_prop->ce->name),
2507
0
    zend_get_unmangled_property_name(error_prop->name),
2508
0
    ZSTR_VAL(type_str));
2509
0
  zend_string_release(type_str);
2510
0
}
2511
2512
static void ZEND_FASTCALL zend_jit_pre_inc_typed_ref(zend_reference *ref, zval *ret)
2513
0
{
2514
0
  zval *var_ptr = &ref->val;
2515
0
  zval tmp;
2516
2517
0
  ZVAL_COPY(&tmp, var_ptr);
2518
2519
0
  increment_function(var_ptr);
2520
2521
0
  if (UNEXPECTED(Z_TYPE_P(var_ptr) == IS_DOUBLE) && Z_TYPE(tmp) == IS_LONG) {
2522
0
    zend_property_info *error_prop = zend_jit_get_prop_not_accepting_double(ref);
2523
0
    if (UNEXPECTED(error_prop)) {
2524
0
      zend_jit_throw_inc_ref_error(ref, error_prop);
2525
0
      ZVAL_LONG(var_ptr, ZEND_LONG_MAX);
2526
0
    }
2527
0
  } else if (UNEXPECTED(!zend_verify_ref_assignable_zval(ref, var_ptr, ZEND_CALL_USES_STRICT_TYPES(EG(current_execute_data))))) {
2528
0
    zval_ptr_dtor(var_ptr);
2529
0
    ZVAL_COPY_VALUE(var_ptr, &tmp);
2530
0
  } else {
2531
0
    zval_ptr_dtor(&tmp);
2532
0
  }
2533
0
  if (ret) {
2534
0
    ZVAL_COPY(ret, var_ptr);
2535
0
  }
2536
0
}
2537
2538
static void ZEND_FASTCALL zend_jit_pre_dec_typed_ref(zend_reference *ref, zval *ret)
2539
0
{
2540
0
  zval *var_ptr = &ref->val;
2541
0
  zval tmp;
2542
2543
0
  ZVAL_COPY(&tmp, var_ptr);
2544
2545
0
  decrement_function(var_ptr);
2546
2547
0
  if (UNEXPECTED(Z_TYPE_P(var_ptr) == IS_DOUBLE) && Z_TYPE(tmp) == IS_LONG) {
2548
0
    zend_property_info *error_prop = zend_jit_get_prop_not_accepting_double(ref);
2549
0
    if (UNEXPECTED(error_prop)) {
2550
0
      zend_jit_throw_dec_ref_error(ref, error_prop);
2551
0
      ZVAL_LONG(var_ptr, ZEND_LONG_MIN);
2552
0
    }
2553
0
  } else if (UNEXPECTED(!zend_verify_ref_assignable_zval(ref, var_ptr, ZEND_CALL_USES_STRICT_TYPES(EG(current_execute_data))))) {
2554
0
    zval_ptr_dtor(var_ptr);
2555
0
    ZVAL_COPY_VALUE(var_ptr, &tmp);
2556
0
  } else {
2557
0
    zval_ptr_dtor(&tmp);
2558
0
  }
2559
0
  if (ret) {
2560
0
    ZVAL_COPY(ret, var_ptr);
2561
0
  }
2562
0
}
2563
2564
static void ZEND_FASTCALL zend_jit_post_inc_typed_ref(zend_reference *ref, zval *ret)
2565
0
{
2566
0
  zval *var_ptr = &ref->val;
2567
0
  ZVAL_COPY(ret, var_ptr);
2568
2569
0
  increment_function(var_ptr);
2570
2571
0
  if (UNEXPECTED(Z_TYPE_P(var_ptr) == IS_DOUBLE) && Z_TYPE_P(ret) == IS_LONG) {
2572
0
    zend_property_info *error_prop = zend_jit_get_prop_not_accepting_double(ref);
2573
0
    if (UNEXPECTED(error_prop)) {
2574
0
      zend_jit_throw_inc_ref_error(ref, error_prop);
2575
0
      ZVAL_LONG(var_ptr, ZEND_LONG_MAX);
2576
0
    }
2577
0
  } else if (UNEXPECTED(!zend_verify_ref_assignable_zval(ref, var_ptr, ZEND_CALL_USES_STRICT_TYPES(EG(current_execute_data))))) {
2578
0
    zval_ptr_dtor(var_ptr);
2579
0
    ZVAL_COPY_VALUE(var_ptr, ret);
2580
0
  }
2581
0
}
2582
2583
static void ZEND_FASTCALL zend_jit_post_dec_typed_ref(zend_reference *ref, zval *ret)
2584
0
{
2585
0
  zval *var_ptr = &ref->val;
2586
0
  ZVAL_COPY(ret, var_ptr);
2587
2588
0
  decrement_function(var_ptr);
2589
2590
0
  if (UNEXPECTED(Z_TYPE_P(var_ptr) == IS_DOUBLE) && Z_TYPE_P(ret) == IS_LONG) {
2591
0
    zend_property_info *error_prop = zend_jit_get_prop_not_accepting_double(ref);
2592
0
    if (UNEXPECTED(error_prop)) {
2593
0
      zend_jit_throw_dec_ref_error(ref, error_prop);
2594
0
      ZVAL_LONG(var_ptr, ZEND_LONG_MIN);
2595
0
    }
2596
0
  } else if (UNEXPECTED(!zend_verify_ref_assignable_zval(ref, var_ptr, ZEND_CALL_USES_STRICT_TYPES(EG(current_execute_data))))) {
2597
0
    zval_ptr_dtor(var_ptr);
2598
0
    ZVAL_COPY_VALUE(var_ptr, ret);
2599
0
  }
2600
0
}
2601
2602
static void ZEND_FASTCALL zend_jit_assign_op_to_typed_ref(zend_reference *ref, zval *val, binary_op_type binary_op)
2603
0
{
2604
0
  zval z_copy;
2605
2606
  /* Make sure that in-place concatenation is used if the LHS is a string. */
2607
0
  if (binary_op == concat_function && Z_TYPE(ref->val) == IS_STRING) {
2608
0
    concat_function(&ref->val, &ref->val, val);
2609
0
    ZEND_ASSERT(Z_TYPE(ref->val) == IS_STRING && "Concat should return string");
2610
0
    return;
2611
0
  }
2612
2613
0
  binary_op(&z_copy, &ref->val, val);
2614
0
  if (EXPECTED(zend_verify_ref_assignable_zval(ref, &z_copy, ZEND_CALL_USES_STRICT_TYPES(EG(current_execute_data))))) {
2615
0
    zval_ptr_dtor(&ref->val);
2616
0
    ZVAL_COPY_VALUE(&ref->val, &z_copy);
2617
0
  } else {
2618
0
    zval_ptr_dtor(&z_copy);
2619
0
  }
2620
0
}
2621
2622
static void ZEND_FASTCALL zend_jit_assign_op_to_typed_ref_tmp(zend_reference *ref, zval *val, binary_op_type binary_op)
2623
0
{
2624
0
  zval z_copy;
2625
2626
0
  binary_op(&z_copy, &ref->val, val);
2627
0
  if (EXPECTED(zend_verify_ref_assignable_zval(ref, &z_copy, ZEND_CALL_USES_STRICT_TYPES(EG(current_execute_data))))) {
2628
0
    zval_ptr_dtor(&ref->val);
2629
0
    ZVAL_COPY_VALUE(&ref->val, &z_copy);
2630
0
  } else {
2631
0
    zval_ptr_dtor(&z_copy);
2632
0
  }
2633
0
  zval_ptr_dtor_nogc(val);
2634
0
}
2635
2636
static void ZEND_FASTCALL zend_jit_only_vars_by_reference(zval *arg)
2637
0
{
2638
0
  ZVAL_NEW_REF(arg, arg);
2639
0
  zend_error(E_NOTICE, "Only variables should be passed by reference");
2640
0
}
2641
2642
static void ZEND_FASTCALL zend_jit_invalid_array_use(const zval *container)
2643
0
{
2644
  /* Warning should not occur on null */
2645
0
  if (Z_TYPE_P(container) != IS_NULL) {
2646
0
    zend_error(E_WARNING, "Cannot use %s as array", zend_zval_type_name(container));
2647
0
  }
2648
0
}
2649
2650
static void ZEND_FASTCALL zend_jit_invalid_array_access(zval *container)
2651
0
{
2652
0
  zend_error(E_WARNING, "Trying to access array offset on %s", zend_zval_value_name(container));
2653
0
}
2654
2655
static void ZEND_FASTCALL zend_jit_nan_coerced_to_type_warning(void)
2656
0
{
2657
0
  zend_nan_coerced_to_type_warning(_IS_BOOL);
2658
0
}
2659
2660
static void ZEND_FASTCALL zend_jit_invalid_property_read(zval *container, const char *property_name)
2661
0
{
2662
0
  zend_error(E_WARNING, "Attempt to read property \"%s\" on %s", property_name, zend_zval_value_name(container));
2663
0
}
2664
2665
static void ZEND_FASTCALL zend_jit_invalid_property_write(zval *container, const char *property_name)
2666
0
{
2667
0
  zend_throw_error(NULL,
2668
0
    "Attempt to modify property \"%s\" on %s",
2669
0
    property_name, zend_zval_value_name(container));
2670
0
}
2671
2672
static void ZEND_FASTCALL zend_jit_invalid_property_incdec(zval *container, const char *property_name)
2673
0
{
2674
0
  zend_execute_data *execute_data = EG(current_execute_data);
2675
0
  const zend_op *opline = EX(opline);
2676
2677
0
  if (Z_TYPE_P(container) == IS_UNDEF && opline->op1_type == IS_CV) {
2678
0
    zend_string *cv = EX(func)->op_array.vars[EX_VAR_TO_NUM(opline->op1.var)];
2679
2680
0
    zend_error_unchecked(E_WARNING, "Undefined variable $%S", cv);
2681
0
  }
2682
0
  if (opline->result_type & (IS_VAR|IS_TMP_VAR)) {
2683
0
    ZVAL_UNDEF(EX_VAR(opline->result.var));
2684
0
  }
2685
0
  zend_throw_error(NULL,
2686
0
    "Attempt to increment/decrement property \"%s\" on %s",
2687
0
    property_name, zend_zval_value_name(container));
2688
0
  if (opline->op1_type == IS_VAR) {
2689
0
    zval_ptr_dtor_nogc(EX_VAR(opline->op1.var));
2690
0
  }
2691
0
}
2692
2693
static void ZEND_FASTCALL zend_jit_invalid_property_assign(zval *container, const char *property_name)
2694
0
{
2695
0
  zend_throw_error(NULL,
2696
0
    "Attempt to assign property \"%s\" on %s",
2697
0
    property_name, zend_zval_value_name(container));
2698
0
}
2699
2700
static void ZEND_FASTCALL zend_jit_invalid_property_assign_op(zval *container, const char *property_name)
2701
0
{
2702
0
  if (Z_TYPE_P(container) == IS_UNDEF) {
2703
0
    const zend_execute_data *execute_data = EG(current_execute_data);
2704
2705
0
    zend_jit_undefined_op_helper(EX(opline)->op1.var);
2706
0
  }
2707
0
  zend_jit_invalid_property_assign(container, property_name);
2708
0
}
2709
2710
0
static zval * ZEND_FASTCALL zend_jit_prepare_assign_dim_ref(zval *ref) {
2711
0
  zval *val = Z_REFVAL_P(ref);
2712
0
  if (Z_TYPE_P(val) <= IS_FALSE) {
2713
0
    if (ZEND_REF_HAS_TYPE_SOURCES(Z_REF_P(ref))
2714
0
        && !zend_verify_ref_array_assignable(Z_REF_P(ref))) {
2715
0
      return NULL;
2716
0
    }
2717
0
    if (Z_TYPE_P(val) == IS_FALSE) {
2718
0
      ZVAL_ARR(val, zend_new_array(8));
2719
0
      zend_false_to_array_deprecated();
2720
0
      if (EG(exception)) {
2721
0
        return NULL;
2722
0
      }
2723
0
    } else {
2724
0
      ZVAL_ARR(val, zend_new_array(8));
2725
0
    }
2726
0
  }
2727
0
  return val;
2728
0
}
2729
2730
static void ZEND_FASTCALL zend_jit_pre_inc(zval *var_ptr, zval *ret)
2731
0
{
2732
0
  increment_function(var_ptr);
2733
0
  ZVAL_COPY(ret, var_ptr);
2734
0
}
2735
2736
static void ZEND_FASTCALL zend_jit_pre_dec(zval *var_ptr, zval *ret)
2737
0
{
2738
0
  decrement_function(var_ptr);
2739
0
  ZVAL_COPY(ret, var_ptr);
2740
0
}
2741
2742
0
#define HT_POISONED_PTR ((HashTable *) (intptr_t) -1)
2743
2744
static zend_never_inline void ZEND_FASTCALL _zend_hash_iterators_remove(HashTable *ht)
2745
0
{
2746
0
  HashTableIterator *iter = EG(ht_iterators);
2747
0
  HashTableIterator *end  = iter + EG(ht_iterators_used);
2748
2749
0
  while (iter != end) {
2750
0
    if (iter->ht == ht) {
2751
0
      iter->ht = HT_POISONED_PTR;
2752
0
    }
2753
0
    iter++;
2754
0
  }
2755
0
}
2756
2757
static void ZEND_FASTCALL zend_jit_array_free(HashTable *ht)
2758
0
{
2759
0
  GC_REMOVE_FROM_BUFFER(ht);
2760
0
  if (UNEXPECTED(HT_HAS_ITERATORS(ht))) {
2761
0
    _zend_hash_iterators_remove(ht);
2762
0
  }
2763
0
  if (!(EXPECTED(HT_FLAGS(ht) & HASH_FLAG_UNINITIALIZED))) {
2764
0
    efree(HT_GET_DATA_ADDR(ht));
2765
0
  }
2766
0
  FREE_HASHTABLE(ht);
2767
0
}
2768
2769
static HashTable *ZEND_FASTCALL zend_jit_zval_array_dup(zval *arr)
2770
0
{
2771
0
  HashTable *ht;
2772
2773
0
  Z_TRY_DELREF_P(arr);
2774
0
  ht = Z_ARRVAL_P(arr);
2775
0
  ht = zend_array_dup(ht);
2776
0
  ZVAL_ARR(arr, ht);
2777
0
  return ht;
2778
0
}
2779
2780
static zend_array *ZEND_FASTCALL zend_jit_add_arrays_helper(zend_array *op1, zend_array *op2)
2781
0
{
2782
0
  zend_array *res;
2783
0
  res = zend_array_dup(op1);
2784
0
  zend_hash_merge(res, op2, zval_add_ref, 0);
2785
0
  return res;
2786
0
}
2787
2788
static void ZEND_FASTCALL zend_jit_assign_obj_helper(zend_object *zobj, zend_string *name, zval *value, void **cache_slot, zval *result)
2789
0
{
2790
0
  if (UNEXPECTED(Z_TYPE_P(value) == IS_UNDEF)) {
2791
0
    const zend_op *op_data = EG(current_execute_data)->opline + 1;
2792
0
    ZEND_ASSERT(op_data->opcode == ZEND_OP_DATA && op_data->op1_type == IS_CV);
2793
0
    zend_jit_undefined_op_helper(op_data->op1.var);
2794
0
    value = &EG(uninitialized_zval);
2795
0
  }
2796
2797
0
  ZVAL_DEREF(value);
2798
0
  value = zobj->handlers->write_property(zobj, name, value, cache_slot);
2799
0
  if (result && value) {
2800
0
    ZVAL_COPY_DEREF(result, value);
2801
0
  }
2802
0
}
2803
2804
static zend_always_inline bool verify_readonly_and_avis(zval *property_val, zend_property_info *info, bool indirect)
2805
0
{
2806
0
  if (UNEXPECTED(info->flags & (ZEND_ACC_READONLY|ZEND_ACC_PPP_SET_MASK))) {
2807
0
    if ((info->flags & ZEND_ACC_READONLY) && !(Z_PROP_FLAG_P(property_val) & IS_PROP_REINITABLE)) {
2808
0
      zend_readonly_property_modification_error(info);
2809
0
      return false;
2810
0
    }
2811
0
    if ((info->flags & ZEND_ACC_PPP_SET_MASK) && !zend_asymmetric_property_has_set_access(info)) {
2812
0
      const char *operation = indirect ? "indirectly modify" : "modify";
2813
0
      zend_asymmetric_visibility_property_modification_error(info, operation);
2814
0
      return false;
2815
0
    }
2816
0
  }
2817
0
  return true;
2818
0
}
2819
2820
static void ZEND_FASTCALL zend_jit_assign_to_typed_prop(zval *property_val, zend_property_info *info, zval *value, zval *result)
2821
0
{
2822
0
  zend_execute_data *execute_data = EG(current_execute_data);
2823
0
  zend_refcounted *garbage = NULL;
2824
0
  zval tmp;
2825
2826
0
  if (UNEXPECTED(Z_TYPE_P(value) == IS_UNDEF)) {
2827
0
    const zend_op *op_data = execute_data->opline + 1;
2828
0
    ZEND_ASSERT(op_data->opcode == ZEND_OP_DATA && op_data->op1_type == IS_CV);
2829
0
    zend_jit_undefined_op_helper(op_data->op1.var);
2830
0
    value = &EG(uninitialized_zval);
2831
0
  }
2832
2833
0
  if (UNEXPECTED(!verify_readonly_and_avis(property_val, info, false))) {
2834
0
    if (result) {
2835
0
      ZVAL_UNDEF(result);
2836
0
    }
2837
0
    return;
2838
0
  }
2839
2840
0
  ZVAL_DEREF(value);
2841
0
  ZVAL_COPY(&tmp, value);
2842
2843
0
  if (UNEXPECTED(!zend_verify_property_type(info, &tmp, EX_USES_STRICT_TYPES()))) {
2844
0
    zval_ptr_dtor(&tmp);
2845
0
    if (result) {
2846
0
      ZVAL_NULL(result);
2847
0
    }
2848
0
    return;
2849
0
  }
2850
2851
0
  Z_PROP_FLAG_P(property_val) &= ~IS_PROP_REINITABLE;
2852
2853
0
  value = zend_assign_to_variable_ex(property_val, &tmp, IS_TMP_VAR, EX_USES_STRICT_TYPES(), &garbage);
2854
0
  if (result) {
2855
0
    ZVAL_COPY_DEREF(result, value);
2856
0
  }
2857
0
  if (garbage) {
2858
0
    GC_DTOR(garbage);
2859
0
  }
2860
0
}
2861
2862
static zend_never_inline void _zend_jit_assign_op_overloaded_property(zend_object *object, zend_string *name, void **cache_slot, zval *value, binary_op_type binary_op)
2863
0
{
2864
0
  zval *z;
2865
0
  zval rv, res;
2866
2867
0
  GC_ADDREF(object);
2868
0
  z = object->handlers->read_property(object, name, BP_VAR_R, cache_slot, &rv);
2869
0
  if (UNEXPECTED(EG(exception))) {
2870
0
    OBJ_RELEASE(object);
2871
//???   if (UNEXPECTED(RETURN_VALUE_USED(opline))) {
2872
//???     ZVAL_UNDEF(EX_VAR(opline->result.var));
2873
//???   }
2874
0
    return;
2875
0
  }
2876
0
  if (binary_op(&res, z, value) == SUCCESS) {
2877
0
    object->handlers->write_property(object, name, &res, cache_slot);
2878
0
  }
2879
//??? if (UNEXPECTED(RETURN_VALUE_USED(opline))) {
2880
//???   ZVAL_COPY(EX_VAR(opline->result.var), &res);
2881
//??? }
2882
0
  if (z == &rv) {
2883
0
    zval_ptr_dtor(z);
2884
0
  }
2885
0
  zval_ptr_dtor(&res);
2886
0
  OBJ_RELEASE(object);
2887
0
}
2888
2889
static void ZEND_FASTCALL zend_jit_assign_op_to_typed_prop(zval *zptr, zend_property_info *prop_info, zval *value, binary_op_type binary_op)
2890
0
{
2891
0
  zend_execute_data *execute_data = EG(current_execute_data);
2892
0
  zval z_copy;
2893
2894
0
  if (UNEXPECTED(!verify_readonly_and_avis(zptr, prop_info, true))) {
2895
0
    return;
2896
0
  }
2897
2898
0
  ZVAL_DEREF(zptr);
2899
  /* Make sure that in-place concatenation is used if the LHS is a string. */
2900
0
  if (binary_op == concat_function && Z_TYPE_P(zptr) == IS_STRING) {
2901
0
    concat_function(zptr, zptr, value);
2902
0
    ZEND_ASSERT(Z_TYPE_P(zptr) == IS_STRING && "Concat should return string");
2903
0
    return;
2904
0
  }
2905
2906
0
  binary_op(&z_copy, zptr, value);
2907
0
  if (EXPECTED(zend_verify_property_type(prop_info, &z_copy, EX_USES_STRICT_TYPES()))) {
2908
0
    Z_PROP_FLAG_P(zptr) &= ~IS_PROP_REINITABLE;
2909
0
    zval_ptr_dtor(zptr);
2910
0
    ZVAL_COPY_VALUE(zptr, &z_copy);
2911
0
  } else {
2912
0
    zval_ptr_dtor(&z_copy);
2913
0
  }
2914
0
}
2915
2916
static void ZEND_FASTCALL zend_jit_assign_obj_op_helper(zend_object *zobj, zend_string *name, zval *value, void **cache_slot, binary_op_type binary_op)
2917
0
{
2918
0
  zval *zptr;
2919
0
  zend_property_info *prop_info;
2920
2921
0
  if (EXPECTED((zptr = zobj->handlers->get_property_ptr_ptr(zobj, name, BP_VAR_RW, cache_slot)) != NULL)) {
2922
0
    if (UNEXPECTED(Z_ISERROR_P(zptr))) {
2923
//???     if (UNEXPECTED(RETURN_VALUE_USED(opline))) {
2924
//???       ZVAL_NULL(EX_VAR(opline->result.var));
2925
//???     }
2926
0
    } else {
2927
//???     zval *orig_zptr = zptr;
2928
0
      zend_reference *ref;
2929
2930
0
      do {
2931
0
        if (UNEXPECTED(Z_ISREF_P(zptr))) {
2932
0
          ref = Z_REF_P(zptr);
2933
0
          zptr = Z_REFVAL_P(zptr);
2934
0
          if (UNEXPECTED(ZEND_REF_HAS_TYPE_SOURCES(ref))) {
2935
0
            zend_jit_assign_op_to_typed_ref(ref, value, binary_op);
2936
0
            break;
2937
0
          }
2938
0
        }
2939
2940
//???       if (OP2_TYPE == IS_CONST) {
2941
0
        prop_info = (zend_property_info*)CACHED_PTR_EX(cache_slot + 2);
2942
//???       } else {
2943
//???         prop_info = zend_object_fetch_property_type_info(Z_OBJ_P(object), orig_zptr);
2944
//???       }
2945
0
        if (prop_info && ZEND_TYPE_IS_SET(prop_info->type)) {
2946
          /* special case for typed properties */
2947
0
          zend_jit_assign_op_to_typed_prop(zptr, prop_info, value, binary_op);
2948
0
        } else {
2949
0
          binary_op(zptr, zptr, value);
2950
0
        }
2951
0
      } while (0);
2952
2953
//???     if (UNEXPECTED(RETURN_VALUE_USED(opline))) {
2954
//???       ZVAL_COPY(EX_VAR(opline->result.var), zptr);
2955
//???     }
2956
0
    }
2957
0
  } else {
2958
0
    _zend_jit_assign_op_overloaded_property(zobj, name, cache_slot, value, binary_op);
2959
0
  }
2960
0
}
2961
2962
static ZEND_COLD zend_long _zend_jit_throw_inc_prop_error(zend_property_info *prop)
2963
0
{
2964
0
  zend_string *type_str = zend_type_to_string(prop->type);
2965
0
  zend_type_error("Cannot increment property %s::$%s of type %s past its maximal value",
2966
0
    ZSTR_VAL(prop->ce->name),
2967
0
    zend_get_unmangled_property_name(prop->name),
2968
0
    ZSTR_VAL(type_str));
2969
0
  zend_string_release(type_str);
2970
0
  return ZEND_LONG_MAX;
2971
0
}
2972
2973
static ZEND_COLD zend_long _zend_jit_throw_dec_prop_error(zend_property_info *prop)
2974
0
{
2975
0
  zend_string *type_str = zend_type_to_string(prop->type);
2976
0
  zend_type_error("Cannot decrement property %s::$%s of type %s past its minimal value",
2977
0
    ZSTR_VAL(prop->ce->name),
2978
0
    zend_get_unmangled_property_name(prop->name),
2979
0
    ZSTR_VAL(type_str));
2980
0
  zend_string_release(type_str);
2981
0
  return ZEND_LONG_MIN;
2982
0
}
2983
2984
static void ZEND_FASTCALL zend_jit_inc_typed_prop(zval *var_ptr, zend_property_info *prop_info)
2985
0
{
2986
0
  ZEND_ASSERT(Z_TYPE_P(var_ptr) != IS_UNDEF);
2987
2988
0
  if (UNEXPECTED(!verify_readonly_and_avis(var_ptr, prop_info, true))) {
2989
0
    return;
2990
0
  }
2991
2992
0
  zend_execute_data *execute_data = EG(current_execute_data);
2993
0
  zval tmp;
2994
2995
0
  ZVAL_DEREF(var_ptr);
2996
0
  ZVAL_COPY(&tmp, var_ptr);
2997
2998
0
  increment_function(var_ptr);
2999
3000
0
  if (UNEXPECTED(Z_TYPE_P(var_ptr) == IS_DOUBLE) && Z_TYPE(tmp) == IS_LONG) {
3001
0
    if (!(ZEND_TYPE_FULL_MASK(prop_info->type) & MAY_BE_DOUBLE)) {
3002
0
      zend_long val = _zend_jit_throw_inc_prop_error(prop_info);
3003
0
      ZVAL_LONG(var_ptr, val);
3004
0
    } else {
3005
0
      Z_PROP_FLAG_P(var_ptr) &= ~IS_PROP_REINITABLE;
3006
0
    }
3007
0
  } else if (UNEXPECTED(!zend_verify_property_type(prop_info, var_ptr, EX_USES_STRICT_TYPES()))) {
3008
0
    zval_ptr_dtor(var_ptr);
3009
0
    ZVAL_COPY_VALUE(var_ptr, &tmp);
3010
0
  } else {
3011
0
    Z_PROP_FLAG_P(var_ptr) &= ~IS_PROP_REINITABLE;
3012
0
    zval_ptr_dtor(&tmp);
3013
0
  }
3014
0
}
3015
3016
static void ZEND_FASTCALL zend_jit_dec_typed_prop(zval *var_ptr, zend_property_info *prop_info)
3017
0
{
3018
0
  ZEND_ASSERT(Z_TYPE_P(var_ptr) != IS_UNDEF);
3019
3020
0
  if (UNEXPECTED(!verify_readonly_and_avis(var_ptr, prop_info, true))) {
3021
0
    return;
3022
0
  }
3023
3024
0
  zend_execute_data *execute_data = EG(current_execute_data);
3025
0
  zval tmp;
3026
3027
0
  ZVAL_DEREF(var_ptr);
3028
0
  ZVAL_COPY(&tmp, var_ptr);
3029
3030
0
  decrement_function(var_ptr);
3031
3032
0
  if (UNEXPECTED(Z_TYPE_P(var_ptr) == IS_DOUBLE) && Z_TYPE(tmp) == IS_LONG) {
3033
0
    if (!(ZEND_TYPE_FULL_MASK(prop_info->type) & MAY_BE_DOUBLE)) {
3034
0
      zend_long val = _zend_jit_throw_dec_prop_error(prop_info);
3035
0
      ZVAL_LONG(var_ptr, val);
3036
0
    } else {
3037
0
      Z_PROP_FLAG_P(var_ptr) &= ~IS_PROP_REINITABLE;
3038
0
    }
3039
0
  } else if (UNEXPECTED(!zend_verify_property_type(prop_info, var_ptr, EX_USES_STRICT_TYPES()))) {
3040
0
    zval_ptr_dtor(var_ptr);
3041
0
    ZVAL_COPY_VALUE(var_ptr, &tmp);
3042
0
  } else {
3043
0
    Z_PROP_FLAG_P(var_ptr) &= ~IS_PROP_REINITABLE;
3044
0
    zval_ptr_dtor(&tmp);
3045
0
  }
3046
0
}
3047
3048
static void ZEND_FASTCALL zend_jit_pre_inc_typed_prop(zval *var_ptr, zend_property_info *prop_info, zval *result)
3049
0
{
3050
0
  ZVAL_DEREF(var_ptr);
3051
0
  zend_jit_inc_typed_prop(var_ptr, prop_info);
3052
0
  ZVAL_COPY(result, var_ptr);
3053
0
}
3054
3055
static void ZEND_FASTCALL zend_jit_pre_dec_typed_prop(zval *var_ptr, zend_property_info *prop_info, zval *result)
3056
0
{
3057
0
  ZVAL_DEREF(var_ptr);
3058
0
  zend_jit_dec_typed_prop(var_ptr, prop_info);
3059
0
  ZVAL_COPY(result, var_ptr);
3060
0
}
3061
3062
static void ZEND_FASTCALL zend_jit_post_inc_typed_prop(zval *var_ptr, zend_property_info *prop_info, zval *result)
3063
0
{
3064
0
  ZEND_ASSERT(Z_TYPE_P(var_ptr) != IS_UNDEF);
3065
3066
0
  if (UNEXPECTED(!verify_readonly_and_avis(var_ptr, prop_info, true))) {
3067
0
    if (result) {
3068
0
      ZVAL_UNDEF(result);
3069
0
    }
3070
0
    return;
3071
0
  }
3072
3073
0
  zend_execute_data *execute_data = EG(current_execute_data);
3074
3075
0
  ZVAL_DEREF(var_ptr);
3076
0
  ZVAL_COPY(result, var_ptr);
3077
3078
0
  increment_function(var_ptr);
3079
3080
0
  if (UNEXPECTED(Z_TYPE_P(var_ptr) == IS_DOUBLE) && Z_TYPE_P(result) == IS_LONG) {
3081
0
    if (!(ZEND_TYPE_FULL_MASK(prop_info->type) & MAY_BE_DOUBLE)) {
3082
0
      zend_long val = _zend_jit_throw_inc_prop_error(prop_info);
3083
0
      ZVAL_LONG(var_ptr, val);
3084
0
    } else {
3085
0
      Z_PROP_FLAG_P(var_ptr) &= ~IS_PROP_REINITABLE;
3086
0
    }
3087
0
  } else if (UNEXPECTED(!zend_verify_property_type(prop_info, var_ptr, EX_USES_STRICT_TYPES()))) {
3088
0
    zval_ptr_dtor(var_ptr);
3089
0
    ZVAL_COPY_VALUE(var_ptr, result);
3090
0
    ZVAL_UNDEF(result);
3091
0
  } else {
3092
0
    Z_PROP_FLAG_P(var_ptr) &= ~IS_PROP_REINITABLE;
3093
0
  }
3094
0
}
3095
3096
static void ZEND_FASTCALL zend_jit_post_dec_typed_prop(zval *var_ptr, zend_property_info *prop_info, zval *result)
3097
0
{
3098
0
  ZEND_ASSERT(Z_TYPE_P(var_ptr) != IS_UNDEF);
3099
3100
0
  if (UNEXPECTED(!verify_readonly_and_avis(var_ptr, prop_info, true))) {
3101
0
    if (result) {
3102
0
      ZVAL_UNDEF(result);
3103
0
    }
3104
0
    return;
3105
0
  }
3106
3107
0
  zend_execute_data *execute_data = EG(current_execute_data);
3108
3109
0
  ZVAL_DEREF(var_ptr);
3110
0
  ZVAL_COPY(result, var_ptr);
3111
3112
0
  decrement_function(var_ptr);
3113
3114
0
  if (UNEXPECTED(Z_TYPE_P(var_ptr) == IS_DOUBLE) && Z_TYPE_P(result) == IS_LONG) {
3115
0
    if (!(ZEND_TYPE_FULL_MASK(prop_info->type) & MAY_BE_DOUBLE)) {
3116
0
      zend_long val = _zend_jit_throw_dec_prop_error(prop_info);
3117
0
      ZVAL_LONG(var_ptr, val);
3118
0
    } else {
3119
0
      Z_PROP_FLAG_P(var_ptr) &= ~IS_PROP_REINITABLE;
3120
0
    }
3121
0
  } else if (UNEXPECTED(!zend_verify_property_type(prop_info, var_ptr, EX_USES_STRICT_TYPES()))) {
3122
0
    zval_ptr_dtor(var_ptr);
3123
0
    ZVAL_COPY_VALUE(var_ptr, result);
3124
0
    ZVAL_UNDEF(result);
3125
0
  } else {
3126
0
    Z_PROP_FLAG_P(var_ptr) &= ~IS_PROP_REINITABLE;
3127
0
  }
3128
0
}
3129
3130
static void ZEND_FASTCALL zend_jit_pre_inc_obj_helper(zend_object *zobj, zend_string *name, void **cache_slot, zval *result)
3131
0
{
3132
0
  zval *prop;
3133
3134
0
  if (EXPECTED((prop = zobj->handlers->get_property_ptr_ptr(zobj, name, BP_VAR_RW, cache_slot)) != NULL)) {
3135
0
    if (UNEXPECTED(Z_ISERROR_P(prop))) {
3136
0
      if (UNEXPECTED(result)) {
3137
0
        ZVAL_NULL(result);
3138
0
      }
3139
0
    } else {
3140
0
      zend_property_info *prop_info = (zend_property_info *) CACHED_PTR_EX(cache_slot + 2);
3141
0
      if (prop_info && !ZEND_TYPE_IS_SET(prop_info->type)) {
3142
0
        prop_info = NULL;
3143
0
      }
3144
3145
0
      if (EXPECTED(Z_TYPE_P(prop) == IS_LONG)) {
3146
0
        fast_long_increment_function(prop);
3147
0
        if (UNEXPECTED(Z_TYPE_P(prop) != IS_LONG) && prop_info
3148
0
            && !(ZEND_TYPE_FULL_MASK(prop_info->type) & MAY_BE_DOUBLE)) {
3149
0
          zend_long val = _zend_jit_throw_inc_prop_error(prop_info);
3150
0
          ZVAL_LONG(prop, val);
3151
0
        }
3152
0
      } else {
3153
0
        do {
3154
0
          if (Z_ISREF_P(prop)) {
3155
0
            zend_reference *ref = Z_REF_P(prop);
3156
0
            prop = Z_REFVAL_P(prop);
3157
0
            if (UNEXPECTED(ZEND_REF_HAS_TYPE_SOURCES(ref))) {
3158
0
              zend_jit_pre_inc_typed_ref(ref, result);
3159
0
              break;
3160
0
            }
3161
0
          }
3162
3163
0
          if (prop_info) {
3164
0
            zend_jit_inc_typed_prop(prop, prop_info);
3165
0
          } else {
3166
0
            increment_function(prop);
3167
0
          }
3168
0
        } while (0);
3169
0
      }
3170
0
      if (UNEXPECTED(result)) {
3171
0
        ZVAL_COPY(result, prop);
3172
0
      }
3173
0
    }
3174
0
  } else {
3175
0
    zval rv;
3176
0
    zval *z;
3177
0
    zval z_copy;
3178
3179
0
    GC_ADDREF(zobj);
3180
0
    z = zobj->handlers->read_property(zobj, name, BP_VAR_R, cache_slot, &rv);
3181
0
    if (UNEXPECTED(EG(exception))) {
3182
0
      OBJ_RELEASE(zobj);
3183
0
      if (UNEXPECTED(result)) {
3184
0
        ZVAL_NULL(result);
3185
0
      }
3186
0
      return;
3187
0
    }
3188
3189
0
    ZVAL_COPY_DEREF(&z_copy, z);
3190
0
    increment_function(&z_copy);
3191
0
    if (UNEXPECTED(result)) {
3192
0
      ZVAL_COPY(result, &z_copy);
3193
0
    }
3194
0
    zobj->handlers->write_property(zobj, name, &z_copy, cache_slot);
3195
0
    OBJ_RELEASE(zobj);
3196
0
    zval_ptr_dtor(&z_copy);
3197
0
    if (z == &rv) {
3198
0
      zval_ptr_dtor(z);
3199
0
    }
3200
0
  }
3201
0
}
3202
3203
static void ZEND_FASTCALL zend_jit_pre_dec_obj_helper(zend_object *zobj, zend_string *name, void **cache_slot, zval *result)
3204
0
{
3205
0
  zval *prop;
3206
3207
0
  if (EXPECTED((prop = zobj->handlers->get_property_ptr_ptr(zobj, name, BP_VAR_RW, cache_slot)) != NULL)) {
3208
0
    if (UNEXPECTED(Z_ISERROR_P(prop))) {
3209
0
      if (UNEXPECTED(result)) {
3210
0
        ZVAL_NULL(result);
3211
0
      }
3212
0
    } else {
3213
0
      zend_property_info *prop_info = (zend_property_info *) CACHED_PTR_EX(cache_slot + 2);
3214
0
      if (prop_info && !ZEND_TYPE_IS_SET(prop_info->type)) {
3215
0
        prop_info = NULL;
3216
0
      }
3217
3218
0
      if (EXPECTED(Z_TYPE_P(prop) == IS_LONG)) {
3219
0
        fast_long_decrement_function(prop);
3220
0
        if (UNEXPECTED(Z_TYPE_P(prop) != IS_LONG) && prop_info
3221
0
            && !(ZEND_TYPE_FULL_MASK(prop_info->type) & MAY_BE_DOUBLE)) {
3222
0
          zend_long val = _zend_jit_throw_dec_prop_error(prop_info);
3223
0
          ZVAL_LONG(prop, val);
3224
0
        }
3225
0
      } else {
3226
0
        do {
3227
0
          if (Z_ISREF_P(prop)) {
3228
0
            zend_reference *ref = Z_REF_P(prop);
3229
0
            prop = Z_REFVAL_P(prop);
3230
0
            if (UNEXPECTED(ZEND_REF_HAS_TYPE_SOURCES(ref))) {
3231
0
              zend_jit_pre_dec_typed_ref(ref, result);
3232
0
              break;
3233
0
            }
3234
0
          }
3235
3236
0
          if (prop_info) {
3237
0
            zend_jit_dec_typed_prop(prop, prop_info);
3238
0
          } else {
3239
0
            decrement_function(prop);
3240
0
          }
3241
0
        } while (0);
3242
0
      }
3243
0
      if (UNEXPECTED(result)) {
3244
0
        ZVAL_COPY(result, prop);
3245
0
      }
3246
0
    }
3247
0
  } else {
3248
0
    zval rv;
3249
0
    zval *z;
3250
0
    zval z_copy;
3251
3252
0
    GC_ADDREF(zobj);
3253
0
    z = zobj->handlers->read_property(zobj, name, BP_VAR_R, cache_slot, &rv);
3254
0
    if (UNEXPECTED(EG(exception))) {
3255
0
      OBJ_RELEASE(zobj);
3256
0
      if (UNEXPECTED(result)) {
3257
0
        ZVAL_NULL(result);
3258
0
      }
3259
0
      return;
3260
0
    }
3261
3262
0
    ZVAL_COPY_DEREF(&z_copy, z);
3263
0
    decrement_function(&z_copy);
3264
0
    if (UNEXPECTED(result)) {
3265
0
      ZVAL_COPY(result, &z_copy);
3266
0
    }
3267
0
    zobj->handlers->write_property(zobj, name, &z_copy, cache_slot);
3268
0
    OBJ_RELEASE(zobj);
3269
0
    zval_ptr_dtor(&z_copy);
3270
0
    if (z == &rv) {
3271
0
      zval_ptr_dtor(z);
3272
0
    }
3273
0
  }
3274
0
}
3275
3276
static void ZEND_FASTCALL zend_jit_post_inc_obj_helper(zend_object *zobj, zend_string *name, void **cache_slot, zval *result)
3277
0
{
3278
0
  zval *prop;
3279
3280
0
  if (EXPECTED((prop = zobj->handlers->get_property_ptr_ptr(zobj, name, BP_VAR_RW, cache_slot)) != NULL)) {
3281
0
    if (UNEXPECTED(Z_ISERROR_P(prop))) {
3282
0
      ZVAL_NULL(result);
3283
0
    } else {
3284
0
      zend_property_info *prop_info = (zend_property_info*)CACHED_PTR_EX(cache_slot + 2);
3285
0
      if (prop_info && !ZEND_TYPE_IS_SET(prop_info->type)) {
3286
0
        prop_info = NULL;
3287
0
      }
3288
3289
0
      if (EXPECTED(Z_TYPE_P(prop) == IS_LONG)) {
3290
0
        ZVAL_LONG(result, Z_LVAL_P(prop));
3291
0
        fast_long_increment_function(prop);
3292
0
        if (UNEXPECTED(Z_TYPE_P(prop) != IS_LONG) && prop_info
3293
0
            && !(ZEND_TYPE_FULL_MASK(prop_info->type) & MAY_BE_DOUBLE)) {
3294
0
          zend_long val = _zend_jit_throw_inc_prop_error(prop_info);
3295
0
          ZVAL_LONG(prop, val);
3296
0
        }
3297
0
      } else {
3298
0
        if (Z_ISREF_P(prop)) {
3299
0
          zend_reference *ref = Z_REF_P(prop);
3300
0
          prop = Z_REFVAL_P(prop);
3301
0
          if (ZEND_REF_HAS_TYPE_SOURCES(ref)) {
3302
0
            zend_jit_post_inc_typed_ref(ref, result);
3303
0
            return;
3304
0
          }
3305
0
        }
3306
3307
0
        if (prop_info) {
3308
0
          zend_jit_post_inc_typed_prop(prop, prop_info, result);
3309
0
        } else {
3310
0
          ZVAL_COPY(result, prop);
3311
0
          increment_function(prop);
3312
0
        }
3313
0
      }
3314
0
    }
3315
0
  } else {
3316
0
    zval rv;
3317
0
    zval *z;
3318
0
    zval z_copy;
3319
3320
0
    GC_ADDREF(zobj);
3321
0
    z = zobj->handlers->read_property(zobj, name, BP_VAR_R, cache_slot, &rv);
3322
0
    if (UNEXPECTED(EG(exception))) {
3323
0
      OBJ_RELEASE(zobj);
3324
0
      ZVAL_UNDEF(result);
3325
0
      return;
3326
0
    }
3327
3328
0
    ZVAL_COPY_DEREF(&z_copy, z);
3329
0
    ZVAL_COPY(result, &z_copy);
3330
0
    increment_function(&z_copy);
3331
0
    zobj->handlers->write_property(zobj, name, &z_copy, cache_slot);
3332
0
    OBJ_RELEASE(zobj);
3333
0
    zval_ptr_dtor(&z_copy);
3334
0
    if (z == &rv) {
3335
0
      zval_ptr_dtor(z);
3336
0
    }
3337
0
  }
3338
0
}
3339
3340
static void ZEND_FASTCALL zend_jit_post_dec_obj_helper(zend_object *zobj, zend_string *name, void **cache_slot, zval *result)
3341
0
{
3342
0
  zval *prop;
3343
3344
0
  if (EXPECTED((prop = zobj->handlers->get_property_ptr_ptr(zobj, name, BP_VAR_RW, cache_slot)) != NULL)) {
3345
0
    if (UNEXPECTED(Z_ISERROR_P(prop))) {
3346
0
      ZVAL_NULL(result);
3347
0
    } else {
3348
0
      zend_property_info *prop_info = (zend_property_info*)CACHED_PTR_EX(cache_slot + 2);
3349
0
      if (prop_info && !ZEND_TYPE_IS_SET(prop_info->type)) {
3350
0
        prop_info = NULL;
3351
0
      }
3352
3353
0
      if (EXPECTED(Z_TYPE_P(prop) == IS_LONG)) {
3354
0
        ZVAL_LONG(result, Z_LVAL_P(prop));
3355
0
        fast_long_decrement_function(prop);
3356
0
        if (UNEXPECTED(Z_TYPE_P(prop) != IS_LONG) && prop_info
3357
0
            && !(ZEND_TYPE_FULL_MASK(prop_info->type) & MAY_BE_DOUBLE)) {
3358
0
          zend_long val = _zend_jit_throw_dec_prop_error(prop_info);
3359
0
          ZVAL_LONG(prop, val);
3360
0
        }
3361
0
      } else {
3362
0
        if (Z_ISREF_P(prop)) {
3363
0
          zend_reference *ref = Z_REF_P(prop);
3364
0
          prop = Z_REFVAL_P(prop);
3365
0
          if (ZEND_REF_HAS_TYPE_SOURCES(ref)) {
3366
0
            zend_jit_post_dec_typed_ref(ref, result);
3367
0
            return;
3368
0
          }
3369
0
        }
3370
3371
0
        if (prop_info) {
3372
0
          zend_jit_post_dec_typed_prop(prop, prop_info, result);
3373
0
        } else {
3374
0
          ZVAL_COPY(result, prop);
3375
0
          decrement_function(prop);
3376
0
        }
3377
0
      }
3378
0
    }
3379
0
  } else {
3380
0
    zval rv;
3381
0
    zval *z;
3382
0
    zval z_copy;
3383
3384
0
    GC_ADDREF(zobj);
3385
0
    z = zobj->handlers->read_property(zobj, name, BP_VAR_R, cache_slot, &rv);
3386
0
    if (UNEXPECTED(EG(exception))) {
3387
0
      OBJ_RELEASE(zobj);
3388
0
      ZVAL_UNDEF(result);
3389
0
      return;
3390
0
    }
3391
3392
0
    ZVAL_COPY_DEREF(&z_copy, z);
3393
0
    ZVAL_COPY(result, &z_copy);
3394
0
    decrement_function(&z_copy);
3395
0
    zobj->handlers->write_property(zobj, name, &z_copy, cache_slot);
3396
0
    OBJ_RELEASE(zobj);
3397
0
    zval_ptr_dtor(&z_copy);
3398
0
    if (z == &rv) {
3399
0
      zval_ptr_dtor(z);
3400
0
    }
3401
0
  }
3402
0
}
3403
3404
static void ZEND_FASTCALL zend_jit_uninit_static_prop(void)
3405
0
{
3406
0
  zend_execute_data *execute_data = EG(current_execute_data);
3407
0
  const zend_op *opline = EX(opline);
3408
0
  uint32_t cache_slot = opline->extended_value & ~ZEND_FETCH_OBJ_FLAGS;
3409
0
  const zend_property_info *property_info = CACHED_PTR(cache_slot + sizeof(void *) * 2);
3410
3411
0
  zend_throw_error(NULL, "Typed static property %s::$%s must not be accessed before initialization",
3412
0
    ZSTR_VAL(property_info->ce->name),
3413
0
    zend_get_unmangled_property_name(property_info->name));
3414
0
}
3415
3416
static void ZEND_FASTCALL zend_jit_free_trampoline_helper(zend_function *func)
3417
0
{
3418
0
  ZEND_ASSERT(func->common.fn_flags & ZEND_ACC_CALL_VIA_TRAMPOLINE);
3419
0
  zend_string_release_ex(func->common.function_name, 0);
3420
0
  zend_free_trampoline(func);
3421
0
}
3422
3423
static void ZEND_FASTCALL zend_jit_exception_in_interrupt_handler_helper(void)
3424
0
{
3425
0
  if (EG(exception)) {
3426
    /* We have to UNDEF result, because ZEND_HANDLE_EXCEPTION is going to free it */
3427
0
    const zend_op *throw_op = EG(opline_before_exception);
3428
3429
0
    if (throw_op
3430
0
     && throw_op->result_type & (IS_TMP_VAR|IS_VAR)
3431
0
     && throw_op->opcode != ZEND_ADD_ARRAY_ELEMENT
3432
0
     && throw_op->opcode != ZEND_ADD_ARRAY_UNPACK
3433
0
     && throw_op->opcode != ZEND_ROPE_INIT
3434
0
     && throw_op->opcode != ZEND_ROPE_ADD) {
3435
0
      ZVAL_UNDEF(ZEND_CALL_VAR(EG(current_execute_data), throw_op->result.var));
3436
0
    }
3437
0
  }
3438
0
}
3439
3440
static zend_string* ZEND_FASTCALL zend_jit_rope_end(zend_string **rope, uint32_t count)
3441
0
{
3442
0
  zend_string *ret;
3443
0
  uint32_t i;
3444
0
  size_t len = 0;
3445
3446
0
  uint32_t flags = ZSTR_COPYABLE_CONCAT_PROPERTIES;
3447
0
  for (i = 0; i <= count; i++) {
3448
0
    flags &= ZSTR_GET_COPYABLE_CONCAT_PROPERTIES(rope[i]);
3449
0
    len += ZSTR_LEN(rope[i]);
3450
0
  }
3451
0
  ret = zend_string_alloc(len, 0);
3452
0
  GC_ADD_FLAGS(ret, flags);
3453
3454
0
  char *target = ZSTR_VAL(ret);
3455
0
  for (i = 0; i <= count; i++) {
3456
0
    target = zend_mempcpy(target, ZSTR_VAL(rope[i]), ZSTR_LEN(rope[i]));
3457
0
    zend_string_release_ex(rope[i], 0);
3458
0
  }
3459
0
  *target = '\0';
3460
0
  return ret;
3461
0
}