Skip to content

Commit cbd51cc

Browse files
committed
zend_vm_gen.php: Make room for new ZEND_VM_ flags
Split OP flags and EXT flags in two separate sets, in zend_vm_gen.php to maintain 32bit support. In Zend/zend_vm_opcodes.c we can unify them again.
1 parent 8c42cf4 commit cbd51cc

File tree

5 files changed

+348
-306
lines changed

5 files changed

+348
-306
lines changed

Zend/Optimizer/zend_dump.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -460,7 +460,7 @@ static void zend_dump_range_constraint(const zend_op_array *op_array, const zend
460460
ZEND_API void zend_dump_op(const zend_op_array *op_array, const zend_basic_block *b, const zend_op *opline, uint32_t dump_flags, const zend_ssa *ssa, const zend_ssa_op *ssa_op)
461461
{
462462
const char *name = zend_get_opcode_name(opline->opcode);
463-
uint32_t flags = zend_get_opcode_flags(opline->opcode);
463+
uint64_t flags = zend_get_opcode_flags(opline->opcode);
464464
uint32_t n = 0;
465465

466466
if (!ssa_op || ssa_op->result_use < 0) {

Zend/zend_vm_gen.php

Lines changed: 91 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -55,30 +55,50 @@
5555
const ZEND_VM_KIND_HYBRID = 4;
5656
const ZEND_VM_KIND_TAILCALL = 5;
5757

58+
// Per-operand flags
59+
// ZEND_VM_OP[12]_FLAGS(zend_get_opcode_flags(opcode))
5860
$vm_op_flags = array(
59-
"ZEND_VM_OP_SPEC" => 1<<0,
60-
"ZEND_VM_OP_CONST" => 1<<1,
61-
"ZEND_VM_OP_TMPVAR" => 1<<2,
62-
"ZEND_VM_OP_TMPVARCV" => 1<<3,
63-
"ZEND_VM_OP_MASK" => 0xf0,
64-
"ZEND_VM_OP_NUM" => 0x10,
65-
"ZEND_VM_OP_JMP_ADDR" => 0x20,
66-
"ZEND_VM_OP_TRY_CATCH" => 0x30,
67-
"ZEND_VM_OP_LOOP_END" => 0x40,
68-
"ZEND_VM_OP_THIS" => 0x50,
69-
"ZEND_VM_OP_NEXT" => 0x60,
70-
"ZEND_VM_OP_CLASS_FETCH" => 0x70,
71-
"ZEND_VM_OP_CONSTRUCTOR" => 0x80,
72-
"ZEND_VM_OP_CONST_FETCH" => 0x90,
73-
"ZEND_VM_OP_CACHE_SLOT" => 0xa0,
61+
"ZEND_VM_OP_SHIFT" => 16,
62+
63+
// An operand can have zero of more of these:
64+
"ZEND_VM_OP_SPEC_MASK" => 0xff,
65+
"ZEND_VM_OP_CONST" => 1<<0,
66+
"ZEND_VM_OP_TMP" => 1<<1,
67+
"ZEND_VM_OP_VAR" => 1<<2,
68+
"ZEND_VM_OP_UNUSED" => 1<<3,
69+
"ZEND_VM_OP_CV" => 1<<4,
70+
"ZEND_VM_OP_TMPVAR" => 1<<5,
71+
"ZEND_VM_OP_TMPVARCV" => 1<<6,
72+
// unused in ZEND_VM_OP_SPEC_MASK: (1<<7)
73+
74+
// unused: (1<<8)-(1<<11)
75+
76+
// An operand can have at most one of these:
77+
"ZEND_VM_OP_MASK" => 0xf000,
78+
"ZEND_VM_OP_NUM" => 1<<12,
79+
"ZEND_VM_OP_JMP_ADDR" => 2<<12,
80+
"ZEND_VM_OP_TRY_CATCH" => 3<<12,
81+
"ZEND_VM_OP_LOOP_END" => 4<<12,
82+
"ZEND_VM_OP_THIS" => 5<<12,
83+
"ZEND_VM_OP_NEXT" => 6<<12,
84+
"ZEND_VM_OP_CLASS_FETCH" => 7<<12,
85+
"ZEND_VM_OP_CONSTRUCTOR" => 8<<12,
86+
"ZEND_VM_OP_CONST_FETCH" => 9<<12,
87+
"ZEND_VM_OP_CACHE_SLOT" => 10<<12,
88+
// unused in ZEND_VM_OP_MASK: (11<<12)-(15<<12)
89+
);
90+
91+
// Opcode-level flags
92+
$vm_ext_flags = array(
93+
// unused: bits (1<<0)-(1<<15)
7494

7595
"ZEND_VM_EXT_VAR_FETCH" => 1<<16,
7696
"ZEND_VM_EXT_ISSET" => 1<<17,
7797
"ZEND_VM_EXT_CACHE_SLOT" => 1<<18,
7898
"ZEND_VM_EXT_ARRAY_INIT" => 1<<19,
7999
"ZEND_VM_EXT_REF" => 1<<20,
80100
"ZEND_VM_EXT_FETCH_REF" => 1<<21,
81-
"ZEND_VM_EXT_DIM_WRITE" => 1<<22,
101+
"ZEND_VM_EXT_DIM_WRITE" => 1<<22,
82102
"ZEND_VM_EXT_MASK" => 0x0f000000,
83103
"ZEND_VM_EXT_NUM" => 0x01000000,
84104
"ZEND_VM_EXT_LAST_CATCH" => 0x02000000,
@@ -100,15 +120,19 @@
100120
define($name, $val);
101121
}
102122

123+
foreach ($vm_ext_flags as $name => $val) {
124+
define($name, $val);
125+
}
126+
103127
$vm_op_decode = array(
104128
"ANY" => 0,
105-
"CONST" => ZEND_VM_OP_SPEC | ZEND_VM_OP_CONST,
106-
"TMP" => ZEND_VM_OP_SPEC,
107-
"VAR" => ZEND_VM_OP_SPEC,
108-
"UNUSED" => ZEND_VM_OP_SPEC,
109-
"CV" => ZEND_VM_OP_SPEC,
110-
"TMPVAR" => ZEND_VM_OP_SPEC | ZEND_VM_OP_TMPVAR,
111-
"TMPVARCV" => ZEND_VM_OP_SPEC | ZEND_VM_OP_TMPVARCV,
129+
"CONST" => ZEND_VM_OP_CONST,
130+
"TMP" => ZEND_VM_OP_TMP,
131+
"VAR" => ZEND_VM_OP_VAR,
132+
"UNUSED" => ZEND_VM_OP_UNUSED,
133+
"CV" => ZEND_VM_OP_CV,
134+
"TMPVAR" => ZEND_VM_OP_TMPVAR,
135+
"TMPVARCV" => ZEND_VM_OP_TMPVARCV,
112136
"NUM" => ZEND_VM_OP_NUM,
113137
"JMP_ADDR" => ZEND_VM_OP_JMP_ADDR,
114138
"TRY_CATCH" => ZEND_VM_OP_TRY_CATCH,
@@ -2389,7 +2413,7 @@ function parse_operand_spec($def, $lineno, $str, &$flags) {
23892413
die("ERROR ($def:$lineno): Wrong operand type '$str'\n");
23902414
}
23912415
}
2392-
if (!($flags & ZEND_VM_OP_SPEC)) {
2416+
if (!($flags & ZEND_VM_OP_SPEC_MASK)) {
23932417
if (count($a) != 1) {
23942418
die("ERROR ($def:$lineno): Wrong operand type '$str'\n");
23952419
}
@@ -2398,18 +2422,32 @@ function parse_operand_spec($def, $lineno, $str, &$flags) {
23982422
return array_flip($a);
23992423
}
24002424

2401-
function parse_ext_spec($def, $lineno, $str) {
2425+
function parse_ext_spec($def, $lineno, $str, $spec_str) {
24022426
global $vm_ext_decode;
24032427

24042428
$flags = 0;
2405-
$a = explode("|",$str);
2406-
foreach ($a as $val) {
2407-
if (isset($vm_ext_decode[$val])) {
2408-
$flags |= $vm_ext_decode[$val];
2409-
} else {
2410-
die("ERROR ($def:$lineno): Wrong extended_value type '$str'\n");
2429+
2430+
if ($str !== '') {
2431+
$a = explode("|",$str);
2432+
foreach ($a as $val) {
2433+
if (isset($vm_ext_decode[$val])) {
2434+
$flags |= $vm_ext_decode[$val];
2435+
} else {
2436+
die("ERROR ($def:$lineno): Wrong extended_value type '$str'\n");
2437+
}
2438+
}
2439+
}
2440+
if ($spec_str !== '') {
2441+
$a = explode(",",$spec_str);
2442+
foreach ($a as $val) {
2443+
if (isset($vm_ext_decode[$val])) {
2444+
$flags |= $vm_ext_decode[$val];
2445+
} else {
2446+
// Spec flags are validated separately.
2447+
}
24112448
}
24122449
}
2450+
24132451
return $flags;
24142452
}
24152453

@@ -2464,7 +2502,7 @@ function parse_spec_rules($def, $lineno, $str) {
24642502
}
24652503

24662504
function gen_vm_opcodes_header(
2467-
array $opcodes, int $max_opcode, int $max_opcode_len, array $vm_op_flags
2505+
array $opcodes, int $max_opcode, int $max_opcode_len, array $vm_op_flags, array $vm_ext_flags
24682506
): string {
24692507
$str = HEADER_TEXT;
24702508
$str .= "#ifndef ZEND_VM_OPCODES_H\n#define ZEND_VM_OPCODES_H\n\n";
@@ -2538,12 +2576,15 @@ function gen_vm_opcodes_header(
25382576
foreach ($vm_op_flags as $name => $val) {
25392577
$str .= sprintf("#define %-24s 0x%08x\n", $name, $val);
25402578
}
2541-
$str .= "#define ZEND_VM_OP1_FLAGS(flags) (flags & 0xff)\n";
2542-
$str .= "#define ZEND_VM_OP2_FLAGS(flags) ((flags >> 8) & 0xff)\n";
2579+
foreach ($vm_ext_flags as $name => $val) {
2580+
$str .= sprintf("#define %-24s (UINT64_C(0x%08x) << 32)\n", $name, $val);
2581+
}
2582+
$str .= sprintf("#define ZEND_VM_OP1_FLAGS(flags) (flags & 0x%08x)\n", (1<<ZEND_VM_OP_SHIFT)-1);
2583+
$str .= sprintf("#define ZEND_VM_OP2_FLAGS(flags) ((flags >> %d) & 0x%08x)\n", ZEND_VM_OP_SHIFT, (1<<ZEND_VM_OP_SHIFT)-1);
25432584
$str .= "\n";
25442585
$str .= "BEGIN_EXTERN_C()\n\n";
25452586
$str .= "ZEND_API const char* ZEND_FASTCALL zend_get_opcode_name(uint8_t opcode);\n";
2546-
$str .= "ZEND_API uint32_t ZEND_FASTCALL zend_get_opcode_flags(uint8_t opcode);\n";
2587+
$str .= "ZEND_API uint64_t ZEND_FASTCALL zend_get_opcode_flags(uint8_t opcode);\n";
25472588
$str .= "ZEND_API uint8_t zend_get_opcode_id(const char *name, size_t length);\n\n";
25482589
$str .= "END_EXTERN_C()\n\n";
25492590

@@ -2567,7 +2608,7 @@ function gen_vm_opcodes_header(
25672608
function gen_vm($def, $skel) {
25682609
global $definition_file, $skeleton_file, $executor_file,
25692610
$op_types, $list, $opcodes, $helpers, $params, $opnames,
2570-
$vm_op_flags, $used_extra_spec;
2611+
$vm_op_flags, $vm_ext_flags, $used_extra_spec;
25712612

25722613
// Load definition file
25732614
$in = @file($def);
@@ -2632,10 +2673,8 @@ function gen_vm($def, $skel) {
26322673
$len = strlen($op);
26332674
$op1 = parse_operand_spec($def, $lineno, $m[4], $flags1);
26342675
$op2 = parse_operand_spec($def, $lineno, $m[5], $flags2);
2635-
$flags = $flags1 | ($flags2 << 8);
2636-
if (!empty($m[7])) {
2637-
$flags |= parse_ext_spec($def, $lineno, $m[7]);
2638-
}
2676+
$flags = $flags1 | ($flags2 << ZEND_VM_OP_SHIFT);
2677+
$ext_flags = parse_ext_spec($def, $lineno, $m[7] ?? '', $m[9] ?? '');
26392678

26402679
if ($len > $max_opcode_len) {
26412680
$max_opcode_len = $len;
@@ -2649,14 +2688,14 @@ function gen_vm($def, $skel) {
26492688
if (isset($opnames[$op])) {
26502689
die("ERROR ($def:$lineno): Opcode with name '$op' is already defined.\n");
26512690
}
2652-
$opcodes[$code] = array("op"=>$op,"op1"=>$op1,"op2"=>$op2,"code"=>"","flags"=>$flags,"hot"=>$hot);
2691+
$opcodes[$code] = array("op"=>$op,"op1"=>$op1,"op2"=>$op2,"code"=>"","flags"=>$flags,"ext_flags"=>$ext_flags,"hot"=>$hot);
26532692
if (isset($m[9])) {
26542693
$opcodes[$code]["spec"] = parse_spec_rules($def, $lineno, $m[9]);
26552694
if (isset($opcodes[$code]["spec"]["NO_CONST_CONST"])) {
2656-
$opcodes[$code]["flags"] |= $vm_op_flags["ZEND_VM_NO_CONST_CONST"];
2695+
$opcodes[$code]["ext_flags"] |= ZEND_VM_NO_CONST_CONST;
26572696
}
26582697
if (isset($opcodes[$code]["spec"]["COMMUTATIVE"])) {
2659-
$opcodes[$code]["flags"] |= $vm_op_flags["ZEND_VM_COMMUTATIVE"];
2698+
$opcodes[$code]["ext_flags"] |= ZEND_VM_COMMUTATIVE;
26602699
}
26612700
}
26622701
$opnames[$op] = $code;
@@ -2701,23 +2740,21 @@ function gen_vm($def, $skel) {
27012740
$op = $m[4];
27022741
$op1 = parse_operand_spec($def, $lineno, $m[5], $flags1);
27032742
$op2 = parse_operand_spec($def, $lineno, $m[6], $flags2);
2704-
$flags = $flags1 | ($flags2 << 8);
2705-
if (!empty($m[8])) {
2706-
$flags |= parse_ext_spec($def, $lineno, $m[8]);
2707-
}
2743+
$flags = $flags1 | ($flags2 << ZEND_VM_OP_SHIFT);
2744+
$ext_flags = parse_ext_spec($def, $lineno, $m[8] ?? '', $m[10] ?? '');
27082745

27092746
if (isset($opcodes[$code])) {
27102747
die("ERROR ($def:$lineno): Opcode with name '$code' is already defined.\n");
27112748
}
27122749
$used_extra_spec["TYPE"] = 1;
2713-
$opcodes[$code] = array("op"=>$op,"op1"=>$op1,"op2"=>$op2,"code"=>"","flags"=>$flags,"hot"=>$hot,"is_type_spec"=>true);
2750+
$opcodes[$code] = array("op"=>$op,"op1"=>$op1,"op2"=>$op2,"code"=>"","flags"=>$flags,"ext_flags"=>$ext_flags,"hot"=>$hot,"is_type_spec"=>true);
27142751
if (isset($m[10])) {
27152752
$opcodes[$code]["spec"] = parse_spec_rules($def, $lineno, $m[10]);
27162753
if (isset($opcodes[$code]["spec"]["NO_CONST_CONST"])) {
2717-
$opcodes[$code]["flags"] |= $vm_op_flags["ZEND_VM_NO_CONST_CONST"];
2754+
$opcodes[$code]["ext_flags"] |= ZEND_VM_NO_CONST_CONST;
27182755
}
27192756
if (isset($opcodes[$code]["spec"]["COMMUTATIVE"])) {
2720-
$opcodes[$code]["flags"] |= $vm_op_flags["ZEND_VM_COMMUTATIVE"];
2757+
$opcodes[$code]["ext_flags"] |= ZEND_VM_COMMUTATIVE;
27212758
}
27222759
}
27232760
$opnames[$op] = $code;
@@ -2836,7 +2873,7 @@ function gen_vm($def, $skel) {
28362873
}
28372874

28382875
// Generate opcode #defines (zend_vm_opcodes.h)
2839-
$str = gen_vm_opcodes_header($opcodes, $max_opcode, $max_opcode_len, $vm_op_flags);
2876+
$str = gen_vm_opcodes_header($opcodes, $max_opcode, $max_opcode_len, $vm_op_flags, $vm_ext_flags);
28402877
write_file_if_changed(__DIR__ . "/zend_vm_opcodes.h", $str);
28412878
echo "zend_vm_opcodes.h generated successfully.\n";
28422879

@@ -2855,9 +2892,9 @@ function gen_vm($def, $skel) {
28552892
}
28562893
out($f, "};\n\n");
28572894

2858-
out($f,"static uint32_t zend_vm_opcodes_flags[".($max_opcode + 1)."] = {\n");
2895+
out($f,"static uint64_t zend_vm_opcodes_flags[".($max_opcode + 1)."] = {\n");
28592896
for ($i = 0; $i <= $max_opcode; $i++) {
2860-
out($f, sprintf("\t0x%08x,\n", isset($opcodes[$i]["flags"]) ? $opcodes[$i]["flags"] : 0));
2897+
out($f, sprintf("\tUINT64_C(0x%08x) | (UINT64_C(0x%08x) << 32), /* %s */\n", $opcodes[$i]["flags"] ?? 0, $opcodes[$i]["ext_flags"] ?? 0, $opcodes[$i]["op"] ?? ''));
28612898
}
28622899
out($f, "};\n\n");
28632900

@@ -2868,7 +2905,7 @@ function gen_vm($def, $skel) {
28682905
out($f, "\treturn zend_vm_opcodes_names[opcode];\n");
28692906
out($f, "}\n");
28702907

2871-
out($f, "ZEND_API uint32_t ZEND_FASTCALL zend_get_opcode_flags(uint8_t opcode) {\n");
2908+
out($f, "ZEND_API uint64_t ZEND_FASTCALL zend_get_opcode_flags(uint8_t opcode) {\n");
28722909
out($f, "\tif (UNEXPECTED(opcode > ZEND_VM_LAST_OPCODE)) {\n");
28732910
out($f, "\t\topcode = ZEND_NOP;\n");
28742911
out($f, "\t}\n");

0 commit comments

Comments
 (0)