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 ,
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 ,
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
24662504function 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(
25672608function 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 ("\t 0x %08x, \n" , isset ( $ opcodes [$ i ]["flags " ]) ? $ opcodes [$ i ]["flags " ] : 0 ));
2897+ 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 " ] ?? '' ));
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