5555const ZEND_VM_KIND_HYBRID = 4 ;
5656const 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 ,
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
24662503function 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(
25672607function 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 ("\t 0x %08x, \n" , isset ( $ opcodes [$ i ]["flags " ]) ? $ opcodes [$ i ]["flags " ] : 0 ));
2896+ out ($ f , sprintf ("\t UINT64_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