From a7580899f3e236f8a2f642a01df9cd07d49a7fa8 Mon Sep 17 00:00:00 2001 From: Tyson Andre Date: Wed, 13 Nov 2019 09:10:22 -0500 Subject: [PATCH] Support the same handler for multiple opcodes --- Zend/zend_vm_def.h | 22 +++++++++++----------- Zend/zend_vm_execute.h | 34 ++++++++++++++++++++++++++++++++-- Zend/zend_vm_gen.php | 31 ++++++++++++------------------- 3 files changed, 55 insertions(+), 32 deletions(-) diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h index a8ab1ff375..0dfa91e384 100644 --- a/Zend/zend_vm_def.h +++ b/Zend/zend_vm_def.h @@ -1496,7 +1496,7 @@ ZEND_VM_HELPER(zend_pre_dec_helper, VAR|CV, ANY) SAVE_OPLINE(); if (OP1_TYPE == IS_CV && UNEXPECTED(Z_TYPE_P(var_ptr) == IS_UNDEF)) { - ZVAL_NULL(var_ptr); + ZVAL_NULL(var_ptr); ZVAL_UNDEFINED_OP1(); } @@ -2234,7 +2234,7 @@ ZEND_VM_C_LABEL(fetch_obj_is_fast_copy): } retval = zobj->handlers->read_property(zobj, name, BP_VAR_IS, cache_slot, EX_VAR(opline->result.var)); - + if (OP2_TYPE != IS_CONST) { zend_tmp_string_release(tmp_name); } @@ -5528,10 +5528,10 @@ ZEND_VM_HANDLER(147, ZEND_ADD_ARRAY_UNPACK, ANY, ANY) { USE_OPLINE zval *op1; - + SAVE_OPLINE(); op1 = GET_OP1_ZVAL_PTR(BP_VAR_R); - + ZEND_VM_C_LABEL(add_unpack_again): if (EXPECTED(Z_TYPE_P(op1) == IS_ARRAY)) { HashTable *ht = Z_ARRVAL_P(op1); @@ -5572,11 +5572,11 @@ ZEND_VM_C_LABEL(add_unpack_again): } HANDLE_EXCEPTION(); } - + if (iter->funcs->rewind) { iter->funcs->rewind(iter); } - + for (; iter->funcs->valid(iter) == SUCCESS; ) { zval *val; @@ -5625,7 +5625,7 @@ ZEND_VM_C_LABEL(add_unpack_again): } else { zend_throw_error(NULL, "Only arrays and Traversables can be unpacked"); } - + FREE_OP1(); ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); } @@ -8677,7 +8677,7 @@ ZEND_VM_HOT_TYPE_SPEC_HANDLER(ZEND_MUL, (op1_info == MAY_BE_DOUBLE && op2_info = ZEND_VM_NEXT_OPCODE(); } -ZEND_VM_HOT_TYPE_SPEC_HANDLER(ZEND_IS_EQUAL, (op1_info == MAY_BE_LONG && op2_info == MAY_BE_LONG), ZEND_IS_EQUAL_LONG, CONST|TMPVARCV, CONST|TMPVARCV, SPEC(SMART_BRANCH,NO_CONST_CONST,COMMUTATIVE)) +ZEND_VM_HOT_TYPE_SPEC_HANDLER(ZEND_IS_EQUAL|ZEND_IS_IDENTICAL, (op1_info == MAY_BE_LONG && op2_info == MAY_BE_LONG), ZEND_IS_EQUAL_LONG, CONST|TMPVARCV, CONST|TMPVARCV, SPEC(SMART_BRANCH,NO_CONST_CONST,COMMUTATIVE)) { USE_OPLINE zval *op1, *op2; @@ -8689,7 +8689,7 @@ ZEND_VM_HOT_TYPE_SPEC_HANDLER(ZEND_IS_EQUAL, (op1_info == MAY_BE_LONG && op2_inf ZEND_VM_SMART_BRANCH(result, 0); } -ZEND_VM_HOT_TYPE_SPEC_HANDLER(ZEND_IS_EQUAL, (op1_info == MAY_BE_DOUBLE && op2_info == MAY_BE_DOUBLE), ZEND_IS_EQUAL_DOUBLE, CONST|TMPVARCV, CONST|TMPVARCV, SPEC(SMART_BRANCH,NO_CONST_CONST,COMMUTATIVE)) +ZEND_VM_HOT_TYPE_SPEC_HANDLER(ZEND_IS_EQUAL|ZEND_IS_IDENTICAL, (op1_info == MAY_BE_DOUBLE && op2_info == MAY_BE_DOUBLE), ZEND_IS_EQUAL_DOUBLE, CONST|TMPVARCV, CONST|TMPVARCV, SPEC(SMART_BRANCH,NO_CONST_CONST,COMMUTATIVE)) { USE_OPLINE zval *op1, *op2; @@ -8701,7 +8701,7 @@ ZEND_VM_HOT_TYPE_SPEC_HANDLER(ZEND_IS_EQUAL, (op1_info == MAY_BE_DOUBLE && op2_i ZEND_VM_SMART_BRANCH(result, 0); } -ZEND_VM_HOT_TYPE_SPEC_HANDLER(ZEND_IS_NOT_EQUAL, (op1_info == MAY_BE_LONG && op2_info == MAY_BE_LONG), ZEND_IS_NOT_EQUAL_LONG, CONST|TMPVARCV, CONST|TMPVARCV, SPEC(SMART_BRANCH,NO_CONST_CONST,COMMUTATIVE)) +ZEND_VM_HOT_TYPE_SPEC_HANDLER(ZEND_IS_NOT_EQUAL|ZEND_IS_NOT_IDENTICAL, (op1_info == MAY_BE_LONG && op2_info == MAY_BE_LONG), ZEND_IS_NOT_EQUAL_LONG, CONST|TMPVARCV, CONST|TMPVARCV, SPEC(SMART_BRANCH,NO_CONST_CONST,COMMUTATIVE)) { USE_OPLINE zval *op1, *op2; @@ -8713,7 +8713,7 @@ ZEND_VM_HOT_TYPE_SPEC_HANDLER(ZEND_IS_NOT_EQUAL, (op1_info == MAY_BE_LONG && op2 ZEND_VM_SMART_BRANCH(result, 0); } -ZEND_VM_HOT_TYPE_SPEC_HANDLER(ZEND_IS_NOT_EQUAL, (op1_info == MAY_BE_DOUBLE && op2_info == MAY_BE_DOUBLE), ZEND_IS_NOT_EQUAL_DOUBLE, CONST|TMPVARCV, CONST|TMPVARCV, SPEC(SMART_BRANCH,NO_CONST_CONST,COMMUTATIVE)) +ZEND_VM_HOT_TYPE_SPEC_HANDLER(ZEND_IS_NOT_EQUAL|ZEND_IS_NOT_IDENTICAL, (op1_info == MAY_BE_DOUBLE && op2_info == MAY_BE_DOUBLE), ZEND_IS_NOT_EQUAL_DOUBLE, CONST|TMPVARCV, CONST|TMPVARCV, SPEC(SMART_BRANCH,NO_CONST_CONST,COMMUTATIVE)) { USE_OPLINE zval *op1, *op2; diff --git a/Zend/zend_vm_execute.h b/Zend/zend_vm_execute.h index fec62d8dc0..812a7e5bd2 100644 --- a/Zend/zend_vm_execute.h +++ b/Zend/zend_vm_execute.h @@ -59193,7 +59193,6 @@ ZEND_API void ZEND_FASTCALL zend_vm_set_opcode_handler_ex(zend_op* op, uint32_t spec = 2512 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_COMMUTATIVE; } break; - case ZEND_IS_EQUAL: case ZEND_IS_IDENTICAL: if (op->op1_type < op->op2_type) { zend_swap_operands(op); @@ -59210,7 +59209,6 @@ ZEND_API void ZEND_FASTCALL zend_vm_set_opcode_handler_ex(zend_op* op, uint32_t spec = 2612 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_SMART_BRANCH | SPEC_RULE_COMMUTATIVE; } break; - case ZEND_IS_NOT_EQUAL: case ZEND_IS_NOT_IDENTICAL: if (op->op1_type < op->op2_type) { zend_swap_operands(op); @@ -59227,6 +59225,38 @@ ZEND_API void ZEND_FASTCALL zend_vm_set_opcode_handler_ex(zend_op* op, uint32_t spec = 2762 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_SMART_BRANCH | SPEC_RULE_COMMUTATIVE; } break; + case ZEND_IS_EQUAL: + if (op->op1_type < op->op2_type) { + zend_swap_operands(op); + } + if (op1_info == MAY_BE_LONG && op2_info == MAY_BE_LONG) { + if (op->op1_type == IS_CONST && op->op2_type == IS_CONST) { + break; + } + spec = 2537 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_SMART_BRANCH | SPEC_RULE_COMMUTATIVE; + } else if (op1_info == MAY_BE_DOUBLE && op2_info == MAY_BE_DOUBLE) { + if (op->op1_type == IS_CONST && op->op2_type == IS_CONST) { + break; + } + spec = 2612 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_SMART_BRANCH | SPEC_RULE_COMMUTATIVE; + } + break; + case ZEND_IS_NOT_EQUAL: + if (op->op1_type < op->op2_type) { + zend_swap_operands(op); + } + if (op1_info == MAY_BE_LONG && op2_info == MAY_BE_LONG) { + if (op->op1_type == IS_CONST && op->op2_type == IS_CONST) { + break; + } + spec = 2687 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_SMART_BRANCH | SPEC_RULE_COMMUTATIVE; + } else if (op1_info == MAY_BE_DOUBLE && op2_info == MAY_BE_DOUBLE) { + if (op->op1_type == IS_CONST && op->op2_type == IS_CONST) { + break; + } + spec = 2762 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_SMART_BRANCH | SPEC_RULE_COMMUTATIVE; + } + break; case ZEND_IS_SMALLER: if (op1_info == MAY_BE_LONG && op2_info == MAY_BE_LONG) { if (op->op1_type == IS_CONST && op->op2_type == IS_CONST) { diff --git a/Zend/zend_vm_gen.php b/Zend/zend_vm_gen.php index 47975b3940..ccf23613f7 100755 --- a/Zend/zend_vm_gen.php +++ b/Zend/zend_vm_gen.php @@ -2394,19 +2394,22 @@ function gen_vm($def, $skel) { strpos($line,"ZEND_VM_HOT_OBJ_TYPE_SPEC_HANDLER(") === 0) { // Parsing opcode handler's definition if (preg_match( - "/^ZEND_VM_(HOT_|INLINE_|HOT_OBJ_|HOT_SEND_|HOT_NOCONST_|HOT_NOCONSTCONST_)?TYPE_SPEC_HANDLER\(\s*([A-Z_]+)\s*,\s*((?:[^(,]|\([^()]*|(?R)*\))*),\s*([A-Za-z_]+)\s*,\s*([A-Z_|]+)\s*,\s*([A-Z_|]+)\s*(,\s*([A-Z_|]+)\s*)?(,\s*SPEC\(([A-Z_|=,]+)\)\s*)?\)/", + "/^ZEND_VM_(HOT_|INLINE_|HOT_OBJ_|HOT_SEND_|HOT_NOCONST_|HOT_NOCONSTCONST_)?TYPE_SPEC_HANDLER\(\s*([A-Z_|]+)\s*,\s*((?:[^(,]|\([^()]*|(?R)*\))*),\s*([A-Za-z_]+)\s*,\s*([A-Z_|]+)\s*,\s*([A-Z_|]+)\s*(,\s*([A-Z_|]+)\s*)?(,\s*SPEC\(([A-Z_|=,]+)\)\s*)?\)/", $line, $m) == 0) { die("ERROR ($def:$lineno): Invalid ZEND_VM_TYPE_HANDLER_HANDLER definition.\n"); } $hot = !empty($m[1]) ? $m[1] : false; - $orig_op = $m[2]; - if (!isset($opnames[$orig_op])) { - die("ERROR ($def:$lineno): Opcode with name '$orig_op' is not defined.\n"); - } - $orig_code = $opnames[$orig_op]; - $condition = $m[3]; + $orig_op_list = $m[2]; $code = $extra_num++; + foreach (explode('|', $orig_op_list) as $orig_op) { + if (!isset($opnames[$orig_op])) { + die("ERROR ($def:$lineno): Opcode with name '$orig_op' is not defined.\n"); + } + $orig_code = $opnames[$orig_op]; + $condition = $m[3]; + $opcodes[$orig_code]['type_spec'][$code] = $condition; + } $op = $m[4]; $op1 = parse_operand_spec($def, $lineno, $m[5], $flags1); $op2 = parse_operand_spec($def, $lineno, $m[6], $flags2); @@ -2418,7 +2421,6 @@ function gen_vm($def, $skel) { if (isset($opcodes[$code])) { die("ERROR ($def:$lineno): Opcode with name '$code' is already defined.\n"); } - $opcodes[$orig_code]['type_spec'][$code] = $condition; $used_extra_spec["TYPE"] = 1; $opcodes[$code] = array("op"=>$op,"op1"=>$op1,"op2"=>$op2,"code"=>"","flags"=>$flags,"hot"=>$hot,"is_type_spec"=>true); if (isset($m[10])) { @@ -2818,13 +2820,6 @@ function gen_vm($def, $skel) { if (isset($dsc['type_spec'])) { $orig_op = $dsc['op']; out($f, "\t\tcase $orig_op:\n"); - // XXX: Copy the specializations for LONG == LONG and DOUBLE != DOUBLE to work for ===/!== as well. - // (Those are currently the only specializations) - if ($orig_op === 'ZEND_IS_EQUAL') { - out($f, "\t\tcase ZEND_IS_IDENTICAL:\n"); - } elseif ($orig_op === 'ZEND_IS_NOT_EQUAL') { - out($f, "\t\tcase ZEND_IS_NOT_IDENTICAL:\n"); - } if (isset($dsc["spec"]["COMMUTATIVE"])) { out($f, "\t\t\tif (op->op1_type < op->op2_type) {\n"); out($f, "\t\t\t\tzend_swap_operands(op);\n"); @@ -2864,10 +2859,8 @@ function gen_vm($def, $skel) { !isset($dsc['type_spec']) && isset($dsc["spec"]["COMMUTATIVE"])) { $orig_op = $dsc['op']; - if (!in_array($orig_op, ['ZEND_IS_IDENTICAL', 'ZEND_IS_NOT_IDENTICAL'])) { - out($f, "\t\tcase $orig_op:\n"); - $has_commutative = true; - } + out($f, "\t\tcase $orig_op:\n"); + $has_commutative = true; } } if ($has_commutative) { -- 2.50.1