Skip to content

Commit b2a3690

Browse files
committed
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 46357cb commit b2a3690

2 files changed

Lines changed: 87 additions & 54 deletions

File tree

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: 86 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -56,21 +56,36 @@
5656
const ZEND_VM_KIND_TAILCALL = 5;
5757

5858
$vm_op_flags = array(
59-
"ZEND_VM_OP_SPEC" => 1<<0,
59+
"ZEND_VM_OP_SHIFT" => 16,
60+
61+
"ZEND_VM_OP_SPEC_MASK" => 0x1ff,
6062
"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,
63+
"ZEND_VM_OP_TMP" => 1<<2,
64+
"ZEND_VM_OP_VAR" => 1<<3,
65+
"ZEND_VM_OP_UNUSED" => 1<<4,
66+
"ZEND_VM_OP_CV" => 1<<5,
67+
"ZEND_VM_OP_TMPVAR" => 1<<6,
68+
"ZEND_VM_OP_TMPVARCV" => 1<<7,
69+
"ZEND_VM_OP_REG" => 1<<8,
70+
71+
// unused bits: 9-11
72+
73+
"ZEND_VM_OP_MASK" => 0xf000,
74+
"ZEND_VM_OP_NUM" => 1<<12,
75+
"ZEND_VM_OP_JMP_ADDR" => 2<<12,
76+
"ZEND_VM_OP_TRY_CATCH" => 3<<12,
77+
"ZEND_VM_OP_LOOP_END" => 4<<12,
78+
"ZEND_VM_OP_THIS" => 5<<12,
79+
"ZEND_VM_OP_NEXT" => 6<<12,
80+
"ZEND_VM_OP_CLASS_FETCH" => 7<<12,
81+
"ZEND_VM_OP_CONSTRUCTOR" => 8<<12,
82+
"ZEND_VM_OP_CONST_FETCH" => 9<<12,
83+
"ZEND_VM_OP_CACHE_SLOT" => 10<<12,
84+
// unused: (11<<12)-(15<<12)
85+
);
86+
87+
$vm_ext_flags = array(
88+
// unused: bits 1-15
7489

7590
"ZEND_VM_EXT_VAR_FETCH" => 1<<16,
7691
"ZEND_VM_EXT_ISSET" => 1<<17,
@@ -100,15 +115,20 @@
100115
define($name, $val);
101116
}
102117

