}
/* }}} */
-void zend_compile_encaps_list(znode *result, zend_ast *ast) /* {{{ */
+static zend_op *zend_compile_rope_add(znode *result, uint32_t num, znode *elem_node) /* {{{ */
{
- zend_ast_list *list = zend_ast_get_list(ast);
- uint32_t i;
+ zend_op *opline = get_next_op(CG(active_op_array));
- ZEND_ASSERT(list->children > 0);
+ if (num == 0) {
+ result->op_type = IS_TMP_VAR;
+ result->u.op.var = -1;
+ opline->opcode = ZEND_ROPE_INIT;
+ SET_UNUSED(opline->op1);
+ } else {
+ opline->opcode = ZEND_ROPE_ADD;
+ SET_NODE(opline->op1, result);
+ }
+ SET_NODE(opline->op2, elem_node);
+ SET_NODE(opline->result, result);
+ opline->extended_value = num;
+ return opline;
+}
+/* }}} */
- result->op_type = IS_TMP_VAR;
- result->u.op.var = get_temporary_variable(CG(active_op_array));
+static void zend_compile_encaps_list(znode *result, zend_ast *ast) /* {{{ */
+{
+ uint32_t i, j;
+ uint32_t rope_init_lineno = -1;
+ zend_op *opline = NULL, *init_opline;
+ znode elem_node, last_const_node;
+ zend_ast_list *list = zend_ast_get_list(ast);
- for (i = 0; i < list->children; ++i) {
- zend_ast *elem_ast = list->child[i];
- znode elem_node;
- zend_op *opline;
+ ZEND_ASSERT(list->children > 0);
- zend_compile_expr(&elem_node, elem_ast);
+ j = 0;
+ last_const_node.op_type = IS_UNUSED;
+ for (i = 0; i < list->children; i++) {
+ zend_compile_expr(&elem_node, list->child[i]);
- if (elem_ast->kind == ZEND_AST_ZVAL) {
- zval *zv = &elem_node.u.constant;
- ZEND_ASSERT(Z_TYPE_P(zv) == IS_STRING);
+ if (elem_node.op_type == IS_CONST) {
+ convert_to_string(&elem_node.u.constant);
- if (Z_STRLEN_P(zv) > 1) {
- opline = get_next_op(CG(active_op_array));
- opline->opcode = ZEND_ADD_STRING;
- } else if (Z_STRLEN_P(zv) == 1) {
- char ch = *Z_STRVAL_P(zv);
- zend_string_release(Z_STR_P(zv));
- ZVAL_LONG(zv, ch);
-
- opline = get_next_op(CG(active_op_array));
- opline->opcode = ZEND_ADD_CHAR;
+ if (Z_STRLEN(elem_node.u.constant) == 0) {
+ zval_ptr_dtor(&elem_node.u.constant);
+ } else if (last_const_node.op_type == IS_CONST) {
+ concat_function(&last_const_node.u.constant, &last_const_node.u.constant, &elem_node.u.constant);
+ zval_ptr_dtor(&elem_node.u.constant);
} else {
- /* String can be empty after a variable at the end of a heredoc */
- zend_string_release(Z_STR_P(zv));
- continue;
+ last_const_node.op_type = IS_CONST;
+ ZVAL_COPY_VALUE(&last_const_node.u.constant, &elem_node.u.constant);
}
+ continue;
} else {
- opline = get_next_op(CG(active_op_array));
- opline->opcode = ZEND_ADD_VAR;
- ZEND_ASSERT(elem_node.op_type != IS_CONST);
+ if (j == 0) {
+ rope_init_lineno = get_next_op_number(CG(active_op_array));
+ }
+ if (last_const_node.op_type == IS_CONST) {
+ zend_compile_rope_add(result, j++, &last_const_node);
+ last_const_node.op_type = IS_UNUSED;
+ }
+ opline = zend_compile_rope_add(result, j++, &elem_node);
}
+ }
- if (i == 0) {
- SET_UNUSED(opline->op1);
+ if (j == 0) {
+ result->op_type = IS_CONST;
+ if (last_const_node.op_type == IS_CONST) {
+ ZVAL_COPY_VALUE(&result->u.constant, &last_const_node.u.constant);
+ } else {
+ ZVAL_EMPTY_STRING(&result->u.constant);
+ /* empty string */
+ }
+ return;
+ } else if (last_const_node.op_type == IS_CONST) {
+ opline = zend_compile_rope_add(result, j++, &last_const_node);
+ }
+ init_opline = CG(active_op_array)->opcodes + rope_init_lineno;
+ if (j == 1) {
+ if (opline->op2_type == IS_CONST) {
+ GET_NODE(result, opline->op2);
+ MAKE_NOP(opline);
} else {
- SET_NODE(opline->op1, result);
+ opline->opcode = ZEND_CAST;
+ opline->extended_value = IS_STRING;
+ opline->op1_type = opline->op2_type;
+ opline->op1 = opline->op2;
+ opline->result_type = IS_TMP_VAR;
+ opline->result.var = get_temporary_variable(CG(active_op_array));
+ SET_UNUSED(opline->op2);
+ GET_NODE(result, opline->result);
+ }
+ } else if (j == 2) {
+ opline->opcode = ZEND_FAST_CONCAT;
+ opline->extended_value = 0;
+ opline->op1_type = init_opline->op2_type;
+ opline->op1 = init_opline->op2;
+ opline->result_type = IS_TMP_VAR;
+ opline->result.var = get_temporary_variable(CG(active_op_array));
+ MAKE_NOP(init_opline);
+ GET_NODE(result, opline->result);
+ } else {
+ uint32_t var;
+
+ init_opline->extended_value = j;
+ opline->opcode = ZEND_ROPE_END;
+ opline->result.var = get_temporary_variable(CG(active_op_array));
+ var = opline->op1.var = get_temporary_variable(CG(active_op_array));
+ GET_NODE(result, opline->result);
+
+ /* Allocates the necessary number of zval slots to keep the rope */
+ i = ((j * sizeof(zend_string*)) + (sizeof(zval) - 1)) / sizeof(zval);
+ while (i > 1) {
+ get_temporary_variable(CG(active_op_array));
+ i--;
+ }
+ /* Update all the previous opcodes to use the same variable */
+ while (opline != init_opline) {
+ opline--;
+ if (opline->opcode == ZEND_ROPE_ADD &&
+ opline->result.var == -1) {
+ opline->op1.var = var;
+ opline->result.var = var;
+ } else if (opline->opcode == ZEND_ROPE_INIT &&
+ opline->result.var == -1) {
+ opline->result.var = var;
+ }
}
- SET_NODE(opline->op2, &elem_node);
- SET_NODE(opline->result, result);
}
}
/* }}} */
ZEND_VM_NEXT_OPCODE();
}
+static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FAST_CONCAT_SPEC_CONST_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
+{
+ USE_OPLINE
+
+ zval *op1, *op2;
+ zend_string *op1_str, *op2_str, *str;
+
+ SAVE_OPLINE();
+ op1 = EX_CONSTANT(opline->op1);
+ op2 = EX_CONSTANT(opline->op2);
+ if (IS_CONST == IS_CONST) {
+ op1_str = Z_STR_P(op1);
+ } else {
+ op1_str = zval_get_string(op1);
+ }
+ if (IS_CONST == IS_CONST) {
+ op2_str = Z_STR_P(op2);
+ } else {
+ op2_str = zval_get_string(op2);
+ }
+ str = zend_string_alloc(op1_str->len + op2_str->len, 0);
+ memcpy(str->val, op1_str->val, op1_str->len);
+ memcpy(str->val + op1_str->len, op2_str->val, op2_str->len+1);
+ ZVAL_NEW_STR(EX_VAR(opline->result.var), str);
+ if (IS_CONST != IS_CONST) {
+ zend_string_release(op1_str);
+ }
+ if (IS_CONST != IS_CONST) {
+ zend_string_release(op2_str);
+ }
+
+
+ CHECK_EXCEPTION();
+ ZEND_VM_NEXT_OPCODE();
+}
+
static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_CONST_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
{
USE_OPLINE
}
}
+static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FAST_CONCAT_SPEC_CONST_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
+{
+ USE_OPLINE
+
+ zval *op1, *op2;
+ zend_string *op1_str, *op2_str, *str;
+
+ SAVE_OPLINE();
+ op1 = EX_CONSTANT(opline->op1);
+ op2 = _get_zval_ptr_cv_BP_VAR_R(execute_data, opline->op2.var);
+ if (IS_CONST == IS_CONST) {
+ op1_str = Z_STR_P(op1);
+ } else {
+ op1_str = zval_get_string(op1);
+ }
+ if (IS_CV == IS_CONST) {
+ op2_str = Z_STR_P(op2);
+ } else {
+ op2_str = zval_get_string(op2);
+ }
+ str = zend_string_alloc(op1_str->len + op2_str->len, 0);
+ memcpy(str->val, op1_str->val, op1_str->len);
+ memcpy(str->val + op1_str->len, op2_str->val, op2_str->len+1);
+ ZVAL_NEW_STR(EX_VAR(opline->result.var), str);
+ if (IS_CONST != IS_CONST) {
+ zend_string_release(op1_str);
+ }
+ if (IS_CV != IS_CONST) {
+ zend_string_release(op2_str);
+ }
+
+
+ CHECK_EXCEPTION();
+ ZEND_VM_NEXT_OPCODE();
+}
+
static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_CONST_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
{
USE_OPLINE
}
}
+static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FAST_CONCAT_SPEC_CONST_TMPVAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
+{
+ USE_OPLINE
+ zend_free_op free_op2;
+ zval *op1, *op2;
+ zend_string *op1_str, *op2_str, *str;
+
+ SAVE_OPLINE();
+ op1 = EX_CONSTANT(opline->op1);
+ op2 = _get_zval_ptr_var(opline->op2.var, execute_data, &free_op2);
+ if (IS_CONST == IS_CONST) {
+ op1_str = Z_STR_P(op1);
+ } else {
+ op1_str = zval_get_string(op1);
+ }
+ if ((IS_TMP_VAR|IS_VAR) == IS_CONST) {
+ op2_str = Z_STR_P(op2);
+ } else {
+ op2_str = zval_get_string(op2);
+ }
+ str = zend_string_alloc(op1_str->len + op2_str->len, 0);
+ memcpy(str->val, op1_str->val, op1_str->len);
+ memcpy(str->val + op1_str->len, op2_str->val, op2_str->len+1);
+ ZVAL_NEW_STR(EX_VAR(opline->result.var), str);
+ if (IS_CONST != IS_CONST) {
+ zend_string_release(op1_str);
+ }
+ if ((IS_TMP_VAR|IS_VAR) != IS_CONST) {
+ zend_string_release(op2_str);
+ }
+
+ zval_ptr_dtor_nogc(free_op2);
+ CHECK_EXCEPTION();
+ ZEND_VM_NEXT_OPCODE();
+}
+
static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_CONST_TMPVAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
{
USE_OPLINE
}
}
-static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ADD_CHAR_SPEC_TMP_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
+static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ROPE_ADD_SPEC_TMP_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
{
USE_OPLINE
- zval *str = EX_VAR(opline->result.var);
- SAVE_OPLINE();
-
- if (IS_TMP_VAR == IS_UNUSED) {
- /* Initialize for erealloc in add_char_to_string */
- ZVAL_EMPTY_STRING(str);
- }
+ zend_string **rope;
+ zval *var;
- add_char_to_string(str, str, EX_CONSTANT(opline->op2));
+ /* op1 and result are the same */
+ rope = (zend_string**)EX_VAR(opline->op1.var);
+ if (IS_CONST == IS_CONST) {
+ var = EX_CONSTANT(opline->op2);
+ rope[opline->extended_value] = zend_string_copy(Z_STR_P(var));
+ } else {
+ SAVE_OPLINE();
+ var = EX_CONSTANT(opline->op2);
+ rope[opline->extended_value] = zval_get_string(var);
- /* FREE_OP is missing intentionally here - we're always working on the same temporary variable */
- /*CHECK_EXCEPTION();*/
+ CHECK_EXCEPTION();
+ }
ZEND_VM_NEXT_OPCODE();
}
-static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ADD_STRING_SPEC_TMP_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
+static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ROPE_END_SPEC_TMP_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
{
USE_OPLINE
- zval *str = EX_VAR(opline->result.var);
- SAVE_OPLINE();
+ zend_string **rope;
+ zval *var, *ret;
+ uint32_t i;
+ size_t len = 0;
+ char *target;
- if (IS_TMP_VAR == IS_UNUSED) {
- /* Initialize for erealloc in add_string_to_string */
- ZVAL_EMPTY_STRING(str);
- }
+ rope = (zend_string**)EX_VAR(opline->op1.var);
+ if (IS_CONST == IS_CONST) {
+ var = EX_CONSTANT(opline->op2);
+ rope[opline->extended_value] = zend_string_copy(Z_STR_P(var));
+ } else {
+ SAVE_OPLINE();
+ var = EX_CONSTANT(opline->op2);
+ rope[opline->extended_value] = zval_get_string(var);
- add_string_to_string(str, str, EX_CONSTANT(opline->op2));
+ CHECK_EXCEPTION();
+ }
+ for (i = 0; i <= opline->extended_value; i++) {
+ len += rope[i]->len;
+ }
+ ret = EX_VAR(opline->result.var);
+ ZVAL_STR(ret, zend_string_alloc(len, 0));
+ target = Z_STRVAL_P(ret);
+ for (i = 0; i <= opline->extended_value; i++) {
+ memcpy(target, rope[i]->val, rope[i]->len);
+ target += rope[i]->len;
+ zend_string_release(rope[i]);
+ }
+ *target = '\0';
- /* FREE_OP is missing intentionally here - we're always working on the same temporary variable */
- /*CHECK_EXCEPTION();*/
ZEND_VM_NEXT_OPCODE();
}
}
}
-static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ADD_VAR_SPEC_TMP_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
+static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ROPE_ADD_SPEC_TMP_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
{
USE_OPLINE
- zval *str = EX_VAR(opline->result.var);
+ zend_string **rope;
zval *var;
- zval var_copy;
- int use_copy = 0;
- SAVE_OPLINE();
- var = _get_zval_ptr_cv_BP_VAR_R(execute_data, opline->op2.var);
+ /* op1 and result are the same */
+ rope = (zend_string**)EX_VAR(opline->op1.var);
+ if (IS_CV == IS_CONST) {
+ var = _get_zval_ptr_cv_BP_VAR_R(execute_data, opline->op2.var);
+ rope[opline->extended_value] = zend_string_copy(Z_STR_P(var));
+ } else {
+ SAVE_OPLINE();
+ var = _get_zval_ptr_cv_BP_VAR_R(execute_data, opline->op2.var);
+ rope[opline->extended_value] = zval_get_string(var);
- if (IS_TMP_VAR == IS_UNUSED) {
- /* Initialize for erealloc in add_string_to_string */
- ZVAL_EMPTY_STRING(str);
+ CHECK_EXCEPTION();
}
+ ZEND_VM_NEXT_OPCODE();
+}
- if (Z_TYPE_P(var) != IS_STRING) {
- use_copy = zend_make_printable_zval(var, &var_copy);
+static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ROPE_END_SPEC_TMP_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
+{
+ USE_OPLINE
- if (use_copy) {
- var = &var_copy;
- }
- }
- add_string_to_string(str, str, var);
+ zend_string **rope;
+ zval *var, *ret;
+ uint32_t i;
+ size_t len = 0;
+ char *target;
+
+ rope = (zend_string**)EX_VAR(opline->op1.var);
+ if (IS_CV == IS_CONST) {
+ var = _get_zval_ptr_cv_BP_VAR_R(execute_data, opline->op2.var);
+ rope[opline->extended_value] = zend_string_copy(Z_STR_P(var));
+ } else {
+ SAVE_OPLINE();
+ var = _get_zval_ptr_cv_BP_VAR_R(execute_data, opline->op2.var);
+ rope[opline->extended_value] = zval_get_string(var);
- if (use_copy) {
- zend_string_release(Z_STR_P(var));
+ CHECK_EXCEPTION();
+ }
+ for (i = 0; i <= opline->extended_value; i++) {
+ len += rope[i]->len;
+ }
+ ret = EX_VAR(opline->result.var);
+ ZVAL_STR(ret, zend_string_alloc(len, 0));
+ target = Z_STRVAL_P(ret);
+ for (i = 0; i <= opline->extended_value; i++) {
+ memcpy(target, rope[i]->val, rope[i]->len);
+ target += rope[i]->len;
+ zend_string_release(rope[i]);
}
- /* original comment, possibly problematic:
- * FREE_OP is missing intentionally here - we're always working on the same temporary variable
- * (Zeev): I don't think it's problematic, we only use variables
- * which aren't affected by FREE_OP(Ts, )'s anyway, unless they're
- * string offsets or overloaded objects
- */
+ *target = '\0';
- CHECK_EXCEPTION();
ZEND_VM_NEXT_OPCODE();
}
}
}
-static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ADD_VAR_SPEC_TMP_TMPVAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
+static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ROPE_ADD_SPEC_TMP_TMPVAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
{
USE_OPLINE
zend_free_op free_op2;
- zval *str = EX_VAR(opline->result.var);
+ zend_string **rope;
zval *var;
- zval var_copy;
- int use_copy = 0;
- SAVE_OPLINE();
- var = _get_zval_ptr_var(opline->op2.var, execute_data, &free_op2);
-
- if (IS_TMP_VAR == IS_UNUSED) {
- /* Initialize for erealloc in add_string_to_string */
- ZVAL_EMPTY_STRING(str);
+ /* op1 and result are the same */
+ rope = (zend_string**)EX_VAR(opline->op1.var);
+ if ((IS_TMP_VAR|IS_VAR) == IS_CONST) {
+ var = _get_zval_ptr_var(opline->op2.var, execute_data, &free_op2);
+ rope[opline->extended_value] = zend_string_copy(Z_STR_P(var));
+ } else {
+ SAVE_OPLINE();
+ var = _get_zval_ptr_var(opline->op2.var, execute_data, &free_op2);
+ rope[opline->extended_value] = zval_get_string(var);
+ zval_ptr_dtor_nogc(free_op2);
+ CHECK_EXCEPTION();
}
+ ZEND_VM_NEXT_OPCODE();
+}
- if (Z_TYPE_P(var) != IS_STRING) {
- use_copy = zend_make_printable_zval(var, &var_copy);
+static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ROPE_END_SPEC_TMP_TMPVAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
+{
+ USE_OPLINE
+ zend_free_op free_op2;
+ zend_string **rope;
+ zval *var, *ret;
+ uint32_t i;
+ size_t len = 0;
+ char *target;
- if (use_copy) {
- var = &var_copy;
- }
+ rope = (zend_string**)EX_VAR(opline->op1.var);
+ if ((IS_TMP_VAR|IS_VAR) == IS_CONST) {
+ var = _get_zval_ptr_var(opline->op2.var, execute_data, &free_op2);
+ rope[opline->extended_value] = zend_string_copy(Z_STR_P(var));
+ } else {
+ SAVE_OPLINE();
+ var = _get_zval_ptr_var(opline->op2.var, execute_data, &free_op2);
+ rope[opline->extended_value] = zval_get_string(var);
+ zval_ptr_dtor_nogc(free_op2);
+ CHECK_EXCEPTION();
}
- add_string_to_string(str, str, var);
-
- if (use_copy) {
- zend_string_release(Z_STR_P(var));
+ for (i = 0; i <= opline->extended_value; i++) {
+ len += rope[i]->len;
}
- /* original comment, possibly problematic:
- * FREE_OP is missing intentionally here - we're always working on the same temporary variable
- * (Zeev): I don't think it's problematic, we only use variables
- * which aren't affected by FREE_OP(Ts, )'s anyway, unless they're
- * string offsets or overloaded objects
- */
- zval_ptr_dtor_nogc(free_op2);
+ ret = EX_VAR(opline->result.var);
+ ZVAL_STR(ret, zend_string_alloc(len, 0));
+ target = Z_STRVAL_P(ret);
+ for (i = 0; i <= opline->extended_value; i++) {
+ memcpy(target, rope[i]->val, rope[i]->len);
+ target += rope[i]->len;
+ zend_string_release(rope[i]);
+ }
+ *target = '\0';
- CHECK_EXCEPTION();
ZEND_VM_NEXT_OPCODE();
}
ZEND_VM_NEXT_OPCODE();
}
-static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ADD_CHAR_SPEC_UNUSED_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
+static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ROPE_INIT_SPEC_UNUSED_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
{
USE_OPLINE
- zval *str = EX_VAR(opline->result.var);
-
- SAVE_OPLINE();
-
- if (IS_UNUSED == IS_UNUSED) {
- /* Initialize for erealloc in add_char_to_string */
- ZVAL_EMPTY_STRING(str);
- }
-
- add_char_to_string(str, str, EX_CONSTANT(opline->op2));
- /* FREE_OP is missing intentionally here - we're always working on the same temporary variable */
- /*CHECK_EXCEPTION();*/
- ZEND_VM_NEXT_OPCODE();
-}
-
-static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ADD_STRING_SPEC_UNUSED_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
-{
- USE_OPLINE
- zval *str = EX_VAR(opline->result.var);
+ zend_string **rope;
+ zval *var;
- SAVE_OPLINE();
+ /* Compiler allocates the necessary number of zval slots to keep the rope */
+ rope = (zend_string**)EX_VAR(opline->result.var);
+ if (IS_CONST == IS_CONST) {
+ var = EX_CONSTANT(opline->op2);
+ rope[0] = zend_string_copy(Z_STR_P(var));
+ } else {
+ SAVE_OPLINE();
+ var = EX_CONSTANT(opline->op2);
+ rope[0] = zval_get_string(var);
- if (IS_UNUSED == IS_UNUSED) {
- /* Initialize for erealloc in add_string_to_string */
- ZVAL_EMPTY_STRING(str);
+ CHECK_EXCEPTION();
}
-
- add_string_to_string(str, str, EX_CONSTANT(opline->op2));
-
- /* FREE_OP is missing intentionally here - we're always working on the same temporary variable */
- /*CHECK_EXCEPTION();*/
ZEND_VM_NEXT_OPCODE();
}
ZEND_VM_NEXT_OPCODE();
}
-static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ADD_VAR_SPEC_UNUSED_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
+static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ROPE_INIT_SPEC_UNUSED_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
{
USE_OPLINE
- zval *str = EX_VAR(opline->result.var);
+ zend_string **rope;
zval *var;
- zval var_copy;
- int use_copy = 0;
-
- SAVE_OPLINE();
- var = _get_zval_ptr_cv_BP_VAR_R(execute_data, opline->op2.var);
-
- if (IS_UNUSED == IS_UNUSED) {
- /* Initialize for erealloc in add_string_to_string */
- ZVAL_EMPTY_STRING(str);
- }
-
- if (Z_TYPE_P(var) != IS_STRING) {
- use_copy = zend_make_printable_zval(var, &var_copy);
- if (use_copy) {
- var = &var_copy;
- }
- }
- add_string_to_string(str, str, var);
+ /* Compiler allocates the necessary number of zval slots to keep the rope */
+ rope = (zend_string**)EX_VAR(opline->result.var);
+ if (IS_CV == IS_CONST) {
+ var = _get_zval_ptr_cv_BP_VAR_R(execute_data, opline->op2.var);
+ rope[0] = zend_string_copy(Z_STR_P(var));
+ } else {
+ SAVE_OPLINE();
+ var = _get_zval_ptr_cv_BP_VAR_R(execute_data, opline->op2.var);
+ rope[0] = zval_get_string(var);
- if (use_copy) {
- zend_string_release(Z_STR_P(var));
+ CHECK_EXCEPTION();
}
- /* original comment, possibly problematic:
- * FREE_OP is missing intentionally here - we're always working on the same temporary variable
- * (Zeev): I don't think it's problematic, we only use variables
- * which aren't affected by FREE_OP(Ts, )'s anyway, unless they're
- * string offsets or overloaded objects
- */
-
- CHECK_EXCEPTION();
ZEND_VM_NEXT_OPCODE();
}
ZEND_VM_NEXT_OPCODE();
}
-static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ADD_VAR_SPEC_UNUSED_TMPVAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
+static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ROPE_INIT_SPEC_UNUSED_TMPVAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
{
USE_OPLINE
zend_free_op free_op2;
- zval *str = EX_VAR(opline->result.var);
+ zend_string **rope;
zval *var;
- zval var_copy;
- int use_copy = 0;
-
- SAVE_OPLINE();
- var = _get_zval_ptr_var(opline->op2.var, execute_data, &free_op2);
- if (IS_UNUSED == IS_UNUSED) {
- /* Initialize for erealloc in add_string_to_string */
- ZVAL_EMPTY_STRING(str);
- }
-
- if (Z_TYPE_P(var) != IS_STRING) {
- use_copy = zend_make_printable_zval(var, &var_copy);
-
- if (use_copy) {
- var = &var_copy;
- }
- }
- add_string_to_string(str, str, var);
-
- if (use_copy) {
- zend_string_release(Z_STR_P(var));
+ /* Compiler allocates the necessary number of zval slots to keep the rope */
+ rope = (zend_string**)EX_VAR(opline->result.var);
+ if ((IS_TMP_VAR|IS_VAR) == IS_CONST) {
+ var = _get_zval_ptr_var(opline->op2.var, execute_data, &free_op2);
+ rope[0] = zend_string_copy(Z_STR_P(var));
+ } else {
+ SAVE_OPLINE();
+ var = _get_zval_ptr_var(opline->op2.var, execute_data, &free_op2);
+ rope[0] = zval_get_string(var);
+ zval_ptr_dtor_nogc(free_op2);
+ CHECK_EXCEPTION();
}
- /* original comment, possibly problematic:
- * FREE_OP is missing intentionally here - we're always working on the same temporary variable
- * (Zeev): I don't think it's problematic, we only use variables
- * which aren't affected by FREE_OP(Ts, )'s anyway, unless they're
- * string offsets or overloaded objects
- */
- zval_ptr_dtor_nogc(free_op2);
-
- CHECK_EXCEPTION();
ZEND_VM_NEXT_OPCODE();
}
ZEND_VM_NEXT_OPCODE();
}
+static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FAST_CONCAT_SPEC_CV_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
+{
+ USE_OPLINE
+
+ zval *op1, *op2;
+ zend_string *op1_str, *op2_str, *str;
+
+ SAVE_OPLINE();
+ op1 = _get_zval_ptr_cv_BP_VAR_R(execute_data, opline->op1.var);
+ op2 = EX_CONSTANT(opline->op2);
+ if (IS_CV == IS_CONST) {
+ op1_str = Z_STR_P(op1);
+ } else {
+ op1_str = zval_get_string(op1);
+ }
+ if (IS_CONST == IS_CONST) {
+ op2_str = Z_STR_P(op2);
+ } else {
+ op2_str = zval_get_string(op2);
+ }
+ str = zend_string_alloc(op1_str->len + op2_str->len, 0);
+ memcpy(str->val, op1_str->val, op1_str->len);
+ memcpy(str->val + op1_str->len, op2_str->val, op2_str->len+1);
+ ZVAL_NEW_STR(EX_VAR(opline->result.var), str);
+ if (IS_CV != IS_CONST) {
+ zend_string_release(op1_str);
+ }
+ if (IS_CONST != IS_CONST) {
+ zend_string_release(op2_str);
+ }
+
+
+ CHECK_EXCEPTION();
+ ZEND_VM_NEXT_OPCODE();
+}
+
static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_CV_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
{
USE_OPLINE
ZEND_VM_NEXT_OPCODE();
}
+static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FAST_CONCAT_SPEC_CV_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
+{
+ USE_OPLINE
+
+ zval *op1, *op2;
+ zend_string *op1_str, *op2_str, *str;
+
+ SAVE_OPLINE();
+ op1 = _get_zval_ptr_cv_BP_VAR_R(execute_data, opline->op1.var);
+ op2 = _get_zval_ptr_cv_BP_VAR_R(execute_data, opline->op2.var);
+ if (IS_CV == IS_CONST) {
+ op1_str = Z_STR_P(op1);
+ } else {
+ op1_str = zval_get_string(op1);
+ }
+ if (IS_CV == IS_CONST) {
+ op2_str = Z_STR_P(op2);
+ } else {
+ op2_str = zval_get_string(op2);
+ }
+ str = zend_string_alloc(op1_str->len + op2_str->len, 0);
+ memcpy(str->val, op1_str->val, op1_str->len);
+ memcpy(str->val + op1_str->len, op2_str->val, op2_str->len+1);
+ ZVAL_NEW_STR(EX_VAR(opline->result.var), str);
+ if (IS_CV != IS_CONST) {
+ zend_string_release(op1_str);
+ }
+ if (IS_CV != IS_CONST) {
+ zend_string_release(op2_str);
+ }
+
+
+ CHECK_EXCEPTION();
+ ZEND_VM_NEXT_OPCODE();
+}
+
static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_CV_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
{
USE_OPLINE
ZEND_VM_NEXT_OPCODE();
}
+static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FAST_CONCAT_SPEC_CV_TMPVAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
+{
+ USE_OPLINE
+ zend_free_op free_op2;
+ zval *op1, *op2;
+ zend_string *op1_str, *op2_str, *str;
+
+ SAVE_OPLINE();
+ op1 = _get_zval_ptr_cv_BP_VAR_R(execute_data, opline->op1.var);
+ op2 = _get_zval_ptr_var(opline->op2.var, execute_data, &free_op2);
+ if (IS_CV == IS_CONST) {
+ op1_str = Z_STR_P(op1);
+ } else {
+ op1_str = zval_get_string(op1);
+ }
+ if ((IS_TMP_VAR|IS_VAR) == IS_CONST) {
+ op2_str = Z_STR_P(op2);
+ } else {
+ op2_str = zval_get_string(op2);
+ }
+ str = zend_string_alloc(op1_str->len + op2_str->len, 0);
+ memcpy(str->val, op1_str->val, op1_str->len);
+ memcpy(str->val + op1_str->len, op2_str->val, op2_str->len+1);
+ ZVAL_NEW_STR(EX_VAR(opline->result.var), str);
+ if (IS_CV != IS_CONST) {
+ zend_string_release(op1_str);
+ }
+ if ((IS_TMP_VAR|IS_VAR) != IS_CONST) {
+ zend_string_release(op2_str);
+ }
+
+ zval_ptr_dtor_nogc(free_op2);
+ CHECK_EXCEPTION();
+ ZEND_VM_NEXT_OPCODE();
+}
+
static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_CV_TMPVAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
{
USE_OPLINE
ZEND_VM_NEXT_OPCODE();
}
+static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FAST_CONCAT_SPEC_TMPVAR_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
+{
+ USE_OPLINE
+ zend_free_op free_op1;
+ zval *op1, *op2;
+ zend_string *op1_str, *op2_str, *str;
+
+ SAVE_OPLINE();
+ op1 = _get_zval_ptr_var(opline->op1.var, execute_data, &free_op1);
+ op2 = EX_CONSTANT(opline->op2);
+ if ((IS_TMP_VAR|IS_VAR) == IS_CONST) {
+ op1_str = Z_STR_P(op1);
+ } else {
+ op1_str = zval_get_string(op1);
+ }
+ if (IS_CONST == IS_CONST) {
+ op2_str = Z_STR_P(op2);
+ } else {
+ op2_str = zval_get_string(op2);
+ }
+ str = zend_string_alloc(op1_str->len + op2_str->len, 0);
+ memcpy(str->val, op1_str->val, op1_str->len);
+ memcpy(str->val + op1_str->len, op2_str->val, op2_str->len+1);
+ ZVAL_NEW_STR(EX_VAR(opline->result.var), str);
+ if ((IS_TMP_VAR|IS_VAR) != IS_CONST) {
+ zend_string_release(op1_str);
+ }
+ if (IS_CONST != IS_CONST) {
+ zend_string_release(op2_str);
+ }
+ zval_ptr_dtor_nogc(free_op1);
+
+ CHECK_EXCEPTION();
+ ZEND_VM_NEXT_OPCODE();
+}
+
static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_TMPVAR_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
{
USE_OPLINE
ZEND_VM_NEXT_OPCODE();
}
+static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FAST_CONCAT_SPEC_TMPVAR_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
+{
+ USE_OPLINE
+ zend_free_op free_op1;
+ zval *op1, *op2;
+ zend_string *op1_str, *op2_str, *str;
+
+ SAVE_OPLINE();
+ op1 = _get_zval_ptr_var(opline->op1.var, execute_data, &free_op1);
+ op2 = _get_zval_ptr_cv_BP_VAR_R(execute_data, opline->op2.var);
+ if ((IS_TMP_VAR|IS_VAR) == IS_CONST) {
+ op1_str = Z_STR_P(op1);
+ } else {
+ op1_str = zval_get_string(op1);
+ }
+ if (IS_CV == IS_CONST) {
+ op2_str = Z_STR_P(op2);
+ } else {
+ op2_str = zval_get_string(op2);
+ }
+ str = zend_string_alloc(op1_str->len + op2_str->len, 0);
+ memcpy(str->val, op1_str->val, op1_str->len);
+ memcpy(str->val + op1_str->len, op2_str->val, op2_str->len+1);
+ ZVAL_NEW_STR(EX_VAR(opline->result.var), str);
+ if ((IS_TMP_VAR|IS_VAR) != IS_CONST) {
+ zend_string_release(op1_str);
+ }
+ if (IS_CV != IS_CONST) {
+ zend_string_release(op2_str);
+ }
+ zval_ptr_dtor_nogc(free_op1);
+
+ CHECK_EXCEPTION();
+ ZEND_VM_NEXT_OPCODE();
+}
+
static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_TMPVAR_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
{
USE_OPLINE
ZEND_VM_NEXT_OPCODE();
}
+static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FAST_CONCAT_SPEC_TMPVAR_TMPVAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
+{
+ USE_OPLINE
+ zend_free_op free_op1, free_op2;
+ zval *op1, *op2;
+ zend_string *op1_str, *op2_str, *str;
+
+ SAVE_OPLINE();
+ op1 = _get_zval_ptr_var(opline->op1.var, execute_data, &free_op1);
+ op2 = _get_zval_ptr_var(opline->op2.var, execute_data, &free_op2);
+ if ((IS_TMP_VAR|IS_VAR) == IS_CONST) {
+ op1_str = Z_STR_P(op1);
+ } else {
+ op1_str = zval_get_string(op1);
+ }
+ if ((IS_TMP_VAR|IS_VAR) == IS_CONST) {
+ op2_str = Z_STR_P(op2);
+ } else {
+ op2_str = zval_get_string(op2);
+ }
+ str = zend_string_alloc(op1_str->len + op2_str->len, 0);
+ memcpy(str->val, op1_str->val, op1_str->len);
+ memcpy(str->val + op1_str->len, op2_str->val, op2_str->len+1);
+ ZVAL_NEW_STR(EX_VAR(opline->result.var), str);
+ if ((IS_TMP_VAR|IS_VAR) != IS_CONST) {
+ zend_string_release(op1_str);
+ }
+ if ((IS_TMP_VAR|IS_VAR) != IS_CONST) {
+ zend_string_release(op2_str);
+ }
+ zval_ptr_dtor_nogc(free_op1);
+ zval_ptr_dtor_nogc(free_op2);
+ CHECK_EXCEPTION();
+ ZEND_VM_NEXT_OPCODE();
+}
+
static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_TMPVAR_TMPVAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
{
USE_OPLINE
ZEND_BOOL_SPEC_CV_HANDLER,
ZEND_BOOL_SPEC_CV_HANDLER,
ZEND_BOOL_SPEC_CV_HANDLER,
+ ZEND_FAST_CONCAT_SPEC_CONST_CONST_HANDLER,
+ ZEND_FAST_CONCAT_SPEC_CONST_TMPVAR_HANDLER,
+ ZEND_FAST_CONCAT_SPEC_CONST_TMPVAR_HANDLER,
ZEND_NULL_HANDLER,
+ ZEND_FAST_CONCAT_SPEC_CONST_CV_HANDLER,
+ ZEND_FAST_CONCAT_SPEC_TMPVAR_CONST_HANDLER,
+ ZEND_FAST_CONCAT_SPEC_TMPVAR_TMPVAR_HANDLER,
+ ZEND_FAST_CONCAT_SPEC_TMPVAR_TMPVAR_HANDLER,
ZEND_NULL_HANDLER,
+ ZEND_FAST_CONCAT_SPEC_TMPVAR_CV_HANDLER,
+ ZEND_FAST_CONCAT_SPEC_TMPVAR_CONST_HANDLER,
+ ZEND_FAST_CONCAT_SPEC_TMPVAR_TMPVAR_HANDLER,
+ ZEND_FAST_CONCAT_SPEC_TMPVAR_TMPVAR_HANDLER,
ZEND_NULL_HANDLER,
+ ZEND_FAST_CONCAT_SPEC_TMPVAR_CV_HANDLER,
ZEND_NULL_HANDLER,
ZEND_NULL_HANDLER,
ZEND_NULL_HANDLER,
ZEND_NULL_HANDLER,
ZEND_NULL_HANDLER,
+ ZEND_FAST_CONCAT_SPEC_CV_CONST_HANDLER,
+ ZEND_FAST_CONCAT_SPEC_CV_TMPVAR_HANDLER,
+ ZEND_FAST_CONCAT_SPEC_CV_TMPVAR_HANDLER,
ZEND_NULL_HANDLER,
+ ZEND_FAST_CONCAT_SPEC_CV_CV_HANDLER,
ZEND_NULL_HANDLER,
ZEND_NULL_HANDLER,
ZEND_NULL_HANDLER,
ZEND_NULL_HANDLER,
ZEND_NULL_HANDLER,
ZEND_NULL_HANDLER,
+ ZEND_ROPE_INIT_SPEC_UNUSED_CONST_HANDLER,
+ ZEND_ROPE_INIT_SPEC_UNUSED_TMPVAR_HANDLER,
+ ZEND_ROPE_INIT_SPEC_UNUSED_TMPVAR_HANDLER,
ZEND_NULL_HANDLER,
- ZEND_NULL_HANDLER,
- ZEND_NULL_HANDLER,
- ZEND_NULL_HANDLER,
- ZEND_NULL_HANDLER,
- ZEND_NULL_HANDLER,
- ZEND_ADD_CHAR_SPEC_TMP_CONST_HANDLER,
- ZEND_NULL_HANDLER,
- ZEND_NULL_HANDLER,
- ZEND_NULL_HANDLER,
- ZEND_NULL_HANDLER,
- ZEND_NULL_HANDLER,
- ZEND_NULL_HANDLER,
- ZEND_NULL_HANDLER,
- ZEND_NULL_HANDLER,
- ZEND_NULL_HANDLER,
- ZEND_ADD_CHAR_SPEC_UNUSED_CONST_HANDLER,
- ZEND_NULL_HANDLER,
- ZEND_NULL_HANDLER,
- ZEND_NULL_HANDLER,
- ZEND_NULL_HANDLER,
+ ZEND_ROPE_INIT_SPEC_UNUSED_CV_HANDLER,
ZEND_NULL_HANDLER,
ZEND_NULL_HANDLER,
ZEND_NULL_HANDLER,
ZEND_NULL_HANDLER,
ZEND_NULL_HANDLER,
ZEND_NULL_HANDLER,
- ZEND_ADD_STRING_SPEC_TMP_CONST_HANDLER,
+ ZEND_ROPE_ADD_SPEC_TMP_CONST_HANDLER,
+ ZEND_ROPE_ADD_SPEC_TMP_TMPVAR_HANDLER,
+ ZEND_ROPE_ADD_SPEC_TMP_TMPVAR_HANDLER,
ZEND_NULL_HANDLER,
+ ZEND_ROPE_ADD_SPEC_TMP_CV_HANDLER,
ZEND_NULL_HANDLER,
ZEND_NULL_HANDLER,
ZEND_NULL_HANDLER,
ZEND_NULL_HANDLER,
ZEND_NULL_HANDLER,
ZEND_NULL_HANDLER,
- ZEND_ADD_STRING_SPEC_UNUSED_CONST_HANDLER,
ZEND_NULL_HANDLER,
ZEND_NULL_HANDLER,
ZEND_NULL_HANDLER,
ZEND_NULL_HANDLER,
ZEND_NULL_HANDLER,
ZEND_NULL_HANDLER,
+ ZEND_ROPE_END_SPEC_TMP_CONST_HANDLER,
+ ZEND_ROPE_END_SPEC_TMP_TMPVAR_HANDLER,
+ ZEND_ROPE_END_SPEC_TMP_TMPVAR_HANDLER,
ZEND_NULL_HANDLER,
+ ZEND_ROPE_END_SPEC_TMP_CV_HANDLER,
ZEND_NULL_HANDLER,
ZEND_NULL_HANDLER,
- ZEND_ADD_VAR_SPEC_TMP_TMPVAR_HANDLER,
- ZEND_ADD_VAR_SPEC_TMP_TMPVAR_HANDLER,
ZEND_NULL_HANDLER,
- ZEND_ADD_VAR_SPEC_TMP_CV_HANDLER,
ZEND_NULL_HANDLER,
ZEND_NULL_HANDLER,
ZEND_NULL_HANDLER,
ZEND_NULL_HANDLER,
ZEND_NULL_HANDLER,
ZEND_NULL_HANDLER,
- ZEND_ADD_VAR_SPEC_UNUSED_TMPVAR_HANDLER,
- ZEND_ADD_VAR_SPEC_UNUSED_TMPVAR_HANDLER,
ZEND_NULL_HANDLER,
- ZEND_ADD_VAR_SPEC_UNUSED_CV_HANDLER,
ZEND_NULL_HANDLER,
ZEND_NULL_HANDLER,
ZEND_NULL_HANDLER,