mirror of
https://github.com/php/php-src.git
synced 2024-09-21 09:57:23 +00:00
Optimized strings concatenation.
ZEND_ADD_STRING/VAR/CHAR are replaced with ZEND_ROPE_INTI, ZEND_ROPE_ADD, ZEND_ROPE_END. Instead of reallocation and copying string on each ZEND_ADD_STRING/VAR/CAHR, collect all the strings and then allocate and construct the resulting string once.
This commit is contained in:
parent
bdf7fc67d8
commit
23c33b1483
@ -6231,55 +6231,129 @@ void zend_compile_resolve_class_name(znode *result, zend_ast *ast) /* {{{ */
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
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_op *opline = get_next_op(CG(active_op_array));
|
||||
|
||||
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;
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
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);
|
||||
uint32_t i;
|
||||
|
||||
ZEND_ASSERT(list->children > 0);
|
||||
|
||||
result->op_type = IS_TMP_VAR;
|
||||
result->u.op.var = get_temporary_variable(CG(active_op_array));
|
||||
j = 0;
|
||||
last_const_node.op_type = IS_UNUSED;
|
||||
for (i = 0; i < list->children; i++) {
|
||||
zend_compile_expr(&elem_node, list->child[i]);
|
||||
|
||||
for (i = 0; i < list->children; ++i) {
|
||||
zend_ast *elem_ast = list->child[i];
|
||||
znode elem_node;
|
||||
zend_op *opline;
|
||||
if (elem_node.op_type == IS_CONST) {
|
||||
convert_to_string(&elem_node.u.constant);
|
||||
|
||||
zend_compile_expr(&elem_node, elem_ast);
|
||||
|
||||
if (elem_ast->kind == ZEND_AST_ZVAL) {
|
||||
zval *zv = &elem_node.u.constant;
|
||||
ZEND_ASSERT(Z_TYPE_P(zv) == IS_STRING);
|
||||
|
||||
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 {
|
||||
SET_NODE(opline->op1, result);
|
||||
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 {
|
||||
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);
|
||||
}
|
||||
}
|
||||
/* }}} */
|
||||
|
@ -861,6 +861,7 @@ ZEND_API binary_op_type get_binary_op(int opcode)
|
||||
case ZEND_SR:
|
||||
case ZEND_ASSIGN_SR:
|
||||
return (binary_op_type) shift_right_function;
|
||||
case ZEND_FAST_CONCAT:
|
||||
case ZEND_CONCAT:
|
||||
case ZEND_ASSIGN_CONCAT:
|
||||
return (binary_op_type) concat_function;
|
||||
|
@ -2571,82 +2571,120 @@ ZEND_VM_HANDLER(127, ZEND_FE_FREE, TMPVAR, ANY)
|
||||
ZEND_VM_NEXT_OPCODE();
|
||||
}
|
||||
|
||||
ZEND_VM_HANDLER(54, ZEND_ADD_CHAR, TMP|UNUSED, CONST)
|
||||
ZEND_VM_HANDLER(53, ZEND_FAST_CONCAT, CONST|TMPVAR|CV, CONST|TMPVAR|CV)
|
||||
{
|
||||
USE_OPLINE
|
||||
zval *str = EX_VAR(opline->result.var);
|
||||
zend_free_op free_op1, free_op2;
|
||||
zval *op1, *op2;
|
||||
zend_string *op1_str, *op2_str, *str;
|
||||
|
||||
SAVE_OPLINE();
|
||||
|
||||
if (OP1_TYPE == IS_UNUSED) {
|
||||
/* Initialize for erealloc in add_char_to_string */
|
||||
ZVAL_EMPTY_STRING(str);
|
||||
op1 = GET_OP1_ZVAL_PTR(BP_VAR_R);
|
||||
op2 = GET_OP2_ZVAL_PTR(BP_VAR_R);
|
||||
if (OP1_TYPE == IS_CONST) {
|
||||
op1_str = Z_STR_P(op1);
|
||||
} else {
|
||||
op1_str = zval_get_string(op1);
|
||||
}
|
||||
|
||||
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();*/
|
||||
if (OP2_TYPE == 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 (OP1_TYPE != IS_CONST) {
|
||||
zend_string_release(op1_str);
|
||||
}
|
||||
if (OP2_TYPE != IS_CONST) {
|
||||
zend_string_release(op2_str);
|
||||
}
|
||||
FREE_OP1();
|
||||
FREE_OP2();
|
||||
CHECK_EXCEPTION();
|
||||
ZEND_VM_NEXT_OPCODE();
|
||||
}
|
||||
|
||||
ZEND_VM_HANDLER(55, ZEND_ADD_STRING, TMP|UNUSED, CONST)
|
||||
{
|
||||
USE_OPLINE
|
||||
zval *str = EX_VAR(opline->result.var);
|
||||
|
||||
SAVE_OPLINE();
|
||||
|
||||
if (OP1_TYPE == IS_UNUSED) {
|
||||
/* Initialize for erealloc in add_string_to_string */
|
||||
ZVAL_EMPTY_STRING(str);
|
||||
}
|
||||
|
||||
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_HANDLER(56, ZEND_ADD_VAR, TMP|UNUSED, TMPVAR|CV)
|
||||
ZEND_VM_HANDLER(54, ZEND_ROPE_INIT, UNUSED, CONST|TMPVAR|CV)
|
||||
{
|
||||
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_OP2_ZVAL_PTR(BP_VAR_R);
|
||||
|
||||
if (OP1_TYPE == IS_UNUSED) {
|
||||
/* Initialize for erealloc in add_string_to_string */
|
||||
ZVAL_EMPTY_STRING(str);
|
||||
/* Compiler allocates the necessary number of zval slots to keep the rope */
|
||||
rope = (zend_string**)EX_VAR(opline->result.var);
|
||||
if (OP2_TYPE == IS_CONST) {
|
||||
var = GET_OP2_ZVAL_PTR(BP_VAR_R);
|
||||
rope[0] = zend_string_copy(Z_STR_P(var));
|
||||
} else {
|
||||
SAVE_OPLINE();
|
||||
var = GET_OP2_ZVAL_PTR(BP_VAR_R);
|
||||
rope[0] = zval_get_string(var);
|
||||
FREE_OP2();
|
||||
CHECK_EXCEPTION();
|
||||
}
|
||||
ZEND_VM_NEXT_OPCODE();
|
||||
}
|
||||
|
||||
if (Z_TYPE_P(var) != IS_STRING) {
|
||||
use_copy = zend_make_printable_zval(var, &var_copy);
|
||||
ZEND_VM_HANDLER(55, ZEND_ROPE_ADD, TMP, CONST|TMPVAR|CV)
|
||||
{
|
||||
USE_OPLINE
|
||||
zend_free_op free_op2;
|
||||
zend_string **rope;
|
||||
zval *var;
|
||||
|
||||
if (use_copy) {
|
||||
var = &var_copy;
|
||||
}
|
||||
/* op1 and result are the same */
|
||||
rope = (zend_string**)EX_VAR(opline->op1.var);
|
||||
if (OP2_TYPE == IS_CONST) {
|
||||
var = GET_OP2_ZVAL_PTR(BP_VAR_R);
|
||||
rope[opline->extended_value] = zend_string_copy(Z_STR_P(var));
|
||||
} else {
|
||||
SAVE_OPLINE();
|
||||
var = GET_OP2_ZVAL_PTR(BP_VAR_R);
|
||||
rope[opline->extended_value] = zval_get_string(var);
|
||||
FREE_OP2();
|
||||
CHECK_EXCEPTION();
|
||||
}
|
||||
add_string_to_string(str, str, var);
|
||||
ZEND_VM_NEXT_OPCODE();
|
||||
}
|
||||
|
||||
if (use_copy) {
|
||||
zend_string_release(Z_STR_P(var));
|
||||
ZEND_VM_HANDLER(56, ZEND_ROPE_END, TMP, CONST|TMPVAR|CV)
|
||||
{
|
||||
USE_OPLINE
|
||||
zend_free_op free_op2;
|
||||
zend_string **rope;
|
||||
zval *var, *ret;
|
||||
uint32_t i;
|
||||
size_t len = 0;
|
||||
char *target;
|
||||
|
||||
rope = (zend_string**)EX_VAR(opline->op1.var);
|
||||
if (OP2_TYPE == IS_CONST) {
|
||||
var = GET_OP2_ZVAL_PTR(BP_VAR_R);
|
||||
rope[opline->extended_value] = zend_string_copy(Z_STR_P(var));
|
||||
} else {
|
||||
SAVE_OPLINE();
|
||||
var = GET_OP2_ZVAL_PTR(BP_VAR_R);
|
||||
rope[opline->extended_value] = zval_get_string(var);
|
||||
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
|
||||
*/
|
||||
FREE_OP2();
|
||||
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';
|
||||
|
||||
CHECK_EXCEPTION();
|
||||
ZEND_VM_NEXT_OPCODE();
|
||||
}
|
||||
|
||||
|
@ -4924,6 +4924,42 @@ try_fetch_list:
|
||||
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
|
||||
@ -8272,6 +8308,42 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_OBJ_FUNC_ARG_SPEC_CONST_
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
@ -9785,6 +9857,42 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_OBJ_FUNC_ARG_SPEC_CONST_
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
@ -11250,41 +11358,62 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_OBJ_FUNC_ARG_SPEC_TMP_CO
|
||||
}
|
||||
}
|
||||
|
||||
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();
|
||||
zend_string **rope;
|
||||
zval *var;
|
||||
|
||||
if (IS_TMP_VAR == IS_UNUSED) {
|
||||
/* Initialize for erealloc in add_char_to_string */
|
||||
ZVAL_EMPTY_STRING(str);
|
||||
/* 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);
|
||||
|
||||
CHECK_EXCEPTION();
|
||||
}
|
||||
|
||||
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_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);
|
||||
|
||||
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';
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
@ -12418,43 +12547,62 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_OBJ_FUNC_ARG_SPEC_TMP_CV
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
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);
|
||||
|
||||
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
|
||||
*/
|
||||
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();
|
||||
}
|
||||
|
||||
@ -12867,44 +13015,62 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_OBJ_FUNC_ARG_SPEC_TMP_TM
|
||||
}
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
@ -21682,41 +21848,25 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_UNUSED_CONST_H
|
||||
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();
|
||||
zend_string **rope;
|
||||
zval *var;
|
||||
|
||||
if (IS_UNUSED == IS_UNUSED) {
|
||||
/* Initialize for erealloc in add_char_to_string */
|
||||
ZVAL_EMPTY_STRING(str);
|
||||
/* 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);
|
||||
|
||||
CHECK_EXCEPTION();
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
SAVE_OPLINE();
|
||||
|
||||
if (IS_UNUSED == IS_UNUSED) {
|
||||
/* Initialize for erealloc in add_string_to_string */
|
||||
ZVAL_EMPTY_STRING(str);
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
@ -23989,43 +24139,25 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_UNUSED_CV_HAND
|
||||
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);
|
||||
/* 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 (IS_UNUSED == IS_UNUSED) {
|
||||
/* Initialize for erealloc in add_string_to_string */
|
||||
ZVAL_EMPTY_STRING(str);
|
||||
CHECK_EXCEPTION();
|
||||
}
|
||||
|
||||
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));
|
||||
}
|
||||
/* 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();
|
||||
}
|
||||
|
||||
@ -25419,44 +25551,25 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_UNUSED_TMPVAR_
|
||||
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);
|
||||
/* 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();
|
||||
}
|
||||
|
||||
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));
|
||||
}
|
||||
/* 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();
|
||||
}
|
||||
|
||||
@ -29375,6 +29488,42 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_SPEC_CV_CONST_HANDLER(Z
|
||||
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
|
||||
@ -34152,6 +34301,42 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_REF_SPEC_CV_CV_HANDLER(
|
||||
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
|
||||
@ -36534,6 +36719,42 @@ assign_dim_clean:
|
||||
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
|
||||
@ -38509,6 +38730,42 @@ try_fetch_list:
|
||||
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
|
||||
@ -40430,6 +40687,42 @@ fetch_obj_is_no_object:
|
||||
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
|
||||
@ -41384,6 +41677,42 @@ fetch_obj_is_no_object:
|
||||
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
|
||||
@ -43049,15 +43378,31 @@ void zend_init_opcodes_handlers(void)
|
||||
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,
|
||||
@ -43073,23 +43418,29 @@ void zend_init_opcodes_handlers(void)
|
||||
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_ROPE_INIT_SPEC_UNUSED_CV_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_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_ADD_CHAR_SPEC_UNUSED_CONST_HANDLER,
|
||||
ZEND_NULL_HANDLER,
|
||||
ZEND_NULL_HANDLER,
|
||||
ZEND_NULL_HANDLER,
|
||||
@ -43104,17 +43455,19 @@ void zend_init_opcodes_handlers(void)
|
||||
ZEND_NULL_HANDLER,
|
||||
ZEND_NULL_HANDLER,
|
||||
ZEND_NULL_HANDLER,
|
||||
ZEND_ADD_STRING_SPEC_TMP_CONST_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_NULL_HANDLER,
|
||||
ZEND_NULL_HANDLER,
|
||||
ZEND_NULL_HANDLER,
|
||||
ZEND_ADD_STRING_SPEC_UNUSED_CONST_HANDLER,
|
||||
ZEND_NULL_HANDLER,
|
||||
ZEND_NULL_HANDLER,
|
||||
ZEND_NULL_HANDLER,
|
||||
@ -43125,30 +43478,6 @@ void zend_init_opcodes_handlers(void)
|
||||
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_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,
|
||||
ZEND_NULL_HANDLER,
|
||||
ZEND_NULL_HANDLER,
|
||||
ZEND_BEGIN_SILENCE_SPEC_HANDLER,
|
||||
ZEND_BEGIN_SILENCE_SPEC_HANDLER,
|
||||
ZEND_BEGIN_SILENCE_SPEC_HANDLER,
|
||||
|
@ -75,10 +75,10 @@ const char *zend_vm_opcodes_map[171] = {
|
||||
"ZEND_BRK",
|
||||
"ZEND_CONT",
|
||||
"ZEND_BOOL",
|
||||
NULL,
|
||||
"ZEND_ADD_CHAR",
|
||||
"ZEND_ADD_STRING",
|
||||
"ZEND_ADD_VAR",
|
||||
"ZEND_FAST_CONCAT",
|
||||
"ZEND_ROPE_INIT",
|
||||
"ZEND_ROPE_ADD",
|
||||
"ZEND_ROPE_END",
|
||||
"ZEND_BEGIN_SILENCE",
|
||||
"ZEND_END_SILENCE",
|
||||
"ZEND_INIT_FCALL_BY_NAME",
|
||||
|
@ -85,9 +85,10 @@ END_EXTERN_C()
|
||||
#define ZEND_BRK 50
|
||||
#define ZEND_CONT 51
|
||||
#define ZEND_BOOL 52
|
||||
#define ZEND_ADD_CHAR 54
|
||||
#define ZEND_ADD_STRING 55
|
||||
#define ZEND_ADD_VAR 56
|
||||
#define ZEND_FAST_CONCAT 53
|
||||
#define ZEND_ROPE_INIT 54
|
||||
#define ZEND_ROPE_ADD 55
|
||||
#define ZEND_ROPE_END 56
|
||||
#define ZEND_BEGIN_SILENCE 57
|
||||
#define ZEND_END_SILENCE 58
|
||||
#define ZEND_INIT_FCALL_BY_NAME 59
|
||||
|
@ -911,38 +911,26 @@ static void zend_optimize_block(zend_code_block *block, zend_op_array *op_array,
|
||||
}
|
||||
ZVAL_NULL(&ZEND_OP1_LITERAL(last_op));
|
||||
MAKE_NOP(last_op);
|
||||
} else if ((opline->opcode == ZEND_CONCAT ||
|
||||
opline->opcode == ZEND_ADD_STRING ||
|
||||
opline->opcode == ZEND_ADD_CHAR) &&
|
||||
} else if ((opline->opcode == ZEND_CONCAT) &&
|
||||
ZEND_OP2_TYPE(opline) == IS_CONST &&
|
||||
ZEND_OP1_TYPE(opline) == IS_TMP_VAR &&
|
||||
VAR_SOURCE(opline->op1) &&
|
||||
(VAR_SOURCE(opline->op1)->opcode == ZEND_CONCAT ||
|
||||
VAR_SOURCE(opline->op1)->opcode == ZEND_ADD_STRING ||
|
||||
VAR_SOURCE(opline->op1)->opcode == ZEND_ADD_CHAR) &&
|
||||
VAR_SOURCE(opline->op1)->opcode == ZEND_FAST_CONCAT) &&
|
||||
ZEND_OP2_TYPE(VAR_SOURCE(opline->op1)) == IS_CONST &&
|
||||
ZEND_RESULT(VAR_SOURCE(opline->op1)).var == ZEND_OP1(opline).var) {
|
||||
/* compress consecutive CONCAT/ADD_STRING/ADD_CHARs */
|
||||
zend_op *src = VAR_SOURCE(opline->op1);
|
||||
int l, old_len;
|
||||
|
||||
if (opline->opcode == ZEND_ADD_CHAR) {
|
||||
char c = (char)Z_LVAL(ZEND_OP2_LITERAL(opline));
|
||||
ZVAL_STRINGL(&ZEND_OP2_LITERAL(opline), &c, 1);
|
||||
} else if (Z_TYPE(ZEND_OP2_LITERAL(opline)) != IS_STRING) {
|
||||
if (Z_TYPE(ZEND_OP2_LITERAL(opline)) != IS_STRING) {
|
||||
convert_to_string_safe(&ZEND_OP2_LITERAL(opline));
|
||||
}
|
||||
if (src->opcode == ZEND_ADD_CHAR) {
|
||||
char c = (char)Z_LVAL(ZEND_OP2_LITERAL(src));
|
||||
ZVAL_STRINGL(&ZEND_OP2_LITERAL(src), &c, 1);
|
||||
} else if (Z_TYPE(ZEND_OP2_LITERAL(src)) != IS_STRING) {
|
||||
if (Z_TYPE(ZEND_OP2_LITERAL(src)) != IS_STRING) {
|
||||
convert_to_string_safe(&ZEND_OP2_LITERAL(src));
|
||||
}
|
||||
|
||||
VAR_UNSET(opline->op1);
|
||||
if (opline->opcode != ZEND_CONCAT) {
|
||||
opline->opcode = ZEND_ADD_STRING;
|
||||
}
|
||||
COPY_NODE(opline->op1, src->op1);
|
||||
old_len = Z_STRLEN(ZEND_OP2_LITERAL(src));
|
||||
l = old_len + Z_STRLEN(ZEND_OP2_LITERAL(opline));
|
||||
@ -971,6 +959,7 @@ static void zend_optimize_block(zend_code_block *block, zend_op_array *op_array,
|
||||
opline->opcode == ZEND_SL ||
|
||||
opline->opcode == ZEND_SR ||
|
||||
opline->opcode == ZEND_CONCAT ||
|
||||
opline->opcode == ZEND_FAST_CONCAT ||
|
||||
opline->opcode == ZEND_IS_EQUAL ||
|
||||
opline->opcode == ZEND_IS_NOT_EQUAL ||
|
||||
opline->opcode == ZEND_IS_SMALLER ||
|
||||
@ -1036,7 +1025,40 @@ static void zend_optimize_block(zend_code_block *block, zend_op_array *op_array,
|
||||
VAR_UNSET(opline->op1);
|
||||
COPY_NODE(opline->op1, src->op1);
|
||||
MAKE_NOP(src);
|
||||
} else if (opline->opcode == ZEND_CONCAT) {
|
||||
} else if (opline->opcode == ZEND_CONCAT || opline->opcode == ZEND_FAST_CONCAT) {
|
||||
#if 0
|
||||
if (opline->opcode == ZEND_CONCAT) {
|
||||
fprintf(stderr, "CONCAT ");
|
||||
} else {
|
||||
fprintf(stderr, "FAST_CONCAT ");
|
||||
}
|
||||
if (opline->op1_type == IS_CONST) {
|
||||
fprintf(stderr, "CONST");
|
||||
} else if (opline->op1_type == IS_TMP_VAR) {
|
||||
fprintf(stderr, "TMP");
|
||||
if (VAR_SOURCE(opline->op1)) {
|
||||
fprintf(stderr, "(%s)", zend_get_opcode_name(VAR_SOURCE(opline->op1)->opcode));
|
||||
}
|
||||
} else if (opline->op1_type == IS_VAR) {
|
||||
fprintf(stderr, "VAR");
|
||||
} else if (opline->op1_type == IS_CV) {
|
||||
fprintf(stderr, "CV");
|
||||
}
|
||||
fprintf(stderr, ", ");
|
||||
if (opline->op2_type == IS_CONST) {
|
||||
fprintf(stderr, "CONST");
|
||||
} else if (opline->op2_type == IS_TMP_VAR) {
|
||||
fprintf(stderr, "TMP");
|
||||
if (VAR_SOURCE(opline->op2)) {
|
||||
fprintf(stderr, "(%s)", zend_get_opcode_name(VAR_SOURCE(opline->op2)->opcode));
|
||||
}
|
||||
} else if (opline->op2_type == IS_VAR) {
|
||||
fprintf(stderr, "VAR");
|
||||
} else if (opline->op2_type == IS_CV) {
|
||||
fprintf(stderr, "CV");
|
||||
}
|
||||
fprintf(stderr, "\n");
|
||||
#endif
|
||||
if ((ZEND_OP1_TYPE(opline) & (IS_TMP_VAR|IS_VAR)) &&
|
||||
VAR_SOURCE(opline->op1) &&
|
||||
VAR_SOURCE(opline->op1)->opcode == ZEND_CAST &&
|
||||
@ -1076,6 +1098,20 @@ static void zend_optimize_block(zend_code_block *block, zend_op_array *op_array,
|
||||
opline->extended_value = IS_STRING;
|
||||
opline->op2_type = IS_UNUSED;
|
||||
opline->op2.var = 0;
|
||||
} else if (opline->opcode == ZEND_CONCAT &&
|
||||
(opline->op1_type == IS_CONST ||
|
||||
(opline->op1_type == IS_TMP_VAR &&
|
||||
VAR_SOURCE(opline->op1) &&
|
||||
(VAR_SOURCE(opline->op1)->opcode == ZEND_FAST_CONCAT ||
|
||||
VAR_SOURCE(opline->op1)->opcode == ZEND_ROPE_END ||
|
||||
VAR_SOURCE(opline->op1)->opcode == ZEND_FETCH_CONSTANT))) &&
|
||||
(opline->op2_type == IS_CONST ||
|
||||
(opline->op2_type == IS_TMP_VAR &&
|
||||
VAR_SOURCE(opline->op2) &&
|
||||
(VAR_SOURCE(opline->op2)->opcode == ZEND_FAST_CONCAT ||
|
||||
VAR_SOURCE(opline->op2)->opcode == ZEND_ROPE_END ||
|
||||
VAR_SOURCE(opline->op2)->opcode == ZEND_FETCH_CONSTANT)))) {
|
||||
opline->opcode = ZEND_FAST_CONCAT;
|
||||
}
|
||||
} else if (opline->opcode == ZEND_QM_ASSIGN &&
|
||||
ZEND_OP1_TYPE(opline) == ZEND_RESULT_TYPE(opline) &&
|
||||
|
@ -79,12 +79,32 @@ void optimize_temporary_variables(zend_op_array *op_array, zend_optimizer_ctx *c
|
||||
if ((ZEND_OP1_TYPE(opline) & (IS_VAR | IS_TMP_VAR))) {
|
||||
|
||||
currT = VAR_NUM(ZEND_OP1(opline).var) - offset;
|
||||
if (!valid_T[currT]) {
|
||||
GET_AVAILABLE_T();
|
||||
map_T[currT] = i;
|
||||
if (opline->opcode == ZEND_ROPE_END) {
|
||||
int num = (((opline->extended_value + 1) * sizeof(zend_string*)) + (sizeof(zval) - 1)) / sizeof(zval);
|
||||
int var;
|
||||
|
||||
var = max;
|
||||
while (var >= 0 && !taken_T[var]) {
|
||||
var--;
|
||||
}
|
||||
max = MAX(max, var + num);
|
||||
var = var + 1;
|
||||
map_T[currT] = var;
|
||||
valid_T[currT] = 1;
|
||||
taken_T[var] = 1;
|
||||
ZEND_OP1(opline).var = NUM_VAR(var + offset);
|
||||
while (num > 1) {
|
||||
num--;
|
||||
taken_T[var + num] = 1;
|
||||
}
|
||||
} else {
|
||||
if (!valid_T[currT]) {
|
||||
GET_AVAILABLE_T();
|
||||
map_T[currT] = i;
|
||||
valid_T[currT] = 1;
|
||||
}
|
||||
ZEND_OP1(opline).var = NUM_VAR(map_T[currT] + offset);
|
||||
}
|
||||
ZEND_OP1(opline).var = NUM_VAR(map_T[currT] + offset);
|
||||
}
|
||||
|
||||
/* Skip OP_DATA */
|
||||
@ -135,6 +155,15 @@ void optimize_temporary_variables(zend_op_array *op_array, zend_optimizer_ctx *c
|
||||
taken_T[map_T[currT]] = 0;
|
||||
}
|
||||
ZEND_RESULT(opline).var = NUM_VAR(map_T[currT] + offset);
|
||||
if (opline->opcode == ZEND_ROPE_INIT) {
|
||||
if (start_of_T[currT] == opline) {
|
||||
uint32_t num = ((opline->extended_value * sizeof(zend_string*)) + (sizeof(zval) - 1)) / sizeof(zval);
|
||||
while (num > 1) {
|
||||
num--;
|
||||
taken_T[map_T[currT]+num] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else { /* Au still needs to be assigned a T which is a bit dumb. Should consider changing Zend */
|
||||
GET_AVAILABLE_T();
|
||||
|
||||
|
@ -55,6 +55,7 @@ void zend_optimizer_pass1(zend_op_array *op_array, zend_optimizer_ctx *ctx)
|
||||
case ZEND_SL:
|
||||
case ZEND_SR:
|
||||
case ZEND_CONCAT:
|
||||
case ZEND_FAST_CONCAT:
|
||||
case ZEND_IS_EQUAL:
|
||||
case ZEND_IS_NOT_EQUAL:
|
||||
case ZEND_IS_SMALLER:
|
||||
@ -160,6 +161,7 @@ void zend_optimizer_pass1(zend_op_array *op_array, zend_optimizer_ctx *ctx)
|
||||
}
|
||||
break;
|
||||
|
||||
#if 0
|
||||
case ZEND_ADD_STRING:
|
||||
case ZEND_ADD_CHAR:
|
||||
{
|
||||
@ -230,6 +232,7 @@ void zend_optimizer_pass1(zend_op_array *op_array, zend_optimizer_ctx *ctx)
|
||||
}
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
|
||||
case ZEND_FETCH_CONSTANT:
|
||||
if (ZEND_OP1_TYPE(opline) == IS_UNUSED &&
|
||||
|
@ -90,6 +90,7 @@ void zend_optimizer_pass2(zend_op_array *op_array)
|
||||
break;
|
||||
|
||||
case ZEND_CONCAT:
|
||||
case ZEND_FAST_CONCAT:
|
||||
if (ZEND_OP1_TYPE(opline) == IS_CONST) {
|
||||
if (Z_TYPE(ZEND_OP1_LITERAL(opline)) != IS_STRING) {
|
||||
convert_to_string(&ZEND_OP1_LITERAL(opline));
|
||||
|
@ -141,6 +141,10 @@ void zend_optimizer_update_op1_const(zend_op_array *op_array,
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
if (opline->opcode == ZEND_CONCAT ||
|
||||
opline->opcode == ZEND_FAST_CONCAT) {
|
||||
convert_to_string(val);
|
||||
}
|
||||
opline->op1.constant = zend_optimizer_add_literal(op_array, val);
|
||||
}
|
||||
}
|
||||
@ -158,9 +162,12 @@ void zend_optimizer_update_op2_const(zend_op_array *op_array,
|
||||
Z_CACHE_SLOT(op_array->literals[opline->op2.constant]) = op_array->cache_size;
|
||||
op_array->cache_size += sizeof(void*);
|
||||
return;
|
||||
} else if (opline->opcode == ZEND_ADD_VAR) {
|
||||
} else if (opline->opcode == ZEND_ROPE_INIT ||
|
||||
opline->opcode == ZEND_ROPE_ADD ||
|
||||
opline->opcode == ZEND_ROPE_END ||
|
||||
opline->opcode == ZEND_CONCAT ||
|
||||
opline->opcode == ZEND_FAST_CONCAT) {
|
||||
convert_to_string(val);
|
||||
opline->opcode = ZEND_ADD_STRING;
|
||||
}
|
||||
opline->op2.constant = zend_optimizer_add_literal(op_array, val);
|
||||
if (Z_TYPE_P(val) == IS_STRING) {
|
||||
|
Loading…
Reference in New Issue
Block a user