118+
foreach ($vm_ext_flags as $name => $val) {
119+
define($name, $val);
120+
}
121+
103122
$vm_op_decode = array(
104123
"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,
124+
"CONST" => ZEND_VM_OP_CONST,
125+
"TMP" => ZEND_VM_OP_TMP,
126+
"VAR" => ZEND_VM_OP_VAR,
127+
"UNUSED" => ZEND_VM_OP_UNUSED,
128+
"CV" => ZEND_VM_OP_CV,
129+
"TMPVAR" => ZEND_VM_OP_TMPVAR,
130+
"TMPVARCV" => ZEND_VM_OP_TMPVARCV,
131+
"REG" => ZEND_VM_OP_REG,
112132
"NUM" => ZEND_VM_OP_NUM,
113133
"JMP_ADDR" => ZEND_VM_OP_JMP_ADDR,
114134
"TRY_CATCH" => ZEND_VM_OP_TRY_CATCH,
@@ -1885,7 +1905,7 @@ function gen_executor($f, $skl, $spec, $kind, $executor_name, $initializer_name)
18851905
out($f,"#define SPEC_RULE_ISSET 0x01000000\n");
18861906
out($f,"#define SPEC_RULE_OBSERVER 0x02000000\n");
18871907
out($f,"\n");
1888-
out($f,"static const uint32_t *zend_spec_handlers;\n");
1908+
out($f,"const uint32_t *zend_spec_handlers;\n");
18891909
out($f,"static zend_vm_opcode_handler_t const *zend_opcode_handlers;\n");
18901910
out($f,"static int zend_handlers_count;\n");
18911911
if ($kind == ZEND_VM_KIND_HYBRID) {
@@ -2389,7 +2409,7 @@ function parse_operand_spec($def, $lineno, $str, &$flags) {
23892409
die("ERROR ($def:$lineno): Wrong operand type '$str'\n");
23902410
}
23912411
}
2392-
if (!($flags & ZEND_VM_OP_SPEC)) {
2412+
if (!($flags & ZEND_VM_OP_SPEC_MASK)) {
23932413
if (count($a) != 1) {
23942414
die("ERROR ($def:$lineno): Wrong operand type '$str'\n");
23952415
}
@@ -2398,18 +2418,32 @@ function parse_operand_spec($def, $lineno, $str, &$flags) {
23982418
return array_flip($a);
23992419
}
24002420

2401-
function parse_ext_spec($def, $lineno, $str) {
2421+
function parse_ext_spec($def, $lineno, $str, $spec_str) {
24022422
global $vm_ext_decode;
24032423

24042424
$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");
2425+
2426+
if ($str !== '') {
2427+
$a = explode("|",$str);
2428+
foreach ($a as $val) {
2429+
if (isset($vm_ext_decode[$val])) {
2430+
$flags |= $vm_ext_decode[$val];
2431+
} else {
2432+
die("ERROR ($def:$lineno): Wrong extended_value type '$str'\n");
2433+
}
2434+
}
2435+
}
2436+
if ($spec_str !== '') {
2437+
$a = explode(",",$spec_str);
2438+
foreach ($a as $val) {
2439+
if (isset($vm_ext_decode[$val])) {
2440+
$flags |= $vm_ext_decode[$val];
2441+
} else {
2442+
// Spec flags are validated separately.
2443+
}
24112444
}
24122445
}
2446+
24132447
return $flags;
24142448
}
24152449

@@ -2464,7 +2498,7 @@ function parse_spec_rules($def, $lineno, $str) {
24642498
}
24652499

24662500
function gen_vm_opcodes_header(
2467-
array $opcodes, int $max_opcode, int $max_opcode_len, array $vm_op_flags
2501+
array $opcodes, int $max_opcode, int $max_opcode_len, array $vm_op_flags, array $vm_ext_flags
24682502
): string {
24692503
$str = HEADER_TEXT;
24702504
$str .= "#ifndef ZEND_VM_OPCODES_H\n#define ZEND_VM_OPCODES_H\n\n";
@@ -2538,12 +2572,15 @@ function gen_vm_opcodes_header(
25382572
foreach ($vm_op_flags as $name => $val) {
25392573
$str .= sprintf("#define %-24s 0x%08x\n", $name, $val);
25402574
}
2541-
$str .= "#define ZEND_VM_OP1_FLAGS(flags) (flags & 0xff)\n";
2542-
$str .= "#define ZEND_VM_OP2_FLAGS(flags) ((flags >> 8) & 0xff)\n";
2575+
foreach ($vm_ext_flags as $name => $val) {
2576+
$str .= sprintf("#define %-24s (UINT64_C(0x%08x) << 32)\n", $name, $val);
2577+
}
2578+
$str .= sprintf("#define ZEND_VM_OP1_FLAGS(flags) (flags & 0x%08x)\n", (1<<ZEND_VM_OP_SHIFT)-1);
2579+
$str .= sprintf("#define ZEND_VM_OP2_FLAGS(flags) ((flags >> %d) & 0x%08x)\n", ZEND_VM_OP_SHIFT, (1<<ZEND_VM_OP_SHIFT)-1);
25432580
$str .= "\n";
25442581
$str .= "BEGIN_EXTERN_C()\n\n";
25452582
$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";
2583+
$str .= "ZEND_API uint64_t ZEND_FASTCALL zend_get_opcode_flags(uint8_t opcode);\n";
25472584
$str .= "ZEND_API uint8_t zend_get_opcode_id(const char *name, size_t length);\n\n";
25482585
$str .= "END_EXTERN_C()\n\n";
25492586

@@ -2567,7 +2604,7 @@ function gen_vm_opcodes_header(
25672604
function gen_vm($def, $skel) {
25682605
global $definition_file, $skeleton_file, $executor_file,
25692606
$op_types, $list, $opcodes, $helpers, $params, $opnames,
2570-
$vm_op_flags, $used_extra_spec;
2607+
$vm_op_flags, $vm_ext_flags, $used_extra_spec;
25712608

25722609
// Load definition file
25732610
$in = @file($def);
@@ -2632,10 +2669,8 @@ function gen_vm($def, $skel) {
26322669
$len = strlen($op);
26332670
$op1 = parse_operand_spec($def, $lineno, $m[4], $flags1);
26342671
$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-
}
2672+
$flags = $flags1 | ($flags2 << ZEND_VM_OP_SHIFT);
2673+
$ext_flags = parse_ext_spec($def, $lineno, $m[7] ?? '', $m[9] ?? '');
26392674

26402675
if ($len > $max_opcode_len) {
26412676
$max_opcode_len = $len;
@@ -2649,14 +2684,14 @@ function gen_vm($def, $skel) {
26492684
if (isset($opnames[$op])) {
26502685
die("ERROR ($def:$lineno): Opcode with name '$op' is already defined.\n");
26512686
}
2652-
$opcodes[$code] = array("op"=>$op,"op1"=>$op1,"op2"=>$op2,"code"=>"","flags"=>$flags,"hot"=>$hot);
2687+
$opcodes[$code] = array("op"=>$op,"op1"=>$op1,"op2"=>$op2,"code"=>"","flags"=>$flags,"ext_flags"=>$ext_flags,"hot"=>$hot);
26532688
if (isset($m[9])) {
26542689
$opcodes[$code]["spec"] = parse_spec_rules($def, $lineno, $m[9]);
26552690
if (isset($opcodes[$code]["spec"]["NO_CONST_CONST"])) {
2656-
$opcodes[$code]["flags"] |= $vm_op_flags["ZEND_VM_NO_CONST_CONST"];
2691+
$opcodes[$code]["ext_flags"] |= ZEND_VM_NO_CONST_CONST;
26572692
}
26582693
if (isset($opcodes[$code]["spec"]["COMMUTATIVE"])) {
2659-
$opcodes[$code]["flags"] |= $vm_op_flags["ZEND_VM_COMMUTATIVE"];
2694+
$opcodes[$code]["ext_flags"] |= ZEND_VM_COMMUTATIVE;
26602695
}
26612696
}
26622697
$opnames[$op] = $code;
@@ -2701,23 +2736,21 @@ function gen_vm($def, $skel) {
27012736
$op = $m[4];
27022737
$op1 = parse_operand_spec($def, $lineno, $m[5], $flags1);
27032738
$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-
}
2739+
$flags = $flags1 | ($flags2 << ZEND_VM_OP_SHIFT);
2740+
$ext_flags = parse_ext_spec($def, $lineno, $m[8] ?? '', $m[10] ?? '');
27082741

27092742
if (isset($opcodes[$code])) {
27102743
die("ERROR ($def:$lineno): Opcode with name '$code' is already defined.\n");
27112744
}
27122745
$used_extra_spec["TYPE"] = 1;
2713-
$opcodes[$code] = array("op"=>$op,"op1"=>$op1,"op2"=>$op2,"code"=>"","flags"=>$flags,"hot"=>$hot,"is_type_spec"=>true);
2746+
$opcodes[$code] = array("op"=>$op,"op1"=>$op1,"op2"=>$op2,"code"=>"","flags"=>$flags,"ext_flags"=>$ext_flags,"hot"=>$hot,"is_type_spec"=>true);
27142747
if (isset($m[10])) {
27152748
$opcodes[$code]["spec"] = parse_spec_rules($def, $lineno, $m[10]);
27162749
if (isset($opcodes[$code]["spec"]["NO_CONST_CONST"])) {
2717-
$opcodes[$code]["flags"] |= $vm_op_flags["ZEND_VM_NO_CONST_CONST"];
2750+
$opcodes[$code]["ext_flags"] |= ZEND_VM_NO_CONST_CONST;
27182751
}
27192752
if (isset($opcodes[$code]["spec"]["COMMUTATIVE"])) {
2720-
$opcodes[$code]["flags"] |= $vm_op_flags["ZEND_VM_COMMUTATIVE"];
2753+
$opcodes[$code]["ext_flags"] |= ZEND_VM_COMMUTATIVE;
27212754
}
27222755
}
27232756
$opnames[$op] = $code;
@@ -2836,7 +2869,7 @@ function gen_vm($def, $skel) {
28362869
}
28372870

28382871
// Generate opcode #defines (zend_vm_opcodes.h)
2839-
$str = gen_vm_opcodes_header($opcodes, $max_opcode, $max_opcode_len, $vm_op_flags);
2872+
$str = gen_vm_opcodes_header($opcodes, $max_opcode, $max_opcode_len, $vm_op_flags, $vm_ext_flags);
28402873
write_file_if_changed(__DIR__ . "/zend_vm_opcodes.h", $str);
28412874
echo "zend_vm_opcodes.h generated successfully.\n";
28422875

@@ -2855,9 +2888,9 @@ function gen_vm($def, $skel) {
28552888
}
28562889
out($f, "};\n\n");
28572890

2858-
out($f,"static uint32_t zend_vm_opcodes_flags[".($max_opcode + 1)."] = {\n");
2891+
out($f,"static uint64_t zend_vm_opcodes_flags[".($max_opcode + 1)."] = {\n");
28592892
for ($i = 0; $i <= $max_opcode; $i++) {
2860-
out($f, sprintf("\t0x%08x,\n", isset($opcodes[$i]["flags"]) ? $opcodes[$i]["flags"] : 0));
2893+
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"] ?? ''));
28612894
}
28622895
out($f, "};\n\n");
28632896

@@ -2868,7 +2901,7 @@ function gen_vm($def, $skel) {
28682901
out($f, "\treturn zend_vm_opcodes_names[opcode];\n");
28692902
out($f, "}\n");
28702903

2871-
out($f, "ZEND_API uint32_t ZEND_FASTCALL zend_get_opcode_flags(uint8_t opcode) {\n");
2904+
out($f, "ZEND_API uint64_t ZEND_FASTCALL zend_get_opcode_flags(uint8_t opcode) {\n");
28722905
out($f, "\tif (UNEXPECTED(opcode > ZEND_VM_LAST_OPCODE)) {\n");
28732906
out($f, "\t\topcode = ZEND_NOP;\n");
28742907
out($f, "\t}\n");

0 commit comments

Comments
 (0)