From 1735e29b7f2703315e606230164c6aca02ab0455 Mon Sep 17 00:00:00 2001 From: Dmitry Stogov Date: Thu, 22 Mar 2018 11:33:17 +0300 Subject: [PATCH] Reduce overhead of extra-specialization for opcode handler selection. --- Zend/zend_vm_execute.h | 71 ++++++++++---------- Zend/zend_vm_gen.php | 146 +++++++++++++++++++++++++---------------- 2 files changed, 129 insertions(+), 88 deletions(-) diff --git a/Zend/zend_vm_execute.h b/Zend/zend_vm_execute.h index 34fdcbd6bb..66915b5ab8 100644 --- a/Zend/zend_vm_execute.h +++ b/Zend/zend_vm_execute.h @@ -307,6 +307,7 @@ static zend_uchar zend_user_opcodes[256] = {0, }; #define SPEC_START_MASK 0x0000ffff +#define SPEC_EXTRA_MASK 0xfffc0000 #define SPEC_RULE_OP1 0x00010000 #define SPEC_RULE_OP2 0x00020000 #define SPEC_RULE_OP_DATA 0x00040000 @@ -64350,23 +64351,25 @@ static const void *zend_vm_get_opcode_handler_ex(uint32_t spec, const zend_op* o uint32_t offset = 0; if (spec & SPEC_RULE_OP1) offset = offset * 5 + zend_vm_decode[op->op1_type]; if (spec & SPEC_RULE_OP2) offset = offset * 5 + zend_vm_decode[op->op2_type]; - if (spec & SPEC_RULE_OP_DATA) offset = offset * 5 + zend_vm_decode[(op + 1)->op1_type]; - if (spec & SPEC_RULE_RETVAL) offset = offset * 2 + (op->result_type != IS_UNUSED); - if (spec & SPEC_RULE_QUICK_ARG) offset = offset * 2 + (op->op2.num < MAX_ARG_FLAG_NUM); - if (spec & SPEC_RULE_SMART_BRANCH) { - offset = offset * 3; - if ((op+1)->opcode == ZEND_JMPZ) { - offset += 1; - } else if ((op+1)->opcode == ZEND_JMPNZ) { - offset += 2; + if (spec & SPEC_EXTRA_MASK) { + if (spec & SPEC_RULE_OP_DATA) offset = offset * 5 + zend_vm_decode[(op + 1)->op1_type]; + else if (spec & SPEC_RULE_RETVAL) offset = offset * 2 + (op->result_type != IS_UNUSED); + else if (spec & SPEC_RULE_QUICK_ARG) offset = offset * 2 + (op->op2.num < MAX_ARG_FLAG_NUM); + else if (spec & SPEC_RULE_SMART_BRANCH) { + offset = offset * 3; + if ((op+1)->opcode == ZEND_JMPZ) { + offset += 1; + } else if ((op+1)->opcode == ZEND_JMPNZ) { + offset += 2; + } } - } - if (spec & SPEC_RULE_DIM_OBJ) { - offset = offset * 3; - if (op->extended_value == ZEND_ASSIGN_DIM) { - offset += 1; - } else if (op->extended_value == ZEND_ASSIGN_OBJ) { - offset += 2; + else if (spec & SPEC_RULE_DIM_OBJ) { + offset = offset * 3; + if (op->extended_value == ZEND_ASSIGN_DIM) { + offset += 1; + } else if (op->extended_value == ZEND_ASSIGN_OBJ) { + offset += 2; + } } } return zend_opcode_handlers[(spec & SPEC_START_MASK) + offset]; @@ -64397,23 +64400,25 @@ static const void *zend_vm_get_opcode_handler_func(zend_uchar opcode, const zend uint32_t offset = 0; if (spec & SPEC_RULE_OP1) offset = offset * 5 + zend_vm_decode[op->op1_type]; if (spec & SPEC_RULE_OP2) offset = offset * 5 + zend_vm_decode[op->op2_type]; - if (spec & SPEC_RULE_OP_DATA) offset = offset * 5 + zend_vm_decode[(op + 1)->op1_type]; - if (spec & SPEC_RULE_RETVAL) offset = offset * 2 + (op->result_type != IS_UNUSED); - if (spec & SPEC_RULE_QUICK_ARG) offset = offset * 2 + (op->op2.num < MAX_ARG_FLAG_NUM); - if (spec & SPEC_RULE_SMART_BRANCH) { - offset = offset * 3; - if ((op+1)->opcode == ZEND_JMPZ) { - offset += 1; - } else if ((op+1)->opcode == ZEND_JMPNZ) { - offset += 2; - } - } - if (spec & SPEC_RULE_DIM_OBJ) { - offset = offset * 3; - if (op->extended_value == ZEND_ASSIGN_DIM) { - offset += 1; - } else if (op->extended_value == ZEND_ASSIGN_OBJ) { - offset += 2; + if (spec & SPEC_EXTRA_MASK) { + if (spec & SPEC_RULE_OP_DATA) offset = offset * 5 + zend_vm_decode[(op + 1)->op1_type]; + else if (spec & SPEC_RULE_RETVAL) offset = offset * 2 + (op->result_type != IS_UNUSED); + else if (spec & SPEC_RULE_QUICK_ARG) offset = offset * 2 + (op->op2.num < MAX_ARG_FLAG_NUM); + else if (spec & SPEC_RULE_SMART_BRANCH) { + offset = offset * 3; + if ((op+1)->opcode == ZEND_JMPZ) { + offset += 1; + } else if ((op+1)->opcode == ZEND_JMPNZ) { + offset += 2; + } + } + else if (spec & SPEC_RULE_DIM_OBJ) { + offset = offset * 3; + if (op->extended_value == ZEND_ASSIGN_DIM) { + offset += 1; + } else if (op->extended_value == ZEND_ASSIGN_OBJ) { + offset += 2; + } } } return zend_opcode_handler_funcs[(spec & SPEC_START_MASK) + offset]; diff --git a/Zend/zend_vm_gen.php b/Zend/zend_vm_gen.php index 03b964b278..74beb1af1d 100644 --- a/Zend/zend_vm_gen.php +++ b/Zend/zend_vm_gen.php @@ -1698,6 +1698,7 @@ function gen_executor($f, $skl, $spec, $kind, $executor_name, $initializer_name) switch ($m[2]) { case "DEFINES": out($f,"#define SPEC_START_MASK 0x0000ffff\n"); + out($f,"#define SPEC_EXTRA_MASK 0xfffc0000\n"); out($f,"#define SPEC_RULE_OP1 0x00010000\n"); out($f,"#define SPEC_RULE_OP2 0x00020000\n"); out($f,"#define SPEC_RULE_OP_DATA 0x00040000\n"); @@ -2564,33 +2565,50 @@ function gen_vm($def, $skel) { out($f, "\tuint32_t offset = 0;\n"); out($f, "\tif (spec & SPEC_RULE_OP1) offset = offset * 5 + zend_vm_decode[op->op1_type];\n"); out($f, "\tif (spec & SPEC_RULE_OP2) offset = offset * 5 + zend_vm_decode[op->op2_type];\n"); - if (isset($used_extra_spec["OP_DATA"])) { - out($f, "\tif (spec & SPEC_RULE_OP_DATA) offset = offset * 5 + zend_vm_decode[(op + 1)->op1_type];\n"); - } - if (isset($used_extra_spec["RETVAL"])) { - out($f, "\tif (spec & SPEC_RULE_RETVAL) offset = offset * 2 + (op->result_type != IS_UNUSED);\n"); - } - if (isset($used_extra_spec["QUICK_ARG"])) { - out($f, "\tif (spec & SPEC_RULE_QUICK_ARG) offset = offset * 2 + (op->op2.num < MAX_ARG_FLAG_NUM);\n"); - } - if (isset($used_extra_spec["SMART_BRANCH"])) { - out($f, "\tif (spec & SPEC_RULE_SMART_BRANCH) {\n"); - out($f, "\t\toffset = offset * 3;\n"); - out($f, "\t\tif ((op+1)->opcode == ZEND_JMPZ) {\n"); - out($f, "\t\t\toffset += 1;\n"); - out($f, "\t\t} else if ((op+1)->opcode == ZEND_JMPNZ) {\n"); - out($f, "\t\t\toffset += 2;\n"); - out($f, "\t\t}\n"); - out($f, "\t}\n"); - } - if (isset($used_extra_spec["DIM_OBJ"])) { - out($f, "\tif (spec & SPEC_RULE_DIM_OBJ) {\n"); - out($f, "\t\toffset = offset * 3;\n"); - out($f, "\t\tif (op->extended_value == ZEND_ASSIGN_DIM) {\n"); - out($f, "\t\t\toffset += 1;\n"); - out($f, "\t\t} else if (op->extended_value == ZEND_ASSIGN_OBJ) {\n"); - out($f, "\t\t\toffset += 2;\n"); - out($f, "\t\t}\n"); + + if (isset($used_extra_spec["OP_DATA"]) || + isset($used_extra_spec["RETVAL"]) || + isset($used_extra_spec["QUICK_ARG"]) || + isset($used_extra_spec["SMART_BRANCH"]) || + isset($used_extra_spec["DIM_OBJ"])) { + + $else = ""; + out($f, "\tif (spec & SPEC_EXTRA_MASK) {\n"); + + if (isset($used_extra_spec["OP_DATA"])) { + out($f, "\t\t{$else}if (spec & SPEC_RULE_OP_DATA) offset = offset * 5 + zend_vm_decode[(op + 1)->op1_type];\n"); + $else = "else "; + } + if (isset($used_extra_spec["RETVAL"])) { + out($f, "\t\t{$else}if (spec & SPEC_RULE_RETVAL) offset = offset * 2 + (op->result_type != IS_UNUSED);\n"); + $else = "else "; + } + if (isset($used_extra_spec["QUICK_ARG"])) { + out($f, "\t\t{$else}if (spec & SPEC_RULE_QUICK_ARG) offset = offset * 2 + (op->op2.num < MAX_ARG_FLAG_NUM);\n"); + $else = "else "; + } + if (isset($used_extra_spec["SMART_BRANCH"])) { + out($f, "\t\t{$else}if (spec & SPEC_RULE_SMART_BRANCH) {\n"); + out($f, "\t\t\toffset = offset * 3;\n"); + out($f, "\t\t\tif ((op+1)->opcode == ZEND_JMPZ) {\n"); + out($f, "\t\t\t\toffset += 1;\n"); + out($f, "\t\t\t} else if ((op+1)->opcode == ZEND_JMPNZ) {\n"); + out($f, "\t\t\t\toffset += 2;\n"); + out($f, "\t\t\t}\n"); + out($f, "\t\t}\n"); + $else = "else "; + } + if (isset($used_extra_spec["DIM_OBJ"])) { + out($f, "\t\t{$else}if (spec & SPEC_RULE_DIM_OBJ) {\n"); + out($f, "\t\t\toffset = offset * 3;\n"); + out($f, "\t\t\tif (op->extended_value == ZEND_ASSIGN_DIM) {\n"); + out($f, "\t\t\t\toffset += 1;\n"); + out($f, "\t\t\t} else if (op->extended_value == ZEND_ASSIGN_OBJ) {\n"); + out($f, "\t\t\t\toffset += 2;\n"); + out($f, "\t\t\t}\n"); + out($f, "\t\t}\n"); + $else = "else "; + } out($f, "\t}\n"); } out($f, "\treturn zend_opcode_handlers[(spec & SPEC_START_MASK) + offset];\n"); @@ -2630,35 +2648,53 @@ function gen_vm($def, $skel) { out($f, "\tuint32_t offset = 0;\n"); out($f, "\tif (spec & SPEC_RULE_OP1) offset = offset * 5 + zend_vm_decode[op->op1_type];\n"); out($f, "\tif (spec & SPEC_RULE_OP2) offset = offset * 5 + zend_vm_decode[op->op2_type];\n"); - if (isset($used_extra_spec["OP_DATA"])) { - out($f, "\tif (spec & SPEC_RULE_OP_DATA) offset = offset * 5 + zend_vm_decode[(op + 1)->op1_type];\n"); - } - if (isset($used_extra_spec["RETVAL"])) { - out($f, "\tif (spec & SPEC_RULE_RETVAL) offset = offset * 2 + (op->result_type != IS_UNUSED);\n"); - } - if (isset($used_extra_spec["QUICK_ARG"])) { - out($f, "\tif (spec & SPEC_RULE_QUICK_ARG) offset = offset * 2 + (op->op2.num < MAX_ARG_FLAG_NUM);\n"); - } - if (isset($used_extra_spec["SMART_BRANCH"])) { - out($f, "\tif (spec & SPEC_RULE_SMART_BRANCH) {\n"); - out($f, "\t\toffset = offset * 3;\n"); - out($f, "\t\tif ((op+1)->opcode == ZEND_JMPZ) {\n"); - out($f, "\t\t\toffset += 1;\n"); - out($f, "\t\t} else if ((op+1)->opcode == ZEND_JMPNZ) {\n"); - out($f, "\t\t\toffset += 2;\n"); - out($f, "\t\t}\n"); - out($f, "\t}\n"); - } - if (isset($used_extra_spec["DIM_OBJ"])) { - out($f, "\tif (spec & SPEC_RULE_DIM_OBJ) {\n"); - out($f, "\t\toffset = offset * 3;\n"); - out($f, "\t\tif (op->extended_value == ZEND_ASSIGN_DIM) {\n"); - out($f, "\t\t\toffset += 1;\n"); - out($f, "\t\t} else if (op->extended_value == ZEND_ASSIGN_OBJ) {\n"); - out($f, "\t\t\toffset += 2;\n"); - out($f, "\t\t}\n"); + + if (isset($used_extra_spec["OP_DATA"]) || + isset($used_extra_spec["RETVAL"]) || + isset($used_extra_spec["QUICK_ARG"]) || + isset($used_extra_spec["SMART_BRANCH"]) || + isset($used_extra_spec["DIM_OBJ"])) { + + $else = ""; + out($f, "\tif (spec & SPEC_EXTRA_MASK) {\n"); + + if (isset($used_extra_spec["OP_DATA"])) { + out($f, "\t\t{$else}if (spec & SPEC_RULE_OP_DATA) offset = offset * 5 + zend_vm_decode[(op + 1)->op1_type];\n"); + $else = "else "; + } + if (isset($used_extra_spec["RETVAL"])) { + out($f, "\t\t{$else}if (spec & SPEC_RULE_RETVAL) offset = offset * 2 + (op->result_type != IS_UNUSED);\n"); + $else = "else "; + } + if (isset($used_extra_spec["QUICK_ARG"])) { + out($f, "\t\t{$else}if (spec & SPEC_RULE_QUICK_ARG) offset = offset * 2 + (op->op2.num < MAX_ARG_FLAG_NUM);\n"); + $else = "else "; + } + if (isset($used_extra_spec["SMART_BRANCH"])) { + out($f, "\t\t{$else}if (spec & SPEC_RULE_SMART_BRANCH) {\n"); + out($f, "\t\t\toffset = offset * 3;\n"); + out($f, "\t\t\tif ((op+1)->opcode == ZEND_JMPZ) {\n"); + out($f, "\t\t\t\toffset += 1;\n"); + out($f, "\t\t\t} else if ((op+1)->opcode == ZEND_JMPNZ) {\n"); + out($f, "\t\t\t\toffset += 2;\n"); + out($f, "\t\t\t}\n"); + out($f, "\t\t}\n"); + $else = "else "; + } + if (isset($used_extra_spec["DIM_OBJ"])) { + out($f, "\t\t{$else}if (spec & SPEC_RULE_DIM_OBJ) {\n"); + out($f, "\t\t\toffset = offset * 3;\n"); + out($f, "\t\t\tif (op->extended_value == ZEND_ASSIGN_DIM) {\n"); + out($f, "\t\t\t\toffset += 1;\n"); + out($f, "\t\t\t} else if (op->extended_value == ZEND_ASSIGN_OBJ) {\n"); + out($f, "\t\t\t\toffset += 2;\n"); + out($f, "\t\t\t}\n"); + out($f, "\t\t}\n"); + $else = "else "; + } out($f, "\t}\n"); - } + } + out($f, "\treturn zend_opcode_handler_funcs[(spec & SPEC_START_MASK) + offset];\n"); } out($f, "}\n\n"); -- 2.40.0