Skip to content

Commit edee519

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 edee519

File tree

5 files changed

+345
-304
lines changed

5 files changed

+345
-304
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: 89 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -55,30 +55,49 @@
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,
61+
"ZEND_VM_OP_SHIFT" => 16,
62+
63+
// An operand can have zero of more of these:
64+
"ZEND_VM_OP_SPEC_MASK" => 0xff,
6065
"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,
66+
"ZEND_VM_OP_TMP" => 1<<2,
67+
"ZEND_VM_OP_VAR" => 1<<3,
68+
"ZEND_VM_OP_UNUSED" => 1<<4,
69+
"ZEND_VM_OP_CV" => 1<<5,
70+
"ZEND_VM_OP_TMPVAR" => 1<<6,
71+
"ZEND_VM_OP_TMPVARCV" => 1<<7,
72+
73+
// unused: (1<<8)-(1<<11)
74+
75+
// An operand can have at most one of these:
76+
"ZEND_VM_OP_MASK" => 0xf000,
77+
"ZEND_VM_OP_NUM" => 1<<12,
78+
"ZEND_VM_OP_JMP_ADDR" => 2<<12,
79+
"ZEND_VM_OP_TRY_CATCH" => 3<<12,
80+
"ZEND_VM_OP_LOOP_END" => 4<<12,
81+
"ZEND_VM_OP_THIS" => 5<<12,
82+
"ZEND_VM_OP_NEXT" => 6<<12,
83+
"ZEND_VM_OP_CLASS_FETCH" => 7<<12,
84+
"ZEND_VM_OP_CONSTRUCTOR" => 8<<12,
85+
"ZEND_VM_OP_CONST_FETCH" => 9<<12,
86+
"ZEND_VM_OP_CACHE_SLOT" => 10<<12,
87+
// unused in ZEND_VM_OP_MASK: (11<<12)-(15<<12)
88+
);
89+
90+
// Opcode-level flags
91+
$vm_ext_flags = array(
92+
// unused: bits (1<<0)-(1<<15)
7493

7594
"ZEND_VM_EXT_VAR_FETCH" => 1<<16,
7695
"ZEND_VM_EXT_ISSET" => 1<<17,
7796
"ZEND_VM_EXT_CACHE_SLOT" => 1<<18,
7897
"ZEND_VM_EXT_ARRAY_INIT" => 1<<19,
7998
"ZEND_VM_EXT_REF" => 1<<20,
8099
"ZEND_VM_EXT_FETCH_REF" => 1<<21,
81-
"ZEND_VM_EXT_DIM_WRITE" => 1<<22,
100+
"ZEND_VM_EXT_DIM_WRITE" => 1<<22,
82101
"ZEND_VM_EXT_MASK" => 0x0f000000,
83102
"ZEND_VM_EXT_NUM" => 0x01000000,
84103
"ZEND_VM_EXT_LAST_CATCH" => 0x02000000,
@@ -100,15 +119,19 @@
100119
define($name, $val);
101120
}
102121

