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