zend_stack_push(&CG(loop_var_stack), &reset_node);
opnum_fetch = get_next_op_number(CG(active_op_array));
- opline = zend_emit_op(&value_node, by_ref ? ZEND_FE_FETCH_RW : ZEND_FE_FETCH_R, &reset_node, NULL);
- if (key_ast) {
- opline->extended_value = 1;
- }
-
- opline = zend_emit_op(NULL, ZEND_OP_DATA, NULL, NULL);
-
- if (key_ast) {
- zend_make_tmp_result(&key_node, opline);
- }
+ opline = zend_emit_op(NULL, by_ref ? ZEND_FE_FETCH_RW : ZEND_FE_FETCH_R, &reset_node, NULL);
- if (by_ref) {
- zend_emit_assign_ref_znode(value_ast, &value_node);
+ if (value_ast->kind == ZEND_AST_VAR &&
+ zend_try_compile_cv(&value_node, value_ast) == SUCCESS) {
+ SET_NODE(opline->op2, &value_node);
} else {
- zend_emit_assign_znode(value_ast, &value_node);
+ opline->op2_type = IS_VAR;
+ opline->op2.var = get_temporary_variable(CG(active_op_array));
+ GET_NODE(&value_node, opline->op2);
+ if (by_ref) {
+ zend_emit_assign_ref_znode(value_ast, &value_node);
+ } else {
+ zend_emit_assign_znode(value_ast, &value_node);
+ }
}
if (key_ast) {
+ opline = &CG(active_op_array)->opcodes[opnum_fetch];
+ zend_make_tmp_result(&key_node, opline);
zend_emit_assign_znode(key_ast, &key_node);
}
opline->op2.opline_num = get_next_op_number(CG(active_op_array));
opline = &CG(active_op_array)->opcodes[opnum_fetch];
- opline->op2.opline_num = get_next_op_number(CG(active_op_array));
+ opline->extended_value = get_next_op_number(CG(active_op_array));
zend_end_loop(opnum_fetch, 1);
static inline void zend_assign_to_variable_reference(zval *variable_ptr, zval *value_ptr)
{
+ zend_reference *ref;
+
if (EXPECTED(!Z_ISREF_P(value_ptr))) {
ZVAL_NEW_REF(value_ptr, value_ptr);
+ } else if (UNEXPECTED(variable_ptr == value_ptr)) {
+ return;
}
- if (EXPECTED(variable_ptr != value_ptr)) {
- zend_reference *ref;
- ref = Z_REF_P(value_ptr);
- GC_REFCOUNT(ref)++;
- zval_ptr_dtor(variable_ptr);
- ZVAL_REF(variable_ptr, ref);
- }
+ ref = Z_REF_P(value_ptr);
+ GC_REFCOUNT(ref)++;
+ zval_ptr_dtor(variable_ptr);
+ ZVAL_REF(variable_ptr, ref);
}
/* this should modify object only if it's empty */
case ZEND_NEW:
case ZEND_FE_RESET_R:
case ZEND_FE_RESET_RW:
- case ZEND_FE_FETCH_R:
- case ZEND_FE_FETCH_RW:
case ZEND_ASSERT_CHECK:
ZEND_PASS_TWO_UPDATE_JMP_TARGET(op_array, opline, opline->op2);
break;
+ case ZEND_FE_FETCH_R:
+ case ZEND_FE_FETCH_RW:
+ opline->extended_value = ZEND_OPLINE_NUM_TO_OFFSET(op_array, opline, opline->extended_value);
+ break;
case ZEND_VERIFY_RETURN_TYPE:
if (op_array->fn_flags & ZEND_ACC_GENERATOR) {
MAKE_NOP(opline);
#define Z_COUNTED(zval) (zval).value.counted
#define Z_COUNTED_P(zval_p) Z_COUNTED(*(zval_p))
+#define Z_TYPE_MASK 0xff
+
#define Z_TYPE_FLAGS_SHIFT 8
#define Z_CONST_FLAGS_SHIFT 16
#define Z_SYMBOLTABLE_P(zval_p) Z_SYMBOLTABLE(*(zval_p))
/* the following Z_OPT_* macros make better code when Z_TYPE_INFO accessed before */
-#define Z_OPT_TYPE(zval) (Z_TYPE_INFO(zval) & 0xff)
+#define Z_OPT_TYPE(zval) (Z_TYPE_INFO(zval) & Z_TYPE_MASK)
#define Z_OPT_TYPE_P(zval_p) Z_OPT_TYPE(*(zval_p))
#define Z_OPT_CONSTANT(zval) ((Z_TYPE_INFO(zval) & (IS_TYPE_CONSTANT << Z_TYPE_FLAGS_SHIFT)) != 0)
#if SIZEOF_ZEND_LONG == 4
# define ZVAL_COPY_VALUE_EX(z, v, gc, t) \
do { \
- uint32_t _w2; \
- gc = v->value.counted; \
- _w2 = v->value.ww.w2; \
- t = Z_TYPE_INFO_P(v); \
- z->value.counted = gc; \
+ uint32_t _w2 = v->value.ww.w2; \
+ Z_COUNTED_P(z) = gc; \
z->value.ww.w2 = _w2; \
Z_TYPE_INFO_P(z) = t; \
} while (0)
#elif SIZEOF_ZEND_LONG == 8
# define ZVAL_COPY_VALUE_EX(z, v, gc, t) \
do { \
- gc = v->value.counted; \
- t = Z_TYPE_INFO_P(v); \
- z->value.counted = gc; \
+ Z_COUNTED_P(z) = gc; \
Z_TYPE_INFO_P(z) = t; \
} while (0)
#else
do { \
zval *_z1 = (z); \
const zval *_z2 = (v); \
- zend_refcounted *_gc; \
- uint32_t _t; \
+ zend_refcounted *_gc = Z_COUNTED_P(_z2); \
+ uint32_t _t = Z_TYPE_INFO_P(_z2); \
ZVAL_COPY_VALUE_EX(_z1, _z2, _gc, _t); \
} while (0)
do { \
zval *_z1 = (z); \
const zval *_z2 = (v); \
- zend_refcounted *_gc; \
- uint32_t _t; \
+ zend_refcounted *_gc = Z_COUNTED_P(_z2); \
+ uint32_t _t = Z_TYPE_INFO_P(_z2); \
ZVAL_COPY_VALUE_EX(_z1, _z2, _gc, _t); \
if ((_t & (IS_TYPE_REFCOUNTED << Z_TYPE_FLAGS_SHIFT)) != 0) { \
GC_REFCOUNT(_gc)++; \
do { \
zval *_z1 = (z); \
const zval *_z2 = (v); \
- zend_refcounted *_gc; \
- uint32_t _t; \
+ zend_refcounted *_gc = Z_COUNTED_P(_z2); \
+ uint32_t _t = Z_TYPE_INFO_P(_z2); \
ZVAL_COPY_VALUE_EX(_z1, _z2, _gc, _t); \
if ((_t & ((IS_TYPE_REFCOUNTED|IS_TYPE_IMMUTABLE) << Z_TYPE_FLAGS_SHIFT)) != 0) { \
if ((_t & ((IS_TYPE_COPYABLE|IS_TYPE_IMMUTABLE) << Z_TYPE_FLAGS_SHIFT)) != 0) { \
USE_OPLINE
zval *array;
zval *value;
+ uint32_t value_type;
HashTable *fe_ht;
HashPosition pos;
Bucket *p;
SAVE_OPLINE();
if (EXPECTED(Z_TYPE_P(array) == IS_ARRAY)) {
fe_ht = Z_ARRVAL_P(array);
- pos = Z_FE_POS_P(EX_VAR(opline->op1.var));
+ pos = Z_FE_POS_P(array);
p = fe_ht->arData + pos;
while (1) {
if (UNEXPECTED(pos >= fe_ht->nNumUsed)) {
/* reached end of iteration */
- ZEND_VM_JMP(OP_JMP_ADDR(opline, opline->op2));
+ ZEND_VM_C_GOTO(fe_fetch_r_exit);
}
value = &p->val;
- if (Z_TYPE_INFO_P(value) == IS_UNDEF) {
+ value_type = Z_TYPE_INFO_P(value);
+ if (value_type == IS_UNDEF) {
pos++;
p++;
continue;
- } else if (UNEXPECTED(Z_TYPE_INFO_P(value) == IS_INDIRECT)) {
+ } else if (UNEXPECTED(value_type == IS_INDIRECT)) {
value = Z_INDIRECT_P(value);
- if (UNEXPECTED(Z_TYPE_INFO_P(value) == IS_UNDEF)) {
+ value_type = Z_TYPE_INFO_P(value);
+ if (UNEXPECTED(value_type == IS_UNDEF)) {
pos++;
p++;
continue;
}
break;
}
- ZVAL_COPY(EX_VAR(opline->result.var), value);
- Z_FE_POS_P(EX_VAR(opline->op1.var)) = pos + 1;
- if (opline->extended_value) {
+ Z_FE_POS_P(array) = pos + 1;
+ if (opline->result_type == IS_TMP_VAR) {
if (!p->key) {
- ZVAL_LONG(EX_VAR((opline+1)->result.var), p->h);
+ ZVAL_LONG(EX_VAR(opline->result.var), p->h);
} else {
- ZVAL_STR_COPY(EX_VAR((opline+1)->result.var), p->key);
+ ZVAL_STR_COPY(EX_VAR(opline->result.var), p->key);
}
}
- ZEND_VM_INC_OPCODE();
- ZEND_VM_NEXT_OPCODE();
} else if (EXPECTED(Z_TYPE_P(array) == IS_OBJECT)) {
zend_object_iterator *iter;
/* plain object */
fe_ht = Z_OBJPROP_P(array);
- pos = zend_hash_iterator_pos(Z_FE_ITER_P(EX_VAR(opline->op1.var)), fe_ht);
+ pos = zend_hash_iterator_pos(Z_FE_ITER_P(array), fe_ht);
p = fe_ht->arData + pos;
while (1) {
if (UNEXPECTED(pos >= fe_ht->nNumUsed)) {
/* reached end of iteration */
- ZEND_VM_JMP(OP_JMP_ADDR(opline, opline->op2));
+ ZEND_VM_C_GOTO(fe_fetch_r_exit);
}
value = &p->val;
- if (UNEXPECTED(Z_TYPE_INFO_P(value) == IS_UNDEF)) {
+ value_type = Z_TYPE_INFO_P(value);
+ if (UNEXPECTED(value_type == IS_UNDEF)) {
pos++;
p++;
continue;
- } else if (UNEXPECTED(Z_TYPE_INFO_P(value) == IS_INDIRECT)) {
+ } else if (UNEXPECTED(value_type == IS_INDIRECT)) {
value = Z_INDIRECT_P(value);
- if (UNEXPECTED(Z_TYPE_INFO_P(value) == IS_UNDEF)) {
+ value_type = Z_TYPE_INFO_P(value);
+ if (UNEXPECTED(value_type == IS_UNDEF)) {
pos++;
p++;
continue;
pos++;
p++;
}
- ZVAL_COPY(EX_VAR(opline->result.var), value);
- if (opline->extended_value) {
+ if (opline->result_type == IS_TMP_VAR) {
if (UNEXPECTED(!p->key)) {
- ZVAL_LONG(EX_VAR((opline+1)->result.var), p->h);
+ ZVAL_LONG(EX_VAR(opline->result.var), p->h);
} else if (p->key->val[0]) {
- ZVAL_STR_COPY(EX_VAR((opline+1)->result.var), p->key);
+ ZVAL_STR_COPY(EX_VAR(opline->result.var), p->key);
} else {
const char *class_name, *prop_name;
size_t prop_name_len;
zend_unmangle_property_name_ex(
p->key, &class_name, &prop_name, &prop_name_len);
- ZVAL_STRINGL(EX_VAR((opline+1)->result.var), prop_name, prop_name_len);
+ ZVAL_STRINGL(EX_VAR(opline->result.var), prop_name, prop_name_len);
}
}
while (1) {
break;
}
}
- EG(ht_iterators)[Z_FE_ITER_P(EX_VAR(opline->op1.var))].pos = pos;
- ZEND_VM_INC_OPCODE();
- ZEND_VM_NEXT_OPCODE();
+ EG(ht_iterators)[Z_FE_ITER_P(array)].pos = pos;
} else {
- /* !iter happens from exception */
- if (iter && ++iter->index > 0) {
+ if (EXPECTED(++iter->index > 0)) {
/* This could cause an endless loop if index becomes zero again.
* In case that ever happens we need an additional flag. */
iter->funcs->move_forward(iter);
zval_ptr_dtor(array);
HANDLE_EXCEPTION();
}
- }
- /* If index is zero we come from FE_RESET and checked valid() already. */
- if (!iter || (iter->index > 0 && iter->funcs->valid(iter) == FAILURE)) {
- /* reached end of iteration */
- if (UNEXPECTED(EG(exception) != NULL)) {
- zval_ptr_dtor(array);
- HANDLE_EXCEPTION();
+ if (UNEXPECTED(iter->funcs->valid(iter) == FAILURE)) {
+ /* reached end of iteration */
+ if (UNEXPECTED(EG(exception) != NULL)) {
+ zval_ptr_dtor(array);
+ HANDLE_EXCEPTION();
+ }
+ ZEND_VM_C_GOTO(fe_fetch_r_exit);
}
- ZEND_VM_JMP(OP_JMP_ADDR(opline, opline->op2));
}
value = iter->funcs->get_current_data(iter);
if (UNEXPECTED(EG(exception) != NULL)) {
}
if (!value) {
/* failure in get_current_data */
- ZEND_VM_JMP(OP_JMP_ADDR(opline, opline->op2));
+ ZEND_VM_C_GOTO(fe_fetch_r_exit);
}
- ZVAL_COPY(EX_VAR(opline->result.var), value);
- if (opline->extended_value) {
+ if (opline->result_type == IS_TMP_VAR) {
if (iter->funcs->get_current_key) {
- iter->funcs->get_current_key(iter, EX_VAR((opline+1)->result.var));
+ iter->funcs->get_current_key(iter, EX_VAR(opline->result.var));
if (UNEXPECTED(EG(exception) != NULL)) {
zval_ptr_dtor(array);
HANDLE_EXCEPTION();
}
} else {
- ZVAL_LONG(EX_VAR((opline+1)->result.var), iter->index);
+ ZVAL_LONG(EX_VAR(opline->result.var), iter->index);
}
}
- ZEND_VM_INC_OPCODE();
- ZEND_VM_NEXT_OPCODE();
+ value_type = Z_TYPE_INFO_P(value);
}
} else {
zend_error(E_WARNING, "Invalid argument supplied for foreach()");
- ZEND_VM_JMP(OP_JMP_ADDR(opline, opline->op2));
+ZEND_VM_C_LABEL(fe_fetch_r_exit):
+ if (EXPECTED(!EG(exception))) {
+ ZEND_VM_SET_RELATIVE_OPCODE(opline, opline->extended_value);
+ }
+ ZEND_VM_CONTINUE();
}
+
+ if (EXPECTED(OP2_TYPE == IS_CV)) {
+ zval *variable_ptr = _get_zval_ptr_cv_undef_BP_VAR_W(execute_data, opline->op2.var);
+ zend_assign_to_variable(variable_ptr, value, IS_CV);
+ } else {
+ zval *res = EX_VAR(opline->op2.var);
+ zend_refcounted *gc = Z_COUNTED_P(value);
+
+ ZVAL_COPY_VALUE_EX(res, value, gc, value_type);
+ if (EXPECTED((value_type & (IS_TYPE_REFCOUNTED << Z_TYPE_FLAGS_SHIFT)) != 0)) {
+ GC_REFCOUNT(gc)++;
+ }
+ }
+ ZEND_VM_NEXT_OPCODE();
}
ZEND_VM_HANDLER(126, ZEND_FE_FETCH_RW, VAR, ANY)
USE_OPLINE
zval *array;
zval *value;
+ uint32_t value_type;
HashTable *fe_ht;
HashPosition pos;
Bucket *p;
while (1) {
if (UNEXPECTED(pos >= fe_ht->nNumUsed)) {
/* reached end of iteration */
- ZEND_VM_JMP(OP_JMP_ADDR(opline, opline->op2));
+ ZEND_VM_C_GOTO(fe_fetch_w_exit);
}
value = &p->val;
- if (UNEXPECTED(Z_TYPE_P(value) == IS_UNDEF)) {
+ value_type = Z_TYPE_INFO_P(value);
+ if (UNEXPECTED(value_type == IS_UNDEF)) {
pos++;
p++;
continue;
- } else if (UNEXPECTED(Z_TYPE_P(value) == IS_INDIRECT)) {
+ } else if (UNEXPECTED(value_type == IS_INDIRECT)) {
value = Z_INDIRECT_P(value);
- if (UNEXPECTED(Z_TYPE_P(value) == IS_UNDEF)) {
+ value_type = Z_TYPE_INFO_P(value);
+ if (UNEXPECTED(value_type == IS_UNDEF)) {
pos++;
p++;
continue;
}
break;
}
- ZVAL_MAKE_REF(value);
- Z_ADDREF_P(value);
- ZVAL_REF(EX_VAR(opline->result.var), Z_REF_P(value));
- if (opline->extended_value) {
+ if (opline->result_type == IS_TMP_VAR) {
if (!p->key) {
- ZVAL_LONG(EX_VAR((opline+1)->result.var), p->h);
+ ZVAL_LONG(EX_VAR(opline->result.var), p->h);
} else {
- ZVAL_STR_COPY(EX_VAR((opline+1)->result.var), p->key);
+ ZVAL_STR_COPY(EX_VAR(opline->result.var), p->key);
}
}
while (1) {
}
}
EG(ht_iterators)[Z_FE_ITER_P(EX_VAR(opline->op1.var))].pos = pos;
- ZEND_VM_INC_OPCODE();
- ZEND_VM_NEXT_OPCODE();
} else if (EXPECTED(Z_TYPE_P(array) == IS_OBJECT)) {
zend_object_iterator *iter;
while (1) {
if (UNEXPECTED(pos >= fe_ht->nNumUsed)) {
/* reached end of iteration */
- ZEND_VM_JMP(OP_JMP_ADDR(opline, opline->op2));
+ ZEND_VM_C_GOTO(fe_fetch_w_exit);
}
value = &p->val;
- if (UNEXPECTED(Z_TYPE_P(value) == IS_UNDEF)) {
+ value_type = Z_TYPE_INFO_P(value);
+ if (UNEXPECTED(value_type == IS_UNDEF)) {
pos++;
p++;
continue;
- } else if (UNEXPECTED(Z_TYPE_P(value) == IS_INDIRECT)) {
+ } else if (UNEXPECTED(value_type == IS_INDIRECT)) {
value = Z_INDIRECT_P(value);
- if (UNEXPECTED(Z_TYPE_P(value) == IS_UNDEF)) {
+ value_type = Z_TYPE_INFO_P(value);
+ if (UNEXPECTED(value_type == IS_UNDEF)) {
pos++;
p++;
continue;
pos++;
p++;
}
- ZVAL_MAKE_REF(value);
- Z_ADDREF_P(value);
- ZVAL_REF(EX_VAR(opline->result.var), Z_REF_P(value));
- if (opline->extended_value) {
+ if (opline->result_type == IS_TMP_VAR) {
if (UNEXPECTED(!p->key)) {
- ZVAL_LONG(EX_VAR((opline+1)->result.var), p->h);
+ ZVAL_LONG(EX_VAR(opline->result.var), p->h);
} else if (p->key->val[0]) {
- ZVAL_STR_COPY(EX_VAR((opline+1)->result.var), p->key);
+ ZVAL_STR_COPY(EX_VAR(opline->result.var), p->key);
} else {
const char *class_name, *prop_name;
size_t prop_name_len;
zend_unmangle_property_name_ex(
p->key, &class_name, &prop_name, &prop_name_len);
- ZVAL_STRINGL(EX_VAR((opline+1)->result.var), prop_name, prop_name_len);
+ ZVAL_STRINGL(EX_VAR(opline->result.var), prop_name, prop_name_len);
}
}
while (1) {
}
}
EG(ht_iterators)[Z_FE_ITER_P(EX_VAR(opline->op1.var))].pos = pos;
- ZEND_VM_INC_OPCODE();
- ZEND_VM_NEXT_OPCODE();
} else {
- /* !iter happens from exception */
- if (iter && ++iter->index > 0) {
+ if (++iter->index > 0) {
/* This could cause an endless loop if index becomes zero again.
* In case that ever happens we need an additional flag. */
iter->funcs->move_forward(iter);
zval_ptr_dtor(array);
HANDLE_EXCEPTION();
}
- }
- /* If index is zero we come from FE_RESET and checked valid() already. */
- if (!iter || (iter->index > 0 && iter->funcs->valid(iter) == FAILURE)) {
- /* reached end of iteration */
- if (UNEXPECTED(EG(exception) != NULL)) {
- zval_ptr_dtor(array);
- HANDLE_EXCEPTION();
+ if (UNEXPECTED(iter->funcs->valid(iter) == FAILURE)) {
+ /* reached end of iteration */
+ if (UNEXPECTED(EG(exception) != NULL)) {
+ zval_ptr_dtor(array);
+ HANDLE_EXCEPTION();
+ }
+ ZEND_VM_C_GOTO(fe_fetch_w_exit);
}
- ZEND_VM_JMP(OP_JMP_ADDR(opline, opline->op2));
}
value = iter->funcs->get_current_data(iter);
if (UNEXPECTED(EG(exception) != NULL)) {
}
if (!value) {
/* failure in get_current_data */
- ZEND_VM_JMP(OP_JMP_ADDR(opline, opline->op2));
+ ZEND_VM_C_GOTO(fe_fetch_w_exit);
}
- if (opline->extended_value) {
+ if (opline->result_type == IS_TMP_VAR) {
if (iter->funcs->get_current_key) {
- iter->funcs->get_current_key(iter, EX_VAR((opline+1)->result.var));
+ iter->funcs->get_current_key(iter, EX_VAR(opline->result.var));
if (UNEXPECTED(EG(exception) != NULL)) {
zval_ptr_dtor(array);
HANDLE_EXCEPTION();
}
} else {
- ZVAL_LONG(EX_VAR((opline+1)->result.var), iter->index);
+ ZVAL_LONG(EX_VAR(opline->result.var), iter->index);
}
}
- ZVAL_MAKE_REF(value);
- Z_ADDREF_P(value);
- ZVAL_REF(EX_VAR(opline->result.var), Z_REF_P(value));
- ZEND_VM_INC_OPCODE();
- ZEND_VM_NEXT_OPCODE();
+ value_type = Z_TYPE_INFO_P(value);
}
} else {
zend_error(E_WARNING, "Invalid argument supplied for foreach()");
- ZEND_VM_JMP(OP_JMP_ADDR(opline, opline->op2));
+ZEND_VM_C_LABEL(fe_fetch_w_exit):
+ if (EXPECTED(!EG(exception))) {
+ ZEND_VM_SET_RELATIVE_OPCODE(opline, opline->extended_value);
+ }
+ ZEND_VM_CONTINUE();
+ }
+
+ if (EXPECTED((value_type & Z_TYPE_MASK) != IS_REFERENCE)) {
+ zend_refcounted *gc = Z_COUNTED_P(value);
+ zval *ref;
+ ZVAL_NEW_EMPTY_REF(value);
+ ref = Z_REFVAL_P(value);
+ ZVAL_COPY_VALUE_EX(ref, value, gc, value_type);
}
+ if (EXPECTED(OP2_TYPE == IS_CV)) {
+ zval *variable_ptr = _get_zval_ptr_cv_undef_BP_VAR_W(execute_data, opline->op2.var);
+ if (EXPECTED(variable_ptr != value)) {
+ zend_reference *ref;
+
+ ref = Z_REF_P(value);
+ GC_REFCOUNT(ref)++;
+ zval_ptr_dtor(variable_ptr);
+ ZVAL_REF(variable_ptr, ref);
+ }
+ } else {
+ Z_ADDREF_P(value);
+ ZVAL_REF(EX_VAR(opline->op2.var), Z_REF_P(value));
+ }
+ ZEND_VM_NEXT_OPCODE();
}
ZEND_VM_HANDLER(114, ZEND_ISSET_ISEMPTY_VAR, CONST|TMPVAR|CV, UNUSED|CONST|VAR)
variable_ptr = GET_OP1_ZVAL_PTR_PTR_UNDEF(BP_VAR_W);
- if (UNEXPECTED(!Z_ISREF_P(value))) {
- ZVAL_NEW_REF(value, value);
- }
- if (EXPECTED(variable_ptr != value)) {
+ do {
zend_reference *ref;
+ if (UNEXPECTED(!Z_ISREF_P(value))) {
+ ZVAL_NEW_REF(value, value);
+ } else if (UNEXPECTED(variable_ptr == value)) {
+ break;
+ }
ref = Z_REF_P(value);
GC_REFCOUNT(ref)++;
if (UNEXPECTED(Z_REFCOUNTED_P(variable_ptr))) {
}
}
ZVAL_REF(variable_ptr, ref);
- }
+ } while (0);
ZEND_VM_REPEAT_OPCODE(ZEND_BIND_GLOBAL);
ZEND_VM_NEXT_OPCODE();
USE_OPLINE
zval *array;
zval *value;
+ uint32_t value_type;
HashTable *fe_ht;
HashPosition pos;
Bucket *p;
SAVE_OPLINE();
if (EXPECTED(Z_TYPE_P(array) == IS_ARRAY)) {
fe_ht = Z_ARRVAL_P(array);
- pos = Z_FE_POS_P(EX_VAR(opline->op1.var));
+ pos = Z_FE_POS_P(array);
p = fe_ht->arData + pos;
while (1) {
if (UNEXPECTED(pos >= fe_ht->nNumUsed)) {
/* reached end of iteration */
- ZEND_VM_JMP(OP_JMP_ADDR(opline, opline->op2));
+ goto fe_fetch_r_exit;
}
value = &p->val;
- if (Z_TYPE_INFO_P(value) == IS_UNDEF) {
+ value_type = Z_TYPE_INFO_P(value);
+ if (value_type == IS_UNDEF) {
pos++;
p++;
continue;
- } else if (UNEXPECTED(Z_TYPE_INFO_P(value) == IS_INDIRECT)) {
+ } else if (UNEXPECTED(value_type == IS_INDIRECT)) {
value = Z_INDIRECT_P(value);
- if (UNEXPECTED(Z_TYPE_INFO_P(value) == IS_UNDEF)) {
+ value_type = Z_TYPE_INFO_P(value);
+ if (UNEXPECTED(value_type == IS_UNDEF)) {
pos++;
p++;
continue;
}
break;
}
- ZVAL_COPY(EX_VAR(opline->result.var), value);
- Z_FE_POS_P(EX_VAR(opline->op1.var)) = pos + 1;
- if (opline->extended_value) {
+ Z_FE_POS_P(array) = pos + 1;
+ if (opline->result_type == IS_TMP_VAR) {
if (!p->key) {
- ZVAL_LONG(EX_VAR((opline+1)->result.var), p->h);
+ ZVAL_LONG(EX_VAR(opline->result.var), p->h);
} else {
- ZVAL_STR_COPY(EX_VAR((opline+1)->result.var), p->key);
+ ZVAL_STR_COPY(EX_VAR(opline->result.var), p->key);
}
}
- ZEND_VM_INC_OPCODE();
- ZEND_VM_NEXT_OPCODE();
} else if (EXPECTED(Z_TYPE_P(array) == IS_OBJECT)) {
zend_object_iterator *iter;
/* plain object */
fe_ht = Z_OBJPROP_P(array);
- pos = zend_hash_iterator_pos(Z_FE_ITER_P(EX_VAR(opline->op1.var)), fe_ht);
+ pos = zend_hash_iterator_pos(Z_FE_ITER_P(array), fe_ht);
p = fe_ht->arData + pos;
while (1) {
if (UNEXPECTED(pos >= fe_ht->nNumUsed)) {
/* reached end of iteration */
- ZEND_VM_JMP(OP_JMP_ADDR(opline, opline->op2));
+ goto fe_fetch_r_exit;
}
value = &p->val;
- if (UNEXPECTED(Z_TYPE_INFO_P(value) == IS_UNDEF)) {
+ value_type = Z_TYPE_INFO_P(value);
+ if (UNEXPECTED(value_type == IS_UNDEF)) {
pos++;
p++;
continue;
- } else if (UNEXPECTED(Z_TYPE_INFO_P(value) == IS_INDIRECT)) {
+ } else if (UNEXPECTED(value_type == IS_INDIRECT)) {
value = Z_INDIRECT_P(value);
- if (UNEXPECTED(Z_TYPE_INFO_P(value) == IS_UNDEF)) {
+ value_type = Z_TYPE_INFO_P(value);
+ if (UNEXPECTED(value_type == IS_UNDEF)) {
pos++;
p++;
continue;
pos++;
p++;
}
- ZVAL_COPY(EX_VAR(opline->result.var), value);
- if (opline->extended_value) {
+ if (opline->result_type == IS_TMP_VAR) {
if (UNEXPECTED(!p->key)) {
- ZVAL_LONG(EX_VAR((opline+1)->result.var), p->h);
+ ZVAL_LONG(EX_VAR(opline->result.var), p->h);
} else if (p->key->val[0]) {
- ZVAL_STR_COPY(EX_VAR((opline+1)->result.var), p->key);
+ ZVAL_STR_COPY(EX_VAR(opline->result.var), p->key);
} else {
const char *class_name, *prop_name;
size_t prop_name_len;
zend_unmangle_property_name_ex(
p->key, &class_name, &prop_name, &prop_name_len);
- ZVAL_STRINGL(EX_VAR((opline+1)->result.var), prop_name, prop_name_len);
+ ZVAL_STRINGL(EX_VAR(opline->result.var), prop_name, prop_name_len);
}
}
while (1) {
break;
}
}
- EG(ht_iterators)[Z_FE_ITER_P(EX_VAR(opline->op1.var))].pos = pos;
- ZEND_VM_INC_OPCODE();
- ZEND_VM_NEXT_OPCODE();
+ EG(ht_iterators)[Z_FE_ITER_P(array)].pos = pos;
} else {
- /* !iter happens from exception */
- if (iter && ++iter->index > 0) {
+ if (EXPECTED(++iter->index > 0)) {
/* This could cause an endless loop if index becomes zero again.
* In case that ever happens we need an additional flag. */
iter->funcs->move_forward(iter);
zval_ptr_dtor(array);
HANDLE_EXCEPTION();
}
- }
- /* If index is zero we come from FE_RESET and checked valid() already. */
- if (!iter || (iter->index > 0 && iter->funcs->valid(iter) == FAILURE)) {
- /* reached end of iteration */
- if (UNEXPECTED(EG(exception) != NULL)) {
- zval_ptr_dtor(array);
- HANDLE_EXCEPTION();
+ if (UNEXPECTED(iter->funcs->valid(iter) == FAILURE)) {
+ /* reached end of iteration */
+ if (UNEXPECTED(EG(exception) != NULL)) {
+ zval_ptr_dtor(array);
+ HANDLE_EXCEPTION();
+ }
+ goto fe_fetch_r_exit;
}
- ZEND_VM_JMP(OP_JMP_ADDR(opline, opline->op2));
}
value = iter->funcs->get_current_data(iter);
if (UNEXPECTED(EG(exception) != NULL)) {
}
if (!value) {
/* failure in get_current_data */
- ZEND_VM_JMP(OP_JMP_ADDR(opline, opline->op2));
+ goto fe_fetch_r_exit;
}
- ZVAL_COPY(EX_VAR(opline->result.var), value);
- if (opline->extended_value) {
+ if (opline->result_type == IS_TMP_VAR) {
if (iter->funcs->get_current_key) {
- iter->funcs->get_current_key(iter, EX_VAR((opline+1)->result.var));
+ iter->funcs->get_current_key(iter, EX_VAR(opline->result.var));
if (UNEXPECTED(EG(exception) != NULL)) {
zval_ptr_dtor(array);
HANDLE_EXCEPTION();
}
} else {
- ZVAL_LONG(EX_VAR((opline+1)->result.var), iter->index);
+ ZVAL_LONG(EX_VAR(opline->result.var), iter->index);
}
}
- ZEND_VM_INC_OPCODE();
- ZEND_VM_NEXT_OPCODE();
+ value_type = Z_TYPE_INFO_P(value);
}
} else {
zend_error(E_WARNING, "Invalid argument supplied for foreach()");
- ZEND_VM_JMP(OP_JMP_ADDR(opline, opline->op2));
+fe_fetch_r_exit:
+ if (EXPECTED(!EG(exception))) {
+ ZEND_VM_SET_RELATIVE_OPCODE(opline, opline->extended_value);
+ }
+ ZEND_VM_CONTINUE();
}
+
+ if (EXPECTED(opline->op2_type == IS_CV)) {
+ zval *variable_ptr = _get_zval_ptr_cv_undef_BP_VAR_W(execute_data, opline->op2.var);
+ zend_assign_to_variable(variable_ptr, value, IS_CV);
+ } else {
+ zval *res = EX_VAR(opline->op2.var);
+ zend_refcounted *gc = Z_COUNTED_P(value);
+
+ ZVAL_COPY_VALUE_EX(res, value, gc, value_type);
+ if (EXPECTED((value_type & (IS_TYPE_REFCOUNTED << Z_TYPE_FLAGS_SHIFT)) != 0)) {
+ GC_REFCOUNT(gc)++;
+ }
+ }
+ ZEND_VM_NEXT_OPCODE();
}
static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FE_FETCH_RW_SPEC_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
USE_OPLINE
zval *array;
zval *value;
+ uint32_t value_type;
HashTable *fe_ht;
HashPosition pos;
Bucket *p;
while (1) {
if (UNEXPECTED(pos >= fe_ht->nNumUsed)) {
/* reached end of iteration */
- ZEND_VM_JMP(OP_JMP_ADDR(opline, opline->op2));
+ goto fe_fetch_w_exit;
}
value = &p->val;
- if (UNEXPECTED(Z_TYPE_P(value) == IS_UNDEF)) {
+ value_type = Z_TYPE_INFO_P(value);
+ if (UNEXPECTED(value_type == IS_UNDEF)) {
pos++;
p++;
continue;
- } else if (UNEXPECTED(Z_TYPE_P(value) == IS_INDIRECT)) {
+ } else if (UNEXPECTED(value_type == IS_INDIRECT)) {
value = Z_INDIRECT_P(value);
- if (UNEXPECTED(Z_TYPE_P(value) == IS_UNDEF)) {
+ value_type = Z_TYPE_INFO_P(value);
+ if (UNEXPECTED(value_type == IS_UNDEF)) {
pos++;
p++;
continue;
}
break;
}
- ZVAL_MAKE_REF(value);
- Z_ADDREF_P(value);
- ZVAL_REF(EX_VAR(opline->result.var), Z_REF_P(value));
- if (opline->extended_value) {
+ if (opline->result_type == IS_TMP_VAR) {
if (!p->key) {
- ZVAL_LONG(EX_VAR((opline+1)->result.var), p->h);
+ ZVAL_LONG(EX_VAR(opline->result.var), p->h);
} else {
- ZVAL_STR_COPY(EX_VAR((opline+1)->result.var), p->key);
+ ZVAL_STR_COPY(EX_VAR(opline->result.var), p->key);
}
}
while (1) {
}
}
EG(ht_iterators)[Z_FE_ITER_P(EX_VAR(opline->op1.var))].pos = pos;
- ZEND_VM_INC_OPCODE();
- ZEND_VM_NEXT_OPCODE();
} else if (EXPECTED(Z_TYPE_P(array) == IS_OBJECT)) {
zend_object_iterator *iter;
while (1) {
if (UNEXPECTED(pos >= fe_ht->nNumUsed)) {
/* reached end of iteration */
- ZEND_VM_JMP(OP_JMP_ADDR(opline, opline->op2));
+ goto fe_fetch_w_exit;
}
value = &p->val;
- if (UNEXPECTED(Z_TYPE_P(value) == IS_UNDEF)) {
+ value_type = Z_TYPE_INFO_P(value);
+ if (UNEXPECTED(value_type == IS_UNDEF)) {
pos++;
p++;
continue;
- } else if (UNEXPECTED(Z_TYPE_P(value) == IS_INDIRECT)) {
+ } else if (UNEXPECTED(value_type == IS_INDIRECT)) {
value = Z_INDIRECT_P(value);
- if (UNEXPECTED(Z_TYPE_P(value) == IS_UNDEF)) {
+ value_type = Z_TYPE_INFO_P(value);
+ if (UNEXPECTED(value_type == IS_UNDEF)) {
pos++;
p++;
continue;
pos++;
p++;
}
- ZVAL_MAKE_REF(value);
- Z_ADDREF_P(value);
- ZVAL_REF(EX_VAR(opline->result.var), Z_REF_P(value));
- if (opline->extended_value) {
+ if (opline->result_type == IS_TMP_VAR) {
if (UNEXPECTED(!p->key)) {
- ZVAL_LONG(EX_VAR((opline+1)->result.var), p->h);
+ ZVAL_LONG(EX_VAR(opline->result.var), p->h);
} else if (p->key->val[0]) {
- ZVAL_STR_COPY(EX_VAR((opline+1)->result.var), p->key);
+ ZVAL_STR_COPY(EX_VAR(opline->result.var), p->key);
} else {
const char *class_name, *prop_name;
size_t prop_name_len;
zend_unmangle_property_name_ex(
p->key, &class_name, &prop_name, &prop_name_len);
- ZVAL_STRINGL(EX_VAR((opline+1)->result.var), prop_name, prop_name_len);
+ ZVAL_STRINGL(EX_VAR(opline->result.var), prop_name, prop_name_len);
}
}
while (1) {
}
}
EG(ht_iterators)[Z_FE_ITER_P(EX_VAR(opline->op1.var))].pos = pos;
- ZEND_VM_INC_OPCODE();
- ZEND_VM_NEXT_OPCODE();
} else {
- /* !iter happens from exception */
- if (iter && ++iter->index > 0) {
+ if (++iter->index > 0) {
/* This could cause an endless loop if index becomes zero again.
* In case that ever happens we need an additional flag. */
iter->funcs->move_forward(iter);
zval_ptr_dtor(array);
HANDLE_EXCEPTION();
}
- }
- /* If index is zero we come from FE_RESET and checked valid() already. */
- if (!iter || (iter->index > 0 && iter->funcs->valid(iter) == FAILURE)) {
- /* reached end of iteration */
- if (UNEXPECTED(EG(exception) != NULL)) {
- zval_ptr_dtor(array);
- HANDLE_EXCEPTION();
+ if (UNEXPECTED(iter->funcs->valid(iter) == FAILURE)) {
+ /* reached end of iteration */
+ if (UNEXPECTED(EG(exception) != NULL)) {
+ zval_ptr_dtor(array);
+ HANDLE_EXCEPTION();
+ }
+ goto fe_fetch_w_exit;
}
- ZEND_VM_JMP(OP_JMP_ADDR(opline, opline->op2));
}
value = iter->funcs->get_current_data(iter);
if (UNEXPECTED(EG(exception) != NULL)) {
}
if (!value) {
/* failure in get_current_data */
- ZEND_VM_JMP(OP_JMP_ADDR(opline, opline->op2));
+ goto fe_fetch_w_exit;
}
- if (opline->extended_value) {
+ if (opline->result_type == IS_TMP_VAR) {
if (iter->funcs->get_current_key) {
- iter->funcs->get_current_key(iter, EX_VAR((opline+1)->result.var));
+ iter->funcs->get_current_key(iter, EX_VAR(opline->result.var));
if (UNEXPECTED(EG(exception) != NULL)) {
zval_ptr_dtor(array);
HANDLE_EXCEPTION();
}
} else {
- ZVAL_LONG(EX_VAR((opline+1)->result.var), iter->index);
+ ZVAL_LONG(EX_VAR(opline->result.var), iter->index);
}
}
- ZVAL_MAKE_REF(value);
- Z_ADDREF_P(value);
- ZVAL_REF(EX_VAR(opline->result.var), Z_REF_P(value));
- ZEND_VM_INC_OPCODE();
- ZEND_VM_NEXT_OPCODE();
+ value_type = Z_TYPE_INFO_P(value);
}
} else {
zend_error(E_WARNING, "Invalid argument supplied for foreach()");
- ZEND_VM_JMP(OP_JMP_ADDR(opline, opline->op2));
+fe_fetch_w_exit:
+ if (EXPECTED(!EG(exception))) {
+ ZEND_VM_SET_RELATIVE_OPCODE(opline, opline->extended_value);
+ }
+ ZEND_VM_CONTINUE();
+ }
+
+ if (EXPECTED((value_type & Z_TYPE_MASK) != IS_REFERENCE)) {
+ zend_refcounted *gc = Z_COUNTED_P(value);
+ zval *ref;
+ ZVAL_NEW_EMPTY_REF(value);
+ ref = Z_REFVAL_P(value);
+ ZVAL_COPY_VALUE_EX(ref, value, gc, value_type);
}
+ if (EXPECTED(opline->op2_type == IS_CV)) {
+ zval *variable_ptr = _get_zval_ptr_cv_undef_BP_VAR_W(execute_data, opline->op2.var);
+ if (EXPECTED(variable_ptr != value)) {
+ zend_reference *ref;
+
+ ref = Z_REF_P(value);
+ GC_REFCOUNT(ref)++;
+ zval_ptr_dtor(variable_ptr);
+ ZVAL_REF(variable_ptr, ref);
+ }
+ } else {
+ Z_ADDREF_P(value);
+ ZVAL_REF(EX_VAR(opline->op2.var), Z_REF_P(value));
+ }
+ ZEND_VM_NEXT_OPCODE();
}
static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_JMP_SET_SPEC_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
variable_ptr = _get_zval_ptr_cv_undef_BP_VAR_W(execute_data, opline->op1.var);
- if (UNEXPECTED(!Z_ISREF_P(value))) {
- ZVAL_NEW_REF(value, value);
- }
- if (EXPECTED(variable_ptr != value)) {
+ do {
zend_reference *ref;
+ if (UNEXPECTED(!Z_ISREF_P(value))) {
+ ZVAL_NEW_REF(value, value);
+ } else if (UNEXPECTED(variable_ptr == value)) {
+ break;
+ }
ref = Z_REF_P(value);
GC_REFCOUNT(ref)++;
if (UNEXPECTED(Z_REFCOUNTED_P(variable_ptr))) {
}
}
ZVAL_REF(variable_ptr, ref);
- }
+ } while (0);
ZEND_VM_REPEAT_OPCODE(ZEND_BIND_GLOBAL);
ZEND_VM_NEXT_OPCODE();
break;
case ZEND_FE_FETCH_R:
case ZEND_FE_FETCH_RW:
- START_BLOCK_OP(ZEND_OP2(opline).opline_num);
- START_BLOCK_OP(opno + 2);
+ START_BLOCK_OP(opline->extended_value);
+ START_BLOCK_OP(opno + 1);
break;
}
opno++;
cur_block->ext_to = &blocks[opline->extended_value];
cur_block->follow_to = &blocks[opno];
break;
+ case ZEND_FE_FETCH_R:
+ case ZEND_FE_FETCH_RW:
+ cur_block->ext_to = &blocks[opline->extended_value];
+ cur_block->follow_to = &blocks[opno];
+ break;
case ZEND_JMPZ:
case ZEND_JMPNZ:
case ZEND_JMPZ_EX:
case ZEND_NEW:
case ZEND_JMP_SET:
case ZEND_COALESCE:
- case ZEND_FE_FETCH_R:
- case ZEND_FE_FETCH_RW:
case ZEND_ASSERT_CHECK:
cur_block->op2_to = &blocks[ZEND_OP2(opline).opline_num];
/* break missing intentionally */
while (opline<end) {
T_USAGE(opline->op1);
- T_USAGE(opline->op2);
+ if (opline->op2_type & (IS_VAR | IS_TMP_VAR)) {
+ if (opline->opcode == ZEND_FE_FETCH_R || opline->opcode == ZEND_FE_FETCH_RW) {
+ /* these opcode use the op2 as result */
+ defined_here[VAR_NUM(ZEND_OP2(opline).var)] = 1;
+ } else {
+ T_USAGE(opline->op2);
+ }
+ }
if (RESULT_USED(opline)) {
if (!defined_here[VAR_NUM(ZEND_RESULT(opline).var)] && !used_ext[VAR_NUM(ZEND_RESULT(opline).var)] &&
case ZEND_JMPNZ:
case ZEND_JMPZ_EX:
case ZEND_JMPNZ_EX:
- case ZEND_FE_FETCH_R:
- case ZEND_FE_FETCH_RW:
case ZEND_FE_RESET_R:
case ZEND_FE_RESET_RW:
case ZEND_NEW:
case ZEND_ASSERT_CHECK:
ZEND_OP2(opline).opline_num -= shiftlist[ZEND_OP2(opline).opline_num];
break;
+ case ZEND_FE_FETCH_R:
+ case ZEND_FE_FETCH_RW:
+ opline->extended_value -= shiftlist[opline->extended_value];
+ break;
case ZEND_JMPZNZ:
ZEND_OP2(opline).opline_num -= shiftlist[ZEND_OP2(opline).opline_num];
opline->extended_value -= shiftlist[opline->extended_value];
case ZEND_NEW:
case ZEND_FE_RESET_R:
case ZEND_FE_RESET_RW:
- case ZEND_FE_FETCH_R:
- case ZEND_FE_FETCH_RW:
case ZEND_ASSERT_CHECK:
ZEND_PASS_TWO_UNDO_JMP_TARGET(op_array, opline, ZEND_OP2(opline));
break;
+ case ZEND_FE_FETCH_R:
+ case ZEND_FE_FETCH_RW:
+ opline->extended_value = ZEND_OFFSET_TO_OPLINE_NUM(op_array, opline, opline->extended_value);
+ break;
}
opline++;
}
case ZEND_NEW:
case ZEND_FE_RESET_R:
case ZEND_FE_RESET_RW:
- case ZEND_FE_FETCH_R:
- case ZEND_FE_FETCH_RW:
case ZEND_ASSERT_CHECK:
ZEND_PASS_TWO_UPDATE_JMP_TARGET(op_array, opline, ZEND_OP2(opline));
break;
+ case ZEND_FE_FETCH_R:
+ case ZEND_FE_FETCH_RW:
+ opline->extended_value = ZEND_OPLINE_NUM_TO_OFFSET(op_array, opline, opline->extended_value);
+ break;
}
ZEND_VM_SET_OPCODE_HANDLER(opline);
opline++;
case ZEND_NEW:
case ZEND_FE_RESET_R:
case ZEND_FE_RESET_RW:
- case ZEND_FE_FETCH_R:
- case ZEND_FE_FETCH_RW:
case ZEND_ASSERT_CHECK:
SERIALIZE_PTR(opline->op2.jmp_addr);
break;
+ case ZEND_FE_FETCH_R:
+ case ZEND_FE_FETCH_RW:
+ /* relative extended_value don't have to be changed */
+ break;
}
# endif
opline++;
case ZEND_NEW:
case ZEND_FE_RESET_R:
case ZEND_FE_RESET_RW:
- case ZEND_FE_FETCH_R:
- case ZEND_FE_FETCH_RW:
case ZEND_ASSERT_CHECK:
UNSERIALIZE_PTR(opline->op2.jmp_addr);
break;
+ case ZEND_FE_FETCH_R:
+ case ZEND_FE_FETCH_RW:
+ /* relative extended_value don't have to be changed */
+ break;
}
# endif
ZEND_VM_SET_OPCODE_HANDLER(opline);
case ZEND_NEW:
case ZEND_FE_RESET_R:
case ZEND_FE_RESET_RW:
- case ZEND_FE_FETCH_R:
- case ZEND_FE_FETCH_RW:
case ZEND_ASSERT_CHECK:
ZEND_OP2(opline).jmp_addr = &new_opcodes[ZEND_OP2(opline).jmp_addr - op_array->opcodes];
break;
+ case ZEND_FE_FETCH_R:
+ case ZEND_FE_FETCH_RW:
+ /* relative extended_value don't have to be changed */
+ break;
}
}
# endif