122+
foreach ($vm_ext_flags as $name => $val) {
123+
define($name, $val);
124+
}
125+
103126
$vm_op_decode = array(
104127
"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,
128+
"CONST" => ZEND_VM_OP_CONST,
129+
"TMP" => ZEND_VM_OP_TMP,
130+
"VAR" => ZEND_VM_OP_VAR,
131+
"UNUSED" => ZEND_VM_OP_UNUSED,
132+
"CV" => ZEND_VM_OP_CV,
133+
"TMPVAR" => ZEND_VM_OP_TMPVAR,
134+
"TMPVARCV" => ZEND_VM_OP_TMPVARCV,
112135
"NUM" => ZEND_VM_OP_NUM,
113136
"JMP_ADDR" => ZEND_VM_OP_JMP_ADDR,
114137
"TRY_CATCH" => ZEND_VM_OP_TRY_CATCH,
@@ -2389,7 +2412,7 @@ function parse_operand_spec($def, $lineno, $str, &$flags) {
23892412
die("ERROR ($def:$lineno): Wrong operand type '$str'\n");
23902413
}
23912414
}
2392-
if (!($flags & ZEND_VM_OP_SPEC)) {
2415+
if (!($flags & ZEND_VM_OP_SPEC_MASK)) {
23932416
if (count($a) != 1) {
23942417
die("ERROR ($def:$lineno): Wrong operand type '$str'\n");
23952418
}
@@ -2398,18 +2421,32 @@ function parse_operand_spec($def, $lineno, $str, &$flags) {
23982421
return array_flip($a);
23992422
}
24002423

2401-
function parse_ext_spec($def, $lineno, $str) {
2424+
function parse_ext_spec($def, $lineno, $str, $spec_str) {
24022425
global $vm_ext_decode;
24032426

24042427
$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");
2428+
2429+
if ($str !== '') {
2430+
$a = explode("|",$str);
2431+
foreach ($a as $val) {
2432+
if (isset($vm_ext_decode[$val])) {
2433+
$flags |= $vm_ext_decode[$val];
2434+
} else {
2435+
die("ERROR ($def:$lineno): Wrong extended_value type '$str'\n");
2436+
}
2437+
}
2438+
}
2439+
if ($spec_str !== '') {
2440+
$a = explode(",",$spec_str);
2441+
foreach ($a as $val) {
2442+
if (isset($vm_ext_decode[$val])) {
2443+
$flags |= $vm_ext_decode[$val];
2444+
} else {
2445+
// Spec flags are validated separately.
2446+
}
24112447
}
24122448
}
2449+
24132450
return $flags;
24142451
}
24152452

@@ -2464,7 +2501,7 @@ function parse_spec_rules($def, $lineno, $str) {
24642501
}
24652502

24662503
function gen_vm_opcodes_header(
2467-
array $opcodes, int $max_opcode, int $max_opcode_len, array $vm_op_flags
2504+
array $opcodes, int $max_opcode, int $max_opcode_len, array $vm_op_flags, array $vm_ext_flags
24682505
): string {
24692506
$str = HEADER_TEXT;
24702507
$str .= "#ifndef ZEND_VM_OPCODES_H\n#define ZEND_VM_OPCODES_H\n\n";
@@ -2538,12 +2575,15 @@ function gen_vm_opcodes_header(
25382575
foreach ($vm_op_flags as $name => $val) {
25392576
$str .= sprintf("#define %-24s 0x%08x\n", $name, $val);
25402577
}
2541-
$str .= "#define ZEND_VM_OP1_FLAGS(flags) (flags & 0xff)\n";
2542-
$str .= "#define ZEND_VM_OP2_FLAGS(flags) ((flags >> 8) & 0xff)\n";
2578+
foreach ($vm_ext_flags as $name => $val) {
2579+
$str .= sprintf("#define %-24s (UINT64_C(0x%08x) << 32)\n", $name, $val);
2580+
}
2581+
$str .= sprintf("#define ZEND_VM_OP1_FLAGS(flags) (flags & 0x%08x)\n", (1<<ZEND_VM_OP_SHIFT)-1);
2582+
$str .= sprintf("#define ZEND_VM_OP2_FLAGS(flags) ((flags >> %d) & 0x%08x)\n", ZEND_VM_OP_SHIFT, (1<<ZEND_VM_OP_SHIFT)-1);
25432583
$str .= "\n";
25442584
$str .= "BEGIN_EXTERN_C()\n\n";
25452585
$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";
2586+
$str .= "ZEND_API uint64_t ZEND_FASTCALL zend_get_opcode_flags(uint8_t opcode);\n";
25472587
$str .= "ZEND_API uint8_t zend_get_opcode_id(const char *name, size_t length);\n\n";
25482588
$str .= "END_EXTERN_C()\n\n";
25492589

@@ -2567,7 +2607,7 @@ function gen_vm_opcodes_header(
25672607
function gen_vm($def, $skel) {
25682608
global $definition_file, $skeleton_file, $executor_file,
25692609
$op_types, $list, $opcodes, $helpers, $params, $opnames,
2570-
$vm_op_flags, $used_extra_spec;
2610+
$vm_op_flags, $vm_ext_flags, $used_extra_spec;
25712611

25722612
// Load definition file
25732613
$in = @file($def);
@@ -2632,10 +2672,8 @@ function gen_vm($def, $skel) {
26322672
$len = strlen($op);
26332673
$op1 = parse_operand_spec($def, $lineno, $m[4], $flags1);
26342674
$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-
}
2675+
$flags = $flags1 | ($flags2 << ZEND_VM_OP_SHIFT);
2676+
$ext_flags = parse_ext_spec($def, $lineno, $m[7] ?? '', $m[9] ?? '');
26392677

26402678
if ($len > $max_opcode_len) {
26412679
$max_opcode_len = $len;
@@ -2649,14 +2687,14 @@ function gen_vm($def, $skel) {
26492687
if (isset($opnames[$op])) {
26502688
die("ERROR ($def:$lineno): Opcode with name '$op' is already defined.\n");
26512689
}
2652-
$opcodes[$code] = array("op"=>$op,"op1"=>$op1,"op2"=>$op2,"code"=>"","flags"=>$flags,"hot"=>$hot);
2690+
$opcodes[$code] = array("op"=>$op,"op1"=>$op1,"op2"=>$op2,"code"=>"","flags"=>$flags,"ext_flags"=>$ext_flags,"hot"=>$hot);
26532691
if (isset($m[9])) {
26542692
$opcodes[$code]["spec"] = parse_spec_rules($def, $lineno, $m[9]);
26552693
if (isset($opcodes[$code]["spec"]["NO_CONST_CONST"])) {
2656-
$opcodes[$code]["flags"] |= $vm_op_flags["ZEND_VM_NO_CONST_CONST"];
2694+
$opcodes[$code]["ext_flags"] |= ZEND_VM_NO_CONST_CONST;
26572695
}
26582696
if (isset($opcodes[$code]["spec"]["COMMUTATIVE"])) {
2659-
$opcodes[$code]["flags"] |= $vm_op_flags["ZEND_VM_COMMUTATIVE"];
2697+
$opcodes[$code]["ext_flags"] |= ZEND_VM_COMMUTATIVE;
26602698
}
26612699
}
26622700
$opnames[$op] = $code;
@@ -2701,23 +2739,21 @@ function gen_vm($def, $skel) {
27012739
$op = $m[4];
27022740
$op1 = parse_operand_spec($def, $lineno, $m[5], $flags1);
27032741
$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-
}
2742+
$flags = $flags1 | ($flags2 << ZEND_VM_OP_SHIFT);
2743+
$ext_flags = parse_ext_spec($def, $lineno, $m[8] ?? '', $m[10] ?? '');
27082744

27092745
if (isset($opcodes[$code])) {
27102746
die("ERROR ($def:$lineno): Opcode with name '$code' is already defined.\n");
27112747
}
27122748
$used_extra_spec["TYPE"] = 1;
2713-
$opcodes[$code] = array("op"=>$op,"op1"=>$op1,"op2"=>$op2,"code"=>"","flags"=>$flags,"hot"=>$hot,"is_type_spec"=>true);
2749+
$opcodes[$code] = array("op"=>$op,"op1"=>$op1,"op2"=>$op2,"code"=>"","flags"=>$flags,"ext_flags"=>$ext_flags,"hot"=>$hot,"is_type_spec"=>true);
27142750
if (isset($m[10])) {
27152751
$opcodes[$code]["spec"] = parse_spec_rules($def, $lineno, $m[10]);
27162752
if (isset($opcodes[$code]["spec"]["NO_CONST_CONST"])) {
2717-
$opcodes[$code]["flags"] |= $vm_op_flags["ZEND_VM_NO_CONST_CONST"];
2753+
$opcodes[$code]["ext_flags"] |= ZEND_VM_NO_CONST_CONST;
27182754
}
27192755
if (isset($opcodes[$code]["spec"]["COMMUTATIVE"])) {
2720-
$opcodes[$code]["flags"] |= $vm_op_flags["ZEND_VM_COMMUTATIVE"];
2756+
$opcodes[$code]["ext_flags"] |= ZEND_VM_COMMUTATIVE;
27212757
}
27222758
}
27232759
$opnames[$op] = $code;
@@ -2836,7 +2872,7 @@ function gen_vm($def, $skel) {
28362872
}
28372873

28382874
// Generate opcode #defines (zend_vm_opcodes.h)
2839-
$str = gen_vm_opcodes_header($opcodes, $max_opcode, $max_opcode_len, $vm_op_flags);
2875+
$str = gen_vm_opcodes_header($opcodes, $max_opcode, $max_opcode_len, $vm_op_flags, $vm_ext_flags);
28402876
write_file_if_changed(__DIR__ . "/zend_vm_opcodes.h", $str);
28412877
echo "zend_vm_opcodes.h generated successfully.\n";
28422878

@@ -2855,9 +2891,9 @@ function gen_vm($def, $skel) {
28552891
}
28562892
out($f, "};\n\n");
28572893

2858-
out($f,"static uint32_t zend_vm_opcodes_flags[".($max_opcode + 1)."] = {\n");
2894+
out($f,"static uint64_t zend_vm_opcodes_flags[".($max_opcode + 1)."] = {\n");
28592895
for ($i = 0; $i <= $max_opcode; $i++) {
2860-
out($f, sprintf("\t0x%08x,\n", isset($opcodes[$i]["flags"]) ? $opcodes[$i]["flags"] : 0));
2896+
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"] ?? ''));
28612897
}
28622898
out($f, "};\n\n");
28632899

@@ -2868,7 +2904,7 @@ function gen_vm($def, $skel) {
28682904
out($f, "\treturn zend_vm_opcodes_names[opcode];\n");
28692905
out($f, "}\n");
28702906

2871-
out($f, "ZEND_API uint32_t ZEND_FASTCALL zend_get_opcode_flags(uint8_t opcode) {\n");
2907+
out($f, "ZEND_API uint64_t ZEND_FASTCALL zend_get_opcode_flags(uint8_t opcode) {\n");
28722908
out($f, "\tif (UNEXPECTED(opcode > ZEND_VM_LAST_OPCODE)) {\n");
28732909
out($f, "\t\topcode = ZEND_NOP;\n");
28742910
out($f, "\t}\n");

0 commit comments

Comments
 (0)