Coverage Report

Created: 2025-09-27 06:26

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