diff options
author | Nikita Popov <nikita.ppv@gmail.com> | 2020-02-03 13:41:31 +0100 |
---|---|---|
committer | Nikita Popov <nikita.ppv@gmail.com> | 2020-02-03 13:41:31 +0100 |
commit | 58b17906f512866c2e34844fa497ecdf7f1e1e3d (patch) | |
tree | fcfa56bc040ec99990610dba890b72ef4d560663 | |
parent | 4fd63185803aad42790c0ac38c144b346e283009 (diff) | |
download | php-git-58b17906f512866c2e34844fa497ecdf7f1e1e3d.tar.gz |
Apply tidy formatting
Mostly reindent PHP scripts to spaces.
47 files changed, 7449 insertions, 7449 deletions
diff --git a/Zend/bench.php b/Zend/bench.php index a6c0c6daed..8f84d64ee2 100644 --- a/Zend/bench.php +++ b/Zend/bench.php @@ -1,6 +1,6 @@ <?php if (function_exists("date_default_timezone_set")) { - date_default_timezone_set("UTC"); + date_default_timezone_set("UTC"); } function simple() { @@ -220,30 +220,30 @@ function heapsort_r($n, &$ra) { $ir = $n; while (1) { - if ($l > 1) { - $rra = $ra[--$l]; - } else { - $rra = $ra[$ir]; - $ra[$ir] = $ra[1]; - if (--$ir == 1) { - $ra[1] = $rra; - return; - } - } - $i = $l; - $j = $l << 1; - while ($j <= $ir) { - if (($j < $ir) && ($ra[$j] < $ra[$j+1])) { - $j++; - } - if ($rra < $ra[$j]) { - $ra[$i] = $ra[$j]; - $j += ($i = $j); - } else { - $j = $ir + 1; - } - } - $ra[$i] = $rra; + if ($l > 1) { + $rra = $ra[--$l]; + } else { + $rra = $ra[$ir]; + $ra[$ir] = $ra[1]; + if (--$ir == 1) { + $ra[1] = $rra; + return; + } + } + $i = $l; + $j = $l << 1; + while ($j <= $ir) { + if (($j < $ir) && ($ra[$j] < $ra[$j+1])) { + $j++; + } + if ($rra < $ra[$j]) { + $ra[$i] = $ra[$j]; + $j += ($i = $j); + } else { + $j = $ir + 1; + } + } + $ra[$i] = $rra; } } @@ -268,9 +268,9 @@ function mkmatrix ($rows, $cols) { $count = 1; $mx = array(); for ($i=0; $i<$rows; $i++) { - for ($j=0; $j<$cols; $j++) { - $mx[$i][$j] = $count++; - } + for ($j=0; $j<$cols; $j++) { + $mx[$i][$j] = $count++; + } } return($mx); } @@ -278,13 +278,13 @@ function mkmatrix ($rows, $cols) { function mmult ($rows, $cols, $m1, $m2) { $m3 = array(); for ($i=0; $i<$rows; $i++) { - for ($j=0; $j<$cols; $j++) { - $x = 0; - for ($k=0; $k<$cols; $k++) { - $x += $m1[$i][$k] * $m2[$k][$j]; - } - $m3[$i][$j] = $x; - } + for ($j=0; $j<$cols; $j++) { + $x = 0; + for ($k=0; $k<$cols; $k++) { + $x += $m1[$i][$k] * $m2[$k][$j]; + } + $m3[$i][$j] = $x; + } } return($m3); } @@ -353,7 +353,7 @@ function gethrtime() function start_test() { - ob_start(); + ob_start(); return gethrtime(); } @@ -367,7 +367,7 @@ function end_test($start, $name) $pad = str_repeat(" ", 24-strlen($name)-strlen($num)); echo $name.$pad.$num."\n"; - ob_start(); + ob_start(); return gethrtime(); } diff --git a/Zend/micro_bench.php b/Zend/micro_bench.php index 42f1110c88..96ced487e1 100644 --- a/Zend/micro_bench.php +++ b/Zend/micro_bench.php @@ -22,220 +22,220 @@ function simpleicall($n) { } class Foo { - static $a = 0; - public $b = 0; - const TEST = 0; - - static function read_static($n) { - for ($i = 0; $i < $n; ++$i) { - $x = self::$a; - } - } - - static function write_static($n) { - for ($i = 0; $i < $n; ++$i) { - self::$a = 0; - } - } - - static function isset_static($n) { - for ($i = 0; $i < $n; ++$i) { - $x = isset(self::$a); - } - } - - static function empty_static($n) { - for ($i = 0; $i < $n; ++$i) { - $x = empty(self::$a); - } - } - - static function f() { - } - - static function call_static($n) { - for ($i = 0; $i < $n; ++$i) { - self::f(); - } - } - - function read_prop($n) { - for ($i = 0; $i < $n; ++$i) { - $x = $this->b; - } - } - - function write_prop($n) { - for ($i = 0; $i < $n; ++$i) { - $this->b = 0; - } - } - - function assign_add_prop($n) { - for ($i = 0; $i < $n; ++$i) { - $this->b += 2; - } - } - - function pre_inc_prop($n) { - for ($i = 0; $i < $n; ++$i) { - ++$this->b; - } - } - - function pre_dec_prop($n) { - for ($i = 0; $i < $n; ++$i) { - --$this->b; - } - } - - function post_inc_prop($n) { - for ($i = 0; $i < $n; ++$i) { - $this->b++; - } - } - - function post_dec_prop($n) { - for ($i = 0; $i < $n; ++$i) { - $this->b--; - } - } - - function isset_prop($n) { - for ($i = 0; $i < $n; ++$i) { - $x = isset($this->b); - } - } - - function empty_prop($n) { - for ($i = 0; $i < $n; ++$i) { - $x = empty($this->b); - } - } - - function g() { - } - - function call($n) { - for ($i = 0; $i < $n; ++$i) { - $this->g(); - } - } - - function read_const($n) { - for ($i = 0; $i < $n; ++$i) { - $x = $this::TEST; - } - } + static $a = 0; + public $b = 0; + const TEST = 0; + + static function read_static($n) { + for ($i = 0; $i < $n; ++$i) { + $x = self::$a; + } + } + + static function write_static($n) { + for ($i = 0; $i < $n; ++$i) { + self::$a = 0; + } + } + + static function isset_static($n) { + for ($i = 0; $i < $n; ++$i) { + $x = isset(self::$a); + } + } + + static function empty_static($n) { + for ($i = 0; $i < $n; ++$i) { + $x = empty(self::$a); + } + } + + static function f() { + } + + static function call_static($n) { + for ($i = 0; $i < $n; ++$i) { + self::f(); + } + } + + function read_prop($n) { + for ($i = 0; $i < $n; ++$i) { + $x = $this->b; + } + } + + function write_prop($n) { + for ($i = 0; $i < $n; ++$i) { + $this->b = 0; + } + } + + function assign_add_prop($n) { + for ($i = 0; $i < $n; ++$i) { + $this->b += 2; + } + } + + function pre_inc_prop($n) { + for ($i = 0; $i < $n; ++$i) { + ++$this->b; + } + } + + function pre_dec_prop($n) { + for ($i = 0; $i < $n; ++$i) { + --$this->b; + } + } + + function post_inc_prop($n) { + for ($i = 0; $i < $n; ++$i) { + $this->b++; + } + } + + function post_dec_prop($n) { + for ($i = 0; $i < $n; ++$i) { + $this->b--; + } + } + + function isset_prop($n) { + for ($i = 0; $i < $n; ++$i) { + $x = isset($this->b); + } + } + + function empty_prop($n) { + for ($i = 0; $i < $n; ++$i) { + $x = empty($this->b); + } + } + + function g() { + } + + function call($n) { + for ($i = 0; $i < $n; ++$i) { + $this->g(); + } + } + + function read_const($n) { + for ($i = 0; $i < $n; ++$i) { + $x = $this::TEST; + } + } } function read_static($n) { - for ($i = 0; $i < $n; ++$i) { - $x = Foo::$a; - } + for ($i = 0; $i < $n; ++$i) { + $x = Foo::$a; + } } function write_static($n) { - for ($i = 0; $i < $n; ++$i) { - Foo::$a = 0; - } + for ($i = 0; $i < $n; ++$i) { + Foo::$a = 0; + } } function isset_static($n) { - for ($i = 0; $i < $n; ++$i) { - $x = isset(Foo::$a); - } + for ($i = 0; $i < $n; ++$i) { + $x = isset(Foo::$a); + } } function empty_static($n) { - for ($i = 0; $i < $n; ++$i) { - $x = empty(Foo::$a); - } + for ($i = 0; $i < $n; ++$i) { + $x = empty(Foo::$a); + } } function call_static($n) { - for ($i = 0; $i < $n; ++$i) { - Foo::f(); - } + for ($i = 0; $i < $n; ++$i) { + Foo::f(); + } } function create_object($n) { - for ($i = 0; $i < $n; ++$i) { - $x = new Foo(); - } + for ($i = 0; $i < $n; ++$i) { + $x = new Foo(); + } } define('TEST', null); function read_const($n) { - for ($i = 0; $i < $n; ++$i) { - $x = TEST; - } + for ($i = 0; $i < $n; ++$i) { + $x = TEST; + } } function read_auto_global($n) { - for ($i = 0; $i < $n; ++$i) { - $x = $_GET; - } + for ($i = 0; $i < $n; ++$i) { + $x = $_GET; + } } $g_var = 0; function read_global_var($n) { - for ($i = 0; $i < $n; ++$i) { - $x = $GLOBALS['g_var']; - } + for ($i = 0; $i < $n; ++$i) { + $x = $GLOBALS['g_var']; + } } function read_hash($n) { - $hash = array('test' => 0); - for ($i = 0; $i < $n; ++$i) { - $x = $hash['test']; - } + $hash = array('test' => 0); + for ($i = 0; $i < $n; ++$i) { + $x = $hash['test']; + } } function read_str_offset($n) { - $str = "test"; - for ($i = 0; $i < $n; ++$i) { - $x = $str[1]; - } + $str = "test"; + for ($i = 0; $i < $n; ++$i) { + $x = $str[1]; + } } function issetor($n) { - $val = array(0,1,2,3,4,5,6,7,8,9); - for ($i = 0; $i < $n; ++$i) { - $x = $val ?: null; - } + $val = array(0,1,2,3,4,5,6,7,8,9); + for ($i = 0; $i < $n; ++$i) { + $x = $val ?: null; + } } function issetor2($n) { - $f = false; $j = 0; - for ($i = 0; $i < $n; ++$i) { - $x = $f ?: $j + 1; - } + $f = false; $j = 0; + for ($i = 0; $i < $n; ++$i) { + $x = $f ?: $j + 1; + } } function ternary($n) { - $val = array(0,1,2,3,4,5,6,7,8,9); - $f = false; - for ($i = 0; $i < $n; ++$i) { - $x = $f ? null : $val; - } + $val = array(0,1,2,3,4,5,6,7,8,9); + $f = false; + for ($i = 0; $i < $n; ++$i) { + $x = $f ? null : $val; + } } function ternary2($n) { - $f = false; $j = 0; - for ($i = 0; $i < $n; ++$i) { - $x = $f ? $f : $j + 1; - } + $f = false; $j = 0; + for ($i = 0; $i < $n; ++$i) { + $x = $f ? $f : $j + 1; + } } /*****/ function empty_loop($n) { - for ($i = 0; $i < $n; ++$i) { - } + for ($i = 0; $i < $n; ++$i) { + } } function gethrtime() diff --git a/Zend/zend_ast.c b/Zend/zend_ast.c index f17d4ba69a..338ff09f76 100644 --- a/Zend/zend_ast.c +++ b/Zend/zend_ast.c @@ -451,7 +451,7 @@ static int zend_ast_add_unpacked_element(zval *result, zval *expr) { HashTable *ht = Z_ARRVAL_P(expr); zval *val; zend_string *key; - + ZEND_HASH_FOREACH_STR_KEY_VAL(ht, key, val) { if (key) { zend_throw_error(NULL, "Cannot unpack array with string keys"); diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h index f33d07b738..a6e4c2c337 100644 --- a/Zend/zend_vm_def.h +++ b/Zend/zend_vm_def.h @@ -1579,7 +1579,7 @@ ZEND_VM_HELPER(zend_pre_dec_helper, VAR|CV, ANY) SAVE_OPLINE(); if (OP1_TYPE == IS_CV && UNEXPECTED(Z_TYPE_P(var_ptr) == IS_UNDEF)) { - ZVAL_NULL(var_ptr); + ZVAL_NULL(var_ptr); ZVAL_UNDEFINED_OP1(); } @@ -5760,10 +5760,10 @@ ZEND_VM_HANDLER(147, ZEND_ADD_ARRAY_UNPACK, ANY, ANY) USE_OPLINE zend_free_op free_op1; zval *op1; - + SAVE_OPLINE(); op1 = GET_OP1_ZVAL_PTR(BP_VAR_R); - + ZEND_VM_C_LABEL(add_unpack_again): if (EXPECTED(Z_TYPE_P(op1) == IS_ARRAY)) { HashTable *ht = Z_ARRVAL_P(op1); @@ -5804,11 +5804,11 @@ ZEND_VM_C_LABEL(add_unpack_again): } HANDLE_EXCEPTION(); } - + if (iter->funcs->rewind) { iter->funcs->rewind(iter); } - + for (; iter->funcs->valid(iter) == SUCCESS; ) { zval *val; @@ -5857,7 +5857,7 @@ ZEND_VM_C_LABEL(add_unpack_again): } else { zend_throw_error(NULL, "Only arrays and Traversables can be unpacked"); } - + FREE_OP1(); ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); } diff --git a/Zend/zend_vm_gen.php b/Zend/zend_vm_gen.php index 1eabc5687b..22586cbd0b 100755 --- a/Zend/zend_vm_gen.php +++ b/Zend/zend_vm_gen.php @@ -43,8 +43,8 @@ const HEADER_TEXT = <<< DATA DATA; /* - This script creates zend_vm_execute.h and zend_vm_opcodes.h - from existing zend_vm_def.h and zend_vm_execute.skl + This script creates zend_vm_execute.h and zend_vm_opcodes.h + from existing zend_vm_def.h and zend_vm_execute.skl */ error_reporting(E_ALL); @@ -55,564 +55,564 @@ const ZEND_VM_KIND_GOTO = 3; const ZEND_VM_KIND_HYBRID = 4; $vm_op_flags = array( - "ZEND_VM_OP_SPEC" => 1<<0, - "ZEND_VM_OP_CONST" => 1<<1, - "ZEND_VM_OP_TMPVAR" => 1<<2, - "ZEND_VM_OP_TMPVARCV" => 1<<3, - "ZEND_VM_OP_MASK" => 0xf0, - "ZEND_VM_OP_NUM" => 0x10, - "ZEND_VM_OP_JMP_ADDR" => 0x20, - "ZEND_VM_OP_TRY_CATCH" => 0x30, - // unused 0x40 - "ZEND_VM_OP_THIS" => 0x50, - "ZEND_VM_OP_NEXT" => 0x60, - "ZEND_VM_OP_CLASS_FETCH" => 0x70, - "ZEND_VM_OP_CONSTRUCTOR" => 0x80, - "ZEND_VM_OP_CONST_FETCH" => 0x90, - "ZEND_VM_OP_CACHE_SLOT" => 0xa0, - - "ZEND_VM_EXT_VAR_FETCH" => 1<<16, - "ZEND_VM_EXT_ISSET" => 1<<17, - "ZEND_VM_EXT_CACHE_SLOT" => 1<<18, - "ZEND_VM_EXT_ARRAY_INIT" => 1<<19, - "ZEND_VM_EXT_REF" => 1<<20, - "ZEND_VM_EXT_FETCH_REF" => 1<<21, - "ZEND_VM_EXT_DIM_OBJ_WRITE" => 1<<22, - "ZEND_VM_EXT_MASK" => 0x0f000000, - "ZEND_VM_EXT_NUM" => 0x01000000, - "ZEND_VM_EXT_LAST_CATCH" => 0x02000000, - "ZEND_VM_EXT_JMP_ADDR" => 0x03000000, - "ZEND_VM_EXT_OP" => 0x04000000, + "ZEND_VM_OP_SPEC" => 1<<0, + "ZEND_VM_OP_CONST" => 1<<1, + "ZEND_VM_OP_TMPVAR" => 1<<2, + "ZEND_VM_OP_TMPVARCV" => 1<<3, + "ZEND_VM_OP_MASK" => 0xf0, + "ZEND_VM_OP_NUM" => 0x10, + "ZEND_VM_OP_JMP_ADDR" => 0x20, + "ZEND_VM_OP_TRY_CATCH" => 0x30, + // unused 0x40 + "ZEND_VM_OP_THIS" => 0x50, + "ZEND_VM_OP_NEXT" => 0x60, + "ZEND_VM_OP_CLASS_FETCH" => 0x70, + "ZEND_VM_OP_CONSTRUCTOR" => 0x80, + "ZEND_VM_OP_CONST_FETCH" => 0x90, + "ZEND_VM_OP_CACHE_SLOT" => 0xa0, + + "ZEND_VM_EXT_VAR_FETCH" => 1<<16, + "ZEND_VM_EXT_ISSET" => 1<<17, + "ZEND_VM_EXT_CACHE_SLOT" => 1<<18, + "ZEND_VM_EXT_ARRAY_INIT" => 1<<19, + "ZEND_VM_EXT_REF" => 1<<20, + "ZEND_VM_EXT_FETCH_REF" => 1<<21, + "ZEND_VM_EXT_DIM_OBJ_WRITE" => 1<<22, + "ZEND_VM_EXT_MASK" => 0x0f000000, + "ZEND_VM_EXT_NUM" => 0x01000000, + "ZEND_VM_EXT_LAST_CATCH" => 0x02000000, + "ZEND_VM_EXT_JMP_ADDR" => 0x03000000, + "ZEND_VM_EXT_OP" => 0x04000000, // unused 0x5000000 // unused 0x6000000 - "ZEND_VM_EXT_TYPE" => 0x07000000, - "ZEND_VM_EXT_EVAL" => 0x08000000, - "ZEND_VM_EXT_TYPE_MASK" => 0x09000000, - // unused 0x0a000000, - "ZEND_VM_EXT_SRC" => 0x0b000000, - // unused 0x0c000000, - "ZEND_VM_NO_CONST_CONST" => 0x40000000, - "ZEND_VM_COMMUTATIVE" => 0x80000000, + "ZEND_VM_EXT_TYPE" => 0x07000000, + "ZEND_VM_EXT_EVAL" => 0x08000000, + "ZEND_VM_EXT_TYPE_MASK" => 0x09000000, + // unused 0x0a000000, + "ZEND_VM_EXT_SRC" => 0x0b000000, + // unused 0x0c000000, + "ZEND_VM_NO_CONST_CONST" => 0x40000000, + "ZEND_VM_COMMUTATIVE" => 0x80000000, ); foreach ($vm_op_flags as $name => $val) { - define($name, $val); + define($name, $val); } $vm_op_decode = array( - "ANY" => 0, - "CONST" => ZEND_VM_OP_SPEC | ZEND_VM_OP_CONST, - "TMP" => ZEND_VM_OP_SPEC, - "VAR" => ZEND_VM_OP_SPEC, - "UNUSED" => ZEND_VM_OP_SPEC, - "CV" => ZEND_VM_OP_SPEC, - "TMPVAR" => ZEND_VM_OP_SPEC | ZEND_VM_OP_TMPVAR, - "TMPVARCV" => ZEND_VM_OP_SPEC | ZEND_VM_OP_TMPVARCV, - "NUM" => ZEND_VM_OP_NUM, - "JMP_ADDR" => ZEND_VM_OP_JMP_ADDR, - "TRY_CATCH" => ZEND_VM_OP_TRY_CATCH, - "THIS" => ZEND_VM_OP_THIS, - "NEXT" => ZEND_VM_OP_NEXT, - "CLASS_FETCH" => ZEND_VM_OP_CLASS_FETCH, - "CONSTRUCTOR" => ZEND_VM_OP_CONSTRUCTOR, - "CONST_FETCH" => ZEND_VM_OP_CONST_FETCH, - "CACHE_SLOT" => ZEND_VM_OP_CACHE_SLOT, + "ANY" => 0, + "CONST" => ZEND_VM_OP_SPEC | ZEND_VM_OP_CONST, + "TMP" => ZEND_VM_OP_SPEC, + "VAR" => ZEND_VM_OP_SPEC, + "UNUSED" => ZEND_VM_OP_SPEC, + "CV" => ZEND_VM_OP_SPEC, + "TMPVAR" => ZEND_VM_OP_SPEC | ZEND_VM_OP_TMPVAR, + "TMPVARCV" => ZEND_VM_OP_SPEC | ZEND_VM_OP_TMPVARCV, + "NUM" => ZEND_VM_OP_NUM, + "JMP_ADDR" => ZEND_VM_OP_JMP_ADDR, + "TRY_CATCH" => ZEND_VM_OP_TRY_CATCH, + "THIS" => ZEND_VM_OP_THIS, + "NEXT" => ZEND_VM_OP_NEXT, + "CLASS_FETCH" => ZEND_VM_OP_CLASS_FETCH, + "CONSTRUCTOR" => ZEND_VM_OP_CONSTRUCTOR, + "CONST_FETCH" => ZEND_VM_OP_CONST_FETCH, + "CACHE_SLOT" => ZEND_VM_OP_CACHE_SLOT, ); $vm_ext_decode = array( - "NUM" => ZEND_VM_EXT_NUM, - "LAST_CATCH" => ZEND_VM_EXT_LAST_CATCH, - "JMP_ADDR" => ZEND_VM_EXT_JMP_ADDR, - "OP" => ZEND_VM_EXT_OP, - "VAR_FETCH" => ZEND_VM_EXT_VAR_FETCH, - "ARRAY_INIT" => ZEND_VM_EXT_ARRAY_INIT, - "TYPE" => ZEND_VM_EXT_TYPE, - "EVAL" => ZEND_VM_EXT_EVAL, - "TYPE_MASK" => ZEND_VM_EXT_TYPE_MASK, - "ISSET" => ZEND_VM_EXT_ISSET, - "REF" => ZEND_VM_EXT_REF, - "FETCH_REF" => ZEND_VM_EXT_FETCH_REF, - "SRC" => ZEND_VM_EXT_SRC, - "CACHE_SLOT" => ZEND_VM_EXT_CACHE_SLOT, - "DIM_OBJ_WRITE" => ZEND_VM_EXT_DIM_OBJ_WRITE, + "NUM" => ZEND_VM_EXT_NUM, + "LAST_CATCH" => ZEND_VM_EXT_LAST_CATCH, + "JMP_ADDR" => ZEND_VM_EXT_JMP_ADDR, + "OP" => ZEND_VM_EXT_OP, + "VAR_FETCH" => ZEND_VM_EXT_VAR_FETCH, + "ARRAY_INIT" => ZEND_VM_EXT_ARRAY_INIT, + "TYPE" => ZEND_VM_EXT_TYPE, + "EVAL" => ZEND_VM_EXT_EVAL, + "TYPE_MASK" => ZEND_VM_EXT_TYPE_MASK, + "ISSET" => ZEND_VM_EXT_ISSET, + "REF" => ZEND_VM_EXT_REF, + "FETCH_REF" => ZEND_VM_EXT_FETCH_REF, + "SRC" => ZEND_VM_EXT_SRC, + "CACHE_SLOT" => ZEND_VM_EXT_CACHE_SLOT, + "DIM_OBJ_WRITE" => ZEND_VM_EXT_DIM_OBJ_WRITE, ); $vm_kind_name = array( - ZEND_VM_KIND_CALL => "ZEND_VM_KIND_CALL", - ZEND_VM_KIND_SWITCH => "ZEND_VM_KIND_SWITCH", - ZEND_VM_KIND_GOTO => "ZEND_VM_KIND_GOTO", - ZEND_VM_KIND_HYBRID => "ZEND_VM_KIND_HYBRID", + ZEND_VM_KIND_CALL => "ZEND_VM_KIND_CALL", + ZEND_VM_KIND_SWITCH => "ZEND_VM_KIND_SWITCH", + ZEND_VM_KIND_GOTO => "ZEND_VM_KIND_GOTO", + ZEND_VM_KIND_HYBRID => "ZEND_VM_KIND_HYBRID", ); $op_types = array( - "ANY", - "CONST", - "TMP", - "VAR", - "UNUSED", - "CV" + "ANY", + "CONST", + "TMP", + "VAR", + "UNUSED", + "CV" ); $op_types_ex = array( - "ANY", - "CONST", - "TMPVARCV", - "TMPVAR", - "TMP", - "VAR", - "UNUSED", - "CV", + "ANY", + "CONST", + "TMPVARCV", + "TMPVAR", + "TMP", + "VAR", + "UNUSED", + "CV", ); $prefix = array( - "ANY" => "", - "TMP" => "_TMP", - "VAR" => "_VAR", - "CONST" => "_CONST", - "UNUSED" => "_UNUSED", - "CV" => "_CV", - "TMPVAR" => "_TMPVAR", - "TMPVARCV" => "_TMPVARCV", + "ANY" => "", + "TMP" => "_TMP", + "VAR" => "_VAR", + "CONST" => "_CONST", + "UNUSED" => "_UNUSED", + "CV" => "_CV", + "TMPVAR" => "_TMPVAR", + "TMPVARCV" => "_TMPVARCV", ); $commutative_order = array( - "ANY" => 0, - "TMP" => 1, - "VAR" => 2, - "CONST" => 0, - "UNUSED" => 0, - "CV" => 4, - "TMPVAR" => 2, - "TMPVARCV" => 4, + "ANY" => 0, + "TMP" => 1, + "VAR" => 2, + "CONST" => 0, + "UNUSED" => 0, + "CV" => 4, + "TMPVAR" => 2, + "TMPVARCV" => 4, ); $op1_type = array( - "ANY" => "opline->op1_type", - "TMP" => "IS_TMP_VAR", - "VAR" => "IS_VAR", - "CONST" => "IS_CONST", - "UNUSED" => "IS_UNUSED", - "CV" => "IS_CV", - "TMPVAR" => "(IS_TMP_VAR|IS_VAR)", - "TMPVARCV" => "(IS_TMP_VAR|IS_VAR|IS_CV)", + "ANY" => "opline->op1_type", + "TMP" => "IS_TMP_VAR", + "VAR" => "IS_VAR", + "CONST" => "IS_CONST", + "UNUSED" => "IS_UNUSED", + "CV" => "IS_CV", + "TMPVAR" => "(IS_TMP_VAR|IS_VAR)", + "TMPVARCV" => "(IS_TMP_VAR|IS_VAR|IS_CV)", ); $op2_type = array( - "ANY" => "opline->op2_type", - "TMP" => "IS_TMP_VAR", - "VAR" => "IS_VAR", - "CONST" => "IS_CONST", - "UNUSED" => "IS_UNUSED", - "CV" => "IS_CV", - "TMPVAR" => "(IS_TMP_VAR|IS_VAR)", - "TMPVARCV" => "(IS_TMP_VAR|IS_VAR|IS_CV)", + "ANY" => "opline->op2_type", + "TMP" => "IS_TMP_VAR", + "VAR" => "IS_VAR", + "CONST" => "IS_CONST", + "UNUSED" => "IS_UNUSED", + "CV" => "IS_CV", + "TMPVAR" => "(IS_TMP_VAR|IS_VAR)", + "TMPVARCV" => "(IS_TMP_VAR|IS_VAR|IS_CV)", ); $op1_free = array( - "ANY" => "(free_op1 != NULL)", - "TMP" => "1", - "VAR" => "(free_op1 != NULL)", - "CONST" => "0", - "UNUSED" => "0", - "CV" => "0", - "TMPVAR" => "???", - "TMPVARCV" => "???", + "ANY" => "(free_op1 != NULL)", + "TMP" => "1", + "VAR" => "(free_op1 != NULL)", + "CONST" => "0", + "UNUSED" => "0", + "CV" => "0", + "TMPVAR" => "???", + "TMPVARCV" => "???", ); $op2_free = array( - "ANY" => "(free_op2 != NULL)", - "TMP" => "1", - "VAR" => "(free_op2 != NULL)", - "CONST" => "0", - "UNUSED" => "0", - "CV" => "0", - "TMPVAR" => "???", - "TMPVARCV" => "???", + "ANY" => "(free_op2 != NULL)", + "TMP" => "1", + "VAR" => "(free_op2 != NULL)", + "CONST" => "0", + "UNUSED" => "0", + "CV" => "0", + "TMPVAR" => "???", + "TMPVARCV" => "???", ); $op1_get_zval_ptr = array( - "ANY" => "get_zval_ptr(opline->op1_type, opline->op1, &free_op1, \\1)", - "TMP" => "_get_zval_ptr_tmp(opline->op1.var, &free_op1 EXECUTE_DATA_CC)", - "VAR" => "_get_zval_ptr_var(opline->op1.var, &free_op1 EXECUTE_DATA_CC)", - "CONST" => "RT_CONSTANT(opline, opline->op1)", - "UNUSED" => "NULL", - "CV" => "_get_zval_ptr_cv_\\1(opline->op1.var EXECUTE_DATA_CC)", - "TMPVAR" => "_get_zval_ptr_var(opline->op1.var, &free_op1 EXECUTE_DATA_CC)", - "TMPVARCV" => "???", + "ANY" => "get_zval_ptr(opline->op1_type, opline->op1, &free_op1, \\1)", + "TMP" => "_get_zval_ptr_tmp(opline->op1.var, &free_op1 EXECUTE_DATA_CC)", + "VAR" => "_get_zval_ptr_var(opline->op1.var, &free_op1 EXECUTE_DATA_CC)", + "CONST" => "RT_CONSTANT(opline, opline->op1)", + "UNUSED" => "NULL", + "CV" => "_get_zval_ptr_cv_\\1(opline->op1.var EXECUTE_DATA_CC)", + "TMPVAR" => "_get_zval_ptr_var(opline->op1.var, &free_op1 EXECUTE_DATA_CC)", + "TMPVARCV" => "???", ); $op2_get_zval_ptr = array( - "ANY" => "get_zval_ptr(opline->op2_type, opline->op2, &free_op2, \\1)", - "TMP" => "_get_zval_ptr_tmp(opline->op2.var, &free_op2 EXECUTE_DATA_CC)", - "VAR" => "_get_zval_ptr_var(opline->op2.var, &free_op2 EXECUTE_DATA_CC)", - "CONST" => "RT_CONSTANT(opline, opline->op2)", - "UNUSED" => "NULL", - "CV" => "_get_zval_ptr_cv_\\1(opline->op2.var EXECUTE_DATA_CC)", - "TMPVAR" => "_get_zval_ptr_var(opline->op2.var, &free_op2 EXECUTE_DATA_CC)", - "TMPVARCV" => "???", + "ANY" => "get_zval_ptr(opline->op2_type, opline->op2, &free_op2, \\1)", + "TMP" => "_get_zval_ptr_tmp(opline->op2.var, &free_op2 EXECUTE_DATA_CC)", + "VAR" => "_get_zval_ptr_var(opline->op2.var, &free_op2 EXECUTE_DATA_CC)", + "CONST" => "RT_CONSTANT(opline, opline->op2)", + "UNUSED" => "NULL", + "CV" => "_get_zval_ptr_cv_\\1(opline->op2.var EXECUTE_DATA_CC)", + "TMPVAR" => "_get_zval_ptr_var(opline->op2.var, &free_op2 EXECUTE_DATA_CC)", + "TMPVARCV" => "???", ); $op1_get_zval_ptr_ptr = array( - "ANY" => "get_zval_ptr_ptr(opline->op1_type, opline->op1, &free_op1, \\1)", - "TMP" => "NULL", - "VAR" => "_get_zval_ptr_ptr_var(opline->op1.var, &free_op1 EXECUTE_DATA_CC)", - "CONST" => "NULL", - "UNUSED" => "NULL", - "CV" => "_get_zval_ptr_cv_\\1(opline->op1.var EXECUTE_DATA_CC)", - "TMPVAR" => "???", - "TMPVARCV" => "???", + "ANY" => "get_zval_ptr_ptr(opline->op1_type, opline->op1, &free_op1, \\1)", + "TMP" => "NULL", + "VAR" => "_get_zval_ptr_ptr_var(opline->op1.var, &free_op1 EXECUTE_DATA_CC)", + "CONST" => "NULL", + "UNUSED" => "NULL", + "CV" => "_get_zval_ptr_cv_\\1(opline->op1.var EXECUTE_DATA_CC)", + "TMPVAR" => "???", + "TMPVARCV" => "???", ); $op2_get_zval_ptr_ptr = array( - "ANY" => "get_zval_ptr_ptr(opline->op2_type, opline->op2, &free_op2, \\1)", - "TMP" => "NULL", - "VAR" => "_get_zval_ptr_ptr_var(opline->op2.var, &free_op2 EXECUTE_DATA_CC)", - "CONST" => "NULL", - "UNUSED" => "NULL", - "CV" => "_get_zval_ptr_cv_\\1(opline->op2.var EXECUTE_DATA_CC)", - "TMPVAR" => "???", - "TMPVARCV" => "???", + "ANY" => "get_zval_ptr_ptr(opline->op2_type, opline->op2, &free_op2, \\1)", + "TMP" => "NULL", + "VAR" => "_get_zval_ptr_ptr_var(opline->op2.var, &free_op2 EXECUTE_DATA_CC)", + "CONST" => "NULL", + "UNUSED" => "NULL", + "CV" => "_get_zval_ptr_cv_\\1(opline->op2.var EXECUTE_DATA_CC)", + "TMPVAR" => "???", + "TMPVARCV" => "???", ); $op1_get_zval_ptr_deref = array( - "ANY" => "get_zval_ptr_deref(opline->op1_type, opline->op1, &free_op1, \\1)", - "TMP" => "_get_zval_ptr_tmp(opline->op1.var, &free_op1 EXECUTE_DATA_CC)", - "VAR" => "_get_zval_ptr_var_deref(opline->op1.var, &free_op1 EXECUTE_DATA_CC)", - "CONST" => "RT_CONSTANT(opline, opline->op1)", - "UNUSED" => "NULL", - "CV" => "_get_zval_ptr_cv_deref_\\1(opline->op1.var EXECUTE_DATA_CC)", - "TMPVAR" => "???", - "TMPVARCV" => "???", + "ANY" => "get_zval_ptr_deref(opline->op1_type, opline->op1, &free_op1, \\1)", + "TMP" => "_get_zval_ptr_tmp(opline->op1.var, &free_op1 EXECUTE_DATA_CC)", + "VAR" => "_get_zval_ptr_var_deref(opline->op1.var, &free_op1 EXECUTE_DATA_CC)", + "CONST" => "RT_CONSTANT(opline, opline->op1)", + "UNUSED" => "NULL", + "CV" => "_get_zval_ptr_cv_deref_\\1(opline->op1.var EXECUTE_DATA_CC)", + "TMPVAR" => "???", + "TMPVARCV" => "???", ); $op2_get_zval_ptr_deref = array( - "ANY" => "get_zval_ptr_deref(opline->op2_type, opline->op2, &free_op2, \\1)", - "TMP" => "_get_zval_ptr_tmp(opline->op2.var, &free_op2 EXECUTE_DATA_CC)", - "VAR" => "_get_zval_ptr_var_deref(opline->op2.var, &free_op2 EXECUTE_DATA_CC)", - "CONST" => "RT_CONSTANT(opline, opline->op2)", - "UNUSED" => "NULL", - "CV" => "_get_zval_ptr_cv_deref_\\1(opline->op2.var EXECUTE_DATA_CC)", - "TMPVAR" => "???", - "TMPVARCV" => "???", + "ANY" => "get_zval_ptr_deref(opline->op2_type, opline->op2, &free_op2, \\1)", + "TMP" => "_get_zval_ptr_tmp(opline->op2.var, &free_op2 EXECUTE_DATA_CC)", + "VAR" => "_get_zval_ptr_var_deref(opline->op2.var, &free_op2 EXECUTE_DATA_CC)", + "CONST" => "RT_CONSTANT(opline, opline->op2)", + "UNUSED" => "NULL", + "CV" => "_get_zval_ptr_cv_deref_\\1(opline->op2.var EXECUTE_DATA_CC)", + "TMPVAR" => "???", + "TMPVARCV" => "???", ); $op1_get_zval_ptr_undef = array( - "ANY" => "get_zval_ptr_undef(opline->op1_type, opline->op1, &free_op1, \\1)", - "TMP" => "_get_zval_ptr_tmp(opline->op1.var, &free_op1 EXECUTE_DATA_CC)", - "VAR" => "_get_zval_ptr_var(opline->op1.var, &free_op1 EXECUTE_DATA_CC)", - "CONST" => "RT_CONSTANT(opline, opline->op1)", - "UNUSED" => "NULL", - "CV" => "EX_VAR(opline->op1.var)", - "TMPVAR" => "_get_zval_ptr_var(opline->op1.var, &free_op1 EXECUTE_DATA_CC)", - "TMPVARCV" => "EX_VAR(opline->op1.var)", + "ANY" => "get_zval_ptr_undef(opline->op1_type, opline->op1, &free_op1, \\1)", + "TMP" => "_get_zval_ptr_tmp(opline->op1.var, &free_op1 EXECUTE_DATA_CC)", + "VAR" => "_get_zval_ptr_var(opline->op1.var, &free_op1 EXECUTE_DATA_CC)", + "CONST" => "RT_CONSTANT(opline, opline->op1)", + "UNUSED" => "NULL", + "CV" => "EX_VAR(opline->op1.var)", + "TMPVAR" => "_get_zval_ptr_var(opline->op1.var, &free_op1 EXECUTE_DATA_CC)", + "TMPVARCV" => "EX_VAR(opline->op1.var)", ); $op2_get_zval_ptr_undef = array( - "ANY" => "get_zval_ptr_undef(opline->op2_type, opline->op2, &free_op2, \\1)", - "TMP" => "_get_zval_ptr_tmp(opline->op2.var, &free_op2 EXECUTE_DATA_CC)", - "VAR" => "_get_zval_ptr_var(opline->op2.var, &free_op2 EXECUTE_DATA_CC)", - "CONST" => "RT_CONSTANT(opline, opline->op2)", - "UNUSED" => "NULL", - "CV" => "EX_VAR(opline->op2.var)", - "TMPVAR" => "_get_zval_ptr_var(opline->op2.var, &free_op2 EXECUTE_DATA_CC)", - "TMPVARCV" => "EX_VAR(opline->op2.var)", + "ANY" => "get_zval_ptr_undef(opline->op2_type, opline->op2, &free_op2, \\1)", + "TMP" => "_get_zval_ptr_tmp(opline->op2.var, &free_op2 EXECUTE_DATA_CC)", + "VAR" => "_get_zval_ptr_var(opline->op2.var, &free_op2 EXECUTE_DATA_CC)", + "CONST" => "RT_CONSTANT(opline, opline->op2)", + "UNUSED" => "NULL", + "CV" => "EX_VAR(opline->op2.var)", + "TMPVAR" => "_get_zval_ptr_var(opline->op2.var, &free_op2 EXECUTE_DATA_CC)", + "TMPVARCV" => "EX_VAR(opline->op2.var)", ); $op1_get_zval_ptr_ptr_undef = array( - "ANY" => "get_zval_ptr_ptr_undef(opline->op1_type, opline->op1, &free_op1, \\1)", - "TMP" => "NULL", - "VAR" => "_get_zval_ptr_ptr_var(opline->op1.var, &free_op1 EXECUTE_DATA_CC)", - "CONST" => "NULL", - "UNUSED" => "NULL", - "CV" => "EX_VAR(opline->op1.var)", - "TMPVAR" => "???", - "TMPVARCV" => "???", + "ANY" => "get_zval_ptr_ptr_undef(opline->op1_type, opline->op1, &free_op1, \\1)", + "TMP" => "NULL", + "VAR" => "_get_zval_ptr_ptr_var(opline->op1.var, &free_op1 EXECUTE_DATA_CC)", + "CONST" => "NULL", + "UNUSED" => "NULL", + "CV" => "EX_VAR(opline->op1.var)", + "TMPVAR" => "???", + "TMPVARCV" => "???", ); $op2_get_zval_ptr_ptr_undef = array( - "ANY" => "get_zval_ptr_ptr_undef(opline->op2_type, opline->op2, &free_op2, \\1)", - "TMP" => "NULL", - "VAR" => "_get_zval_ptr_ptr_var(opline->op2.var, &free_op2 EXECUTE_DATA_CC)", - "CONST" => "NULL", - "UNUSED" => "NULL", - "CV" => "EX_VAR(opline->op2.var)", - "TMPVAR" => "???", - "TMPVARCV" => "???", + "ANY" => "get_zval_ptr_ptr_undef(opline->op2_type, opline->op2, &free_op2, \\1)", + "TMP" => "NULL", + "VAR" => "_get_zval_ptr_ptr_var(opline->op2.var, &free_op2 EXECUTE_DATA_CC)", + "CONST" => "NULL", + "UNUSED" => "NULL", + "CV" => "EX_VAR(opline->op2.var)", + "TMPVAR" => "???", + "TMPVARCV" => "???", ); $op1_get_obj_zval_ptr = array( - "ANY" => "get_obj_zval_ptr(opline->op1_type, opline->op1, &free_op1, \\1)", - "TMP" => "_get_zval_ptr_tmp(opline->op1.var, &free_op1 EXECUTE_DATA_CC)", - "VAR" => "_get_zval_ptr_var(opline->op1.var, &free_op1 EXECUTE_DATA_CC)", - "CONST" => "RT_CONSTANT(opline, opline->op1)", - "UNUSED" => "&EX(This)", - "CV" => "_get_zval_ptr_cv_\\1(opline->op1.var EXECUTE_DATA_CC)", - "TMPVAR" => "_get_zval_ptr_var(opline->op1.var, &free_op1 EXECUTE_DATA_CC)", - "TMPVARCV" => "???", + "ANY" => "get_obj_zval_ptr(opline->op1_type, opline->op1, &free_op1, \\1)", + "TMP" => "_get_zval_ptr_tmp(opline->op1.var, &free_op1 EXECUTE_DATA_CC)", + "VAR" => "_get_zval_ptr_var(opline->op1.var, &free_op1 EXECUTE_DATA_CC)", + "CONST" => "RT_CONSTANT(opline, opline->op1)", + "UNUSED" => "&EX(This)", + "CV" => "_get_zval_ptr_cv_\\1(opline->op1.var EXECUTE_DATA_CC)", + "TMPVAR" => "_get_zval_ptr_var(opline->op1.var, &free_op1 EXECUTE_DATA_CC)", + "TMPVARCV" => "???", ); $op2_get_obj_zval_ptr = array( - "ANY" => "get_obj_zval_ptr(opline->op2_type, opline->op2, &free_op2, \\1)", - "TMP" => "_get_zval_ptr_tmp(opline->op2.var, &free_op2 EXECUTE_DATA_CC)", - "VAR" => "_get_zval_ptr_var(opline->op2.var, &free_op2 EXECUTE_DATA_CC)", - "CONST" => "RT_CONSTANT(opline, opline->op2)", - "UNUSED" => "&EX(This)", - "CV" => "_get_zval_ptr_cv_\\1(opline->op2.var EXECUTE_DATA_CC)", - "TMPVAR" => "_get_zval_ptr_var(opline->op2.var, &free_op2 EXECUTE_DATA_CC)", - "TMPVARCV" => "???", + "ANY" => "get_obj_zval_ptr(opline->op2_type, opline->op2, &free_op2, \\1)", + "TMP" => "_get_zval_ptr_tmp(opline->op2.var, &free_op2 EXECUTE_DATA_CC)", + "VAR" => "_get_zval_ptr_var(opline->op2.var, &free_op2 EXECUTE_DATA_CC)", + "CONST" => "RT_CONSTANT(opline, opline->op2)", + "UNUSED" => "&EX(This)", + "CV" => "_get_zval_ptr_cv_\\1(opline->op2.var EXECUTE_DATA_CC)", + "TMPVAR" => "_get_zval_ptr_var(opline->op2.var, &free_op2 EXECUTE_DATA_CC)", + "TMPVARCV" => "???", ); $op1_get_obj_zval_ptr_undef = array( - "ANY" => "get_obj_zval_ptr_undef(opline->op1_type, opline->op1, &free_op1, \\1)", - "TMP" => "_get_zval_ptr_tmp(opline->op1.var, &free_op1 EXECUTE_DATA_CC)", - "VAR" => "_get_zval_ptr_var(opline->op1.var, &free_op1 EXECUTE_DATA_CC)", - "CONST" => "RT_CONSTANT(opline, opline->op1)", - "UNUSED" => "&EX(This)", - "CV" => "EX_VAR(opline->op1.var)", - "TMPVAR" => "_get_zval_ptr_var(opline->op1.var, &free_op1 EXECUTE_DATA_CC)", - "TMPVARCV" => "EX_VAR(opline->op1.var)", + "ANY" => "get_obj_zval_ptr_undef(opline->op1_type, opline->op1, &free_op1, \\1)", + "TMP" => "_get_zval_ptr_tmp(opline->op1.var, &free_op1 EXECUTE_DATA_CC)", + "VAR" => "_get_zval_ptr_var(opline->op1.var, &free_op1 EXECUTE_DATA_CC)", + "CONST" => "RT_CONSTANT(opline, opline->op1)", + "UNUSED" => "&EX(This)", + "CV" => "EX_VAR(opline->op1.var)", + "TMPVAR" => "_get_zval_ptr_var(opline->op1.var, &free_op1 EXECUTE_DATA_CC)", + "TMPVARCV" => "EX_VAR(opline->op1.var)", ); $op2_get_obj_zval_ptr_undef = array( - "ANY" => "get_obj_zval_ptr_undef(opline->op2_type, opline->op2, &free_op2, \\1)", - "TMP" => "_get_zval_ptr_tmp(opline->op2.var, &free_op2 EXECUTE_DATA_CC)", - "VAR" => "_get_zval_ptr_var(opline->op2.var, &free_op2 EXECUTE_DATA_CC)", - "CONST" => "RT_CONSTANT(opline, opline->op2)", - "UNUSED" => "&EX(This)", - "CV" => "EX_VAR(opline->op2.var)", - "TMPVAR" => "_get_zval_ptr_var(opline->op2.var, &free_op2 EXECUTE_DATA_CC)", - "TMPVARCV" => "EX_VAR(opline->op2.var)", + "ANY" => "get_obj_zval_ptr_undef(opline->op2_type, opline->op2, &free_op2, \\1)", + "TMP" => "_get_zval_ptr_tmp(opline->op2.var, &free_op2 EXECUTE_DATA_CC)", + "VAR" => "_get_zval_ptr_var(opline->op2.var, &free_op2 EXECUTE_DATA_CC)", + "CONST" => "RT_CONSTANT(opline, opline->op2)", + "UNUSED" => "&EX(This)", + "CV" => "EX_VAR(opline->op2.var)", + "TMPVAR" => "_get_zval_ptr_var(opline->op2.var, &free_op2 EXECUTE_DATA_CC)", + "TMPVARCV" => "EX_VAR(opline->op2.var)", ); $op1_get_obj_zval_ptr_deref = array( - "ANY" => "get_obj_zval_ptr(opline->op1_type, opline->op1, &free_op1, \\1)", - "TMP" => "_get_zval_ptr_tmp(opline->op1.var, &free_op1 EXECUTE_DATA_CC)", - "VAR" => "_get_zval_ptr_var_deref(opline->op1.var, &free_op1 EXECUTE_DATA_CC)", - "CONST" => "RT_CONSTANT(opline, opline->op1)", - "UNUSED" => "&EX(This)", - "CV" => "_get_zval_ptr_cv_deref_\\1(opline->op1.var EXECUTE_DATA_CC)", - "TMPVAR" => "???", - "TMPVARCV" => "???", + "ANY" => "get_obj_zval_ptr(opline->op1_type, opline->op1, &free_op1, \\1)", + "TMP" => "_get_zval_ptr_tmp(opline->op1.var, &free_op1 EXECUTE_DATA_CC)", + "VAR" => "_get_zval_ptr_var_deref(opline->op1.var, &free_op1 EXECUTE_DATA_CC)", + "CONST" => "RT_CONSTANT(opline, opline->op1)", + "UNUSED" => "&EX(This)", + "CV" => "_get_zval_ptr_cv_deref_\\1(opline->op1.var EXECUTE_DATA_CC)", + "TMPVAR" => "???", + "TMPVARCV" => "???", ); $op2_get_obj_zval_ptr_deref = array( - "ANY" => "get_obj_zval_ptr(opline->op2_type, opline->op2, &free_op2, \\1)", - "TMP" => "_get_zval_ptr_tmp(opline->op2.var, &free_op2 EXECUTE_DATA_CC)", - "VAR" => "_get_zval_ptr_var_deref(opline->op2.var, &free_op2 EXECUTE_DATA_CC)", - "CONST" => "RT_CONSTANT(opline, opline->op2)", - "UNUSED" => "&EX(This)", - "CV" => "_get_zval_ptr_cv_deref_\\1(opline->op2.var EXECUTE_DATA_CC)", - "TMPVAR" => "???", - "TMPVARCV" => "???", + "ANY" => "get_obj_zval_ptr(opline->op2_type, opline->op2, &free_op2, \\1)", + "TMP" => "_get_zval_ptr_tmp(opline->op2.var, &free_op2 EXECUTE_DATA_CC)", + "VAR" => "_get_zval_ptr_var_deref(opline->op2.var, &free_op2 EXECUTE_DATA_CC)", + "CONST" => "RT_CONSTANT(opline, opline->op2)", + "UNUSED" => "&EX(This)", + "CV" => "_get_zval_ptr_cv_deref_\\1(opline->op2.var EXECUTE_DATA_CC)", + "TMPVAR" => "???", + "TMPVARCV" => "???", ); $op1_get_obj_zval_ptr_ptr = array( - "ANY" => "get_obj_zval_ptr_ptr(opline->op1_type, opline->op1, &free_op1, \\1)", - "TMP" => "NULL", - "VAR" => "_get_zval_ptr_ptr_var(opline->op1.var, &free_op1 EXECUTE_DATA_CC)", - "CONST" => "NULL", - "UNUSED" => "&EX(This)", - "CV" => "_get_zval_ptr_cv_\\1(opline->op1.var EXECUTE_DATA_CC)", - "TMPVAR" => "???", - "TMPVARCV" => "???", + "ANY" => "get_obj_zval_ptr_ptr(opline->op1_type, opline->op1, &free_op1, \\1)", + "TMP" => "NULL", + "VAR" => "_get_zval_ptr_ptr_var(opline->op1.var, &free_op1 EXECUTE_DATA_CC)", + "CONST" => "NULL", + "UNUSED" => "&EX(This)", + "CV" => "_get_zval_ptr_cv_\\1(opline->op1.var EXECUTE_DATA_CC)", + "TMPVAR" => "???", + "TMPVARCV" => "???", ); $op2_get_obj_zval_ptr_ptr = array( - "ANY" => "get_obj_zval_ptr_ptr(opline->op2_type, opline->op2, &free_op2, \\1)", - "TMP" => "NULL", - "VAR" => "_get_zval_ptr_ptr_var(opline->op2.var, &free_op2 EXECUTE_DATA_CC)", - "CONST" => "NULL", - "UNUSED" => "&EX(This)", - "CV" => "_get_zval_ptr_cv_\\1(opline->op2.var EXECUTE_DATA_CC)", - "TMPVAR" => "???", - "TMPVARCV" => "???", + "ANY" => "get_obj_zval_ptr_ptr(opline->op2_type, opline->op2, &free_op2, \\1)", + "TMP" => "NULL", + "VAR" => "_get_zval_ptr_ptr_var(opline->op2.var, &free_op2 EXECUTE_DATA_CC)", + "CONST" => "NULL", + "UNUSED" => "&EX(This)", + "CV" => "_get_zval_ptr_cv_\\1(opline->op2.var EXECUTE_DATA_CC)", + "TMPVAR" => "???", + "TMPVARCV" => "???", ); $op1_get_obj_zval_ptr_ptr_undef = array( - "ANY" => "get_obj_zval_ptr_ptr(opline->op1_type, opline->op1, &free_op1, \\1)", - "TMP" => "NULL", - "VAR" => "_get_zval_ptr_ptr_var(opline->op1.var, &free_op1 EXECUTE_DATA_CC)", - "CONST" => "NULL", - "UNUSED" => "&EX(This)", - "CV" => "EX_VAR(opline->op1.var)", - "TMPVAR" => "???", - "TMPVARCV" => "???", + "ANY" => "get_obj_zval_ptr_ptr(opline->op1_type, opline->op1, &free_op1, \\1)", + "TMP" => "NULL", + "VAR" => "_get_zval_ptr_ptr_var(opline->op1.var, &free_op1 EXECUTE_DATA_CC)", + "CONST" => "NULL", + "UNUSED" => "&EX(This)", + "CV" => "EX_VAR(opline->op1.var)", + "TMPVAR" => "???", + "TMPVARCV" => "???", ); $op2_get_obj_zval_ptr_ptr_undef = array( - "ANY" => "get_obj_zval_ptr_ptr(opline->op2_type, opline->op2, &free_op2, \\1)", - "TMP" => "NULL", - "VAR" => "_get_zval_ptr_ptr_var(opline->op2.var, &free_op2 EXECUTE_DATA_CC)", - "CONST" => "NULL", - "UNUSED" => "&EX(This)", - "CV" => "EX_VAR(opline->op2.var)", - "TMPVAR" => "???", - "TMPVARCV" => "???", + "ANY" => "get_obj_zval_ptr_ptr(opline->op2_type, opline->op2, &free_op2, \\1)", + "TMP" => "NULL", + "VAR" => "_get_zval_ptr_ptr_var(opline->op2.var, &free_op2 EXECUTE_DATA_CC)", + "CONST" => "NULL", + "UNUSED" => "&EX(This)", + "CV" => "EX_VAR(opline->op2.var)", + "TMPVAR" => "???", + "TMPVARCV" => "???", ); $op1_free_op = array( - "ANY" => "FREE_OP(free_op1)", - "TMP" => "zval_ptr_dtor_nogc(free_op1)", - "VAR" => "zval_ptr_dtor_nogc(free_op1)", - "CONST" => "", - "UNUSED" => "", - "CV" => "", - "TMPVAR" => "zval_ptr_dtor_nogc(free_op1)", - "TMPVARCV" => "???", + "ANY" => "FREE_OP(free_op1)", + "TMP" => "zval_ptr_dtor_nogc(free_op1)", + "VAR" => "zval_ptr_dtor_nogc(free_op1)", + "CONST" => "", + "UNUSED" => "", + "CV" => "", + "TMPVAR" => "zval_ptr_dtor_nogc(free_op1)", + "TMPVARCV" => "???", ); $op2_free_op = array( - "ANY" => "FREE_OP(free_op2)", - "TMP" => "zval_ptr_dtor_nogc(free_op2)", - "VAR" => "zval_ptr_dtor_nogc(free_op2)", - "CONST" => "", - "UNUSED" => "", - "CV" => "", - "TMPVAR" => "zval_ptr_dtor_nogc(free_op2)", - "TMPVARCV" => "???", + "ANY" => "FREE_OP(free_op2)", + "TMP" => "zval_ptr_dtor_nogc(free_op2)", + "VAR" => "zval_ptr_dtor_nogc(free_op2)", + "CONST" => "", + "UNUSED" => "", + "CV" => "", + "TMPVAR" => "zval_ptr_dtor_nogc(free_op2)", + "TMPVARCV" => "???", ); $op1_free_op_if_var = array( - "ANY" => "if (opline->op1_type == IS_VAR) {zval_ptr_dtor_nogc(free_op1);}", - "TMP" => "", - "VAR" => "zval_ptr_dtor_nogc(free_op1)", - "CONST" => "", - "UNUSED" => "", - "CV" => "", - "TMPVAR" => "???", - "TMPVARCV" => "???", + "ANY" => "if (opline->op1_type == IS_VAR) {zval_ptr_dtor_nogc(free_op1);}", + "TMP" => "", + "VAR" => "zval_ptr_dtor_nogc(free_op1)", + "CONST" => "", + "UNUSED" => "", + "CV" => "", + "TMPVAR" => "???", + "TMPVARCV" => "???", ); $op2_free_op_if_var = array( - "ANY" => "if (opline->op2_type == IS_VAR) {zval_ptr_dtor_nogc(free_op2);}", - "TMP" => "", - "VAR" => "zval_ptr_dtor_nogc(free_op2)", - "CONST" => "", - "UNUSED" => "", - "CV" => "", - "TMPVAR" => "???", - "TMPVARCV" => "???", + "ANY" => "if (opline->op2_type == IS_VAR) {zval_ptr_dtor_nogc(free_op2);}", + "TMP" => "", + "VAR" => "zval_ptr_dtor_nogc(free_op2)", + "CONST" => "", + "UNUSED" => "", + "CV" => "", + "TMPVAR" => "???", + "TMPVARCV" => "???", ); $op1_free_op_var_ptr = array( - "ANY" => "if (free_op1) {zval_ptr_dtor_nogc(free_op1);}", - "TMP" => "", - "VAR" => "if (UNEXPECTED(free_op1)) {zval_ptr_dtor_nogc(free_op1);}", - "CONST" => "", - "UNUSED" => "", - "CV" => "", - "TMPVAR" => "???", - "TMPVARCV" => "???", + "ANY" => "if (free_op1) {zval_ptr_dtor_nogc(free_op1);}", + "TMP" => "", + "VAR" => "if (UNEXPECTED(free_op1)) {zval_ptr_dtor_nogc(free_op1);}", + "CONST" => "", + "UNUSED" => "", + "CV" => "", + "TMPVAR" => "???", + "TMPVARCV" => "???", ); $op2_free_op_var_ptr = array( - "ANY" => "if (free_op2) {zval_ptr_dtor_nogc(free_op2);}", - "TMP" => "", - "VAR" => "if (UNEXPECTED(free_op2)) {zval_ptr_dtor_nogc(free_op2);}", - "CONST" => "", - "UNUSED" => "", - "CV" => "", - "TMPVAR" => "???", - "TMPVARCV" => "???", + "ANY" => "if (free_op2) {zval_ptr_dtor_nogc(free_op2);}", + "TMP" => "", + "VAR" => "if (UNEXPECTED(free_op2)) {zval_ptr_dtor_nogc(free_op2);}", + "CONST" => "", + "UNUSED" => "", + "CV" => "", + "TMPVAR" => "???", + "TMPVARCV" => "???", ); $op1_free_unfetched = array( - "ANY" => "FREE_UNFETCHED_OP(opline->op1_type, opline->op1.var)", - "TMP" => "zval_ptr_dtor_nogc(EX_VAR(opline->op1.var))", - "VAR" => "zval_ptr_dtor_nogc(EX_VAR(opline->op1.var))", - "CONST" => "", - "UNUSED" => "", - "CV" => "", - "TMPVAR" => "zval_ptr_dtor_nogc(EX_VAR(opline->op1.var))", - "TMPVARCV" => "???", + "ANY" => "FREE_UNFETCHED_OP(opline->op1_type, opline->op1.var)", + "TMP" => "zval_ptr_dtor_nogc(EX_VAR(opline->op1.var))", + "VAR" => "zval_ptr_dtor_nogc(EX_VAR(opline->op1.var))", + "CONST" => "", + "UNUSED" => "", + "CV" => "", + "TMPVAR" => "zval_ptr_dtor_nogc(EX_VAR(opline->op1.var))", + "TMPVARCV" => "???", ); $op2_free_unfetched = array( - "ANY" => "FREE_UNFETCHED_OP(opline->op2_type, opline->op2.var)", - "TMP" => "zval_ptr_dtor_nogc(EX_VAR(opline->op2.var))", - "VAR" => "zval_ptr_dtor_nogc(EX_VAR(opline->op2.var))", - "CONST" => "", - "UNUSED" => "", - "CV" => "", - "TMPVAR" => "zval_ptr_dtor_nogc(EX_VAR(opline->op2.var))", - "TMPVARCV" => "???", + "ANY" => "FREE_UNFETCHED_OP(opline->op2_type, opline->op2.var)", + "TMP" => "zval_ptr_dtor_nogc(EX_VAR(opline->op2.var))", + "VAR" => "zval_ptr_dtor_nogc(EX_VAR(opline->op2.var))", + "CONST" => "", + "UNUSED" => "", + "CV" => "", + "TMPVAR" => "zval_ptr_dtor_nogc(EX_VAR(opline->op2.var))", + "TMPVARCV" => "???", ); $op_data_type = array( - "ANY" => "(opline+1)->op1_type", - "TMP" => "IS_TMP_VAR", - "VAR" => "IS_VAR", - "CONST" => "IS_CONST", - "UNUSED" => "IS_UNUSED", - "CV" => "IS_CV", - "TMPVAR" => "(IS_TMP_VAR|IS_VAR)", - "TMPVARCV" => "(IS_TMP_VAR|IS_VAR|IS_CV)", + "ANY" => "(opline+1)->op1_type", + "TMP" => "IS_TMP_VAR", + "VAR" => "IS_VAR", + "CONST" => "IS_CONST", + "UNUSED" => "IS_UNUSED", + "CV" => "IS_CV", + "TMPVAR" => "(IS_TMP_VAR|IS_VAR)", + "TMPVARCV" => "(IS_TMP_VAR|IS_VAR|IS_CV)", ); $op_data_get_zval_ptr = array( - "ANY" => "get_op_data_zval_ptr_r((opline+1)->op1_type, (opline+1)->op1, &free_op_data)", - "TMP" => "_get_zval_ptr_tmp((opline+1)->op1.var, &free_op_data EXECUTE_DATA_CC)", - "VAR" => "_get_zval_ptr_var((opline+1)->op1.var, &free_op_data EXECUTE_DATA_CC)", - "CONST" => "RT_CONSTANT((opline+1), (opline+1)->op1)", - "UNUSED" => "NULL", - "CV" => "_get_zval_ptr_cv_\\1((opline+1)->op1.var EXECUTE_DATA_CC)", - "TMPVAR" => "_get_zval_ptr_var((opline+1)->op1.var, &free_op_data EXECUTE_DATA_CC)", - "TMPVARCV" => "???", + "ANY" => "get_op_data_zval_ptr_r((opline+1)->op1_type, (opline+1)->op1, &free_op_data)", + "TMP" => "_get_zval_ptr_tmp((opline+1)->op1.var, &free_op_data EXECUTE_DATA_CC)", + "VAR" => "_get_zval_ptr_var((opline+1)->op1.var, &free_op_data EXECUTE_DATA_CC)", + "CONST" => "RT_CONSTANT((opline+1), (opline+1)->op1)", + "UNUSED" => "NULL", + "CV" => "_get_zval_ptr_cv_\\1((opline+1)->op1.var EXECUTE_DATA_CC)", + "TMPVAR" => "_get_zval_ptr_var((opline+1)->op1.var, &free_op_data EXECUTE_DATA_CC)", + "TMPVARCV" => "???", ); $op_data_get_zval_ptr_deref = array( - "ANY" => "get_op_data_zval_ptr_deref_r((opline+1)->op1_type, (opline+1)->op1, &free_op_data)", - "TMP" => "_get_zval_ptr_tmp((opline+1)->op1.var, &free_op_data EXECUTE_DATA_CC)", - "VAR" => "_get_zval_ptr_var_deref((opline+1)->op1.var, &free_op_data EXECUTE_DATA_CC)", - "CONST" => "RT_CONSTANT((opline+1), (opline+1)->op1)", - "UNUSED" => "NULL", - "CV" => "_get_zval_ptr_cv_deref_\\1((opline+1)->op1.var EXECUTE_DATA_CC)", - "TMPVAR" => "???", - "TMPVARCV" => "???", + "ANY" => "get_op_data_zval_ptr_deref_r((opline+1)->op1_type, (opline+1)->op1, &free_op_data)", + "TMP" => "_get_zval_ptr_tmp((opline+1)->op1.var, &free_op_data EXECUTE_DATA_CC)", + "VAR" => "_get_zval_ptr_var_deref((opline+1)->op1.var, &free_op_data EXECUTE_DATA_CC)", + "CONST" => "RT_CONSTANT((opline+1), (opline+1)->op1)", + "UNUSED" => "NULL", + "CV" => "_get_zval_ptr_cv_deref_\\1((opline+1)->op1.var EXECUTE_DATA_CC)", + "TMPVAR" => "???", + "TMPVARCV" => "???", ); $op_data_get_zval_ptr_ptr = array( - "ANY" => "get_zval_ptr_ptr((opline+1)->op1_type, (opline+1)->op1, &free_op_data, \\1)", - "TMP" => "NULL", - "VAR" => "_get_zval_ptr_ptr_var((opline+1)->op1.var, &free_op_data EXECUTE_DATA_CC)", - "CONST" => "NULL", - "UNUSED" => "NULL", - "CV" => "_get_zval_ptr_cv_\\1((opline+1)->op1.var EXECUTE_DATA_CC)", - "TMPVAR" => "???", - "TMPVARCV" => "???", + "ANY" => "get_zval_ptr_ptr((opline+1)->op1_type, (opline+1)->op1, &free_op_data, \\1)", + "TMP" => "NULL", + "VAR" => "_get_zval_ptr_ptr_var((opline+1)->op1.var, &free_op_data EXECUTE_DATA_CC)", + "CONST" => "NULL", + "UNUSED" => "NULL", + "CV" => "_get_zval_ptr_cv_\\1((opline+1)->op1.var EXECUTE_DATA_CC)", + "TMPVAR" => "???", + "TMPVARCV" => "???", ); $op_data_free_op = array( - "ANY" => "FREE_OP(free_op_data)", - "TMP" => "zval_ptr_dtor_nogc(free_op_data)", - "VAR" => "zval_ptr_dtor_nogc(free_op_data)", - "CONST" => "", - "UNUSED" => "", - "CV" => "", - "TMPVAR" => "zval_ptr_dtor_nogc(free_op_data)", - "TMPVARCV" => "???", + "ANY" => "FREE_OP(free_op_data)", + "TMP" => "zval_ptr_dtor_nogc(free_op_data)", + "VAR" => "zval_ptr_dtor_nogc(free_op_data)", + "CONST" => "", + "UNUSED" => "", + "CV" => "", + "TMPVAR" => "zval_ptr_dtor_nogc(free_op_data)", + "TMPVARCV" => "???", ); $op_data_free_op_var_ptr = array( - "ANY" => "if (free_op_data) {zval_ptr_dtor_nogc(free_op_data);}", - "TMP" => "", - "VAR" => "if (UNEXPECTED(free_op_data)) {zval_ptr_dtor_nogc(free_op_data);}", - "CONST" => "", - "UNUSED" => "", - "CV" => "", - "TMPVAR" => "???", - "TMPVARCV" => "???", + "ANY" => "if (free_op_data) {zval_ptr_dtor_nogc(free_op_data);}", + "TMP" => "", + "VAR" => "if (UNEXPECTED(free_op_data)) {zval_ptr_dtor_nogc(free_op_data);}", + "CONST" => "", + "UNUSED" => "", + "CV" => "", + "TMPVAR" => "???", + "TMPVARCV" => "???", ); $op_data_free_unfetched = array( - "ANY" => "FREE_UNFETCHED_OP((opline+1)->op1_type, (opline+1)->op1.var)", - "TMP" => "zval_ptr_dtor_nogc(EX_VAR((opline+1)->op1.var))", - "VAR" => "zval_ptr_dtor_nogc(EX_VAR((opline+1)->op1.var))", - "CONST" => "", - "UNUSED" => "", - "CV" => "", - "TMPVAR" => "zval_ptr_dtor_nogc(EX_VAR((opline+1)->op1.var))", - "TMPVARCV" => "???", + "ANY" => "FREE_UNFETCHED_OP((opline+1)->op1_type, (opline+1)->op1.var)", + "TMP" => "zval_ptr_dtor_nogc(EX_VAR((opline+1)->op1.var))", + "VAR" => "zval_ptr_dtor_nogc(EX_VAR((opline+1)->op1.var))", + "CONST" => "", + "UNUSED" => "", + "CV" => "", + "TMPVAR" => "zval_ptr_dtor_nogc(EX_VAR((opline+1)->op1.var))", + "TMPVARCV" => "???", ); $list = array(); // list of opcode handlers and helpers in original order @@ -626,2576 +626,2576 @@ $used_extra_spec = array(); // Writes $s into resulting executor function out($f, $s) { - global $line_no; + global $line_no; - fputs($f,$s); - $line_no += substr_count($s, "\n"); + fputs($f,$s); + $line_no += substr_count($s, "\n"); } // Resets #line directives in resulting executor function out_line($f) { - global $line_no, $executor_file; + global $line_no, $executor_file; - fputs($f,"#line ".($line_no+1)." \"".$executor_file."\"\n"); - ++$line_no; + fputs($f,"#line ".($line_no+1)." \"".$executor_file."\"\n"); + ++$line_no; } function is_hot_helper($name) { - global $helpers; + global $helpers; - if (isset($helpers[$name]["hot"])) { - return $helpers[$name]["hot"]; - } else { - return false; - } + if (isset($helpers[$name]["hot"])) { + return $helpers[$name]["hot"]; + } else { + return false; + } } // Returns name of specialized helper function helper_name($name, $spec, $op1, $op2, $extra_spec) { - global $prefix, $helpers; - - $extra = ""; - - if (isset($helpers[$name])) { - // If we haven't helper with specified spicialized operands then - // using unspecialized helper - if (!isset($helpers[$name]["op1"][$op1])) { - if (($op1 == 'TMP' || $op1 == 'VAR') && - isset($helpers[$name]["op1"]["TMPVAR"])) { - $op1 = "TMPVAR"; - } else if (($op1 == 'TMP' || $op1 == 'VAR') && - isset($helpers[$name]["op1"]["TMPVARCV"])) { - $op1 = "TMPVARCV"; - } else if ($op1 == 'CV' && - isset($helpers[$name]["op1"]["TMPVARCV"])) { - $op1 = "TMPVARCV"; - } else if (isset($helpers[$name]["op1"]["ANY"])) { - $op1 = "ANY"; - } - } - if (!isset($helpers[$name]["op2"][$op2])) { - if (($op2 == 'TMP' || $op2 == 'VAR') && - isset($helpers[$name]["op2"]["TMPVAR"])) { - $op2 = "TMPVAR"; - } else if (($op2 == 'TMP' || $op2 == 'VAR') && - isset($helpers[$name]["op2"]["TMPVARCV"])) { - $op2 = "TMPVARCV"; - } else if ($op2 == 'CV' && - isset($helpers[$name]["op2"]["TMPVARCV"])) { - $op2 = "TMPVARCV"; - } else if (isset($helpers[$name]["op2"]["ANY"])) { - $op2 = "ANY"; - } - } - /* forward common specs (e.g. in ZEND_VM_DISPATCH_TO_HELPER) */ - if (isset($extra_spec, $helpers[$name]["spec"])) { - $extra = extra_spec_name(array_intersect_key($extra_spec, $helpers[$name]["spec"])); - } - } - return $name.($spec?"_SPEC":"").$prefix[$op1].$prefix[$op2].$extra; + global $prefix, $helpers; + + $extra = ""; + + if (isset($helpers[$name])) { + // If we haven't helper with specified spicialized operands then + // using unspecialized helper + if (!isset($helpers[$name]["op1"][$op1])) { + if (($op1 == 'TMP' || $op1 == 'VAR') && + isset($helpers[$name]["op1"]["TMPVAR"])) { + $op1 = "TMPVAR"; + } else if (($op1 == 'TMP' || $op1 == 'VAR') && + isset($helpers[$name]["op1"]["TMPVARCV"])) { + $op1 = "TMPVARCV"; + } else if ($op1 == 'CV' && + isset($helpers[$name]["op1"]["TMPVARCV"])) { + $op1 = "TMPVARCV"; + } else if (isset($helpers[$name]["op1"]["ANY"])) { + $op1 = "ANY"; + } + } + if (!isset($helpers[$name]["op2"][$op2])) { + if (($op2 == 'TMP' || $op2 == 'VAR') && + isset($helpers[$name]["op2"]["TMPVAR"])) { + $op2 = "TMPVAR"; + } else if (($op2 == 'TMP' || $op2 == 'VAR') && + isset($helpers[$name]["op2"]["TMPVARCV"])) { + $op2 = "TMPVARCV"; + } else if ($op2 == 'CV' && + isset($helpers[$name]["op2"]["TMPVARCV"])) { + $op2 = "TMPVARCV"; + } else if (isset($helpers[$name]["op2"]["ANY"])) { + $op2 = "ANY"; + } + } + /* forward common specs (e.g. in ZEND_VM_DISPATCH_TO_HELPER) */ + if (isset($extra_spec, $helpers[$name]["spec"])) { + $extra = extra_spec_name(array_intersect_key($extra_spec, $helpers[$name]["spec"])); + } + } + return $name.($spec?"_SPEC":"").$prefix[$op1].$prefix[$op2].$extra; } function opcode_name($name, $spec, $op1, $op2, $extra_spec) { - global $prefix, $opnames, $opcodes; - - $extra = ""; - - if (isset($opnames[$name])) { - $opcode = $opcodes[$opnames[$name]]; - // If we haven't helper with specified spicialized operands then - // using unspecialized helper - if (!isset($opcode["op1"][$op1])) { - if (($op1 == 'TMP' || $op1 == 'VAR') && - isset($opcode["op1"]["TMPVAR"])) { - $op1 = "TMPVAR"; - } else if (($op1 == 'TMP' || $op1 == 'VAR') && - isset($opcode["op1"]["TMPVARCV"])) { - $op1 = "TMPVARCV"; - } else if ($op1 == 'CV' && - isset($opcode["op1"]["TMPVARCV"])) { - $op1 = "TMPVARCV"; - } else if (isset($opcode["op1"]["ANY"])) { - $op1 = "ANY"; - } else if ($spec) { - /* dispatch to invalid handler from unreachable code */ - return "ZEND_NULL"; - } - } - if (!isset($opcode["op2"][$op2])) { - if (($op2 == 'TMP' || $op2 == 'VAR') && - isset($opcode["op2"]["TMPVAR"])) { - $op2 = "TMPVAR"; - } else if (($op2 == 'TMP' || $op2 == 'VAR') && - isset($opcode["op2"]["TMPVARCV"])) { - $op2 = "TMPVARCV"; - } else if ($op2 == 'CV' && - isset($opcode["op2"]["TMPVARCV"])) { - $op2 = "TMPVARCV"; - } else if (isset($opcode["op2"]["ANY"])) { - $op2 = "ANY"; - } else if ($spec) { - /* dispatch to unknown handler in unreachable code */ - return "ZEND_NULL"; - } - } - /* forward common specs (e.g. in ZEND_VM_DISPATCH_TO_HANDLER) */ - if (isset($extra_spec, $opcode["spec"])) { - $extra = extra_spec_name(array_intersect_key($extra_spec, $opcode["spec"])); - } - } - return $name.($spec?"_SPEC":"").$prefix[$op1].$prefix[$op2].$extra; + global $prefix, $opnames, $opcodes; + + $extra = ""; + + if (isset($opnames[$name])) { + $opcode = $opcodes[$opnames[$name]]; + // If we haven't helper with specified spicialized operands then + // using unspecialized helper + if (!isset($opcode["op1"][$op1])) { + if (($op1 == 'TMP' || $op1 == 'VAR') && + isset($opcode["op1"]["TMPVAR"])) { + $op1 = "TMPVAR"; + } else if (($op1 == 'TMP' || $op1 == 'VAR') && + isset($opcode["op1"]["TMPVARCV"])) { + $op1 = "TMPVARCV"; + } else if ($op1 == 'CV' && + isset($opcode["op1"]["TMPVARCV"])) { + $op1 = "TMPVARCV"; + } else if (isset($opcode["op1"]["ANY"])) { + $op1 = "ANY"; + } else if ($spec) { + /* dispatch to invalid handler from unreachable code */ + return "ZEND_NULL"; + } + } + if (!isset($opcode["op2"][$op2])) { + if (($op2 == 'TMP' || $op2 == 'VAR') && + isset($opcode["op2"]["TMPVAR"])) { + $op2 = "TMPVAR"; + } else if (($op2 == 'TMP' || $op2 == 'VAR') && + isset($opcode["op2"]["TMPVARCV"])) { + $op2 = "TMPVARCV"; + } else if ($op2 == 'CV' && + isset($opcode["op2"]["TMPVARCV"])) { + $op2 = "TMPVARCV"; + } else if (isset($opcode["op2"]["ANY"])) { + $op2 = "ANY"; + } else if ($spec) { + /* dispatch to unknown handler in unreachable code */ + return "ZEND_NULL"; + } + } + /* forward common specs (e.g. in ZEND_VM_DISPATCH_TO_HANDLER) */ + if (isset($extra_spec, $opcode["spec"])) { + $extra = extra_spec_name(array_intersect_key($extra_spec, $opcode["spec"])); + } + } + return $name.($spec?"_SPEC":"").$prefix[$op1].$prefix[$op2].$extra; } // Formats condition, protecting it by parentheses when needed. function format_condition($condition) { - if ($condition === "") { - throw new InvalidArgumentException("A non empty string condition was expected."); - } + if ($condition === "") { + throw new InvalidArgumentException("A non empty string condition was expected."); + } - if ($condition[0] === "(" && substr($condition, -1) === ")") { - return $condition; - } + if ($condition[0] === "(" && substr($condition, -1) === ")") { + return $condition; + } - return "(".$condition.")"; + return "(".$condition.")"; } // Generates code for opcode handler or helper function gen_code($f, $spec, $kind, $export, $code, $op1, $op2, $name, $extra_spec=null) { - global $op1_type, $op2_type, $op1_get_zval_ptr, $op2_get_zval_ptr, - $op1_get_zval_ptr_deref, $op2_get_zval_ptr_deref, - $op1_get_zval_ptr_undef, $op2_get_zval_ptr_undef, - $op1_get_zval_ptr_ptr, $op2_get_zval_ptr_ptr, - $op1_get_zval_ptr_ptr_undef, $op2_get_zval_ptr_ptr_undef, - $op1_get_obj_zval_ptr, $op2_get_obj_zval_ptr, - $op1_get_obj_zval_ptr_undef, $op2_get_obj_zval_ptr_undef, - $op1_get_obj_zval_ptr_deref, $op2_get_obj_zval_ptr_deref, - $op1_get_obj_zval_ptr_ptr, $op2_get_obj_zval_ptr_ptr, - $op1_get_obj_zval_ptr_ptr_undef, $op2_get_obj_zval_ptr_ptr_undef, - $op1_free, $op2_free, $op1_free_unfetched, $op2_free_unfetched, - $op1_free_op, $op2_free_op, $op1_free_op_if_var, $op2_free_op_if_var, - $op1_free_op_var_ptr, $op2_free_op_var_ptr, $prefix, - $op_data_type, $op_data_get_zval_ptr, - $op_data_get_zval_ptr_deref, $op_data_get_zval_ptr_ptr, - $op_data_free_op, $op_data_free_op_var_ptr, $op_data_free_unfetched; - - // Specializing - $specialized_replacements = array( - "/OP1_TYPE/" => $op1_type[$op1], - "/OP2_TYPE/" => $op2_type[$op2], - "/OP1_FREE/" => $op1_free[$op1], - "/OP2_FREE/" => $op2_free[$op2], - "/GET_OP1_ZVAL_PTR\(([^)]*)\)/" => $op1_get_zval_ptr[$op1], - "/GET_OP2_ZVAL_PTR\(([^)]*)\)/" => $op2_get_zval_ptr[$op2], - "/GET_OP1_ZVAL_PTR_DEREF\(([^)]*)\)/" => $op1_get_zval_ptr_deref[$op1], - "/GET_OP2_ZVAL_PTR_DEREF\(([^)]*)\)/" => $op2_get_zval_ptr_deref[$op2], - "/GET_OP1_ZVAL_PTR_UNDEF\(([^)]*)\)/" => $op1_get_zval_ptr_undef[$op1], - "/GET_OP2_ZVAL_PTR_UNDEF\(([^)]*)\)/" => $op2_get_zval_ptr_undef[$op2], - "/GET_OP1_ZVAL_PTR_PTR\(([^)]*)\)/" => $op1_get_zval_ptr_ptr[$op1], - "/GET_OP2_ZVAL_PTR_PTR\(([^)]*)\)/" => $op2_get_zval_ptr_ptr[$op2], - "/GET_OP1_ZVAL_PTR_PTR_UNDEF\(([^)]*)\)/" => $op1_get_zval_ptr_ptr_undef[$op1], - "/GET_OP2_ZVAL_PTR_PTR_UNDEF\(([^)]*)\)/" => $op2_get_zval_ptr_ptr_undef[$op2], - "/GET_OP1_OBJ_ZVAL_PTR\(([^)]*)\)/" => $op1_get_obj_zval_ptr[$op1], - "/GET_OP2_OBJ_ZVAL_PTR\(([^)]*)\)/" => $op2_get_obj_zval_ptr[$op2], - "/GET_OP1_OBJ_ZVAL_PTR_UNDEF\(([^)]*)\)/" => $op1_get_obj_zval_ptr_undef[$op1], - "/GET_OP2_OBJ_ZVAL_PTR_UNDEF\(([^)]*)\)/" => $op2_get_obj_zval_ptr_undef[$op2], - "/GET_OP1_OBJ_ZVAL_PTR_DEREF\(([^)]*)\)/" => $op1_get_obj_zval_ptr_deref[$op1], - "/GET_OP2_OBJ_ZVAL_PTR_DEREF\(([^)]*)\)/" => $op2_get_obj_zval_ptr_deref[$op2], - "/GET_OP1_OBJ_ZVAL_PTR_PTR\(([^)]*)\)/" => $op1_get_obj_zval_ptr_ptr[$op1], - "/GET_OP2_OBJ_ZVAL_PTR_PTR\(([^)]*)\)/" => $op2_get_obj_zval_ptr_ptr[$op2], - "/GET_OP1_OBJ_ZVAL_PTR_PTR_UNDEF\(([^)]*)\)/" => $op1_get_obj_zval_ptr_ptr_undef[$op1], - "/GET_OP2_OBJ_ZVAL_PTR_PTR_UNDEF\(([^)]*)\)/" => $op2_get_obj_zval_ptr_ptr_undef[$op2], - "/FREE_OP1\(\)/" => $op1_free_op[$op1], - "/FREE_OP2\(\)/" => $op2_free_op[$op2], - "/FREE_OP1_IF_VAR\(\)/" => $op1_free_op_if_var[$op1], - "/FREE_OP2_IF_VAR\(\)/" => $op2_free_op_if_var[$op2], - "/FREE_OP1_VAR_PTR\(\)/" => $op1_free_op_var_ptr[$op1], - "/FREE_OP2_VAR_PTR\(\)/" => $op2_free_op_var_ptr[$op2], - "/FREE_UNFETCHED_OP1\(\)/" => $op1_free_unfetched[$op1], - "/FREE_UNFETCHED_OP2\(\)/" => $op2_free_unfetched[$op2], - "/\!ZEND_VM_SPEC/m" => ($op1!="ANY"||$op2!="ANY")?"0":"1", - "/ZEND_VM_SPEC/m" => ($op1!="ANY"||$op2!="ANY")?"1":"0", - "/ZEND_VM_C_LABEL\(\s*([A-Za-z_]*)\s*\)/m" => "\\1".(($spec && $kind != ZEND_VM_KIND_CALL)?("_SPEC".$prefix[$op1].$prefix[$op2].extra_spec_name($extra_spec)):""), - "/ZEND_VM_C_GOTO\(\s*([A-Za-z_]*)\s*\)/m" => "goto \\1".(($spec && $kind != ZEND_VM_KIND_CALL)?("_SPEC".$prefix[$op1].$prefix[$op2].extra_spec_name($extra_spec)):""), - "/^#(\s*)if\s+1\s*\\|\\|.*[^\\\\]$/m" => "#\\1if 1", - "/^#(\s*)if\s+0\s*&&.*[^\\\\]$/m" => "#\\1if 0", - "/^#(\s*)elif\s+1\s*\\|\\|.*[^\\\\]$/m" => "#\\1elif 1", - "/^#(\s*)elif\s+0\s*&&.*[^\\\\]$/m" => "#\\1elif 0", - "/^#(\s*)ifdef\s+ZEND_VM_EXPORT\s*\n/m" => $export?"#\\1if 1\n":"#\\1if 0\n", - "/^#(\s*)ifndef\s+ZEND_VM_EXPORT\s*\n/m" => $export?"#\\1if 0\n":"#\\1if 1\n", - "/OP_DATA_TYPE/" => $op_data_type[isset($extra_spec['OP_DATA']) ? $extra_spec['OP_DATA'] : "ANY"], - "/GET_OP_DATA_ZVAL_PTR\(([^)]*)\)/" => $op_data_get_zval_ptr[isset($extra_spec['OP_DATA']) ? $extra_spec['OP_DATA'] : "ANY"], - "/GET_OP_DATA_ZVAL_PTR_DEREF\(([^)]*)\)/" => $op_data_get_zval_ptr_deref[isset($extra_spec['OP_DATA']) ? $extra_spec['OP_DATA'] : "ANY"], - "/GET_OP_DATA_ZVAL_PTR_PTR\(([^)]*)\)/" => $op_data_get_zval_ptr_ptr[isset($extra_spec['OP_DATA']) ? $extra_spec['OP_DATA'] : "ANY"], - "/FREE_OP_DATA\(\)/" => $op_data_free_op[isset($extra_spec['OP_DATA']) ? $extra_spec['OP_DATA'] : "ANY"], - "/FREE_OP_DATA_VAR_PTR\(\)/" => $op_data_free_op_var_ptr[isset($extra_spec['OP_DATA']) ? $extra_spec['OP_DATA'] : "ANY"], - "/FREE_UNFETCHED_OP_DATA\(\)/" => $op_data_free_unfetched[isset($extra_spec['OP_DATA']) ? $extra_spec['OP_DATA'] : "ANY"], - "/RETURN_VALUE_USED\(opline\)/" => isset($extra_spec['RETVAL']) ? $extra_spec['RETVAL'] : "RETURN_VALUE_USED(opline)", - "/arg_num <= MAX_ARG_FLAG_NUM/" => isset($extra_spec['QUICK_ARG']) ? $extra_spec['QUICK_ARG'] : "arg_num <= MAX_ARG_FLAG_NUM", - "/ZEND_VM_SMART_BRANCH\(\s*([^,)]*)\s*,\s*([^)]*)\s*\)/" => isset($extra_spec['SMART_BRANCH']) ? - ($extra_spec['SMART_BRANCH'] == 1 ? - "ZEND_VM_SMART_BRANCH_JMPZ(\\1, \\2)" - : ($extra_spec['SMART_BRANCH'] == 2 ? - "ZEND_VM_SMART_BRANCH_JMPNZ(\\1, \\2)" : "")) - : "ZEND_VM_SMART_BRANCH(\\1, \\2)", - "/ZEND_VM_SMART_BRANCH_TRUE\(\s*\)/" => isset($extra_spec['SMART_BRANCH']) ? - ($extra_spec['SMART_BRANCH'] == 1 ? - "ZEND_VM_SMART_BRANCH_TRUE_JMPZ()" - : ($extra_spec['SMART_BRANCH'] == 2 ? - "ZEND_VM_SMART_BRANCH_TRUE_JMPNZ()" : "")) - : "ZEND_VM_SMART_BRANCH_TRUE()", - "/ZEND_VM_SMART_BRANCH_FALSE\(\s*\)/" => isset($extra_spec['SMART_BRANCH']) ? - ($extra_spec['SMART_BRANCH'] == 1 ? - "ZEND_VM_SMART_BRANCH_FALSE_JMPZ()" - : ($extra_spec['SMART_BRANCH'] == 2 ? - "ZEND_VM_SMART_BRANCH_FALSE_JMPNZ()" : "")) - : "ZEND_VM_SMART_BRANCH_FALSE()", - "/opline->extended_value\s*&\s*ZEND_ISEMPTY/" => isset($extra_spec['ISSET']) ? - ($extra_spec['ISSET'] == 0 ? "0" : "1") - : "\\0", - "/opline->extended_value\s*&\s*~\s*ZEND_ISEMPTY/" => isset($extra_spec['ISSET']) ? - ($extra_spec['ISSET'] == 0 ? "\\0" : "opline->extended_value") - : "\\0", - ); - $code = preg_replace(array_keys($specialized_replacements), array_values($specialized_replacements), $code); - - if (0 && strpos($code, '{') === 0) { - $code = "{\n\tfprintf(stderr, \"$name\\n\");\n" . substr($code, 1); - } - // Updating code according to selected threading model - switch($kind) { - case ZEND_VM_KIND_HYBRID: - $code = preg_replace_callback( - array( - "/EXECUTE_DATA(?=[^_])/m", - "/ZEND_VM_DISPATCH_TO_HANDLER\(\s*([A-Z_]*)\s*\)/m", - "/ZEND_VM_DISPATCH_TO_HELPER\(\s*([A-Za-z_]*)\s*(,[^)]*)?\)/m", - ), - function($matches) use ($spec, $prefix, $op1, $op2, $extra_spec) { - if (strncasecmp($matches[0], "EXECUTE_DATA", strlen("EXECUTE_DATA")) == 0) { - return "execute_data"; - } else if (strncasecmp($matches[0], "ZEND_VM_DISPATCH_TO_HANDLER", strlen("ZEND_VM_DISPATCH_TO_HANDLER")) == 0) { - global $opcodes, $opnames; - - $name = $matches[1]; - $opcode = $opcodes[$opnames[$name]]; - return "goto " . opcode_name($name, $spec, $op1, $op2, $extra_spec) . "_LABEL"; - } else { - // ZEND_VM_DISPATCH_TO_HELPER - if (is_hot_helper($matches[1])) { - if (isset($matches[2])) { - // extra args - $args = preg_replace("/,\s*([A-Za-z0-9_]*)\s*,\s*([^,)\s]*)\s*/", "$1 = $2; ", $matches[2]); - return $args . "goto " . helper_name($matches[1], $spec, $op1, $op2, $extra_spec) . "_LABEL"; - } - return "goto " . helper_name($matches[1], $spec, $op1, $op2, $extra_spec) . "_LABEL"; - } - if (isset($matches[2])) { - // extra args - $args = substr(preg_replace("/,\s*[A-Za-z0-9_]*\s*,\s*([^,)\s]*)\s*/", ", $1", $matches[2]), 2); - return "ZEND_VM_TAIL_CALL(" . helper_name($matches[1], $spec, $op1, $op2, $extra_spec) . "(" . $args. " ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC))"; - } - return "ZEND_VM_TAIL_CALL(" . helper_name($matches[1], $spec, $op1, $op2, $extra_spec) . "(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU))"; - } - }, - $code); - break; - case ZEND_VM_KIND_CALL: - $code = preg_replace_callback( - array( - "/EXECUTE_DATA(?=[^_])/m", - "/ZEND_VM_DISPATCH_TO_HANDLER\(\s*([A-Z_]*)\s*\)/m", - "/ZEND_VM_DISPATCH_TO_HELPER\(\s*([A-Za-z_]*)\s*(,[^)]*)?\)/m", - ), - function($matches) use ($spec, $prefix, $op1, $op2, $extra_spec, $name) { - if (strncasecmp($matches[0], "EXECUTE_DATA", strlen("EXECUTE_DATA")) == 0) { - return "execute_data"; - } else if (strncasecmp($matches[0], "ZEND_VM_DISPATCH_TO_HANDLER", strlen("ZEND_VM_DISPATCH_TO_HANDLER")) == 0) { - global $opcodes, $opnames; - - $handler = $matches[1]; - $opcode = $opcodes[$opnames[$handler]]; - $inline = - ZEND_VM_KIND == ZEND_VM_KIND_HYBRID && - isset($opcode["use"]) && - is_hot_handler($opcode["hot"], $op1, $op2, $extra_spec) && - is_hot_handler($opcodes[$opnames[$name]]["hot"], $op1, $op2, $extra_spec) ? - "_INLINE" : ""; - return "ZEND_VM_TAIL_CALL(" . opcode_name($handler, $spec, $op1, $op2, $extra_spec) . $inline . "_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU))"; - } else { - // ZEND_VM_DISPATCH_TO_HELPER - if (isset($matches[2])) { - // extra args - $args = substr(preg_replace("/,\s*[A-Za-z0-9_]*\s*,\s*([^,)\s]*)\s*/", ", $1", $matches[2]), 2); - return "ZEND_VM_TAIL_CALL(" . helper_name($matches[1], $spec, $op1, $op2, $extra_spec) . "(" . $args. " ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC))"; - } - return "ZEND_VM_TAIL_CALL(" . helper_name($matches[1], $spec, $op1, $op2, $extra_spec) . "(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU))"; - } - }, - $code); - break; - case ZEND_VM_KIND_SWITCH: - $code = preg_replace_callback( - array( - "/EXECUTE_DATA(?=[^_])/m", - "/ZEND_VM_DISPATCH_TO_HANDLER\(\s*([A-Z_]*)\s*\)/m", - "/ZEND_VM_DISPATCH_TO_HELPER\(\s*([A-Za-z_]*)\s*(,[^)]*)?\)/m", - ), - function($matches) use ($spec, $prefix, $op1, $op2, $extra_spec) { - if (strncasecmp($matches[0], "EXECUTE_DATA", strlen("EXECUTE_DATA")) == 0) { - return "execute_data"; - } else if (strncasecmp($matches[0], "ZEND_VM_DISPATCH_TO_HANDLER", strlen("ZEND_VM_DISPATCH_TO_HANDLER")) == 0) { - return "goto " . opcode_name($matches[1], $spec, $op1, $op2, $extra_spec) . "_LABEL"; - } else { - // ZEND_VM_DISPATCH_TO_HELPER - if (isset($matches[2])) { - // extra args - $args = preg_replace("/,\s*([A-Za-z0-9_]*)\s*,\s*([^,)\s]*)\s*/", "$1 = $2; ", $matches[2]); - return $args . "goto " . helper_name($matches[1], $spec, $op1, $op2, $extra_spec); - } - return "goto " . helper_name($matches[1], $spec, $op1, $op2, $extra_spec); - } - }, - $code); - break; - case ZEND_VM_KIND_GOTO: - $code = preg_replace_callback( - array( - "/EXECUTE_DATA(?=[^_])/m", - "/ZEND_VM_DISPATCH_TO_HANDLER\(\s*([A-Z_]*)\s*\)/m", - "/ZEND_VM_DISPATCH_TO_HELPER\(\s*([A-Za-z_]*)\s*(,[^)]*)?\)/m", - ), - function($matches) use ($spec, $prefix, $op1, $op2, $extra_spec) { - if (strncasecmp($matches[0], "EXECUTE_DATA", strlen("EXECUTE_DATA")) == 0) { - return "execute_data"; - } else if (strncasecmp($matches[0], "ZEND_VM_DISPATCH_TO_HANDLER", strlen("ZEND_VM_DISPATCH_TO_HANDLER")) == 0) { - return "goto " . opcode_name($matches[1], $spec, $op1, $op2, $extra_spec) . "_LABEL"; - } else { - // ZEND_VM_DISPATCH_TO_HELPER - if (isset($matches[2])) { - // extra args - $args = preg_replace("/,\s*([A-Za-z0-9_]*)\s*,\s*([^,)\s]*)\s*/", "$1 = $2; ", $matches[2]); - return $args . "goto " . helper_name($matches[1], $spec, $op1, $op2, $extra_spec); - } - return "goto " . helper_name($matches[1], $spec, $op1, $op2, $extra_spec); - } - }, - $code); - break; - } - - /* Remove unused free_op1 and free_op2 declarations */ - if ($spec && preg_match_all('/^\s*zend_free_op\s+[^;]+;\s*$/m', $code, $matches, PREG_SET_ORDER)) { - $n = 0; - foreach ($matches as $match) { - $code = preg_replace('/'.preg_quote($match[0],'/').'/', "\$D$n", $code); - ++$n; - } - $del_free_op1 = (strpos($code, "free_op1") === false); - $del_free_op2 = (strpos($code, "free_op2") === false); - $del_free_op_data = (strpos($code, "free_op_data") === false); - $n = 0; - foreach ($matches as $match) { - $dcl = $match[0]; - $changed = 0; - if ($del_free_op1 && strpos($dcl, "free_op1") !== false) { - $dcl = preg_replace("/free_op1\s*,\s*/", "", $dcl); - $dcl = preg_replace("/free_op1\s*;/", ";", $dcl); - $changed = 1; - } - if ($del_free_op2 && strpos($dcl, "free_op2") !== false) { - $dcl = preg_replace("/free_op2\s*,\s*/", "", $dcl); - $dcl = preg_replace("/free_op2\s*;/", ";", $dcl); - $changed = 1; - } - if ($del_free_op_data && strpos($dcl, "free_op_data") !== false) { - $dcl = preg_replace("/free_op_data\s*,\s*/", "", $dcl); - $dcl = preg_replace("/free_op_data\s*;/", ";", $dcl); - $changed = 1; - } - if ($changed) { - $dcl = preg_replace("/,\s*;/", ";", $dcl); - $dcl = preg_replace("/zend_free_op\s*;/", "", $dcl); - } - $code = preg_replace("/\\\$D$n/", $dcl, $code); - ++$n; - } - } - - /* Remove unnecessary ';' */ - $code = preg_replace('/^\s*;\s*$/m', '', $code); - - /* Remove WS */ - $code = preg_replace('/[ \t]+\n/m', "\n", $code); - - out($f, $code); + global $op1_type, $op2_type, $op1_get_zval_ptr, $op2_get_zval_ptr, + $op1_get_zval_ptr_deref, $op2_get_zval_ptr_deref, + $op1_get_zval_ptr_undef, $op2_get_zval_ptr_undef, + $op1_get_zval_ptr_ptr, $op2_get_zval_ptr_ptr, + $op1_get_zval_ptr_ptr_undef, $op2_get_zval_ptr_ptr_undef, + $op1_get_obj_zval_ptr, $op2_get_obj_zval_ptr, + $op1_get_obj_zval_ptr_undef, $op2_get_obj_zval_ptr_undef, + $op1_get_obj_zval_ptr_deref, $op2_get_obj_zval_ptr_deref, + $op1_get_obj_zval_ptr_ptr, $op2_get_obj_zval_ptr_ptr, + $op1_get_obj_zval_ptr_ptr_undef, $op2_get_obj_zval_ptr_ptr_undef, + $op1_free, $op2_free, $op1_free_unfetched, $op2_free_unfetched, + $op1_free_op, $op2_free_op, $op1_free_op_if_var, $op2_free_op_if_var, + $op1_free_op_var_ptr, $op2_free_op_var_ptr, $prefix, + $op_data_type, $op_data_get_zval_ptr, + $op_data_get_zval_ptr_deref, $op_data_get_zval_ptr_ptr, + $op_data_free_op, $op_data_free_op_var_ptr, $op_data_free_unfetched; + + // Specializing + $specialized_replacements = array( + "/OP1_TYPE/" => $op1_type[$op1], + "/OP2_TYPE/" => $op2_type[$op2], + "/OP1_FREE/" => $op1_free[$op1], + "/OP2_FREE/" => $op2_free[$op2], + "/GET_OP1_ZVAL_PTR\(([^)]*)\)/" => $op1_get_zval_ptr[$op1], + "/GET_OP2_ZVAL_PTR\(([^)]*)\)/" => $op2_get_zval_ptr[$op2], + "/GET_OP1_ZVAL_PTR_DEREF\(([^)]*)\)/" => $op1_get_zval_ptr_deref[$op1], + "/GET_OP2_ZVAL_PTR_DEREF\(([^)]*)\)/" => $op2_get_zval_ptr_deref[$op2], + "/GET_OP1_ZVAL_PTR_UNDEF\(([^)]*)\)/" => $op1_get_zval_ptr_undef[$op1], + "/GET_OP2_ZVAL_PTR_UNDEF\(([^)]*)\)/" => $op2_get_zval_ptr_undef[$op2], + "/GET_OP1_ZVAL_PTR_PTR\(([^)]*)\)/" => $op1_get_zval_ptr_ptr[$op1], + "/GET_OP2_ZVAL_PTR_PTR\(([^)]*)\)/" => $op2_get_zval_ptr_ptr[$op2], + "/GET_OP1_ZVAL_PTR_PTR_UNDEF\(([^)]*)\)/" => $op1_get_zval_ptr_ptr_undef[$op1], + "/GET_OP2_ZVAL_PTR_PTR_UNDEF\(([^)]*)\)/" => $op2_get_zval_ptr_ptr_undef[$op2], + "/GET_OP1_OBJ_ZVAL_PTR\(([^)]*)\)/" => $op1_get_obj_zval_ptr[$op1], + "/GET_OP2_OBJ_ZVAL_PTR\(([^)]*)\)/" => $op2_get_obj_zval_ptr[$op2], + "/GET_OP1_OBJ_ZVAL_PTR_UNDEF\(([^)]*)\)/" => $op1_get_obj_zval_ptr_undef[$op1], + "/GET_OP2_OBJ_ZVAL_PTR_UNDEF\(([^)]*)\)/" => $op2_get_obj_zval_ptr_undef[$op2], + "/GET_OP1_OBJ_ZVAL_PTR_DEREF\(([^)]*)\)/" => $op1_get_obj_zval_ptr_deref[$op1], + "/GET_OP2_OBJ_ZVAL_PTR_DEREF\(([^)]*)\)/" => $op2_get_obj_zval_ptr_deref[$op2], + "/GET_OP1_OBJ_ZVAL_PTR_PTR\(([^)]*)\)/" => $op1_get_obj_zval_ptr_ptr[$op1], + "/GET_OP2_OBJ_ZVAL_PTR_PTR\(([^)]*)\)/" => $op2_get_obj_zval_ptr_ptr[$op2], + "/GET_OP1_OBJ_ZVAL_PTR_PTR_UNDEF\(([^)]*)\)/" => $op1_get_obj_zval_ptr_ptr_undef[$op1], + "/GET_OP2_OBJ_ZVAL_PTR_PTR_UNDEF\(([^)]*)\)/" => $op2_get_obj_zval_ptr_ptr_undef[$op2], + "/FREE_OP1\(\)/" => $op1_free_op[$op1], + "/FREE_OP2\(\)/" => $op2_free_op[$op2], + "/FREE_OP1_IF_VAR\(\)/" => $op1_free_op_if_var[$op1], + "/FREE_OP2_IF_VAR\(\)/" => $op2_free_op_if_var[$op2], + "/FREE_OP1_VAR_PTR\(\)/" => $op1_free_op_var_ptr[$op1], + "/FREE_OP2_VAR_PTR\(\)/" => $op2_free_op_var_ptr[$op2], + "/FREE_UNFETCHED_OP1\(\)/" => $op1_free_unfetched[$op1], + "/FREE_UNFETCHED_OP2\(\)/" => $op2_free_unfetched[$op2], + "/\!ZEND_VM_SPEC/m" => ($op1!="ANY"||$op2!="ANY")?"0":"1", + "/ZEND_VM_SPEC/m" => ($op1!="ANY"||$op2!="ANY")?"1":"0", + "/ZEND_VM_C_LABEL\(\s*([A-Za-z_]*)\s*\)/m" => "\\1".(($spec && $kind != ZEND_VM_KIND_CALL)?("_SPEC".$prefix[$op1].$prefix[$op2].extra_spec_name($extra_spec)):""), + "/ZEND_VM_C_GOTO\(\s*([A-Za-z_]*)\s*\)/m" => "goto \\1".(($spec && $kind != ZEND_VM_KIND_CALL)?("_SPEC".$prefix[$op1].$prefix[$op2].extra_spec_name($extra_spec)):""), + "/^#(\s*)if\s+1\s*\\|\\|.*[^\\\\]$/m" => "#\\1if 1", + "/^#(\s*)if\s+0\s*&&.*[^\\\\]$/m" => "#\\1if 0", + "/^#(\s*)elif\s+1\s*\\|\\|.*[^\\\\]$/m" => "#\\1elif 1", + "/^#(\s*)elif\s+0\s*&&.*[^\\\\]$/m" => "#\\1elif 0", + "/^#(\s*)ifdef\s+ZEND_VM_EXPORT\s*\n/m" => $export?"#\\1if 1\n":"#\\1if 0\n", + "/^#(\s*)ifndef\s+ZEND_VM_EXPORT\s*\n/m" => $export?"#\\1if 0\n":"#\\1if 1\n", + "/OP_DATA_TYPE/" => $op_data_type[isset($extra_spec['OP_DATA']) ? $extra_spec['OP_DATA'] : "ANY"], + "/GET_OP_DATA_ZVAL_PTR\(([^)]*)\)/" => $op_data_get_zval_ptr[isset($extra_spec['OP_DATA']) ? $extra_spec['OP_DATA'] : "ANY"], + "/GET_OP_DATA_ZVAL_PTR_DEREF\(([^)]*)\)/" => $op_data_get_zval_ptr_deref[isset($extra_spec['OP_DATA']) ? $extra_spec['OP_DATA'] : "ANY"], + "/GET_OP_DATA_ZVAL_PTR_PTR\(([^)]*)\)/" => $op_data_get_zval_ptr_ptr[isset($extra_spec['OP_DATA']) ? $extra_spec['OP_DATA'] : "ANY"], + "/FREE_OP_DATA\(\)/" => $op_data_free_op[isset($extra_spec['OP_DATA']) ? $extra_spec['OP_DATA'] : "ANY"], + "/FREE_OP_DATA_VAR_PTR\(\)/" => $op_data_free_op_var_ptr[isset($extra_spec['OP_DATA']) ? $extra_spec['OP_DATA'] : "ANY"], + "/FREE_UNFETCHED_OP_DATA\(\)/" => $op_data_free_unfetched[isset($extra_spec['OP_DATA']) ? $extra_spec['OP_DATA'] : "ANY"], + "/RETURN_VALUE_USED\(opline\)/" => isset($extra_spec['RETVAL']) ? $extra_spec['RETVAL'] : "RETURN_VALUE_USED(opline)", + "/arg_num <= MAX_ARG_FLAG_NUM/" => isset($extra_spec['QUICK_ARG']) ? $extra_spec['QUICK_ARG'] : "arg_num <= MAX_ARG_FLAG_NUM", + "/ZEND_VM_SMART_BRANCH\(\s*([^,)]*)\s*,\s*([^)]*)\s*\)/" => isset($extra_spec['SMART_BRANCH']) ? + ($extra_spec['SMART_BRANCH'] == 1 ? + "ZEND_VM_SMART_BRANCH_JMPZ(\\1, \\2)" + : ($extra_spec['SMART_BRANCH'] == 2 ? + "ZEND_VM_SMART_BRANCH_JMPNZ(\\1, \\2)" : "")) + : "ZEND_VM_SMART_BRANCH(\\1, \\2)", + "/ZEND_VM_SMART_BRANCH_TRUE\(\s*\)/" => isset($extra_spec['SMART_BRANCH']) ? + ($extra_spec['SMART_BRANCH'] == 1 ? + "ZEND_VM_SMART_BRANCH_TRUE_JMPZ()" + : ($extra_spec['SMART_BRANCH'] == 2 ? + "ZEND_VM_SMART_BRANCH_TRUE_JMPNZ()" : "")) + : "ZEND_VM_SMART_BRANCH_TRUE()", + "/ZEND_VM_SMART_BRANCH_FALSE\(\s*\)/" => isset($extra_spec['SMART_BRANCH']) ? + ($extra_spec['SMART_BRANCH'] == 1 ? + "ZEND_VM_SMART_BRANCH_FALSE_JMPZ()" + : ($extra_spec['SMART_BRANCH'] == 2 ? + "ZEND_VM_SMART_BRANCH_FALSE_JMPNZ()" : "")) + : "ZEND_VM_SMART_BRANCH_FALSE()", + "/opline->extended_value\s*&\s*ZEND_ISEMPTY/" => isset($extra_spec['ISSET']) ? + ($extra_spec['ISSET'] == 0 ? "0" : "1") + : "\\0", + "/opline->extended_value\s*&\s*~\s*ZEND_ISEMPTY/" => isset($extra_spec['ISSET']) ? + ($extra_spec['ISSET'] == 0 ? "\\0" : "opline->extended_value") + : "\\0", + ); + $code = preg_replace(array_keys($specialized_replacements), array_values($specialized_replacements), $code); + + if (0 && strpos($code, '{') === 0) { + $code = "{\n\tfprintf(stderr, \"$name\\n\");\n" . substr($code, 1); + } + // Updating code according to selected threading model + switch($kind) { + case ZEND_VM_KIND_HYBRID: + $code = preg_replace_callback( + array( + "/EXECUTE_DATA(?=[^_])/m", + "/ZEND_VM_DISPATCH_TO_HANDLER\(\s*([A-Z_]*)\s*\)/m", + "/ZEND_VM_DISPATCH_TO_HELPER\(\s*([A-Za-z_]*)\s*(,[^)]*)?\)/m", + ), + function($matches) use ($spec, $prefix, $op1, $op2, $extra_spec) { + if (strncasecmp($matches[0], "EXECUTE_DATA", strlen("EXECUTE_DATA")) == 0) { + return "execute_data"; + } else if (strncasecmp($matches[0], "ZEND_VM_DISPATCH_TO_HANDLER", strlen("ZEND_VM_DISPATCH_TO_HANDLER")) == 0) { + global $opcodes, $opnames; + + $name = $matches[1]; + $opcode = $opcodes[$opnames[$name]]; + return "goto " . opcode_name($name, $spec, $op1, $op2, $extra_spec) . "_LABEL"; + } else { + // ZEND_VM_DISPATCH_TO_HELPER + if (is_hot_helper($matches[1])) { + if (isset($matches[2])) { + // extra args + $args = preg_replace("/,\s*([A-Za-z0-9_]*)\s*,\s*([^,)\s]*)\s*/", "$1 = $2; ", $matches[2]); + return $args . "goto " . helper_name($matches[1], $spec, $op1, $op2, $extra_spec) . "_LABEL"; + } + return "goto " . helper_name($matches[1], $spec, $op1, $op2, $extra_spec) . "_LABEL"; + } + if (isset($matches[2])) { + // extra args + $args = substr(preg_replace("/,\s*[A-Za-z0-9_]*\s*,\s*([^,)\s]*)\s*/", ", $1", $matches[2]), 2); + return "ZEND_VM_TAIL_CALL(" . helper_name($matches[1], $spec, $op1, $op2, $extra_spec) . "(" . $args. " ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC))"; + } + return "ZEND_VM_TAIL_CALL(" . helper_name($matches[1], $spec, $op1, $op2, $extra_spec) . "(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU))"; + } + }, + $code); + break; + case ZEND_VM_KIND_CALL: + $code = preg_replace_callback( + array( + "/EXECUTE_DATA(?=[^_])/m", + "/ZEND_VM_DISPATCH_TO_HANDLER\(\s*([A-Z_]*)\s*\)/m", + "/ZEND_VM_DISPATCH_TO_HELPER\(\s*([A-Za-z_]*)\s*(,[^)]*)?\)/m", + ), + function($matches) use ($spec, $prefix, $op1, $op2, $extra_spec, $name) { + if (strncasecmp($matches[0], "EXECUTE_DATA", strlen("EXECUTE_DATA")) == 0) { + return "execute_data"; + } else if (strncasecmp($matches[0], "ZEND_VM_DISPATCH_TO_HANDLER", strlen("ZEND_VM_DISPATCH_TO_HANDLER")) == 0) { + global $opcodes, $opnames; + + $handler = $matches[1]; + $opcode = $opcodes[$opnames[$handler]]; + $inline = + ZEND_VM_KIND == ZEND_VM_KIND_HYBRID && + isset($opcode["use"]) && + is_hot_handler($opcode["hot"], $op1, $op2, $extra_spec) && + is_hot_handler($opcodes[$opnames[$name]]["hot"], $op1, $op2, $extra_spec) ? + "_INLINE" : ""; + return "ZEND_VM_TAIL_CALL(" . opcode_name($handler, $spec, $op1, $op2, $extra_spec) . $inline . "_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU))"; + } else { + // ZEND_VM_DISPATCH_TO_HELPER + if (isset($matches[2])) { + // extra args + $args = substr(preg_replace("/,\s*[A-Za-z0-9_]*\s*,\s*([^,)\s]*)\s*/", ", $1", $matches[2]), 2); + return "ZEND_VM_TAIL_CALL(" . helper_name($matches[1], $spec, $op1, $op2, $extra_spec) . "(" . $args. " ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC))"; + } + return "ZEND_VM_TAIL_CALL(" . helper_name($matches[1], $spec, $op1, $op2, $extra_spec) . "(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU))"; + } + }, + $code); + break; + case ZEND_VM_KIND_SWITCH: + $code = preg_replace_callback( + array( + "/EXECUTE_DATA(?=[^_])/m", + "/ZEND_VM_DISPATCH_TO_HANDLER\(\s*([A-Z_]*)\s*\)/m", + "/ZEND_VM_DISPATCH_TO_HELPER\(\s*([A-Za-z_]*)\s*(,[^)]*)?\)/m", + ), + function($matches) use ($spec, $prefix, $op1, $op2, $extra_spec) { + if (strncasecmp($matches[0], "EXECUTE_DATA", strlen("EXECUTE_DATA")) == 0) { + return "execute_data"; + } else if (strncasecmp($matches[0], "ZEND_VM_DISPATCH_TO_HANDLER", strlen("ZEND_VM_DISPATCH_TO_HANDLER")) == 0) { + return "goto " . opcode_name($matches[1], $spec, $op1, $op2, $extra_spec) . "_LABEL"; + } else { + // ZEND_VM_DISPATCH_TO_HELPER + if (isset($matches[2])) { + // extra args + $args = preg_replace("/,\s*([A-Za-z0-9_]*)\s*,\s*([^,)\s]*)\s*/", "$1 = $2; ", $matches[2]); + return $args . "goto " . helper_name($matches[1], $spec, $op1, $op2, $extra_spec); + } + return "goto " . helper_name($matches[1], $spec, $op1, $op2, $extra_spec); + } + }, + $code); + break; + case ZEND_VM_KIND_GOTO: + $code = preg_replace_callback( + array( + "/EXECUTE_DATA(?=[^_])/m", + "/ZEND_VM_DISPATCH_TO_HANDLER\(\s*([A-Z_]*)\s*\)/m", + "/ZEND_VM_DISPATCH_TO_HELPER\(\s*([A-Za-z_]*)\s*(,[^)]*)?\)/m", + ), + function($matches) use ($spec, $prefix, $op1, $op2, $extra_spec) { + if (strncasecmp($matches[0], "EXECUTE_DATA", strlen("EXECUTE_DATA")) == 0) { + return "execute_data"; + } else if (strncasecmp($matches[0], "ZEND_VM_DISPATCH_TO_HANDLER", strlen("ZEND_VM_DISPATCH_TO_HANDLER")) == 0) { + return "goto " . opcode_name($matches[1], $spec, $op1, $op2, $extra_spec) . "_LABEL"; + } else { + // ZEND_VM_DISPATCH_TO_HELPER + if (isset($matches[2])) { + // extra args + $args = preg_replace("/,\s*([A-Za-z0-9_]*)\s*,\s*([^,)\s]*)\s*/", "$1 = $2; ", $matches[2]); + return $args . "goto " . helper_name($matches[1], $spec, $op1, $op2, $extra_spec); + } + return "goto " . helper_name($matches[1], $spec, $op1, $op2, $extra_spec); + } + }, + $code); + break; + } + + /* Remove unused free_op1 and free_op2 declarations */ + if ($spec && preg_match_all('/^\s*zend_free_op\s+[^;]+;\s*$/m', $code, $matches, PREG_SET_ORDER)) { + $n = 0; + foreach ($matches as $match) { + $code = preg_replace('/'.preg_quote($match[0],'/').'/', "\$D$n", $code); + ++$n; + } + $del_free_op1 = (strpos($code, "free_op1") === false); + $del_free_op2 = (strpos($code, "free_op2") === false); + $del_free_op_data = (strpos($code, "free_op_data") === false); + $n = 0; + foreach ($matches as $match) { + $dcl = $match[0]; + $changed = 0; + if ($del_free_op1 && strpos($dcl, "free_op1") !== false) { + $dcl = preg_replace("/free_op1\s*,\s*/", "", $dcl); + $dcl = preg_replace("/free_op1\s*;/", ";", $dcl); + $changed = 1; + } + if ($del_free_op2 && strpos($dcl, "free_op2") !== false) { + $dcl = preg_replace("/free_op2\s*,\s*/", "", $dcl); + $dcl = preg_replace("/free_op2\s*;/", ";", $dcl); + $changed = 1; + } + if ($del_free_op_data && strpos($dcl, "free_op_data") !== false) { + $dcl = preg_replace("/free_op_data\s*,\s*/", "", $dcl); + $dcl = preg_replace("/free_op_data\s*;/", ";", $dcl); + $changed = 1; + } + if ($changed) { + $dcl = preg_replace("/,\s*;/", ";", $dcl); + $dcl = preg_replace("/zend_free_op\s*;/", "", $dcl); + } + $code = preg_replace("/\\\$D$n/", $dcl, $code); + ++$n; + } + } + + /* Remove unnecessary ';' */ + $code = preg_replace('/^\s*;\s*$/m', '', $code); + + /* Remove WS */ + $code = preg_replace('/[ \t]+\n/m', "\n", $code); + + out($f, $code); } function skip_extra_spec_function($op1, $op2, $extra_spec) { - global $commutative_order; + global $commutative_order; - if (isset($extra_spec["NO_CONST_CONST"]) && - $op1 == "CONST" && $op2 == "CONST") { - // Skip useless constant handlers - return true; - } + if (isset($extra_spec["NO_CONST_CONST"]) && + $op1 == "CONST" && $op2 == "CONST") { + // Skip useless constant handlers + return true; + } - if (isset($extra_spec["COMMUTATIVE"]) && - $commutative_order[$op1] < $commutative_order[$op2]) { - // Skip duplicate commutative handlers - return true; - } + if (isset($extra_spec["COMMUTATIVE"]) && + $commutative_order[$op1] < $commutative_order[$op2]) { + // Skip duplicate commutative handlers + return true; + } - return false; + return false; } function is_hot_handler($hot, $op1, $op2, $extra_spec) { - if (isset($extra_spec["SMART_BRANCH"]) && $extra_spec["SMART_BRANCH"] == 0) { - return false; - } - if ($hot === 'HOT_' || $hot === 'INLINE_') { - return true; - } else if ($hot === 'HOT_NOCONST_') { - return ($op1 !== 'CONST'); - } else if ($hot === 'HOT_NOCONSTCONST_') { - return (($op1 !== 'CONST') || ($op2 !== 'CONST')) ; - } else if ($hot === 'HOT_OBJ_') { - return (($op1 === 'UNUSED') || ($op1 === 'CV')) && ($op2 === 'CONST'); - } else if ($hot === 'HOT_SEND_') { - return !empty($extra_spec["QUICK_ARG"]); - } else { - return false; - } + if (isset($extra_spec["SMART_BRANCH"]) && $extra_spec["SMART_BRANCH"] == 0) { + return false; + } + if ($hot === 'HOT_' || $hot === 'INLINE_') { + return true; + } else if ($hot === 'HOT_NOCONST_') { + return ($op1 !== 'CONST'); + } else if ($hot === 'HOT_NOCONSTCONST_') { + return (($op1 !== 'CONST') || ($op2 !== 'CONST')) ; + } else if ($hot === 'HOT_OBJ_') { + return (($op1 === 'UNUSED') || ($op1 === 'CV')) && ($op2 === 'CONST'); + } else if ($hot === 'HOT_SEND_') { + return !empty($extra_spec["QUICK_ARG"]); + } else { + return false; + } } function is_cold_handler($hot, $op1, $op2, $extra_spec) { - if ($hot === 'COLD_') { - return true; - } else if ($hot === 'COLD_CONST_') { - return ($op1 === 'CONST'); - } else if ($hot === 'COLD_CONSTCONST_') { - return ($op1 === 'CONST' && $op2 === 'CONST'); - } else if ($hot === 'HOT_OBJ_') { - return ($op1 === 'CONST'); - } else if ($hot === 'HOT_NOCONST_') { - return ($op1 === 'CONST'); - } else if ($hot === 'HOT_NOCONSTCONST_') { - return ($op1 === 'CONST' && $op2 === 'CONST'); - } else { - return false; - } + if ($hot === 'COLD_') { + return true; + } else if ($hot === 'COLD_CONST_') { + return ($op1 === 'CONST'); + } else if ($hot === 'COLD_CONSTCONST_') { + return ($op1 === 'CONST' && $op2 === 'CONST'); + } else if ($hot === 'HOT_OBJ_') { + return ($op1 === 'CONST'); + } else if ($hot === 'HOT_NOCONST_') { + return ($op1 === 'CONST'); + } else if ($hot === 'HOT_NOCONSTCONST_') { + return ($op1 === 'CONST' && $op2 === 'CONST'); + } else { + return false; + } } function is_inline_hybrid_handler($name, $hot, $op1, $op2, $extra_spec) { - return ($hot === 'INLINE_'); + return ($hot === 'INLINE_'); } // Generates opcode handler function gen_handler($f, $spec, $kind, $name, $op1, $op2, $use, $code, $lineno, $opcode, $extra_spec = null, &$switch_labels = array()) { - global $definition_file, $prefix, $opnames, $gen_order; - - if (isset($opcode['alias']) && ($spec || $kind != ZEND_VM_KIND_SWITCH)) { - return; - } - - if ($spec && skip_extra_spec_function($op1, $op2, $extra_spec)) { - return; - } - - /* Skip SMART_BRANCH specialization for "cold" CONST_CONST instructions */ - if (isset($extra_spec["SMART_BRANCH"])) { - if ($opcode["hot"] === 'HOT_NOCONSTCONST_' - || $opcode["hot"] === 'COLD_CONSTCONST_') { - if (($op1 === 'CONST') && ($op2 === 'CONST')) { - if ($extra_spec["SMART_BRANCH"] == 0) { - unset($extra_spec["SMART_BRANCH"]); - } else { - return; - } - } - } - } - - if (ZEND_VM_LINES) { - out($f, "#line $lineno \"$definition_file\"\n"); - } - - // Generate opcode handler's entry point according to selected threading model - $additional_func = false; - $spec_name = $name.($spec?"_SPEC":"").$prefix[$op1].$prefix[$op2].($spec?extra_spec_name($extra_spec):""); - switch($kind) { - case ZEND_VM_KIND_HYBRID: - if (is_inline_hybrid_handler($name, $opcode["hot"], $op1, $op2, $extra_spec)) { - $out = fopen('php://memory', 'w+'); - gen_code($out, $spec, $kind, 0, $code, $op1, $op2, $name, $extra_spec); - rewind($out); - $code = - "\t\t\tHYBRID_CASE({$spec_name}):\n" - . "\t\t\t\tVM_TRACE($spec_name)\n" - . stream_get_contents($out); - fclose($out); - } else { - $inline = - isset($opcode["use"]) && - is_hot_handler($opcode["hot"], $op1, $op2, $extra_spec) ? - "_INLINE" : ""; - $code = - "\t\t\tHYBRID_CASE({$spec_name}):\n" - . "\t\t\t\tVM_TRACE($spec_name)\n" - . "\t\t\t\t{$spec_name}{$inline}_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);\n" - . "\t\t\t\tHYBRID_BREAK();\n"; - } - if (is_array($gen_order)) { - $gen_order[$spec_name] = $code; - } else { - out($f, $code); - } - return; - case ZEND_VM_KIND_CALL: - if ($opcode["hot"] && ZEND_VM_KIND == ZEND_VM_KIND_HYBRID && is_hot_handler($opcode["hot"], $op1, $op2, $extra_spec)) { - if (isset($opcode["use"])) { - out($f,"static zend_always_inline ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL {$spec_name}_INLINE_HANDLER(ZEND_OPCODE_HANDLER_ARGS)\n"); - $additional_func = true; - } else { - out($f,"static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL {$spec_name}_HANDLER(ZEND_OPCODE_HANDLER_ARGS)\n"); - } - } else if ($opcode["hot"] && is_cold_handler($opcode["hot"], $op1, $op2, $extra_spec)) { - out($f,"static ZEND_VM_COLD ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL {$spec_name}_HANDLER(ZEND_OPCODE_HANDLER_ARGS)\n"); - } else { - out($f,"static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL {$spec_name}_HANDLER(ZEND_OPCODE_HANDLER_ARGS)\n"); - } - break; - case ZEND_VM_KIND_SWITCH: - if ($spec) { - $cur = $switch_labels ? end($switch_labels) + 1 : 0; - out($f,"case $cur: /* $spec_name */"); - $switch_labels[$spec_name] = $cur; - } else { - out($f,"case ".$name.":"); - } - if ($use) { - // This handler is used by other handlers. We will add label to call it. - out($f," {$spec_name}_LABEL:\n"); - } else { - out($f,"\n"); - } - break; - case ZEND_VM_KIND_GOTO: - out($f,"{$spec_name}_LABEL: ZEND_VM_GUARD($spec_name);\n"); - break; - } - - // Generate opcode handler's code - gen_code($f, $spec, $kind, 0, $code, $op1, $op2, $name, $extra_spec); - - if ($additional_func) { - out($f,"static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL {$spec_name}_HANDLER(ZEND_OPCODE_HANDLER_ARGS)\n"); - out($f,"{\n"); - out($f,"\tZEND_VM_TAIL_CALL({$spec_name}_INLINE_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU));\n"); - out($f,"}\n"); - out($f,"\n"); - } + global $definition_file, $prefix, $opnames, $gen_order; + + if (isset($opcode['alias']) && ($spec || $kind != ZEND_VM_KIND_SWITCH)) { + return; + } + + if ($spec && skip_extra_spec_function($op1, $op2, $extra_spec)) { + return; + } + + /* Skip SMART_BRANCH specialization for "cold" CONST_CONST instructions */ + if (isset($extra_spec["SMART_BRANCH"])) { + if ($opcode["hot"] === 'HOT_NOCONSTCONST_' + || $opcode["hot"] === 'COLD_CONSTCONST_') { + if (($op1 === 'CONST') && ($op2 === 'CONST')) { + if ($extra_spec["SMART_BRANCH"] == 0) { + unset($extra_spec["SMART_BRANCH"]); + } else { + return; + } + } + } + } + + if (ZEND_VM_LINES) { + out($f, "#line $lineno \"$definition_file\"\n"); + } + + // Generate opcode handler's entry point according to selected threading model + $additional_func = false; + $spec_name = $name.($spec?"_SPEC":"").$prefix[$op1].$prefix[$op2].($spec?extra_spec_name($extra_spec):""); + switch($kind) { + case ZEND_VM_KIND_HYBRID: + if (is_inline_hybrid_handler($name, $opcode["hot"], $op1, $op2, $extra_spec)) { + $out = fopen('php://memory', 'w+'); + gen_code($out, $spec, $kind, 0, $code, $op1, $op2, $name, $extra_spec); + rewind($out); + $code = + "\t\t\tHYBRID_CASE({$spec_name}):\n" + . "\t\t\t\tVM_TRACE($spec_name)\n" + . stream_get_contents($out); + fclose($out); + } else { + $inline = + isset($opcode["use"]) && + is_hot_handler($opcode["hot"], $op1, $op2, $extra_spec) ? + "_INLINE" : ""; + $code = + "\t\t\tHYBRID_CASE({$spec_name}):\n" + . "\t\t\t\tVM_TRACE($spec_name)\n" + . "\t\t\t\t{$spec_name}{$inline}_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);\n" + . "\t\t\t\tHYBRID_BREAK();\n"; + } + if (is_array($gen_order)) { + $gen_order[$spec_name] = $code; + } else { + out($f, $code); + } + return; + case ZEND_VM_KIND_CALL: + if ($opcode["hot"] && ZEND_VM_KIND == ZEND_VM_KIND_HYBRID && is_hot_handler($opcode["hot"], $op1, $op2, $extra_spec)) { + if (isset($opcode["use"])) { + out($f,"static zend_always_inline ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL {$spec_name}_INLINE_HANDLER(ZEND_OPCODE_HANDLER_ARGS)\n"); + $additional_func = true; + } else { + out($f,"static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL {$spec_name}_HANDLER(ZEND_OPCODE_HANDLER_ARGS)\n"); + } + } else if ($opcode["hot"] && is_cold_handler($opcode["hot"], $op1, $op2, $extra_spec)) { + out($f,"static ZEND_VM_COLD ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL {$spec_name}_HANDLER(ZEND_OPCODE_HANDLER_ARGS)\n"); + } else { + out($f,"static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL {$spec_name}_HANDLER(ZEND_OPCODE_HANDLER_ARGS)\n"); + } + break; + case ZEND_VM_KIND_SWITCH: + if ($spec) { + $cur = $switch_labels ? end($switch_labels) + 1 : 0; + out($f,"case $cur: /* $spec_name */"); + $switch_labels[$spec_name] = $cur; + } else { + out($f,"case ".$name.":"); + } + if ($use) { + // This handler is used by other handlers. We will add label to call it. + out($f," {$spec_name}_LABEL:\n"); + } else { + out($f,"\n"); + } + break; + case ZEND_VM_KIND_GOTO: + out($f,"{$spec_name}_LABEL: ZEND_VM_GUARD($spec_name);\n"); + break; + } + + // Generate opcode handler's code + gen_code($f, $spec, $kind, 0, $code, $op1, $op2, $name, $extra_spec); + + if ($additional_func) { + out($f,"static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL {$spec_name}_HANDLER(ZEND_OPCODE_HANDLER_ARGS)\n"); + out($f,"{\n"); + out($f,"\tZEND_VM_TAIL_CALL({$spec_name}_INLINE_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU));\n"); + out($f,"}\n"); + out($f,"\n"); + } } // Generates helper function gen_helper($f, $spec, $kind, $name, $op1, $op2, $param, $code, $lineno, $inline, $cold = false, $hot = false, $extra_spec = null) { - global $definition_file, $prefix; - - if ($kind == ZEND_VM_KIND_HYBRID && !$hot) { - return; - } - - if ($spec && skip_extra_spec_function($op1, $op2, $extra_spec)) { - return; - } - - if (ZEND_VM_LINES) { - out($f, "#line $lineno \"$definition_file\"\n"); - } - - $spec_name = $name.($spec?"_SPEC":"").$prefix[$op1].$prefix[$op2].($spec?extra_spec_name($extra_spec):""); - - // Generate helper's entry point according to selected threading model - switch($kind) { - case ZEND_VM_KIND_HYBRID: - out($f, $spec_name . "_LABEL:\n"); - break; - case ZEND_VM_KIND_CALL: - if ($inline) { - $zend_attributes = " zend_always_inline"; - $zend_fastcall = ""; - } else { - if ($cold) { - $zend_attributes = " zend_never_inline ZEND_COLD"; - } else { - $zend_attributes = " zend_never_inline"; - } - $zend_fastcall = " ZEND_FASTCALL"; - } - if ($param == null) { - // Helper without parameters - out($f, "static$zend_attributes ZEND_OPCODE_HANDLER_RET$zend_fastcall $spec_name(ZEND_OPCODE_HANDLER_ARGS)\n"); - } else { - // Helper with parameter - out($f, "static$zend_attributes ZEND_OPCODE_HANDLER_RET$zend_fastcall $spec_name($param ZEND_OPCODE_HANDLER_ARGS_DC)\n"); - } - break; - case ZEND_VM_KIND_SWITCH: - out($f, "$spec_name:\n"); - break; - case ZEND_VM_KIND_GOTO: - out($f, "$spec_name:\n"); - break; - } - - // Generate helper's code - gen_code($f, $spec, $kind, 0, $code, $op1, $op2, $name, $extra_spec); + global $definition_file, $prefix; + + if ($kind == ZEND_VM_KIND_HYBRID && !$hot) { + return; + } + + if ($spec && skip_extra_spec_function($op1, $op2, $extra_spec)) { + return; + } + + if (ZEND_VM_LINES) { + out($f, "#line $lineno \"$definition_file\"\n"); + } + + $spec_name = $name.($spec?"_SPEC":"").$prefix[$op1].$prefix[$op2].($spec?extra_spec_name($extra_spec):""); + + // Generate helper's entry point according to selected threading model + switch($kind) { + case ZEND_VM_KIND_HYBRID: + out($f, $spec_name . "_LABEL:\n"); + break; + case ZEND_VM_KIND_CALL: + if ($inline) { + $zend_attributes = " zend_always_inline"; + $zend_fastcall = ""; + } else { + if ($cold) { + $zend_attributes = " zend_never_inline ZEND_COLD"; + } else { + $zend_attributes = " zend_never_inline"; + } + $zend_fastcall = " ZEND_FASTCALL"; + } + if ($param == null) { + // Helper without parameters + out($f, "static$zend_attributes ZEND_OPCODE_HANDLER_RET$zend_fastcall $spec_name(ZEND_OPCODE_HANDLER_ARGS)\n"); + } else { + // Helper with parameter + out($f, "static$zend_attributes ZEND_OPCODE_HANDLER_RET$zend_fastcall $spec_name($param ZEND_OPCODE_HANDLER_ARGS_DC)\n"); + } + break; + case ZEND_VM_KIND_SWITCH: + out($f, "$spec_name:\n"); + break; + case ZEND_VM_KIND_GOTO: + out($f, "$spec_name:\n"); + break; + } + + // Generate helper's code + gen_code($f, $spec, $kind, 0, $code, $op1, $op2, $name, $extra_spec); } function gen_null_label($f, $kind, $prolog) { - switch ($kind) { - case ZEND_VM_KIND_CALL: - out($f,$prolog."ZEND_NULL_HANDLER,\n"); - break; - case ZEND_VM_KIND_SWITCH: - out($f,$prolog."(void*)(uintptr_t)-1,\n"); - break; - case ZEND_VM_KIND_GOTO: - out($f,$prolog."(void*)&&ZEND_NULL_LABEL,\n"); - break; - } + switch ($kind) { + case ZEND_VM_KIND_CALL: + out($f,$prolog."ZEND_NULL_HANDLER,\n"); + break; + case ZEND_VM_KIND_SWITCH: + out($f,$prolog."(void*)(uintptr_t)-1,\n"); + break; + case ZEND_VM_KIND_GOTO: + out($f,$prolog."(void*)&&ZEND_NULL_LABEL,\n"); + break; + } } // Generates array of opcode handlers (specialized or unspecialized) function gen_labels($f, $spec, $kind, $prolog, &$specs, $switch_labels = array()) { - global $opcodes, $opnames, $op_types, $prefix, $op_types_ex; - - $list = []; - $next = 0; - $label = 0; - if ($spec) { - // Emit labels for specialized executor - - // For each opcode in opcode number order - foreach($opcodes as $num => $dsc) { - if (isset($dsc['alias'])) { - $specs[$num] = $specs[$opnames[$dsc['alias']]]; - continue; - } - $specs[$num] = "$label"; - $spec_op1 = $spec_op2 = $spec_extra = false; - $def_op1_type = $def_op2_type = "ANY"; - $next = $num + 1; - if (isset($dsc["op1"]) && !isset($dsc["op1"]["ANY"])) { - $count = 0; - foreach ($op_types_ex as $t) { - if (isset($dsc["op1"][$t])) { - $def_op1_type = $t; - $count++; - } - } - if ($count > 1) { - $spec_op1 = true; - $specs[$num] .= " | SPEC_RULE_OP1"; - $def_op1_type = "ANY"; - } - } - if (isset($dsc["op2"]) && !isset($dsc["op2"]["ANY"])) { - $count = 0; - foreach ($op_types_ex as $t) { - if (isset($dsc["op2"][$t])) { - $def_op2_type = $t; - $count++; - } - } - if ($count > 1) { - $spec_op2 = true; - $specs[$num] .= " | SPEC_RULE_OP2"; - $def_op2_type = "ANY"; - } - } - $spec_extra = call_user_func_array("array_merge", extra_spec_handler($dsc) ?: array(array())); - $flags = extra_spec_flags($spec_extra); - if ($flags) { - $specs[$num] .= " | " . implode(" | ", $flags); - } - if ($num >= 256) { - $opcodes[$num]['spec_code'] = $specs[$num]; - unset($specs[$num]); - } - - $foreach_op1 = function($do) use ($dsc, $op_types) { - return function($_, $op2) use ($do, $dsc, $op_types) { - // For each op1.op_type except ANY - foreach($op_types as $op1) { - if ($op1 != "ANY") { - if (!isset($dsc["op1"][$op1])) { - if ($op1 == "TMP" || $op1 == "VAR") { - if (isset($dsc["op1"]["TMPVAR"])) { - $op1 = "TMPVAR"; - } else if (isset($dsc["op1"]["TMPVARCV"])) { - $op1 = "TMPVARCV"; - } else { - $op1 = "ANY"; - } - } else if ($op1 == "CV" && isset($dsc["op1"]["TMPVARCV"])) { - $op1 = "TMPVARCV"; - } else { - // Try to use unspecialized handler - $op1 = "ANY"; - } - } - $do($op1, $op2); - } - } - }; - }; - $foreach_op2 = function($do) use ($dsc, $op_types) { - return function($op1, $_) use ($do, $dsc, $op_types) { - // For each op2.op_type except ANY - foreach($op_types as $op2) { - if ($op2 != "ANY") { - if (!isset($dsc["op2"][$op2])) { - if ($op2 == "TMP" || $op2 == "VAR") { - if (isset($dsc["op2"]["TMPVAR"])) { - $op2 = "TMPVAR"; - } else if (isset($dsc["op2"]["TMPVARCV"])) { - $op2 = "TMPVARCV"; - } else { - $op2 = "ANY"; - } - } else if ($op2 == "CV" && isset($dsc["op2"]["TMPVARCV"])) { - $op2 = "TMPVARCV"; - } else { - // Try to use unspecialized handler - $op2 = "ANY"; - } - } - $do($op1, $op2); - } - } - }; - }; - $foreach_op_data = function($do) use ($dsc, $op_types) { - return function($op1, $op2, $extra_spec = array()) use ($do, $dsc, $op_types) { - // For each op_data.op_type except ANY - foreach($op_types as $op_data) { - if ($op_data != "ANY") { - if (!isset($dsc["spec"]["OP_DATA"][$op_data])) { - if ($op_data == "TMP" || $op_data == "VAR") { - if (isset($dsc["spec"]["OP_DATA"]["TMPVAR"])) { - $op_data = "TMPVAR"; - } else if (isset($dsc["spec"]["OP_DATA"]["TMPVARCV"])) { - $op_data = "TMPVARCV"; - } else { - // Try to use unspecialized handler - $op_data = "ANY"; - } - } else if ($op_data == "CV" && isset($dsc["OP_DATA"]["TMPVARCV"])) { - $op_data = "TMPVARCV"; - } else { - // Try to use unspecialized handler - $op_data = "ANY"; - } - } - $do($op1, $op2, array("OP_DATA" => $op_data) + $extra_spec); - } - } - }; - }; - $foreach_extra_spec = function($do, $spec) use ($dsc) { - return function($op1, $op2, $extra_spec = array()) use ($do, $spec, $dsc) { - foreach ($dsc["spec"][$spec] as $val) { - $do($op1, $op2, array($spec => $val) + $extra_spec); - } - }; - }; - $generate = function ($op1, $op2, $extra_spec = array()) use ($f, $kind, $dsc, $prefix, $prolog, $num, $switch_labels, &$label, &$list) { - global $commutative_order; - - // Check if specialized handler is defined - /* TODO: figure out better way to signal "specialized and not defined" than an extra lookup */ - if (isset($dsc["op1"][$op1]) && - isset($dsc["op2"][$op2]) && - (!isset($extra_spec["OP_DATA"]) || isset($dsc["spec"]["OP_DATA"][$extra_spec["OP_DATA"]]))) { - if (skip_extra_spec_function($op1, $op2, $extra_spec)) { - gen_null_label($f, $kind, $prolog); - $list[$label] = null; - $label++; - return; - } - - /* Skip SMART_BRANCH specialization for "cold" CONST_CONST instructions */ - if (isset($extra_spec["SMART_BRANCH"])) { - if ($dsc["hot"] === 'HOT_NOCONSTCONST_' - || $dsc["hot"] === 'COLD_CONSTCONST_') { - if (($op1 === 'CONST') && ($op2 === 'CONST')) { - unset($extra_spec["SMART_BRANCH"]); - } - } - } - - // Emit pointer to specialized handler - $spec_name = $dsc["op"]."_SPEC".$prefix[$op1].$prefix[$op2].extra_spec_name($extra_spec); - switch ($kind) { - case ZEND_VM_KIND_CALL: - out($f,"$prolog{$spec_name}_HANDLER,\n"); - break; - case ZEND_VM_KIND_SWITCH: - out($f,$prolog."(void*)(uintptr_t)$switch_labels[$spec_name],\n"); - break; - case ZEND_VM_KIND_GOTO: - out($f,$prolog."(void*)&&{$spec_name}_LABEL,\n"); - break; - } - $list[$label] = $spec_name; - $label++; - } else { - // Emit pointer to handler of undefined opcode - gen_null_label($f, $kind, $prolog); - $list[$label] = null; - $label++; - } - }; - - $do = $generate; - if ($spec_extra) { - foreach ($spec_extra as $extra => $devnull) { - if ($extra == "OP_DATA") { - $do = $foreach_op_data($do); - } else { - $do = $foreach_extra_spec($do, $extra); - } - } - } - if ($spec_op2) { - $do = $foreach_op2($do); - } - if ($spec_op1) { - $do = $foreach_op1($do); - } - - $do($def_op1_type, $def_op2_type); - } - } else { - // Emit labels for unspecialized executor - - // For each opcode in opcode number order - foreach($opcodes as $num => $dsc) { - while ($next != $num) { - // If some opcode numbers are not used then fill hole with pointers - // to handler of undefined opcode - switch ($kind) { - case ZEND_VM_KIND_CALL: - out($f,$prolog."ZEND_NULL_HANDLER,\n"); - break; - case ZEND_VM_KIND_SWITCH: - out($f,$prolog."(void*)(uintptr_t)-1,\n"); - break; - case ZEND_VM_KIND_GOTO: - out($f,$prolog."(void*)&&ZEND_NULL_LABEL,\n"); - break; - } - $next++; - } - if ($num >= 256) { - continue; - } - $next = $num+1; - - if (isset($dsc['alias']) && $kind != ZEND_VM_KIND_SWITCH) { - // Emit pointer to unspecialized handler - switch ($kind) { - case ZEND_VM_KIND_CALL: - out($f,$prolog.$dsc['alias']."_HANDLER,\n"); - break; - case ZEND_VM_KIND_GOTO: - out($f,$prolog."(void*)&&".$dsc['alias']."_LABEL,\n"); - break; - } - $list[] = $dsc["op"]; - } else if ($dsc["code"]) { //ugly trick for ZEND_VM_DEFINE_OP - // Emit pointer to unspecialized handler - switch ($kind) { - case ZEND_VM_KIND_CALL: - out($f,$prolog.$dsc["op"]."_HANDLER,\n"); - break; - case ZEND_VM_KIND_SWITCH: - out($f,$prolog."(void*)(uintptr_t)".((string)$num).",\n"); - break; - case ZEND_VM_KIND_GOTO: - out($f,$prolog."(void*)&&".$dsc["op"]."_LABEL,\n"); - break; - } - $list[] = $dsc["op"]; - } else { - switch ($kind) { - case ZEND_VM_KIND_CALL: - out($f,$prolog."ZEND_NULL_HANDLER,\n"); - break; - case ZEND_VM_KIND_SWITCH: - out($f,$prolog."(void*)(uintptr_t)-1,\n"); - break; - case ZEND_VM_KIND_GOTO: - out($f,$prolog."(void*)&&ZEND_NULL_LABEL,\n"); - break; - } - $list[] = null; - } - } - } - - // Emit last handler's label (undefined opcode) - switch ($kind) { - case ZEND_VM_KIND_CALL: - out($f,$prolog."ZEND_NULL_HANDLER\n"); - break; - case ZEND_VM_KIND_SWITCH: - out($f,$prolog."(void*)(uintptr_t)-1\n"); - break; - case ZEND_VM_KIND_GOTO: - out($f,$prolog."(void*)&&ZEND_NULL_LABEL\n"); - break; - } - $specs[$num + 1] = "$label"; - - $l = fopen(__DIR__ . "/zend_vm_handlers.h", "w+") or die("ERROR: Cannot create zend_vm_handlers.h\n"); - out($l, "#define VM_HANDLERS(_) \\\n"); - foreach ($list as $n => $name) { - if (!is_null($name)) { - out($l, "\t_($n, $name) \\\n"); - } - } - out($l, "\t_($n+1, ZEND_NULL)\n"); - fclose($l); + global $opcodes, $opnames, $op_types, $prefix, $op_types_ex; + + $list = []; + $next = 0; + $label = 0; + if ($spec) { + // Emit labels for specialized executor + + // For each opcode in opcode number order + foreach($opcodes as $num => $dsc) { + if (isset($dsc['alias'])) { + $specs[$num] = $specs[$opnames[$dsc['alias']]]; + continue; + } + $specs[$num] = "$label"; + $spec_op1 = $spec_op2 = $spec_extra = false; + $def_op1_type = $def_op2_type = "ANY"; + $next = $num + 1; + if (isset($dsc["op1"]) && !isset($dsc["op1"]["ANY"])) { + $count = 0; + foreach ($op_types_ex as $t) { + if (isset($dsc["op1"][$t])) { + $def_op1_type = $t; + $count++; + } + } + if ($count > 1) { + $spec_op1 = true; + $specs[$num] .= " | SPEC_RULE_OP1"; + $def_op1_type = "ANY"; + } + } + if (isset($dsc["op2"]) && !isset($dsc["op2"]["ANY"])) { + $count = 0; + foreach ($op_types_ex as $t) { + if (isset($dsc["op2"][$t])) { + $def_op2_type = $t; + $count++; + } + } + if ($count > 1) { + $spec_op2 = true; + $specs[$num] .= " | SPEC_RULE_OP2"; + $def_op2_type = "ANY"; + } + } + $spec_extra = call_user_func_array("array_merge", extra_spec_handler($dsc) ?: array(array())); + $flags = extra_spec_flags($spec_extra); + if ($flags) { + $specs[$num] .= " | " . implode(" | ", $flags); + } + if ($num >= 256) { + $opcodes[$num]['spec_code'] = $specs[$num]; + unset($specs[$num]); + } + + $foreach_op1 = function($do) use ($dsc, $op_types) { + return function($_, $op2) use ($do, $dsc, $op_types) { + // For each op1.op_type except ANY + foreach($op_types as $op1) { + if ($op1 != "ANY") { + if (!isset($dsc["op1"][$op1])) { + if ($op1 == "TMP" || $op1 == "VAR") { + if (isset($dsc["op1"]["TMPVAR"])) { + $op1 = "TMPVAR"; + } else if (isset($dsc["op1"]["TMPVARCV"])) { + $op1 = "TMPVARCV"; + } else { + $op1 = "ANY"; + } + } else if ($op1 == "CV" && isset($dsc["op1"]["TMPVARCV"])) { + $op1 = "TMPVARCV"; + } else { + // Try to use unspecialized handler + $op1 = "ANY"; + } + } + $do($op1, $op2); + } + } + }; + }; + $foreach_op2 = function($do) use ($dsc, $op_types) { + return function($op1, $_) use ($do, $dsc, $op_types) { + // For each op2.op_type except ANY + foreach($op_types as $op2) { + if ($op2 != "ANY") { + if (!isset($dsc["op2"][$op2])) { + if ($op2 == "TMP" || $op2 == "VAR") { + if (isset($dsc["op2"]["TMPVAR"])) { + $op2 = "TMPVAR"; + } else if (isset($dsc["op2"]["TMPVARCV"])) { + $op2 = "TMPVARCV"; + } else { + $op2 = "ANY"; + } + } else if ($op2 == "CV" && isset($dsc["op2"]["TMPVARCV"])) { + $op2 = "TMPVARCV"; + } else { + // Try to use unspecialized handler + $op2 = "ANY"; + } + } + $do($op1, $op2); + } + } + }; + }; + $foreach_op_data = function($do) use ($dsc, $op_types) { + return function($op1, $op2, $extra_spec = array()) use ($do, $dsc, $op_types) { + // For each op_data.op_type except ANY + foreach($op_types as $op_data) { + if ($op_data != "ANY") { + if (!isset($dsc["spec"]["OP_DATA"][$op_data])) { + if ($op_data == "TMP" || $op_data == "VAR") { + if (isset($dsc["spec"]["OP_DATA"]["TMPVAR"])) { + $op_data = "TMPVAR"; + } else if (isset($dsc["spec"]["OP_DATA"]["TMPVARCV"])) { + $op_data = "TMPVARCV"; + } else { + // Try to use unspecialized handler + $op_data = "ANY"; + } + } else if ($op_data == "CV" && isset($dsc["OP_DATA"]["TMPVARCV"])) { + $op_data = "TMPVARCV"; + } else { + // Try to use unspecialized handler + $op_data = "ANY"; + } + } + $do($op1, $op2, array("OP_DATA" => $op_data) + $extra_spec); + } + } + }; + }; + $foreach_extra_spec = function($do, $spec) use ($dsc) { + return function($op1, $op2, $extra_spec = array()) use ($do, $spec, $dsc) { + foreach ($dsc["spec"][$spec] as $val) { + $do($op1, $op2, array($spec => $val) + $extra_spec); + } + }; + }; + $generate = function ($op1, $op2, $extra_spec = array()) use ($f, $kind, $dsc, $prefix, $prolog, $num, $switch_labels, &$label, &$list) { + global $commutative_order; + + // Check if specialized handler is defined + /* TODO: figure out better way to signal "specialized and not defined" than an extra lookup */ + if (isset($dsc["op1"][$op1]) && + isset($dsc["op2"][$op2]) && + (!isset($extra_spec["OP_DATA"]) || isset($dsc["spec"]["OP_DATA"][$extra_spec["OP_DATA"]]))) { + if (skip_extra_spec_function($op1, $op2, $extra_spec)) { + gen_null_label($f, $kind, $prolog); + $list[$label] = null; + $label++; + return; + } + + /* Skip SMART_BRANCH specialization for "cold" CONST_CONST instructions */ + if (isset($extra_spec["SMART_BRANCH"])) { + if ($dsc["hot"] === 'HOT_NOCONSTCONST_' + || $dsc["hot"] === 'COLD_CONSTCONST_') { + if (($op1 === 'CONST') && ($op2 === 'CONST')) { + unset($extra_spec["SMART_BRANCH"]); + } + } + } + + // Emit pointer to specialized handler + $spec_name = $dsc["op"]."_SPEC".$prefix[$op1].$prefix[$op2].extra_spec_name($extra_spec); + switch ($kind) { + case ZEND_VM_KIND_CALL: + out($f,"$prolog{$spec_name}_HANDLER,\n"); + break; + case ZEND_VM_KIND_SWITCH: + out($f,$prolog."(void*)(uintptr_t)$switch_labels[$spec_name],\n"); + break; + case ZEND_VM_KIND_GOTO: + out($f,$prolog."(void*)&&{$spec_name}_LABEL,\n"); + break; + } + $list[$label] = $spec_name; + $label++; + } else { + // Emit pointer to handler of undefined opcode + gen_null_label($f, $kind, $prolog); + $list[$label] = null; + $label++; + } + }; + + $do = $generate; + if ($spec_extra) { + foreach ($spec_extra as $extra => $devnull) { + if ($extra == "OP_DATA") { + $do = $foreach_op_data($do); + } else { + $do = $foreach_extra_spec($do, $extra); + } + } + } + if ($spec_op2) { + $do = $foreach_op2($do); + } + if ($spec_op1) { + $do = $foreach_op1($do); + } + + $do($def_op1_type, $def_op2_type); + } + } else { + // Emit labels for unspecialized executor + + // For each opcode in opcode number order + foreach($opcodes as $num => $dsc) { + while ($next != $num) { + // If some opcode numbers are not used then fill hole with pointers + // to handler of undefined opcode + switch ($kind) { + case ZEND_VM_KIND_CALL: + out($f,$prolog."ZEND_NULL_HANDLER,\n"); + break; + case ZEND_VM_KIND_SWITCH: + out($f,$prolog."(void*)(uintptr_t)-1,\n"); + break; + case ZEND_VM_KIND_GOTO: + out($f,$prolog."(void*)&&ZEND_NULL_LABEL,\n"); + break; + } + $next++; + } + if ($num >= 256) { + continue; + } + $next = $num+1; + + if (isset($dsc['alias']) && $kind != ZEND_VM_KIND_SWITCH) { + // Emit pointer to unspecialized handler + switch ($kind) { + case ZEND_VM_KIND_CALL: + out($f,$prolog.$dsc['alias']."_HANDLER,\n"); + break; + case ZEND_VM_KIND_GOTO: + out($f,$prolog."(void*)&&".$dsc['alias']."_LABEL,\n"); + break; + } + $list[] = $dsc["op"]; + } else if ($dsc["code"]) { //ugly trick for ZEND_VM_DEFINE_OP + // Emit pointer to unspecialized handler + switch ($kind) { + case ZEND_VM_KIND_CALL: + out($f,$prolog.$dsc["op"]."_HANDLER,\n"); + break; + case ZEND_VM_KIND_SWITCH: + out($f,$prolog."(void*)(uintptr_t)".((string)$num).",\n"); + break; + case ZEND_VM_KIND_GOTO: + out($f,$prolog."(void*)&&".$dsc["op"]."_LABEL,\n"); + break; + } + $list[] = $dsc["op"]; + } else { + switch ($kind) { + case ZEND_VM_KIND_CALL: + out($f,$prolog."ZEND_NULL_HANDLER,\n"); + break; + case ZEND_VM_KIND_SWITCH: + out($f,$prolog."(void*)(uintptr_t)-1,\n"); + break; + case ZEND_VM_KIND_GOTO: + out($f,$prolog."(void*)&&ZEND_NULL_LABEL,\n"); + break; + } + $list[] = null; + } + } + } + + // Emit last handler's label (undefined opcode) + switch ($kind) { + case ZEND_VM_KIND_CALL: + out($f,$prolog."ZEND_NULL_HANDLER\n"); + break; + case ZEND_VM_KIND_SWITCH: + out($f,$prolog."(void*)(uintptr_t)-1\n"); + break; + case ZEND_VM_KIND_GOTO: + out($f,$prolog."(void*)&&ZEND_NULL_LABEL\n"); + break; + } + $specs[$num + 1] = "$label"; + + $l = fopen(__DIR__ . "/zend_vm_handlers.h", "w+") or die("ERROR: Cannot create zend_vm_handlers.h\n"); + out($l, "#define VM_HANDLERS(_) \\\n"); + foreach ($list as $n => $name) { + if (!is_null($name)) { + out($l, "\t_($n, $name) \\\n"); + } + } + out($l, "\t_($n+1, ZEND_NULL)\n"); + fclose($l); } // Generates specialized offsets function gen_specs($f, $prolog, $specs) { - $lastdef = array_pop($specs); - $last = 0; - foreach ($specs as $num => $def) { - while (++$last < $num) { - out($f, "$prolog$lastdef,\n"); - } - $last = $num; - out($f, "$prolog$def,\n"); - } - out($f, "$prolog$lastdef\n"); + $lastdef = array_pop($specs); + $last = 0; + foreach ($specs as $num => $def) { + while (++$last < $num) { + out($f, "$prolog$lastdef,\n"); + } + $last = $num; + out($f, "$prolog$def,\n"); + } + out($f, "$prolog$lastdef\n"); } // Generates handler for undefined opcodes (CALL threading model) function gen_null_handler($f) { - static $done = 0; - - // New and all executors with CALL threading model can use the same handler - // for undefined opcodes, do we emit code for it only once - if (!$done) { - $done = 1; - out($f,"static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_NULL_HANDLER(ZEND_OPCODE_HANDLER_ARGS)\n"); - out($f,"{\n"); - out($f,"\tUSE_OPLINE\n"); - out($f,"\n"); - out($f,"\tzend_error_noreturn(E_ERROR, \"Invalid opcode %d/%d/%d.\", OPLINE->opcode, OPLINE->op1_type, OPLINE->op2_type);\n"); - out($f,"\tZEND_VM_NEXT_OPCODE(); /* Never reached */\n"); - out($f,"}\n\n"); - } + static $done = 0; + + // New and all executors with CALL threading model can use the same handler + // for undefined opcodes, do we emit code for it only once + if (!$done) { + $done = 1; + out($f,"static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_NULL_HANDLER(ZEND_OPCODE_HANDLER_ARGS)\n"); + out($f,"{\n"); + out($f,"\tUSE_OPLINE\n"); + out($f,"\n"); + out($f,"\tzend_error_noreturn(E_ERROR, \"Invalid opcode %d/%d/%d.\", OPLINE->opcode, OPLINE->op1_type, OPLINE->op2_type);\n"); + out($f,"\tZEND_VM_NEXT_OPCODE(); /* Never reached */\n"); + out($f,"}\n\n"); + } } function extra_spec_name($extra_spec) { - global $prefix; - - $s = ""; - if (isset($extra_spec["OP_DATA"])) { - $s .= "_OP_DATA" . $prefix[$extra_spec["OP_DATA"]]; - } - if (isset($extra_spec["RETVAL"])) { - $s .= "_RETVAL_".($extra_spec["RETVAL"] ? "USED" : "UNUSED"); - } - if (isset($extra_spec["QUICK_ARG"])) { - if ($extra_spec["QUICK_ARG"]) { - $s .= "_QUICK"; - } - } - if (isset($extra_spec["SMART_BRANCH"])) { - if ($extra_spec["SMART_BRANCH"] == 1) { - $s .= "_JMPZ"; - } else if ($extra_spec["SMART_BRANCH"] == 2) { - $s .= "_JMPNZ"; - } - } - if (isset($extra_spec["ISSET"])) { - if ($extra_spec["ISSET"] == 0) { - $s .= "_SET"; - } else { - $s .= "_EMPTY"; - } - } - return $s; + global $prefix; + + $s = ""; + if (isset($extra_spec["OP_DATA"])) { + $s .= "_OP_DATA" . $prefix[$extra_spec["OP_DATA"]]; + } + if (isset($extra_spec["RETVAL"])) { + $s .= "_RETVAL_".($extra_spec["RETVAL"] ? "USED" : "UNUSED"); + } + if (isset($extra_spec["QUICK_ARG"])) { + if ($extra_spec["QUICK_ARG"]) { + $s .= "_QUICK"; + } + } + if (isset($extra_spec["SMART_BRANCH"])) { + if ($extra_spec["SMART_BRANCH"] == 1) { + $s .= "_JMPZ"; + } else if ($extra_spec["SMART_BRANCH"] == 2) { + $s .= "_JMPNZ"; + } + } + if (isset($extra_spec["ISSET"])) { + if ($extra_spec["ISSET"] == 0) { + $s .= "_SET"; + } else { + $s .= "_EMPTY"; + } + } + return $s; } function extra_spec_flags($extra_spec) { - $s = array(); - if (isset($extra_spec["OP_DATA"])) { - $s[] = "SPEC_RULE_OP_DATA"; - } - if (isset($extra_spec["RETVAL"])) { - $s[] = "SPEC_RULE_RETVAL"; - } - if (isset($extra_spec["QUICK_ARG"])) { - $s[] = "SPEC_RULE_QUICK_ARG"; - } - if (isset($extra_spec["SMART_BRANCH"])) { - $s[] = "SPEC_RULE_SMART_BRANCH"; - } - if (isset($extra_spec["COMMUTATIVE"])) { - $s[] = "SPEC_RULE_COMMUTATIVE"; - } - if (isset($extra_spec["ISSET"])) { - $s[] = "SPEC_RULE_ISSET"; - } - return $s; + $s = array(); + if (isset($extra_spec["OP_DATA"])) { + $s[] = "SPEC_RULE_OP_DATA"; + } + if (isset($extra_spec["RETVAL"])) { + $s[] = "SPEC_RULE_RETVAL"; + } + if (isset($extra_spec["QUICK_ARG"])) { + $s[] = "SPEC_RULE_QUICK_ARG"; + } + if (isset($extra_spec["SMART_BRANCH"])) { + $s[] = "SPEC_RULE_SMART_BRANCH"; + } + if (isset($extra_spec["COMMUTATIVE"])) { + $s[] = "SPEC_RULE_COMMUTATIVE"; + } + if (isset($extra_spec["ISSET"])) { + $s[] = "SPEC_RULE_ISSET"; + } + return $s; } function extra_spec_handler($dsc) { - global $op_types_ex; - - if (!isset($dsc["spec"])) { - return array(array()); - } - $specs = $dsc["spec"]; - - if (isset($specs["OP_DATA"])) { - $op_data_specs = $specs["OP_DATA"]; - $specs["OP_DATA"] = array(); - foreach($op_types_ex as $op_data) { - if (isset($dsc["spec"]["OP_DATA"][$op_data])) { - $specs["OP_DATA"][] = $op_data; - } - } - } - - $f = function($specs) use (&$f) { - $spec = key($specs); - $top = array_shift($specs); - if ($specs) { - $next = $f($specs); - } else { - $next = array(array()); - } - $ret = array(); - foreach ($next as $existing) { - foreach ($top as $mode) { - $ret[] = array($spec => $mode) + $existing; - } - } - return $ret; - }; - return $f($specs); + global $op_types_ex; + + if (!isset($dsc["spec"])) { + return array(array()); + } + $specs = $dsc["spec"]; + + if (isset($specs["OP_DATA"])) { + $op_data_specs = $specs["OP_DATA"]; + $specs["OP_DATA"] = array(); + foreach($op_types_ex as $op_data) { + if (isset($dsc["spec"]["OP_DATA"][$op_data])) { + $specs["OP_DATA"][] = $op_data; + } + } + } + + $f = function($specs) use (&$f) { + $spec = key($specs); + $top = array_shift($specs); + if ($specs) { + $next = $f($specs); + } else { + $next = array(array()); + } + $ret = array(); + foreach ($next as $existing) { + foreach ($top as $mode) { + $ret[] = array($spec => $mode) + $existing; + } + } + return $ret; + }; + return $f($specs); } function read_order_file($fn) { - $f = fopen($fn, "r"); - if (!is_resource($f)) { - return false; - } - $order = []; - while (!feof($f)) { - $op = trim(fgets($f)); - if ($op !== "") { - $order[$op] = null; - } - } - fclose($f); - return $order; + $f = fopen($fn, "r"); + if (!is_resource($f)) { + return false; + } + $order = []; + while (!feof($f)) { + $op = trim(fgets($f)); + if ($op !== "") { + $order[$op] = null; + } + } + fclose($f); + return $order; } // Generates all opcode handlers and helpers (specialized or unspecilaized) function gen_executor_code($f, $spec, $kind, $prolog, &$switch_labels = array()) { - global $list, $opcodes, $helpers, $op_types_ex, $gen_order; - - if ($kind == ZEND_VM_KIND_HYBRID && file_exists(__DIR__ . "/zend_vm_order.txt")) { - $gen_order = read_order_file(__DIR__ . "/zend_vm_order.txt"); - } else { - $gen_order = null; - } - - if ($spec) { - // Produce specialized executor - $op1t = $op_types_ex; - // for each op1.op_type - foreach($op1t as $op1) { - $op2t = $op_types_ex; - // for each op2.op_type - foreach($op2t as $op2) { - // for each handlers in helpers in original order - foreach ($list as $lineno => $dsc) { - if (isset($dsc["handler"])) { - $num = $dsc["handler"]; - foreach (extra_spec_handler($opcodes[$num]) as $extra_spec) { - // Check if handler accepts such types of operands (op1 and op2) - if (isset($opcodes[$num]["op1"][$op1]) && - isset($opcodes[$num]["op2"][$op2])) { - // Generate handler code - gen_handler($f, 1, $kind, $opcodes[$num]["op"], $op1, $op2, isset($opcodes[$num]["use"]), $opcodes[$num]["code"], $lineno, $opcodes[$num], $extra_spec, $switch_labels); - } - } - } else if (isset($dsc["helper"])) { - $num = $dsc["helper"]; - foreach (extra_spec_handler($helpers[$num]) as $extra_spec) { - // Check if handler accepts such types of operands (op1 and op2) - if (isset($helpers[$num]["op1"][$op1]) && - isset($helpers[$num]["op2"][$op2])) { - // Generate helper code - gen_helper($f, 1, $kind, $num, $op1, $op2, $helpers[$num]["param"], $helpers[$num]["code"], $lineno, $helpers[$num]["inline"], $helpers[$num]["cold"], $helpers[$num]["hot"], $extra_spec); - } - } - } else { - var_dump($dsc); - die("??? $kind:$num\n"); - } - } - } - } - } else { - // Produce unspecialized executor - - // for each handlers in helpers in original order - foreach ($list as $lineno => $dsc) { - if (isset($dsc["handler"])) { - $num = $dsc["handler"]; - // Generate handler code - if ($num < 256) { - gen_handler($f, 0, $kind, $opcodes[$num]["op"], "ANY", "ANY", isset($opcodes[$num]["use"]), $opcodes[$num]["code"], $lineno, $opcodes[$num]); - } - } else if (isset($dsc["helper"])) { - $num = $dsc["helper"]; - // Generate helper code - gen_helper($f, 0, $kind, $num, "ANY", "ANY", $helpers[$num]["param"], $helpers[$num]["code"], $lineno, $helpers[$num]["inline"], $helpers[$num]["cold"], $helpers[$num]["hot"]); - } else { - var_dump($dsc); - die("??? $kind:$num\n"); - } - } - } - - if (is_array($gen_order)) { - foreach ($gen_order as $txt) { - if ($txt !== null) { - out($f, $txt); - } - } - } - - if (ZEND_VM_LINES) { - // Reset #line directives - out_line($f); - } - - // Generate handler for undefined opcodes - switch ($kind) { - case ZEND_VM_KIND_CALL: - gen_null_handler($f); - break; - case ZEND_VM_KIND_SWITCH: - out($f,"default: ZEND_NULL_LABEL:\n"); - out($f,"\tzend_error_noreturn(E_ERROR, \"Invalid opcode %d/%d/%d.\", OPLINE->opcode, OPLINE->op1_type, OPLINE->op2_type);\n"); - out($f,"\tZEND_VM_NEXT_OPCODE(); /* Never reached */\n"); - break; - case ZEND_VM_KIND_GOTO: - out($f,"ZEND_NULL_LABEL:\n"); - out($f,"\tzend_error_noreturn(E_ERROR, \"Invalid opcode %d/%d/%d.\", OPLINE->opcode, OPLINE->op1_type, OPLINE->op2_type);\n"); - out($f,"\tZEND_VM_NEXT_OPCODE(); /* Never reached */\n"); - break; - case ZEND_VM_KIND_HYBRID: - out($f,"\t\t\tHYBRID_CASE(HYBRID_HALT):\n"); - out($f,"#ifdef ZEND_VM_FP_GLOBAL_REG\n"); - out($f,"\t\t\t\texecute_data = orig_execute_data;\n"); - out($f,"#endif\n"); - out($f,"#ifdef ZEND_VM_IP_GLOBAL_REG\n"); - out($f,"\t\t\t\topline = orig_opline;\n"); - out($f,"#endif\n"); - out($f,"\t\t\t\treturn;\n"); - out($f,"\t\t\tHYBRID_DEFAULT:\n"); - out($f,"\t\t\t\tVM_TRACE(ZEND_NULL)\n"); - out($f,"\t\t\t\tZEND_NULL_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);\n"); - out($f,"\t\t\t\tHYBRID_BREAK(); /* Never reached */\n"); - break; - } + global $list, $opcodes, $helpers, $op_types_ex, $gen_order; + + if ($kind == ZEND_VM_KIND_HYBRID && file_exists(__DIR__ . "/zend_vm_order.txt")) { + $gen_order = read_order_file(__DIR__ . "/zend_vm_order.txt"); + } else { + $gen_order = null; + } + + if ($spec) { + // Produce specialized executor + $op1t = $op_types_ex; + // for each op1.op_type + foreach($op1t as $op1) { + $op2t = $op_types_ex; + // for each op2.op_type + foreach($op2t as $op2) { + // for each handlers in helpers in original order + foreach ($list as $lineno => $dsc) { + if (isset($dsc["handler"])) { + $num = $dsc["handler"]; + foreach (extra_spec_handler($opcodes[$num]) as $extra_spec) { + // Check if handler accepts such types of operands (op1 and op2) + if (isset($opcodes[$num]["op1"][$op1]) && + isset($opcodes[$num]["op2"][$op2])) { + // Generate handler code + gen_handler($f, 1, $kind, $opcodes[$num]["op"], $op1, $op2, isset($opcodes[$num]["use"]), $opcodes[$num]["code"], $lineno, $opcodes[$num], $extra_spec, $switch_labels); + } + } + } else if (isset($dsc["helper"])) { + $num = $dsc["helper"]; + foreach (extra_spec_handler($helpers[$num]) as $extra_spec) { + // Check if handler accepts such types of operands (op1 and op2) + if (isset($helpers[$num]["op1"][$op1]) && + isset($helpers[$num]["op2"][$op2])) { + // Generate helper code + gen_helper($f, 1, $kind, $num, $op1, $op2, $helpers[$num]["param"], $helpers[$num]["code"], $lineno, $helpers[$num]["inline"], $helpers[$num]["cold"], $helpers[$num]["hot"], $extra_spec); + } + } + } else { + var_dump($dsc); + die("??? $kind:$num\n"); + } + } + } + } + } else { + // Produce unspecialized executor + + // for each handlers in helpers in original order + foreach ($list as $lineno => $dsc) { + if (isset($dsc["handler"])) { + $num = $dsc["handler"]; + // Generate handler code + if ($num < 256) { + gen_handler($f, 0, $kind, $opcodes[$num]["op"], "ANY", "ANY", isset($opcodes[$num]["use"]), $opcodes[$num]["code"], $lineno, $opcodes[$num]); + } + } else if (isset($dsc["helper"])) { + $num = $dsc["helper"]; + // Generate helper code + gen_helper($f, 0, $kind, $num, "ANY", "ANY", $helpers[$num]["param"], $helpers[$num]["code"], $lineno, $helpers[$num]["inline"], $helpers[$num]["cold"], $helpers[$num]["hot"]); + } else { + var_dump($dsc); + die("??? $kind:$num\n"); + } + } + } + + if (is_array($gen_order)) { + foreach ($gen_order as $txt) { + if ($txt !== null) { + out($f, $txt); + } + } + } + + if (ZEND_VM_LINES) { + // Reset #line directives + out_line($f); + } + + // Generate handler for undefined opcodes + switch ($kind) { + case ZEND_VM_KIND_CALL: + gen_null_handler($f); + break; + case ZEND_VM_KIND_SWITCH: + out($f,"default: ZEND_NULL_LABEL:\n"); + out($f,"\tzend_error_noreturn(E_ERROR, \"Invalid opcode %d/%d/%d.\", OPLINE->opcode, OPLINE->op1_type, OPLINE->op2_type);\n"); + out($f,"\tZEND_VM_NEXT_OPCODE(); /* Never reached */\n"); + break; + case ZEND_VM_KIND_GOTO: + out($f,"ZEND_NULL_LABEL:\n"); + out($f,"\tzend_error_noreturn(E_ERROR, \"Invalid opcode %d/%d/%d.\", OPLINE->opcode, OPLINE->op1_type, OPLINE->op2_type);\n"); + out($f,"\tZEND_VM_NEXT_OPCODE(); /* Never reached */\n"); + break; + case ZEND_VM_KIND_HYBRID: + out($f,"\t\t\tHYBRID_CASE(HYBRID_HALT):\n"); + out($f,"#ifdef ZEND_VM_FP_GLOBAL_REG\n"); + out($f,"\t\t\t\texecute_data = orig_execute_data;\n"); + out($f,"#endif\n"); + out($f,"#ifdef ZEND_VM_IP_GLOBAL_REG\n"); + out($f,"\t\t\t\topline = orig_opline;\n"); + out($f,"#endif\n"); + out($f,"\t\t\t\treturn;\n"); + out($f,"\t\t\tHYBRID_DEFAULT:\n"); + out($f,"\t\t\t\tVM_TRACE(ZEND_NULL)\n"); + out($f,"\t\t\t\tZEND_NULL_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);\n"); + out($f,"\t\t\t\tHYBRID_BREAK(); /* Never reached */\n"); + break; + } } function skip_blanks($f, $prolog, $epilog) { - if (trim($prolog) != "" || trim($epilog) != "") { - out($f, $prolog.$epilog); - } + if (trim($prolog) != "" || trim($epilog) != "") { + out($f, $prolog.$epilog); + } } // Generates executor from skeleton file and definition (specialized or unspecialized) function gen_executor($f, $skl, $spec, $kind, $executor_name, $initializer_name) { - global $params, $skeleton_file, $line_no; - - $switch_labels = array(); - $lineno = 0; - foreach ($skl as $line) { - // Skeleton file contains special markers in form %NAME% those are - // substituted by custom code - if (preg_match("/(.*)[{][%]([A-Z_]*)[%][}](.*)/", $line, $m)) { - switch ($m[2]) { - case "DEFINES": - out($f,"#define SPEC_START_MASK 0x0000ffff\n"); - out($f,"#define SPEC_EXTRA_MASK 0xfffc0000\n"); - out($f,"#define SPEC_RULE_OP1 0x00010000\n"); - out($f,"#define SPEC_RULE_OP2 0x00020000\n"); - out($f,"#define SPEC_RULE_OP_DATA 0x00040000\n"); - out($f,"#define SPEC_RULE_RETVAL 0x00080000\n"); - out($f,"#define SPEC_RULE_QUICK_ARG 0x00100000\n"); - out($f,"#define SPEC_RULE_SMART_BRANCH 0x00200000\n"); - out($f,"#define SPEC_RULE_COMMUTATIVE 0x00800000\n"); - out($f,"#define SPEC_RULE_ISSET 0x01000000\n"); - out($f,"\n"); - out($f,"static const uint32_t *zend_spec_handlers;\n"); - out($f,"static const void * const *zend_opcode_handlers;\n"); - out($f,"static int zend_handlers_count;\n"); - if ($kind == ZEND_VM_KIND_HYBRID) { - out($f,"#if (ZEND_VM_KIND == ZEND_VM_KIND_HYBRID)\n"); - out($f,"static const void * const * zend_opcode_handler_funcs;\n"); - out($f,"static zend_op hybrid_halt_op;\n"); - out($f,"#endif\n"); - } - out($f,"#if (ZEND_VM_KIND != ZEND_VM_KIND_HYBRID) || !ZEND_VM_SPEC\n"); - out($f,"static const void *zend_vm_get_opcode_handler(zend_uchar opcode, const zend_op* op);\n"); - out($f,"#endif\n\n"); - if ($kind == ZEND_VM_KIND_HYBRID) { - out($f,"#if (ZEND_VM_KIND == ZEND_VM_KIND_HYBRID)\n"); - out($f,"static const void *zend_vm_get_opcode_handler_func(zend_uchar opcode, const zend_op* op);\n"); - out($f,"#else\n"); - out($f,"# define zend_vm_get_opcode_handler_func zend_vm_get_opcode_handler\n"); - out($f,"#endif\n\n"); - } - out($f,"#ifndef VM_TRACE\n"); - out($f,"# define VM_TRACE(op)\n"); - out($f,"#endif\n"); - out($f,"#ifndef VM_TRACE_START\n"); - out($f,"# define VM_TRACE_START()\n"); - out($f,"#endif\n"); - out($f,"#ifndef VM_TRACE_END\n"); - out($f,"# define VM_TRACE_END()\n"); - out($f,"#endif\n"); - switch ($kind) { - case ZEND_VM_KIND_HYBRID: - out($f,"#if (ZEND_VM_KIND == ZEND_VM_KIND_HYBRID)\n"); - out($f,"#define HYBRID_NEXT() goto *(void**)(OPLINE->handler)\n"); - out($f,"#define HYBRID_SWITCH() HYBRID_NEXT();\n"); - out($f,"#define HYBRID_CASE(op) op ## _LABEL\n"); - out($f,"#define HYBRID_BREAK() HYBRID_NEXT()\n"); - out($f,"#define HYBRID_DEFAULT ZEND_NULL_LABEL\n"); - out($f,"#endif\n"); - case ZEND_VM_KIND_CALL: - out($f,"\n"); - out($f,"#ifdef ZEND_VM_FP_GLOBAL_REG\n"); - out($f,"# define ZEND_OPCODE_HANDLER_ARGS void\n"); - out($f,"# define ZEND_OPCODE_HANDLER_ARGS_PASSTHRU\n"); - out($f,"# define ZEND_OPCODE_HANDLER_ARGS_DC\n"); - out($f,"# define ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC\n"); - out($f,"#else\n"); - out($f,"# define ZEND_OPCODE_HANDLER_ARGS zend_execute_data *execute_data\n"); - out($f,"# define ZEND_OPCODE_HANDLER_ARGS_PASSTHRU execute_data\n"); - out($f,"# define ZEND_OPCODE_HANDLER_ARGS_DC , ZEND_OPCODE_HANDLER_ARGS\n"); - out($f,"# define ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC , ZEND_OPCODE_HANDLER_ARGS_PASSTHRU\n"); - out($f,"#endif\n"); - out($f,"\n"); - out($f,"#if defined(ZEND_VM_FP_GLOBAL_REG) && defined(ZEND_VM_IP_GLOBAL_REG)\n"); - out($f,"# define ZEND_OPCODE_HANDLER_RET void\n"); - out($f,"# define ZEND_VM_TAIL_CALL(call) call; return\n"); - out($f,"# ifdef ZEND_VM_TAIL_CALL_DISPATCH\n"); - out($f,"# define ZEND_VM_CONTINUE() ((opcode_handler_t)OPLINE->handler)(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); return\n"); - out($f,"# else\n"); - out($f,"# define ZEND_VM_CONTINUE() return\n"); - out($f,"# endif\n"); - if ($kind == ZEND_VM_KIND_HYBRID) { - out($f,"# if (ZEND_VM_KIND == ZEND_VM_KIND_HYBRID)\n"); - out($f,"# define ZEND_VM_RETURN() opline = &hybrid_halt_op; return\n"); - out($f,"# define ZEND_VM_HOT zend_always_inline ZEND_COLD ZEND_OPT_SIZE\n"); - out($f,"# define ZEND_VM_COLD ZEND_COLD ZEND_OPT_SIZE\n"); - out($f,"# else\n"); - out($f,"# define ZEND_VM_RETURN() opline = NULL; return\n"); - out($f,"# define ZEND_VM_HOT\n"); - out($f,"# define ZEND_VM_COLD ZEND_COLD ZEND_OPT_SIZE\n"); - out($f,"# endif\n"); - } else { - out($f,"# define ZEND_VM_RETURN() opline = NULL; return\n"); - out($f,"# define ZEND_VM_COLD ZEND_COLD ZEND_OPT_SIZE\n"); - } - out($f,"#else\n"); - out($f,"# define ZEND_OPCODE_HANDLER_RET int\n"); - out($f,"# define ZEND_VM_TAIL_CALL(call) return call\n"); - out($f,"# define ZEND_VM_CONTINUE() return 0\n"); - out($f,"# define ZEND_VM_RETURN() return -1\n"); - if ($kind == ZEND_VM_KIND_HYBRID) { - out($f,"# define ZEND_VM_HOT\n"); - } - out($f,"# define ZEND_VM_COLD ZEND_COLD ZEND_OPT_SIZE\n"); - out($f,"#endif\n"); - out($f,"\n"); - out($f,"typedef ZEND_OPCODE_HANDLER_RET (ZEND_FASTCALL *opcode_handler_t) (ZEND_OPCODE_HANDLER_ARGS);\n"); - out($f,"\n"); - out($f,"#undef OPLINE\n"); - out($f,"#undef DCL_OPLINE\n"); - out($f,"#undef USE_OPLINE\n"); - out($f,"#undef LOAD_OPLINE\n"); - out($f,"#undef LOAD_OPLINE_EX\n"); - out($f,"#undef SAVE_OPLINE\n"); - out($f,"#undef SAVE_OPLINE_EX\n"); - out($f,"#define DCL_OPLINE\n"); - out($f,"#ifdef ZEND_VM_IP_GLOBAL_REG\n"); - out($f,"# define OPLINE opline\n"); - out($f,"# define USE_OPLINE\n"); - out($f,"# define LOAD_OPLINE() opline = EX(opline)\n"); - out($f,"# define LOAD_OPLINE_EX()\n"); - out($f,"# define LOAD_NEXT_OPLINE() opline = EX(opline) + 1\n"); - out($f,"# define SAVE_OPLINE() EX(opline) = opline\n"); - out($f,"# define SAVE_OPLINE_EX() SAVE_OPLINE()\n"); - out($f,"#else\n"); - out($f,"# define OPLINE EX(opline)\n"); - out($f,"# define USE_OPLINE const zend_op *opline = EX(opline);\n"); - out($f,"# define LOAD_OPLINE()\n"); - out($f,"# define LOAD_OPLINE_EX()\n"); - out($f,"# define LOAD_NEXT_OPLINE() ZEND_VM_INC_OPCODE()\n"); - out($f,"# define SAVE_OPLINE()\n"); - out($f,"# define SAVE_OPLINE_EX()\n"); - out($f,"#endif\n"); - out($f,"#undef HANDLE_EXCEPTION\n"); - out($f,"#undef HANDLE_EXCEPTION_LEAVE\n"); - out($f,"#define HANDLE_EXCEPTION() LOAD_OPLINE(); ZEND_VM_CONTINUE()\n"); - out($f,"#define HANDLE_EXCEPTION_LEAVE() LOAD_OPLINE(); ZEND_VM_LEAVE()\n"); - out($f,"#if defined(ZEND_VM_FP_GLOBAL_REG)\n"); - out($f,"# define ZEND_VM_ENTER_EX() ZEND_VM_INTERRUPT_CHECK(); ZEND_VM_CONTINUE()\n"); - out($f,"# define ZEND_VM_ENTER() execute_data = EG(current_execute_data); LOAD_OPLINE(); ZEND_VM_ENTER_EX()\n"); - out($f,"# define ZEND_VM_LEAVE() ZEND_VM_CONTINUE()\n"); - out($f,"#elif defined(ZEND_VM_IP_GLOBAL_REG)\n"); - out($f,"# define ZEND_VM_ENTER_EX() return 1\n"); - out($f,"# define ZEND_VM_ENTER() opline = EG(current_execute_data)->opline; ZEND_VM_ENTER_EX()\n"); - out($f,"# define ZEND_VM_LEAVE() return 2\n"); - out($f,"#else\n"); - out($f,"# define ZEND_VM_ENTER_EX() return 1\n"); - out($f,"# define ZEND_VM_ENTER() return 1\n"); - out($f,"# define ZEND_VM_LEAVE() return 2\n"); - out($f,"#endif\n"); - out($f,"#define ZEND_VM_INTERRUPT() ZEND_VM_TAIL_CALL(zend_interrupt_helper".($spec?"_SPEC":"")."(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU));\n"); - out($f,"#define ZEND_VM_LOOP_INTERRUPT() zend_interrupt_helper".($spec?"_SPEC":"")."(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);\n"); - if ($kind == ZEND_VM_KIND_HYBRID) { - out($f,"#define ZEND_VM_DISPATCH(opcode, opline) ZEND_VM_TAIL_CALL(((opcode_handler_t)zend_vm_get_opcode_handler_func(opcode, opline))(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU));\n"); - } else { - out($f,"#define ZEND_VM_DISPATCH(opcode, opline) ZEND_VM_TAIL_CALL(((opcode_handler_t)zend_vm_get_opcode_handler(opcode, opline))(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU));\n"); - } - out($f,"\n"); - out($f,"static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_interrupt_helper".($spec?"_SPEC":"")."(ZEND_OPCODE_HANDLER_ARGS);\n"); - out($f,"static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_NULL_HANDLER(ZEND_OPCODE_HANDLER_ARGS);\n"); - out($f,"\n"); - break; - case ZEND_VM_KIND_SWITCH: - out($f,"\n"); - out($f,"#undef OPLINE\n"); - out($f,"#undef DCL_OPLINE\n"); - out($f,"#undef USE_OPLINE\n"); - out($f,"#undef LOAD_OPLINE\n"); - out($f,"#undef LOAD_OPLINE_EX\n"); - out($f,"#undef LOAD_NEXT_OPLINE\n"); - out($f,"#undef SAVE_OPLINE\n"); - out($f,"#undef SAVE_OPLINE_EX\n"); - out($f,"#define OPLINE opline\n"); - out($f,"#ifdef ZEND_VM_IP_GLOBAL_REG\n"); - out($f,"# define DCL_OPLINE register const zend_op *opline __asm__(ZEND_VM_IP_GLOBAL_REG);\n"); - out($f,"#else\n"); - out($f,"# define DCL_OPLINE const zend_op *opline;\n"); - out($f,"#endif\n"); - out($f,"#define USE_OPLINE\n"); - out($f,"#define LOAD_OPLINE() opline = EX(opline)\n"); - out($f,"# define LOAD_OPLINE_EX() LOAD_OPLINE()\n"); - out($f,"#define LOAD_NEXT_OPLINE() opline = EX(opline) + 1\n"); - out($f,"#define SAVE_OPLINE() EX(opline) = opline\n"); - out($f,"#define SAVE_OPLINE_EX()\n"); - out($f,"#undef HANDLE_EXCEPTION\n"); - out($f,"#undef HANDLE_EXCEPTION_LEAVE\n"); - out($f,"#define HANDLE_EXCEPTION() LOAD_OPLINE(); ZEND_VM_CONTINUE()\n"); - out($f,"#define HANDLE_EXCEPTION_LEAVE() LOAD_OPLINE(); ZEND_VM_LEAVE()\n"); - out($f,"#define ZEND_VM_CONTINUE() goto zend_vm_continue\n"); - out($f,"#define ZEND_VM_RETURN() return\n"); - out($f,"#define ZEND_VM_ENTER_EX() ZEND_VM_INTERRUPT_CHECK(); ZEND_VM_CONTINUE()\n"); - out($f,"#define ZEND_VM_ENTER() execute_data = EG(current_execute_data); LOAD_OPLINE(); ZEND_VM_ENTER_EX()\n"); - out($f,"#define ZEND_VM_LEAVE() ZEND_VM_CONTINUE()\n"); - out($f,"#define ZEND_VM_INTERRUPT() goto zend_interrupt_helper".($spec?"_SPEC":"").";\n"); - out($f,"#define ZEND_VM_LOOP_INTERRUPT() goto zend_interrupt_helper".($spec?"_SPEC":"").";\n"); - out($f,"#define ZEND_VM_DISPATCH(opcode, opline) dispatch_handler = zend_vm_get_opcode_handler(opcode, opline); goto zend_vm_dispatch;\n"); - out($f,"\n"); - break; - case ZEND_VM_KIND_GOTO: - out($f,"\n"); - out($f,"#undef OPLINE\n"); - out($f,"#undef DCL_OPLINE\n"); - out($f,"#undef USE_OPLINE\n"); - out($f,"#undef LOAD_OPLINE\n"); - out($f,"#undef LOAD_OPLINE_EX\n"); - out($f,"#undef LOAD_NEXT_OPLINE\n"); - out($f,"#undef SAVE_OPLINE\n"); - out($f,"#undef SAVE_OPLINE_EX\n"); - out($f,"#define OPLINE opline\n"); - out($f,"#ifdef ZEND_VM_IP_GLOBAL_REG\n"); - out($f,"# define DCL_OPLINE register const zend_op *opline __asm__(ZEND_VM_IP_GLOBAL_REG);\n"); - out($f,"#else\n"); - out($f,"# define DCL_OPLINE const zend_op *opline;\n"); - out($f,"#endif\n"); - out($f,"#define USE_OPLINE\n"); - out($f,"#define LOAD_OPLINE() opline = EX(opline)\n"); - out($f,"#define LOAD_OPLINE_EX() LOAD_OPLINE()\n"); - out($f,"#define LOAD_NEXT_OPLINE() opline = EX(opline) + 1\n"); - out($f,"#define SAVE_OPLINE() EX(opline) = opline\n"); - out($f,"#define SAVE_OPLINE_EX()\n"); - out($f,"#undef HANDLE_EXCEPTION\n"); - out($f,"#undef HANDLE_EXCEPTION_LEAVE\n"); - if (ZEND_VM_SPEC) { - out($f,"#define HANDLE_EXCEPTION() goto ZEND_HANDLE_EXCEPTION_SPEC_LABEL\n"); - out($f,"#define HANDLE_EXCEPTION_LEAVE() goto ZEND_HANDLE_EXCEPTION_SPEC_LABEL\n"); - } else { - out($f,"#define HANDLE_EXCEPTION() goto ZEND_HANDLE_EXCEPTION_LABEL\n"); - out($f,"#define HANDLE_EXCEPTION_LEAVE() goto ZEND_HANDLE_EXCEPTION_LABEL\n"); - } - out($f,"#define ZEND_VM_CONTINUE() goto *(void**)(OPLINE->handler)\n"); - out($f,"#define ZEND_VM_RETURN() return\n"); - out($f,"#define ZEND_VM_ENTER_EX() ZEND_VM_INTERRUPT_CHECK(); ZEND_VM_CONTINUE()\n"); - out($f,"#define ZEND_VM_ENTER() execute_data = EG(current_execute_data); LOAD_OPLINE(); ZEND_VM_ENTER_EX()\n"); - out($f,"#define ZEND_VM_LEAVE() ZEND_VM_CONTINUE()\n"); - out($f,"#define ZEND_VM_INTERRUPT() goto zend_interrupt_helper".($spec?"_SPEC":"").";\n"); - out($f,"#define ZEND_VM_LOOP_INTERRUPT() goto zend_interrupt_helper".($spec?"_SPEC":"").";\n"); - out($f,"#define ZEND_VM_DISPATCH(opcode, opline) goto *(void**)(zend_vm_get_opcode_handler(opcode, opline));\n"); - out($f,"\n"); - break; - } - if ($kind == ZEND_VM_KIND_HYBRID) { - gen_executor_code($f, $spec, ZEND_VM_KIND_CALL, $m[1]); - out($f,"\n"); - out($f,"#if (ZEND_VM_KIND == ZEND_VM_KIND_HYBRID)\n"); - out($f,"# undef ZEND_VM_TAIL_CALL\n"); - out($f,"# undef ZEND_VM_CONTINUE\n"); - out($f,"# undef ZEND_VM_RETURN\n"); + global $params, $skeleton_file, $line_no; + + $switch_labels = array(); + $lineno = 0; + foreach ($skl as $line) { + // Skeleton file contains special markers in form %NAME% those are + // substituted by custom code + if (preg_match("/(.*)[{][%]([A-Z_]*)[%][}](.*)/", $line, $m)) { + switch ($m[2]) { + case "DEFINES": + out($f,"#define SPEC_START_MASK 0x0000ffff\n"); + out($f,"#define SPEC_EXTRA_MASK 0xfffc0000\n"); + out($f,"#define SPEC_RULE_OP1 0x00010000\n"); + out($f,"#define SPEC_RULE_OP2 0x00020000\n"); + out($f,"#define SPEC_RULE_OP_DATA 0x00040000\n"); + out($f,"#define SPEC_RULE_RETVAL 0x00080000\n"); + out($f,"#define SPEC_RULE_QUICK_ARG 0x00100000\n"); + out($f,"#define SPEC_RULE_SMART_BRANCH 0x00200000\n"); + out($f,"#define SPEC_RULE_COMMUTATIVE 0x00800000\n"); + out($f,"#define SPEC_RULE_ISSET 0x01000000\n"); + out($f,"\n"); + out($f,"static const uint32_t *zend_spec_handlers;\n"); + out($f,"static const void * const *zend_opcode_handlers;\n"); + out($f,"static int zend_handlers_count;\n"); + if ($kind == ZEND_VM_KIND_HYBRID) { + out($f,"#if (ZEND_VM_KIND == ZEND_VM_KIND_HYBRID)\n"); + out($f,"static const void * const * zend_opcode_handler_funcs;\n"); + out($f,"static zend_op hybrid_halt_op;\n"); + out($f,"#endif\n"); + } + out($f,"#if (ZEND_VM_KIND != ZEND_VM_KIND_HYBRID) || !ZEND_VM_SPEC\n"); + out($f,"static const void *zend_vm_get_opcode_handler(zend_uchar opcode, const zend_op* op);\n"); + out($f,"#endif\n\n"); + if ($kind == ZEND_VM_KIND_HYBRID) { + out($f,"#if (ZEND_VM_KIND == ZEND_VM_KIND_HYBRID)\n"); + out($f,"static const void *zend_vm_get_opcode_handler_func(zend_uchar opcode, const zend_op* op);\n"); + out($f,"#else\n"); + out($f,"# define zend_vm_get_opcode_handler_func zend_vm_get_opcode_handler\n"); + out($f,"#endif\n\n"); + } + out($f,"#ifndef VM_TRACE\n"); + out($f,"# define VM_TRACE(op)\n"); + out($f,"#endif\n"); + out($f,"#ifndef VM_TRACE_START\n"); + out($f,"# define VM_TRACE_START()\n"); + out($f,"#endif\n"); + out($f,"#ifndef VM_TRACE_END\n"); + out($f,"# define VM_TRACE_END()\n"); + out($f,"#endif\n"); + switch ($kind) { + case ZEND_VM_KIND_HYBRID: + out($f,"#if (ZEND_VM_KIND == ZEND_VM_KIND_HYBRID)\n"); + out($f,"#define HYBRID_NEXT() goto *(void**)(OPLINE->handler)\n"); + out($f,"#define HYBRID_SWITCH() HYBRID_NEXT();\n"); + out($f,"#define HYBRID_CASE(op) op ## _LABEL\n"); + out($f,"#define HYBRID_BREAK() HYBRID_NEXT()\n"); + out($f,"#define HYBRID_DEFAULT ZEND_NULL_LABEL\n"); + out($f,"#endif\n"); + case ZEND_VM_KIND_CALL: + out($f,"\n"); + out($f,"#ifdef ZEND_VM_FP_GLOBAL_REG\n"); + out($f,"# define ZEND_OPCODE_HANDLER_ARGS void\n"); + out($f,"# define ZEND_OPCODE_HANDLER_ARGS_PASSTHRU\n"); + out($f,"# define ZEND_OPCODE_HANDLER_ARGS_DC\n"); + out($f,"# define ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC\n"); + out($f,"#else\n"); + out($f,"# define ZEND_OPCODE_HANDLER_ARGS zend_execute_data *execute_data\n"); + out($f,"# define ZEND_OPCODE_HANDLER_ARGS_PASSTHRU execute_data\n"); + out($f,"# define ZEND_OPCODE_HANDLER_ARGS_DC , ZEND_OPCODE_HANDLER_ARGS\n"); + out($f,"# define ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC , ZEND_OPCODE_HANDLER_ARGS_PASSTHRU\n"); + out($f,"#endif\n"); + out($f,"\n"); + out($f,"#if defined(ZEND_VM_FP_GLOBAL_REG) && defined(ZEND_VM_IP_GLOBAL_REG)\n"); + out($f,"# define ZEND_OPCODE_HANDLER_RET void\n"); + out($f,"# define ZEND_VM_TAIL_CALL(call) call; return\n"); + out($f,"# ifdef ZEND_VM_TAIL_CALL_DISPATCH\n"); + out($f,"# define ZEND_VM_CONTINUE() ((opcode_handler_t)OPLINE->handler)(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); return\n"); + out($f,"# else\n"); + out($f,"# define ZEND_VM_CONTINUE() return\n"); + out($f,"# endif\n"); + if ($kind == ZEND_VM_KIND_HYBRID) { + out($f,"# if (ZEND_VM_KIND == ZEND_VM_KIND_HYBRID)\n"); + out($f,"# define ZEND_VM_RETURN() opline = &hybrid_halt_op; return\n"); + out($f,"# define ZEND_VM_HOT zend_always_inline ZEND_COLD ZEND_OPT_SIZE\n"); + out($f,"# define ZEND_VM_COLD ZEND_COLD ZEND_OPT_SIZE\n"); + out($f,"# else\n"); + out($f,"# define ZEND_VM_RETURN() opline = NULL; return\n"); + out($f,"# define ZEND_VM_HOT\n"); + out($f,"# define ZEND_VM_COLD ZEND_COLD ZEND_OPT_SIZE\n"); + out($f,"# endif\n"); + } else { + out($f,"# define ZEND_VM_RETURN() opline = NULL; return\n"); + out($f,"# define ZEND_VM_COLD ZEND_COLD ZEND_OPT_SIZE\n"); + } + out($f,"#else\n"); + out($f,"# define ZEND_OPCODE_HANDLER_RET int\n"); + out($f,"# define ZEND_VM_TAIL_CALL(call) return call\n"); + out($f,"# define ZEND_VM_CONTINUE() return 0\n"); + out($f,"# define ZEND_VM_RETURN() return -1\n"); + if ($kind == ZEND_VM_KIND_HYBRID) { + out($f,"# define ZEND_VM_HOT\n"); + } + out($f,"# define ZEND_VM_COLD ZEND_COLD ZEND_OPT_SIZE\n"); + out($f,"#endif\n"); + out($f,"\n"); + out($f,"typedef ZEND_OPCODE_HANDLER_RET (ZEND_FASTCALL *opcode_handler_t) (ZEND_OPCODE_HANDLER_ARGS);\n"); + out($f,"\n"); + out($f,"#undef OPLINE\n"); + out($f,"#undef DCL_OPLINE\n"); + out($f,"#undef USE_OPLINE\n"); + out($f,"#undef LOAD_OPLINE\n"); + out($f,"#undef LOAD_OPLINE_EX\n"); + out($f,"#undef SAVE_OPLINE\n"); + out($f,"#undef SAVE_OPLINE_EX\n"); + out($f,"#define DCL_OPLINE\n"); + out($f,"#ifdef ZEND_VM_IP_GLOBAL_REG\n"); + out($f,"# define OPLINE opline\n"); + out($f,"# define USE_OPLINE\n"); + out($f,"# define LOAD_OPLINE() opline = EX(opline)\n"); + out($f,"# define LOAD_OPLINE_EX()\n"); + out($f,"# define LOAD_NEXT_OPLINE() opline = EX(opline) + 1\n"); + out($f,"# define SAVE_OPLINE() EX(opline) = opline\n"); + out($f,"# define SAVE_OPLINE_EX() SAVE_OPLINE()\n"); + out($f,"#else\n"); + out($f,"# define OPLINE EX(opline)\n"); + out($f,"# define USE_OPLINE const zend_op *opline = EX(opline);\n"); + out($f,"# define LOAD_OPLINE()\n"); + out($f,"# define LOAD_OPLINE_EX()\n"); + out($f,"# define LOAD_NEXT_OPLINE() ZEND_VM_INC_OPCODE()\n"); + out($f,"# define SAVE_OPLINE()\n"); + out($f,"# define SAVE_OPLINE_EX()\n"); + out($f,"#endif\n"); + out($f,"#undef HANDLE_EXCEPTION\n"); + out($f,"#undef HANDLE_EXCEPTION_LEAVE\n"); + out($f,"#define HANDLE_EXCEPTION() LOAD_OPLINE(); ZEND_VM_CONTINUE()\n"); + out($f,"#define HANDLE_EXCEPTION_LEAVE() LOAD_OPLINE(); ZEND_VM_LEAVE()\n"); + out($f,"#if defined(ZEND_VM_FP_GLOBAL_REG)\n"); + out($f,"# define ZEND_VM_ENTER_EX() ZEND_VM_INTERRUPT_CHECK(); ZEND_VM_CONTINUE()\n"); + out($f,"# define ZEND_VM_ENTER() execute_data = EG(current_execute_data); LOAD_OPLINE(); ZEND_VM_ENTER_EX()\n"); + out($f,"# define ZEND_VM_LEAVE() ZEND_VM_CONTINUE()\n"); + out($f,"#elif defined(ZEND_VM_IP_GLOBAL_REG)\n"); + out($f,"# define ZEND_VM_ENTER_EX() return 1\n"); + out($f,"# define ZEND_VM_ENTER() opline = EG(current_execute_data)->opline; ZEND_VM_ENTER_EX()\n"); + out($f,"# define ZEND_VM_LEAVE() return 2\n"); + out($f,"#else\n"); + out($f,"# define ZEND_VM_ENTER_EX() return 1\n"); + out($f,"# define ZEND_VM_ENTER() return 1\n"); + out($f,"# define ZEND_VM_LEAVE() return 2\n"); + out($f,"#endif\n"); + out($f,"#define ZEND_VM_INTERRUPT() ZEND_VM_TAIL_CALL(zend_interrupt_helper".($spec?"_SPEC":"")."(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU));\n"); + out($f,"#define ZEND_VM_LOOP_INTERRUPT() zend_interrupt_helper".($spec?"_SPEC":"")."(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);\n"); + if ($kind == ZEND_VM_KIND_HYBRID) { + out($f,"#define ZEND_VM_DISPATCH(opcode, opline) ZEND_VM_TAIL_CALL(((opcode_handler_t)zend_vm_get_opcode_handler_func(opcode, opline))(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU));\n"); + } else { + out($f,"#define ZEND_VM_DISPATCH(opcode, opline) ZEND_VM_TAIL_CALL(((opcode_handler_t)zend_vm_get_opcode_handler(opcode, opline))(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU));\n"); + } + out($f,"\n"); + out($f,"static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_interrupt_helper".($spec?"_SPEC":"")."(ZEND_OPCODE_HANDLER_ARGS);\n"); + out($f,"static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_NULL_HANDLER(ZEND_OPCODE_HANDLER_ARGS);\n"); + out($f,"\n"); + break; + case ZEND_VM_KIND_SWITCH: + out($f,"\n"); + out($f,"#undef OPLINE\n"); + out($f,"#undef DCL_OPLINE\n"); + out($f,"#undef USE_OPLINE\n"); + out($f,"#undef LOAD_OPLINE\n"); + out($f,"#undef LOAD_OPLINE_EX\n"); + out($f,"#undef LOAD_NEXT_OPLINE\n"); + out($f,"#undef SAVE_OPLINE\n"); + out($f,"#undef SAVE_OPLINE_EX\n"); + out($f,"#define OPLINE opline\n"); + out($f,"#ifdef ZEND_VM_IP_GLOBAL_REG\n"); + out($f,"# define DCL_OPLINE register const zend_op *opline __asm__(ZEND_VM_IP_GLOBAL_REG);\n"); + out($f,"#else\n"); + out($f,"# define DCL_OPLINE const zend_op *opline;\n"); + out($f,"#endif\n"); + out($f,"#define USE_OPLINE\n"); + out($f,"#define LOAD_OPLINE() opline = EX(opline)\n"); + out($f,"# define LOAD_OPLINE_EX() LOAD_OPLINE()\n"); + out($f,"#define LOAD_NEXT_OPLINE() opline = EX(opline) + 1\n"); + out($f,"#define SAVE_OPLINE() EX(opline) = opline\n"); + out($f,"#define SAVE_OPLINE_EX()\n"); + out($f,"#undef HANDLE_EXCEPTION\n"); + out($f,"#undef HANDLE_EXCEPTION_LEAVE\n"); + out($f,"#define HANDLE_EXCEPTION() LOAD_OPLINE(); ZEND_VM_CONTINUE()\n"); + out($f,"#define HANDLE_EXCEPTION_LEAVE() LOAD_OPLINE(); ZEND_VM_LEAVE()\n"); + out($f,"#define ZEND_VM_CONTINUE() goto zend_vm_continue\n"); + out($f,"#define ZEND_VM_RETURN() return\n"); + out($f,"#define ZEND_VM_ENTER_EX() ZEND_VM_INTERRUPT_CHECK(); ZEND_VM_CONTINUE()\n"); + out($f,"#define ZEND_VM_ENTER() execute_data = EG(current_execute_data); LOAD_OPLINE(); ZEND_VM_ENTER_EX()\n"); + out($f,"#define ZEND_VM_LEAVE() ZEND_VM_CONTINUE()\n"); + out($f,"#define ZEND_VM_INTERRUPT() goto zend_interrupt_helper".($spec?"_SPEC":"").";\n"); + out($f,"#define ZEND_VM_LOOP_INTERRUPT() goto zend_interrupt_helper".($spec?"_SPEC":"").";\n"); + out($f,"#define ZEND_VM_DISPATCH(opcode, opline) dispatch_handler = zend_vm_get_opcode_handler(opcode, opline); goto zend_vm_dispatch;\n"); + out($f,"\n"); + break; + case ZEND_VM_KIND_GOTO: + out($f,"\n"); + out($f,"#undef OPLINE\n"); + out($f,"#undef DCL_OPLINE\n"); + out($f,"#undef USE_OPLINE\n"); + out($f,"#undef LOAD_OPLINE\n"); + out($f,"#undef LOAD_OPLINE_EX\n"); + out($f,"#undef LOAD_NEXT_OPLINE\n"); + out($f,"#undef SAVE_OPLINE\n"); + out($f,"#undef SAVE_OPLINE_EX\n"); + out($f,"#define OPLINE opline\n"); + out($f,"#ifdef ZEND_VM_IP_GLOBAL_REG\n"); + out($f,"# define DCL_OPLINE register const zend_op *opline __asm__(ZEND_VM_IP_GLOBAL_REG);\n"); + out($f,"#else\n"); + out($f,"# define DCL_OPLINE const zend_op *opline;\n"); + out($f,"#endif\n"); + out($f,"#define USE_OPLINE\n"); + out($f,"#define LOAD_OPLINE() opline = EX(opline)\n"); + out($f,"#define LOAD_OPLINE_EX() LOAD_OPLINE()\n"); + out($f,"#define LOAD_NEXT_OPLINE() opline = EX(opline) + 1\n"); + out($f,"#define SAVE_OPLINE() EX(opline) = opline\n"); + out($f,"#define SAVE_OPLINE_EX()\n"); + out($f,"#undef HANDLE_EXCEPTION\n"); + out($f,"#undef HANDLE_EXCEPTION_LEAVE\n"); + if (ZEND_VM_SPEC) { + out($f,"#define HANDLE_EXCEPTION() goto ZEND_HANDLE_EXCEPTION_SPEC_LABEL\n"); + out($f,"#define HANDLE_EXCEPTION_LEAVE() goto ZEND_HANDLE_EXCEPTION_SPEC_LABEL\n"); + } else { + out($f,"#define HANDLE_EXCEPTION() goto ZEND_HANDLE_EXCEPTION_LABEL\n"); + out($f,"#define HANDLE_EXCEPTION_LEAVE() goto ZEND_HANDLE_EXCEPTION_LABEL\n"); + } + out($f,"#define ZEND_VM_CONTINUE() goto *(void**)(OPLINE->handler)\n"); + out($f,"#define ZEND_VM_RETURN() return\n"); + out($f,"#define ZEND_VM_ENTER_EX() ZEND_VM_INTERRUPT_CHECK(); ZEND_VM_CONTINUE()\n"); + out($f,"#define ZEND_VM_ENTER() execute_data = EG(current_execute_data); LOAD_OPLINE(); ZEND_VM_ENTER_EX()\n"); + out($f,"#define ZEND_VM_LEAVE() ZEND_VM_CONTINUE()\n"); + out($f,"#define ZEND_VM_INTERRUPT() goto zend_interrupt_helper".($spec?"_SPEC":"").";\n"); + out($f,"#define ZEND_VM_LOOP_INTERRUPT() goto zend_interrupt_helper".($spec?"_SPEC":"").";\n"); + out($f,"#define ZEND_VM_DISPATCH(opcode, opline) goto *(void**)(zend_vm_get_opcode_handler(opcode, opline));\n"); + out($f,"\n"); + break; + } + if ($kind == ZEND_VM_KIND_HYBRID) { + gen_executor_code($f, $spec, ZEND_VM_KIND_CALL, $m[1]); + out($f,"\n"); + out($f,"#if (ZEND_VM_KIND == ZEND_VM_KIND_HYBRID)\n"); + out($f,"# undef ZEND_VM_TAIL_CALL\n"); + out($f,"# undef ZEND_VM_CONTINUE\n"); + out($f,"# undef ZEND_VM_RETURN\n"); // out($f,"# undef ZEND_VM_INTERRUPT\n"); - out($f,"\n"); - out($f,"# define ZEND_VM_TAIL_CALL(call) call; ZEND_VM_CONTINUE()\n"); - out($f,"# define ZEND_VM_CONTINUE() HYBRID_NEXT()\n"); - out($f,"# define ZEND_VM_RETURN() goto HYBRID_HALT_LABEL\n"); + out($f,"\n"); + out($f,"# define ZEND_VM_TAIL_CALL(call) call; ZEND_VM_CONTINUE()\n"); + out($f,"# define ZEND_VM_CONTINUE() HYBRID_NEXT()\n"); + out($f,"# define ZEND_VM_RETURN() goto HYBRID_HALT_LABEL\n"); // out($f,"# define ZEND_VM_INTERRUPT() goto zend_interrupt_helper_SPEC_LABEL\n"); - out($f,"#endif\n\n"); - } - break; - case "EXECUTOR_NAME": - out($f, $m[1].$executor_name.$m[3]."\n"); - break; - case "HELPER_VARS": - if ($kind == ZEND_VM_KIND_SWITCH) { - out($f,$m[1]."const void *dispatch_handler;\n"); - } - if ($kind != ZEND_VM_KIND_CALL && count($params)) { - if ($kind == ZEND_VM_KIND_HYBRID) { - out($f, "#if (ZEND_VM_KIND == ZEND_VM_KIND_HYBRID)\n"); - } - // Emit local variables those are used for helpers' parameters - foreach ($params as $param => $x) { - out($f,$m[1].$param.";\n"); - } - if ($kind == ZEND_VM_KIND_HYBRID) { - out($f, "#endif\n"); - } - } - if ($kind != ZEND_VM_KIND_CALL && $kind != ZEND_VM_KIND_HYBRID) { - out($f,"#ifdef ZEND_VM_FP_GLOBAL_REG\n"); - out($f,$m[1]."register zend_execute_data *execute_data __asm__(ZEND_VM_FP_GLOBAL_REG) = ex;\n"); - out($f,"#else\n"); - out($f,$m[1]."zend_execute_data *execute_data = ex;\n"); - out($f,"#endif\n"); - } else { - out($f,"#ifdef ZEND_VM_IP_GLOBAL_REG\n"); - out($f,$m[1]."const zend_op *orig_opline = opline;\n"); - out($f,"#endif\n"); - out($f,"#ifdef ZEND_VM_FP_GLOBAL_REG\n"); - out($f,$m[1]."zend_execute_data *orig_execute_data = execute_data;\n"); - out($f,$m[1]."execute_data = ex;\n"); - out($f,"#else\n"); - out($f,$m[1]."zend_execute_data *execute_data = ex;\n"); - out($f,"#endif\n"); - } - break; - case "INTERNAL_LABELS": - if ($kind == ZEND_VM_KIND_GOTO || $kind == ZEND_VM_KIND_HYBRID) { - // Emit array of labels of opcode handlers and code for - // zend_opcode_handlers initialization - if ($kind == ZEND_VM_KIND_HYBRID) { - out($f,"#if (ZEND_VM_KIND == ZEND_VM_KIND_HYBRID)\n"); - } - $prolog = $m[1]; - out($f,$prolog."if (UNEXPECTED(execute_data == NULL)) {\n"); - out($f,$prolog."\tstatic const void * const labels[] = {\n"); - gen_labels($f, $spec, ($kind == ZEND_VM_KIND_HYBRID) ? ZEND_VM_KIND_GOTO : $kind, $prolog."\t\t", $specs); - out($f,$prolog."\t};\n"); - out($f,$prolog."\tzend_opcode_handlers = (const void **) labels;\n"); - out($f,$prolog."\tzend_handlers_count = sizeof(labels) / sizeof(void*);\n"); - if ($kind == ZEND_VM_KIND_HYBRID) { - out($f,$prolog."\tmemset(&hybrid_halt_op, 0, sizeof(hybrid_halt_op));\n"); - out($f,$prolog."\thybrid_halt_op.handler = (void*)&&HYBRID_HALT_LABEL;\n"); - out($f,$prolog."\tgoto HYBRID_HALT_LABEL;\n"); - } else { - out($f,$prolog."\treturn;\n"); - } - out($f,$prolog."}\n"); - if ($kind == ZEND_VM_KIND_HYBRID) { - out($f,"#endif\n"); - } - } else { - skip_blanks($f, $m[1], $m[3]); - } - break; - case "ZEND_VM_CONTINUE_LABEL": - if ($kind == ZEND_VM_KIND_CALL || $kind == ZEND_VM_KIND_HYBRID) { - // Only SWITCH dispatch method use it - out($f,"#if !defined(ZEND_VM_FP_GLOBAL_REG) || !defined(ZEND_VM_IP_GLOBAL_REG)\n"); - out($f,$m[1]."\tint ret;".$m[3]."\n"); - out($f,"#endif\n"); - } else if ($kind == ZEND_VM_KIND_SWITCH) { - // Only SWITCH dispatch method use it - out($f,"zend_vm_continue:".$m[3]."\n"); - } else { - skip_blanks($f, $m[1], $m[3]); - } - break; - case "ZEND_VM_DISPATCH": - // Emit code that dispatches to opcode handler - switch ($kind) { - case ZEND_VM_KIND_SWITCH: - out($f, $m[1]."dispatch_handler = OPLINE->handler;\nzend_vm_dispatch:\n".$m[1]."switch ((int)(uintptr_t)dispatch_handler)".$m[3]."\n"); - break; - case ZEND_VM_KIND_GOTO: - out($f, $m[1]."goto *(void**)(OPLINE->handler);".$m[3]."\n"); - break; - case ZEND_VM_KIND_HYBRID: - out($f,"#if (ZEND_VM_KIND == ZEND_VM_KIND_HYBRID)\n"); - out($f, $m[1]."HYBRID_SWITCH()".$m[3]."\n"); - out($f,"#else\n"); - case ZEND_VM_KIND_CALL: - out($f,"#if defined(ZEND_VM_FP_GLOBAL_REG) && defined(ZEND_VM_IP_GLOBAL_REG)\n"); - out($f, $m[1]."((opcode_handler_t)OPLINE->handler)(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);\n"); - out($f, $m[1]."if (UNEXPECTED(!OPLINE))".$m[3]."\n"); - out($f,"#else\n"); - out($f, $m[1]."if (UNEXPECTED((ret = ((opcode_handler_t)OPLINE->handler)(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU)) != 0))".$m[3]."\n"); - out($f,"#endif\n"); - if ($kind == ZEND_VM_KIND_HYBRID) { - out($f,"#endif\n"); - } - break; - } - break; - case "INTERNAL_EXECUTOR": - if ($kind != ZEND_VM_KIND_CALL) { - // Emit executor code - if ($kind == ZEND_VM_KIND_HYBRID) { - out($f,"#if (ZEND_VM_KIND == ZEND_VM_KIND_HYBRID)\n"); - } - gen_executor_code($f, $spec, $kind, $m[1], $switch_labels); - } - if ($kind == ZEND_VM_KIND_CALL || $kind == ZEND_VM_KIND_HYBRID) { - // Executor is defined as a set of functions - if ($kind == ZEND_VM_KIND_HYBRID) { - out($f,"#else\n"); - } - out($f, - "#ifdef ZEND_VM_FP_GLOBAL_REG\n" . - $m[1]."execute_data = orig_execute_data;\n" . - "# ifdef ZEND_VM_IP_GLOBAL_REG\n" . - $m[1]."opline = orig_opline;\n" . - "# endif\n" . - $m[1]."return;\n" . - "#else\n" . - $m[1]."if (EXPECTED(ret > 0)) {\n" . - $m[1]."\texecute_data = EG(current_execute_data);\n". - $m[1]."\tZEND_VM_LOOP_INTERRUPT_CHECK();\n". - $m[1]."} else {\n" . - "# ifdef ZEND_VM_IP_GLOBAL_REG\n" . - $m[1]."\topline = orig_opline;\n" . - "# endif\n". - $m[1]."\treturn;\n". - $m[1]."}\n". - "#endif\n"); - if ($kind == ZEND_VM_KIND_HYBRID) { - out($f,"#endif\n"); - } - } - break; - case "EXTERNAL_EXECUTOR": - if ($kind == ZEND_VM_KIND_CALL) { - gen_executor_code($f, $spec, $kind, $m[1]); - } - break; - case "INITIALIZER_NAME": - out($f, $m[1].$initializer_name.$m[3]."\n"); - break; - case "EXTERNAL_LABELS": - // Emit code that initializes zend_opcode_handlers array - $prolog = $m[1]; - if ($kind == ZEND_VM_KIND_GOTO) { - // Labels are defined in the executor itself, so we call it - // with execute_data NULL and it sets zend_opcode_handlers array - out($f,$prolog."static const uint32_t specs[] = {\n"); - gen_specs($f, $prolog."\t", $specs); - out($f,$prolog."};\n"); - out($f,$prolog."zend_spec_handlers = specs;\n"); - out($f,$prolog.$executor_name."_ex(NULL);\n"); - } else { - out($f,$prolog."static const void * const labels[] = {\n"); - gen_labels($f, $spec, ($kind == ZEND_VM_KIND_HYBRID) ? ZEND_VM_KIND_CALL : $kind, $prolog."\t", $specs, $switch_labels); - out($f,$prolog."};\n"); - out($f,$prolog."static const uint32_t specs[] = {\n"); - gen_specs($f, $prolog."\t", $specs); - out($f,$prolog."};\n"); - if ($kind == ZEND_VM_KIND_HYBRID) { - out($f,"#if (ZEND_VM_KIND == ZEND_VM_KIND_HYBRID)\n"); - out($f,$prolog."zend_opcode_handler_funcs = labels;\n"); - out($f,$prolog."zend_spec_handlers = specs;\n"); - out($f,$prolog.$executor_name."_ex(NULL);\n"); - out($f,"#else\n"); - } - out($f,$prolog."zend_opcode_handlers = labels;\n"); - out($f,$prolog."zend_handlers_count = sizeof(labels) / sizeof(void*);\n"); - out($f,$prolog."zend_spec_handlers = specs;\n"); - if ($kind == ZEND_VM_KIND_HYBRID) { - out($f,"#endif\n"); - } - } - break; - default: - die("ERROR: Unknown keyword ".$m[2]." in skeleton file.\n"); - } - } else { - // Copy the line as is - out($f, $line); - } - } + out($f,"#endif\n\n"); + } + break; + case "EXECUTOR_NAME": + out($f, $m[1].$executor_name.$m[3]."\n"); + break; + case "HELPER_VARS": + if ($kind == ZEND_VM_KIND_SWITCH) { + out($f,$m[1]."const void *dispatch_handler;\n"); + } + if ($kind != ZEND_VM_KIND_CALL && count($params)) { + if ($kind == ZEND_VM_KIND_HYBRID) { + out($f, "#if (ZEND_VM_KIND == ZEND_VM_KIND_HYBRID)\n"); + } + // Emit local variables those are used for helpers' parameters + foreach ($params as $param => $x) { + out($f,$m[1].$param.";\n"); + } + if ($kind == ZEND_VM_KIND_HYBRID) { + out($f, "#endif\n"); + } + } + if ($kind != ZEND_VM_KIND_CALL && $kind != ZEND_VM_KIND_HYBRID) { + out($f,"#ifdef ZEND_VM_FP_GLOBAL_REG\n"); + out($f,$m[1]."register zend_execute_data *execute_data __asm__(ZEND_VM_FP_GLOBAL_REG) = ex;\n"); + out($f,"#else\n"); + out($f,$m[1]."zend_execute_data *execute_data = ex;\n"); + out($f,"#endif\n"); + } else { + out($f,"#ifdef ZEND_VM_IP_GLOBAL_REG\n"); + out($f,$m[1]."const zend_op *orig_opline = opline;\n"); + out($f,"#endif\n"); + out($f,"#ifdef ZEND_VM_FP_GLOBAL_REG\n"); + out($f,$m[1]."zend_execute_data *orig_execute_data = execute_data;\n"); + out($f,$m[1]."execute_data = ex;\n"); + out($f,"#else\n"); + out($f,$m[1]."zend_execute_data *execute_data = ex;\n"); + out($f,"#endif\n"); + } + break; + case "INTERNAL_LABELS": + if ($kind == ZEND_VM_KIND_GOTO || $kind == ZEND_VM_KIND_HYBRID) { + // Emit array of labels of opcode handlers and code for + // zend_opcode_handlers initialization + if ($kind == ZEND_VM_KIND_HYBRID) { + out($f,"#if (ZEND_VM_KIND == ZEND_VM_KIND_HYBRID)\n"); + } + $prolog = $m[1]; + out($f,$prolog."if (UNEXPECTED(execute_data == NULL)) {\n"); + out($f,$prolog."\tstatic const void * const labels[] = {\n"); + gen_labels($f, $spec, ($kind == ZEND_VM_KIND_HYBRID) ? ZEND_VM_KIND_GOTO : $kind, $prolog."\t\t", $specs); + out($f,$prolog."\t};\n"); + out($f,$prolog."\tzend_opcode_handlers = (const void **) labels;\n"); + out($f,$prolog."\tzend_handlers_count = sizeof(labels) / sizeof(void*);\n"); + if ($kind == ZEND_VM_KIND_HYBRID) { + out($f,$prolog."\tmemset(&hybrid_halt_op, 0, sizeof(hybrid_halt_op));\n"); + out($f,$prolog."\thybrid_halt_op.handler = (void*)&&HYBRID_HALT_LABEL;\n"); + out($f,$prolog."\tgoto HYBRID_HALT_LABEL;\n"); + } else { + out($f,$prolog."\treturn;\n"); + } + out($f,$prolog."}\n"); + if ($kind == ZEND_VM_KIND_HYBRID) { + out($f,"#endif\n"); + } + } else { + skip_blanks($f, $m[1], $m[3]); + } + break; + case "ZEND_VM_CONTINUE_LABEL": + if ($kind == ZEND_VM_KIND_CALL || $kind == ZEND_VM_KIND_HYBRID) { + // Only SWITCH dispatch method use it + out($f,"#if !defined(ZEND_VM_FP_GLOBAL_REG) || !defined(ZEND_VM_IP_GLOBAL_REG)\n"); + out($f,$m[1]."\tint ret;".$m[3]."\n"); + out($f,"#endif\n"); + } else if ($kind == ZEND_VM_KIND_SWITCH) { + // Only SWITCH dispatch method use it + out($f,"zend_vm_continue:".$m[3]."\n"); + } else { + skip_blanks($f, $m[1], $m[3]); + } + break; + case "ZEND_VM_DISPATCH": + // Emit code that dispatches to opcode handler + switch ($kind) { + case ZEND_VM_KIND_SWITCH: + out($f, $m[1]."dispatch_handler = OPLINE->handler;\nzend_vm_dispatch:\n".$m[1]."switch ((int)(uintptr_t)dispatch_handler)".$m[3]."\n"); + break; + case ZEND_VM_KIND_GOTO: + out($f, $m[1]."goto *(void**)(OPLINE->handler);".$m[3]."\n"); + break; + case ZEND_VM_KIND_HYBRID: + out($f,"#if (ZEND_VM_KIND == ZEND_VM_KIND_HYBRID)\n"); + out($f, $m[1]."HYBRID_SWITCH()".$m[3]."\n"); + out($f,"#else\n"); + case ZEND_VM_KIND_CALL: + out($f,"#if defined(ZEND_VM_FP_GLOBAL_REG) && defined(ZEND_VM_IP_GLOBAL_REG)\n"); + out($f, $m[1]."((opcode_handler_t)OPLINE->handler)(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);\n"); + out($f, $m[1]."if (UNEXPECTED(!OPLINE))".$m[3]."\n"); + out($f,"#else\n"); + out($f, $m[1]."if (UNEXPECTED((ret = ((opcode_handler_t)OPLINE->handler)(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU)) != 0))".$m[3]."\n"); + out($f,"#endif\n"); + if ($kind == ZEND_VM_KIND_HYBRID) { + out($f,"#endif\n"); + } + break; + } + break; + case "INTERNAL_EXECUTOR": + if ($kind != ZEND_VM_KIND_CALL) { + // Emit executor code + if ($kind == ZEND_VM_KIND_HYBRID) { + out($f,"#if (ZEND_VM_KIND == ZEND_VM_KIND_HYBRID)\n"); + } + gen_executor_code($f, $spec, $kind, $m[1], $switch_labels); + } + if ($kind == ZEND_VM_KIND_CALL || $kind == ZEND_VM_KIND_HYBRID) { + // Executor is defined as a set of functions + if ($kind == ZEND_VM_KIND_HYBRID) { + out($f,"#else\n"); + } + out($f, + "#ifdef ZEND_VM_FP_GLOBAL_REG\n" . + $m[1]."execute_data = orig_execute_data;\n" . + "# ifdef ZEND_VM_IP_GLOBAL_REG\n" . + $m[1]."opline = orig_opline;\n" . + "# endif\n" . + $m[1]."return;\n" . + "#else\n" . + $m[1]."if (EXPECTED(ret > 0)) {\n" . + $m[1]."\texecute_data = EG(current_execute_data);\n". + $m[1]."\tZEND_VM_LOOP_INTERRUPT_CHECK();\n". + $m[1]."} else {\n" . + "# ifdef ZEND_VM_IP_GLOBAL_REG\n" . + $m[1]."\topline = orig_opline;\n" . + "# endif\n". + $m[1]."\treturn;\n". + $m[1]."}\n". + "#endif\n"); + if ($kind == ZEND_VM_KIND_HYBRID) { + out($f,"#endif\n"); + } + } + break; + case "EXTERNAL_EXECUTOR": + if ($kind == ZEND_VM_KIND_CALL) { + gen_executor_code($f, $spec, $kind, $m[1]); + } + break; + case "INITIALIZER_NAME": + out($f, $m[1].$initializer_name.$m[3]."\n"); + break; + case "EXTERNAL_LABELS": + // Emit code that initializes zend_opcode_handlers array + $prolog = $m[1]; + if ($kind == ZEND_VM_KIND_GOTO) { + // Labels are defined in the executor itself, so we call it + // with execute_data NULL and it sets zend_opcode_handlers array + out($f,$prolog."static const uint32_t specs[] = {\n"); + gen_specs($f, $prolog."\t", $specs); + out($f,$prolog."};\n"); + out($f,$prolog."zend_spec_handlers = specs;\n"); + out($f,$prolog.$executor_name."_ex(NULL);\n"); + } else { + out($f,$prolog."static const void * const labels[] = {\n"); + gen_labels($f, $spec, ($kind == ZEND_VM_KIND_HYBRID) ? ZEND_VM_KIND_CALL : $kind, $prolog."\t", $specs, $switch_labels); + out($f,$prolog."};\n"); + out($f,$prolog."static const uint32_t specs[] = {\n"); + gen_specs($f, $prolog."\t", $specs); + out($f,$prolog."};\n"); + if ($kind == ZEND_VM_KIND_HYBRID) { + out($f,"#if (ZEND_VM_KIND == ZEND_VM_KIND_HYBRID)\n"); + out($f,$prolog."zend_opcode_handler_funcs = labels;\n"); + out($f,$prolog."zend_spec_handlers = specs;\n"); + out($f,$prolog.$executor_name."_ex(NULL);\n"); + out($f,"#else\n"); + } + out($f,$prolog."zend_opcode_handlers = labels;\n"); + out($f,$prolog."zend_handlers_count = sizeof(labels) / sizeof(void*);\n"); + out($f,$prolog."zend_spec_handlers = specs;\n"); + if ($kind == ZEND_VM_KIND_HYBRID) { + out($f,"#endif\n"); + } + } + break; + default: + die("ERROR: Unknown keyword ".$m[2]." in skeleton file.\n"); + } + } else { + // Copy the line as is + out($f, $line); + } + } } function parse_operand_spec($def, $lineno, $str, &$flags) { - global $vm_op_decode; - - $flags = 0; - $a = explode("|",$str); - foreach($a as $val) { - if (isset($vm_op_decode[$val])) { - $flags |= $vm_op_decode[$val]; - } else { - die("ERROR ($def:$lineno): Wrong operand type '$str'\n"); - } - } - if (!($flags & ZEND_VM_OP_SPEC)) { - if (count($a) != 1) { - die("ERROR ($def:$lineno): Wrong operand type '$str'\n"); - } - $a = array("ANY"); - } - return array_flip($a); + global $vm_op_decode; + + $flags = 0; + $a = explode("|",$str); + foreach($a as $val) { + if (isset($vm_op_decode[$val])) { + $flags |= $vm_op_decode[$val]; + } else { + die("ERROR ($def:$lineno): Wrong operand type '$str'\n"); + } + } + if (!($flags & ZEND_VM_OP_SPEC)) { + if (count($a) != 1) { + die("ERROR ($def:$lineno): Wrong operand type '$str'\n"); + } + $a = array("ANY"); + } + return array_flip($a); } function parse_ext_spec($def, $lineno, $str) { - global $vm_ext_decode; - - $flags = 0; - $a = explode("|",$str); - foreach($a as $val) { - if (isset($vm_ext_decode[$val])) { - $flags |= $vm_ext_decode[$val]; - } else { - die("ERROR ($def:$lineno): Wrong extended_value type '$str'\n"); - } - } - return $flags; + global $vm_ext_decode; + + $flags = 0; + $a = explode("|",$str); + foreach($a as $val) { + if (isset($vm_ext_decode[$val])) { + $flags |= $vm_ext_decode[$val]; + } else { + die("ERROR ($def:$lineno): Wrong extended_value type '$str'\n"); + } + } + return $flags; } function parse_spec_rules($def, $lineno, $str) { - global $used_extra_spec; - - $ret = array(); - $a = explode(",", $str); - foreach($a as $rule) { - $n = strpos($rule, "="); - if ($n !== false) { - $id = trim(substr($rule, 0, $n)); - $val = trim(substr($rule, $n+1)); - switch ($id) { - case "OP_DATA": - $ret["OP_DATA"] = parse_operand_spec($def, $lineno, $val, $devnull); - break; - default: - die("ERROR ($def:$lineno): Wrong specialization rules '$str'\n"); - } - $used_extra_spec[$id] = 1; - } else { - switch ($rule) { - case "RETVAL": - $ret["RETVAL"] = array(0, 1); - break; - case "QUICK_ARG": - $ret["QUICK_ARG"] = array(0, 1); - break; - case "SMART_BRANCH": - $ret["SMART_BRANCH"] = array(0, 1, 2); - break; - case "NO_CONST_CONST": - $ret["NO_CONST_CONST"] = array(1); - break; - case "COMMUTATIVE": - $ret["COMMUTATIVE"] = array(1); - break; - case "ISSET": - $ret["ISSET"] = array(0, 1); - break; - default: - die("ERROR ($def:$lineno): Wrong specialization rules '$str'\n"); - } - $used_extra_spec[$rule] = 1; - } - } - return $ret; + global $used_extra_spec; + + $ret = array(); + $a = explode(",", $str); + foreach($a as $rule) { + $n = strpos($rule, "="); + if ($n !== false) { + $id = trim(substr($rule, 0, $n)); + $val = trim(substr($rule, $n+1)); + switch ($id) { + case "OP_DATA": + $ret["OP_DATA"] = parse_operand_spec($def, $lineno, $val, $devnull); + break; + default: + die("ERROR ($def:$lineno): Wrong specialization rules '$str'\n"); + } + $used_extra_spec[$id] = 1; + } else { + switch ($rule) { + case "RETVAL": + $ret["RETVAL"] = array(0, 1); + break; + case "QUICK_ARG": + $ret["QUICK_ARG"] = array(0, 1); + break; + case "SMART_BRANCH": + $ret["SMART_BRANCH"] = array(0, 1, 2); + break; + case "NO_CONST_CONST": + $ret["NO_CONST_CONST"] = array(1); + break; + case "COMMUTATIVE": + $ret["COMMUTATIVE"] = array(1); + break; + case "ISSET": + $ret["ISSET"] = array(0, 1); + break; + default: + die("ERROR ($def:$lineno): Wrong specialization rules '$str'\n"); + } + $used_extra_spec[$rule] = 1; + } + } + return $ret; } function gen_vm($def, $skel) { - global $definition_file, $skeleton_file, $executor_file, - $op_types, $list, $opcodes, $helpers, $params, $opnames, - $vm_op_flags, $used_extra_spec; - - // Load definition file - $in = @file($def); - if (!$in) { - die("ERROR: Can not open definition file '$def'\n"); - } - // We need absolute path to definition file to use it in #line directives - $definition_file = realpath($def); - - // Load skeleton file - $skl = @file($skel); - if (!$skl) { - die("ERROR: Can not open skeleton file '$skel'\n"); - } - // We need absolute path to skeleton file to use it in #line directives - $skeleton_file = realpath($skel); - - // Parse definition file into tree - $lineno = 0; - $handler = null; - $helper = null; - $max_opcode_len = 0; - $max_opcode = 0; - $extra_num = 256; - $export = array(); - foreach ($in as $line) { - ++$lineno; - if (strpos($line,"ZEND_VM_HANDLER(") === 0 || - strpos($line,"ZEND_VM_INLINE_HANDLER(") === 0 || - strpos($line,"ZEND_VM_HOT_HANDLER(") === 0 || - strpos($line,"ZEND_VM_HOT_NOCONST_HANDLER(") === 0 || - strpos($line,"ZEND_VM_HOT_NOCONSTCONST_HANDLER(") === 0 || - strpos($line,"ZEND_VM_HOT_SEND_HANDLER(") === 0 || - strpos($line,"ZEND_VM_HOT_OBJ_HANDLER(") === 0 || - strpos($line,"ZEND_VM_COLD_HANDLER(") === 0 || - strpos($line,"ZEND_VM_COLD_CONST_HANDLER(") === 0 || - strpos($line,"ZEND_VM_COLD_CONSTCONST_HANDLER(") === 0) { - // Parsing opcode handler's definition - if (preg_match( - "/^ZEND_VM_(HOT_|INLINE_|HOT_OBJ_|HOT_SEND_|HOT_NOCONST_|HOT_NOCONSTCONST_|COLD_|COLD_CONST_|COLD_CONSTCONST_)?HANDLER\(\s*([0-9]+)\s*,\s*([A-Z_]+)\s*,\s*([A-Z_|]+)\s*,\s*([A-Z_|]+)\s*(,\s*([A-Z_|]+)\s*)?(,\s*SPEC\(([A-Z_|=,]+)\)\s*)?\)/", - $line, - $m) == 0) { - die("ERROR ($def:$lineno): Invalid ZEND_VM_HANDLER definition.\n"); - } - $hot = !empty($m[1]) ? $m[1] : false; - $code = (int)$m[2]; - $op = $m[3]; - $len = strlen($op); - $op1 = parse_operand_spec($def, $lineno, $m[4], $flags1); - $op2 = parse_operand_spec($def, $lineno, $m[5], $flags2); - $flags = $flags1 | ($flags2 << 8); - if (!empty($m[7])) { - $flags |= parse_ext_spec($def, $lineno, $m[7]); - } - - if ($len > $max_opcode_len) { - $max_opcode_len = $len; - } - if ($code > $max_opcode) { - $max_opcode = $code; - } - if (isset($opcodes[$code])) { - die("ERROR ($def:$lineno): Opcode with code '$code' is already defined.\n"); - } - if (isset($opnames[$op])) { - die("ERROR ($def:$lineno): Opcode with name '$op' is already defined.\n"); - } - $opcodes[$code] = array("op"=>$op,"op1"=>$op1,"op2"=>$op2,"code"=>"","flags"=>$flags,"hot"=>$hot); - if (isset($m[9])) { - $opcodes[$code]["spec"] = parse_spec_rules($def, $lineno, $m[9]); - if (isset($opcodes[$code]["spec"]["NO_CONST_CONST"])) { - $opcodes[$code]["flags"] |= $vm_op_flags["ZEND_VM_NO_CONST_CONST"]; - } - if (isset($opcodes[$code]["spec"]["COMMUTATIVE"])) { - $opcodes[$code]["flags"] |= $vm_op_flags["ZEND_VM_COMMUTATIVE"]; - } - } - $opnames[$op] = $code; - $handler = $code; - $helper = null; - $list[$lineno] = array("handler"=>$handler); - } else if (strpos($line,"ZEND_VM_TYPE_SPEC_HANDLER(") === 0 || - strpos($line,"ZEND_VM_INLINE_TYPE_SPEC_HANDLER(") === 0 || - strpos($line,"ZEND_VM_HOT_TYPE_SPEC_HANDLER(") === 0 || - strpos($line,"ZEND_VM_HOT_NOCONST_TYPE_SPEC_HANDLER(") === 0 || - strpos($line,"ZEND_VM_HOT_NOCONSTCONST_TYPE_SPEC_HANDLER(") === 0 || - strpos($line,"ZEND_VM_HOT_SEND_TYPE_SPEC_HANDLER(") === 0 || - strpos($line,"ZEND_VM_HOT_OBJ_TYPE_SPEC_HANDLER(") === 0) { - // Parsing opcode handler's definition - if (preg_match( - "/^ZEND_VM_(HOT_|INLINE_|HOT_OBJ_|HOT_SEND_|HOT_NOCONST_|HOT_NOCONSTCONST_)?TYPE_SPEC_HANDLER\(\s*([A-Z_]+)\s*,\s*((?:[^(,]|\([^()]*|(?R)*\))*),\s*([A-Za-z_]+)\s*,\s*([A-Z_|]+)\s*,\s*([A-Z_|]+)\s*(,\s*([A-Z_|]+)\s*)?(,\s*SPEC\(([A-Z_|=,]+)\)\s*)?\)/", - $line, - $m) == 0) { - die("ERROR ($def:$lineno): Invalid ZEND_VM_TYPE_HANDLER_HANDLER definition.\n"); - } - $hot = !empty($m[1]) ? $m[1] : false; - $orig_op = $m[2]; - if (!isset($opnames[$orig_op])) { - die("ERROR ($def:$lineno): Opcode with name '$orig_op' is not defined.\n"); - } - $orig_code = $opnames[$orig_op]; - $condition = $m[3]; - $code = $extra_num++; - $op = $m[4]; - $op1 = parse_operand_spec($def, $lineno, $m[5], $flags1); - $op2 = parse_operand_spec($def, $lineno, $m[6], $flags2); - $flags = $flags1 | ($flags2 << 8); - if (!empty($m[8])) { - $flags |= parse_ext_spec($def, $lineno, $m[8]); - } - - if (isset($opcodes[$code])) { - die("ERROR ($def:$lineno): Opcode with name '$code' is already defined.\n"); - } - $opcodes[$orig_code]['type_spec'][$code] = $condition; - $used_extra_spec["TYPE"] = 1; - $opcodes[$code] = array("op"=>$op,"op1"=>$op1,"op2"=>$op2,"code"=>"","flags"=>$flags,"hot"=>$hot,"is_type_spec"=>true); - if (isset($m[10])) { - $opcodes[$code]["spec"] = parse_spec_rules($def, $lineno, $m[10]); - if (isset($opcodes[$code]["spec"]["NO_CONST_CONST"])) { - $opcodes[$code]["flags"] |= $vm_op_flags["ZEND_VM_NO_CONST_CONST"]; - } - if (isset($opcodes[$code]["spec"]["COMMUTATIVE"])) { - $opcodes[$code]["flags"] |= $vm_op_flags["ZEND_VM_COMMUTATIVE"]; - } - } - $opnames[$op] = $code; - $handler = $code; - $helper = null; - $list[$lineno] = array("handler"=>$handler); - } else if (strpos($line,"ZEND_VM_HELPER(") === 0 || - strpos($line,"ZEND_VM_INLINE_HELPER(") === 0 || - strpos($line,"ZEND_VM_COLD_HELPER(") === 0 || - strpos($line,"ZEND_VM_HOT_HELPER(") === 0) { - // Parsing helper's definition - if (preg_match( - "/^ZEND_VM(_INLINE|_COLD|_HOT)?_HELPER\(\s*([A-Za-z_]+)\s*,\s*([A-Z_|]+)\s*,\s*([A-Z_|]+)\s*(?:,\s*SPEC\(([A-Z_|=,]+)\)\s*)?(?:,\s*([^)]*)\s*)?\)/", - $line, - $m) == 0) { - die("ERROR ($def:$lineno): Invalid ZEND_VM_HELPER definition.\n"); - } - $inline = !empty($m[1]) && $m[1] === "_INLINE"; - $cold = !empty($m[1]) && $m[1] === "_COLD"; - $hot = !empty($m[1]) && $m[1] === "_HOT"; - $helper = $m[2]; - $op1 = parse_operand_spec($def, $lineno, $m[3], $flags1); - $op2 = parse_operand_spec($def, $lineno, $m[4], $flags2); - $param = isset($m[6]) ? $m[6] : null; - if (isset($helpers[$helper])) { - die("ERROR ($def:$lineno): Helper with name '$helper' is already defined.\n"); - } - - // Store parameters - if (ZEND_VM_KIND == ZEND_VM_KIND_GOTO - || ZEND_VM_KIND == ZEND_VM_KIND_SWITCH - || (ZEND_VM_KIND == ZEND_VM_KIND_HYBRID && $hot)) { - foreach (explode(",", $param) as $p) { - $p = trim($p); - if ($p !== "") { - $params[$p] = 1; - } - } - } - - $helpers[$helper] = array("op1"=>$op1,"op2"=>$op2,"param"=>$param,"code"=>"","inline"=>$inline,"cold"=>$cold,"hot"=>$hot); - - if (!empty($m[5])) { - $helpers[$helper]["spec"] = parse_spec_rules($def, $lineno, $m[5]); - } - - $handler = null; - $list[$lineno] = array("helper"=>$helper); - } else if (strpos($line,"ZEND_VM_EXPORT_HANDLER(") === 0) { - if (preg_match( - "/^ZEND_VM_EXPORT_HANDLER\(\s*([A-Za-z_]+)\s*,\s*([A-Z_]+)\s*\)/", - $line, - $m) == 0) { - die("ERROR ($def:$lineno): Invalid ZEND_VM_EXPORT_HANDLER definition.\n"); - } - if (!isset($opnames[$m[2]])) { - die("ERROR ($def:$lineno): opcode '{$m[2]}' is not defined.\n"); - } - $export[] = array("handler",$m[1],$m[2]); - } else if (strpos($line,"ZEND_VM_EXPORT_HELPER(") === 0) { - if (preg_match( - "/^ZEND_VM_EXPORT_HELPER\(\s*([A-Za-z_]+)\s*,\s*([A-Za-z_]+)\s*\)/", - $line, - $m) == 0) { - die("ERROR ($def:$lineno): Invalid ZEND_VM_EXPORT_HELPER definition.\n"); - } - if (!isset($helpers[$m[2]])) { - die("ERROR ($def:$lineno): helper '{$m[2]}' is not defined.\n"); - } - $export[] = array("helper",$m[1],$m[2]); - } else if (strpos($line,"ZEND_VM_DEFINE_OP(") === 0) { - if (preg_match( - "/^ZEND_VM_DEFINE_OP\(\s*([0-9]+)\s*,\s*([A-Z_]+)\s*\);/", - $line, - $m) == 0) { - die("ERROR ($def:$lineno): Invalid ZEND_VM_DEFINE_OP definition.\n"); - } - $code = (int)$m[1]; - $op = $m[2]; - $len = strlen($op); - - if ($len > $max_opcode_len) { - $max_opcode_len = $len; - } - if ($code > $max_opcode) { - $max_opcode = $code; - } - if (isset($opcodes[$code])) { - die("ERROR ($def:$lineno): Opcode with code '$code' is already defined.\n"); - } - if (isset($opnames[$op])) { - die("ERROR ($def:$lineno): Opcode with name '$op' is already defined.\n"); - } - $opcodes[$code] = array("op"=>$op,"code"=>""); - $opnames[$op] = $code; - } else if ($handler !== null) { - // Add line of code to current opcode handler - $opcodes[$handler]["code"] .= $line; - } else if ($helper !== null) { - // Add line of code to current helper - $helpers[$helper]["code"] .= $line; - } - } - - ksort($opcodes); - - // Search for opcode handlers those are used by other opcode handlers - foreach ($opcodes as $dsc) { - if (preg_match("/^\s*{\s*ZEND_VM_DISPATCH_TO_HANDLER\(\s*([A-Z_]*)\s*\)\s*;\s*}\s*/", $dsc["code"], $m)) { - $op = $m[1]; - if (!isset($opnames[$op])) { - die("ERROR ($def:$lineno): Opcode with name '$op' is not defined.\n"); - } - $opcodes[$opnames[$dsc['op']]]['alias'] = $op; - if (!ZEND_VM_SPEC && ZEND_VM_KIND == ZEND_VM_KIND_SWITCH) { - $code = $opnames[$op]; - $opcodes[$code]['use'] = 1; - } - } else if (preg_match_all("/ZEND_VM_DISPATCH_TO_HANDLER\(\s*([A-Z_]*)\s*\)/m", $dsc["code"], $mm, PREG_SET_ORDER)) { - foreach ($mm as $m) { - $op = $m[1]; - if (!isset($opnames[$op])) { - die("ERROR ($def:$lineno): Opcode with name '$op' is not defined.\n"); - } - $code = $opnames[$op]; - $opcodes[$code]['use'] = 1; - } - } - } - - // Generate opcode #defines (zend_vm_opcodes.h) - $code_len = strlen((string)$max_opcode); - $f = fopen(__DIR__ . "/zend_vm_opcodes.h", "w+") or die("ERROR: Cannot create zend_vm_opcodes.h\n"); - - // Insert header - out($f, HEADER_TEXT); - fputs($f, "#ifndef ZEND_VM_OPCODES_H\n#define ZEND_VM_OPCODES_H\n\n"); - fputs($f, "#define ZEND_VM_SPEC\t\t" . ZEND_VM_SPEC . "\n"); - fputs($f, "#define ZEND_VM_LINES\t\t" . ZEND_VM_LINES . "\n"); - fputs($f, "#define ZEND_VM_KIND_CALL\t" . ZEND_VM_KIND_CALL . "\n"); - fputs($f, "#define ZEND_VM_KIND_SWITCH\t" . ZEND_VM_KIND_SWITCH . "\n"); - fputs($f, "#define ZEND_VM_KIND_GOTO\t" . ZEND_VM_KIND_GOTO . "\n"); - fputs($f, "#define ZEND_VM_KIND_HYBRID\t" . ZEND_VM_KIND_HYBRID . "\n"); - if ($GLOBALS["vm_kind_name"][ZEND_VM_KIND] === "ZEND_VM_KIND_HYBRID") { - fputs($f, "/* HYBRID requires support for computed GOTO and global register variables*/\n"); - fputs($f, "#if (defined(__GNUC__) && defined(HAVE_GCC_GLOBAL_REGS))\n"); - fputs($f, "# define ZEND_VM_KIND\t\tZEND_VM_KIND_HYBRID\n"); - fputs($f, "#else\n"); - fputs($f, "# define ZEND_VM_KIND\t\tZEND_VM_KIND_CALL\n"); - fputs($f, "#endif\n"); - } else { - fputs($f, "#define ZEND_VM_KIND\t\t" . $GLOBALS["vm_kind_name"][ZEND_VM_KIND] . "\n"); - } - fputs($f, "\n"); - foreach($vm_op_flags as $name => $val) { - fprintf($f, "#define %-24s 0x%08x\n", $name, $val); - } - fputs($f, "#define ZEND_VM_OP1_FLAGS(flags) (flags & 0xff)\n"); - fputs($f, "#define ZEND_VM_OP2_FLAGS(flags) ((flags >> 8) & 0xff)\n"); - fputs($f, "\n"); - fputs($f, "BEGIN_EXTERN_C()\n\n"); - fputs($f, "ZEND_API const char* ZEND_FASTCALL zend_get_opcode_name(zend_uchar opcode);\n"); - fputs($f, "ZEND_API uint32_t ZEND_FASTCALL zend_get_opcode_flags(zend_uchar opcode);\n\n"); - fputs($f, "END_EXTERN_C()\n\n"); - - foreach ($opcodes as $code => $dsc) { - $code = str_pad((string)$code,$code_len," ",STR_PAD_LEFT); - $op = str_pad($dsc["op"],$max_opcode_len); - if ($code <= $max_opcode) { - fputs($f,"#define $op $code\n"); - } - } - - $code = str_pad((string)$max_opcode,$code_len," ",STR_PAD_LEFT); - $op = str_pad("ZEND_VM_LAST_OPCODE",$max_opcode_len); - fputs($f,"\n#define $op $code\n"); - - fputs($f, "\n#endif\n"); - fclose($f); - echo "zend_vm_opcodes.h generated successfully.\n"; - - // zend_vm_opcodes.c - $f = fopen(__DIR__ . "/zend_vm_opcodes.c", "w+") or die("ERROR: Cannot create zend_vm_opcodes.c\n"); - - // Insert header - out($f, HEADER_TEXT); - fputs($f,"#include <stdio.h>\n"); - fputs($f,"#include <zend.h>\n"); - fputs($f,"#include <zend_vm_opcodes.h>\n\n"); - - fputs($f,"static const char *zend_vm_opcodes_names[".($max_opcode + 1)."] = {\n"); - for ($i = 0; $i <= $max_opcode; $i++) { - fputs($f,"\t".(isset($opcodes[$i]["op"])?'"'.$opcodes[$i]["op"].'"':"NULL").",\n"); - } - fputs($f, "};\n\n"); - - fputs($f,"static uint32_t zend_vm_opcodes_flags[".($max_opcode + 1)."] = {\n"); - for ($i = 0; $i <= $max_opcode; $i++) { - fprintf($f, "\t0x%08x,\n", isset($opcodes[$i]["flags"]) ? $opcodes[$i]["flags"] : 0); - } - fputs($f, "};\n\n"); - - fputs($f, "ZEND_API const char* ZEND_FASTCALL zend_get_opcode_name(zend_uchar opcode) {\n"); - fputs($f, "\tif (UNEXPECTED(opcode > ZEND_VM_LAST_OPCODE)) {\n"); - fputs($f, "\t\treturn NULL;\n"); - fputs($f, "\t}\n"); - fputs($f, "\treturn zend_vm_opcodes_names[opcode];\n"); - fputs($f, "}\n"); - - fputs($f, "ZEND_API uint32_t ZEND_FASTCALL zend_get_opcode_flags(zend_uchar opcode) {\n"); - fputs($f, "\tif (UNEXPECTED(opcode > ZEND_VM_LAST_OPCODE)) {\n"); - fputs($f, "\t\topcode = ZEND_NOP;\n"); - fputs($f, "\t}\n"); - fputs($f, "\treturn zend_vm_opcodes_flags[opcode];\n"); - fputs($f, "}\n"); - - fclose($f); - echo "zend_vm_opcodes.c generated successfully.\n"; - - // Generate zend_vm_execute.h - $f = fopen(__DIR__ . "/zend_vm_execute.h", "w+") or die("ERROR: Cannot create zend_vm_execute.h\n"); - $executor_file = realpath(__DIR__ . "/zend_vm_execute.h"); - - // Insert header - out($f, HEADER_TEXT); - - out($f, "#ifdef ZEND_WIN32\n"); - // Suppress free_op1 warnings on Windows - out($f, "# pragma warning(disable : 4101)\n"); - if (ZEND_VM_SPEC) { - // Suppress (<non-zero constant> || <expression>) warnings on windows - out($f, "# pragma warning(once : 6235)\n"); - // Suppress (<zero> && <expression>) warnings on windows - out($f, "# pragma warning(once : 6237)\n"); - // Suppress (<non-zero constant> && <expression>) warnings on windows - out($f, "# pragma warning(once : 6239)\n"); - // Suppress (<expression> && <non-zero constant>) warnings on windows - out($f, "# pragma warning(once : 6240)\n"); - // Suppress (<non-zero constant> || <non-zero constant>) warnings on windows - out($f, "# pragma warning(once : 6285)\n"); - // Suppress (<non-zero constant> || <expression>) warnings on windows - out($f, "# pragma warning(once : 6286)\n"); - // Suppress constant with constant comparison warnings on windows - out($f, "# pragma warning(once : 6326)\n"); - } - out($f, "#endif\n"); - - // Support for ZEND_USER_OPCODE - out($f, "static user_opcode_handler_t zend_user_opcode_handlers[256] = {\n"); - for ($i = 0; $i < 255; ++$i) { - out($f, "\t(user_opcode_handler_t)NULL,\n"); - } - out($f, "\t(user_opcode_handler_t)NULL\n};\n\n"); - - out($f, "static zend_uchar zend_user_opcodes[256] = {"); - for ($i = 0; $i < 255; ++$i) { - if ($i % 16 == 1) out($f, "\n\t"); - out($f, "$i,"); - } - out($f, "255\n};\n\n"); - - // Generate specialized executor - gen_executor($f, $skl, ZEND_VM_SPEC, ZEND_VM_KIND, "execute", "zend_vm_init"); - out($f, "\n"); - - // Generate zend_vm_get_opcode_handler() function - out($f, "static const void* ZEND_FASTCALL zend_vm_get_opcode_handler_ex(uint32_t spec, const zend_op* op)\n"); - out($f, "{\n"); - if (!ZEND_VM_SPEC) { - out($f, "\treturn zend_opcode_handlers[spec];\n"); - } else { - out($f, "\tstatic const int zend_vm_decode[] = {\n"); - out($f, "\t\t_UNUSED_CODE, /* 0 = IS_UNUSED */\n"); - out($f, "\t\t_CONST_CODE, /* 1 = IS_CONST */\n"); - out($f, "\t\t_TMP_CODE, /* 2 = IS_TMP_VAR */\n"); - out($f, "\t\t_UNUSED_CODE, /* 3 */\n"); - out($f, "\t\t_VAR_CODE, /* 4 = IS_VAR */\n"); - out($f, "\t\t_UNUSED_CODE, /* 5 */\n"); - out($f, "\t\t_UNUSED_CODE, /* 6 */\n"); - out($f, "\t\t_UNUSED_CODE, /* 7 */\n"); - out($f, "\t\t_CV_CODE /* 8 = IS_CV */\n"); - out($f, "\t};\n"); - out($f, "\tuint32_t offset = 0;\n"); - out($f, "\tif (spec & SPEC_RULE_OP1) offset = offset * 5 + zend_vm_decode[op->op1_type];\n"); - out($f, "\tif (spec & SPEC_RULE_OP2) offset = offset * 5 + zend_vm_decode[op->op2_type];\n"); - - if (isset($used_extra_spec["OP_DATA"]) || - isset($used_extra_spec["RETVAL"]) || - isset($used_extra_spec["QUICK_ARG"]) || - isset($used_extra_spec["SMART_BRANCH"]) || - isset($used_extra_spec["ISSET"])) { - - $else = ""; - out($f, "\tif (spec & SPEC_EXTRA_MASK) {\n"); - - if (isset($used_extra_spec["RETVAL"])) { - out($f, "\t\t{$else}if (spec & SPEC_RULE_RETVAL) {\n"); - out($f, "\t\t\toffset = offset * 2 + (op->result_type != IS_UNUSED);\n"); - $else = "} else "; - } - if (isset($used_extra_spec["QUICK_ARG"])) { - out($f, "\t\t{$else}if (spec & SPEC_RULE_QUICK_ARG) {\n"); - out($f, "\t\t\toffset = offset * 2 + (op->op2.num <= MAX_ARG_FLAG_NUM);\n"); - $else = "} else "; - } - if (isset($used_extra_spec["OP_DATA"])) { - out($f, "\t\t{$else}if (spec & SPEC_RULE_OP_DATA) {\n"); - out($f, "\t\t\toffset = offset * 5 + zend_vm_decode[(op + 1)->op1_type];\n"); - $else = "} else "; - } - if (isset($used_extra_spec["ISSET"])) { - out($f, "\t\t{$else}if (spec & SPEC_RULE_ISSET) {\n"); - out($f, "\t\t\toffset = offset * 2 + (op->extended_value & ZEND_ISEMPTY);\n"); - $else = "} else "; - } - if (isset($used_extra_spec["SMART_BRANCH"])) { - out($f, "\t\t{$else}if (spec & SPEC_RULE_SMART_BRANCH) {\n"); - out($f, "\t\t\toffset = offset * 3;\n"); - out($f, "\t\t\tif ((op+1)->opcode == ZEND_JMPZ) {\n"); - out($f, "\t\t\t\toffset += 1;\n"); - out($f, "\t\t\t} else if ((op+1)->opcode == ZEND_JMPNZ) {\n"); - out($f, "\t\t\t\toffset += 2;\n"); - out($f, "\t\t\t}\n"); - $else = "} else "; - } - if ($else !== "") { - out($f, "\t\t}\n"); - } - out($f, "\t}\n"); - } - out($f, "\treturn zend_opcode_handlers[(spec & SPEC_START_MASK) + offset];\n"); - } - out($f, "}\n\n"); - out($f, "#if (ZEND_VM_KIND != ZEND_VM_KIND_HYBRID) || !ZEND_VM_SPEC\n"); - out($f, "static const void *zend_vm_get_opcode_handler(zend_uchar opcode, const zend_op* op)\n"); - out($f, "{\n"); - if (!ZEND_VM_SPEC) { - out($f, "\treturn zend_vm_get_opcode_handler_ex(opcode, op);\n"); - } else { - out($f, "\treturn zend_vm_get_opcode_handler_ex(zend_spec_handlers[opcode], op);\n"); - } - out($f, "}\n"); - out($f, "#endif\n\n"); - - if (ZEND_VM_KIND == ZEND_VM_KIND_HYBRID) { - // Generate zend_vm_get_opcode_handler_func() function - out($f, "#if ZEND_VM_KIND == ZEND_VM_KIND_HYBRID\n"); - out($f,"static const void *zend_vm_get_opcode_handler_func(zend_uchar opcode, const zend_op* op)\n"); - out($f, "{\n"); - out($f, "\tuint32_t spec = zend_spec_handlers[opcode];\n"); - if (!ZEND_VM_SPEC) { - out($f, "\treturn zend_opcode_handler_funcs[spec];\n"); - } else { - out($f, "\tstatic const int zend_vm_decode[] = {\n"); - out($f, "\t\t_UNUSED_CODE, /* 0 = IS_UNUSED */\n"); - out($f, "\t\t_CONST_CODE, /* 1 = IS_CONST */\n"); - out($f, "\t\t_TMP_CODE, /* 2 = IS_TMP_VAR */\n"); - out($f, "\t\t_UNUSED_CODE, /* 3 */\n"); - out($f, "\t\t_VAR_CODE, /* 4 = IS_VAR */\n"); - out($f, "\t\t_UNUSED_CODE, /* 5 */\n"); - out($f, "\t\t_UNUSED_CODE, /* 6 */\n"); - out($f, "\t\t_UNUSED_CODE, /* 7 */\n"); - out($f, "\t\t_CV_CODE /* 8 = IS_CV */\n"); - out($f, "\t};\n"); - out($f, "\tuint32_t offset = 0;\n"); - out($f, "\tif (spec & SPEC_RULE_OP1) offset = offset * 5 + zend_vm_decode[op->op1_type];\n"); - out($f, "\tif (spec & SPEC_RULE_OP2) offset = offset * 5 + zend_vm_decode[op->op2_type];\n"); - - if (isset($used_extra_spec["OP_DATA"]) || - isset($used_extra_spec["RETVAL"]) || - isset($used_extra_spec["QUICK_ARG"]) || - isset($used_extra_spec["SMART_BRANCH"]) || - isset($used_extra_spec["ISSET"])) { - - $else = ""; - out($f, "\tif (spec & SPEC_EXTRA_MASK) {\n"); - - if (isset($used_extra_spec["OP_DATA"])) { - out($f, "\t\t{$else}if (spec & SPEC_RULE_OP_DATA) offset = offset * 5 + zend_vm_decode[(op + 1)->op1_type];\n"); - $else = "else "; - } - if (isset($used_extra_spec["RETVAL"])) { - out($f, "\t\t{$else}if (spec & SPEC_RULE_RETVAL) offset = offset * 2 + (op->result_type != IS_UNUSED);\n"); - $else = "else "; - } - if (isset($used_extra_spec["QUICK_ARG"])) { - out($f, "\t\t{$else}if (spec & SPEC_RULE_QUICK_ARG) offset = offset * 2 + (op->op2.num <= MAX_ARG_FLAG_NUM);\n"); - $else = "else "; - } - if (isset($used_extra_spec["SMART_BRANCH"])) { - out($f, "\t\t{$else}if (spec & SPEC_RULE_SMART_BRANCH) {\n"); - out($f, "\t\t\toffset = offset * 3;\n"); - out($f, "\t\t\tif ((op+1)->opcode == ZEND_JMPZ) {\n"); - out($f, "\t\t\t\toffset += 1;\n"); - out($f, "\t\t\t} else if ((op+1)->opcode == ZEND_JMPNZ) {\n"); - out($f, "\t\t\t\toffset += 2;\n"); - out($f, "\t\t\t}\n"); - out($f, "\t\t}\n"); - $else = "else "; - } - if (isset($used_extra_spec["ISSET"])) { - out($f, "\t\t{$else}if (spec & SPEC_RULE_ISSET) offset = offset * 2 + (op->extended_value & ZEND_ISEMPTY);\n"); - $else = "else "; - } - out($f, "\t}\n"); - } - - out($f, "\treturn zend_opcode_handler_funcs[(spec & SPEC_START_MASK) + offset];\n"); - } - out($f, "}\n\n"); - out($f, "#endif\n\n"); - } - - // Generate zend_vm_get_opcode_handler() function - out($f, "ZEND_API void ZEND_FASTCALL zend_vm_set_opcode_handler(zend_op* op)\n"); - out($f, "{\n"); - out($f, "\tzend_uchar opcode = zend_user_opcodes[op->opcode];\n"); - if (!ZEND_VM_SPEC) { - out($f, "\top->handler = zend_vm_get_opcode_handler(opcode, op);\n"); - } else { - out($f, "\n"); - out($f, "\tif (zend_spec_handlers[op->opcode] & SPEC_RULE_COMMUTATIVE) {\n"); - out($f, "\t\tif (op->op1_type < op->op2_type) {\n"); - out($f, "\t\t\tzend_swap_operands(op);\n"); - out($f, "\t\t}\n"); - out($f, "\t}\n"); - out($f, "\top->handler = zend_vm_get_opcode_handler_ex(zend_spec_handlers[opcode], op);\n"); - } - out($f, "}\n\n"); - - // Generate zend_vm_set_opcode_handler_ex() function - out($f, "ZEND_API void ZEND_FASTCALL zend_vm_set_opcode_handler_ex(zend_op* op, uint32_t op1_info, uint32_t op2_info, uint32_t res_info)\n"); - out($f, "{\n"); - out($f, "\tzend_uchar opcode = zend_user_opcodes[op->opcode];\n"); - if (!ZEND_VM_SPEC) { - out($f, "\top->handler = zend_vm_get_opcode_handler_ex(opcode, op);\n"); - } else { - out($f, "\tuint32_t spec = zend_spec_handlers[opcode];\n"); - if (isset($used_extra_spec["TYPE"])) { - out($f, "\tswitch (opcode) {\n"); - foreach($opcodes as $code => $dsc) { - if (isset($dsc['type_spec'])) { - $orig_op = $dsc['op']; - out($f, "\t\tcase $orig_op:\n"); - if (isset($dsc["spec"]["COMMUTATIVE"])) { - out($f, "\t\t\tif (op->op1_type < op->op2_type) {\n"); - out($f, "\t\t\t\tzend_swap_operands(op);\n"); - out($f, "\t\t\t}\n"); - } - $first = true; - foreach($dsc['type_spec'] as $code => $condition) { - $condition = format_condition($condition); - if ($first) { - out($f, "\t\t\tif $condition {\n"); - $first = false; - } else { - out($f, "\t\t\t} else if $condition {\n"); - } - $spec_dsc = $opcodes[$code]; - if (isset($spec_dsc["spec"]["NO_CONST_CONST"])) { - out($f, "\t\t\t\tif (op->op1_type == IS_CONST && op->op2_type == IS_CONST) {\n"); - out($f, "\t\t\t\t\tbreak;\n"); - out($f, "\t\t\t\t}\n"); - } - out($f, "\t\t\t\tspec = ${spec_dsc['spec_code']};\n"); - if (isset($spec_dsc["spec"]["COMMUTATIVE"]) && !isset($dsc["spec"]["COMMUTATIVE"])) { - out($f, "\t\t\t\tif (op->op1_type < op->op2_type) {\n"); - out($f, "\t\t\t\t\tzend_swap_operands(op);\n"); - out($f, "\t\t\t\t}\n"); - } - } - if (!$first) { - out($f, "\t\t\t}\n"); - } - out($f, "\t\t\tbreak;\n"); - } - } - $has_commutative = false; - foreach($opcodes as $code => $dsc) { - if (!isset($dsc['is_type_spec']) && - !isset($dsc['type_spec']) && - isset($dsc["spec"]["COMMUTATIVE"])) { - $orig_op = $dsc['op']; - out($f, "\t\tcase $orig_op:\n"); - $has_commutative = true; - } - } - if ($has_commutative) { - out($f, "\t\t\tif (op->op1_type < op->op2_type) {\n"); - out($f, "\t\t\t\tzend_swap_operands(op);\n"); - out($f, "\t\t\t}\n"); - out($f, "\t\t\tbreak;\n"); - out($f, "\t\tcase ZEND_USER_OPCODE:\n"); - out($f, "\t\t\tif (zend_spec_handlers[op->opcode] & SPEC_RULE_COMMUTATIVE) {\n"); - out($f, "\t\t\t\tif (op->op1_type < op->op2_type) {\n"); - out($f, "\t\t\t\t\tzend_swap_operands(op);\n"); - out($f, "\t\t\t\t}\n"); - out($f, "\t\t\t}\n"); - out($f, "\t\t\tbreak;\n"); - } - out($f, "\t\tdefault:\n"); - out($f, "\t\t\tbreak;\n"); - out($f, "\t}\n"); - } - out($f, "\top->handler = zend_vm_get_opcode_handler_ex(spec, op);\n"); - } - out($f, "}\n\n"); - - // Generate zend_vm_call_opcode_handler() function - if (ZEND_VM_KIND == ZEND_VM_KIND_CALL || ZEND_VM_KIND == ZEND_VM_KIND_HYBRID) { - out($f, "ZEND_API int ZEND_FASTCALL zend_vm_call_opcode_handler(zend_execute_data* ex)\n"); - out($f, "{\n"); - if (ZEND_VM_KIND == ZEND_VM_KIND_HYBRID) { - out($f,"#if (ZEND_VM_KIND == ZEND_VM_KIND_HYBRID)\n"); - out($f, "\topcode_handler_t handler;\n"); - out($f,"#endif\n"); - } - out($f, "\tint ret;\n"); - out($f, "#ifdef ZEND_VM_IP_GLOBAL_REG\n"); - out($f, "\tconst zend_op *orig_opline = opline;\n"); - out($f, "#endif\n"); - out($f, "#ifdef ZEND_VM_FP_GLOBAL_REG\n"); - out($f, "\tzend_execute_data *orig_execute_data = execute_data;\n"); - out($f, "\texecute_data = ex;\n"); - out($f, "#else\n"); - out($f, "\tzend_execute_data *execute_data = ex;\n"); - out($f, "#endif\n"); - out($f, "\n"); - out($f, "\tLOAD_OPLINE();\n"); - out($f,"#if defined(ZEND_VM_FP_GLOBAL_REG) && defined(ZEND_VM_IP_GLOBAL_REG)\n"); - if (ZEND_VM_KIND == ZEND_VM_KIND_HYBRID) { - out($f,"#if (ZEND_VM_KIND == ZEND_VM_KIND_HYBRID)\n"); - out($f, "\thandler = (opcode_handler_t)zend_vm_get_opcode_handler_func(zend_user_opcodes[opline->opcode], opline);\n"); - out($f, "\thandler(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);\n"); - out($f, "\tif (EXPECTED(opline != &hybrid_halt_op)) {\n"); - out($f,"#else\n"); - } - out($f, "\t((opcode_handler_t)OPLINE->handler)(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);\n"); - if (ZEND_VM_KIND == ZEND_VM_KIND_HYBRID) { - out($f, "\tif (EXPECTED(opline)) {\n"); - out($f,"#endif\n"); - } else { - out($f, "\tif (EXPECTED(opline)) {\n"); - } - out($f, "\t\tret = execute_data != ex ? (int)(execute_data->prev_execute_data != ex) + 1 : 0;\n"); - out($f, "\t\tSAVE_OPLINE();\n"); - out($f, "\t} else {\n"); - out($f, "\t\tret = -1;\n"); - out($f, "\t}\n"); - out($f, "#else\n"); - out($f, "\tret = ((opcode_handler_t)OPLINE->handler)(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);\n"); - out($f, "\tSAVE_OPLINE();\n"); - out($f, "#endif\n"); - out($f, "#ifdef ZEND_VM_FP_GLOBAL_REG\n"); - out($f, "\texecute_data = orig_execute_data;\n"); - out($f, "#endif\n"); - out($f, "#ifdef ZEND_VM_IP_GLOBAL_REG\n"); - out($f, "\topline = orig_opline;\n"); - out($f, "#endif\n"); - out($f, "\treturn ret;\n"); - out($f, "}\n\n"); - } else { - out($f, "ZEND_API int ZEND_FASTCALL zend_vm_call_opcode_handler(zend_execute_data* ex)\n"); - out($f, "{\n"); - out($f, "\tzend_error_noreturn(E_CORE_ERROR, \"zend_vm_call_opcode_handler() is not supported\");\n"); - out($f, "\treturn 0;\n"); - out($f, "}\n\n"); - } - - // Export handlers and helpers - if (count($export) > 0 && - ZEND_VM_KIND != ZEND_VM_KIND_CALL) { - out($f,"#undef OPLINE\n"); - out($f,"#undef DCL_OPLINE\n"); - out($f,"#undef USE_OPLINE\n"); - out($f,"#undef LOAD_OPLINE\n"); - out($f,"#undef LOAD_OPLINE_EX\n"); - out($f,"#undef LOAD_NEXT_OPLINE\n"); - out($f,"#undef SAVE_OPLINE\n"); - out($f,"#undef SAVE_OPLINE_EX\n"); - out($f,"#define OPLINE EX(opline)\n"); - out($f,"#define DCL_OPLINE\n"); - out($f,"#define USE_OPLINE const zend_op *opline = EX(opline);\n"); - out($f,"#define LOAD_OPLINE()\n"); - out($f,"#define LOAD_OPLINE_EX()\n"); - out($f,"#define LOAD_NEXT_OPLINE() ZEND_VM_INC_OPCODE()\n"); - out($f,"#define SAVE_OPLINE()\n"); - out($f,"#define SAVE_OPLINE_EX()\n"); - out($f,"#undef HANDLE_EXCEPTION\n"); - out($f,"#undef HANDLE_EXCEPTION_LEAVE\n"); - out($f,"#define HANDLE_EXCEPTION() LOAD_OPLINE(); ZEND_VM_CONTINUE()\n"); - out($f,"#define HANDLE_EXCEPTION_LEAVE() LOAD_OPLINE(); ZEND_VM_LEAVE()\n"); - out($f,"#undef ZEND_VM_CONTINUE\n"); - out($f,"#undef ZEND_VM_RETURN\n"); - out($f,"#undef ZEND_VM_ENTER_EX\n"); - out($f,"#undef ZEND_VM_ENTER\n"); - out($f,"#undef ZEND_VM_LEAVE\n"); - out($f,"#undef ZEND_VM_DISPATCH\n"); - out($f,"#define ZEND_VM_CONTINUE() return 0\n"); - out($f,"#define ZEND_VM_RETURN() return -1\n"); - out($f,"#define ZEND_VM_ENTER_EX() return 1\n"); - out($f,"#define ZEND_VM_ENTER() return 1\n"); - out($f,"#define ZEND_VM_LEAVE() return 2\n"); - out($f,"#define ZEND_VM_INTERRUPT() return zend_interrupt_helper(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);\n"); - out($f,"#define ZEND_VM_DISPATCH(opcode, opline) return zend_vm_get_opcode_handler(opcode, opline)(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);\n\n"); - out($f,"\n"); - } - foreach ($export as $dsk) { - list($kind, $func, $name) = $dsk; - out($f, "ZEND_API int $func("); - if ($kind == "handler") { - out($f, "ZEND_OPCODE_HANDLER_ARGS)\n"); - $code = $opcodes[$opnames[$name]]['code']; - } else { - $h = $helpers[$name]; - if ($h['param'] == null) { - out($f, "ZEND_OPCODE_HANDLER_ARGS)\n"); - } else { - out($f, $h['param']. " ZEND_OPCODE_HANDLER_ARGS_DC)\n"); - } - $code = $h['code']; - } - $done = 0; - if (ZEND_VM_KIND == ZEND_VM_KIND_CALL) { - if ($kind == "handler") { - $op = $opcodes[$opnames[$name]]; - if (isset($op['op1']["ANY"]) && isset($op['op2']["ANY"])) { - out($f, "{\n\treturn ".$name.(ZEND_VM_SPEC?"_SPEC":"")."_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);\n}\n\n"); - $done = 1; - } - } else if ($helpers[$name]["param"] == null) { - $h = $helpers[$name]; - if (isset($h['op1']["ANY"]) && isset($h['op2']["ANY"])) { - out($f, "{\n\treturn ".$name.(ZEND_VM_SPEC?"_SPEC":"")."(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);\n}\n\n"); - $done = 1; - } - } - } - if (!$done) { - gen_code($f, 0, ZEND_VM_KIND_CALL, 1, $code, 'ANY', 'ANY', $name); - } - } - - fclose($f); - echo "zend_vm_execute.h generated successfully.\n"; + global $definition_file, $skeleton_file, $executor_file, + $op_types, $list, $opcodes, $helpers, $params, $opnames, + $vm_op_flags, $used_extra_spec; + + // Load definition file + $in = @file($def); + if (!$in) { + die("ERROR: Can not open definition file '$def'\n"); + } + // We need absolute path to definition file to use it in #line directives + $definition_file = realpath($def); + + // Load skeleton file + $skl = @file($skel); + if (!$skl) { + die("ERROR: Can not open skeleton file '$skel'\n"); + } + // We need absolute path to skeleton file to use it in #line directives + $skeleton_file = realpath($skel); + + // Parse definition file into tree + $lineno = 0; + $handler = null; + $helper = null; + $max_opcode_len = 0; + $max_opcode = 0; + $extra_num = 256; + $export = array(); + foreach ($in as $line) { + ++$lineno; + if (strpos($line,"ZEND_VM_HANDLER(") === 0 || + strpos($line,"ZEND_VM_INLINE_HANDLER(") === 0 || + strpos($line,"ZEND_VM_HOT_HANDLER(") === 0 || + strpos($line,"ZEND_VM_HOT_NOCONST_HANDLER(") === 0 || + strpos($line,"ZEND_VM_HOT_NOCONSTCONST_HANDLER(") === 0 || + strpos($line,"ZEND_VM_HOT_SEND_HANDLER(") === 0 || + strpos($line,"ZEND_VM_HOT_OBJ_HANDLER(") === 0 || + strpos($line,"ZEND_VM_COLD_HANDLER(") === 0 || + strpos($line,"ZEND_VM_COLD_CONST_HANDLER(") === 0 || + strpos($line,"ZEND_VM_COLD_CONSTCONST_HANDLER(") === 0) { + // Parsing opcode handler's definition + if (preg_match( + "/^ZEND_VM_(HOT_|INLINE_|HOT_OBJ_|HOT_SEND_|HOT_NOCONST_|HOT_NOCONSTCONST_|COLD_|COLD_CONST_|COLD_CONSTCONST_)?HANDLER\(\s*([0-9]+)\s*,\s*([A-Z_]+)\s*,\s*([A-Z_|]+)\s*,\s*([A-Z_|]+)\s*(,\s*([A-Z_|]+)\s*)?(,\s*SPEC\(([A-Z_|=,]+)\)\s*)?\)/", + $line, + $m) == 0) { + die("ERROR ($def:$lineno): Invalid ZEND_VM_HANDLER definition.\n"); + } + $hot = !empty($m[1]) ? $m[1] : false; + $code = (int)$m[2]; + $op = $m[3]; + $len = strlen($op); + $op1 = parse_operand_spec($def, $lineno, $m[4], $flags1); + $op2 = parse_operand_spec($def, $lineno, $m[5], $flags2); + $flags = $flags1 | ($flags2 << 8); + if (!empty($m[7])) { + $flags |= parse_ext_spec($def, $lineno, $m[7]); + } + + if ($len > $max_opcode_len) { + $max_opcode_len = $len; + } + if ($code > $max_opcode) { + $max_opcode = $code; + } + if (isset($opcodes[$code])) { + die("ERROR ($def:$lineno): Opcode with code '$code' is already defined.\n"); + } + if (isset($opnames[$op])) { + die("ERROR ($def:$lineno): Opcode with name '$op' is already defined.\n"); + } + $opcodes[$code] = array("op"=>$op,"op1"=>$op1,"op2"=>$op2,"code"=>"","flags"=>$flags,"hot"=>$hot); + if (isset($m[9])) { + $opcodes[$code]["spec"] = parse_spec_rules($def, $lineno, $m[9]); + if (isset($opcodes[$code]["spec"]["NO_CONST_CONST"])) { + $opcodes[$code]["flags"] |= $vm_op_flags["ZEND_VM_NO_CONST_CONST"]; + } + if (isset($opcodes[$code]["spec"]["COMMUTATIVE"])) { + $opcodes[$code]["flags"] |= $vm_op_flags["ZEND_VM_COMMUTATIVE"]; + } + } + $opnames[$op] = $code; + $handler = $code; + $helper = null; + $list[$lineno] = array("handler"=>$handler); + } else if (strpos($line,"ZEND_VM_TYPE_SPEC_HANDLER(") === 0 || + strpos($line,"ZEND_VM_INLINE_TYPE_SPEC_HANDLER(") === 0 || + strpos($line,"ZEND_VM_HOT_TYPE_SPEC_HANDLER(") === 0 || + strpos($line,"ZEND_VM_HOT_NOCONST_TYPE_SPEC_HANDLER(") === 0 || + strpos($line,"ZEND_VM_HOT_NOCONSTCONST_TYPE_SPEC_HANDLER(") === 0 || + strpos($line,"ZEND_VM_HOT_SEND_TYPE_SPEC_HANDLER(") === 0 || + strpos($line,"ZEND_VM_HOT_OBJ_TYPE_SPEC_HANDLER(") === 0) { + // Parsing opcode handler's definition + if (preg_match( + "/^ZEND_VM_(HOT_|INLINE_|HOT_OBJ_|HOT_SEND_|HOT_NOCONST_|HOT_NOCONSTCONST_)?TYPE_SPEC_HANDLER\(\s*([A-Z_]+)\s*,\s*((?:[^(,]|\([^()]*|(?R)*\))*),\s*([A-Za-z_]+)\s*,\s*([A-Z_|]+)\s*,\s*([A-Z_|]+)\s*(,\s*([A-Z_|]+)\s*)?(,\s*SPEC\(([A-Z_|=,]+)\)\s*)?\)/", + $line, + $m) == 0) { + die("ERROR ($def:$lineno): Invalid ZEND_VM_TYPE_HANDLER_HANDLER definition.\n"); + } + $hot = !empty($m[1]) ? $m[1] : false; + $orig_op = $m[2]; + if (!isset($opnames[$orig_op])) { + die("ERROR ($def:$lineno): Opcode with name '$orig_op' is not defined.\n"); + } + $orig_code = $opnames[$orig_op]; + $condition = $m[3]; + $code = $extra_num++; + $op = $m[4]; + $op1 = parse_operand_spec($def, $lineno, $m[5], $flags1); + $op2 = parse_operand_spec($def, $lineno, $m[6], $flags2); + $flags = $flags1 | ($flags2 << 8); + if (!empty($m[8])) { + $flags |= parse_ext_spec($def, $lineno, $m[8]); + } + + if (isset($opcodes[$code])) { + die("ERROR ($def:$lineno): Opcode with name '$code' is already defined.\n"); + } + $opcodes[$orig_code]['type_spec'][$code] = $condition; + $used_extra_spec["TYPE"] = 1; + $opcodes[$code] = array("op"=>$op,"op1"=>$op1,"op2"=>$op2,"code"=>"","flags"=>$flags,"hot"=>$hot,"is_type_spec"=>true); + if (isset($m[10])) { + $opcodes[$code]["spec"] = parse_spec_rules($def, $lineno, $m[10]); + if (isset($opcodes[$code]["spec"]["NO_CONST_CONST"])) { + $opcodes[$code]["flags"] |= $vm_op_flags["ZEND_VM_NO_CONST_CONST"]; + } + if (isset($opcodes[$code]["spec"]["COMMUTATIVE"])) { + $opcodes[$code]["flags"] |= $vm_op_flags["ZEND_VM_COMMUTATIVE"]; + } + } + $opnames[$op] = $code; + $handler = $code; + $helper = null; + $list[$lineno] = array("handler"=>$handler); + } else if (strpos($line,"ZEND_VM_HELPER(") === 0 || + strpos($line,"ZEND_VM_INLINE_HELPER(") === 0 || + strpos($line,"ZEND_VM_COLD_HELPER(") === 0 || + strpos($line,"ZEND_VM_HOT_HELPER(") === 0) { + // Parsing helper's definition + if (preg_match( + "/^ZEND_VM(_INLINE|_COLD|_HOT)?_HELPER\(\s*([A-Za-z_]+)\s*,\s*([A-Z_|]+)\s*,\s*([A-Z_|]+)\s*(?:,\s*SPEC\(([A-Z_|=,]+)\)\s*)?(?:,\s*([^)]*)\s*)?\)/", + $line, + $m) == 0) { + die("ERROR ($def:$lineno): Invalid ZEND_VM_HELPER definition.\n"); + } + $inline = !empty($m[1]) && $m[1] === "_INLINE"; + $cold = !empty($m[1]) && $m[1] === "_COLD"; + $hot = !empty($m[1]) && $m[1] === "_HOT"; + $helper = $m[2]; + $op1 = parse_operand_spec($def, $lineno, $m[3], $flags1); + $op2 = parse_operand_spec($def, $lineno, $m[4], $flags2); + $param = isset($m[6]) ? $m[6] : null; + if (isset($helpers[$helper])) { + die("ERROR ($def:$lineno): Helper with name '$helper' is already defined.\n"); + } + + // Store parameters + if (ZEND_VM_KIND == ZEND_VM_KIND_GOTO + || ZEND_VM_KIND == ZEND_VM_KIND_SWITCH + || (ZEND_VM_KIND == ZEND_VM_KIND_HYBRID && $hot)) { + foreach (explode(",", $param) as $p) { + $p = trim($p); + if ($p !== "") { + $params[$p] = 1; + } + } + } + + $helpers[$helper] = array("op1"=>$op1,"op2"=>$op2,"param"=>$param,"code"=>"","inline"=>$inline,"cold"=>$cold,"hot"=>$hot); + + if (!empty($m[5])) { + $helpers[$helper]["spec"] = parse_spec_rules($def, $lineno, $m[5]); + } + + $handler = null; + $list[$lineno] = array("helper"=>$helper); + } else if (strpos($line,"ZEND_VM_EXPORT_HANDLER(") === 0) { + if (preg_match( + "/^ZEND_VM_EXPORT_HANDLER\(\s*([A-Za-z_]+)\s*,\s*([A-Z_]+)\s*\)/", + $line, + $m) == 0) { + die("ERROR ($def:$lineno): Invalid ZEND_VM_EXPORT_HANDLER definition.\n"); + } + if (!isset($opnames[$m[2]])) { + die("ERROR ($def:$lineno): opcode '{$m[2]}' is not defined.\n"); + } + $export[] = array("handler",$m[1],$m[2]); + } else if (strpos($line,"ZEND_VM_EXPORT_HELPER(") === 0) { + if (preg_match( + "/^ZEND_VM_EXPORT_HELPER\(\s*([A-Za-z_]+)\s*,\s*([A-Za-z_]+)\s*\)/", + $line, + $m) == 0) { + die("ERROR ($def:$lineno): Invalid ZEND_VM_EXPORT_HELPER definition.\n"); + } + if (!isset($helpers[$m[2]])) { + die("ERROR ($def:$lineno): helper '{$m[2]}' is not defined.\n"); + } + $export[] = array("helper",$m[1],$m[2]); + } else if (strpos($line,"ZEND_VM_DEFINE_OP(") === 0) { + if (preg_match( + "/^ZEND_VM_DEFINE_OP\(\s*([0-9]+)\s*,\s*([A-Z_]+)\s*\);/", + $line, + $m) == 0) { + die("ERROR ($def:$lineno): Invalid ZEND_VM_DEFINE_OP definition.\n"); + } + $code = (int)$m[1]; + $op = $m[2]; + $len = strlen($op); + + if ($len > $max_opcode_len) { + $max_opcode_len = $len; + } + if ($code > $max_opcode) { + $max_opcode = $code; + } + if (isset($opcodes[$code])) { + die("ERROR ($def:$lineno): Opcode with code '$code' is already defined.\n"); + } + if (isset($opnames[$op])) { + die("ERROR ($def:$lineno): Opcode with name '$op' is already defined.\n"); + } + $opcodes[$code] = array("op"=>$op,"code"=>""); + $opnames[$op] = $code; + } else if ($handler !== null) { + // Add line of code to current opcode handler + $opcodes[$handler]["code"] .= $line; + } else if ($helper !== null) { + // Add line of code to current helper + $helpers[$helper]["code"] .= $line; + } + } + + ksort($opcodes); + + // Search for opcode handlers those are used by other opcode handlers + foreach ($opcodes as $dsc) { + if (preg_match("/^\s*{\s*ZEND_VM_DISPATCH_TO_HANDLER\(\s*([A-Z_]*)\s*\)\s*;\s*}\s*/", $dsc["code"], $m)) { + $op = $m[1]; + if (!isset($opnames[$op])) { + die("ERROR ($def:$lineno): Opcode with name '$op' is not defined.\n"); + } + $opcodes[$opnames[$dsc['op']]]['alias'] = $op; + if (!ZEND_VM_SPEC && ZEND_VM_KIND == ZEND_VM_KIND_SWITCH) { + $code = $opnames[$op]; + $opcodes[$code]['use'] = 1; + } + } else if (preg_match_all("/ZEND_VM_DISPATCH_TO_HANDLER\(\s*([A-Z_]*)\s*\)/m", $dsc["code"], $mm, PREG_SET_ORDER)) { + foreach ($mm as $m) { + $op = $m[1]; + if (!isset($opnames[$op])) { + die("ERROR ($def:$lineno): Opcode with name '$op' is not defined.\n"); + } + $code = $opnames[$op]; + $opcodes[$code]['use'] = 1; + } + } + } + + // Generate opcode #defines (zend_vm_opcodes.h) + $code_len = strlen((string)$max_opcode); + $f = fopen(__DIR__ . "/zend_vm_opcodes.h", "w+") or die("ERROR: Cannot create zend_vm_opcodes.h\n"); + + // Insert header + out($f, HEADER_TEXT); + fputs($f, "#ifndef ZEND_VM_OPCODES_H\n#define ZEND_VM_OPCODES_H\n\n"); + fputs($f, "#define ZEND_VM_SPEC\t\t" . ZEND_VM_SPEC . "\n"); + fputs($f, "#define ZEND_VM_LINES\t\t" . ZEND_VM_LINES . "\n"); + fputs($f, "#define ZEND_VM_KIND_CALL\t" . ZEND_VM_KIND_CALL . "\n"); + fputs($f, "#define ZEND_VM_KIND_SWITCH\t" . ZEND_VM_KIND_SWITCH . "\n"); + fputs($f, "#define ZEND_VM_KIND_GOTO\t" . ZEND_VM_KIND_GOTO . "\n"); + fputs($f, "#define ZEND_VM_KIND_HYBRID\t" . ZEND_VM_KIND_HYBRID . "\n"); + if ($GLOBALS["vm_kind_name"][ZEND_VM_KIND] === "ZEND_VM_KIND_HYBRID") { + fputs($f, "/* HYBRID requires support for computed GOTO and global register variables*/\n"); + fputs($f, "#if (defined(__GNUC__) && defined(HAVE_GCC_GLOBAL_REGS))\n"); + fputs($f, "# define ZEND_VM_KIND\t\tZEND_VM_KIND_HYBRID\n"); + fputs($f, "#else\n"); + fputs($f, "# define ZEND_VM_KIND\t\tZEND_VM_KIND_CALL\n"); + fputs($f, "#endif\n"); + } else { + fputs($f, "#define ZEND_VM_KIND\t\t" . $GLOBALS["vm_kind_name"][ZEND_VM_KIND] . "\n"); + } + fputs($f, "\n"); + foreach($vm_op_flags as $name => $val) { + fprintf($f, "#define %-24s 0x%08x\n", $name, $val); + } + fputs($f, "#define ZEND_VM_OP1_FLAGS(flags) (flags & 0xff)\n"); + fputs($f, "#define ZEND_VM_OP2_FLAGS(flags) ((flags >> 8) & 0xff)\n"); + fputs($f, "\n"); + fputs($f, "BEGIN_EXTERN_C()\n\n"); + fputs($f, "ZEND_API const char* ZEND_FASTCALL zend_get_opcode_name(zend_uchar opcode);\n"); + fputs($f, "ZEND_API uint32_t ZEND_FASTCALL zend_get_opcode_flags(zend_uchar opcode);\n\n"); + fputs($f, "END_EXTERN_C()\n\n"); + + foreach ($opcodes as $code => $dsc) { + $code = str_pad((string)$code,$code_len," ",STR_PAD_LEFT); + $op = str_pad($dsc["op"],$max_opcode_len); + if ($code <= $max_opcode) { + fputs($f,"#define $op $code\n"); + } + } + + $code = str_pad((string)$max_opcode,$code_len," ",STR_PAD_LEFT); + $op = str_pad("ZEND_VM_LAST_OPCODE",$max_opcode_len); + fputs($f,"\n#define $op $code\n"); + + fputs($f, "\n#endif\n"); + fclose($f); + echo "zend_vm_opcodes.h generated successfully.\n"; + + // zend_vm_opcodes.c + $f = fopen(__DIR__ . "/zend_vm_opcodes.c", "w+") or die("ERROR: Cannot create zend_vm_opcodes.c\n"); + + // Insert header + out($f, HEADER_TEXT); + fputs($f,"#include <stdio.h>\n"); + fputs($f,"#include <zend.h>\n"); + fputs($f,"#include <zend_vm_opcodes.h>\n\n"); + + fputs($f,"static const char *zend_vm_opcodes_names[".($max_opcode + 1)."] = {\n"); + for ($i = 0; $i <= $max_opcode; $i++) { + fputs($f,"\t".(isset($opcodes[$i]["op"])?'"'.$opcodes[$i]["op"].'"':"NULL").",\n"); + } + fputs($f, "};\n\n"); + + fputs($f,"static uint32_t zend_vm_opcodes_flags[".($max_opcode + 1)."] = {\n"); + for ($i = 0; $i <= $max_opcode; $i++) { + fprintf($f, "\t0x%08x,\n", isset($opcodes[$i]["flags"]) ? $opcodes[$i]["flags"] : 0); + } + fputs($f, "};\n\n"); + + fputs($f, "ZEND_API const char* ZEND_FASTCALL zend_get_opcode_name(zend_uchar opcode) {\n"); + fputs($f, "\tif (UNEXPECTED(opcode > ZEND_VM_LAST_OPCODE)) {\n"); + fputs($f, "\t\treturn NULL;\n"); + fputs($f, "\t}\n"); + fputs($f, "\treturn zend_vm_opcodes_names[opcode];\n"); + fputs($f, "}\n"); + + fputs($f, "ZEND_API uint32_t ZEND_FASTCALL zend_get_opcode_flags(zend_uchar opcode) {\n"); + fputs($f, "\tif (UNEXPECTED(opcode > ZEND_VM_LAST_OPCODE)) {\n"); + fputs($f, "\t\topcode = ZEND_NOP;\n"); + fputs($f, "\t}\n"); + fputs($f, "\treturn zend_vm_opcodes_flags[opcode];\n"); + fputs($f, "}\n"); + + fclose($f); + echo "zend_vm_opcodes.c generated successfully.\n"; + + // Generate zend_vm_execute.h + $f = fopen(__DIR__ . "/zend_vm_execute.h", "w+") or die("ERROR: Cannot create zend_vm_execute.h\n"); + $executor_file = realpath(__DIR__ . "/zend_vm_execute.h"); + + // Insert header + out($f, HEADER_TEXT); + + out($f, "#ifdef ZEND_WIN32\n"); + // Suppress free_op1 warnings on Windows + out($f, "# pragma warning(disable : 4101)\n"); + if (ZEND_VM_SPEC) { + // Suppress (<non-zero constant> || <expression>) warnings on windows + out($f, "# pragma warning(once : 6235)\n"); + // Suppress (<zero> && <expression>) warnings on windows + out($f, "# pragma warning(once : 6237)\n"); + // Suppress (<non-zero constant> && <expression>) warnings on windows + out($f, "# pragma warning(once : 6239)\n"); + // Suppress (<expression> && <non-zero constant>) warnings on windows + out($f, "# pragma warning(once : 6240)\n"); + // Suppress (<non-zero constant> || <non-zero constant>) warnings on windows + out($f, "# pragma warning(once : 6285)\n"); + // Suppress (<non-zero constant> || <expression>) warnings on windows + out($f, "# pragma warning(once : 6286)\n"); + // Suppress constant with constant comparison warnings on windows + out($f, "# pragma warning(once : 6326)\n"); + } + out($f, "#endif\n"); + + // Support for ZEND_USER_OPCODE + out($f, "static user_opcode_handler_t zend_user_opcode_handlers[256] = {\n"); + for ($i = 0; $i < 255; ++$i) { + out($f, "\t(user_opcode_handler_t)NULL,\n"); + } + out($f, "\t(user_opcode_handler_t)NULL\n};\n\n"); + + out($f, "static zend_uchar zend_user_opcodes[256] = {"); + for ($i = 0; $i < 255; ++$i) { + if ($i % 16 == 1) out($f, "\n\t"); + out($f, "$i,"); + } + out($f, "255\n};\n\n"); + + // Generate specialized executor + gen_executor($f, $skl, ZEND_VM_SPEC, ZEND_VM_KIND, "execute", "zend_vm_init"); + out($f, "\n"); + + // Generate zend_vm_get_opcode_handler() function + out($f, "static const void* ZEND_FASTCALL zend_vm_get_opcode_handler_ex(uint32_t spec, const zend_op* op)\n"); + out($f, "{\n"); + if (!ZEND_VM_SPEC) { + out($f, "\treturn zend_opcode_handlers[spec];\n"); + } else { + out($f, "\tstatic const int zend_vm_decode[] = {\n"); + out($f, "\t\t_UNUSED_CODE, /* 0 = IS_UNUSED */\n"); + out($f, "\t\t_CONST_CODE, /* 1 = IS_CONST */\n"); + out($f, "\t\t_TMP_CODE, /* 2 = IS_TMP_VAR */\n"); + out($f, "\t\t_UNUSED_CODE, /* 3 */\n"); + out($f, "\t\t_VAR_CODE, /* 4 = IS_VAR */\n"); + out($f, "\t\t_UNUSED_CODE, /* 5 */\n"); + out($f, "\t\t_UNUSED_CODE, /* 6 */\n"); + out($f, "\t\t_UNUSED_CODE, /* 7 */\n"); + out($f, "\t\t_CV_CODE /* 8 = IS_CV */\n"); + out($f, "\t};\n"); + out($f, "\tuint32_t offset = 0;\n"); + out($f, "\tif (spec & SPEC_RULE_OP1) offset = offset * 5 + zend_vm_decode[op->op1_type];\n"); + out($f, "\tif (spec & SPEC_RULE_OP2) offset = offset * 5 + zend_vm_decode[op->op2_type];\n"); + + if (isset($used_extra_spec["OP_DATA"]) || + isset($used_extra_spec["RETVAL"]) || + isset($used_extra_spec["QUICK_ARG"]) || + isset($used_extra_spec["SMART_BRANCH"]) || + isset($used_extra_spec["ISSET"])) { + + $else = ""; + out($f, "\tif (spec & SPEC_EXTRA_MASK) {\n"); + + if (isset($used_extra_spec["RETVAL"])) { + out($f, "\t\t{$else}if (spec & SPEC_RULE_RETVAL) {\n"); + out($f, "\t\t\toffset = offset * 2 + (op->result_type != IS_UNUSED);\n"); + $else = "} else "; + } + if (isset($used_extra_spec["QUICK_ARG"])) { + out($f, "\t\t{$else}if (spec & SPEC_RULE_QUICK_ARG) {\n"); + out($f, "\t\t\toffset = offset * 2 + (op->op2.num <= MAX_ARG_FLAG_NUM);\n"); + $else = "} else "; + } + if (isset($used_extra_spec["OP_DATA"])) { + out($f, "\t\t{$else}if (spec & SPEC_RULE_OP_DATA) {\n"); + out($f, "\t\t\toffset = offset * 5 + zend_vm_decode[(op + 1)->op1_type];\n"); + $else = "} else "; + } + if (isset($used_extra_spec["ISSET"])) { + out($f, "\t\t{$else}if (spec & SPEC_RULE_ISSET) {\n"); + out($f, "\t\t\toffset = offset * 2 + (op->extended_value & ZEND_ISEMPTY);\n"); + $else = "} else "; + } + if (isset($used_extra_spec["SMART_BRANCH"])) { + out($f, "\t\t{$else}if (spec & SPEC_RULE_SMART_BRANCH) {\n"); + out($f, "\t\t\toffset = offset * 3;\n"); + out($f, "\t\t\tif ((op+1)->opcode == ZEND_JMPZ) {\n"); + out($f, "\t\t\t\toffset += 1;\n"); + out($f, "\t\t\t} else if ((op+1)->opcode == ZEND_JMPNZ) {\n"); + out($f, "\t\t\t\toffset += 2;\n"); + out($f, "\t\t\t}\n"); + $else = "} else "; + } + if ($else !== "") { + out($f, "\t\t}\n"); + } + out($f, "\t}\n"); + } + out($f, "\treturn zend_opcode_handlers[(spec & SPEC_START_MASK) + offset];\n"); + } + out($f, "}\n\n"); + out($f, "#if (ZEND_VM_KIND != ZEND_VM_KIND_HYBRID) || !ZEND_VM_SPEC\n"); + out($f, "static const void *zend_vm_get_opcode_handler(zend_uchar opcode, const zend_op* op)\n"); + out($f, "{\n"); + if (!ZEND_VM_SPEC) { + out($f, "\treturn zend_vm_get_opcode_handler_ex(opcode, op);\n"); + } else { + out($f, "\treturn zend_vm_get_opcode_handler_ex(zend_spec_handlers[opcode], op);\n"); + } + out($f, "}\n"); + out($f, "#endif\n\n"); + + if (ZEND_VM_KIND == ZEND_VM_KIND_HYBRID) { + // Generate zend_vm_get_opcode_handler_func() function + out($f, "#if ZEND_VM_KIND == ZEND_VM_KIND_HYBRID\n"); + out($f,"static const void *zend_vm_get_opcode_handler_func(zend_uchar opcode, const zend_op* op)\n"); + out($f, "{\n"); + out($f, "\tuint32_t spec = zend_spec_handlers[opcode];\n"); + if (!ZEND_VM_SPEC) { + out($f, "\treturn zend_opcode_handler_funcs[spec];\n"); + } else { + out($f, "\tstatic const int zend_vm_decode[] = {\n"); + out($f, "\t\t_UNUSED_CODE, /* 0 = IS_UNUSED */\n"); + out($f, "\t\t_CONST_CODE, /* 1 = IS_CONST */\n"); + out($f, "\t\t_TMP_CODE, /* 2 = IS_TMP_VAR */\n"); + out($f, "\t\t_UNUSED_CODE, /* 3 */\n"); + out($f, "\t\t_VAR_CODE, /* 4 = IS_VAR */\n"); + out($f, "\t\t_UNUSED_CODE, /* 5 */\n"); + out($f, "\t\t_UNUSED_CODE, /* 6 */\n"); + out($f, "\t\t_UNUSED_CODE, /* 7 */\n"); + out($f, "\t\t_CV_CODE /* 8 = IS_CV */\n"); + out($f, "\t};\n"); + out($f, "\tuint32_t offset = 0;\n"); + out($f, "\tif (spec & SPEC_RULE_OP1) offset = offset * 5 + zend_vm_decode[op->op1_type];\n"); + out($f, "\tif (spec & SPEC_RULE_OP2) offset = offset * 5 + zend_vm_decode[op->op2_type];\n"); + + if (isset($used_extra_spec["OP_DATA"]) || + isset($used_extra_spec["RETVAL"]) || + isset($used_extra_spec["QUICK_ARG"]) || + isset($used_extra_spec["SMART_BRANCH"]) || + isset($used_extra_spec["ISSET"])) { + + $else = ""; + out($f, "\tif (spec & SPEC_EXTRA_MASK) {\n"); + + if (isset($used_extra_spec["OP_DATA"])) { + out($f, "\t\t{$else}if (spec & SPEC_RULE_OP_DATA) offset = offset * 5 + zend_vm_decode[(op + 1)->op1_type];\n"); + $else = "else "; + } + if (isset($used_extra_spec["RETVAL"])) { + out($f, "\t\t{$else}if (spec & SPEC_RULE_RETVAL) offset = offset * 2 + (op->result_type != IS_UNUSED);\n"); + $else = "else "; + } + if (isset($used_extra_spec["QUICK_ARG"])) { + out($f, "\t\t{$else}if (spec & SPEC_RULE_QUICK_ARG) offset = offset * 2 + (op->op2.num <= MAX_ARG_FLAG_NUM);\n"); + $else = "else "; + } + if (isset($used_extra_spec["SMART_BRANCH"])) { + out($f, "\t\t{$else}if (spec & SPEC_RULE_SMART_BRANCH) {\n"); + out($f, "\t\t\toffset = offset * 3;\n"); + out($f, "\t\t\tif ((op+1)->opcode == ZEND_JMPZ) {\n"); + out($f, "\t\t\t\toffset += 1;\n"); + out($f, "\t\t\t} else if ((op+1)->opcode == ZEND_JMPNZ) {\n"); + out($f, "\t\t\t\toffset += 2;\n"); + out($f, "\t\t\t}\n"); + out($f, "\t\t}\n"); + $else = "else "; + } + if (isset($used_extra_spec["ISSET"])) { + out($f, "\t\t{$else}if (spec & SPEC_RULE_ISSET) offset = offset * 2 + (op->extended_value & ZEND_ISEMPTY);\n"); + $else = "else "; + } + out($f, "\t}\n"); + } + + out($f, "\treturn zend_opcode_handler_funcs[(spec & SPEC_START_MASK) + offset];\n"); + } + out($f, "}\n\n"); + out($f, "#endif\n\n"); + } + + // Generate zend_vm_get_opcode_handler() function + out($f, "ZEND_API void ZEND_FASTCALL zend_vm_set_opcode_handler(zend_op* op)\n"); + out($f, "{\n"); + out($f, "\tzend_uchar opcode = zend_user_opcodes[op->opcode];\n"); + if (!ZEND_VM_SPEC) { + out($f, "\top->handler = zend_vm_get_opcode_handler(opcode, op);\n"); + } else { + out($f, "\n"); + out($f, "\tif (zend_spec_handlers[op->opcode] & SPEC_RULE_COMMUTATIVE) {\n"); + out($f, "\t\tif (op->op1_type < op->op2_type) {\n"); + out($f, "\t\t\tzend_swap_operands(op);\n"); + out($f, "\t\t}\n"); + out($f, "\t}\n"); + out($f, "\top->handler = zend_vm_get_opcode_handler_ex(zend_spec_handlers[opcode], op);\n"); + } + out($f, "}\n\n"); + + // Generate zend_vm_set_opcode_handler_ex() function + out($f, "ZEND_API void ZEND_FASTCALL zend_vm_set_opcode_handler_ex(zend_op* op, uint32_t op1_info, uint32_t op2_info, uint32_t res_info)\n"); + out($f, "{\n"); + out($f, "\tzend_uchar opcode = zend_user_opcodes[op->opcode];\n"); + if (!ZEND_VM_SPEC) { + out($f, "\top->handler = zend_vm_get_opcode_handler_ex(opcode, op);\n"); + } else { + out($f, "\tuint32_t spec = zend_spec_handlers[opcode];\n"); + if (isset($used_extra_spec["TYPE"])) { + out($f, "\tswitch (opcode) {\n"); + foreach($opcodes as $code => $dsc) { + if (isset($dsc['type_spec'])) { + $orig_op = $dsc['op']; + out($f, "\t\tcase $orig_op:\n"); + if (isset($dsc["spec"]["COMMUTATIVE"])) { + out($f, "\t\t\tif (op->op1_type < op->op2_type) {\n"); + out($f, "\t\t\t\tzend_swap_operands(op);\n"); + out($f, "\t\t\t}\n"); + } + $first = true; + foreach($dsc['type_spec'] as $code => $condition) { + $condition = format_condition($condition); + if ($first) { + out($f, "\t\t\tif $condition {\n"); + $first = false; + } else { + out($f, "\t\t\t} else if $condition {\n"); + } + $spec_dsc = $opcodes[$code]; + if (isset($spec_dsc["spec"]["NO_CONST_CONST"])) { + out($f, "\t\t\t\tif (op->op1_type == IS_CONST && op->op2_type == IS_CONST) {\n"); + out($f, "\t\t\t\t\tbreak;\n"); + out($f, "\t\t\t\t}\n"); + } + out($f, "\t\t\t\tspec = ${spec_dsc['spec_code']};\n"); + if (isset($spec_dsc["spec"]["COMMUTATIVE"]) && !isset($dsc["spec"]["COMMUTATIVE"])) { + out($f, "\t\t\t\tif (op->op1_type < op->op2_type) {\n"); + out($f, "\t\t\t\t\tzend_swap_operands(op);\n"); + out($f, "\t\t\t\t}\n"); + } + } + if (!$first) { + out($f, "\t\t\t}\n"); + } + out($f, "\t\t\tbreak;\n"); + } + } + $has_commutative = false; + foreach($opcodes as $code => $dsc) { + if (!isset($dsc['is_type_spec']) && + !isset($dsc['type_spec']) && + isset($dsc["spec"]["COMMUTATIVE"])) { + $orig_op = $dsc['op']; + out($f, "\t\tcase $orig_op:\n"); + $has_commutative = true; + } + } + if ($has_commutative) { + out($f, "\t\t\tif (op->op1_type < op->op2_type) {\n"); + out($f, "\t\t\t\tzend_swap_operands(op);\n"); + out($f, "\t\t\t}\n"); + out($f, "\t\t\tbreak;\n"); + out($f, "\t\tcase ZEND_USER_OPCODE:\n"); + out($f, "\t\t\tif (zend_spec_handlers[op->opcode] & SPEC_RULE_COMMUTATIVE) {\n"); + out($f, "\t\t\t\tif (op->op1_type < op->op2_type) {\n"); + out($f, "\t\t\t\t\tzend_swap_operands(op);\n"); + out($f, "\t\t\t\t}\n"); + out($f, "\t\t\t}\n"); + out($f, "\t\t\tbreak;\n"); + } + out($f, "\t\tdefault:\n"); + out($f, "\t\t\tbreak;\n"); + out($f, "\t}\n"); + } + out($f, "\top->handler = zend_vm_get_opcode_handler_ex(spec, op);\n"); + } + out($f, "}\n\n"); + + // Generate zend_vm_call_opcode_handler() function + if (ZEND_VM_KIND == ZEND_VM_KIND_CALL || ZEND_VM_KIND == ZEND_VM_KIND_HYBRID) { + out($f, "ZEND_API int ZEND_FASTCALL zend_vm_call_opcode_handler(zend_execute_data* ex)\n"); + out($f, "{\n"); + if (ZEND_VM_KIND == ZEND_VM_KIND_HYBRID) { + out($f,"#if (ZEND_VM_KIND == ZEND_VM_KIND_HYBRID)\n"); + out($f, "\topcode_handler_t handler;\n"); + out($f,"#endif\n"); + } + out($f, "\tint ret;\n"); + out($f, "#ifdef ZEND_VM_IP_GLOBAL_REG\n"); + out($f, "\tconst zend_op *orig_opline = opline;\n"); + out($f, "#endif\n"); + out($f, "#ifdef ZEND_VM_FP_GLOBAL_REG\n"); + out($f, "\tzend_execute_data *orig_execute_data = execute_data;\n"); + out($f, "\texecute_data = ex;\n"); + out($f, "#else\n"); + out($f, "\tzend_execute_data *execute_data = ex;\n"); + out($f, "#endif\n"); + out($f, "\n"); + out($f, "\tLOAD_OPLINE();\n"); + out($f,"#if defined(ZEND_VM_FP_GLOBAL_REG) && defined(ZEND_VM_IP_GLOBAL_REG)\n"); + if (ZEND_VM_KIND == ZEND_VM_KIND_HYBRID) { + out($f,"#if (ZEND_VM_KIND == ZEND_VM_KIND_HYBRID)\n"); + out($f, "\thandler = (opcode_handler_t)zend_vm_get_opcode_handler_func(zend_user_opcodes[opline->opcode], opline);\n"); + out($f, "\thandler(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);\n"); + out($f, "\tif (EXPECTED(opline != &hybrid_halt_op)) {\n"); + out($f,"#else\n"); + } + out($f, "\t((opcode_handler_t)OPLINE->handler)(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);\n"); + if (ZEND_VM_KIND == ZEND_VM_KIND_HYBRID) { + out($f, "\tif (EXPECTED(opline)) {\n"); + out($f,"#endif\n"); + } else { + out($f, "\tif (EXPECTED(opline)) {\n"); + } + out($f, "\t\tret = execute_data != ex ? (int)(execute_data->prev_execute_data != ex) + 1 : 0;\n"); + out($f, "\t\tSAVE_OPLINE();\n"); + out($f, "\t} else {\n"); + out($f, "\t\tret = -1;\n"); + out($f, "\t}\n"); + out($f, "#else\n"); + out($f, "\tret = ((opcode_handler_t)OPLINE->handler)(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);\n"); + out($f, "\tSAVE_OPLINE();\n"); + out($f, "#endif\n"); + out($f, "#ifdef ZEND_VM_FP_GLOBAL_REG\n"); + out($f, "\texecute_data = orig_execute_data;\n"); + out($f, "#endif\n"); + out($f, "#ifdef ZEND_VM_IP_GLOBAL_REG\n"); + out($f, "\topline = orig_opline;\n"); + out($f, "#endif\n"); + out($f, "\treturn ret;\n"); + out($f, "}\n\n"); + } else { + out($f, "ZEND_API int ZEND_FASTCALL zend_vm_call_opcode_handler(zend_execute_data* ex)\n"); + out($f, "{\n"); + out($f, "\tzend_error_noreturn(E_CORE_ERROR, \"zend_vm_call_opcode_handler() is not supported\");\n"); + out($f, "\treturn 0;\n"); + out($f, "}\n\n"); + } + + // Export handlers and helpers + if (count($export) > 0 && + ZEND_VM_KIND != ZEND_VM_KIND_CALL) { + out($f,"#undef OPLINE\n"); + out($f,"#undef DCL_OPLINE\n"); + out($f,"#undef USE_OPLINE\n"); + out($f,"#undef LOAD_OPLINE\n"); + out($f,"#undef LOAD_OPLINE_EX\n"); + out($f,"#undef LOAD_NEXT_OPLINE\n"); + out($f,"#undef SAVE_OPLINE\n"); + out($f,"#undef SAVE_OPLINE_EX\n"); + out($f,"#define OPLINE EX(opline)\n"); + out($f,"#define DCL_OPLINE\n"); + out($f,"#define USE_OPLINE const zend_op *opline = EX(opline);\n"); + out($f,"#define LOAD_OPLINE()\n"); + out($f,"#define LOAD_OPLINE_EX()\n"); + out($f,"#define LOAD_NEXT_OPLINE() ZEND_VM_INC_OPCODE()\n"); + out($f,"#define SAVE_OPLINE()\n"); + out($f,"#define SAVE_OPLINE_EX()\n"); + out($f,"#undef HANDLE_EXCEPTION\n"); + out($f,"#undef HANDLE_EXCEPTION_LEAVE\n"); + out($f,"#define HANDLE_EXCEPTION() LOAD_OPLINE(); ZEND_VM_CONTINUE()\n"); + out($f,"#define HANDLE_EXCEPTION_LEAVE() LOAD_OPLINE(); ZEND_VM_LEAVE()\n"); + out($f,"#undef ZEND_VM_CONTINUE\n"); + out($f,"#undef ZEND_VM_RETURN\n"); + out($f,"#undef ZEND_VM_ENTER_EX\n"); + out($f,"#undef ZEND_VM_ENTER\n"); + out($f,"#undef ZEND_VM_LEAVE\n"); + out($f,"#undef ZEND_VM_DISPATCH\n"); + out($f,"#define ZEND_VM_CONTINUE() return 0\n"); + out($f,"#define ZEND_VM_RETURN() return -1\n"); + out($f,"#define ZEND_VM_ENTER_EX() return 1\n"); + out($f,"#define ZEND_VM_ENTER() return 1\n"); + out($f,"#define ZEND_VM_LEAVE() return 2\n"); + out($f,"#define ZEND_VM_INTERRUPT() return zend_interrupt_helper(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);\n"); + out($f,"#define ZEND_VM_DISPATCH(opcode, opline) return zend_vm_get_opcode_handler(opcode, opline)(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);\n\n"); + out($f,"\n"); + } + foreach ($export as $dsk) { + list($kind, $func, $name) = $dsk; + out($f, "ZEND_API int $func("); + if ($kind == "handler") { + out($f, "ZEND_OPCODE_HANDLER_ARGS)\n"); + $code = $opcodes[$opnames[$name]]['code']; + } else { + $h = $helpers[$name]; + if ($h['param'] == null) { + out($f, "ZEND_OPCODE_HANDLER_ARGS)\n"); + } else { + out($f, $h['param']. " ZEND_OPCODE_HANDLER_ARGS_DC)\n"); + } + $code = $h['code']; + } + $done = 0; + if (ZEND_VM_KIND == ZEND_VM_KIND_CALL) { + if ($kind == "handler") { + $op = $opcodes[$opnames[$name]]; + if (isset($op['op1']["ANY"]) && isset($op['op2']["ANY"])) { + out($f, "{\n\treturn ".$name.(ZEND_VM_SPEC?"_SPEC":"")."_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);\n}\n\n"); + $done = 1; + } + } else if ($helpers[$name]["param"] == null) { + $h = $helpers[$name]; + if (isset($h['op1']["ANY"]) && isset($h['op2']["ANY"])) { + out($f, "{\n\treturn ".$name.(ZEND_VM_SPEC?"_SPEC":"")."(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);\n}\n\n"); + $done = 1; + } + } + } + if (!$done) { + gen_code($f, 0, ZEND_VM_KIND_CALL, 1, $code, 'ANY', 'ANY', $name); + } + } + + fclose($f); + echo "zend_vm_execute.h generated successfully.\n"; } function usage() { - echo("\nUsage: php zend_vm_gen.php [options]\n". - "\nOptions:". - "\n --with-vm-kind=CALL|SWITCH|GOTO|HYBRID - select threading model (default is HYBRID)". - "\n --without-specializer - disable executor specialization". - "\n --with-lines - enable #line directives". - "\n\n"); + echo("\nUsage: php zend_vm_gen.php [options]\n". + "\nOptions:". + "\n --with-vm-kind=CALL|SWITCH|GOTO|HYBRID - select threading model (default is HYBRID)". + "\n --without-specializer - disable executor specialization". + "\n --with-lines - enable #line directives". + "\n\n"); } // Parse arguments for ($i = 1; $i < $argc; $i++) { - if (strpos($argv[$i],"--with-vm-kind=") === 0) { - $kind = substr($argv[$i], strlen("--with-vm-kind=")); - switch ($kind) { - case "CALL": - define("ZEND_VM_KIND", ZEND_VM_KIND_CALL); - break; - case "SWITCH": - define("ZEND_VM_KIND", ZEND_VM_KIND_SWITCH); - break; - case "GOTO": - define("ZEND_VM_KIND", ZEND_VM_KIND_GOTO); - break; - case "HYBRID": - define("ZEND_VM_KIND", ZEND_VM_KIND_HYBRID); - break; - default: - echo("ERROR: Invalid vm kind '$kind'\n"); - usage(); - die(); - } - } else if ($argv[$i] == "--without-specializer") { - // Disabling specialization - define("ZEND_VM_SPEC", 0); - } else if ($argv[$i] == "--with-lines") { - // Enabling debugging using original zend_vm_def.h - define("ZEND_VM_LINES", 1); - } else if ($argv[$i] == "--help") { - usage(); - exit(); - } else { - echo("ERROR: Invalid option '".$argv[$i]."'\n"); - usage(); - die(); - } + if (strpos($argv[$i],"--with-vm-kind=") === 0) { + $kind = substr($argv[$i], strlen("--with-vm-kind=")); + switch ($kind) { + case "CALL": + define("ZEND_VM_KIND", ZEND_VM_KIND_CALL); + break; + case "SWITCH": + define("ZEND_VM_KIND", ZEND_VM_KIND_SWITCH); + break; + case "GOTO": + define("ZEND_VM_KIND", ZEND_VM_KIND_GOTO); + break; + case "HYBRID": + define("ZEND_VM_KIND", ZEND_VM_KIND_HYBRID); + break; + default: + echo("ERROR: Invalid vm kind '$kind'\n"); + usage(); + die(); + } + } else if ($argv[$i] == "--without-specializer") { + // Disabling specialization + define("ZEND_VM_SPEC", 0); + } else if ($argv[$i] == "--with-lines") { + // Enabling debugging using original zend_vm_def.h + define("ZEND_VM_LINES", 1); + } else if ($argv[$i] == "--help") { + usage(); + exit(); + } else { + echo("ERROR: Invalid option '".$argv[$i]."'\n"); + usage(); + die(); + } } // Using defaults if (!defined("ZEND_VM_KIND")) { - // Using CALL threading by default - define("ZEND_VM_KIND", ZEND_VM_KIND_HYBRID); + // Using CALL threading by default + define("ZEND_VM_KIND", ZEND_VM_KIND_HYBRID); } if (!defined("ZEND_VM_SPEC")) { - // Using specialized executor by default - define("ZEND_VM_SPEC", 1); + // Using specialized executor by default + define("ZEND_VM_SPEC", 1); } if (!defined("ZEND_VM_LINES")) { - // Disabling #line directives - define("ZEND_VM_LINES", 0); + // Disabling #line directives + define("ZEND_VM_LINES", 0); } gen_vm(__DIR__ . "/zend_vm_def.h", __DIR__ . "/zend_vm_execute.skl"); diff --git a/ext/date/php_date.c b/ext/date/php_date.c index 5e70ffc10d..705057766a 100644 --- a/ext/date/php_date.c +++ b/ext/date/php_date.c @@ -4709,7 +4709,7 @@ PHP_METHOD(DatePeriod, __construct) dpobj->end = clone; } } - + if (dpobj->end == NULL && recurrences < 1) { php_error_docref(NULL, E_WARNING, "The recurrence count '%d' is invalid. Needs to be > 0", (int) recurrences); } diff --git a/ext/ext_skel.php b/ext/ext_skel.php index 5f45ed5146..ee274d10c3 100755 --- a/ext/ext_skel.php +++ b/ext/ext_skel.php @@ -23,8 +23,8 @@ /* {{{ error */ function error($message) { - printf('Error: %s%s', $message, PHP_EOL); - exit; + printf('Error: %s%s', $message, PHP_EOL); + exit; } /* }}} */ @@ -116,152 +116,152 @@ OPTIONS --help This help HELP; - exit; + exit; } /* }}} */ /* {{{ task */ function task($label, $callback) { - printf('%s... ', $label); + printf('%s... ', $label); - $callback(); + $callback(); - printf('done%s', PHP_EOL); + printf('done%s', PHP_EOL); } /* }}} */ /* {{{ print_success */ function print_success() { - global $options; - - if (PHP_OS_FAMILY != 'Windows') { - $file_prefix = './'; - $make_prefix = ''; - } else { - $file_prefix = ''; - $make_prefix = 'n'; - } - - printf('%1$sSuccess. The extension is now ready to be compiled. To do so, use the%s', PHP_EOL); - printf('following steps:%1$s%1$s', PHP_EOL); - printf('cd /path/to/php-src/%s%s', $options['ext'], PHP_EOL); - printf('phpize%s', PHP_EOL); - printf('%sconfigure%s', $file_prefix, PHP_EOL); - printf('%smake%2$s%2$s', $make_prefix, PHP_EOL); - printf('Don\'t forget to run tests once the compilation is done:%s', PHP_EOL); - printf('%smake test%2$s%2$s', $make_prefix, PHP_EOL); - printf('Thank you for using PHP!%s', PHP_EOL); + global $options; + + if (PHP_OS_FAMILY != 'Windows') { + $file_prefix = './'; + $make_prefix = ''; + } else { + $file_prefix = ''; + $make_prefix = 'n'; + } + + printf('%1$sSuccess. The extension is now ready to be compiled. To do so, use the%s', PHP_EOL); + printf('following steps:%1$s%1$s', PHP_EOL); + printf('cd /path/to/php-src/%s%s', $options['ext'], PHP_EOL); + printf('phpize%s', PHP_EOL); + printf('%sconfigure%s', $file_prefix, PHP_EOL); + printf('%smake%2$s%2$s', $make_prefix, PHP_EOL); + printf('Don\'t forget to run tests once the compilation is done:%s', PHP_EOL); + printf('%smake test%2$s%2$s', $make_prefix, PHP_EOL); + printf('Thank you for using PHP!%s', PHP_EOL); } /* }}} */ /* {{{ process_args */ function process_args($argv, $argc) { - $options = [ - 'unix' => true, - 'windows' => true, - 'ext' => '', - 'dir' => __DIR__ . DIRECTORY_SEPARATOR, - 'skel' => __DIR__ . DIRECTORY_SEPARATOR . 'skeleton' . DIRECTORY_SEPARATOR, - 'author' => false, - 'experimental' => false, - 'std' => false - ]; - - for($i = 1; $i < $argc; ++$i) - { - $val = $argv[$i]; - - if($val[0] != '-' || $val[1] != '-') - { - continue; - } - - switch($opt = strtolower(substr($val, 2))) - { - case 'help': { - print_help(); - } - case 'onlyunix': { - $options['windows'] = false; - } - break; - case 'onlywindows': { - $options['unix'] = false; - } - break; - case 'experimental': { - $options['experimental'] = true; - } - break; - case 'std': { - $options['std'] = true; - } - break; - case 'ext': - case 'dir': - case 'author': { - if (!isset($argv[$i + 1]) || ($argv[$i + 1][0] == '-' && $argv[$i + 1][1] == '-')) { - error('Argument "' . $val . '" expects a value, none passed'); - } else if ($opt == 'dir' && empty($argv[$i + 1])) { - continue 2; - } - - $options[$opt] = ($opt == 'dir' ? realpath($argv[$i + 1]) . DIRECTORY_SEPARATOR : $argv[$i + 1]); - } - break; - default: { - error('Unsupported argument "' . $val . '" passed'); - } - } - } - - if (empty($options['ext'])) { - error('No extension name passed, use "--ext <name>"'); - } else if (!$options['unix'] && !$options['windows']) { - error('Cannot pass both --onlyunix and --onlywindows'); - } else if (!is_dir($options['skel'])) { - error('The skeleton directory was not found'); - } - - // Validate extension name - if (!preg_match('/^[a-z][a-z0-9_]+$/i', $options['ext'])) { - error('Invalid extension name. Valid names start with a letter,' - .' followed by any number of letters, numbers, or underscores.' - .' Using only lower case letters is preferred.'); - } - - $options['ext'] = str_replace(['\\', '/'], '', strtolower($options['ext'])); - - return $options; + $options = [ + 'unix' => true, + 'windows' => true, + 'ext' => '', + 'dir' => __DIR__ . DIRECTORY_SEPARATOR, + 'skel' => __DIR__ . DIRECTORY_SEPARATOR . 'skeleton' . DIRECTORY_SEPARATOR, + 'author' => false, + 'experimental' => false, + 'std' => false + ]; + + for($i = 1; $i < $argc; ++$i) + { + $val = $argv[$i]; + + if($val[0] != '-' || $val[1] != '-') + { + continue; + } + + switch($opt = strtolower(substr($val, 2))) + { + case 'help': { + print_help(); + } + case 'onlyunix': { + $options['windows'] = false; + } + break; + case 'onlywindows': { + $options['unix'] = false; + } + break; + case 'experimental': { + $options['experimental'] = true; + } + break; + case 'std': { + $options['std'] = true; + } + break; + case 'ext': + case 'dir': + case 'author': { + if (!isset($argv[$i + 1]) || ($argv[$i + 1][0] == '-' && $argv[$i + 1][1] == '-')) { + error('Argument "' . $val . '" expects a value, none passed'); + } else if ($opt == 'dir' && empty($argv[$i + 1])) { + continue 2; + } + + $options[$opt] = ($opt == 'dir' ? realpath($argv[$i + 1]) . DIRECTORY_SEPARATOR : $argv[$i + 1]); + } + break; + default: { + error('Unsupported argument "' . $val . '" passed'); + } + } + } + + if (empty($options['ext'])) { + error('No extension name passed, use "--ext <name>"'); + } else if (!$options['unix'] && !$options['windows']) { + error('Cannot pass both --onlyunix and --onlywindows'); + } else if (!is_dir($options['skel'])) { + error('The skeleton directory was not found'); + } + + // Validate extension name + if (!preg_match('/^[a-z][a-z0-9_]+$/i', $options['ext'])) { + error('Invalid extension name. Valid names start with a letter,' + .' followed by any number of letters, numbers, or underscores.' + .' Using only lower case letters is preferred.'); + } + + $options['ext'] = str_replace(['\\', '/'], '', strtolower($options['ext'])); + + return $options; } /* }}} */ /* {{{ process_source_tags */ function process_source_tags($file, $short_name) { - global $options; + global $options; - $source = file_get_contents($file); + $source = file_get_contents($file); - if ($source === false) { - error('Unable to open file for reading: ' . $short_name); - } + if ($source === false) { + error('Unable to open file for reading: ' . $short_name); + } - $source = str_replace('%EXTNAME%', $options['ext'], $source); - $source = str_replace('%EXTNAMECAPS%', strtoupper($options['ext']), $source); + $source = str_replace('%EXTNAME%', $options['ext'], $source); + $source = str_replace('%EXTNAMECAPS%', strtoupper($options['ext']), $source); - if (strpos($short_name, '.c') !== false || strpos($short_name, '.h') !== false) { - static $header; + if (strpos($short_name, '.c') !== false || strpos($short_name, '.h') !== false) { + static $header; - if (!$header) { - if ($options['std']) { - $author_len = strlen($options['author']); - $credits = $options['author'] . ($author_len && $author_len <= 60 ? str_repeat(' ', 60 - $author_len) : ''); + if (!$header) { + if ($options['std']) { + $author_len = strlen($options['author']); + $credits = $options['author'] . ($author_len && $author_len <= 60 ? str_repeat(' ', 60 - $author_len) : ''); - $header = <<<"HEADER" + $header = <<<"HEADER" /* +----------------------------------------------------------------------+ | PHP Version 7 | @@ -280,140 +280,140 @@ function process_source_tags($file, $short_name) { +----------------------------------------------------------------------+ */ HEADER; - } else { - if ($options['author']) { - $header = sprintf('/* %s extension for PHP (c) %d %s */', $options['ext'], date('Y'), $options['author']); - } else { - $header = sprintf('/* %s extension for PHP */', $options['ext']); - } - } - } - - $source = str_replace('%HEADER%', $header, $source); - } - - if (!file_put_contents($file, $source)) { - error('Unable to save contents to file: ' . $short_name); - } + } else { + if ($options['author']) { + $header = sprintf('/* %s extension for PHP (c) %d %s */', $options['ext'], date('Y'), $options['author']); + } else { + $header = sprintf('/* %s extension for PHP */', $options['ext']); + } + } + } + + $source = str_replace('%HEADER%', $header, $source); + } + + if (!file_put_contents($file, $source)) { + error('Unable to save contents to file: ' . $short_name); + } } /* }}} */ /* {{{ copy_config_scripts */ function copy_config_scripts() { - global $options; + global $options; - $files = []; + $files = []; - if ($options['unix']) { - $files[] = 'config.m4'; - } + if ($options['unix']) { + $files[] = 'config.m4'; + } - if ($options['windows']) { - $files[] = 'config.w32'; - } + if ($options['windows']) { + $files[] = 'config.w32'; + } - $files[] = '.gitignore'; + $files[] = '.gitignore'; - foreach($files as $config_script) { - $new_config_script = $options['dir'] . $options['ext'] . DIRECTORY_SEPARATOR . $config_script; + foreach($files as $config_script) { + $new_config_script = $options['dir'] . $options['ext'] . DIRECTORY_SEPARATOR . $config_script; - if (!copy($options['skel'] . $config_script . '.in', $new_config_script)) { - error('Unable to copy config script: ' . $config_script); - } + if (!copy($options['skel'] . $config_script . '.in', $new_config_script)) { + error('Unable to copy config script: ' . $config_script); + } - process_source_tags($new_config_script, $config_script); - } + process_source_tags($new_config_script, $config_script); + } } /* }}} */ /* {{{ copy_sources */ function copy_sources() { - global $options; + global $options; - $files = [ - 'skeleton.c' => $options['ext'] . '.c', - 'php_skeleton.h' => 'php_' . $options['ext'] . '.h' - ]; + $files = [ + 'skeleton.c' => $options['ext'] . '.c', + 'php_skeleton.h' => 'php_' . $options['ext'] . '.h' + ]; - foreach ($files as $src_file => $dst_file) { - if (!copy($options['skel'] . $src_file, $options['dir'] . $options['ext'] . DIRECTORY_SEPARATOR . $dst_file)) { - error('Unable to copy source file: ' . $src_file); - } + foreach ($files as $src_file => $dst_file) { + if (!copy($options['skel'] . $src_file, $options['dir'] . $options['ext'] . DIRECTORY_SEPARATOR . $dst_file)) { + error('Unable to copy source file: ' . $src_file); + } - process_source_tags($options['dir'] . $options['ext'] . DIRECTORY_SEPARATOR . $dst_file, $dst_file); - } + process_source_tags($options['dir'] . $options['ext'] . DIRECTORY_SEPARATOR . $dst_file, $dst_file); + } } /* }}} */ /* {{{ copy_tests */ function copy_tests() { - global $options; + global $options; - $test_files = glob($options['skel'] . 'tests/*', GLOB_MARK); + $test_files = glob($options['skel'] . 'tests/*', GLOB_MARK); - if (!$test_files) { - return; - } + if (!$test_files) { + return; + } - foreach ($test_files as $test) { - if (is_dir($test)) { - continue; - } + foreach ($test_files as $test) { + if (is_dir($test)) { + continue; + } - $new_test = str_replace([$options['skel'], '/'], ['', DIRECTORY_SEPARATOR], $test); + $new_test = str_replace([$options['skel'], '/'], ['', DIRECTORY_SEPARATOR], $test); - if (!copy($test, $options['dir'] . $options['ext'] . DIRECTORY_SEPARATOR . $new_test)) { - error('Unable to copy file: ' . $new_test); - } + if (!copy($test, $options['dir'] . $options['ext'] . DIRECTORY_SEPARATOR . $new_test)) { + error('Unable to copy file: ' . $new_test); + } - process_source_tags($options['dir'] . $options['ext'] . DIRECTORY_SEPARATOR . $new_test, $new_test); - } + process_source_tags($options['dir'] . $options['ext'] . DIRECTORY_SEPARATOR . $new_test, $new_test); + } } /* }}} */ if (PHP_SAPI != 'cli') { - error('This script is only suited for CLI'); + error('This script is only suited for CLI'); } if ($argc < 1) { - print_help(); - exit; + print_help(); + exit; } $options = process_args($argv, $argc); if (!$options['dir'] || !is_dir($options['dir'])) { - error('The selected output directory does not exist'); + error('The selected output directory does not exist'); } else if (is_dir($options['dir'] . $options['ext'])) { - error('There is already a folder named "' . $options['ext'] . '" in the output directory'); + error('There is already a folder named "' . $options['ext'] . '" in the output directory'); } else if (!mkdir($options['dir'] . $options['ext'])) { - error('Unable to create extension directory in the output directory'); + error('Unable to create extension directory in the output directory'); } else if (!mkdir($options['dir'] . $options['ext'] . DIRECTORY_SEPARATOR . 'tests')) { - error('Unable to create the tests directory'); + error('Unable to create the tests directory'); } if ($options['experimental']) { - print('Creating EXPERIMENTAL... '); + print('Creating EXPERIMENTAL... '); - if (file_put_contents($options['dir'] . $options['ext'] . DIRECTORY_SEPARATOR . 'EXPERIMENTAL', '') === false) { - error('Unable to create the EXPERIMENTAL file'); - } + if (file_put_contents($options['dir'] . $options['ext'] . DIRECTORY_SEPARATOR . 'EXPERIMENTAL', '') === false) { + error('Unable to create the EXPERIMENTAL file'); + } - printf('done%s', PHP_EOL); + printf('done%s', PHP_EOL); } if (!empty($options['author'])) { - print('Creating CREDITS... '); + print('Creating CREDITS... '); - if (!file_put_contents($options['dir'] . $options['ext'] . DIRECTORY_SEPARATOR . 'CREDITS', $options['ext'] . PHP_EOL . $options['author'])) { - error('Unable to create the CREDITS file'); - } + if (!file_put_contents($options['dir'] . $options['ext'] . DIRECTORY_SEPARATOR . 'CREDITS', $options['ext'] . PHP_EOL . $options['author'])) { + error('Unable to create the CREDITS file'); + } - printf('done%s', PHP_EOL); + printf('done%s', PHP_EOL); } date_default_timezone_set('UTC'); diff --git a/ext/fileinfo/create_data_file.php b/ext/fileinfo/create_data_file.php index c1284c60cb..e85be002b0 100755 --- a/ext/fileinfo/create_data_file.php +++ b/ext/fileinfo/create_data_file.php @@ -2,17 +2,17 @@ /* This is a generated file, do not modify */ /* Usage: php create_data_file.php /path/to/magic.mgc > data_file.c */ <?php - $dta = file_get_contents( $argv[1] ); - $dta_l = strlen($dta); - $j = 0; + $dta = file_get_contents( $argv[1] ); + $dta_l = strlen($dta); + $j = 0; - echo "const unsigned char php_magic_database[$dta_l] = {\n"; - for ($i = 0; $i < $dta_l; $i++) { - printf("0x%02X, ", ord($dta[$i])); - if ($j % 16 == 15) { - echo "\n"; - } - $j++; - } - echo "};\n"; + echo "const unsigned char php_magic_database[$dta_l] = {\n"; + for ($i = 0; $i < $dta_l; $i++) { + printf("0x%02X, ", ord($dta[$i])); + if ($j % 16 == 15) { + echo "\n"; + } + $j++; + } + echo "};\n"; ?> diff --git a/ext/hash/bench.php b/ext/hash/bench.php index a1cc4bedd1..60c038ca99 100755 --- a/ext/hash/bench.php +++ b/ext/hash/bench.php @@ -5,68 +5,68 @@ This gives rather interesting results :) Measures on a Notebook P4M-1.7 256MB Windows 2000: - sha1 0.556691 - tiger160,3 0.774469 - tiger192,3 0.776314 - tiger128,3 0.777004 - ripemd128 0.896674 - sha256 1.011164 - md5 1.016032 - tiger160,4 1.056617 - tiger128,4 1.063101 - tiger192,4 1.069258 - haval160,3 1.125099 - haval128,3 1.125679 - haval224,3 1.128017 - haval192,3 1.130026 - haval256,3 1.134846 - ripemd160 1.150693 - haval128,4 1.686261 - haval192,4 1.687274 - haval160,4 1.693091 - haval256,4 1.699323 - haval224,4 1.743094 - haval160,5 2.003452 - haval192,5 2.008341 - haval256,5 2.009048 - haval128,5 2.009555 - haval224,5 2.015539 - sha384 3.370734 - sha512 3.381121 - whirlpool 6.912327 - snefru 9.268168 + sha1 0.556691 + tiger160,3 0.774469 + tiger192,3 0.776314 + tiger128,3 0.777004 + ripemd128 0.896674 + sha256 1.011164 + md5 1.016032 + tiger160,4 1.056617 + tiger128,4 1.063101 + tiger192,4 1.069258 + haval160,3 1.125099 + haval128,3 1.125679 + haval224,3 1.128017 + haval192,3 1.130026 + haval256,3 1.134846 + ripemd160 1.150693 + haval128,4 1.686261 + haval192,4 1.687274 + haval160,4 1.693091 + haval256,4 1.699323 + haval224,4 1.743094 + haval160,5 2.003452 + haval192,5 2.008341 + haval256,5 2.009048 + haval128,5 2.009555 + haval224,5 2.015539 + sha384 3.370734 + sha512 3.381121 + whirlpool 6.912327 + snefru 9.268168 Measures on a Desktop P4-2.4 512MB Debian (Linux-2.4): - md5 0.147739 - haval128,3 0.317006 - haval192,3 0.317524 - haval256,3 0.317526 - haval160,3 0.323035 - haval224,3 0.333318 - ripemd128 0.353447 - sha1 0.376200 - ripemd160 0.413758 - sha256 0.435957 - haval160,4 0.452357 - haval224,4 0.454531 - haval128,4 0.458026 - haval256,4 0.459051 - haval192,4 0.468094 - haval128,5 0.524262 - haval160,5 0.529573 - haval224,5 0.533655 - haval256,5 0.534446 - haval192,5 0.543726 - tiger128,3 0.577975 - tiger160,3 0.579951 - tiger192,3 0.597111 - tiger192,4 0.781408 - tiger160,4 0.801243 - tiger128,4 0.812239 - sha512 1.298627 - sha384 1.313607 - whirlpool 1.556159 - snefru 5.703742 + md5 0.147739 + haval128,3 0.317006 + haval192,3 0.317524 + haval256,3 0.317526 + haval160,3 0.323035 + haval224,3 0.333318 + ripemd128 0.353447 + sha1 0.376200 + ripemd160 0.413758 + sha256 0.435957 + haval160,4 0.452357 + haval224,4 0.454531 + haval128,4 0.458026 + haval256,4 0.459051 + haval192,4 0.468094 + haval128,5 0.524262 + haval160,5 0.529573 + haval224,5 0.533655 + haval256,5 0.534446 + haval192,5 0.543726 + tiger128,3 0.577975 + tiger160,3 0.579951 + tiger192,3 0.597111 + tiger192,4 0.781408 + tiger160,4 0.801243 + tiger128,4 0.812239 + sha512 1.298627 + sha384 1.313607 + whirlpool 1.556159 + snefru 5.703742 */ @@ -76,17 +76,17 @@ $data = file_get_contents(__FILE__); $time = array(); for ($j = 0; $j < 10; $j++) { - foreach (hash_algos() as $algo) { - $start = microtime(true); - for ($i = 0; $i < 1000; $i++) { - hash($algo, $data); - } - $time[$algo] += microtime(true)-$start; - } + foreach (hash_algos() as $algo) { + $start = microtime(true); + for ($i = 0; $i < 1000; $i++) { + hash($algo, $data); + } + $time[$algo] += microtime(true)-$start; + } } asort($time, SORT_NUMERIC); foreach ($time as $a => $t) { - printf("%-12s %02.6f\n", $a, $t); + printf("%-12s %02.6f\n", $a, $t); } ?> diff --git a/ext/intl/calendar/calendar_methods.cpp b/ext/intl/calendar/calendar_methods.cpp index dfe34a4f03..a85f557af6 100644 --- a/ext/intl/calendar/calendar_methods.cpp +++ b/ext/intl/calendar/calendar_methods.cpp @@ -410,7 +410,7 @@ U_CFUNC PHP_FUNCTION(intlcal_set) CALENDAR_METHOD_INIT_VARS; object = getThis(); - + /* must come before zpp because zpp would convert the args in the stack to 0 */ if (ZEND_NUM_ARGS() > (object ? 6 : 7) || zend_get_parameters_array_ex(ZEND_NUM_ARGS(), args) == FAILURE) { diff --git a/ext/pdo_firebird/firebird_statement.c b/ext/pdo_firebird/firebird_statement.c index 8e9b024f2d..05dfe46848 100644 --- a/ext/pdo_firebird/firebird_statement.c +++ b/ext/pdo_firebird/firebird_statement.c @@ -627,7 +627,7 @@ static int firebird_stmt_param_hook(pdo_stmt_t *stmt, struct pdo_bound_param_dat { zend_long lval; double dval; - + if ((Z_STRLEN_P(parameter) == 0)) { *(FB_BOOLEAN*)var->sqldata = FB_FALSE; break; @@ -665,7 +665,7 @@ static int firebird_stmt_param_hook(pdo_stmt_t *stmt, struct pdo_bound_param_dat break; } #endif - + /* check if a NULL should be inserted */ switch (Z_TYPE_P(parameter)) { diff --git a/ext/pdo_firebird/pdo_firebird.c b/ext/pdo_firebird/pdo_firebird.c index 00b4001752..02f577fb35 100644 --- a/ext/pdo_firebird/pdo_firebird.c +++ b/ext/pdo_firebird/pdo_firebird.c @@ -84,7 +84,7 @@ PHP_MINFO_FUNCTION(pdo_firebird) /* {{{ */ { char version[64]; isc_get_client_version(version); - + php_info_print_table_start(); php_info_print_table_header(2, "PDO Driver for Firebird", "enabled"); php_info_print_table_row(2, "Client Library Version", version); diff --git a/ext/pdo_mysql/get_error_codes.php b/ext/pdo_mysql/get_error_codes.php index 4c956f8c4e..27910f8dad 100755 --- a/ext/pdo_mysql/get_error_codes.php +++ b/ext/pdo_mysql/get_error_codes.php @@ -1,28 +1,28 @@ #!/usr/bin/env php <?php - $codes = array(); - $maxlen = 0; + $codes = array(); + $maxlen = 0; - while (!feof(STDIN)) { - $line = fgets(STDIN); + while (!feof(STDIN)) { + $line = fgets(STDIN); - if (ereg('^\{[[:space:]]+(ER_.*)[[:space:]]+,[[:space:]]*"(.*)",[[:space:]]*"(.*)"', $line, $matches)) { - $codes[$matches[1]] = $matches[2]; - $maxlen = max($maxlen, strlen($matches[1])); - } - } + if (ereg('^\{[[:space:]]+(ER_.*)[[:space:]]+,[[:space:]]*"(.*)",[[:space:]]*"(.*)"', $line, $matches)) { + $codes[$matches[1]] = $matches[2]; + $maxlen = max($maxlen, strlen($matches[1])); + } + } - if (empty($codes)) { - fputs(STDERR, "input doesn't look like a MySQL sql_state.h file\n"); - exit(3); - } + if (empty($codes)) { + fputs(STDERR, "input doesn't look like a MySQL sql_state.h file\n"); + exit(3); + } - echo "/* DO NOT EDIT THIS FILE!!! It is auto generated by get_error_codes.php */\n"; - foreach ($codes as $code => $state) { - echo "#ifdef $code\n"; - printf(" case %-{$maxlen}s: return \"%s\";\n", $code, $state); - echo "#endif\n"; - } + echo "/* DO NOT EDIT THIS FILE!!! It is auto generated by get_error_codes.php */\n"; + foreach ($codes as $code => $state) { + echo "#ifdef $code\n"; + printf(" case %-{$maxlen}s: return \"%s\";\n", $code, $state); + echo "#endif\n"; + } ?> diff --git a/ext/pdo_sqlite/sqlite_statement.c b/ext/pdo_sqlite/sqlite_statement.c index d95f520088..80bdcafd10 100644 --- a/ext/pdo_sqlite/sqlite_statement.c +++ b/ext/pdo_sqlite/sqlite_statement.c @@ -59,7 +59,7 @@ static void pdo_sqlite_stmt_set_column_count(pdo_stmt_t *stmt, int new_count) } /* - * The column count has not changed : no need to reload columns description + * The column count has not changed : no need to reload columns description * Note: Do not handle attribute name change, without column count change */ if (new_count == stmt->column_count) { diff --git a/ext/phar/build_precommand.php b/ext/phar/build_precommand.php index c2fe9c8e52..c427ffbd5b 100755 --- a/ext/phar/build_precommand.php +++ b/ext/phar/build_precommand.php @@ -10,44 +10,44 @@ * Phar Command */ foreach(array("SPL", "Reflection", "Phar") as $ext) { - if (!extension_loaded($ext)) { - echo "$argv[0] requires PHP extension $ext.\n"; - exit(1); - } + if (!extension_loaded($ext)) { + echo "$argv[0] requires PHP extension $ext.\n"; + exit(1); + } } <?php $classes = array( - 'DirectoryTreeIterator', - 'DirectoryGraphIterator', - 'InvertedRegexIterator', - 'CLICommand', - 'PharCommand', - ); + 'DirectoryTreeIterator', + 'DirectoryGraphIterator', + 'InvertedRegexIterator', + 'CLICommand', + 'PharCommand', + ); foreach($classes as $name) { - echo "if (!class_exists('$name', 0))\n{\n"; - $f = file(dirname(__FILE__) . '/phar/' . strtolower($name) . '.inc'); - unset($f[0]); - $c = count($f); - while ($c && (strlen($f[$c]) == 0 || $f[$c] == "\n" || $f[$c] == "\r\n")) { - unset($f[$c--]); - } - if (substr($f[$c], -2) == "\r\n") { - $f[$c] = substr($f[$c], 0, -2); - } - if (substr($f[$c], -1) == "\n") { - $f[$c] = substr($f[$c], 0, -1); - } - if (substr($f[$c], -2) == '?>') { - $f[$c] = substr($f[$c], 0,-2); - } - while ($c && (strlen($f[$c]) == 0 || $f[$c] == "\n" || $f[$c] == "\r\n")) { - unset($f[$c--]); - } - echo join('', $f); - echo "\n}\n\n"; + echo "if (!class_exists('$name', 0))\n{\n"; + $f = file(dirname(__FILE__) . '/phar/' . strtolower($name) . '.inc'); + unset($f[0]); + $c = count($f); + while ($c && (strlen($f[$c]) == 0 || $f[$c] == "\n" || $f[$c] == "\r\n")) { + unset($f[$c--]); + } + if (substr($f[$c], -2) == "\r\n") { + $f[$c] = substr($f[$c], 0, -2); + } + if (substr($f[$c], -1) == "\n") { + $f[$c] = substr($f[$c], 0, -1); + } + if (substr($f[$c], -2) == '?>') { + $f[$c] = substr($f[$c], 0,-2); + } + while ($c && (strlen($f[$c]) == 0 || $f[$c] == "\n" || $f[$c] == "\r\n")) { + unset($f[$c--]); + } + echo join('', $f); + echo "\n}\n\n"; } echo 'new PharCommand($argc, $argv);'."\n"; diff --git a/ext/phar/makestub.php b/ext/phar/makestub.php index 2feb730845..42ca3d62d3 100644 --- a/ext/phar/makestub.php +++ b/ext/phar/makestub.php @@ -4,18 +4,18 @@ $s = str_replace("\r", '', file_get_contents(dirname(__FILE__) . '/shortarc.php' $s .= "\nExtract_Phar::go();\n__HALT_COMPILER();"; $news = ''; foreach (token_get_all($s) as $token) { - if (is_array($token)) { - if ($token[0] == T_COMMENT) { - $token[1] = ''; - } - if ($token[0] == T_WHITESPACE) { - $n = str_repeat("\n", substr_count($token[1], "\n")); - $token[1] = strlen($n) ? $n : ' '; - } - $news .= $token[1]; - } else { - $news .= $token; - } + if (is_array($token)) { + if ($token[0] == T_COMMENT) { + $token[1] = ''; + } + if ($token[0] == T_WHITESPACE) { + $n = str_repeat("\n", substr_count($token[1], "\n")); + $token[1] = strlen($n) ? $n : ' '; + } + $news .= $token[1]; + } else { + $news .= $token; + } } $s = $news . ' ?>'; $slen = strlen($s) - strlen('index.php') - strlen("000"); @@ -55,50 +55,50 @@ $s1split = str_split($s1, 2046); $s3split = str_split($s3, 2046); $took = false; foreach ($s1split as $i => $chunk) { - if ($took) { - $s1split[$i] = substr($chunk, 1); - $took = false; - } - if ($chunk[strlen($chunk) - 1] == '\\') { - $s1split[$i] .= $s1split[$i + 1][0]; - $took = true; - } + if ($took) { + $s1split[$i] = substr($chunk, 1); + $took = false; + } + if ($chunk[strlen($chunk) - 1] == '\\') { + $s1split[$i] .= $s1split[$i + 1][0]; + $took = true; + } } foreach ($s3split as $i => $chunk) { - if ($took) { - $s3split[$i] = substr($chunk, 1); - $took = false; - } - if ($chunk[strlen($chunk) - 1] == '\\') { - $s3split[$i] .= $s3split[$i + 1][0]; - $took = true; - } + if ($took) { + $s3split[$i] = substr($chunk, 1); + $took = false; + } + if ($chunk[strlen($chunk) - 1] == '\\') { + $s3split[$i] .= $s3split[$i + 1][0]; + $took = true; + } } $stub .= "\tstatic const char newstub0[] = \"" . $webs . '"; '; foreach ($s1split as $i => $chunk) { - $s1count = $i + 1; - $stub .= "\tstatic const char newstub1_" . $i . '[] = "' . $chunk . '"; + $s1count = $i + 1; + $stub .= "\tstatic const char newstub1_" . $i . '[] = "' . $chunk . '"; '; } $stub .= "\tstatic const char newstub2[] = \"" . $s2 . "\"; "; foreach ($s3split as $i => $chunk) { - $s3count = $i + 1; - $stub .= "\tstatic const char newstub3_" . $i . '[] = "' . $chunk . '"; + $s3count = $i + 1; + $stub .= "\tstatic const char newstub3_" . $i . '[] = "' . $chunk . '"; '; } $stub .= "\n\tstatic const int newstub_len = " . $slen . "; \t*len = spprintf(stub, name_len + web_len + newstub_len, \"%s%s" . str_repeat('%s', $s1count) . '%s%s%d' - . str_repeat('%s', $s3count) . '", newstub0, web'; + . str_repeat('%s', $s3count) . '", newstub0, web'; foreach ($s1split as $i => $unused) { - $stub .= ', newstub1_' . $i; + $stub .= ', newstub1_' . $i; } $stub .= ', index_php, newstub2'; $stub .= ", name_len + web_len + newstub_len"; foreach ($s3split as $i => $unused) { - $stub .= ', newstub3_' . $i; + $stub .= ', newstub3_' . $i; } $stub .= "); }"; diff --git a/ext/phar/phar/phar.php b/ext/phar/phar/phar.php index 13538777a5..53aa76f60a 100755 --- a/ext/phar/phar/phar.php +++ b/ext/phar/phar/phar.php @@ -12,37 +12,37 @@ if (!extension_loaded('phar')) { - if (!class_exists('PHP_Archive', 0)) { - echo "Neither Extension Phar nor class PHP_Archive are available.\n"; - exit(1); - } - if (!in_array('phar', stream_get_wrappers())) { - stream_wrapper_register('phar', 'PHP_Archive'); - } - if (!class_exists('Phar',0)) { - require 'phar://'.__FILE__.'/phar.inc'; - } + if (!class_exists('PHP_Archive', 0)) { + echo "Neither Extension Phar nor class PHP_Archive are available.\n"; + exit(1); + } + if (!in_array('phar', stream_get_wrappers())) { + stream_wrapper_register('phar', 'PHP_Archive'); + } + if (!class_exists('Phar',0)) { + require 'phar://'.__FILE__.'/phar.inc'; + } } foreach(array("SPL", "Reflection") as $ext) { - if (!extension_loaded($ext)) { - echo "$argv[0] requires PHP extension $ext.\n"; - exit(1); - } + if (!extension_loaded($ext)) { + echo "$argv[0] requires PHP extension $ext.\n"; + exit(1); + } } function command_include($file) { - $file = 'phar://' . __FILE__ . '/' . $file; - if (file_exists($file)) { - include($file); - } + $file = 'phar://' . __FILE__ . '/' . $file; + if (file_exists($file)) { + include($file); + } } function command_autoload($classname) { - command_include(strtolower($classname) . '.inc'); + command_include(strtolower($classname) . '.inc'); } Phar::mapPhar(); diff --git a/ext/reflection/php_reflection.c b/ext/reflection/php_reflection.c index 5af48c4978..dbfb67386e 100644 --- a/ext/reflection/php_reflection.c +++ b/ext/reflection/php_reflection.c @@ -4323,7 +4323,7 @@ ZEND_METHOD(reflection_class, getProperties) if (zend_parse_parameters(ZEND_NUM_ARGS(), "|l!", &filter, &filter_is_null) == FAILURE) { return; } - + if (filter_is_null) { filter = ZEND_ACC_PPP_MASK | ZEND_ACC_STATIC; } diff --git a/ext/soap/soap.c b/ext/soap/soap.c index ce776efb3f..1383055370 100644 --- a/ext/soap/soap.c +++ b/ext/soap/soap.c @@ -2581,7 +2581,7 @@ static int do_request(zval *this_ptr, xmlDoc *request, char *location, char *act ret = FALSE; } return ret; -} +} /* }}} */ static void do_soap_call(zend_execute_data *execute_data, @@ -3820,7 +3820,7 @@ static int serialize_response_call2(xmlNodePtr body, sdlFunctionPtr function, ch *node = method; } return use; -} +} /* }}} */ static xmlDocPtr serialize_response_call(sdlFunctionPtr function, char *function_name, char *uri, zval *ret, soapHeader* headers, int version) /* {{{ */ diff --git a/ext/spl/spl_directory.c b/ext/spl/spl_directory.c index 0b276fcb42..d7995bd7fa 100644 --- a/ext/spl/spl_directory.c +++ b/ext/spl/spl_directory.c @@ -2691,7 +2691,7 @@ SPL_METHOD(SplFileObject, setCsvControl) { case 3: switch (esc_len) { - case 0: + case 0: escape = PHP_CSV_NO_ESCAPE; break; case 1: diff --git a/ext/sqlite3/sqlite3.c b/ext/sqlite3/sqlite3.c index 1c337ee6cb..910181a3b7 100644 --- a/ext/sqlite3/sqlite3.c +++ b/ext/sqlite3/sqlite3.c @@ -322,7 +322,7 @@ PHP_METHOD(sqlite3, enableExtendedResultCodes) int ret; SQLITE3_CHECK_INITIALIZED(db_obj, db_obj->db, SQLite3) - + if (zend_parse_parameters(ZEND_NUM_ARGS(), "|b", &enable) == FAILURE) { return; } diff --git a/ext/standard/var.c b/ext/standard/var.c index c816dd05f9..3fa1afcb72 100644 --- a/ext/standard/var.c +++ b/ext/standard/var.c @@ -1070,7 +1070,7 @@ again: if (ce != PHP_IC_ENTRY && zend_hash_str_exists(&ce->function_table, "__sleep", sizeof("__sleep")-1)) { zval retval, tmp; - + Z_ADDREF_P(struc); ZVAL_OBJ(&tmp, Z_OBJ_P(struc)); diff --git a/ext/zip/examples/addglob.php b/ext/zip/examples/addglob.php index 3c432f0be5..13ea83b02a 100644 --- a/ext/zip/examples/addglob.php +++ b/ext/zip/examples/addglob.php @@ -5,8 +5,8 @@ $z->open('a.zip', ZIPARCHIVE::CREATE); /* or 'remove_all_path' => 0*/ $options = array( - 'remove_path' => '/home/francis/myimages', - 'add_path' => 'images/', + 'remove_path' => '/home/francis/myimages', + 'add_path' => 'images/', ); $found = $z->addGlob("/home/pierre/cvs/gd/libgd/tests/*.png", 0, $options); var_dump($found); diff --git a/ext/zip/examples/create.php b/ext/zip/examples/create.php index a41c8e6d0b..d835704c8e 100644 --- a/ext/zip/examples/create.php +++ b/ext/zip/examples/create.php @@ -9,9 +9,9 @@ $zip = new ZipArchive(); $filename = "./test112.zip"; if (!$zip->open($filename, ZIPARCHIVE::CREATE)) { - exit("cannot open <$filename>\n"); + exit("cannot open <$filename>\n"); } else { - echo "file <$filename> OK\n"; + echo "file <$filename> OK\n"; } $zip->addFromString("testfilephp.txt" . time(), "#1 This is a test string added as testfilephp.txt.\n"); diff --git a/ext/zip/examples/dir.php b/ext/zip/examples/dir.php index c362a72ba3..6fe56c0b9b 100644 --- a/ext/zip/examples/dir.php +++ b/ext/zip/examples/dir.php @@ -15,7 +15,7 @@ echo "filename: " . $za->filename . "\n"; echo "comment: " . $za->comment . "\n"; for ($i=0; $i<$za->numFiles;$i++) { - echo "index: $i\n"; - print_r($za->statIndex($i)); + echo "index: $i\n"; + print_r($za->statIndex($i)); } echo "numFile:" . $za->numFiles . "\n"; diff --git a/ext/zip/examples/encryption.php b/ext/zip/examples/encryption.php index 9ef7dd8497..42d3850404 100644 --- a/ext/zip/examples/encryption.php +++ b/ext/zip/examples/encryption.php @@ -40,9 +40,9 @@ $zip->close(); echo "== Stream with context\n"; $ctx = stream_context_create(array( - 'zip' => array( - 'password' => $pass - ) + 'zip' => array( + 'password' => $pass + ) )); $text = file_get_contents("zip://$name#$file", false, $ctx); printf("Size = %d\n", strlen($text)); diff --git a/ext/zip/examples/extract.php b/ext/zip/examples/extract.php index 5276b0dca5..01a9c75aee 100644 --- a/ext/zip/examples/extract.php +++ b/ext/zip/examples/extract.php @@ -19,9 +19,9 @@ echo $zip->filename . "\n"; var_dump($zip); $files = array('test', 'testdir/test2'); if (!$zip->extractTo("./testext/path/to", $files)) { - echo "error!\n"; - echo $zip->status . "\n"; - echo $zip->statusSys . "\n"; + echo "error!\n"; + echo $zip->status . "\n"; + echo $zip->statusSys . "\n"; } diff --git a/ext/zip/examples/extractAll.php b/ext/zip/examples/extractAll.php index d318a453df..69286b93ec 100644 --- a/ext/zip/examples/extractAll.php +++ b/ext/zip/examples/extractAll.php @@ -15,9 +15,9 @@ echo $zip->filename . "\n"; var_dump($zip); $files = array('test', 'testdir/test2'); if (!$zip->extractTo("./testext/path/to")) { - echo "error!\n"; - echo $zip->status . "\n"; - echo $zip->statusSys . "\n"; + echo "error!\n"; + echo $zip->status . "\n"; + echo $zip->statusSys . "\n"; } diff --git a/ext/zip/examples/fopen.php b/ext/zip/examples/fopen.php index 80de5d052a..4dcedba74a 100644 --- a/ext/zip/examples/fopen.php +++ b/ext/zip/examples/fopen.php @@ -6,11 +6,11 @@ if (!extension_loaded('zip')) { $fp = fopen('zip://' . dirname(__FILE__) . '/test.zip#test', 'r'); if (!$fp) { - exit("cannot open\n"); + exit("cannot open\n"); } while (!feof($fp)) { - $contents .= fread($fp, 2); - echo "$contents\n"; + $contents .= fread($fp, 2); + echo "$contents\n"; } fclose($fp); @@ -25,7 +25,7 @@ $fp = $z->getStream('test'); var_dump($fp); if(!$fp) exit("\n"); while (!feof($fp)) { - $contents .= fread($fp, 2); + $contents .= fread($fp, 2); } fclose($fp); diff --git a/ext/zip/examples/get_set_comments.php b/ext/zip/examples/get_set_comments.php index 600b51138d..a9faf08f33 100644 --- a/ext/zip/examples/get_set_comments.php +++ b/ext/zip/examples/get_set_comments.php @@ -7,9 +7,9 @@ $z->open('t.zip'); print_r($z); for ($i=0; $i<$z->numFiles; $i++) { - echo "index: $i\n"; - print_r($z->getCommentIndex($i)); - echo "\n\n"; + echo "index: $i\n"; + print_r($z->getCommentIndex($i)); + echo "\n\n"; } echo "foobar/ " . $z->getCommentName('foobar/') . "\n"; @@ -22,9 +22,9 @@ $z->setCommentName('foobar/', 'new comment foobar/'); $z->setArchiveComment( 'new archive comment'); for ($i=0; $i<$z->numFiles; $i++) { - echo "index: $i\n"; - print_r($z->getCommentIndex($i)); - echo "\n\n"; + echo "index: $i\n"; + print_r($z->getCommentIndex($i)); + echo "\n\n"; } echo $z->getCommentName('foobar/') . "\n"; diff --git a/ext/zip/examples/odt.php b/ext/zip/examples/odt.php index 195c781e33..3f923296a1 100644 --- a/ext/zip/examples/odt.php +++ b/ext/zip/examples/odt.php @@ -5,16 +5,16 @@ $reader = new XMLReader(); $reader->open('zip://' . dirname(__FILE__) . '/test.odt#meta.xml'); $odt_meta = array(); while ($reader->read()) { - if ($reader->nodeType == XMLREADER::ELEMENT) { - $elm = $reader->name; - } else { - if ($reader->nodeType == XMLREADER::END_ELEMENT && $reader->name == 'office:meta') { - break; - } - if (!trim($reader->value)) { - continue; - } - $odt_meta[$elm] = $reader->value; - } + if ($reader->nodeType == XMLREADER::ELEMENT) { + $elm = $reader->name; + } else { + if ($reader->nodeType == XMLREADER::END_ELEMENT && $reader->name == 'office:meta') { + break; + } + if (!trim($reader->value)) { + continue; + } + $odt_meta[$elm] = $reader->value; + } } print_r($odt_meta); diff --git a/ext/zip/examples/oldapi.php b/ext/zip/examples/oldapi.php index 82a6277f3a..216de4837e 100644 --- a/ext/zip/examples/oldapi.php +++ b/ext/zip/examples/oldapi.php @@ -4,14 +4,14 @@ $zip = zip_open('examples/test1.zip'); var_dump($zip); if ($zip) { - $i = 0; - while ($zip_entry = zip_read($zip)) { - var_dump($zip_entry); - $txt = zip_entry_read($zip_entry, 10); + $i = 0; + while ($zip_entry = zip_read($zip)) { + var_dump($zip_entry); + $txt = zip_entry_read($zip_entry, 10); echo $i . ": " . $txt . "size: " . zip_entry_filesize($zip_entry) . - "comp_method: " . zip_entry_compressionmethod($zip_entry) . - "\n"; - $i++; - } - var_dump($zip_entry); + "comp_method: " . zip_entry_compressionmethod($zip_entry) . + "\n"; + $i++; + } + var_dump($zip_entry); } diff --git a/ext/zip/examples/set_compression.php b/ext/zip/examples/set_compression.php index 1efd88c7f1..49494e0bf7 100644 --- a/ext/zip/examples/set_compression.php +++ b/ext/zip/examples/set_compression.php @@ -8,7 +8,7 @@ $zip = new ZipArchive(); $filename = "a.zip"; if (!$zip->open($filename, ZIPARCHIVE::CREATE | ZipArchive::OVERWRITE)) { - exit("cannot open <$filename>\n"); + exit("cannot open <$filename>\n"); } $zip->addFromString("testfilephp.txt", "#1 This is a test string added as testfilephp.txt.\n"); diff --git a/main/php_variables.c b/main/php_variables.c index 5f6f1e5a09..74fea2c848 100644 --- a/main/php_variables.c +++ b/main/php_variables.c @@ -573,7 +573,7 @@ void _php_import_environment_variables(zval *array_ptr) php_register_variable_quick(*env, name_len, &val, Z_ARRVAL_P(array_ptr)); } } - + tsrm_env_unlock(); } diff --git a/run-tests.php b/run-tests.php index 1e5287ed5d..1b17354111 100755 --- a/run-tests.php +++ b/run-tests.php @@ -42,40 +42,40 @@ */ function main() { - /* This list was derived in a naïve mechanical fashion. If a member - * looks like it doesn't belong, it probably doesn't; cull at will. - */ - global $DETAILED, $PHP_FAILED_TESTS, $SHOW_ONLY_GROUPS, $argc, $argv, $cfg, - $cfgfiles, $cfgtypes, $conf_passed, $end_time, $environment, - $exts_skipped, $exts_tested, $exts_to_test, $failed_tests_file, - $html_file, $html_output, $ignored_by_ext, $ini_overwrites, $is_switch, - $just_save_results, $log_format, $matches, $no_clean, $no_file_cache, - $optionals, $output_file, $pass_option_n, $pass_options, - $pattern_match, $php, $php_cgi, $phpdbg, $preload, $redir_tests, - $repeat, $result_tests_file, $slow_min_ms, $start_time, $switch, - $temp_source, $temp_target, $temp_urlbase, $test_cnt, $test_dirs, - $test_files, $test_idx, $test_list, $test_results, $testfile, - $user_tests, $valgrind, $sum_results, $shuffle; - // Parallel testing - global $workers, $workerID; - - $workerID = 0; - if (getenv("TEST_PHP_WORKER")) { - $workerID = intval(getenv("TEST_PHP_WORKER")); - run_worker(); - return; - } - - define('INIT_DIR', getcwd()); - - // change into the PHP source directory. - if (getenv('TEST_PHP_SRCDIR')) { - @chdir(getenv('TEST_PHP_SRCDIR')); - } - define('TEST_PHP_SRCDIR', getcwd()); - - if (!function_exists('proc_open')) { - echo <<<NO_PROC_OPEN_ERROR + /* This list was derived in a naïve mechanical fashion. If a member + * looks like it doesn't belong, it probably doesn't; cull at will. + */ + global $DETAILED, $PHP_FAILED_TESTS, $SHOW_ONLY_GROUPS, $argc, $argv, $cfg, + $cfgfiles, $cfgtypes, $conf_passed, $end_time, $environment, + $exts_skipped, $exts_tested, $exts_to_test, $failed_tests_file, + $html_file, $html_output, $ignored_by_ext, $ini_overwrites, $is_switch, + $just_save_results, $log_format, $matches, $no_clean, $no_file_cache, + $optionals, $output_file, $pass_option_n, $pass_options, + $pattern_match, $php, $php_cgi, $phpdbg, $preload, $redir_tests, + $repeat, $result_tests_file, $slow_min_ms, $start_time, $switch, + $temp_source, $temp_target, $temp_urlbase, $test_cnt, $test_dirs, + $test_files, $test_idx, $test_list, $test_results, $testfile, + $user_tests, $valgrind, $sum_results, $shuffle; + // Parallel testing + global $workers, $workerID; + + $workerID = 0; + if (getenv("TEST_PHP_WORKER")) { + $workerID = intval(getenv("TEST_PHP_WORKER")); + run_worker(); + return; + } + + define('INIT_DIR', getcwd()); + + // change into the PHP source directory. + if (getenv('TEST_PHP_SRCDIR')) { + @chdir(getenv('TEST_PHP_SRCDIR')); + } + define('TEST_PHP_SRCDIR', getcwd()); + + if (!function_exists('proc_open')) { + echo <<<NO_PROC_OPEN_ERROR +-----------------------------------------------------------+ | ! ERROR ! | @@ -84,452 +84,452 @@ function main() +-----------------------------------------------------------+ NO_PROC_OPEN_ERROR; - exit(1); - } - - // If timezone is not set, use UTC. - if (ini_get('date.timezone') == '') { - date_default_timezone_set('UTC'); - } - - // Delete some security related environment variables - putenv('SSH_CLIENT=deleted'); - putenv('SSH_AUTH_SOCK=deleted'); - putenv('SSH_TTY=deleted'); - putenv('SSH_CONNECTION=deleted'); - - set_time_limit(0); - - ini_set('pcre.backtrack_limit', PHP_INT_MAX); - - // delete as much output buffers as possible - while (@ob_end_clean()) { - ; - } - if (ob_get_level()) { - echo "Not all buffers were deleted.\n"; - } - - error_reporting(E_ALL); - - $environment = $_ENV ?? array(); - // Note: php.ini-development sets variables_order="GPCS" not "EGPCS", in which case $_ENV is NOT populated. - // detect and handle this case, or die or warn - if (empty($environment)) { - // not documented, but returns array of all environment variables - $environment = getenv(); - } - if (empty($environment['TEMP'])) { - $environment['TEMP'] = sys_get_temp_dir(); - - if (empty($environment['TEMP'])) { - // for example, OpCache on Windows will fail in this case because child processes (for tests) will not get - // a TEMP variable, so GetTempPath() will fallback to c:\windows, while GetTempPath() will return %TEMP% for parent - // (likely a different path). The parent will initialize the OpCache in that path, and child will fail to reattach to - // the OpCache because it will be using the wrong path. - die("TEMP environment is NOT set"); - } else { - if (count($environment) == 1) { - // not having other environment variables, only having TEMP, is probably ok, but strange and may make a - // difference in the test pass rate, so warn the user. - echo "WARNING: Only 1 environment variable will be available to tests(TEMP environment variable)" . PHP_EOL; - } - } - } - // - if ((substr(PHP_OS, 0, 3) == "WIN") && empty($environment["SystemRoot"])) { - $environment["SystemRoot"] = getenv("SystemRoot"); - } - - $php = null; - $php_cgi = null; - $phpdbg = null; - - if (getenv('TEST_PHP_EXECUTABLE')) { - $php = getenv('TEST_PHP_EXECUTABLE'); - - if ($php == 'auto') { - $php = TEST_PHP_SRCDIR . '/sapi/cli/php'; - putenv("TEST_PHP_EXECUTABLE=$php"); - - if (!getenv('TEST_PHP_CGI_EXECUTABLE')) { - $php_cgi = TEST_PHP_SRCDIR . '/sapi/cgi/php-cgi'; - - if (file_exists($php_cgi)) { - putenv("TEST_PHP_CGI_EXECUTABLE=$php_cgi"); - } else { - $php_cgi = null; - } - } - } - $environment['TEST_PHP_EXECUTABLE'] = $php; - } - - if (getenv('TEST_PHP_CGI_EXECUTABLE')) { - $php_cgi = getenv('TEST_PHP_CGI_EXECUTABLE'); - - if ($php_cgi == 'auto') { - $php_cgi = TEST_PHP_SRCDIR . '/sapi/cgi/php-cgi'; - putenv("TEST_PHP_CGI_EXECUTABLE=$php_cgi"); - } - - $environment['TEST_PHP_CGI_EXECUTABLE'] = $php_cgi; - } - - if (!getenv('TEST_PHPDBG_EXECUTABLE')) { - if (!strncasecmp(PHP_OS, "win", 3) && file_exists(dirname($php) . "/phpdbg.exe")) { - $phpdbg = realpath(dirname($php) . "/phpdbg.exe"); - } elseif (file_exists(dirname($php) . "/../../sapi/phpdbg/phpdbg")) { - $phpdbg = realpath(dirname($php) . "/../../sapi/phpdbg/phpdbg"); - } elseif (file_exists("./sapi/phpdbg/phpdbg")) { - $phpdbg = realpath("./sapi/phpdbg/phpdbg"); - } elseif (file_exists(dirname($php) . "/phpdbg")) { - $phpdbg = realpath(dirname($php) . "/phpdbg"); - } else { - $phpdbg = null; - } - if ($phpdbg) { - putenv("TEST_PHPDBG_EXECUTABLE=$phpdbg"); - } - } - - if (getenv('TEST_PHPDBG_EXECUTABLE')) { - $phpdbg = getenv('TEST_PHPDBG_EXECUTABLE'); - - if ($phpdbg == 'auto') { - $phpdbg = TEST_PHP_SRCDIR . '/sapi/phpdbg/phpdbg'; - putenv("TEST_PHPDBG_EXECUTABLE=$phpdbg"); - } - - $environment['TEST_PHPDBG_EXECUTABLE'] = $phpdbg; - } - - if (getenv('TEST_PHP_LOG_FORMAT')) { - $log_format = strtoupper(getenv('TEST_PHP_LOG_FORMAT')); - } else { - $log_format = 'LEODS'; - } - - // Check whether a detailed log is wanted. - if (getenv('TEST_PHP_DETAILED')) { - $DETAILED = getenv('TEST_PHP_DETAILED'); - } else { - $DETAILED = 0; - } - - junit_init(); - - if (getenv('SHOW_ONLY_GROUPS')) { - $SHOW_ONLY_GROUPS = explode(",", getenv('SHOW_ONLY_GROUPS')); - } else { - $SHOW_ONLY_GROUPS = array(); - } - - // Check whether user test dirs are requested. - if (getenv('TEST_PHP_USER')) { - $user_tests = explode(',', getenv('TEST_PHP_USER')); - } else { - $user_tests = array(); - } - - $exts_to_test = array(); - $ini_overwrites = array( - 'output_handler=', - 'open_basedir=', - 'disable_functions=', - 'output_buffering=Off', - 'error_reporting=' . E_ALL, - 'display_errors=1', - 'display_startup_errors=1', - 'log_errors=0', - 'html_errors=0', - 'track_errors=0', - 'report_memleaks=1', - 'report_zend_debug=0', - 'docref_root=', - 'docref_ext=.html', - 'error_prepend_string=', - 'error_append_string=', - 'auto_prepend_file=', - 'auto_append_file=', - 'ignore_repeated_errors=0', - 'precision=14', - 'memory_limit=128M', - 'log_errors_max_len=0', - 'opcache.fast_shutdown=0', - 'opcache.file_update_protection=0', - 'opcache.revalidate_freq=0', - 'zend.assertions=1', - 'zend.exception_ignore_args=0', - ); - - $no_file_cache = '-d opcache.file_cache= -d opcache.file_cache_only=0'; - - define('PHP_QA_EMAIL', 'qa-reports@lists.php.net'); - define('QA_SUBMISSION_PAGE', 'http://qa.php.net/buildtest-process.php'); - define('QA_REPORTS_PAGE', 'http://qa.php.net/reports'); - define('TRAVIS_CI', (bool)getenv('TRAVIS')); - - // Determine the tests to be run. - - $test_files = array(); - $redir_tests = array(); - $test_results = array(); - $PHP_FAILED_TESTS = array( - 'BORKED' => array(), - 'FAILED' => array(), - 'WARNED' => array(), - 'LEAKED' => array(), - 'XFAILED' => array(), - 'XLEAKED' => array(), - 'SLOW' => array() - ); - - // If parameters given assume they represent selected tests to run. - $result_tests_file = false; - $failed_tests_file = false; - $pass_option_n = false; - $pass_options = ''; - - $output_file = INIT_DIR . '/php_test_results_' . date('Ymd_Hi') . '.txt'; - - $just_save_results = false; - $valgrind = null; - $html_output = false; - $html_file = null; - $temp_source = null; - $temp_target = null; - $temp_urlbase = null; - $conf_passed = null; - $no_clean = false; - $slow_min_ms = INF; - $preload = false; - $shuffle = false; - $workers = null; - - $cfgtypes = array('show', 'keep'); - $cfgfiles = array('skip', 'php', 'clean', 'out', 'diff', 'exp', 'mem'); - $cfg = array(); - - foreach ($cfgtypes as $type) { - $cfg[$type] = array(); - - foreach ($cfgfiles as $file) { - $cfg[$type][$file] = false; - } - } - - if (!isset($argc, $argv) || !$argc) { - $argv = array(__FILE__); - $argc = 1; - } - - if (getenv('TEST_PHP_ARGS')) { - $argv = array_merge($argv, explode(' ', getenv('TEST_PHP_ARGS'))); - $argc = count($argv); - } - - for ($i = 1; $i < $argc; $i++) { - $is_switch = false; - $switch = substr($argv[$i], 1, 1); - $repeat = substr($argv[$i], 0, 1) == '-'; - - while ($repeat) { - - if (!$is_switch) { - $switch = substr($argv[$i], 1, 1); - } - - $is_switch = true; - - if ($repeat) { - foreach ($cfgtypes as $type) { - if (strpos($switch, '--' . $type) === 0) { - foreach ($cfgfiles as $file) { - if ($switch == '--' . $type . '-' . $file) { - $cfg[$type][$file] = true; - $is_switch = false; - break; - } - } - } - } - } - - if (!$is_switch) { - $is_switch = true; - break; - } - - $repeat = false; - - switch ($switch) { - case 'j': - $workers = substr($argv[$i], 2); - if (!preg_match('/^\d+$/', $workers) || $workers == 0) { - error("'$workers' is not a valid number of workers, try e.g. -j16 for 16 workers"); - } - $workers = intval($workers, 10); - // Don't use parallel testing infrastructure if there is only one worker. - if ($workers === 1) { - $workers = null; - } - break; - case 'r': - case 'l': - $test_list = file($argv[++$i]); - if ($test_list) { - foreach ($test_list as $test) { - $matches = array(); - if (preg_match('/^#.*\[(.*)\]\:\s+(.*)$/', $test, $matches)) { - $redir_tests[] = array($matches[1], $matches[2]); - } else { - if (strlen($test)) { - $test_files[] = trim($test); - } - } - } - } - if ($switch != 'l') { - break; - } - $i--; - // break left intentionally - case 'w': - $failed_tests_file = fopen($argv[++$i], 'w+t'); - break; - case 'a': - $failed_tests_file = fopen($argv[++$i], 'a+t'); - break; - case 'W': - $result_tests_file = fopen($argv[++$i], 'w+t'); - break; - case 'c': - $conf_passed = $argv[++$i]; - break; - case 'd': - $ini_overwrites[] = $argv[++$i]; - break; - case 'g': - $SHOW_ONLY_GROUPS = explode(",", $argv[++$i]); - break; - //case 'h' - case '--keep-all': - foreach ($cfgfiles as $file) { - $cfg['keep'][$file] = true; - } - break; - //case 'l' - case 'm': - $valgrind = new RuntestsValgrind($environment); - break; - case 'M': - $valgrind = new RuntestsValgrind($environment, $argv[++$i]); - break; - case 'n': - if (!$pass_option_n) { - $pass_options .= ' -n'; - } - $pass_option_n = true; - break; - case 'e': - $pass_options .= ' -e'; - break; - case '--preload': - $preload = true; - break; - case '--no-clean': - $no_clean = true; - break; - case 'p': - $php = $argv[++$i]; - putenv("TEST_PHP_EXECUTABLE=$php"); - $environment['TEST_PHP_EXECUTABLE'] = $php; - break; - case 'P': - $php = PHP_BINARY; - putenv("TEST_PHP_EXECUTABLE=$php"); - $environment['TEST_PHP_EXECUTABLE'] = $php; - break; - case 'q': - putenv('NO_INTERACTION=1'); - $environment['NO_INTERACTION'] = 1; - break; - //case 'r' - case 's': - $output_file = $argv[++$i]; - $just_save_results = true; - break; - case '--set-timeout': - $environment['TEST_TIMEOUT'] = $argv[++$i]; - break; - case '--show-all': - foreach ($cfgfiles as $file) { - $cfg['show'][$file] = true; - } - break; - case '--show-slow': - $slow_min_ms = $argv[++$i]; - break; - case '--temp-source': - $temp_source = $argv[++$i]; - break; - case '--temp-target': - $temp_target = $argv[++$i]; - if ($temp_urlbase) { - $temp_urlbase = $temp_target; - } - break; - case '--temp-urlbase': - $temp_urlbase = $argv[++$i]; - break; - case 'v': - case '--verbose': - $DETAILED = true; - break; - case 'x': - $environment['SKIP_SLOW_TESTS'] = 1; - break; - case '--offline': - $environment['SKIP_ONLINE_TESTS'] = 1; - break; - case '--shuffle': - $shuffle = true; - break; - case '--asan': - $environment['USE_ZEND_ALLOC'] = 0; - $environment['USE_TRACKED_ALLOC'] = 1; - $environment['SKIP_ASAN'] = 1; - $environment['SKIP_PERF_SENSITIVE'] = 1; - - $lsanSuppressions = __DIR__ . '/azure/lsan-suppressions.txt'; - if (file_exists($lsanSuppressions)) { - $environment['LSAN_OPTIONS'] = 'suppressions=' . $lsanSuppressions - . ':print_suppressions=0'; - } - break; - //case 'w' - case '-': - // repeat check with full switch - $switch = $argv[$i]; - if ($switch != '-') { - $repeat = true; - } - break; - case '--html': - $html_file = fopen($argv[++$i], 'wt'); - $html_output = is_resource($html_file); - break; - case '--version': - echo '$Id$' . "\n"; - exit(1); - - default: - echo "Illegal switch '$switch' specified!\n"; - case 'h': - case '-help': - case '--help': - echo <<<HELP + exit(1); + } + + // If timezone is not set, use UTC. + if (ini_get('date.timezone') == '') { + date_default_timezone_set('UTC'); + } + + // Delete some security related environment variables + putenv('SSH_CLIENT=deleted'); + putenv('SSH_AUTH_SOCK=deleted'); + putenv('SSH_TTY=deleted'); + putenv('SSH_CONNECTION=deleted'); + + set_time_limit(0); + + ini_set('pcre.backtrack_limit', PHP_INT_MAX); + + // delete as much output buffers as possible + while (@ob_end_clean()) { + ; + } + if (ob_get_level()) { + echo "Not all buffers were deleted.\n"; + } + + error_reporting(E_ALL); + + $environment = $_ENV ?? array(); + // Note: php.ini-development sets variables_order="GPCS" not "EGPCS", in which case $_ENV is NOT populated. + // detect and handle this case, or die or warn + if (empty($environment)) { + // not documented, but returns array of all environment variables + $environment = getenv(); + } + if (empty($environment['TEMP'])) { + $environment['TEMP'] = sys_get_temp_dir(); + + if (empty($environment['TEMP'])) { + // for example, OpCache on Windows will fail in this case because child processes (for tests) will not get + // a TEMP variable, so GetTempPath() will fallback to c:\windows, while GetTempPath() will return %TEMP% for parent + // (likely a different path). The parent will initialize the OpCache in that path, and child will fail to reattach to + // the OpCache because it will be using the wrong path. + die("TEMP environment is NOT set"); + } else { + if (count($environment) == 1) { + // not having other environment variables, only having TEMP, is probably ok, but strange and may make a + // difference in the test pass rate, so warn the user. + echo "WARNING: Only 1 environment variable will be available to tests(TEMP environment variable)" . PHP_EOL; + } + } + } + // + if ((substr(PHP_OS, 0, 3) == "WIN") && empty($environment["SystemRoot"])) { + $environment["SystemRoot"] = getenv("SystemRoot"); + } + + $php = null; + $php_cgi = null; + $phpdbg = null; + + if (getenv('TEST_PHP_EXECUTABLE')) { + $php = getenv('TEST_PHP_EXECUTABLE'); + + if ($php == 'auto') { + $php = TEST_PHP_SRCDIR . '/sapi/cli/php'; + putenv("TEST_PHP_EXECUTABLE=$php"); + + if (!getenv('TEST_PHP_CGI_EXECUTABLE')) { + $php_cgi = TEST_PHP_SRCDIR . '/sapi/cgi/php-cgi'; + + if (file_exists($php_cgi)) { + putenv("TEST_PHP_CGI_EXECUTABLE=$php_cgi"); + } else { + $php_cgi = null; + } + } + } + $environment['TEST_PHP_EXECUTABLE'] = $php; + } + + if (getenv('TEST_PHP_CGI_EXECUTABLE')) { + $php_cgi = getenv('TEST_PHP_CGI_EXECUTABLE'); + + if ($php_cgi == 'auto') { + $php_cgi = TEST_PHP_SRCDIR . '/sapi/cgi/php-cgi'; + putenv("TEST_PHP_CGI_EXECUTABLE=$php_cgi"); + } + + $environment['TEST_PHP_CGI_EXECUTABLE'] = $php_cgi; + } + + if (!getenv('TEST_PHPDBG_EXECUTABLE')) { + if (!strncasecmp(PHP_OS, "win", 3) && file_exists(dirname($php) . "/phpdbg.exe")) { + $phpdbg = realpath(dirname($php) . "/phpdbg.exe"); + } elseif (file_exists(dirname($php) . "/../../sapi/phpdbg/phpdbg")) { + $phpdbg = realpath(dirname($php) . "/../../sapi/phpdbg/phpdbg"); + } elseif (file_exists("./sapi/phpdbg/phpdbg")) { + $phpdbg = realpath("./sapi/phpdbg/phpdbg"); + } elseif (file_exists(dirname($php) . "/phpdbg")) { + $phpdbg = realpath(dirname($php) . "/phpdbg"); + } else { + $phpdbg = null; + } + if ($phpdbg) { + putenv("TEST_PHPDBG_EXECUTABLE=$phpdbg"); + } + } + + if (getenv('TEST_PHPDBG_EXECUTABLE')) { + $phpdbg = getenv('TEST_PHPDBG_EXECUTABLE'); + + if ($phpdbg == 'auto') { + $phpdbg = TEST_PHP_SRCDIR . '/sapi/phpdbg/phpdbg'; + putenv("TEST_PHPDBG_EXECUTABLE=$phpdbg"); + } + + $environment['TEST_PHPDBG_EXECUTABLE'] = $phpdbg; + } + + if (getenv('TEST_PHP_LOG_FORMAT')) { + $log_format = strtoupper(getenv('TEST_PHP_LOG_FORMAT')); + } else { + $log_format = 'LEODS'; + } + + // Check whether a detailed log is wanted. + if (getenv('TEST_PHP_DETAILED')) { + $DETAILED = getenv('TEST_PHP_DETAILED'); + } else { + $DETAILED = 0; + } + + junit_init(); + + if (getenv('SHOW_ONLY_GROUPS')) { + $SHOW_ONLY_GROUPS = explode(",", getenv('SHOW_ONLY_GROUPS')); + } else { + $SHOW_ONLY_GROUPS = array(); + } + + // Check whether user test dirs are requested. + if (getenv('TEST_PHP_USER')) { + $user_tests = explode(',', getenv('TEST_PHP_USER')); + } else { + $user_tests = array(); + } + + $exts_to_test = array(); + $ini_overwrites = array( + 'output_handler=', + 'open_basedir=', + 'disable_functions=', + 'output_buffering=Off', + 'error_reporting=' . E_ALL, + 'display_errors=1', + 'display_startup_errors=1', + 'log_errors=0', + 'html_errors=0', + 'track_errors=0', + 'report_memleaks=1', + 'report_zend_debug=0', + 'docref_root=', + 'docref_ext=.html', + 'error_prepend_string=', + 'error_append_string=', + 'auto_prepend_file=', + 'auto_append_file=', + 'ignore_repeated_errors=0', + 'precision=14', + 'memory_limit=128M', + 'log_errors_max_len=0', + 'opcache.fast_shutdown=0', + 'opcache.file_update_protection=0', + 'opcache.revalidate_freq=0', + 'zend.assertions=1', + 'zend.exception_ignore_args=0', + ); + + $no_file_cache = '-d opcache.file_cache= -d opcache.file_cache_only=0'; + + define('PHP_QA_EMAIL', 'qa-reports@lists.php.net'); + define('QA_SUBMISSION_PAGE', 'http://qa.php.net/buildtest-process.php'); + define('QA_REPORTS_PAGE', 'http://qa.php.net/reports'); + define('TRAVIS_CI', (bool)getenv('TRAVIS')); + + // Determine the tests to be run. + + $test_files = array(); + $redir_tests = array(); + $test_results = array(); + $PHP_FAILED_TESTS = array( + 'BORKED' => array(), + 'FAILED' => array(), + 'WARNED' => array(), + 'LEAKED' => array(), + 'XFAILED' => array(), + 'XLEAKED' => array(), + 'SLOW' => array() + ); + + // If parameters given assume they represent selected tests to run. + $result_tests_file = false; + $failed_tests_file = false; + $pass_option_n = false; + $pass_options = ''; + + $output_file = INIT_DIR . '/php_test_results_' . date('Ymd_Hi') . '.txt'; + + $just_save_results = false; + $valgrind = null; + $html_output = false; + $html_file = null; + $temp_source = null; + $temp_target = null; + $temp_urlbase = null; + $conf_passed = null; + $no_clean = false; + $slow_min_ms = INF; + $preload = false; + $shuffle = false; + $workers = null; + + $cfgtypes = array('show', 'keep'); + $cfgfiles = array('skip', 'php', 'clean', 'out', 'diff', 'exp', 'mem'); + $cfg = array(); + + foreach ($cfgtypes as $type) { + $cfg[$type] = array(); + + foreach ($cfgfiles as $file) { + $cfg[$type][$file] = false; + } + } + + if (!isset($argc, $argv) || !$argc) { + $argv = array(__FILE__); + $argc = 1; + } + + if (getenv('TEST_PHP_ARGS')) { + $argv = array_merge($argv, explode(' ', getenv('TEST_PHP_ARGS'))); + $argc = count($argv); + } + + for ($i = 1; $i < $argc; $i++) { + $is_switch = false; + $switch = substr($argv[$i], 1, 1); + $repeat = substr($argv[$i], 0, 1) == '-'; + + while ($repeat) { + + if (!$is_switch) { + $switch = substr($argv[$i], 1, 1); + } + + $is_switch = true; + + if ($repeat) { + foreach ($cfgtypes as $type) { + if (strpos($switch, '--' . $type) === 0) { + foreach ($cfgfiles as $file) { + if ($switch == '--' . $type . '-' . $file) { + $cfg[$type][$file] = true; + $is_switch = false; + break; + } + } + } + } + } + + if (!$is_switch) { + $is_switch = true; + break; + } + + $repeat = false; + + switch ($switch) { + case 'j': + $workers = substr($argv[$i], 2); + if (!preg_match('/^\d+$/', $workers) || $workers == 0) { + error("'$workers' is not a valid number of workers, try e.g. -j16 for 16 workers"); + } + $workers = intval($workers, 10); + // Don't use parallel testing infrastructure if there is only one worker. + if ($workers === 1) { + $workers = null; + } + break; + case 'r': + case 'l': + $test_list = file($argv[++$i]); + if ($test_list) { + foreach ($test_list as $test) { + $matches = array(); + if (preg_match('/^#.*\[(.*)\]\:\s+(.*)$/', $test, $matches)) { + $redir_tests[] = array($matches[1], $matches[2]); + } else { + if (strlen($test)) { + $test_files[] = trim($test); + } + } + } + } + if ($switch != 'l') { + break; + } + $i--; + // break left intentionally + case 'w': + $failed_tests_file = fopen($argv[++$i], 'w+t'); + break; + case 'a': + $failed_tests_file = fopen($argv[++$i], 'a+t'); + break; + case 'W': + $result_tests_file = fopen($argv[++$i], 'w+t'); + break; + case 'c': + $conf_passed = $argv[++$i]; + break; + case 'd': + $ini_overwrites[] = $argv[++$i]; + break; + case 'g': + $SHOW_ONLY_GROUPS = explode(",", $argv[++$i]); + break; + //case 'h' + case '--keep-all': + foreach ($cfgfiles as $file) { + $cfg['keep'][$file] = true; + } + break; + //case 'l' + case 'm': + $valgrind = new RuntestsValgrind($environment); + break; + case 'M': + $valgrind = new RuntestsValgrind($environment, $argv[++$i]); + break; + case 'n': + if (!$pass_option_n) { + $pass_options .= ' -n'; + } + $pass_option_n = true; + break; + case 'e': + $pass_options .= ' -e'; + break; + case '--preload': + $preload = true; + break; + case '--no-clean': + $no_clean = true; + break; + case 'p': + $php = $argv[++$i]; + putenv("TEST_PHP_EXECUTABLE=$php"); + $environment['TEST_PHP_EXECUTABLE'] = $php; + break; + case 'P': + $php = PHP_BINARY; + putenv("TEST_PHP_EXECUTABLE=$php"); + $environment['TEST_PHP_EXECUTABLE'] = $php; + break; + case 'q': + putenv('NO_INTERACTION=1'); + $environment['NO_INTERACTION'] = 1; + break; + //case 'r' + case 's': + $output_file = $argv[++$i]; + $just_save_results = true; + break; + case '--set-timeout': + $environment['TEST_TIMEOUT'] = $argv[++$i]; + break; + case '--show-all': + foreach ($cfgfiles as $file) { + $cfg['show'][$file] = true; + } + break; + case '--show-slow': + $slow_min_ms = $argv[++$i]; + break; + case '--temp-source': + $temp_source = $argv[++$i]; + break; + case '--temp-target': + $temp_target = $argv[++$i]; + if ($temp_urlbase) { + $temp_urlbase = $temp_target; + } + break; + case '--temp-urlbase': + $temp_urlbase = $argv[++$i]; + break; + case 'v': + case '--verbose': + $DETAILED = true; + break; + case 'x': + $environment['SKIP_SLOW_TESTS'] = 1; + break; + case '--offline': + $environment['SKIP_ONLINE_TESTS'] = 1; + break; + case '--shuffle': + $shuffle = true; + break; + case '--asan': + $environment['USE_ZEND_ALLOC'] = 0; + $environment['USE_TRACKED_ALLOC'] = 1; + $environment['SKIP_ASAN'] = 1; + $environment['SKIP_PERF_SENSITIVE'] = 1; + + $lsanSuppressions = __DIR__ . '/azure/lsan-suppressions.txt'; + if (file_exists($lsanSuppressions)) { + $environment['LSAN_OPTIONS'] = 'suppressions=' . $lsanSuppressions + . ':print_suppressions=0'; + } + break; + //case 'w' + case '-': + // repeat check with full switch + $switch = $argv[$i]; + if ($switch != '-') { + $repeat = true; + } + break; + case '--html': + $html_file = fopen($argv[++$i], 'wt'); + $html_output = is_resource($html_file); + break; + case '--version': + echo '$Id$' . "\n"; + exit(1); + + default: + echo "Illegal switch '$switch' specified!\n"; + case 'h': + case '-help': + case '--help': + echo <<<HELP Synopsis: php run-tests.php [options] [files] [directories] @@ -615,297 +615,297 @@ Options: --no-clean Do not execute clean section if any. HELP; - exit(1); - } - } - - if (!$is_switch) { - $testfile = realpath($argv[$i]); - - if (!$testfile && strpos($argv[$i], '*') !== false && function_exists('glob')) { - - if (substr($argv[$i], -5) == '.phpt') { - $pattern_match = glob($argv[$i]); - } else { - if (preg_match("/\*$/", $argv[$i])) { - $pattern_match = glob($argv[$i] . '.phpt'); - } else { - die('Cannot find test file "' . $argv[$i] . '".' . PHP_EOL); - } - } - - if (is_array($pattern_match)) { - $test_files = array_merge($test_files, $pattern_match); - } - - } else { - if (is_dir($testfile)) { - find_files($testfile); - } else { - if (substr($testfile, -5) == '.phpt') { - $test_files[] = $testfile; - } else { - die('Cannot find test file "' . $argv[$i] . '".' . PHP_EOL); - } - } - } - } - } - - // Default to PHP_BINARY as executable - if (!isset($environment['TEST_PHP_EXECUTABLE'])) { - $php = PHP_BINARY; - putenv("TEST_PHP_EXECUTABLE=$php"); - $environment['TEST_PHP_EXECUTABLE'] = $php; - } - - if (strlen($conf_passed)) { - if (substr(PHP_OS, 0, 3) == "WIN") { - $pass_options .= " -c " . escapeshellarg($conf_passed); - } else { - $pass_options .= " -c '" . realpath($conf_passed) . "'"; - } - } - - $test_files = array_unique($test_files); - $test_files = array_merge($test_files, $redir_tests); - - // Run selected tests. - $test_cnt = count($test_files); - - if ($test_cnt) { - putenv('NO_INTERACTION=1'); - verify_config(); - write_information(); - usort($test_files, "test_sort"); - $start_time = time(); - - if (!$html_output) { - echo "Running selected tests.\n"; - } else { - show_start($start_time); - } - - $test_idx = 0; - run_all_tests($test_files, $environment); - $end_time = time(); - - if ($html_output) { - show_end($end_time); - } - - if ($failed_tests_file) { - fclose($failed_tests_file); - } - - if ($result_tests_file) { - fclose($result_tests_file); - } - - compute_summary(); - if ($html_output) { - fwrite($html_file, "<hr/>\n" . get_summary(false, true)); - } - echo "====================================================================="; - echo get_summary(false, false); - - if ($html_output) { - fclose($html_file); - } - - if ($output_file != '' && $just_save_results) { - save_or_mail_results(); - } - - junit_save_xml(); - - if (getenv('REPORT_EXIT_STATUS') !== '0' && - getenv('REPORT_EXIT_STATUS') !== 'no' && ($sum_results['FAILED'] || $sum_results['BORKED'] || $sum_results['LEAKED'])) { - exit(1); - } - - return; - } - - verify_config(); - write_information(); - - // Compile a list of all test files (*.phpt). - $test_files = array(); - $exts_tested = count($exts_to_test); - $exts_skipped = 0; - $ignored_by_ext = 0; - sort($exts_to_test); - $test_dirs = array(); - $optionals = array('Zend', 'tests', 'ext', 'sapi'); - - foreach ($optionals as $dir) { - if (is_dir($dir)) { - $test_dirs[] = $dir; - } - } - - // Convert extension names to lowercase - foreach ($exts_to_test as $key => $val) { - $exts_to_test[$key] = strtolower($val); - } - - foreach ($test_dirs as $dir) { - find_files(TEST_PHP_SRCDIR . "/{$dir}", $dir == 'ext'); - } - - foreach ($user_tests as $dir) { - find_files($dir, $dir == 'ext'); - } - - $test_files = array_unique($test_files); - usort($test_files, "test_sort"); - - $start_time = time(); - show_start($start_time); - - $test_cnt = count($test_files); - $test_idx = 0; - run_all_tests($test_files, $environment); - $end_time = time(); - - if ($failed_tests_file) { - fclose($failed_tests_file); - } - - if ($result_tests_file) { - fclose($result_tests_file); - } - - // Summarize results - - if (0 == count($test_results)) { - echo "No tests were run.\n"; - return; - } - - compute_summary(); - - show_end($end_time); - show_summary(); - - if ($html_output) { - fclose($html_file); - } - - save_or_mail_results(); - - junit_save_xml(); - if (getenv('REPORT_EXIT_STATUS') !== '0' && - getenv('REPORT_EXIT_STATUS') !== 'no' && ($sum_results['FAILED'] || $sum_results['LEAKED'])) { - exit(1); - } - exit(0); + exit(1); + } + } + + if (!$is_switch) { + $testfile = realpath($argv[$i]); + + if (!$testfile && strpos($argv[$i], '*') !== false && function_exists('glob')) { + + if (substr($argv[$i], -5) == '.phpt') { + $pattern_match = glob($argv[$i]); + } else { + if (preg_match("/\*$/", $argv[$i])) { + $pattern_match = glob($argv[$i] . '.phpt'); + } else { + die('Cannot find test file "' . $argv[$i] . '".' . PHP_EOL); + } + } + + if (is_array($pattern_match)) { + $test_files = array_merge($test_files, $pattern_match); + } + + } else { + if (is_dir($testfile)) { + find_files($testfile); + } else { + if (substr($testfile, -5) == '.phpt') { + $test_files[] = $testfile; + } else { + die('Cannot find test file "' . $argv[$i] . '".' . PHP_EOL); + } + } + } + } + } + + // Default to PHP_BINARY as executable + if (!isset($environment['TEST_PHP_EXECUTABLE'])) { + $php = PHP_BINARY; + putenv("TEST_PHP_EXECUTABLE=$php"); + $environment['TEST_PHP_EXECUTABLE'] = $php; + } + + if (strlen($conf_passed)) { + if (substr(PHP_OS, 0, 3) == "WIN") { + $pass_options .= " -c " . escapeshellarg($conf_passed); + } else { + $pass_options .= " -c '" . realpath($conf_passed) . "'"; + } + } + + $test_files = array_unique($test_files); + $test_files = array_merge($test_files, $redir_tests); + + // Run selected tests. + $test_cnt = count($test_files); + + if ($test_cnt) { + putenv('NO_INTERACTION=1'); + verify_config(); + write_information(); + usort($test_files, "test_sort"); + $start_time = time(); + + if (!$html_output) { + echo "Running selected tests.\n"; + } else { + show_start($start_time); + } + + $test_idx = 0; + run_all_tests($test_files, $environment); + $end_time = time(); + + if ($html_output) { + show_end($end_time); + } + + if ($failed_tests_file) { + fclose($failed_tests_file); + } + + if ($result_tests_file) { + fclose($result_tests_file); + } + + compute_summary(); + if ($html_output) { + fwrite($html_file, "<hr/>\n" . get_summary(false, true)); + } + echo "====================================================================="; + echo get_summary(false, false); + + if ($html_output) { + fclose($html_file); + } + + if ($output_file != '' && $just_save_results) { + save_or_mail_results(); + } + + junit_save_xml(); + + if (getenv('REPORT_EXIT_STATUS') !== '0' && + getenv('REPORT_EXIT_STATUS') !== 'no' && ($sum_results['FAILED'] || $sum_results['BORKED'] || $sum_results['LEAKED'])) { + exit(1); + } + + return; + } + + verify_config(); + write_information(); + + // Compile a list of all test files (*.phpt). + $test_files = array(); + $exts_tested = count($exts_to_test); + $exts_skipped = 0; + $ignored_by_ext = 0; + sort($exts_to_test); + $test_dirs = array(); + $optionals = array('Zend', 'tests', 'ext', 'sapi'); + + foreach ($optionals as $dir) { + if (is_dir($dir)) { + $test_dirs[] = $dir; + } + } + + // Convert extension names to lowercase + foreach ($exts_to_test as $key => $val) { + $exts_to_test[$key] = strtolower($val); + } + + foreach ($test_dirs as $dir) { + find_files(TEST_PHP_SRCDIR . "/{$dir}", $dir == 'ext'); + } + + foreach ($user_tests as $dir) { + find_files($dir, $dir == 'ext'); + } + + $test_files = array_unique($test_files); + usort($test_files, "test_sort"); + + $start_time = time(); + show_start($start_time); + + $test_cnt = count($test_files); + $test_idx = 0; + run_all_tests($test_files, $environment); + $end_time = time(); + + if ($failed_tests_file) { + fclose($failed_tests_file); + } + + if ($result_tests_file) { + fclose($result_tests_file); + } + + // Summarize results + + if (0 == count($test_results)) { + echo "No tests were run.\n"; + return; + } + + compute_summary(); + + show_end($end_time); + show_summary(); + + if ($html_output) { + fclose($html_file); + } + + save_or_mail_results(); + + junit_save_xml(); + if (getenv('REPORT_EXIT_STATUS') !== '0' && + getenv('REPORT_EXIT_STATUS') !== 'no' && ($sum_results['FAILED'] || $sum_results['LEAKED'])) { + exit(1); + } + exit(0); } if (!function_exists("hrtime")) { - function hrtime(bool $as_num = false) - { - $t = microtime(true); + function hrtime(bool $as_num = false) + { + $t = microtime(true); - if ($as_num) { - return $t * 1000000000; - } + if ($as_num) { + return $t * 1000000000; + } - $s = floor($t); - return array(0 => $s, 1 => ($t - $s) * 1000000000); - } + $s = floor($t); + return array(0 => $s, 1 => ($t - $s) * 1000000000); + } } function verify_config() { - global $php; + global $php; - if (empty($php) || !file_exists($php)) { - error('environment variable TEST_PHP_EXECUTABLE must be set to specify PHP executable!'); - } + if (empty($php) || !file_exists($php)) { + error('environment variable TEST_PHP_EXECUTABLE must be set to specify PHP executable!'); + } - if (!is_executable($php)) { - error("invalid PHP executable specified by TEST_PHP_EXECUTABLE = $php"); - } + if (!is_executable($php)) { + error("invalid PHP executable specified by TEST_PHP_EXECUTABLE = $php"); + } } function write_information() { - global $php, $php_cgi, $phpdbg, $php_info, $user_tests, $ini_overwrites, $pass_options, $exts_to_test, $valgrind, $no_file_cache; + global $php, $php_cgi, $phpdbg, $php_info, $user_tests, $ini_overwrites, $pass_options, $exts_to_test, $valgrind, $no_file_cache; - // Get info from php - $info_file = __DIR__ . '/run-test-info.php'; - @unlink($info_file); - $php_info = '<?php echo " + // Get info from php + $info_file = __DIR__ . '/run-test-info.php'; + @unlink($info_file); + $php_info = '<?php echo " PHP_SAPI : " , PHP_SAPI , " PHP_VERSION : " , phpversion() , " ZEND_VERSION: " , zend_version() , " PHP_OS : " , PHP_OS , " - " , php_uname() , " INI actual : " , realpath(get_cfg_var("cfg_file_path")) , " More .INIs : " , (function_exists(\'php_ini_scanned_files\') ? str_replace("\n","", php_ini_scanned_files()) : "** not determined **"); ?>'; - save_text($info_file, $php_info); - $info_params = array(); - settings2array($ini_overwrites, $info_params); - $info_params = settings2params($info_params); - $php_info = `$php $pass_options $info_params $no_file_cache "$info_file"`; - define('TESTED_PHP_VERSION', `$php -n -r "echo PHP_VERSION;"`); - - if ($php_cgi && $php != $php_cgi) { - $php_info_cgi = `$php_cgi $pass_options $info_params $no_file_cache -q "$info_file"`; - $php_info_sep = "\n---------------------------------------------------------------------"; - $php_cgi_info = "$php_info_sep\nPHP : $php_cgi $php_info_cgi$php_info_sep"; - } else { - $php_cgi_info = ''; - } - - if ($phpdbg) { - $phpdbg_info = `$phpdbg $pass_options $info_params $no_file_cache -qrr "$info_file"`; - $php_info_sep = "\n---------------------------------------------------------------------"; - $phpdbg_info = "$php_info_sep\nPHP : $phpdbg $phpdbg_info$php_info_sep"; - } else { - $phpdbg_info = ''; - } - - if (function_exists('opcache_invalidate')) { - opcache_invalidate($info_file, true); - } - @unlink($info_file); - - // load list of enabled extensions - save_text($info_file, - '<?php echo str_replace("Zend OPcache", "opcache", implode(",", get_loaded_extensions())); ?>'); - $exts_to_test = explode(',', `$php $pass_options $info_params $no_file_cache "$info_file"`); - // check for extensions that need special handling and regenerate - $info_params_ex = array( - 'session' => array('session.auto_start=0'), - 'tidy' => array('tidy.clean_output=0'), - 'zlib' => array('zlib.output_compression=Off'), - 'xdebug' => array('xdebug.default_enable=0'), - 'mbstring' => array('mbstring.func_overload=0'), - ); - - foreach ($info_params_ex as $ext => $ini_overwrites_ex) { - if (in_array($ext, $exts_to_test)) { - $ini_overwrites = array_merge($ini_overwrites, $ini_overwrites_ex); - } - } - - if (function_exists('opcache_invalidate')) { - opcache_invalidate($info_file, true); - } - @unlink($info_file); - - // Write test context information. - echo " + save_text($info_file, $php_info); + $info_params = array(); + settings2array($ini_overwrites, $info_params); + $info_params = settings2params($info_params); + $php_info = `$php $pass_options $info_params $no_file_cache "$info_file"`; + define('TESTED_PHP_VERSION', `$php -n -r "echo PHP_VERSION;"`); + + if ($php_cgi && $php != $php_cgi) { + $php_info_cgi = `$php_cgi $pass_options $info_params $no_file_cache -q "$info_file"`; + $php_info_sep = "\n---------------------------------------------------------------------"; + $php_cgi_info = "$php_info_sep\nPHP : $php_cgi $php_info_cgi$php_info_sep"; + } else { + $php_cgi_info = ''; + } + + if ($phpdbg) { + $phpdbg_info = `$phpdbg $pass_options $info_params $no_file_cache -qrr "$info_file"`; + $php_info_sep = "\n---------------------------------------------------------------------"; + $phpdbg_info = "$php_info_sep\nPHP : $phpdbg $phpdbg_info$php_info_sep"; + } else { + $phpdbg_info = ''; + } + + if (function_exists('opcache_invalidate')) { + opcache_invalidate($info_file, true); + } + @unlink($info_file); + + // load list of enabled extensions + save_text($info_file, + '<?php echo str_replace("Zend OPcache", "opcache", implode(",", get_loaded_extensions())); ?>'); + $exts_to_test = explode(',', `$php $pass_options $info_params $no_file_cache "$info_file"`); + // check for extensions that need special handling and regenerate + $info_params_ex = array( + 'session' => array('session.auto_start=0'), + 'tidy' => array('tidy.clean_output=0'), + 'zlib' => array('zlib.output_compression=Off'), + 'xdebug' => array('xdebug.default_enable=0'), + 'mbstring' => array('mbstring.func_overload=0'), + ); + + foreach ($info_params_ex as $ext => $ini_overwrites_ex) { + if (in_array($ext, $exts_to_test)) { + $ini_overwrites = array_merge($ini_overwrites, $ini_overwrites_ex); + } + } + + if (function_exists('opcache_invalidate')) { + opcache_invalidate($info_file, true); + } + @unlink($info_file); + + // Write test context information. + echo " ===================================================================== PHP : $php $php_info $php_cgi_info $phpdbg_info CWD : " . TEST_PHP_SRCDIR . " Extra dirs : "; - foreach ($user_tests as $test_dir) { - echo "{$test_dir}\n "; - } - echo " + foreach ($user_tests as $test_dir) { + echo "{$test_dir}\n "; + } + echo " VALGRIND : " . ($valgrind ? $valgrind->getHeader() : 'Not used') . " ===================================================================== "; @@ -913,194 +913,194 @@ VALGRIND : " . ($valgrind ? $valgrind->getHeader() : 'Not used') . " function save_or_mail_results() { - global $sum_results, $just_save_results, $failed_test_summary, - $PHP_FAILED_TESTS, $php, $output_file; - - /* We got failed Tests, offer the user to send an e-mail to QA team, unless NO_INTERACTION is set */ - if (!getenv('NO_INTERACTION') && !TRAVIS_CI) { - $fp = fopen("php://stdin", "r+"); - if ($sum_results['FAILED'] || $sum_results['BORKED'] || $sum_results['WARNED'] || $sum_results['LEAKED']) { - echo "\nYou may have found a problem in PHP."; - } - echo "\nThis report can be automatically sent to the PHP QA team at\n"; - echo QA_REPORTS_PAGE . " and http://news.php.net/php.qa.reports\n"; - echo "This gives us a better understanding of PHP's behavior.\n"; - echo "If you don't want to send the report immediately you can choose\n"; - echo "option \"s\" to save it. You can then email it to " . PHP_QA_EMAIL . " later.\n"; - echo "Do you want to send this report now? [Yns]: "; - flush(); - - $user_input = fgets($fp, 10); - $just_save_results = (strtolower($user_input[0]) == 's'); - } - - if ($just_save_results || !getenv('NO_INTERACTION') || TRAVIS_CI) { - if ($just_save_results || TRAVIS_CI || strlen(trim($user_input)) == 0 || strtolower($user_input[0]) == 'y') { - /* - * Collect information about the host system for our report - * Fetch phpinfo() output so that we can see the PHP environment - * Make an archive of all the failed tests - * Send an email - */ - if ($just_save_results) { - $user_input = 's'; - } - - /* Ask the user to provide an email address, so that QA team can contact the user */ - if (TRAVIS_CI) { - $user_email = 'travis at php dot net'; - } elseif (!strncasecmp($user_input, 'y', 1) || strlen(trim($user_input)) == 0) { - echo "\nPlease enter your email address.\n(Your address will be mangled so that it will not go out on any\nmailinglist in plain text): "; - flush(); - $user_email = trim(fgets($fp, 1024)); - $user_email = str_replace("@", " at ", str_replace(".", " dot ", $user_email)); - } - - $failed_tests_data = ''; - $sep = "\n" . str_repeat('=', 80) . "\n"; - $failed_tests_data .= $failed_test_summary . "\n"; - $failed_tests_data .= get_summary(true, false) . "\n"; - - if ($sum_results['FAILED']) { - foreach ($PHP_FAILED_TESTS['FAILED'] as $test_info) { - $failed_tests_data .= $sep . $test_info['name'] . $test_info['info']; - $failed_tests_data .= $sep . file_get_contents(realpath($test_info['output']), FILE_BINARY); - $failed_tests_data .= $sep . file_get_contents(realpath($test_info['diff']), FILE_BINARY); - $failed_tests_data .= $sep . "\n\n"; - } - $status = "failed"; - } else { - $status = "success"; - } - - $failed_tests_data .= "\n" . $sep . 'BUILD ENVIRONMENT' . $sep; - $failed_tests_data .= "OS:\n" . PHP_OS . " - " . php_uname() . "\n\n"; - $ldd = $autoconf = $sys_libtool = $libtool = $compiler = 'N/A'; - - if (substr(PHP_OS, 0, 3) != "WIN") { - /* If PHP_AUTOCONF is set, use it; otherwise, use 'autoconf'. */ - if (getenv('PHP_AUTOCONF')) { - $autoconf = shell_exec(getenv('PHP_AUTOCONF') . ' --version'); - } else { - $autoconf = shell_exec('autoconf --version'); - } - - /* Always use the generated libtool - Mac OSX uses 'glibtool' */ - $libtool = shell_exec(INIT_DIR . '/libtool --version'); - - /* Use shtool to find out if there is glibtool present (MacOSX) */ - $sys_libtool_path = shell_exec(__DIR__ . '/build/shtool path glibtool libtool'); - - if ($sys_libtool_path) { - $sys_libtool = shell_exec(str_replace("\n", "", $sys_libtool_path) . ' --version'); - } - - /* Try the most common flags for 'version' */ - $flags = array('-v', '-V', '--version'); - $cc_status = 0; - - foreach ($flags as $flag) { - system(getenv('CC') . " $flag >/dev/null 2>&1", $cc_status); - if ($cc_status == 0) { - $compiler = shell_exec(getenv('CC') . " $flag 2>&1"); - break; - } - } - - $ldd = shell_exec("ldd $php 2>/dev/null"); - } - - $failed_tests_data .= "Autoconf:\n$autoconf\n"; - $failed_tests_data .= "Bundled Libtool:\n$libtool\n"; - $failed_tests_data .= "System Libtool:\n$sys_libtool\n"; - $failed_tests_data .= "Compiler:\n$compiler\n"; - $failed_tests_data .= "Bison:\n" . shell_exec('bison --version 2>/dev/null') . "\n"; - $failed_tests_data .= "Libraries:\n$ldd\n"; - $failed_tests_data .= "\n"; - - if (isset($user_email)) { - $failed_tests_data .= "User's E-mail: " . $user_email . "\n\n"; - } - - $failed_tests_data .= $sep . "PHPINFO" . $sep; - $failed_tests_data .= shell_exec($php . ' -ddisplay_errors=stderr -dhtml_errors=0 -i 2> /dev/null'); - - if (($just_save_results || !mail_qa_team($failed_tests_data, $status)) && !TRAVIS_CI) { - file_put_contents($output_file, $failed_tests_data); - - if (!$just_save_results) { - echo "\nThe test script was unable to automatically send the report to PHP's QA Team\n"; - } - - echo "Please send " . $output_file . " to " . PHP_QA_EMAIL . " manually, thank you.\n"; - } elseif (!getenv('NO_INTERACTION') && !TRAVIS_CI) { - fwrite($fp, "\nThank you for helping to make PHP better.\n"); - fclose($fp); - } - } - } + global $sum_results, $just_save_results, $failed_test_summary, + $PHP_FAILED_TESTS, $php, $output_file; + + /* We got failed Tests, offer the user to send an e-mail to QA team, unless NO_INTERACTION is set */ + if (!getenv('NO_INTERACTION') && !TRAVIS_CI) { + $fp = fopen("php://stdin", "r+"); + if ($sum_results['FAILED'] || $sum_results['BORKED'] || $sum_results['WARNED'] || $sum_results['LEAKED']) { + echo "\nYou may have found a problem in PHP."; + } + echo "\nThis report can be automatically sent to the PHP QA team at\n"; + echo QA_REPORTS_PAGE . " and http://news.php.net/php.qa.reports\n"; + echo "This gives us a better understanding of PHP's behavior.\n"; + echo "If you don't want to send the report immediately you can choose\n"; + echo "option \"s\" to save it. You can then email it to " . PHP_QA_EMAIL . " later.\n"; + echo "Do you want to send this report now? [Yns]: "; + flush(); + + $user_input = fgets($fp, 10); + $just_save_results = (strtolower($user_input[0]) == 's'); + } + + if ($just_save_results || !getenv('NO_INTERACTION') || TRAVIS_CI) { + if ($just_save_results || TRAVIS_CI || strlen(trim($user_input)) == 0 || strtolower($user_input[0]) == 'y') { + /* + * Collect information about the host system for our report + * Fetch phpinfo() output so that we can see the PHP environment + * Make an archive of all the failed tests + * Send an email + */ + if ($just_save_results) { + $user_input = 's'; + } + + /* Ask the user to provide an email address, so that QA team can contact the user */ + if (TRAVIS_CI) { + $user_email = 'travis at php dot net'; + } elseif (!strncasecmp($user_input, 'y', 1) || strlen(trim($user_input)) == 0) { + echo "\nPlease enter your email address.\n(Your address will be mangled so that it will not go out on any\nmailinglist in plain text): "; + flush(); + $user_email = trim(fgets($fp, 1024)); + $user_email = str_replace("@", " at ", str_replace(".", " dot ", $user_email)); + } + + $failed_tests_data = ''; + $sep = "\n" . str_repeat('=', 80) . "\n"; + $failed_tests_data .= $failed_test_summary . "\n"; + $failed_tests_data .= get_summary(true, false) . "\n"; + + if ($sum_results['FAILED']) { + foreach ($PHP_FAILED_TESTS['FAILED'] as $test_info) { + $failed_tests_data .= $sep . $test_info['name'] . $test_info['info']; + $failed_tests_data .= $sep . file_get_contents(realpath($test_info['output']), FILE_BINARY); + $failed_tests_data .= $sep . file_get_contents(realpath($test_info['diff']), FILE_BINARY); + $failed_tests_data .= $sep . "\n\n"; + } + $status = "failed"; + } else { + $status = "success"; + } + + $failed_tests_data .= "\n" . $sep . 'BUILD ENVIRONMENT' . $sep; + $failed_tests_data .= "OS:\n" . PHP_OS . " - " . php_uname() . "\n\n"; + $ldd = $autoconf = $sys_libtool = $libtool = $compiler = 'N/A'; + + if (substr(PHP_OS, 0, 3) != "WIN") { + /* If PHP_AUTOCONF is set, use it; otherwise, use 'autoconf'. */ + if (getenv('PHP_AUTOCONF')) { + $autoconf = shell_exec(getenv('PHP_AUTOCONF') . ' --version'); + } else { + $autoconf = shell_exec('autoconf --version'); + } + + /* Always use the generated libtool - Mac OSX uses 'glibtool' */ + $libtool = shell_exec(INIT_DIR . '/libtool --version'); + + /* Use shtool to find out if there is glibtool present (MacOSX) */ + $sys_libtool_path = shell_exec(__DIR__ . '/build/shtool path glibtool libtool'); + + if ($sys_libtool_path) { + $sys_libtool = shell_exec(str_replace("\n", "", $sys_libtool_path) . ' --version'); + } + + /* Try the most common flags for 'version' */ + $flags = array('-v', '-V', '--version'); + $cc_status = 0; + + foreach ($flags as $flag) { + system(getenv('CC') . " $flag >/dev/null 2>&1", $cc_status); + if ($cc_status == 0) { + $compiler = shell_exec(getenv('CC') . " $flag 2>&1"); + break; + } + } + + $ldd = shell_exec("ldd $php 2>/dev/null"); + } + + $failed_tests_data .= "Autoconf:\n$autoconf\n"; + $failed_tests_data .= "Bundled Libtool:\n$libtool\n"; + $failed_tests_data .= "System Libtool:\n$sys_libtool\n"; + $failed_tests_data .= "Compiler:\n$compiler\n"; + $failed_tests_data .= "Bison:\n" . shell_exec('bison --version 2>/dev/null') . "\n"; + $failed_tests_data .= "Libraries:\n$ldd\n"; + $failed_tests_data .= "\n"; + + if (isset($user_email)) { + $failed_tests_data .= "User's E-mail: " . $user_email . "\n\n"; + } + + $failed_tests_data .= $sep . "PHPINFO" . $sep; + $failed_tests_data .= shell_exec($php . ' -ddisplay_errors=stderr -dhtml_errors=0 -i 2> /dev/null'); + + if (($just_save_results || !mail_qa_team($failed_tests_data, $status)) && !TRAVIS_CI) { + file_put_contents($output_file, $failed_tests_data); + + if (!$just_save_results) { + echo "\nThe test script was unable to automatically send the report to PHP's QA Team\n"; + } + + echo "Please send " . $output_file . " to " . PHP_QA_EMAIL . " manually, thank you.\n"; + } elseif (!getenv('NO_INTERACTION') && !TRAVIS_CI) { + fwrite($fp, "\nThank you for helping to make PHP better.\n"); + fclose($fp); + } + } + } } function find_files($dir, $is_ext_dir = false, $ignore = false) { - global $test_files, $exts_to_test, $ignored_by_ext, $exts_skipped; - - $o = opendir($dir) or error("cannot open directory: $dir"); - - while (($name = readdir($o)) !== false) { - - if (is_dir("{$dir}/{$name}") && !in_array($name, array('.', '..', '.svn'))) { - $skip_ext = ($is_ext_dir && !in_array(strtolower($name), $exts_to_test)); - if ($skip_ext) { - $exts_skipped++; - } - find_files("{$dir}/{$name}", false, $ignore || $skip_ext); - } - - // Cleanup any left-over tmp files from last run. - if (substr($name, -4) == '.tmp') { - @unlink("$dir/$name"); - continue; - } - - // Otherwise we're only interested in *.phpt files. - if (substr($name, -5) == '.phpt') { - if ($ignore) { - $ignored_by_ext++; - } else { - $testfile = realpath("{$dir}/{$name}"); - $test_files[] = $testfile; - } - } - } - - closedir($o); + global $test_files, $exts_to_test, $ignored_by_ext, $exts_skipped; + + $o = opendir($dir) or error("cannot open directory: $dir"); + + while (($name = readdir($o)) !== false) { + + if (is_dir("{$dir}/{$name}") && !in_array($name, array('.', '..', '.svn'))) { + $skip_ext = ($is_ext_dir && !in_array(strtolower($name), $exts_to_test)); + if ($skip_ext) { + $exts_skipped++; + } + find_files("{$dir}/{$name}", false, $ignore || $skip_ext); + } + + // Cleanup any left-over tmp files from last run. + if (substr($name, -4) == '.tmp') { + @unlink("$dir/$name"); + continue; + } + + // Otherwise we're only interested in *.phpt files. + if (substr($name, -5) == '.phpt') { + if ($ignore) { + $ignored_by_ext++; + } else { + $testfile = realpath("{$dir}/{$name}"); + $test_files[] = $testfile; + } + } + } + + closedir($o); } function test_name($name) { - if (is_array($name)) { - return $name[0] . ':' . $name[1]; - } else { - return $name; - } + if (is_array($name)) { + return $name[0] . ':' . $name[1]; + } else { + return $name; + } } function test_sort($a, $b) { - $a = test_name($a); - $b = test_name($b); - - $ta = strpos($a, TEST_PHP_SRCDIR . "/tests") === 0 ? 1 + (strpos($a, - TEST_PHP_SRCDIR . "/tests/run-test") === 0 ? 1 : 0) : 0; - $tb = strpos($b, TEST_PHP_SRCDIR . "/tests") === 0 ? 1 + (strpos($b, - TEST_PHP_SRCDIR . "/tests/run-test") === 0 ? 1 : 0) : 0; - - if ($ta == $tb) { - return strcmp($a, $b); - } else { - return $tb - $ta; - } + $a = test_name($a); + $b = test_name($b); + + $ta = strpos($a, TEST_PHP_SRCDIR . "/tests") === 0 ? 1 + (strpos($a, + TEST_PHP_SRCDIR . "/tests/run-test") === 0 ? 1 : 0) : 0; + $tb = strpos($b, TEST_PHP_SRCDIR . "/tests") === 0 ? 1 + (strpos($b, + TEST_PHP_SRCDIR . "/tests/run-test") === 0 ? 1 : 0) : 0; + + if ($ta == $tb) { + return strcmp($a, $b); + } else { + return $tb - $ta; + } } @@ -1111,44 +1111,44 @@ function test_sort($a, $b) function mail_qa_team($data, $status = false) { - $url_bits = parse_url(QA_SUBMISSION_PAGE); - - if ($proxy = getenv('http_proxy')) { - $proxy = parse_url($proxy); - $path = $url_bits['host'] . $url_bits['path']; - $host = $proxy['host']; - if (empty($proxy['port'])) { - $proxy['port'] = 80; - } - $port = $proxy['port']; - } else { - $path = $url_bits['path']; - $host = $url_bits['host']; - $port = empty($url_bits['port']) ? 80 : $port = $url_bits['port']; - } - - $data = "php_test_data=" . urlencode(base64_encode(str_replace("\00", '[0x0]', $data))); - $data_length = strlen($data); - - $fs = fsockopen($host, $port, $errno, $errstr, 10); - - if (!$fs) { - return false; - } - - $php_version = urlencode(TESTED_PHP_VERSION); - - echo "\nPosting to " . QA_SUBMISSION_PAGE . "\n"; - fwrite($fs, "POST " . $path . "?status=$status&version=$php_version HTTP/1.1\r\n"); - fwrite($fs, "Host: " . $host . "\r\n"); - fwrite($fs, "User-Agent: QA Browser 0.1\r\n"); - fwrite($fs, "Content-Type: application/x-www-form-urlencoded\r\n"); - fwrite($fs, "Content-Length: " . $data_length . "\r\n\r\n"); - fwrite($fs, $data); - fwrite($fs, "\r\n\r\n"); - fclose($fs); - - return 1; + $url_bits = parse_url(QA_SUBMISSION_PAGE); + + if ($proxy = getenv('http_proxy')) { + $proxy = parse_url($proxy); + $path = $url_bits['host'] . $url_bits['path']; + $host = $proxy['host']; + if (empty($proxy['port'])) { + $proxy['port'] = 80; + } + $port = $proxy['port']; + } else { + $path = $url_bits['path']; + $host = $url_bits['host']; + $port = empty($url_bits['port']) ? 80 : $port = $url_bits['port']; + } + + $data = "php_test_data=" . urlencode(base64_encode(str_replace("\00", '[0x0]', $data))); + $data_length = strlen($data); + + $fs = fsockopen($host, $port, $errno, $errstr, 10); + + if (!$fs) { + return false; + } + + $php_version = urlencode(TESTED_PHP_VERSION); + + echo "\nPosting to " . QA_SUBMISSION_PAGE . "\n"; + fwrite($fs, "POST " . $path . "?status=$status&version=$php_version HTTP/1.1\r\n"); + fwrite($fs, "Host: " . $host . "\r\n"); + fwrite($fs, "User-Agent: QA Browser 0.1\r\n"); + fwrite($fs, "Content-Type: application/x-www-form-urlencoded\r\n"); + fwrite($fs, "Content-Length: " . $data_length . "\r\n\r\n"); + fwrite($fs, $data); + fwrite($fs, "\r\n\r\n"); + fclose($fs); + + return 1; } @@ -1158,19 +1158,19 @@ function mail_qa_team($data, $status = false) function save_text($filename, $text, $filename_copy = null) { - global $DETAILED; + global $DETAILED; - if ($filename_copy && $filename_copy != $filename) { - if (file_put_contents($filename_copy, $text, FILE_BINARY) === false) { - error("Cannot open file '" . $filename_copy . "' (save_text)"); - } - } + if ($filename_copy && $filename_copy != $filename) { + if (file_put_contents($filename_copy, $text, FILE_BINARY) === false) { + error("Cannot open file '" . $filename_copy . "' (save_text)"); + } + } - if (file_put_contents($filename, $text, FILE_BINARY) === false) { - error("Cannot open file '" . $filename . "' (save_text)"); - } + if (file_put_contents($filename, $text, FILE_BINARY) === false) { + error("Cannot open file '" . $filename . "' (save_text)"); + } - if (1 < $DETAILED) echo " + if (1 < $DETAILED) echo " FILE $filename {{{ $text }}} @@ -1183,547 +1183,547 @@ $text function error_report($testname, $logname, $tested) { - $testname = realpath($testname); - $logname = realpath($logname); - - switch (strtoupper(getenv('TEST_PHP_ERROR_STYLE'))) { - case 'MSVC': - echo $testname . "(1) : $tested\n"; - echo $logname . "(1) : $tested\n"; - break; - case 'EMACS': - echo $testname . ":1: $tested\n"; - echo $logname . ":1: $tested\n"; - break; - } + $testname = realpath($testname); + $logname = realpath($logname); + + switch (strtoupper(getenv('TEST_PHP_ERROR_STYLE'))) { + case 'MSVC': + echo $testname . "(1) : $tested\n"; + echo $logname . "(1) : $tested\n"; + break; + case 'EMACS': + echo $testname . ":1: $tested\n"; + echo $logname . ":1: $tested\n"; + break; + } } function system_with_timeout($commandline, $env = null, $stdin = null, $captureStdIn = true, $captureStdOut = true, $captureStdErr = true) { - global $valgrind; - - $data = ''; - - $bin_env = array(); - foreach ((array)$env as $key => $value) { - $bin_env[$key] = $value; - } - - $descriptorspec = array(); - if ($captureStdIn) { - $descriptorspec[0] = array('pipe', 'r'); - } - if ($captureStdOut) { - $descriptorspec[1] = array('pipe', 'w'); - } - if ($captureStdErr) { - $descriptorspec[2] = array('pipe', 'w'); - } - $proc = proc_open($commandline, $descriptorspec, $pipes, TEST_PHP_SRCDIR, $bin_env, array('suppress_errors' => true)); - - if (!$proc) { - return false; - } - - if ($captureStdIn) { - if (!is_null($stdin)) { - fwrite($pipes[0], $stdin); - } - fclose($pipes[0]); - unset($pipes[0]); - } - - $timeout = $valgrind ? 300 : ($env['TEST_TIMEOUT'] ?? 60); - - while (true) { - /* hide errors from interrupted syscalls */ - $r = $pipes; - $w = null; - $e = null; - - $n = @stream_select($r, $w, $e, $timeout); - - if ($n === false) { - break; - } else if ($n === 0) { - /* timed out */ - $data .= "\n ** ERROR: process timed out **\n"; - proc_terminate($proc, 9); - return $data; - } else if ($n > 0) { - if ($captureStdOut) { - $line = fread($pipes[1], 8192); - } elseif ($captureStdErr) { - $line = fread($pipes[2], 8192); - } else { - $line = ''; - } - if (strlen($line) == 0) { - /* EOF */ - break; - } - $data .= $line; - } - } - - $stat = proc_get_status($proc); - - if ($stat['signaled']) { - $data .= "\nTermsig=" . $stat['stopsig'] . "\n"; - } - if ($stat["exitcode"] > 128 && $stat["exitcode"] < 160) { - $data .= "\nTermsig=" . ($stat["exitcode"] - 128) . "\n"; - } - - proc_close($proc); - return $data; + global $valgrind; + + $data = ''; + + $bin_env = array(); + foreach ((array)$env as $key => $value) { + $bin_env[$key] = $value; + } + + $descriptorspec = array(); + if ($captureStdIn) { + $descriptorspec[0] = array('pipe', 'r'); + } + if ($captureStdOut) { + $descriptorspec[1] = array('pipe', 'w'); + } + if ($captureStdErr) { + $descriptorspec[2] = array('pipe', 'w'); + } + $proc = proc_open($commandline, $descriptorspec, $pipes, TEST_PHP_SRCDIR, $bin_env, array('suppress_errors' => true)); + + if (!$proc) { + return false; + } + + if ($captureStdIn) { + if (!is_null($stdin)) { + fwrite($pipes[0], $stdin); + } + fclose($pipes[0]); + unset($pipes[0]); + } + + $timeout = $valgrind ? 300 : ($env['TEST_TIMEOUT'] ?? 60); + + while (true) { + /* hide errors from interrupted syscalls */ + $r = $pipes; + $w = null; + $e = null; + + $n = @stream_select($r, $w, $e, $timeout); + + if ($n === false) { + break; + } else if ($n === 0) { + /* timed out */ + $data .= "\n ** ERROR: process timed out **\n"; + proc_terminate($proc, 9); + return $data; + } else if ($n > 0) { + if ($captureStdOut) { + $line = fread($pipes[1], 8192); + } elseif ($captureStdErr) { + $line = fread($pipes[2], 8192); + } else { + $line = ''; + } + if (strlen($line) == 0) { + /* EOF */ + break; + } + $data .= $line; + } + } + + $stat = proc_get_status($proc); + + if ($stat['signaled']) { + $data .= "\nTermsig=" . $stat['stopsig'] . "\n"; + } + if ($stat["exitcode"] > 128 && $stat["exitcode"] < 160) { + $data .= "\nTermsig=" . ($stat["exitcode"] - 128) . "\n"; + } + + proc_close($proc); + return $data; } function run_all_tests($test_files, $env, $redir_tested = null) { - global $test_results, $failed_tests_file, $result_tests_file, $php, $test_idx; - // Parallel testing - global $PHP_FAILED_TESTS, $workers, $workerID, $workerSock; - - if ($workers !== null && !$workerID) { - run_all_tests_parallel($test_files, $env, $redir_tested); - return; - } - - foreach ($test_files as $name) { - if (is_array($name)) { - $index = "# $name[1]: $name[0]"; - - if ($redir_tested) { - $name = $name[0]; - } - } else if ($redir_tested) { - $index = "# $redir_tested: $name"; - } else { - $index = $name; - } - $test_idx++; - - if ($workerID) { - $PHP_FAILED_TESTS = ['BORKED' => [], 'FAILED' => [], 'WARNED' => [], 'LEAKED' => [], 'XFAILED' => [], 'XLEAKED' => [], 'SLOW' => []]; - ob_start(); - } - - $result = run_test($php, $name, $env); - if ($workerID) { - $resultText = ob_get_clean(); - } - - if (!is_array($name) && $result != 'REDIR') { - if ($workerID) { - send_message($workerSock, [ - "type" => "test_result", - "name" => $name, - "index" => $index, - "result" => $result, - "text" => $resultText, - "PHP_FAILED_TESTS" => $PHP_FAILED_TESTS - ]); - continue; - } - - $test_results[$index] = $result; - if ($failed_tests_file && ($result == 'XFAILED' || $result == 'XLEAKED' || $result == 'FAILED' || $result == 'WARNED' || $result == 'LEAKED')) { - fwrite($failed_tests_file, "$index\n"); - } - if ($result_tests_file) { - fwrite($result_tests_file, "$result\t$index\n"); - } - } - } + global $test_results, $failed_tests_file, $result_tests_file, $php, $test_idx; + // Parallel testing + global $PHP_FAILED_TESTS, $workers, $workerID, $workerSock; + + if ($workers !== null && !$workerID) { + run_all_tests_parallel($test_files, $env, $redir_tested); + return; + } + + foreach ($test_files as $name) { + if (is_array($name)) { + $index = "# $name[1]: $name[0]"; + + if ($redir_tested) { + $name = $name[0]; + } + } else if ($redir_tested) { + $index = "# $redir_tested: $name"; + } else { + $index = $name; + } + $test_idx++; + + if ($workerID) { + $PHP_FAILED_TESTS = ['BORKED' => [], 'FAILED' => [], 'WARNED' => [], 'LEAKED' => [], 'XFAILED' => [], 'XLEAKED' => [], 'SLOW' => []]; + ob_start(); + } + + $result = run_test($php, $name, $env); + if ($workerID) { + $resultText = ob_get_clean(); + } + + if (!is_array($name) && $result != 'REDIR') { + if ($workerID) { + send_message($workerSock, [ + "type" => "test_result", + "name" => $name, + "index" => $index, + "result" => $result, + "text" => $resultText, + "PHP_FAILED_TESTS" => $PHP_FAILED_TESTS + ]); + continue; + } + + $test_results[$index] = $result; + if ($failed_tests_file && ($result == 'XFAILED' || $result == 'XLEAKED' || $result == 'FAILED' || $result == 'WARNED' || $result == 'LEAKED')) { + fwrite($failed_tests_file, "$index\n"); + } + if ($result_tests_file) { + fwrite($result_tests_file, "$result\t$index\n"); + } + } + } } /** The heart of parallel testing. */ function run_all_tests_parallel($test_files, $env, $redir_tested) { - global $workers, $test_idx, $test_cnt, $test_results, $failed_tests_file, $result_tests_file, $PHP_FAILED_TESTS, $shuffle, $SHOW_ONLY_GROUPS; - - // The PHP binary running run-tests.php, and run-tests.php itself - // This PHP executable is *not* necessarily the same as the tested version - $thisPHP = PHP_BINARY; - $thisScript = __FILE__; - - $workerProcs = []; - $workerSocks = []; - - echo "=====================================================================\n"; - echo "========= WELCOME TO THE FUTURE: run-tests PARALLEL EDITION =========\n"; - echo "=====================================================================\n"; - - // Each test may specify a list of conflict keys. While a test that conflicts with - // key K is running, no other test that conflicts with K may run. Conflict keys are - // specified either in the --CONFLICTS-- section, or CONFLICTS file inside a directory. - $dirConflictsWith = []; - $fileConflictsWith = []; - $sequentialTests = []; - foreach ($test_files as $i => $file) { - $contents = file_get_contents($file); - if (preg_match('/^--CONFLICTS--(.+?)^--/ms', $contents, $matches)) { - $conflicts = parse_conflicts($matches[1]); - } else { - // Cache per-directory conflicts in a separate map, so we compute these only once. - $dir = dirname($file); - if (!isset($dirConflictsWith[$dir])) { - $dirConflicts = []; - if (file_exists($dir . '/CONFLICTS')) { - $contents = file_get_contents($dir . '/CONFLICTS'); - $dirConflicts = parse_conflicts($contents); - } - $dirConflictsWith[$dir] = $dirConflicts; - } - $conflicts = $dirConflictsWith[$dir]; - } - - // For tests conflicting with "all", no other tests may run in parallel. We'll run these - // tests separately at the end, when only one worker is left. - if (in_array('all', $conflicts, true)) { - $sequentialTests[] = $file; - unset($test_files[$i]); - } - - $fileConflictsWith[$file] = $conflicts; - } - - // Some tests assume that they are executed in a certain order. We will be popping from - // $test_files, so reverse its order here. This makes sure that order is preserved at least - // for tests with a common conflict key. - $test_files = array_reverse($test_files); - - // To discover parallelization issues it is useful to randomize the test order. - if ($shuffle) { - shuffle($test_files); - } - - echo "Spawning workers… "; - - // We use sockets rather than STDIN/STDOUT for comms because on Windows, - // those can't be non-blocking for some reason. - $listenSock = stream_socket_server("tcp://127.0.0.1:0") or error("Couldn't create socket on localhost."); - $sockName = stream_socket_get_name($listenSock, false); - // PHP is terrible and returns IPv6 addresses not enclosed by [] - $portPos = strrpos($sockName, ":"); - $sockHost = substr($sockName, 0, $portPos); - if (FALSE !== strpos($sockHost, ":")) { - $sockHost = "[$sockHost]"; - } - $sockPort = substr($sockName, $portPos + 1); - $sockUri = "tcp://$sockHost:$sockPort"; - - for ($i = 1; $i <= $workers; $i++) { - $proc = proc_open( - $thisPHP . ' ' . escapeshellarg($thisScript), - [], // Inherit our stdin, stdout and stderr - $pipes, - NULL, - $_ENV + [ - "TEST_PHP_WORKER" => $i, - "TEST_PHP_URI" => $sockUri, - ], - [ - "suppress_errors" => TRUE - ] - ); - if ($proc === FALSE) { - kill_children($workerProcs); - error("Failed to spawn worker $i"); - } - $workerProcs[$i] = $proc; - - $workerSock = stream_socket_accept($listenSock, 5); - if ($workerSock === FALSE) { - kill_children($workerProcs); - error("Failed to accept connection from worker $i"); - } - - $greeting = base64_encode(serialize([ - "type" => "hello", - "workerID" => $i, - "GLOBALS" => $GLOBALS, - "constants" => [ - "INIT_DIR" => INIT_DIR, - "TEST_PHP_SRCDIR" => TEST_PHP_SRCDIR, - "PHP_QA_EMAIL" => PHP_QA_EMAIL, - "QA_SUBMISSION_PAGE" => QA_SUBMISSION_PAGE, - "QA_REPORTS_PAGE" => QA_REPORTS_PAGE, - "TRAVIS_CI" => TRAVIS_CI - ] - ])) . "\n"; - - stream_set_timeout($workerSock, 5); - if (fwrite($workerSock, $greeting) === FALSE) { - kill_children($workerProcs); - error("Failed to send greeting to worker $i."); - } - - $rawReply = fgets($workerSock); - if ($rawReply === FALSE) { - kill_children($workerProcs); - error("Failed to read greeting reply from worker $i."); - } - - $reply = unserialize(base64_decode($rawReply)); - if (!$reply || $reply["type"] !== "hello_reply" || $reply["workerID"] !== $i) { - kill_children($workerProcs); - error("Greeting reply from worker $i unexpected or could not be decoded: '$rawReply'"); - } - - stream_set_timeout($workerSock, 0); - stream_set_blocking($workerSock, FALSE); - - $workerSocks[$i] = $workerSock; - - echo "$i "; - } - echo "… done!\n"; - echo "=====================================================================\n"; - echo "\n"; - - $rawMessageBuffers = []; - $testsInProgress = 0; - - // Map from conflict key to worker ID. - $activeConflicts = []; - // Tests waiting due to conflicts. Map from conflict key to array. - $waitingTests = []; + global $workers, $test_idx, $test_cnt, $test_results, $failed_tests_file, $result_tests_file, $PHP_FAILED_TESTS, $shuffle, $SHOW_ONLY_GROUPS; + + // The PHP binary running run-tests.php, and run-tests.php itself + // This PHP executable is *not* necessarily the same as the tested version + $thisPHP = PHP_BINARY; + $thisScript = __FILE__; + + $workerProcs = []; + $workerSocks = []; + + echo "=====================================================================\n"; + echo "========= WELCOME TO THE FUTURE: run-tests PARALLEL EDITION =========\n"; + echo "=====================================================================\n"; + + // Each test may specify a list of conflict keys. While a test that conflicts with + // key K is running, no other test that conflicts with K may run. Conflict keys are + // specified either in the --CONFLICTS-- section, or CONFLICTS file inside a directory. + $dirConflictsWith = []; + $fileConflictsWith = []; + $sequentialTests = []; + foreach ($test_files as $i => $file) { + $contents = file_get_contents($file); + if (preg_match('/^--CONFLICTS--(.+?)^--/ms', $contents, $matches)) { + $conflicts = parse_conflicts($matches[1]); + } else { + // Cache per-directory conflicts in a separate map, so we compute these only once. + $dir = dirname($file); + if (!isset($dirConflictsWith[$dir])) { + $dirConflicts = []; + if (file_exists($dir . '/CONFLICTS')) { + $contents = file_get_contents($dir . '/CONFLICTS'); + $dirConflicts = parse_conflicts($contents); + } + $dirConflictsWith[$dir] = $dirConflicts; + } + $conflicts = $dirConflictsWith[$dir]; + } + + // For tests conflicting with "all", no other tests may run in parallel. We'll run these + // tests separately at the end, when only one worker is left. + if (in_array('all', $conflicts, true)) { + $sequentialTests[] = $file; + unset($test_files[$i]); + } + + $fileConflictsWith[$file] = $conflicts; + } + + // Some tests assume that they are executed in a certain order. We will be popping from + // $test_files, so reverse its order here. This makes sure that order is preserved at least + // for tests with a common conflict key. + $test_files = array_reverse($test_files); + + // To discover parallelization issues it is useful to randomize the test order. + if ($shuffle) { + shuffle($test_files); + } + + echo "Spawning workers… "; + + // We use sockets rather than STDIN/STDOUT for comms because on Windows, + // those can't be non-blocking for some reason. + $listenSock = stream_socket_server("tcp://127.0.0.1:0") or error("Couldn't create socket on localhost."); + $sockName = stream_socket_get_name($listenSock, false); + // PHP is terrible and returns IPv6 addresses not enclosed by [] + $portPos = strrpos($sockName, ":"); + $sockHost = substr($sockName, 0, $portPos); + if (FALSE !== strpos($sockHost, ":")) { + $sockHost = "[$sockHost]"; + } + $sockPort = substr($sockName, $portPos + 1); + $sockUri = "tcp://$sockHost:$sockPort"; + + for ($i = 1; $i <= $workers; $i++) { + $proc = proc_open( + $thisPHP . ' ' . escapeshellarg($thisScript), + [], // Inherit our stdin, stdout and stderr + $pipes, + NULL, + $_ENV + [ + "TEST_PHP_WORKER" => $i, + "TEST_PHP_URI" => $sockUri, + ], + [ + "suppress_errors" => TRUE + ] + ); + if ($proc === FALSE) { + kill_children($workerProcs); + error("Failed to spawn worker $i"); + } + $workerProcs[$i] = $proc; + + $workerSock = stream_socket_accept($listenSock, 5); + if ($workerSock === FALSE) { + kill_children($workerProcs); + error("Failed to accept connection from worker $i"); + } + + $greeting = base64_encode(serialize([ + "type" => "hello", + "workerID" => $i, + "GLOBALS" => $GLOBALS, + "constants" => [ + "INIT_DIR" => INIT_DIR, + "TEST_PHP_SRCDIR" => TEST_PHP_SRCDIR, + "PHP_QA_EMAIL" => PHP_QA_EMAIL, + "QA_SUBMISSION_PAGE" => QA_SUBMISSION_PAGE, + "QA_REPORTS_PAGE" => QA_REPORTS_PAGE, + "TRAVIS_CI" => TRAVIS_CI + ] + ])) . "\n"; + + stream_set_timeout($workerSock, 5); + if (fwrite($workerSock, $greeting) === FALSE) { + kill_children($workerProcs); + error("Failed to send greeting to worker $i."); + } + + $rawReply = fgets($workerSock); + if ($rawReply === FALSE) { + kill_children($workerProcs); + error("Failed to read greeting reply from worker $i."); + } + + $reply = unserialize(base64_decode($rawReply)); + if (!$reply || $reply["type"] !== "hello_reply" || $reply["workerID"] !== $i) { + kill_children($workerProcs); + error("Greeting reply from worker $i unexpected or could not be decoded: '$rawReply'"); + } + + stream_set_timeout($workerSock, 0); + stream_set_blocking($workerSock, FALSE); + + $workerSocks[$i] = $workerSock; + + echo "$i "; + } + echo "… done!\n"; + echo "=====================================================================\n"; + echo "\n"; + + $rawMessageBuffers = []; + $testsInProgress = 0; + + // Map from conflict key to worker ID. + $activeConflicts = []; + // Tests waiting due to conflicts. Map from conflict key to array. + $waitingTests = []; escape: - while ($test_files || $sequentialTests || $testsInProgress > 0) { - $toRead = array_values($workerSocks); - $toWrite = NULL; - $toExcept = NULL; - if (stream_select($toRead, $toWrite, $toExcept, 10)) { - foreach ($toRead as $workerSock) { - $i = array_search($workerSock, $workerSocks); - if ($i === FALSE) { - kill_children($workerProcs); - error("Could not find worker stdout in array of worker stdouts, THIS SHOULD NOT HAPPEN."); - } - while (FALSE !== ($rawMessage = fgets($workerSock))) { - // work around fgets truncating things - if (($rawMessageBuffers[$i] ?? '') !== '') { - $rawMessage = $rawMessageBuffers[$i] . $rawMessage; - $rawMessageBuffers[$i] = ''; - } - if (substr($rawMessage, -1) !== "\n") { - $rawMessageBuffers[$i] = $rawMessage; - continue; - } - - $message = unserialize(base64_decode($rawMessage)); - if (!$message) { - kill_children($workerProcs); - $stuff = fread($workerSock, 65536); - error("Could not decode message from worker $i: '$rawMessage$stuff'"); - } - - switch ($message["type"]) { - case "tests_finished": - $testsInProgress--; - foreach ($activeConflicts as $key => $workerId) { - if ($workerId === $i) { - unset($activeConflicts[$key]); - if (isset($waitingTests[$key])) { - while ($test = array_pop($waitingTests[$key])) { - $test_files[] = $test; - } - unset($waitingTests[$key]); - } - } - } - if (junit_enabled()) { - junit_merge_results($message["junit"]); - } - // intentional fall-through - case "ready": - // Schedule sequential tests only once we are down to one worker. - if (count($workerProcs) === 1 && $sequentialTests) { - $test_files = array_merge($test_files, $sequentialTests); - $sequentialTests = []; - } - // Batch multiple tests to reduce communication overhead. - $files = []; - $batchSize = $shuffle ? 4 : 32; - while (count($files) <= $batchSize && $file = array_pop($test_files)) { - foreach ($fileConflictsWith[$file] as $conflictKey) { - if (isset($activeConflicts[$conflictKey])) { - $waitingTests[$conflictKey][] = $file; - continue 2; - } - } - $files[] = $file; - } - if ($files) { - foreach ($files as $file) { - foreach ($fileConflictsWith[$file] as $conflictKey) { - $activeConflicts[$conflictKey] = $i; - } - } - $testsInProgress++; - send_message($workerSocks[$i], [ - "type" => "run_tests", - "test_files" => $files, - "env" => $env, - "redir_tested" => $redir_tested - ]); - } else { - proc_terminate($workerProcs[$i]); - unset($workerProcs[$i]); - unset($workerSocks[$i]); - goto escape; - } - break; - case "test_result": - list($name, $index, $result, $resultText) = [$message["name"], $message["index"], $message["result"], $message["text"]]; - foreach ($message["PHP_FAILED_TESTS"] as $category => $tests) { - $PHP_FAILED_TESTS[$category] = array_merge($PHP_FAILED_TESTS[$category], $tests); - } - $test_idx++; - - if (!$SHOW_ONLY_GROUPS) { - clear_show_test(); - } - - echo $resultText; - - if (!$SHOW_ONLY_GROUPS) { - show_test($test_idx, count($workerProcs) . "/$workers concurrent test workers running"); - } - - if (!is_array($name) && $result != 'REDIR') { - $test_results[$index] = $result; - - if ($failed_tests_file && ($result == 'XFAILED' || $result == 'XLEAKED' || $result == 'FAILED' || $result == 'WARNED' || $result == 'LEAKED')) { - fwrite($failed_tests_file, "$index\n"); - } - if ($result_tests_file) { - fwrite($result_tests_file, "$result\t$index\n"); - } - } - break; - case "error": - kill_children($workerProcs); - error("Worker $i reported error: $message[msg]"); - break; - case "php_error": - kill_children($workerProcs); - $error_consts = [ - 'E_ERROR', - 'E_WARNING', - 'E_PARSE', - 'E_NOTICE', - 'E_CORE_ERROR', - 'E_CORE_WARNING', - 'E_COMPILE_ERROR', - 'E_COMPILE_WARNING', - 'E_USER_ERROR', - 'E_USER_WARNING', - 'E_USER_NOTICE', - 'E_STRICT', // TODO Cleanup when removed from Zend Engine. - 'E_RECOVERABLE_ERROR', - 'E_USER_DEPRECATED' - ]; - $error_consts = array_combine(array_map('constant', $error_consts), $error_consts); - error("Worker $i reported unexpected {$error_consts[$message['errno']]}: $message[errstr] in $message[errfile] on line $message[errline]"); - default: - kill_children($workerProcs); - error("Unrecognised message type '$message[type]' from worker $i"); - } - } - } - } - } - - if (!$SHOW_ONLY_GROUPS) { - clear_show_test(); - } - - kill_children($workerProcs); - - if ($testsInProgress < 0) { - error("$testsInProgress test batches “in progress”, which is less than zero. THIS SHOULD NOT HAPPEN."); - } + while ($test_files || $sequentialTests || $testsInProgress > 0) { + $toRead = array_values($workerSocks); + $toWrite = NULL; + $toExcept = NULL; + if (stream_select($toRead, $toWrite, $toExcept, 10)) { + foreach ($toRead as $workerSock) { + $i = array_search($workerSock, $workerSocks); + if ($i === FALSE) { + kill_children($workerProcs); + error("Could not find worker stdout in array of worker stdouts, THIS SHOULD NOT HAPPEN."); + } + while (FALSE !== ($rawMessage = fgets($workerSock))) { + // work around fgets truncating things + if (($rawMessageBuffers[$i] ?? '') !== '') { + $rawMessage = $rawMessageBuffers[$i] . $rawMessage; + $rawMessageBuffers[$i] = ''; + } + if (substr($rawMessage, -1) !== "\n") { + $rawMessageBuffers[$i] = $rawMessage; + continue; + } + + $message = unserialize(base64_decode($rawMessage)); + if (!$message) { + kill_children($workerProcs); + $stuff = fread($workerSock, 65536); + error("Could not decode message from worker $i: '$rawMessage$stuff'"); + } + + switch ($message["type"]) { + case "tests_finished": + $testsInProgress--; + foreach ($activeConflicts as $key => $workerId) { + if ($workerId === $i) { + unset($activeConflicts[$key]); + if (isset($waitingTests[$key])) { + while ($test = array_pop($waitingTests[$key])) { + $test_files[] = $test; + } + unset($waitingTests[$key]); + } + } + } + if (junit_enabled()) { + junit_merge_results($message["junit"]); + } + // intentional fall-through + case "ready": + // Schedule sequential tests only once we are down to one worker. + if (count($workerProcs) === 1 && $sequentialTests) { + $test_files = array_merge($test_files, $sequentialTests); + $sequentialTests = []; + } + // Batch multiple tests to reduce communication overhead. + $files = []; + $batchSize = $shuffle ? 4 : 32; + while (count($files) <= $batchSize && $file = array_pop($test_files)) { + foreach ($fileConflictsWith[$file] as $conflictKey) { + if (isset($activeConflicts[$conflictKey])) { + $waitingTests[$conflictKey][] = $file; + continue 2; + } + } + $files[] = $file; + } + if ($files) { + foreach ($files as $file) { + foreach ($fileConflictsWith[$file] as $conflictKey) { + $activeConflicts[$conflictKey] = $i; + } + } + $testsInProgress++; + send_message($workerSocks[$i], [ + "type" => "run_tests", + "test_files" => $files, + "env" => $env, + "redir_tested" => $redir_tested + ]); + } else { + proc_terminate($workerProcs[$i]); + unset($workerProcs[$i]); + unset($workerSocks[$i]); + goto escape; + } + break; + case "test_result": + list($name, $index, $result, $resultText) = [$message["name"], $message["index"], $message["result"], $message["text"]]; + foreach ($message["PHP_FAILED_TESTS"] as $category => $tests) { + $PHP_FAILED_TESTS[$category] = array_merge($PHP_FAILED_TESTS[$category], $tests); + } + $test_idx++; + + if (!$SHOW_ONLY_GROUPS) { + clear_show_test(); + } + + echo $resultText; + + if (!$SHOW_ONLY_GROUPS) { + show_test($test_idx, count($workerProcs) . "/$workers concurrent test workers running"); + } + + if (!is_array($name) && $result != 'REDIR') { + $test_results[$index] = $result; + + if ($failed_tests_file && ($result == 'XFAILED' || $result == 'XLEAKED' || $result == 'FAILED' || $result == 'WARNED' || $result == 'LEAKED')) { + fwrite($failed_tests_file, "$index\n"); + } + if ($result_tests_file) { + fwrite($result_tests_file, "$result\t$index\n"); + } + } + break; + case "error": + kill_children($workerProcs); + error("Worker $i reported error: $message[msg]"); + break; + case "php_error": + kill_children($workerProcs); + $error_consts = [ + 'E_ERROR', + 'E_WARNING', + 'E_PARSE', + 'E_NOTICE', + 'E_CORE_ERROR', + 'E_CORE_WARNING', + 'E_COMPILE_ERROR', + 'E_COMPILE_WARNING', + 'E_USER_ERROR', + 'E_USER_WARNING', + 'E_USER_NOTICE', + 'E_STRICT', // TODO Cleanup when removed from Zend Engine. + 'E_RECOVERABLE_ERROR', + 'E_USER_DEPRECATED' + ]; + $error_consts = array_combine(array_map('constant', $error_consts), $error_consts); + error("Worker $i reported unexpected {$error_consts[$message['errno']]}: $message[errstr] in $message[errfile] on line $message[errline]"); + default: + kill_children($workerProcs); + error("Unrecognised message type '$message[type]' from worker $i"); + } + } + } + } + } + + if (!$SHOW_ONLY_GROUPS) { + clear_show_test(); + } + + kill_children($workerProcs); + + if ($testsInProgress < 0) { + error("$testsInProgress test batches “in progress”, which is less than zero. THIS SHOULD NOT HAPPEN."); + } } function send_message($stream, array $message) { - $blocking = stream_get_meta_data($stream)["blocked"]; - stream_set_blocking($stream, true); - fwrite($stream, base64_encode(serialize($message)) . "\n"); - stream_set_blocking($stream, $blocking); + $blocking = stream_get_meta_data($stream)["blocked"]; + stream_set_blocking($stream, true); + fwrite($stream, base64_encode(serialize($message)) . "\n"); + stream_set_blocking($stream, $blocking); } function kill_children(array $children) { - foreach ($children as $child) { - if ($child) { - proc_terminate($child); - } - } + foreach ($children as $child) { + if ($child) { + proc_terminate($child); + } + } } function run_worker() { - global $workerID, $workerSock; - - $sockUri = getenv("TEST_PHP_URI"); - - $workerSock = stream_socket_client($sockUri, $_, $_, 5) or error("Couldn't connect to $sockUri"); - - $greeting = fgets($workerSock); - $greeting = unserialize(base64_decode($greeting)) or die("Could not decode greeting\n"); - if ($greeting["type"] !== "hello" || $greeting["workerID"] !== $workerID) { - error("Unexpected greeting of type $greeting[type] and for worker $greeting[workerID]"); - } - - set_error_handler(function ($errno, $errstr, $errfile, $errline) use ($workerSock) { - if (error_reporting() & $errno) { - send_message($workerSock, compact('errno', 'errstr', 'errfile', 'errline') + [ - 'type' => 'php_error' - ]); - } - - return true; - }); - - foreach ($greeting["GLOBALS"] as $var => $value) { - if ($var !== "workerID" && $var !== "workerSock" && $var !== "GLOBALS") { - $GLOBALS[$var] = $value; - } - } - foreach ($greeting["constants"] as $const => $value) { - define($const, $value); - } - - send_message($workerSock, [ - "type" => "hello_reply", - "workerID" => $workerID - ]); - - send_message($workerSock, [ - "type" => "ready" - ]); - - while (($command = fgets($workerSock))) { - $command = unserialize(base64_decode($command)); - - switch ($command["type"]) { - case "run_tests": - run_all_tests($command["test_files"], $command["env"], $command["redir_tested"]); - send_message($workerSock, [ - "type" => "tests_finished", - "junit" => junit_enabled() ? $GLOBALS['JUNIT'] : null, - ]); - junit_init(); - break; - default: - send_message($workerSock, [ - "type" => "error", - "msg" => "Unrecognised message type: $command[type]" - ]); - break 2; - } - } + global $workerID, $workerSock; + + $sockUri = getenv("TEST_PHP_URI"); + + $workerSock = stream_socket_client($sockUri, $_, $_, 5) or error("Couldn't connect to $sockUri"); + + $greeting = fgets($workerSock); + $greeting = unserialize(base64_decode($greeting)) or die("Could not decode greeting\n"); + if ($greeting["type"] !== "hello" || $greeting["workerID"] !== $workerID) { + error("Unexpected greeting of type $greeting[type] and for worker $greeting[workerID]"); + } + + set_error_handler(function ($errno, $errstr, $errfile, $errline) use ($workerSock) { + if (error_reporting() & $errno) { + send_message($workerSock, compact('errno', 'errstr', 'errfile', 'errline') + [ + 'type' => 'php_error' + ]); + } + + return true; + }); + + foreach ($greeting["GLOBALS"] as $var => $value) { + if ($var !== "workerID" && $var !== "workerSock" && $var !== "GLOBALS") { + $GLOBALS[$var] = $value; + } + } + foreach ($greeting["constants"] as $const => $value) { + define($const, $value); + } + + send_message($workerSock, [ + "type" => "hello_reply", + "workerID" => $workerID + ]); + + send_message($workerSock, [ + "type" => "ready" + ]); + + while (($command = fgets($workerSock))) { + $command = unserialize(base64_decode($command)); + + switch ($command["type"]) { + case "run_tests": + run_all_tests($command["test_files"], $command["env"], $command["redir_tested"]); + send_message($workerSock, [ + "type" => "tests_finished", + "junit" => junit_enabled() ? $GLOBALS['JUNIT'] : null, + ]); + junit_init(); + break; + default: + send_message($workerSock, [ + "type" => "error", + "msg" => "Unrecognised message type: $command[type]" + ]); + break 2; + } + } } // @@ -1731,18 +1731,18 @@ function run_worker() { // function show_file_block($file, $block, $section = null) { - global $cfg; + global $cfg; - if ($cfg['show'][$file]) { + if ($cfg['show'][$file]) { - if (is_null($section)) { - $section = strtoupper($file); - } + if (is_null($section)) { + $section = strtoupper($file); + } - echo "\n========" . $section . "========\n"; - echo rtrim($block); - echo "\n========DONE========\n"; - } + echo "\n========" . $section . "========\n"; + echo rtrim($block); + echo "\n========DONE========\n"; + } } // @@ -1750,691 +1750,691 @@ function show_file_block($file, $block, $section = null) // function run_test($php, $file, $env) { - global $log_format, $ini_overwrites, $PHP_FAILED_TESTS; - global $pass_options, $DETAILED, $IN_REDIRECT, $test_cnt, $test_idx; - global $valgrind, $temp_source, $temp_target, $cfg, $environment; - global $no_clean; - global $SHOW_ONLY_GROUPS; - global $no_file_cache; - global $slow_min_ms; - global $preload; - // Parallel testing - global $workerID; - $temp_filenames = null; - $org_file = $file; - - if (isset($env['TEST_PHP_CGI_EXECUTABLE'])) { - $php_cgi = $env['TEST_PHP_CGI_EXECUTABLE']; - } - - if (isset($env['TEST_PHPDBG_EXECUTABLE'])) { - $phpdbg = $env['TEST_PHPDBG_EXECUTABLE']; - } - - if (is_array($file)) { - $file = $file[0]; - } - - if ($DETAILED) echo " + global $log_format, $ini_overwrites, $PHP_FAILED_TESTS; + global $pass_options, $DETAILED, $IN_REDIRECT, $test_cnt, $test_idx; + global $valgrind, $temp_source, $temp_target, $cfg, $environment; + global $no_clean; + global $SHOW_ONLY_GROUPS; + global $no_file_cache; + global $slow_min_ms; + global $preload; + // Parallel testing + global $workerID; + $temp_filenames = null; + $org_file = $file; + + if (isset($env['TEST_PHP_CGI_EXECUTABLE'])) { + $php_cgi = $env['TEST_PHP_CGI_EXECUTABLE']; + } + + if (isset($env['TEST_PHPDBG_EXECUTABLE'])) { + $phpdbg = $env['TEST_PHPDBG_EXECUTABLE']; + } + + if (is_array($file)) { + $file = $file[0]; + } + + if ($DETAILED) echo " ================= TEST $file "; - // Load the sections of the test file. - $section_text = array('TEST' => ''); - - $fp = fopen($file, "rb") or error("Cannot open test file: $file"); - - $bork_info = null; - - if (!feof($fp)) { - $line = fgets($fp); - - if ($line === false) { - $bork_info = "cannot read test"; - } - } else { - $bork_info = "empty test [$file]"; - } - if ($bork_info === null && strncmp('--TEST--', $line, 8)) { - $bork_info = "tests must start with --TEST-- [$file]"; - } - - $section = 'TEST'; - $secfile = false; - $secdone = false; - - while (!feof($fp)) { - $line = fgets($fp); - - if ($line === false) { - break; - } - - // Match the beginning of a section. - if (preg_match('/^--([_A-Z]+)--/', $line, $r)) { - $section = (string)$r[1]; - - if (isset($section_text[$section]) && $section_text[$section]) { - $bork_info = "duplicated $section section"; - } - - // check for unknown sections - if (!in_array($section, array( - 'EXPECT', 'EXPECTF', 'EXPECTREGEX', 'EXPECTREGEX_EXTERNAL', 'EXPECT_EXTERNAL', 'EXPECTF_EXTERNAL', 'EXPECTHEADERS', - 'POST', 'POST_RAW', 'GZIP_POST', 'DEFLATE_POST', 'PUT', 'GET', 'COOKIE', 'ARGS', - 'FILE', 'FILEEOF', 'FILE_EXTERNAL', 'REDIRECTTEST', - 'CAPTURE_STDIO', 'STDIN', 'CGI', 'PHPDBG', - 'INI', 'ENV', 'EXTENSIONS', - 'SKIPIF', 'XFAIL', 'XLEAK', 'CLEAN', - 'CREDITS', 'DESCRIPTION', 'CONFLICTS', 'WHITESPACE_SENSITIVE', - ))) { - $bork_info = 'Unknown section "' . $section . '"'; - } - - $section_text[$section] = ''; - $secfile = $section == 'FILE' || $section == 'FILEEOF' || $section == 'FILE_EXTERNAL'; - $secdone = false; - continue; - } - - // Add to the section text. - if (!$secdone) { - $section_text[$section] .= $line; - } - - // End of actual test? - if ($secfile && preg_match('/^===DONE===\s*$/', $line)) { - $secdone = true; - } - } - - // the redirect section allows a set of tests to be reused outside of - // a given test dir - if ($bork_info === null) { - if (isset($section_text['REDIRECTTEST'])) { - - if ($IN_REDIRECT) { - $bork_info = "Can't redirect a test from within a redirected test"; - } - - } else { - - if (!isset($section_text['PHPDBG']) && isset($section_text['FILE']) + isset($section_text['FILEEOF']) + isset($section_text['FILE_EXTERNAL']) != 1) { - $bork_info = "missing section --FILE--"; - } - - if (isset($section_text['FILEEOF'])) { - $section_text['FILE'] = preg_replace("/[\r\n]+$/", '', $section_text['FILEEOF']); - unset($section_text['FILEEOF']); - } - - foreach (array('FILE', 'EXPECT', 'EXPECTF', 'EXPECTREGEX') as $prefix) { - $key = $prefix . '_EXTERNAL'; - - if (isset($section_text[$key])) { - // don't allow tests to retrieve files from anywhere but this subdirectory - $section_text[$key] = dirname($file) . '/' . trim(str_replace('..', '', $section_text[$key])); - - if (file_exists($section_text[$key])) { - $section_text[$prefix] = file_get_contents($section_text[$key], FILE_BINARY); - unset($section_text[$key]); - } else { - $bork_info = "could not load --" . $key . "-- " . dirname($file) . '/' . trim($section_text[$key]); - } - } - } - - if ((isset($section_text['EXPECT']) + isset($section_text['EXPECTF']) + isset($section_text['EXPECTREGEX'])) != 1) { - $bork_info = "missing section --EXPECT--, --EXPECTF-- or --EXPECTREGEX--"; - } - } - } - fclose($fp); - - $shortname = str_replace(TEST_PHP_SRCDIR . '/', '', $file); - $tested_file = $shortname; - - if ($bork_info !== null) { - show_result("BORK", $bork_info, $tested_file); - $PHP_FAILED_TESTS['BORKED'][] = array( - 'name' => $file, - 'test_name' => '', - 'output' => '', - 'diff' => '', - 'info' => "$bork_info [$file]", - ); - - junit_mark_test_as('BORK', $shortname, $tested_file, 0, $bork_info); - return 'BORKED'; - } - - if (isset($section_text['CAPTURE_STDIO'])) { - $captureStdIn = stripos($section_text['CAPTURE_STDIO'], 'STDIN') !== false; - $captureStdOut = stripos($section_text['CAPTURE_STDIO'], 'STDOUT') !== false; - $captureStdErr = stripos($section_text['CAPTURE_STDIO'], 'STDERR') !== false; - } else { - $captureStdIn = true; - $captureStdOut = true; - $captureStdErr = true; - } - if ($captureStdOut && $captureStdErr) { - $cmdRedirect = ' 2>&1'; - } else { - $cmdRedirect = ''; - } - - $tested = trim($section_text['TEST']); - - /* For GET/POST/PUT tests, check if cgi sapi is available and if it is, use it. */ - if (array_key_exists('CGI', $section_text) || !empty($section_text['GET']) || !empty($section_text['POST']) || !empty($section_text['GZIP_POST']) || !empty($section_text['DEFLATE_POST']) || !empty($section_text['POST_RAW']) || !empty($section_text['PUT']) || !empty($section_text['COOKIE']) || !empty($section_text['EXPECTHEADERS'])) { - if (isset($php_cgi)) { - $php = $php_cgi . ' -C '; - } else if (!strncasecmp(PHP_OS, "win", 3) && file_exists(dirname($php) . "/php-cgi.exe")) { - $php = realpath(dirname($php) . "/php-cgi.exe") . ' -C '; - } else { - if (file_exists(dirname($php) . "/../../sapi/cgi/php-cgi")) { - $php = realpath(dirname($php) . "/../../sapi/cgi/php-cgi") . ' -C '; - } else if (file_exists("./sapi/cgi/php-cgi")) { - $php = realpath("./sapi/cgi/php-cgi") . ' -C '; - } else if (file_exists(dirname($php) . "/php-cgi")) { - $php = realpath(dirname($php) . "/php-cgi") . ' -C '; - } else { - show_result('SKIP', $tested, $tested_file, "reason: CGI not available"); - - junit_init_suite(junit_get_suitename_for($shortname)); - junit_mark_test_as('SKIP', $shortname, $tested, 0, 'CGI not available'); - return 'SKIPPED'; - } - } - $uses_cgi = true; - } - - /* For phpdbg tests, check if phpdbg sapi is available and if it is, use it. */ - $extra_options = ''; - if (array_key_exists('PHPDBG', $section_text)) { - if (!isset($section_text['STDIN'])) { - $section_text['STDIN'] = $section_text['PHPDBG'] . "\n"; - } - - if (isset($phpdbg)) { - $php = $phpdbg . ' -qIb'; - - // Additional phpdbg command line options for sections that need to - // be run straight away. For example, EXTENSIONS, SKIPIF, CLEAN. - $extra_options = '-rr'; - } else { - show_result('SKIP', $tested, $tested_file, "reason: phpdbg not available"); - - junit_init_suite(junit_get_suitename_for($shortname)); - junit_mark_test_as('SKIP', $shortname, $tested, 0, 'phpdbg not available'); - return 'SKIPPED'; - } - } - - if (!$SHOW_ONLY_GROUPS && !$workerID) { - show_test($test_idx, $shortname); - } - - if (is_array($IN_REDIRECT)) { - $temp_dir = $test_dir = $IN_REDIRECT['dir']; - } else { - $temp_dir = $test_dir = realpath(dirname($file)); - } - - if ($temp_source && $temp_target) { - $temp_dir = str_replace($temp_source, $temp_target, $temp_dir); - } - - $main_file_name = basename($file, 'phpt'); - - $diff_filename = $temp_dir . DIRECTORY_SEPARATOR . $main_file_name . 'diff'; - $log_filename = $temp_dir . DIRECTORY_SEPARATOR . $main_file_name . 'log'; - $exp_filename = $temp_dir . DIRECTORY_SEPARATOR . $main_file_name . 'exp'; - $output_filename = $temp_dir . DIRECTORY_SEPARATOR . $main_file_name . 'out'; - $memcheck_filename = $temp_dir . DIRECTORY_SEPARATOR . $main_file_name . 'mem'; - $sh_filename = $temp_dir . DIRECTORY_SEPARATOR . $main_file_name . 'sh'; - $temp_file = $temp_dir . DIRECTORY_SEPARATOR . $main_file_name . 'php'; - $test_file = $test_dir . DIRECTORY_SEPARATOR . $main_file_name . 'php'; - $temp_skipif = $temp_dir . DIRECTORY_SEPARATOR . $main_file_name . 'skip.php'; - $test_skipif = $test_dir . DIRECTORY_SEPARATOR . $main_file_name . 'skip.php'; - $temp_clean = $temp_dir . DIRECTORY_SEPARATOR . $main_file_name . 'clean.php'; - $test_clean = $test_dir . DIRECTORY_SEPARATOR . $main_file_name . 'clean.php'; - $preload_filename = $temp_dir . DIRECTORY_SEPARATOR . $main_file_name . 'preload.php'; - $tmp_post = $temp_dir . DIRECTORY_SEPARATOR . $main_file_name . 'post'; - $tmp_relative_file = str_replace(__DIR__ . DIRECTORY_SEPARATOR, '', $test_file) . 't'; - - if ($temp_source && $temp_target) { - $temp_skipif .= 's'; - $temp_file .= 's'; - $temp_clean .= 's'; - $copy_file = $temp_dir . DIRECTORY_SEPARATOR . basename(is_array($file) ? $file[1] : $file) . '.phps'; - - if (!is_dir(dirname($copy_file))) { - mkdir(dirname($copy_file), 0777, true) or error("Cannot create output directory - " . dirname($copy_file)); - } - - if (isset($section_text['FILE'])) { - save_text($copy_file, $section_text['FILE']); - } - - $temp_filenames = array( - 'file' => $copy_file, - 'diff' => $diff_filename, - 'log' => $log_filename, - 'exp' => $exp_filename, - 'out' => $output_filename, - 'mem' => $memcheck_filename, - 'sh' => $sh_filename, - 'php' => $temp_file, - 'skip' => $temp_skipif, - 'clean' => $temp_clean - ); - } - - if (is_array($IN_REDIRECT)) { - $tested = $IN_REDIRECT['prefix'] . ' ' . trim($section_text['TEST']); - $tested_file = $tmp_relative_file; - $shortname = str_replace(TEST_PHP_SRCDIR . '/', '', $tested_file); - } - - // unlink old test results - @unlink($diff_filename); - @unlink($log_filename); - @unlink($exp_filename); - @unlink($output_filename); - @unlink($memcheck_filename); - @unlink($sh_filename); - @unlink($temp_file); - @unlink($test_file); - @unlink($temp_skipif); - @unlink($test_skipif); - @unlink($tmp_post); - @unlink($temp_clean); - @unlink($test_clean); - @unlink($preload_filename); - - // Reset environment from any previous test. - $env['REDIRECT_STATUS'] = ''; - $env['QUERY_STRING'] = ''; - $env['PATH_TRANSLATED'] = ''; - $env['SCRIPT_FILENAME'] = ''; - $env['REQUEST_METHOD'] = ''; - $env['CONTENT_TYPE'] = ''; - $env['CONTENT_LENGTH'] = ''; - $env['TZ'] = ''; - - if (!empty($section_text['ENV'])) { - - foreach (explode("\n", trim($section_text['ENV'])) as $e) { - $e = explode('=', trim($e), 2); - - if (!empty($e[0]) && isset($e[1])) { - $env[$e[0]] = $e[1]; - } - } - } - - // Default ini settings - $ini_settings = $workerID ? array('opcache.cache_id' => "worker$workerID") : array(); - - // Additional required extensions - if (array_key_exists('EXTENSIONS', $section_text)) { - $ext_params = array(); - settings2array($ini_overwrites, $ext_params); - $ext_params = settings2params($ext_params); - $ext_dir = `$php $pass_options $extra_options $ext_params -d display_errors=0 -r "echo ini_get('extension_dir');"`; - $extensions = preg_split("/[\n\r]+/", trim($section_text['EXTENSIONS'])); - $loaded = explode(",", `$php $pass_options $extra_options $ext_params -d display_errors=0 -r "echo implode(',', get_loaded_extensions());"`); - $ext_prefix = substr(PHP_OS, 0, 3) === "WIN" ? "php_" : ""; - foreach ($extensions as $req_ext) { - if (!in_array($req_ext, $loaded)) { - if ($req_ext == 'opcache') { - $ini_settings['zend_extension'][] = $ext_dir . DIRECTORY_SEPARATOR . $ext_prefix . $req_ext . '.' . PHP_SHLIB_SUFFIX; - } else { - $ini_settings['extension'][] = $ext_dir . DIRECTORY_SEPARATOR . $ext_prefix . $req_ext . '.' . PHP_SHLIB_SUFFIX; - } - } - } - } - - // additional ini overwrites - //$ini_overwrites[] = 'setting=value'; - settings2array($ini_overwrites, $ini_settings); - - $orig_ini_settings = settings2params($ini_settings); - - // Any special ini settings - // these may overwrite the test defaults... - if (array_key_exists('INI', $section_text)) { - $section_text['INI'] = str_replace('{PWD}', dirname($file), $section_text['INI']); - $section_text['INI'] = str_replace('{TMP}', sys_get_temp_dir(), $section_text['INI']); - settings2array(preg_split("/[\n\r]+/", $section_text['INI']), $ini_settings); - } - - $ini_settings = settings2params($ini_settings); - - $env['TEST_PHP_EXTRA_ARGS'] = $pass_options . ' ' . $ini_settings; - - // Check if test should be skipped. - $info = ''; - $warn = false; - - if (array_key_exists('SKIPIF', $section_text)) { - - if (trim($section_text['SKIPIF'])) { - show_file_block('skip', $section_text['SKIPIF']); - save_text($test_skipif, $section_text['SKIPIF'], $temp_skipif); - $extra = substr(PHP_OS, 0, 3) !== "WIN" ? - "unset REQUEST_METHOD; unset QUERY_STRING; unset PATH_TRANSLATED; unset SCRIPT_FILENAME; unset REQUEST_METHOD;" : ""; - - if ($valgrind) { - $env['USE_ZEND_ALLOC'] = '0'; - $env['ZEND_DONT_UNLOAD_MODULES'] = 1; - } - - junit_start_timer($shortname); - - $output = system_with_timeout("$extra $php $pass_options $extra_options -q $orig_ini_settings $no_file_cache -d display_errors=0 \"$test_skipif\"", $env); - - junit_finish_timer($shortname); - - if (!$cfg['keep']['skip']) { - @unlink($test_skipif); - } - - if (!strncasecmp('skip', ltrim($output), 4)) { - - if (preg_match('/^\s*skip\s*(.+)\s*/i', $output, $m)) { - show_result('SKIP', $tested, $tested_file, "reason: $m[1]", $temp_filenames); - } else { - show_result('SKIP', $tested, $tested_file, '', $temp_filenames); - } - - if (!$cfg['keep']['skip']) { - @unlink($test_skipif); - } - - $message = !empty($m[1]) ? $m[1] : ''; - junit_mark_test_as('SKIP', $shortname, $tested, null, $message); - return 'SKIPPED'; - } - - if (!strncasecmp('info', ltrim($output), 4)) { - if (preg_match('/^\s*info\s*(.+)\s*/i', $output, $m)) { - $info = " (info: $m[1])"; - } - } - - if (!strncasecmp('warn', ltrim($output), 4)) { - if (preg_match('/^\s*warn\s*(.+)\s*/i', $output, $m)) { - $warn = true; /* only if there is a reason */ - $info = " (warn: $m[1])"; - } - } - - if (!strncasecmp('xfail', ltrim($output), 5)) { - // Pretend we have an XFAIL section - $section_text['XFAIL'] = trim(substr(ltrim($output), 5)); - } - } - } - - if (!extension_loaded("zlib") - && (array_key_exists("GZIP_POST", $section_text) - || array_key_exists("DEFLATE_POST", $section_text))) { - $message = "ext/zlib required"; - show_result('SKIP', $tested, $tested_file, "reason: $message", $temp_filenames); - junit_mark_test_as('SKIP', $shortname, $tested, null, $message); - return 'SKIPPED'; - } - - if (isset($section_text['REDIRECTTEST'])) { - $test_files = array(); - - $IN_REDIRECT = eval($section_text['REDIRECTTEST']); - $IN_REDIRECT['via'] = "via [$shortname]\n\t"; - $IN_REDIRECT['dir'] = realpath(dirname($file)); - $IN_REDIRECT['prefix'] = trim($section_text['TEST']); - - if (!empty($IN_REDIRECT['TESTS'])) { - - if (is_array($org_file)) { - $test_files[] = $org_file[1]; - } else { - $GLOBALS['test_files'] = $test_files; - find_files($IN_REDIRECT['TESTS']); - - foreach ($GLOBALS['test_files'] as $f) { - $test_files[] = array($f, $file); - } - } - $test_cnt += count($test_files) - 1; - $test_idx--; - - show_redirect_start($IN_REDIRECT['TESTS'], $tested, $tested_file); - - // set up environment - $redirenv = array_merge($environment, $IN_REDIRECT['ENV']); - $redirenv['REDIR_TEST_DIR'] = realpath($IN_REDIRECT['TESTS']) . DIRECTORY_SEPARATOR; - - usort($test_files, "test_sort"); - run_all_tests($test_files, $redirenv, $tested); - - show_redirect_ends($IN_REDIRECT['TESTS'], $tested, $tested_file); - - // a redirected test never fails - $IN_REDIRECT = false; - - junit_mark_test_as('PASS', $shortname, $tested); - return 'REDIR'; - - } else { - - $bork_info = "Redirect info must contain exactly one TEST string to be used as redirect directory."; - show_result("BORK", $bork_info, '', $temp_filenames); - $PHP_FAILED_TESTS['BORKED'][] = array( - 'name' => $file, - 'test_name' => '', - 'output' => '', - 'diff' => '', - 'info' => "$bork_info [$file]", - ); - } - } - - if (is_array($org_file) || isset($section_text['REDIRECTTEST'])) { - - if (is_array($org_file)) { - $file = $org_file[0]; - } - - $bork_info = "Redirected test did not contain redirection info"; - show_result("BORK", $bork_info, '', $temp_filenames); - $PHP_FAILED_TESTS['BORKED'][] = array( - 'name' => $file, - 'test_name' => '', - 'output' => '', - 'diff' => '', - 'info' => "$bork_info [$file]", - ); - - junit_mark_test_as('BORK', $shortname, $tested, null, $bork_info); - - return 'BORKED'; - } - - // We've satisfied the preconditions - run the test! - if (isset($section_text['FILE'])) { - show_file_block('php', $section_text['FILE'], 'TEST'); - save_text($test_file, $section_text['FILE'], $temp_file); - } else { - $test_file = $temp_file = ""; - } - - if (array_key_exists('GET', $section_text)) { - $query_string = trim($section_text['GET']); - } else { - $query_string = ''; - } - - $env['REDIRECT_STATUS'] = '1'; - if (empty($env['QUERY_STRING'])) { - $env['QUERY_STRING'] = $query_string; - } - if (empty($env['PATH_TRANSLATED'])) { - $env['PATH_TRANSLATED'] = $test_file; - } - if (empty($env['SCRIPT_FILENAME'])) { - $env['SCRIPT_FILENAME'] = $test_file; - } - - if (array_key_exists('COOKIE', $section_text)) { - $env['HTTP_COOKIE'] = trim($section_text['COOKIE']); - } else { - $env['HTTP_COOKIE'] = ''; - } - - $args = isset($section_text['ARGS']) ? ' -- ' . $section_text['ARGS'] : ''; + // Load the sections of the test file. + $section_text = array('TEST' => ''); - if ($preload && !empty($test_file)) { - save_text($preload_filename, "<?php opcache_compile_file('$test_file');"); - $local_pass_options = $pass_options; - unset($pass_options); - $pass_options = $local_pass_options; - $pass_options .= " -d opcache.preload=" . $preload_filename; - } + $fp = fopen($file, "rb") or error("Cannot open test file: $file"); - if (array_key_exists('POST_RAW', $section_text) && !empty($section_text['POST_RAW'])) { + $bork_info = null; - $post = trim($section_text['POST_RAW']); - $raw_lines = explode("\n", $post); + if (!feof($fp)) { + $line = fgets($fp); - $request = ''; - $started = false; + if ($line === false) { + $bork_info = "cannot read test"; + } + } else { + $bork_info = "empty test [$file]"; + } + if ($bork_info === null && strncmp('--TEST--', $line, 8)) { + $bork_info = "tests must start with --TEST-- [$file]"; + } - foreach ($raw_lines as $line) { - - if (empty($env['CONTENT_TYPE']) && preg_match('/^Content-Type:(.*)/i', $line, $res)) { - $env['CONTENT_TYPE'] = trim(str_replace("\r", '', $res[1])); - continue; - } + $section = 'TEST'; + $secfile = false; + $secdone = false; - if ($started) { - $request .= "\n"; - } + while (!feof($fp)) { + $line = fgets($fp); - $started = true; - $request .= $line; - } + if ($line === false) { + break; + } - $env['CONTENT_LENGTH'] = strlen($request); - $env['REQUEST_METHOD'] = 'POST'; + // Match the beginning of a section. + if (preg_match('/^--([_A-Z]+)--/', $line, $r)) { + $section = (string)$r[1]; + + if (isset($section_text[$section]) && $section_text[$section]) { + $bork_info = "duplicated $section section"; + } + + // check for unknown sections + if (!in_array($section, array( + 'EXPECT', 'EXPECTF', 'EXPECTREGEX', 'EXPECTREGEX_EXTERNAL', 'EXPECT_EXTERNAL', 'EXPECTF_EXTERNAL', 'EXPECTHEADERS', + 'POST', 'POST_RAW', 'GZIP_POST', 'DEFLATE_POST', 'PUT', 'GET', 'COOKIE', 'ARGS', + 'FILE', 'FILEEOF', 'FILE_EXTERNAL', 'REDIRECTTEST', + 'CAPTURE_STDIO', 'STDIN', 'CGI', 'PHPDBG', + 'INI', 'ENV', 'EXTENSIONS', + 'SKIPIF', 'XFAIL', 'XLEAK', 'CLEAN', + 'CREDITS', 'DESCRIPTION', 'CONFLICTS', 'WHITESPACE_SENSITIVE', + ))) { + $bork_info = 'Unknown section "' . $section . '"'; + } + + $section_text[$section] = ''; + $secfile = $section == 'FILE' || $section == 'FILEEOF' || $section == 'FILE_EXTERNAL'; + $secdone = false; + continue; + } - if (empty($request)) { - junit_mark_test_as('BORK', $shortname, $tested, null, 'empty $request'); - return 'BORKED'; - } + // Add to the section text. + if (!$secdone) { + $section_text[$section] .= $line; + } - save_text($tmp_post, $request); - $cmd = "$php $pass_options $ini_settings -f \"$test_file\"$cmdRedirect < \"$tmp_post\""; + // End of actual test? + if ($secfile && preg_match('/^===DONE===\s*$/', $line)) { + $secdone = true; + } + } - } elseif (array_key_exists('PUT', $section_text) && !empty($section_text['PUT'])) { + // the redirect section allows a set of tests to be reused outside of + // a given test dir + if ($bork_info === null) { + if (isset($section_text['REDIRECTTEST'])) { - $post = trim($section_text['PUT']); - $raw_lines = explode("\n", $post); + if ($IN_REDIRECT) { + $bork_info = "Can't redirect a test from within a redirected test"; + } - $request = ''; - $started = false; + } else { - foreach ($raw_lines as $line) { + if (!isset($section_text['PHPDBG']) && isset($section_text['FILE']) + isset($section_text['FILEEOF']) + isset($section_text['FILE_EXTERNAL']) != 1) { + $bork_info = "missing section --FILE--"; + } + + if (isset($section_text['FILEEOF'])) { + $section_text['FILE'] = preg_replace("/[\r\n]+$/", '', $section_text['FILEEOF']); + unset($section_text['FILEEOF']); + } + + foreach (array('FILE', 'EXPECT', 'EXPECTF', 'EXPECTREGEX') as $prefix) { + $key = $prefix . '_EXTERNAL'; + + if (isset($section_text[$key])) { + // don't allow tests to retrieve files from anywhere but this subdirectory + $section_text[$key] = dirname($file) . '/' . trim(str_replace('..', '', $section_text[$key])); + + if (file_exists($section_text[$key])) { + $section_text[$prefix] = file_get_contents($section_text[$key], FILE_BINARY); + unset($section_text[$key]); + } else { + $bork_info = "could not load --" . $key . "-- " . dirname($file) . '/' . trim($section_text[$key]); + } + } + } + + if ((isset($section_text['EXPECT']) + isset($section_text['EXPECTF']) + isset($section_text['EXPECTREGEX'])) != 1) { + $bork_info = "missing section --EXPECT--, --EXPECTF-- or --EXPECTREGEX--"; + } + } + } + fclose($fp); + + $shortname = str_replace(TEST_PHP_SRCDIR . '/', '', $file); + $tested_file = $shortname; + + if ($bork_info !== null) { + show_result("BORK", $bork_info, $tested_file); + $PHP_FAILED_TESTS['BORKED'][] = array( + 'name' => $file, + 'test_name' => '', + 'output' => '', + 'diff' => '', + 'info' => "$bork_info [$file]", + ); + + junit_mark_test_as('BORK', $shortname, $tested_file, 0, $bork_info); + return 'BORKED'; + } - if (empty($env['CONTENT_TYPE']) && preg_match('/^Content-Type:(.*)/i', $line, $res)) { - $env['CONTENT_TYPE'] = trim(str_replace("\r", '', $res[1])); - continue; - } + if (isset($section_text['CAPTURE_STDIO'])) { + $captureStdIn = stripos($section_text['CAPTURE_STDIO'], 'STDIN') !== false; + $captureStdOut = stripos($section_text['CAPTURE_STDIO'], 'STDOUT') !== false; + $captureStdErr = stripos($section_text['CAPTURE_STDIO'], 'STDERR') !== false; + } else { + $captureStdIn = true; + $captureStdOut = true; + $captureStdErr = true; + } + if ($captureStdOut && $captureStdErr) { + $cmdRedirect = ' 2>&1'; + } else { + $cmdRedirect = ''; + } - if ($started) { - $request .= "\n"; - } + $tested = trim($section_text['TEST']); - $started = true; - $request .= $line; - } + /* For GET/POST/PUT tests, check if cgi sapi is available and if it is, use it. */ + if (array_key_exists('CGI', $section_text) || !empty($section_text['GET']) || !empty($section_text['POST']) || !empty($section_text['GZIP_POST']) || !empty($section_text['DEFLATE_POST']) || !empty($section_text['POST_RAW']) || !empty($section_text['PUT']) || !empty($section_text['COOKIE']) || !empty($section_text['EXPECTHEADERS'])) { + if (isset($php_cgi)) { + $php = $php_cgi . ' -C '; + } else if (!strncasecmp(PHP_OS, "win", 3) && file_exists(dirname($php) . "/php-cgi.exe")) { + $php = realpath(dirname($php) . "/php-cgi.exe") . ' -C '; + } else { + if (file_exists(dirname($php) . "/../../sapi/cgi/php-cgi")) { + $php = realpath(dirname($php) . "/../../sapi/cgi/php-cgi") . ' -C '; + } else if (file_exists("./sapi/cgi/php-cgi")) { + $php = realpath("./sapi/cgi/php-cgi") . ' -C '; + } else if (file_exists(dirname($php) . "/php-cgi")) { + $php = realpath(dirname($php) . "/php-cgi") . ' -C '; + } else { + show_result('SKIP', $tested, $tested_file, "reason: CGI not available"); + + junit_init_suite(junit_get_suitename_for($shortname)); + junit_mark_test_as('SKIP', $shortname, $tested, 0, 'CGI not available'); + return 'SKIPPED'; + } + } + $uses_cgi = true; + } - $env['CONTENT_LENGTH'] = strlen($request); - $env['REQUEST_METHOD'] = 'PUT'; + /* For phpdbg tests, check if phpdbg sapi is available and if it is, use it. */ + $extra_options = ''; + if (array_key_exists('PHPDBG', $section_text)) { + if (!isset($section_text['STDIN'])) { + $section_text['STDIN'] = $section_text['PHPDBG'] . "\n"; + } - if (empty($request)) { - junit_mark_test_as('BORK', $shortname, $tested, null, 'empty $request'); - return 'BORKED'; - } + if (isset($phpdbg)) { + $php = $phpdbg . ' -qIb'; - save_text($tmp_post, $request); - $cmd = "$php $pass_options $ini_settings -f \"$test_file\"$cmdRedirect < \"$tmp_post\""; + // Additional phpdbg command line options for sections that need to + // be run straight away. For example, EXTENSIONS, SKIPIF, CLEAN. + $extra_options = '-rr'; + } else { + show_result('SKIP', $tested, $tested_file, "reason: phpdbg not available"); - } else if (array_key_exists('POST', $section_text) && !empty($section_text['POST'])) { + junit_init_suite(junit_get_suitename_for($shortname)); + junit_mark_test_as('SKIP', $shortname, $tested, 0, 'phpdbg not available'); + return 'SKIPPED'; + } + } - $post = trim($section_text['POST']); - $content_length = strlen($post); - save_text($tmp_post, $post); + if (!$SHOW_ONLY_GROUPS && !$workerID) { + show_test($test_idx, $shortname); + } - $env['REQUEST_METHOD'] = 'POST'; - if (empty($env['CONTENT_TYPE'])) { - $env['CONTENT_TYPE'] = 'application/x-www-form-urlencoded'; - } + if (is_array($IN_REDIRECT)) { + $temp_dir = $test_dir = $IN_REDIRECT['dir']; + } else { + $temp_dir = $test_dir = realpath(dirname($file)); + } + + if ($temp_source && $temp_target) { + $temp_dir = str_replace($temp_source, $temp_target, $temp_dir); + } + + $main_file_name = basename($file, 'phpt'); + + $diff_filename = $temp_dir . DIRECTORY_SEPARATOR . $main_file_name . 'diff'; + $log_filename = $temp_dir . DIRECTORY_SEPARATOR . $main_file_name . 'log'; + $exp_filename = $temp_dir . DIRECTORY_SEPARATOR . $main_file_name . 'exp'; + $output_filename = $temp_dir . DIRECTORY_SEPARATOR . $main_file_name . 'out'; + $memcheck_filename = $temp_dir . DIRECTORY_SEPARATOR . $main_file_name . 'mem'; + $sh_filename = $temp_dir . DIRECTORY_SEPARATOR . $main_file_name . 'sh'; + $temp_file = $temp_dir . DIRECTORY_SEPARATOR . $main_file_name . 'php'; + $test_file = $test_dir . DIRECTORY_SEPARATOR . $main_file_name . 'php'; + $temp_skipif = $temp_dir . DIRECTORY_SEPARATOR . $main_file_name . 'skip.php'; + $test_skipif = $test_dir . DIRECTORY_SEPARATOR . $main_file_name . 'skip.php'; + $temp_clean = $temp_dir . DIRECTORY_SEPARATOR . $main_file_name . 'clean.php'; + $test_clean = $test_dir . DIRECTORY_SEPARATOR . $main_file_name . 'clean.php'; + $preload_filename = $temp_dir . DIRECTORY_SEPARATOR . $main_file_name . 'preload.php'; + $tmp_post = $temp_dir . DIRECTORY_SEPARATOR . $main_file_name . 'post'; + $tmp_relative_file = str_replace(__DIR__ . DIRECTORY_SEPARATOR, '', $test_file) . 't'; + + if ($temp_source && $temp_target) { + $temp_skipif .= 's'; + $temp_file .= 's'; + $temp_clean .= 's'; + $copy_file = $temp_dir . DIRECTORY_SEPARATOR . basename(is_array($file) ? $file[1] : $file) . '.phps'; + + if (!is_dir(dirname($copy_file))) { + mkdir(dirname($copy_file), 0777, true) or error("Cannot create output directory - " . dirname($copy_file)); + } + + if (isset($section_text['FILE'])) { + save_text($copy_file, $section_text['FILE']); + } + + $temp_filenames = array( + 'file' => $copy_file, + 'diff' => $diff_filename, + 'log' => $log_filename, + 'exp' => $exp_filename, + 'out' => $output_filename, + 'mem' => $memcheck_filename, + 'sh' => $sh_filename, + 'php' => $temp_file, + 'skip' => $temp_skipif, + 'clean' => $temp_clean + ); + } - if (empty($env['CONTENT_LENGTH'])) { - $env['CONTENT_LENGTH'] = $content_length; - } + if (is_array($IN_REDIRECT)) { + $tested = $IN_REDIRECT['prefix'] . ' ' . trim($section_text['TEST']); + $tested_file = $tmp_relative_file; + $shortname = str_replace(TEST_PHP_SRCDIR . '/', '', $tested_file); + } - $cmd = "$php $pass_options $ini_settings -f \"$test_file\"$cmdRedirect < \"$tmp_post\""; + // unlink old test results + @unlink($diff_filename); + @unlink($log_filename); + @unlink($exp_filename); + @unlink($output_filename); + @unlink($memcheck_filename); + @unlink($sh_filename); + @unlink($temp_file); + @unlink($test_file); + @unlink($temp_skipif); + @unlink($test_skipif); + @unlink($tmp_post); + @unlink($temp_clean); + @unlink($test_clean); + @unlink($preload_filename); + + // Reset environment from any previous test. + $env['REDIRECT_STATUS'] = ''; + $env['QUERY_STRING'] = ''; + $env['PATH_TRANSLATED'] = ''; + $env['SCRIPT_FILENAME'] = ''; + $env['REQUEST_METHOD'] = ''; + $env['CONTENT_TYPE'] = ''; + $env['CONTENT_LENGTH'] = ''; + $env['TZ'] = ''; + + if (!empty($section_text['ENV'])) { + + foreach (explode("\n", trim($section_text['ENV'])) as $e) { + $e = explode('=', trim($e), 2); + + if (!empty($e[0]) && isset($e[1])) { + $env[$e[0]] = $e[1]; + } + } + } - } else if (array_key_exists('GZIP_POST', $section_text) && !empty($section_text['GZIP_POST'])) { + // Default ini settings + $ini_settings = $workerID ? array('opcache.cache_id' => "worker$workerID") : array(); + + // Additional required extensions + if (array_key_exists('EXTENSIONS', $section_text)) { + $ext_params = array(); + settings2array($ini_overwrites, $ext_params); + $ext_params = settings2params($ext_params); + $ext_dir = `$php $pass_options $extra_options $ext_params -d display_errors=0 -r "echo ini_get('extension_dir');"`; + $extensions = preg_split("/[\n\r]+/", trim($section_text['EXTENSIONS'])); + $loaded = explode(",", `$php $pass_options $extra_options $ext_params -d display_errors=0 -r "echo implode(',', get_loaded_extensions());"`); + $ext_prefix = substr(PHP_OS, 0, 3) === "WIN" ? "php_" : ""; + foreach ($extensions as $req_ext) { + if (!in_array($req_ext, $loaded)) { + if ($req_ext == 'opcache') { + $ini_settings['zend_extension'][] = $ext_dir . DIRECTORY_SEPARATOR . $ext_prefix . $req_ext . '.' . PHP_SHLIB_SUFFIX; + } else { + $ini_settings['extension'][] = $ext_dir . DIRECTORY_SEPARATOR . $ext_prefix . $req_ext . '.' . PHP_SHLIB_SUFFIX; + } + } + } + } + + // additional ini overwrites + //$ini_overwrites[] = 'setting=value'; + settings2array($ini_overwrites, $ini_settings); - $post = trim($section_text['GZIP_POST']); - $post = gzencode($post, 9, FORCE_GZIP); - $env['HTTP_CONTENT_ENCODING'] = 'gzip'; + $orig_ini_settings = settings2params($ini_settings); + + // Any special ini settings + // these may overwrite the test defaults... + if (array_key_exists('INI', $section_text)) { + $section_text['INI'] = str_replace('{PWD}', dirname($file), $section_text['INI']); + $section_text['INI'] = str_replace('{TMP}', sys_get_temp_dir(), $section_text['INI']); + settings2array(preg_split("/[\n\r]+/", $section_text['INI']), $ini_settings); + } - save_text($tmp_post, $post); - $content_length = strlen($post); + $ini_settings = settings2params($ini_settings); - $env['REQUEST_METHOD'] = 'POST'; - $env['CONTENT_TYPE'] = 'application/x-www-form-urlencoded'; - $env['CONTENT_LENGTH'] = $content_length; + $env['TEST_PHP_EXTRA_ARGS'] = $pass_options . ' ' . $ini_settings; - $cmd = "$php $pass_options $ini_settings -f \"$test_file\"$cmdRedirect < \"$tmp_post\""; + // Check if test should be skipped. + $info = ''; + $warn = false; - } else if (array_key_exists('DEFLATE_POST', $section_text) && !empty($section_text['DEFLATE_POST'])) { - $post = trim($section_text['DEFLATE_POST']); - $post = gzcompress($post, 9); - $env['HTTP_CONTENT_ENCODING'] = 'deflate'; - save_text($tmp_post, $post); - $content_length = strlen($post); + if (array_key_exists('SKIPIF', $section_text)) { - $env['REQUEST_METHOD'] = 'POST'; - $env['CONTENT_TYPE'] = 'application/x-www-form-urlencoded'; - $env['CONTENT_LENGTH'] = $content_length; + if (trim($section_text['SKIPIF'])) { + show_file_block('skip', $section_text['SKIPIF']); + save_text($test_skipif, $section_text['SKIPIF'], $temp_skipif); + $extra = substr(PHP_OS, 0, 3) !== "WIN" ? + "unset REQUEST_METHOD; unset QUERY_STRING; unset PATH_TRANSLATED; unset SCRIPT_FILENAME; unset REQUEST_METHOD;" : ""; - $cmd = "$php $pass_options $ini_settings -f \"$test_file\"$cmdRedirect < \"$tmp_post\""; + if ($valgrind) { + $env['USE_ZEND_ALLOC'] = '0'; + $env['ZEND_DONT_UNLOAD_MODULES'] = 1; + } - } else { + junit_start_timer($shortname); - $env['REQUEST_METHOD'] = 'GET'; - $env['CONTENT_TYPE'] = ''; - $env['CONTENT_LENGTH'] = ''; + $output = system_with_timeout("$extra $php $pass_options $extra_options -q $orig_ini_settings $no_file_cache -d display_errors=0 \"$test_skipif\"", $env); - $cmd = "$php $pass_options $ini_settings -f \"$test_file\" $args$cmdRedirect"; - } + junit_finish_timer($shortname); - if ($valgrind) { - $env['USE_ZEND_ALLOC'] = '0'; - $env['ZEND_DONT_UNLOAD_MODULES'] = 1; + if (!$cfg['keep']['skip']) { + @unlink($test_skipif); + } - $cmd = $valgrind->wrapCommand($cmd, $memcheck_filename, strpos($test_file, "pcre") !== false); - } + if (!strncasecmp('skip', ltrim($output), 4)) { - if ($DETAILED) echo " + if (preg_match('/^\s*skip\s*(.+)\s*/i', $output, $m)) { + show_result('SKIP', $tested, $tested_file, "reason: $m[1]", $temp_filenames); + } else { + show_result('SKIP', $tested, $tested_file, '', $temp_filenames); + } + + if (!$cfg['keep']['skip']) { + @unlink($test_skipif); + } + + $message = !empty($m[1]) ? $m[1] : ''; + junit_mark_test_as('SKIP', $shortname, $tested, null, $message); + return 'SKIPPED'; + } + + if (!strncasecmp('info', ltrim($output), 4)) { + if (preg_match('/^\s*info\s*(.+)\s*/i', $output, $m)) { + $info = " (info: $m[1])"; + } + } + + if (!strncasecmp('warn', ltrim($output), 4)) { + if (preg_match('/^\s*warn\s*(.+)\s*/i', $output, $m)) { + $warn = true; /* only if there is a reason */ + $info = " (warn: $m[1])"; + } + } + + if (!strncasecmp('xfail', ltrim($output), 5)) { + // Pretend we have an XFAIL section + $section_text['XFAIL'] = trim(substr(ltrim($output), 5)); + } + } + } + + if (!extension_loaded("zlib") + && (array_key_exists("GZIP_POST", $section_text) + || array_key_exists("DEFLATE_POST", $section_text))) { + $message = "ext/zlib required"; + show_result('SKIP', $tested, $tested_file, "reason: $message", $temp_filenames); + junit_mark_test_as('SKIP', $shortname, $tested, null, $message); + return 'SKIPPED'; + } + + if (isset($section_text['REDIRECTTEST'])) { + $test_files = array(); + + $IN_REDIRECT = eval($section_text['REDIRECTTEST']); + $IN_REDIRECT['via'] = "via [$shortname]\n\t"; + $IN_REDIRECT['dir'] = realpath(dirname($file)); + $IN_REDIRECT['prefix'] = trim($section_text['TEST']); + + if (!empty($IN_REDIRECT['TESTS'])) { + + if (is_array($org_file)) { + $test_files[] = $org_file[1]; + } else { + $GLOBALS['test_files'] = $test_files; + find_files($IN_REDIRECT['TESTS']); + + foreach ($GLOBALS['test_files'] as $f) { + $test_files[] = array($f, $file); + } + } + $test_cnt += count($test_files) - 1; + $test_idx--; + + show_redirect_start($IN_REDIRECT['TESTS'], $tested, $tested_file); + + // set up environment + $redirenv = array_merge($environment, $IN_REDIRECT['ENV']); + $redirenv['REDIR_TEST_DIR'] = realpath($IN_REDIRECT['TESTS']) . DIRECTORY_SEPARATOR; + + usort($test_files, "test_sort"); + run_all_tests($test_files, $redirenv, $tested); + + show_redirect_ends($IN_REDIRECT['TESTS'], $tested, $tested_file); + + // a redirected test never fails + $IN_REDIRECT = false; + + junit_mark_test_as('PASS', $shortname, $tested); + return 'REDIR'; + + } else { + + $bork_info = "Redirect info must contain exactly one TEST string to be used as redirect directory."; + show_result("BORK", $bork_info, '', $temp_filenames); + $PHP_FAILED_TESTS['BORKED'][] = array( + 'name' => $file, + 'test_name' => '', + 'output' => '', + 'diff' => '', + 'info' => "$bork_info [$file]", + ); + } + } + + if (is_array($org_file) || isset($section_text['REDIRECTTEST'])) { + + if (is_array($org_file)) { + $file = $org_file[0]; + } + + $bork_info = "Redirected test did not contain redirection info"; + show_result("BORK", $bork_info, '', $temp_filenames); + $PHP_FAILED_TESTS['BORKED'][] = array( + 'name' => $file, + 'test_name' => '', + 'output' => '', + 'diff' => '', + 'info' => "$bork_info [$file]", + ); + + junit_mark_test_as('BORK', $shortname, $tested, null, $bork_info); + + return 'BORKED'; + } + + // We've satisfied the preconditions - run the test! + if (isset($section_text['FILE'])) { + show_file_block('php', $section_text['FILE'], 'TEST'); + save_text($test_file, $section_text['FILE'], $temp_file); + } else { + $test_file = $temp_file = ""; + } + + if (array_key_exists('GET', $section_text)) { + $query_string = trim($section_text['GET']); + } else { + $query_string = ''; + } + + $env['REDIRECT_STATUS'] = '1'; + if (empty($env['QUERY_STRING'])) { + $env['QUERY_STRING'] = $query_string; + } + if (empty($env['PATH_TRANSLATED'])) { + $env['PATH_TRANSLATED'] = $test_file; + } + if (empty($env['SCRIPT_FILENAME'])) { + $env['SCRIPT_FILENAME'] = $test_file; + } + + if (array_key_exists('COOKIE', $section_text)) { + $env['HTTP_COOKIE'] = trim($section_text['COOKIE']); + } else { + $env['HTTP_COOKIE'] = ''; + } + + $args = isset($section_text['ARGS']) ? ' -- ' . $section_text['ARGS'] : ''; + + if ($preload && !empty($test_file)) { + save_text($preload_filename, "<?php opcache_compile_file('$test_file');"); + $local_pass_options = $pass_options; + unset($pass_options); + $pass_options = $local_pass_options; + $pass_options .= " -d opcache.preload=" . $preload_filename; + } + + if (array_key_exists('POST_RAW', $section_text) && !empty($section_text['POST_RAW'])) { + + $post = trim($section_text['POST_RAW']); + $raw_lines = explode("\n", $post); + + $request = ''; + $started = false; + + foreach ($raw_lines as $line) { + + if (empty($env['CONTENT_TYPE']) && preg_match('/^Content-Type:(.*)/i', $line, $res)) { + $env['CONTENT_TYPE'] = trim(str_replace("\r", '', $res[1])); + continue; + } + + if ($started) { + $request .= "\n"; + } + + $started = true; + $request .= $line; + } + + $env['CONTENT_LENGTH'] = strlen($request); + $env['REQUEST_METHOD'] = 'POST'; + + if (empty($request)) { + junit_mark_test_as('BORK', $shortname, $tested, null, 'empty $request'); + return 'BORKED'; + } + + save_text($tmp_post, $request); + $cmd = "$php $pass_options $ini_settings -f \"$test_file\"$cmdRedirect < \"$tmp_post\""; + + } elseif (array_key_exists('PUT', $section_text) && !empty($section_text['PUT'])) { + + $post = trim($section_text['PUT']); + $raw_lines = explode("\n", $post); + + $request = ''; + $started = false; + + foreach ($raw_lines as $line) { + + if (empty($env['CONTENT_TYPE']) && preg_match('/^Content-Type:(.*)/i', $line, $res)) { + $env['CONTENT_TYPE'] = trim(str_replace("\r", '', $res[1])); + continue; + } + + if ($started) { + $request .= "\n"; + } + + $started = true; + $request .= $line; + } + + $env['CONTENT_LENGTH'] = strlen($request); + $env['REQUEST_METHOD'] = 'PUT'; + + if (empty($request)) { + junit_mark_test_as('BORK', $shortname, $tested, null, 'empty $request'); + return 'BORKED'; + } + + save_text($tmp_post, $request); + $cmd = "$php $pass_options $ini_settings -f \"$test_file\"$cmdRedirect < \"$tmp_post\""; + + } else if (array_key_exists('POST', $section_text) && !empty($section_text['POST'])) { + + $post = trim($section_text['POST']); + $content_length = strlen($post); + save_text($tmp_post, $post); + + $env['REQUEST_METHOD'] = 'POST'; + if (empty($env['CONTENT_TYPE'])) { + $env['CONTENT_TYPE'] = 'application/x-www-form-urlencoded'; + } + + if (empty($env['CONTENT_LENGTH'])) { + $env['CONTENT_LENGTH'] = $content_length; + } + + $cmd = "$php $pass_options $ini_settings -f \"$test_file\"$cmdRedirect < \"$tmp_post\""; + + } else if (array_key_exists('GZIP_POST', $section_text) && !empty($section_text['GZIP_POST'])) { + + $post = trim($section_text['GZIP_POST']); + $post = gzencode($post, 9, FORCE_GZIP); + $env['HTTP_CONTENT_ENCODING'] = 'gzip'; + + save_text($tmp_post, $post); + $content_length = strlen($post); + + $env['REQUEST_METHOD'] = 'POST'; + $env['CONTENT_TYPE'] = 'application/x-www-form-urlencoded'; + $env['CONTENT_LENGTH'] = $content_length; + + $cmd = "$php $pass_options $ini_settings -f \"$test_file\"$cmdRedirect < \"$tmp_post\""; + + } else if (array_key_exists('DEFLATE_POST', $section_text) && !empty($section_text['DEFLATE_POST'])) { + $post = trim($section_text['DEFLATE_POST']); + $post = gzcompress($post, 9); + $env['HTTP_CONTENT_ENCODING'] = 'deflate'; + save_text($tmp_post, $post); + $content_length = strlen($post); + + $env['REQUEST_METHOD'] = 'POST'; + $env['CONTENT_TYPE'] = 'application/x-www-form-urlencoded'; + $env['CONTENT_LENGTH'] = $content_length; + + $cmd = "$php $pass_options $ini_settings -f \"$test_file\"$cmdRedirect < \"$tmp_post\""; + + } else { + + $env['REQUEST_METHOD'] = 'GET'; + $env['CONTENT_TYPE'] = ''; + $env['CONTENT_LENGTH'] = ''; + + $cmd = "$php $pass_options $ini_settings -f \"$test_file\" $args$cmdRedirect"; + } + + if ($valgrind) { + $env['USE_ZEND_ALLOC'] = '0'; + $env['ZEND_DONT_UNLOAD_MODULES'] = 1; + + $cmd = $valgrind->wrapCommand($cmd, $memcheck_filename, strpos($test_file, "pcre") !== false); + } + + if ($DETAILED) echo " CONTENT_LENGTH = " . $env['CONTENT_LENGTH'] . " CONTENT_TYPE = " . $env['CONTENT_TYPE'] . " PATH_TRANSLATED = " . $env['PATH_TRANSLATED'] . " @@ -2446,578 +2446,578 @@ HTTP_COOKIE = " . $env['HTTP_COOKIE'] . " COMMAND $cmd "; - junit_start_timer($shortname); - $hrtime = hrtime(); - $startTime = $hrtime[0] * 1000000000 + $hrtime[1]; - - $out = system_with_timeout($cmd, $env, $section_text['STDIN'] ?? null, $captureStdIn, $captureStdOut, $captureStdErr); - - junit_finish_timer($shortname); - $hrtime = hrtime(); - $time = $hrtime[0] * 1000000000 + $hrtime[1] - $startTime; - if ($time >= $slow_min_ms * 1000000) { - $PHP_FAILED_TESTS['SLOW'][] = array( - 'name' => $file, - 'test_name' => (is_array($IN_REDIRECT) ? $IN_REDIRECT['via'] : '') . $tested . " [$tested_file]", - 'output' => '', - 'diff' => '', - 'info' => $time / 1000000000, - ); - } - - if (array_key_exists('CLEAN', $section_text) && (!$no_clean || $cfg['keep']['clean'])) { - - if (trim($section_text['CLEAN'])) { - show_file_block('clean', $section_text['CLEAN']); - save_text($test_clean, trim($section_text['CLEAN']), $temp_clean); - - if (!$no_clean) { - $clean_params = array(); - settings2array($ini_overwrites, $clean_params); - $clean_params = settings2params($clean_params); - $extra = substr(PHP_OS, 0, 3) !== "WIN" ? - "unset REQUEST_METHOD; unset QUERY_STRING; unset PATH_TRANSLATED; unset SCRIPT_FILENAME; unset REQUEST_METHOD;" : ""; - system_with_timeout("$extra $php $pass_options $extra_options -q $clean_params $no_file_cache \"$test_clean\"", $env); - } - - if (!$cfg['keep']['clean']) { - @unlink($test_clean); - } - } - } - - @unlink($preload_filename); - - $leaked = false; - $passed = false; - - if ($valgrind) { // leak check - $leaked = filesize($memcheck_filename) > 0; - - if (!$leaked) { - @unlink($memcheck_filename); - } - } - - // Does the output match what is expected? - $output = preg_replace("/\r\n/", "\n", trim($out)); - - /* when using CGI, strip the headers from the output */ - $headers = array(); - - if (!empty($uses_cgi) && preg_match("/^(.*?)\r?\n\r?\n(.*)/s", $out, $match)) { - $output = trim($match[2]); - $rh = preg_split("/[\n\r]+/", $match[1]); - - foreach ($rh as $line) { - if (strpos($line, ':') !== false) { - $line = explode(':', $line, 2); - $headers[trim($line[0])] = trim($line[1]); - } - } - } - - $failed_headers = false; - - if (isset($section_text['EXPECTHEADERS'])) { - $want = array(); - $wanted_headers = array(); - $lines = preg_split("/[\n\r]+/", $section_text['EXPECTHEADERS']); - - foreach ($lines as $line) { - if (strpos($line, ':') !== false) { - $line = explode(':', $line, 2); - $want[trim($line[0])] = trim($line[1]); - $wanted_headers[] = trim($line[0]) . ': ' . trim($line[1]); - } - } - - $output_headers = array(); - - foreach ($want as $k => $v) { - - if (isset($headers[$k])) { - $output_headers[] = $k . ': ' . $headers[$k]; - } - - if (!isset($headers[$k]) || $headers[$k] != $v) { - $failed_headers = true; - } - } - - ksort($wanted_headers); - $wanted_headers = implode("\n", $wanted_headers); - ksort($output_headers); - $output_headers = implode("\n", $output_headers); - } - - show_file_block('out', $output); - - if ($preload) { - $output = trim(preg_replace("/\n?Warning: Can't preload [^\n]*\n?/", "", $output)); - } - - if (isset($section_text['EXPECTF']) || isset($section_text['EXPECTREGEX'])) { - - if (isset($section_text['EXPECTF'])) { - $wanted = trim($section_text['EXPECTF']); - } else { - $wanted = trim($section_text['EXPECTREGEX']); - } - - show_file_block('exp', $wanted); - $wanted_re = preg_replace('/\r\n/', "\n", $wanted); - - if (isset($section_text['EXPECTF'])) { - - // do preg_quote, but miss out any %r delimited sections - $temp = ""; - $r = "%r"; - $startOffset = 0; - $length = strlen($wanted_re); - while ($startOffset < $length) { - $start = strpos($wanted_re, $r, $startOffset); - if ($start !== false) { - // we have found a start tag - $end = strpos($wanted_re, $r, $start + 2); - if ($end === false) { - // unbalanced tag, ignore it. - $end = $start = $length; - } - } else { - // no more %r sections - $start = $end = $length; - } - // quote a non re portion of the string - $temp .= preg_quote(substr($wanted_re, $startOffset, $start - $startOffset), '/'); - // add the re unquoted. - if ($end > $start) { - $temp .= '(' . substr($wanted_re, $start + 2, $end - $start - 2) . ')'; - } - $startOffset = $end + 2; - } - $wanted_re = $temp; - - // Stick to basics - $wanted_re = str_replace('%e', '\\' . DIRECTORY_SEPARATOR, $wanted_re); - $wanted_re = str_replace('%s', '[^\r\n]+', $wanted_re); - $wanted_re = str_replace('%S', '[^\r\n]*', $wanted_re); - $wanted_re = str_replace('%a', '.+', $wanted_re); - $wanted_re = str_replace('%A', '.*', $wanted_re); - $wanted_re = str_replace('%w', '\s*', $wanted_re); - $wanted_re = str_replace('%i', '[+-]?\d+', $wanted_re); - $wanted_re = str_replace('%d', '\d+', $wanted_re); - $wanted_re = str_replace('%x', '[0-9a-fA-F]+', $wanted_re); - $wanted_re = str_replace('%f', '[+-]?\.?\d+\.?\d*(?:[Ee][+-]?\d+)?', $wanted_re); - $wanted_re = str_replace('%c', '.', $wanted_re); - // %f allows two points "-.0.0" but that is the best *simple* expression - } + junit_start_timer($shortname); + $hrtime = hrtime(); + $startTime = $hrtime[0] * 1000000000 + $hrtime[1]; + + $out = system_with_timeout($cmd, $env, $section_text['STDIN'] ?? null, $captureStdIn, $captureStdOut, $captureStdErr); + + junit_finish_timer($shortname); + $hrtime = hrtime(); + $time = $hrtime[0] * 1000000000 + $hrtime[1] - $startTime; + if ($time >= $slow_min_ms * 1000000) { + $PHP_FAILED_TESTS['SLOW'][] = array( + 'name' => $file, + 'test_name' => (is_array($IN_REDIRECT) ? $IN_REDIRECT['via'] : '') . $tested . " [$tested_file]", + 'output' => '', + 'diff' => '', + 'info' => $time / 1000000000, + ); + } + + if (array_key_exists('CLEAN', $section_text) && (!$no_clean || $cfg['keep']['clean'])) { + + if (trim($section_text['CLEAN'])) { + show_file_block('clean', $section_text['CLEAN']); + save_text($test_clean, trim($section_text['CLEAN']), $temp_clean); + + if (!$no_clean) { + $clean_params = array(); + settings2array($ini_overwrites, $clean_params); + $clean_params = settings2params($clean_params); + $extra = substr(PHP_OS, 0, 3) !== "WIN" ? + "unset REQUEST_METHOD; unset QUERY_STRING; unset PATH_TRANSLATED; unset SCRIPT_FILENAME; unset REQUEST_METHOD;" : ""; + system_with_timeout("$extra $php $pass_options $extra_options -q $clean_params $no_file_cache \"$test_clean\"", $env); + } + + if (!$cfg['keep']['clean']) { + @unlink($test_clean); + } + } + } + + @unlink($preload_filename); + + $leaked = false; + $passed = false; + + if ($valgrind) { // leak check + $leaked = filesize($memcheck_filename) > 0; + + if (!$leaked) { + @unlink($memcheck_filename); + } + } + + // Does the output match what is expected? + $output = preg_replace("/\r\n/", "\n", trim($out)); + + /* when using CGI, strip the headers from the output */ + $headers = array(); + + if (!empty($uses_cgi) && preg_match("/^(.*?)\r?\n\r?\n(.*)/s", $out, $match)) { + $output = trim($match[2]); + $rh = preg_split("/[\n\r]+/", $match[1]); + + foreach ($rh as $line) { + if (strpos($line, ':') !== false) { + $line = explode(':', $line, 2); + $headers[trim($line[0])] = trim($line[1]); + } + } + } + + $failed_headers = false; + + if (isset($section_text['EXPECTHEADERS'])) { + $want = array(); + $wanted_headers = array(); + $lines = preg_split("/[\n\r]+/", $section_text['EXPECTHEADERS']); + + foreach ($lines as $line) { + if (strpos($line, ':') !== false) { + $line = explode(':', $line, 2); + $want[trim($line[0])] = trim($line[1]); + $wanted_headers[] = trim($line[0]) . ': ' . trim($line[1]); + } + } + + $output_headers = array(); + + foreach ($want as $k => $v) { + + if (isset($headers[$k])) { + $output_headers[] = $k . ': ' . $headers[$k]; + } + + if (!isset($headers[$k]) || $headers[$k] != $v) { + $failed_headers = true; + } + } + + ksort($wanted_headers); + $wanted_headers = implode("\n", $wanted_headers); + ksort($output_headers); + $output_headers = implode("\n", $output_headers); + } + + show_file_block('out', $output); + + if ($preload) { + $output = trim(preg_replace("/\n?Warning: Can't preload [^\n]*\n?/", "", $output)); + } + + if (isset($section_text['EXPECTF']) || isset($section_text['EXPECTREGEX'])) { + + if (isset($section_text['EXPECTF'])) { + $wanted = trim($section_text['EXPECTF']); + } else { + $wanted = trim($section_text['EXPECTREGEX']); + } + + show_file_block('exp', $wanted); + $wanted_re = preg_replace('/\r\n/', "\n", $wanted); + + if (isset($section_text['EXPECTF'])) { + + // do preg_quote, but miss out any %r delimited sections + $temp = ""; + $r = "%r"; + $startOffset = 0; + $length = strlen($wanted_re); + while ($startOffset < $length) { + $start = strpos($wanted_re, $r, $startOffset); + if ($start !== false) { + // we have found a start tag + $end = strpos($wanted_re, $r, $start + 2); + if ($end === false) { + // unbalanced tag, ignore it. + $end = $start = $length; + } + } else { + // no more %r sections + $start = $end = $length; + } + // quote a non re portion of the string + $temp .= preg_quote(substr($wanted_re, $startOffset, $start - $startOffset), '/'); + // add the re unquoted. + if ($end > $start) { + $temp .= '(' . substr($wanted_re, $start + 2, $end - $start - 2) . ')'; + } + $startOffset = $end + 2; + } + $wanted_re = $temp; + + // Stick to basics + $wanted_re = str_replace('%e', '\\' . DIRECTORY_SEPARATOR, $wanted_re); + $wanted_re = str_replace('%s', '[^\r\n]+', $wanted_re); + $wanted_re = str_replace('%S', '[^\r\n]*', $wanted_re); + $wanted_re = str_replace('%a', '.+', $wanted_re); + $wanted_re = str_replace('%A', '.*', $wanted_re); + $wanted_re = str_replace('%w', '\s*', $wanted_re); + $wanted_re = str_replace('%i', '[+-]?\d+', $wanted_re); + $wanted_re = str_replace('%d', '\d+', $wanted_re); + $wanted_re = str_replace('%x', '[0-9a-fA-F]+', $wanted_re); + $wanted_re = str_replace('%f', '[+-]?\.?\d+\.?\d*(?:[Ee][+-]?\d+)?', $wanted_re); + $wanted_re = str_replace('%c', '.', $wanted_re); + // %f allows two points "-.0.0" but that is the best *simple* expression + } /* DEBUG YOUR REGEX HERE - var_dump($wanted_re); - print(str_repeat('=', 80) . "\n"); - var_dump($output); - */ - if (preg_match("/^$wanted_re\$/s", $output)) { - $passed = true; - if (!$cfg['keep']['php']) { - @unlink($test_file); - } - @unlink($tmp_post); - - if (!$leaked && !$failed_headers) { - if (isset($section_text['XFAIL'])) { - $warn = true; - $info = " (warn: XFAIL section but test passes)"; - } else if (isset($section_text['XLEAK'])) { - $warn = true; - $info = " (warn: XLEAK section but test passes)"; + var_dump($wanted_re); + print(str_repeat('=', 80) . "\n"); + var_dump($output); + */ + if (preg_match("/^$wanted_re\$/s", $output)) { + $passed = true; + if (!$cfg['keep']['php']) { + @unlink($test_file); + } + @unlink($tmp_post); + + if (!$leaked && !$failed_headers) { + if (isset($section_text['XFAIL'])) { + $warn = true; + $info = " (warn: XFAIL section but test passes)"; + } else if (isset($section_text['XLEAK'])) { + $warn = true; + $info = " (warn: XLEAK section but test passes)"; } else { - show_result("PASS", $tested, $tested_file, '', $temp_filenames); - junit_mark_test_as('PASS', $shortname, $tested); - return 'PASSED'; - } - } - } - - } else { - - $wanted = trim($section_text['EXPECT']); - $wanted = preg_replace('/\r\n/', "\n", $wanted); - show_file_block('exp', $wanted); - - // compare and leave on success - if (!strcmp($output, $wanted)) { - $passed = true; - - if (!$cfg['keep']['php']) { - @unlink($test_file); - } - @unlink($tmp_post); - - if (!$leaked && !$failed_headers) { - if (isset($section_text['XFAIL'])) { - $warn = true; - $info = " (warn: XFAIL section but test passes)"; - } elseif (isset($section_text['XLEAK'])) { - $warn = true; - $info = " (warn: XLEAK section but test passes)"; + show_result("PASS", $tested, $tested_file, '', $temp_filenames); + junit_mark_test_as('PASS', $shortname, $tested); + return 'PASSED'; + } + } + } + + } else { + + $wanted = trim($section_text['EXPECT']); + $wanted = preg_replace('/\r\n/', "\n", $wanted); + show_file_block('exp', $wanted); + + // compare and leave on success + if (!strcmp($output, $wanted)) { + $passed = true; + + if (!$cfg['keep']['php']) { + @unlink($test_file); + } + @unlink($tmp_post); + + if (!$leaked && !$failed_headers) { + if (isset($section_text['XFAIL'])) { + $warn = true; + $info = " (warn: XFAIL section but test passes)"; + } elseif (isset($section_text['XLEAK'])) { + $warn = true; + $info = " (warn: XLEAK section but test passes)"; } else { - show_result("PASS", $tested, $tested_file, '', $temp_filenames); - junit_mark_test_as('PASS', $shortname, $tested); - return 'PASSED'; - } - } - } - - $wanted_re = null; - } - - // Test failed so we need to report details. - if ($failed_headers) { - $passed = false; - $wanted = $wanted_headers . "\n--HEADERS--\n" . $wanted; - $output = $output_headers . "\n--HEADERS--\n" . $output; - - if (isset($wanted_re)) { - $wanted_re = preg_quote($wanted_headers . "\n--HEADERS--\n", '/') . $wanted_re; - } - } - - if ($leaked) { + show_result("PASS", $tested, $tested_file, '', $temp_filenames); + junit_mark_test_as('PASS', $shortname, $tested); + return 'PASSED'; + } + } + } + + $wanted_re = null; + } + + // Test failed so we need to report details. + if ($failed_headers) { + $passed = false; + $wanted = $wanted_headers . "\n--HEADERS--\n" . $wanted; + $output = $output_headers . "\n--HEADERS--\n" . $output; + + if (isset($wanted_re)) { + $wanted_re = preg_quote($wanted_headers . "\n--HEADERS--\n", '/') . $wanted_re; + } + } + + if ($leaked) { $restype[] = isset($section_text['XLEAK']) ? 'XLEAK' : 'LEAK'; - } + } - if ($warn) { - $restype[] = 'WARN'; - } + if ($warn) { + $restype[] = 'WARN'; + } - if (!$passed) { - if (isset($section_text['XFAIL'])) { - $restype[] = 'XFAIL'; - $info = ' XFAIL REASON: ' . rtrim($section_text['XFAIL']); - } else if (isset($section_text['XLEAK'])) { + if (!$passed) { + if (isset($section_text['XFAIL'])) { + $restype[] = 'XFAIL'; + $info = ' XFAIL REASON: ' . rtrim($section_text['XFAIL']); + } else if (isset($section_text['XLEAK'])) { $restype[] = 'XLEAK'; - $info = ' XLEAK REASON: ' . rtrim($section_text['XLEAK']); + $info = ' XLEAK REASON: ' . rtrim($section_text['XLEAK']); } else { - $restype[] = 'FAIL'; - } - } - - if (!$passed) { - - // write .exp - if (strpos($log_format, 'E') !== false && file_put_contents($exp_filename, $wanted, FILE_BINARY) === false) { - error("Cannot create expected test output - $exp_filename"); - } - - // write .out - if (strpos($log_format, 'O') !== false && file_put_contents($output_filename, $output, FILE_BINARY) === false) { - error("Cannot create test output - $output_filename"); - } - - // write .diff - $diff = generate_diff($wanted, $wanted_re, $output); - if (is_array($IN_REDIRECT)) { - $orig_shortname = str_replace(TEST_PHP_SRCDIR . '/', '', $file); - $diff = "# original source file: $orig_shortname\n" . $diff; - } - show_file_block('diff', $diff); - if (strpos($log_format, 'D') !== false && file_put_contents($diff_filename, $diff, FILE_BINARY) === false) { - error("Cannot create test diff - $diff_filename"); - } - - // write .sh - if (strpos($log_format, 'S') !== false && file_put_contents($sh_filename, "#!/bin/sh + $restype[] = 'FAIL'; + } + } + + if (!$passed) { + + // write .exp + if (strpos($log_format, 'E') !== false && file_put_contents($exp_filename, $wanted, FILE_BINARY) === false) { + error("Cannot create expected test output - $exp_filename"); + } + + // write .out + if (strpos($log_format, 'O') !== false && file_put_contents($output_filename, $output, FILE_BINARY) === false) { + error("Cannot create test output - $output_filename"); + } + + // write .diff + $diff = generate_diff($wanted, $wanted_re, $output); + if (is_array($IN_REDIRECT)) { + $orig_shortname = str_replace(TEST_PHP_SRCDIR . '/', '', $file); + $diff = "# original source file: $orig_shortname\n" . $diff; + } + show_file_block('diff', $diff); + if (strpos($log_format, 'D') !== false && file_put_contents($diff_filename, $diff, FILE_BINARY) === false) { + error("Cannot create test diff - $diff_filename"); + } + + // write .sh + if (strpos($log_format, 'S') !== false && file_put_contents($sh_filename, "#!/bin/sh {$cmd} ", FILE_BINARY) === false) { - error("Cannot create test shell script - $sh_filename"); - } - chmod($sh_filename, 0755); + error("Cannot create test shell script - $sh_filename"); + } + chmod($sh_filename, 0755); - // write .log - if (strpos($log_format, 'L') !== false && file_put_contents($log_filename, " + // write .log + if (strpos($log_format, 'L') !== false && file_put_contents($log_filename, " ---- EXPECTED OUTPUT $wanted ---- ACTUAL OUTPUT $output ---- FAILED ", FILE_BINARY) === false) { - error("Cannot create test log - $log_filename"); - error_report($file, $log_filename, $tested); - } - } + error("Cannot create test log - $log_filename"); + error_report($file, $log_filename, $tested); + } + } - if ($valgrind && $leaked && $cfg["show"]["mem"]) { - show_file_block('mem', file_get_contents($memcheck_filename)); - } + if ($valgrind && $leaked && $cfg["show"]["mem"]) { + show_file_block('mem', file_get_contents($memcheck_filename)); + } - show_result(implode('&', $restype), $tested, $tested_file, $info, $temp_filenames); + show_result(implode('&', $restype), $tested, $tested_file, $info, $temp_filenames); - foreach ($restype as $type) { - $PHP_FAILED_TESTS[$type . 'ED'][] = array( - 'name' => $file, - 'test_name' => (is_array($IN_REDIRECT) ? $IN_REDIRECT['via'] : '') . $tested . " [$tested_file]", - 'output' => $output_filename, - 'diff' => $diff_filename, - 'info' => $info, - ); - } + foreach ($restype as $type) { + $PHP_FAILED_TESTS[$type . 'ED'][] = array( + 'name' => $file, + 'test_name' => (is_array($IN_REDIRECT) ? $IN_REDIRECT['via'] : '') . $tested . " [$tested_file]", + 'output' => $output_filename, + 'diff' => $diff_filename, + 'info' => $info, + ); + } - $diff = empty($diff) ? '' : preg_replace('/\e/', '<esc>', $diff); + $diff = empty($diff) ? '' : preg_replace('/\e/', '<esc>', $diff); - junit_mark_test_as($restype, $shortname, $tested, null, $info, $diff); + junit_mark_test_as($restype, $shortname, $tested, null, $info, $diff); - return $restype[0] . 'ED'; + return $restype[0] . 'ED'; } function comp_line($l1, $l2, $is_reg) { - if ($is_reg) { - return preg_match('/^' . $l1 . '$/s', $l2); - } else { - return !strcmp($l1, $l2); - } + if ($is_reg) { + return preg_match('/^' . $l1 . '$/s', $l2); + } else { + return !strcmp($l1, $l2); + } } function count_array_diff($ar1, $ar2, $is_reg, $w, $idx1, $idx2, $cnt1, $cnt2, $steps) { - $equal = 0; - - while ($idx1 < $cnt1 && $idx2 < $cnt2 && comp_line($ar1[$idx1], $ar2[$idx2], $is_reg)) { - $idx1++; - $idx2++; - $equal++; - $steps--; - } - if (--$steps > 0) { - $eq1 = 0; - $st = $steps / 2; - - for ($ofs1 = $idx1 + 1; $ofs1 < $cnt1 && $st-- > 0; $ofs1++) { - $eq = @count_array_diff($ar1, $ar2, $is_reg, $w, $ofs1, $idx2, $cnt1, $cnt2, $st); - - if ($eq > $eq1) { - $eq1 = $eq; - } - } - - $eq2 = 0; - $st = $steps; - - for ($ofs2 = $idx2 + 1; $ofs2 < $cnt2 && $st-- > 0; $ofs2++) { - $eq = @count_array_diff($ar1, $ar2, $is_reg, $w, $idx1, $ofs2, $cnt1, $cnt2, $st); - if ($eq > $eq2) { - $eq2 = $eq; - } - } - - if ($eq1 > $eq2) { - $equal += $eq1; - } else if ($eq2 > 0) { - $equal += $eq2; - } - } - - return $equal; + $equal = 0; + + while ($idx1 < $cnt1 && $idx2 < $cnt2 && comp_line($ar1[$idx1], $ar2[$idx2], $is_reg)) { + $idx1++; + $idx2++; + $equal++; + $steps--; + } + if (--$steps > 0) { + $eq1 = 0; + $st = $steps / 2; + + for ($ofs1 = $idx1 + 1; $ofs1 < $cnt1 && $st-- > 0; $ofs1++) { + $eq = @count_array_diff($ar1, $ar2, $is_reg, $w, $ofs1, $idx2, $cnt1, $cnt2, $st); + + if ($eq > $eq1) { + $eq1 = $eq; + } + } + + $eq2 = 0; + $st = $steps; + + for ($ofs2 = $idx2 + 1; $ofs2 < $cnt2 && $st-- > 0; $ofs2++) { + $eq = @count_array_diff($ar1, $ar2, $is_reg, $w, $idx1, $ofs2, $cnt1, $cnt2, $st); + if ($eq > $eq2) { + $eq2 = $eq; + } + } + + if ($eq1 > $eq2) { + $equal += $eq1; + } else if ($eq2 > 0) { + $equal += $eq2; + } + } + + return $equal; } function generate_array_diff($ar1, $ar2, $is_reg, $w) { - $idx1 = 0; - $cnt1 = @count($ar1); - $idx2 = 0; - $cnt2 = @count($ar2); - $diff = array(); - $old1 = array(); - $old2 = array(); - - while ($idx1 < $cnt1 && $idx2 < $cnt2) { - - if (comp_line($ar1[$idx1], $ar2[$idx2], $is_reg)) { - $idx1++; - $idx2++; - continue; - } else { - - $c1 = @count_array_diff($ar1, $ar2, $is_reg, $w, $idx1 + 1, $idx2, $cnt1, $cnt2, 10); - $c2 = @count_array_diff($ar1, $ar2, $is_reg, $w, $idx1, $idx2 + 1, $cnt1, $cnt2, 10); - - if ($c1 > $c2) { - $old1[$idx1] = sprintf("%03d- ", $idx1 + 1) . $w[$idx1++]; - } else if ($c2 > 0) { - $old2[$idx2] = sprintf("%03d+ ", $idx2 + 1) . $ar2[$idx2++]; - } else { - $old1[$idx1] = sprintf("%03d- ", $idx1 + 1) . $w[$idx1++]; - $old2[$idx2] = sprintf("%03d+ ", $idx2 + 1) . $ar2[$idx2++]; - } - } - } - - reset($old1); - $k1 = key($old1); - $l1 = -2; - reset($old2); - $k2 = key($old2); - $l2 = -2; - - while ($k1 !== null || $k2 !== null) { - - if ($k1 == $l1 + 1 || $k2 === null) { - $l1 = $k1; - $diff[] = current($old1); - $k1 = next($old1) ? key($old1) : null; - } else if ($k2 == $l2 + 1 || $k1 === null) { - $l2 = $k2; - $diff[] = current($old2); - $k2 = next($old2) ? key($old2) : null; - } else if ($k1 < $k2) { - $l1 = $k1; - $diff[] = current($old1); - $k1 = next($old1) ? key($old1) : null; - } else { - $l2 = $k2; - $diff[] = current($old2); - $k2 = next($old2) ? key($old2) : null; - } - } - - while ($idx1 < $cnt1) { - $diff[] = sprintf("%03d- ", $idx1 + 1) . $w[$idx1++]; - } - - while ($idx2 < $cnt2) { - $diff[] = sprintf("%03d+ ", $idx2 + 1) . $ar2[$idx2++]; - } - - return $diff; + $idx1 = 0; + $cnt1 = @count($ar1); + $idx2 = 0; + $cnt2 = @count($ar2); + $diff = array(); + $old1 = array(); + $old2 = array(); + + while ($idx1 < $cnt1 && $idx2 < $cnt2) { + + if (comp_line($ar1[$idx1], $ar2[$idx2], $is_reg)) { + $idx1++; + $idx2++; + continue; + } else { + + $c1 = @count_array_diff($ar1, $ar2, $is_reg, $w, $idx1 + 1, $idx2, $cnt1, $cnt2, 10); + $c2 = @count_array_diff($ar1, $ar2, $is_reg, $w, $idx1, $idx2 + 1, $cnt1, $cnt2, 10); + + if ($c1 > $c2) { + $old1[$idx1] = sprintf("%03d- ", $idx1 + 1) . $w[$idx1++]; + } else if ($c2 > 0) { + $old2[$idx2] = sprintf("%03d+ ", $idx2 + 1) . $ar2[$idx2++]; + } else { + $old1[$idx1] = sprintf("%03d- ", $idx1 + 1) . $w[$idx1++]; + $old2[$idx2] = sprintf("%03d+ ", $idx2 + 1) . $ar2[$idx2++]; + } + } + } + + reset($old1); + $k1 = key($old1); + $l1 = -2; + reset($old2); + $k2 = key($old2); + $l2 = -2; + + while ($k1 !== null || $k2 !== null) { + + if ($k1 == $l1 + 1 || $k2 === null) { + $l1 = $k1; + $diff[] = current($old1); + $k1 = next($old1) ? key($old1) : null; + } else if ($k2 == $l2 + 1 || $k1 === null) { + $l2 = $k2; + $diff[] = current($old2); + $k2 = next($old2) ? key($old2) : null; + } else if ($k1 < $k2) { + $l1 = $k1; + $diff[] = current($old1); + $k1 = next($old1) ? key($old1) : null; + } else { + $l2 = $k2; + $diff[] = current($old2); + $k2 = next($old2) ? key($old2) : null; + } + } + + while ($idx1 < $cnt1) { + $diff[] = sprintf("%03d- ", $idx1 + 1) . $w[$idx1++]; + } + + while ($idx2 < $cnt2) { + $diff[] = sprintf("%03d+ ", $idx2 + 1) . $ar2[$idx2++]; + } + + return $diff; } function generate_diff($wanted, $wanted_re, $output) { - $w = explode("\n", $wanted); - $o = explode("\n", $output); - $r = is_null($wanted_re) ? $w : explode("\n", $wanted_re); - $diff = generate_array_diff($r, $o, !is_null($wanted_re), $w); + $w = explode("\n", $wanted); + $o = explode("\n", $output); + $r = is_null($wanted_re) ? $w : explode("\n", $wanted_re); + $diff = generate_array_diff($r, $o, !is_null($wanted_re), $w); - return implode(PHP_EOL, $diff); + return implode(PHP_EOL, $diff); } function error($message) { - echo "ERROR: {$message}\n"; - exit(1); + echo "ERROR: {$message}\n"; + exit(1); } function settings2array($settings, &$ini_settings) { - foreach ($settings as $setting) { + foreach ($settings as $setting) { - if (strpos($setting, '=') !== false) { - $setting = explode("=", $setting, 2); - $name = trim($setting[0]); - $value = trim($setting[1]); + if (strpos($setting, '=') !== false) { + $setting = explode("=", $setting, 2); + $name = trim($setting[0]); + $value = trim($setting[1]); - if ($name == 'extension' || $name == 'zend_extension') { + if ($name == 'extension' || $name == 'zend_extension') { - if (!isset($ini_settings[$name])) { - $ini_settings[$name] = array(); - } + if (!isset($ini_settings[$name])) { + $ini_settings[$name] = array(); + } - $ini_settings[$name][] = $value; + $ini_settings[$name][] = $value; - } else { - $ini_settings[$name] = $value; - } - } - } + } else { + $ini_settings[$name] = $value; + } + } + } } function settings2params($ini_settings) { - $settings = ''; - - foreach($ini_settings as $name => $value) { - - if (is_array($value)) { - foreach($value as $val) { - $val = addslashes($val); - $settings .= " -d \"$name=$val\""; - } - } else { - if (substr(PHP_OS, 0, 3) == "WIN" && !empty($value) && $value[0] == '"') { - $len = strlen($value); - - if ($value[$len - 1] == '"') { - $value[0] = "'"; - $value[$len - 1] = "'"; - } - } else { - $value = addslashes($value); - } - - $settings .= " -d \"$name=$value\""; - } - } - - return $settings; + $settings = ''; + + foreach($ini_settings as $name => $value) { + + if (is_array($value)) { + foreach($value as $val) { + $val = addslashes($val); + $settings .= " -d \"$name=$val\""; + } + } else { + if (substr(PHP_OS, 0, 3) == "WIN" && !empty($value) && $value[0] == '"') { + $len = strlen($value); + + if ($value[$len - 1] == '"') { + $value[0] = "'"; + $value[$len - 1] = "'"; + } + } else { + $value = addslashes($value); + } + + $settings .= " -d \"$name=$value\""; + } + } + + return $settings; } function compute_summary() { - global $n_total, $test_results, $ignored_by_ext, $sum_results, $percent_results; - - $n_total = count($test_results); - $n_total += $ignored_by_ext; - $sum_results = array( - 'PASSED' => 0, - 'WARNED' => 0, - 'SKIPPED' => 0, - 'FAILED' => 0, - 'BORKED' => 0, - 'LEAKED' => 0, - 'XFAILED' => 0, - 'XLEAKED' => 0 - ); - - foreach ($test_results as $v) { - $sum_results[$v]++; - } - - $sum_results['SKIPPED'] += $ignored_by_ext; - $percent_results = array(); - - foreach ($sum_results as $v => $n) { - $percent_results[$v] = (100.0 * $n) / $n_total; - } + global $n_total, $test_results, $ignored_by_ext, $sum_results, $percent_results; + + $n_total = count($test_results); + $n_total += $ignored_by_ext; + $sum_results = array( + 'PASSED' => 0, + 'WARNED' => 0, + 'SKIPPED' => 0, + 'FAILED' => 0, + 'BORKED' => 0, + 'LEAKED' => 0, + 'XFAILED' => 0, + 'XLEAKED' => 0 + ); + + foreach ($test_results as $v) { + $sum_results[$v]++; + } + + $sum_results['SKIPPED'] += $ignored_by_ext; + $percent_results = array(); + + foreach ($sum_results as $v => $n) { + $percent_results[$v] = (100.0 * $n) / $n_total; + } } function get_summary($show_ext_summary, $show_html) { - global $exts_skipped, $exts_tested, $n_total, $sum_results, $percent_results, $end_time, $start_time, $failed_test_summary, $PHP_FAILED_TESTS, $valgrind; - - $x_total = $n_total - $sum_results['SKIPPED'] - $sum_results['BORKED']; - - if ($x_total) { - $x_warned = (100.0 * $sum_results['WARNED']) / $x_total; - $x_failed = (100.0 * $sum_results['FAILED']) / $x_total; - $x_xfailed = (100.0 * $sum_results['XFAILED']) / $x_total; - $x_xleaked = (100.0 * $sum_results['XLEAKED']) / $x_total; - $x_leaked = (100.0 * $sum_results['LEAKED']) / $x_total; - $x_passed = (100.0 * $sum_results['PASSED']) / $x_total; - } else { - $x_warned = $x_failed = $x_passed = $x_leaked = $x_xfailed = $x_xleaked = 0; - } + global $exts_skipped, $exts_tested, $n_total, $sum_results, $percent_results, $end_time, $start_time, $failed_test_summary, $PHP_FAILED_TESTS, $valgrind; + + $x_total = $n_total - $sum_results['SKIPPED'] - $sum_results['BORKED']; + + if ($x_total) { + $x_warned = (100.0 * $sum_results['WARNED']) / $x_total; + $x_failed = (100.0 * $sum_results['FAILED']) / $x_total; + $x_xfailed = (100.0 * $sum_results['XFAILED']) / $x_total; + $x_xleaked = (100.0 * $sum_results['XLEAKED']) / $x_total; + $x_leaked = (100.0 * $sum_results['LEAKED']) / $x_total; + $x_passed = (100.0 * $sum_results['PASSED']) / $x_total; + } else { + $x_warned = $x_failed = $x_passed = $x_leaked = $x_xfailed = $x_xleaked = 0; + } - $summary = ''; + $summary = ''; - if ($show_html) { - $summary .= "<pre>\n"; - } + if ($show_html) { + $summary .= "<pre>\n"; + } - if ($show_ext_summary) { - $summary .= ' + if ($show_ext_summary) { + $summary .= ' ===================================================================== TEST RESULT SUMMARY --------------------------------------------------------------------- @@ -3025,17 +3025,17 @@ Exts skipped : ' . sprintf('%4d', $exts_skipped) . ' Exts tested : ' . sprintf('%4d', $exts_tested) . ' --------------------------------------------------------------------- '; - } + } - $summary .= ' + $summary .= ' Number of tests : ' . sprintf('%4d', $n_total) . ' ' . sprintf('%8d', $x_total); - if ($sum_results['BORKED']) { - $summary .= ' + if ($sum_results['BORKED']) { + $summary .= ' Tests borked : ' . sprintf('%4d (%5.1f%%)', $sum_results['BORKED'], $percent_results['BORKED']) . ' --------'; - } + } - $summary .= ' + $summary .= ' Tests skipped : ' . sprintf('%4d (%5.1f%%)', $sum_results['SKIPPED'], $percent_results['SKIPPED']) . ' -------- Tests warned : ' . sprintf('%4d (%5.1f%%)', $sum_results['WARNED'], $percent_results['WARNED']) . ' ' . sprintf('(%5.1f%%)', $x_warned) . ' Tests failed : ' . sprintf('%4d (%5.1f%%)', $sum_results['FAILED'], $percent_results['FAILED']) . ' ' . sprintf('(%5.1f%%)', $x_failed); @@ -3045,357 +3045,357 @@ Tests failed : ' . sprintf('%4d (%5.1f%%)', $sum_results['FAILED'], $percent_ Expected fail : ' . sprintf('%4d (%5.1f%%)', $sum_results['XFAILED'], $percent_results['XFAILED']) . ' ' . sprintf('(%5.1f%%)', $x_xfailed); } - if ($valgrind) { - $summary .= ' + if ($valgrind) { + $summary .= ' Tests leaked : ' . sprintf('%4d (%5.1f%%)', $sum_results['LEAKED'], $percent_results['LEAKED']) . ' ' . sprintf('(%5.1f%%)', $x_leaked); if ($sum_results['XLEAKED']) { $summary .= ' Expected leak : ' . sprintf('%4d (%5.1f%%)', $sum_results['XLEAKED'], $percent_results['XLEAKED']) . ' ' . sprintf('(%5.1f%%)', $x_xleaked); } - } + } - $summary .= ' + $summary .= ' Tests passed : ' . sprintf('%4d (%5.1f%%)', $sum_results['PASSED'], $percent_results['PASSED']) . ' ' . sprintf('(%5.1f%%)', $x_passed) . ' --------------------------------------------------------------------- Time taken : ' . sprintf('%4d seconds', $end_time - $start_time) . ' ===================================================================== '; - $failed_test_summary = ''; + $failed_test_summary = ''; - if (count($PHP_FAILED_TESTS['SLOW'])) { - usort($PHP_FAILED_TESTS['SLOW'], function ($a, $b) { - return $a['info'] < $b['info'] ? 1 : -1; - }); + if (count($PHP_FAILED_TESTS['SLOW'])) { + usort($PHP_FAILED_TESTS['SLOW'], function ($a, $b) { + return $a['info'] < $b['info'] ? 1 : -1; + }); - $failed_test_summary .= ' + $failed_test_summary .= ' ===================================================================== SLOW TEST SUMMARY --------------------------------------------------------------------- '; - foreach ($PHP_FAILED_TESTS['SLOW'] as $failed_test_data) { - $failed_test_summary .= sprintf('(%.3f s) ', $failed_test_data['info']) . $failed_test_data['test_name'] . "\n"; - } - $failed_test_summary .= "=====================================================================\n"; - } - - if (count($PHP_FAILED_TESTS['XFAILED'])) { - $failed_test_summary .= ' + foreach ($PHP_FAILED_TESTS['SLOW'] as $failed_test_data) { + $failed_test_summary .= sprintf('(%.3f s) ', $failed_test_data['info']) . $failed_test_data['test_name'] . "\n"; + } + $failed_test_summary .= "=====================================================================\n"; + } + + if (count($PHP_FAILED_TESTS['XFAILED'])) { + $failed_test_summary .= ' ===================================================================== EXPECTED FAILED TEST SUMMARY --------------------------------------------------------------------- '; - foreach ($PHP_FAILED_TESTS['XFAILED'] as $failed_test_data) { - $failed_test_summary .= $failed_test_data['test_name'] . $failed_test_data['info'] . "\n"; - } - $failed_test_summary .= "=====================================================================\n"; - } - - if (count($PHP_FAILED_TESTS['BORKED'])) { - $failed_test_summary .= ' + foreach ($PHP_FAILED_TESTS['XFAILED'] as $failed_test_data) { + $failed_test_summary .= $failed_test_data['test_name'] . $failed_test_data['info'] . "\n"; + } + $failed_test_summary .= "=====================================================================\n"; + } + + if (count($PHP_FAILED_TESTS['BORKED'])) { + $failed_test_summary .= ' ===================================================================== BORKED TEST SUMMARY --------------------------------------------------------------------- '; - foreach ($PHP_FAILED_TESTS['BORKED'] as $failed_test_data) { - $failed_test_summary .= $failed_test_data['info'] . "\n"; - } + foreach ($PHP_FAILED_TESTS['BORKED'] as $failed_test_data) { + $failed_test_summary .= $failed_test_data['info'] . "\n"; + } - $failed_test_summary .= "=====================================================================\n"; - } + $failed_test_summary .= "=====================================================================\n"; + } - if (count($PHP_FAILED_TESTS['FAILED'])) { - $failed_test_summary .= ' + if (count($PHP_FAILED_TESTS['FAILED'])) { + $failed_test_summary .= ' ===================================================================== FAILED TEST SUMMARY --------------------------------------------------------------------- '; - foreach ($PHP_FAILED_TESTS['FAILED'] as $failed_test_data) { - $failed_test_summary .= $failed_test_data['test_name'] . $failed_test_data['info'] . "\n"; - } - $failed_test_summary .= "=====================================================================\n"; - } - if (count($PHP_FAILED_TESTS['WARNED'])) { - $failed_test_summary .= ' + foreach ($PHP_FAILED_TESTS['FAILED'] as $failed_test_data) { + $failed_test_summary .= $failed_test_data['test_name'] . $failed_test_data['info'] . "\n"; + } + $failed_test_summary .= "=====================================================================\n"; + } + if (count($PHP_FAILED_TESTS['WARNED'])) { + $failed_test_summary .= ' ===================================================================== WARNED TEST SUMMARY --------------------------------------------------------------------- '; - foreach ($PHP_FAILED_TESTS['WARNED'] as $failed_test_data) { - $failed_test_summary .= $failed_test_data['test_name'] . $failed_test_data['info'] . "\n"; - } + foreach ($PHP_FAILED_TESTS['WARNED'] as $failed_test_data) { + $failed_test_summary .= $failed_test_data['test_name'] . $failed_test_data['info'] . "\n"; + } - $failed_test_summary .= "=====================================================================\n"; - } + $failed_test_summary .= "=====================================================================\n"; + } - if (count($PHP_FAILED_TESTS['LEAKED'])) { - $failed_test_summary .= ' + if (count($PHP_FAILED_TESTS['LEAKED'])) { + $failed_test_summary .= ' ===================================================================== LEAKED TEST SUMMARY --------------------------------------------------------------------- '; - foreach ($PHP_FAILED_TESTS['LEAKED'] as $failed_test_data) { - $failed_test_summary .= $failed_test_data['test_name'] . $failed_test_data['info'] . "\n"; - } + foreach ($PHP_FAILED_TESTS['LEAKED'] as $failed_test_data) { + $failed_test_summary .= $failed_test_data['test_name'] . $failed_test_data['info'] . "\n"; + } - $failed_test_summary .= "=====================================================================\n"; - } + $failed_test_summary .= "=====================================================================\n"; + } - if (count($PHP_FAILED_TESTS['XLEAKED'])) { - $failed_test_summary .= ' + if (count($PHP_FAILED_TESTS['XLEAKED'])) { + $failed_test_summary .= ' ===================================================================== EXPECTED LEAK TEST SUMMARY --------------------------------------------------------------------- '; - foreach ($PHP_FAILED_TESTS['XLEAKED'] as $failed_test_data) { - $failed_test_summary .= $failed_test_data['test_name'] . $failed_test_data['info'] . "\n"; - } + foreach ($PHP_FAILED_TESTS['XLEAKED'] as $failed_test_data) { + $failed_test_summary .= $failed_test_data['test_name'] . $failed_test_data['info'] . "\n"; + } - $failed_test_summary .= "=====================================================================\n"; - } + $failed_test_summary .= "=====================================================================\n"; + } - if ($failed_test_summary && !getenv('NO_PHPTEST_SUMMARY')) { - $summary .= $failed_test_summary; - } + if ($failed_test_summary && !getenv('NO_PHPTEST_SUMMARY')) { + $summary .= $failed_test_summary; + } - if ($show_html) { - $summary .= "</pre>"; - } + if ($show_html) { + $summary .= "</pre>"; + } - return $summary; + return $summary; } function show_start($start_time) { - global $html_output, $html_file; + global $html_output, $html_file; - if ($html_output) { - fwrite($html_file, "<h2>Time Start: " . date('Y-m-d H:i:s', $start_time) . "</h2>\n"); - fwrite($html_file, "<table>\n"); - } + if ($html_output) { + fwrite($html_file, "<h2>Time Start: " . date('Y-m-d H:i:s', $start_time) . "</h2>\n"); + fwrite($html_file, "<table>\n"); + } - echo "TIME START " . date('Y-m-d H:i:s', $start_time) . "\n=====================================================================\n"; + echo "TIME START " . date('Y-m-d H:i:s', $start_time) . "\n=====================================================================\n"; } function show_end($end_time) { - global $html_output, $html_file; + global $html_output, $html_file; - if ($html_output) { - fwrite($html_file, "</table>\n"); - fwrite($html_file, "<h2>Time End: " . date('Y-m-d H:i:s', $end_time) . "</h2>\n"); - } + if ($html_output) { + fwrite($html_file, "</table>\n"); + fwrite($html_file, "<h2>Time End: " . date('Y-m-d H:i:s', $end_time) . "</h2>\n"); + } - echo "=====================================================================\nTIME END " . date('Y-m-d H:i:s', $end_time) . "\n"; + echo "=====================================================================\nTIME END " . date('Y-m-d H:i:s', $end_time) . "\n"; } function show_summary() { - global $html_output, $html_file; + global $html_output, $html_file; - if ($html_output) { - fwrite($html_file, "<hr/>\n" . get_summary(true, true)); - } + if ($html_output) { + fwrite($html_file, "<hr/>\n" . get_summary(true, true)); + } - echo get_summary(true, false); + echo get_summary(true, false); } function show_redirect_start($tests, $tested, $tested_file) { - global $html_output, $html_file, $line_length, $SHOW_ONLY_GROUPS; + global $html_output, $html_file, $line_length, $SHOW_ONLY_GROUPS; - if ($html_output) { - fwrite($html_file, "<tr><td colspan='3'>---> $tests ($tested [$tested_file]) begin</td></tr>\n"); - } + if ($html_output) { + fwrite($html_file, "<tr><td colspan='3'>---> $tests ($tested [$tested_file]) begin</td></tr>\n"); + } - if (!$SHOW_ONLY_GROUPS || in_array('REDIRECT', $SHOW_ONLY_GROUPS)) { - echo "REDIRECT $tests ($tested [$tested_file]) begin\n"; - } else { - clear_show_test(); - } + if (!$SHOW_ONLY_GROUPS || in_array('REDIRECT', $SHOW_ONLY_GROUPS)) { + echo "REDIRECT $tests ($tested [$tested_file]) begin\n"; + } else { + clear_show_test(); + } } function show_redirect_ends($tests, $tested, $tested_file) { - global $html_output, $html_file, $line_length, $SHOW_ONLY_GROUPS; + global $html_output, $html_file, $line_length, $SHOW_ONLY_GROUPS; - if ($html_output) { - fwrite($html_file, "<tr><td colspan='3'>---> $tests ($tested [$tested_file]) done</td></tr>\n"); - } + if ($html_output) { + fwrite($html_file, "<tr><td colspan='3'>---> $tests ($tested [$tested_file]) done</td></tr>\n"); + } - if (!$SHOW_ONLY_GROUPS || in_array('REDIRECT', $SHOW_ONLY_GROUPS)) { - echo "REDIRECT $tests ($tested [$tested_file]) done\n"; - } else { - clear_show_test(); - } + if (!$SHOW_ONLY_GROUPS || in_array('REDIRECT', $SHOW_ONLY_GROUPS)) { + echo "REDIRECT $tests ($tested [$tested_file]) done\n"; + } else { + clear_show_test(); + } } function show_test($test_idx, $shortname) { - global $test_cnt; - global $line_length; + global $test_cnt; + global $line_length; - $str = "TEST $test_idx/$test_cnt [$shortname]\r"; - $line_length = strlen($str); - echo $str; - flush(); + $str = "TEST $test_idx/$test_cnt [$shortname]\r"; + $line_length = strlen($str); + echo $str; + flush(); } function clear_show_test() { - global $line_length; - // Parallel testing - global $workerID; - - if (!$workerID) { - // Write over the last line to avoid random trailing chars on next echo - echo str_repeat(" ", $line_length), "\r"; - } + global $line_length; + // Parallel testing + global $workerID; + + if (!$workerID) { + // Write over the last line to avoid random trailing chars on next echo + echo str_repeat(" ", $line_length), "\r"; + } } function parse_conflicts(string $text) : array { - // Strip comments - $text = preg_replace('/#.*/', '', $text); - return array_map('trim', explode("\n", trim($text))); + // Strip comments + $text = preg_replace('/#.*/', '', $text); + return array_map('trim', explode("\n", trim($text))); } function show_result($result, $tested, $tested_file, $extra = '', $temp_filenames = null) { - global $html_output, $html_file, $temp_target, $temp_urlbase, $line_length, $SHOW_ONLY_GROUPS; - - if (!$SHOW_ONLY_GROUPS || in_array($result, $SHOW_ONLY_GROUPS)) { - echo "$result $tested [$tested_file] $extra\n"; - } else if (!$SHOW_ONLY_GROUPS) { - clear_show_test(); - } - - if ($html_output) { - - if (isset($temp_filenames['file']) && file_exists($temp_filenames['file'])) { - $url = str_replace($temp_target, $temp_urlbase, $temp_filenames['file']); - $tested = "<a href='$url'>$tested</a>"; - } - - if (isset($temp_filenames['skip']) && file_exists($temp_filenames['skip'])) { - - if (empty($extra)) { - $extra = "skipif"; - } - - $url = str_replace($temp_target, $temp_urlbase, $temp_filenames['skip']); - $extra = "<a href='$url'>$extra</a>"; - - } else if (empty($extra)) { - $extra = " "; - } - - if (isset($temp_filenames['diff']) && file_exists($temp_filenames['diff'])) { - $url = str_replace($temp_target, $temp_urlbase, $temp_filenames['diff']); - $diff = "<a href='$url'>diff</a>"; - } else { - $diff = " "; - } - - if (isset($temp_filenames['mem']) && file_exists($temp_filenames['mem'])) { - $url = str_replace($temp_target, $temp_urlbase, $temp_filenames['mem']); - $mem = "<a href='$url'>leaks</a>"; - } else { - $mem = " "; - } - - fwrite( - $html_file, - "<tr>" . - "<td>$result</td>" . - "<td>$tested</td>" . - "<td>$extra</td>" . - "<td>$diff</td>" . - "<td>$mem</td>" . - "</tr>\n" - ); - } + global $html_output, $html_file, $temp_target, $temp_urlbase, $line_length, $SHOW_ONLY_GROUPS; + + if (!$SHOW_ONLY_GROUPS || in_array($result, $SHOW_ONLY_GROUPS)) { + echo "$result $tested [$tested_file] $extra\n"; + } else if (!$SHOW_ONLY_GROUPS) { + clear_show_test(); + } + + if ($html_output) { + + if (isset($temp_filenames['file']) && file_exists($temp_filenames['file'])) { + $url = str_replace($temp_target, $temp_urlbase, $temp_filenames['file']); + $tested = "<a href='$url'>$tested</a>"; + } + + if (isset($temp_filenames['skip']) && file_exists($temp_filenames['skip'])) { + + if (empty($extra)) { + $extra = "skipif"; + } + + $url = str_replace($temp_target, $temp_urlbase, $temp_filenames['skip']); + $extra = "<a href='$url'>$extra</a>"; + + } else if (empty($extra)) { + $extra = " "; + } + + if (isset($temp_filenames['diff']) && file_exists($temp_filenames['diff'])) { + $url = str_replace($temp_target, $temp_urlbase, $temp_filenames['diff']); + $diff = "<a href='$url'>diff</a>"; + } else { + $diff = " "; + } + + if (isset($temp_filenames['mem']) && file_exists($temp_filenames['mem'])) { + $url = str_replace($temp_target, $temp_urlbase, $temp_filenames['mem']); + $mem = "<a href='$url'>leaks</a>"; + } else { + $mem = " "; + } + + fwrite( + $html_file, + "<tr>" . + "<td>$result</td>" . + "<td>$tested</td>" . + "<td>$extra</td>" . + "<td>$diff</td>" . + "<td>$mem</td>" . + "</tr>\n" + ); + } } function junit_init() { - // Check whether a junit log is wanted. - global $workerID; - $JUNIT = getenv('TEST_PHP_JUNIT'); - if (empty($JUNIT)) { - $GLOBALS['JUNIT'] = false; - return; - } - if ($workerID) { - $fp = null; - } else if (!$fp = fopen($JUNIT, 'w')) { - error("Failed to open $JUNIT for writing."); - } - $GLOBALS['JUNIT'] = array( - 'fp' => $fp, - 'name' => 'PHP', - 'test_total' => 0, - 'test_pass' => 0, - 'test_fail' => 0, - 'test_error' => 0, - 'test_skip' => 0, - 'test_warn' => 0, - 'execution_time' => 0, - 'suites' => array(), - 'files' => array() - ); + // Check whether a junit log is wanted. + global $workerID; + $JUNIT = getenv('TEST_PHP_JUNIT'); + if (empty($JUNIT)) { + $GLOBALS['JUNIT'] = false; + return; + } + if ($workerID) { + $fp = null; + } else if (!$fp = fopen($JUNIT, 'w')) { + error("Failed to open $JUNIT for writing."); + } + $GLOBALS['JUNIT'] = array( + 'fp' => $fp, + 'name' => 'PHP', + 'test_total' => 0, + 'test_pass' => 0, + 'test_fail' => 0, + 'test_error' => 0, + 'test_skip' => 0, + 'test_warn' => 0, + 'execution_time' => 0, + 'suites' => array(), + 'files' => array() + ); } function junit_save_xml() { - global $JUNIT; - if (!junit_enabled()) return; - - $xml = '<' . '?' . 'xml version="1.0" encoding="UTF-8"' . '?' . '>' . PHP_EOL; - $xml .= sprintf( - '<testsuites name="%s" tests="%s" failures="%d" errors="%d" skip="%d" time="%s">' . PHP_EOL, - $JUNIT['name'], - $JUNIT['test_total'], - $JUNIT['test_fail'], - $JUNIT['test_error'], - $JUNIT['test_skip'], - $JUNIT['execution_time'] - ); - $xml .= junit_get_suite_xml(); - $xml .= '</testsuites>'; - fwrite($JUNIT['fp'], $xml); + global $JUNIT; + if (!junit_enabled()) return; + + $xml = '<' . '?' . 'xml version="1.0" encoding="UTF-8"' . '?' . '>' . PHP_EOL; + $xml .= sprintf( + '<testsuites name="%s" tests="%s" failures="%d" errors="%d" skip="%d" time="%s">' . PHP_EOL, + $JUNIT['name'], + $JUNIT['test_total'], + $JUNIT['test_fail'], + $JUNIT['test_error'], + $JUNIT['test_skip'], + $JUNIT['execution_time'] + ); + $xml .= junit_get_suite_xml(); + $xml .= '</testsuites>'; + fwrite($JUNIT['fp'], $xml); } function junit_get_suite_xml($suite_name = '') { - global $JUNIT; - - $result = ""; - - foreach ($JUNIT['suites'] as $suite_name => $suite) { - $result .= sprintf( - '<testsuite name="%s" tests="%s" failures="%d" errors="%d" skip="%d" time="%s">' . PHP_EOL, - $suite['name'], - $suite['test_total'], - $suite['test_fail'], - $suite['test_error'], - $suite['test_skip'], - $suite['execution_time'] - ); - - if (!empty($suite_name)) { - foreach ($suite['files'] as $file) { - $result .= $JUNIT['files'][$file]['xml']; - } - } - - $result .= '</testsuite>' . PHP_EOL; - } - - return $result; + global $JUNIT; + + $result = ""; + + foreach ($JUNIT['suites'] as $suite_name => $suite) { + $result .= sprintf( + '<testsuite name="%s" tests="%s" failures="%d" errors="%d" skip="%d" time="%s">' . PHP_EOL, + $suite['name'], + $suite['test_total'], + $suite['test_fail'], + $suite['test_error'], + $suite['test_skip'], + $suite['execution_time'] + ); + + if (!empty($suite_name)) { + foreach ($suite['files'] as $file) { + $result .= $JUNIT['files'][$file]['xml']; + } + } + + $result .= '</testsuite>' . PHP_EOL; + } + + return $result; } function junit_enabled() { - global $JUNIT; - return !empty($JUNIT); + global $JUNIT; + return !empty($JUNIT); } /** @@ -3409,253 +3409,253 @@ function junit_enabled() */ function junit_mark_test_as($type, $file_name, $test_name, $time = null, $message = '', $details = '') { - global $JUNIT; - if (!junit_enabled()) return; - - $suite = junit_get_suitename_for($file_name); - - junit_suite_record($suite, 'test_total'); - - $time = $time ?? junit_get_timer($file_name); - junit_suite_record($suite, 'execution_time', $time); - - $escaped_details = htmlspecialchars($details, ENT_QUOTES, 'UTF-8'); - $escaped_details = preg_replace_callback('/[\0-\x08\x0B\x0C\x0E-\x1F]/', function ($c) { - return sprintf('[[0x%02x]]', ord($c[0])); - }, $escaped_details); - $escaped_message = htmlspecialchars($message, ENT_QUOTES, 'UTF-8'); - - $escaped_test_name = htmlspecialchars($file_name . ' (' . $test_name . ')', ENT_QUOTES); - $JUNIT['files'][$file_name]['xml'] = "<testcase name='$escaped_test_name' time='$time'>\n"; - - if (is_array($type)) { - $output_type = $type[0] . 'ED'; - $temp = array_intersect(array('XFAIL', 'XLEAK', 'FAIL', 'WARN'), $type); - $type = reset($temp); - } else { - $output_type = $type . 'ED'; - } - - if ('PASS' == $type || 'XFAIL' == $type || 'XLEAK' == $type) { - junit_suite_record($suite, 'test_pass'); - } elseif ('BORK' == $type) { - junit_suite_record($suite, 'test_error'); - $JUNIT['files'][$file_name]['xml'] .= "<error type='$output_type' message='$escaped_message'/>\n"; - } elseif ('SKIP' == $type) { - junit_suite_record($suite, 'test_skip'); - $JUNIT['files'][$file_name]['xml'] .= "<skipped>$escaped_message</skipped>\n"; - } elseif ('WARN' == $type) { - junit_suite_record($suite, 'test_warn'); - $JUNIT['files'][$file_name]['xml'] .= "<warning>$escaped_message</warning>\n"; - } elseif ('FAIL' == $type) { - junit_suite_record($suite, 'test_fail'); - $JUNIT['files'][$file_name]['xml'] .= "<failure type='$output_type' message='$escaped_message'>$escaped_details</failure>\n"; - } else { - junit_suite_record($suite, 'test_error'); - $JUNIT['files'][$file_name]['xml'] .= "<error type='$output_type' message='$escaped_message'>$escaped_details</error>\n"; - } - - $JUNIT['files'][$file_name]['xml'] .= "</testcase>\n"; + global $JUNIT; + if (!junit_enabled()) return; + + $suite = junit_get_suitename_for($file_name); + + junit_suite_record($suite, 'test_total'); + + $time = $time ?? junit_get_timer($file_name); + junit_suite_record($suite, 'execution_time', $time); + + $escaped_details = htmlspecialchars($details, ENT_QUOTES, 'UTF-8'); + $escaped_details = preg_replace_callback('/[\0-\x08\x0B\x0C\x0E-\x1F]/', function ($c) { + return sprintf('[[0x%02x]]', ord($c[0])); + }, $escaped_details); + $escaped_message = htmlspecialchars($message, ENT_QUOTES, 'UTF-8'); + + $escaped_test_name = htmlspecialchars($file_name . ' (' . $test_name . ')', ENT_QUOTES); + $JUNIT['files'][$file_name]['xml'] = "<testcase name='$escaped_test_name' time='$time'>\n"; + + if (is_array($type)) { + $output_type = $type[0] . 'ED'; + $temp = array_intersect(array('XFAIL', 'XLEAK', 'FAIL', 'WARN'), $type); + $type = reset($temp); + } else { + $output_type = $type . 'ED'; + } + + if ('PASS' == $type || 'XFAIL' == $type || 'XLEAK' == $type) { + junit_suite_record($suite, 'test_pass'); + } elseif ('BORK' == $type) { + junit_suite_record($suite, 'test_error'); + $JUNIT['files'][$file_name]['xml'] .= "<error type='$output_type' message='$escaped_message'/>\n"; + } elseif ('SKIP' == $type) { + junit_suite_record($suite, 'test_skip'); + $JUNIT['files'][$file_name]['xml'] .= "<skipped>$escaped_message</skipped>\n"; + } elseif ('WARN' == $type) { + junit_suite_record($suite, 'test_warn'); + $JUNIT['files'][$file_name]['xml'] .= "<warning>$escaped_message</warning>\n"; + } elseif ('FAIL' == $type) { + junit_suite_record($suite, 'test_fail'); + $JUNIT['files'][$file_name]['xml'] .= "<failure type='$output_type' message='$escaped_message'>$escaped_details</failure>\n"; + } else { + junit_suite_record($suite, 'test_error'); + $JUNIT['files'][$file_name]['xml'] .= "<error type='$output_type' message='$escaped_message'>$escaped_details</error>\n"; + } + + $JUNIT['files'][$file_name]['xml'] .= "</testcase>\n"; } function junit_suite_record($suite, $param, $value = 1) { - global $JUNIT; + global $JUNIT; - $JUNIT[$param] += $value; - $JUNIT['suites'][$suite][$param] += $value; + $JUNIT[$param] += $value; + $JUNIT['suites'][$suite][$param] += $value; } function junit_get_timer($file_name) { - global $JUNIT; - if (!junit_enabled()) return 0; + global $JUNIT; + if (!junit_enabled()) return 0; - if (isset($JUNIT['files'][$file_name]['total'])) { - return number_format($JUNIT['files'][$file_name]['total'], 4); - } + if (isset($JUNIT['files'][$file_name]['total'])) { + return number_format($JUNIT['files'][$file_name]['total'], 4); + } - return 0; + return 0; } function junit_start_timer($file_name) { - global $JUNIT; - if (!junit_enabled()) return; + global $JUNIT; + if (!junit_enabled()) return; - if (!isset($JUNIT['files'][$file_name]['start'])) { - $JUNIT['files'][$file_name]['start'] = microtime(true); + if (!isset($JUNIT['files'][$file_name]['start'])) { + $JUNIT['files'][$file_name]['start'] = microtime(true); - $suite = junit_get_suitename_for($file_name); - junit_init_suite($suite); - $JUNIT['suites'][$suite]['files'][$file_name] = $file_name; - } + $suite = junit_get_suitename_for($file_name); + junit_init_suite($suite); + $JUNIT['suites'][$suite]['files'][$file_name] = $file_name; + } } function junit_get_suitename_for($file_name) { - return junit_path_to_classname(dirname($file_name)); + return junit_path_to_classname(dirname($file_name)); } function junit_path_to_classname($file_name) { - global $JUNIT; - - if (!junit_enabled()) return ''; - - $ret = $JUNIT['name']; - $_tmp = array(); - - // lookup whether we're in the PHP source checkout - $max = 5; - if (is_file($file_name)) { - $dir = dirname(realpath($file_name)); - } else { - $dir = realpath($file_name); - } - do { - array_unshift($_tmp, basename($dir)); - $chk = $dir . DIRECTORY_SEPARATOR . "main" . DIRECTORY_SEPARATOR . "php_version.h"; - $dir = dirname($dir); - } while (!file_exists($chk) && --$max > 0); - if (file_exists($chk)) { - if ($max) { - array_shift($_tmp); - } - foreach ($_tmp as $p) { - $ret .= "." . preg_replace(",[^a-z0-9]+,i", ".", $p); - } - return $ret; - } - - return $JUNIT['name'] . '.' . str_replace(array(DIRECTORY_SEPARATOR, '-'), '.', $file_name); + global $JUNIT; + + if (!junit_enabled()) return ''; + + $ret = $JUNIT['name']; + $_tmp = array(); + + // lookup whether we're in the PHP source checkout + $max = 5; + if (is_file($file_name)) { + $dir = dirname(realpath($file_name)); + } else { + $dir = realpath($file_name); + } + do { + array_unshift($_tmp, basename($dir)); + $chk = $dir . DIRECTORY_SEPARATOR . "main" . DIRECTORY_SEPARATOR . "php_version.h"; + $dir = dirname($dir); + } while (!file_exists($chk) && --$max > 0); + if (file_exists($chk)) { + if ($max) { + array_shift($_tmp); + } + foreach ($_tmp as $p) { + $ret .= "." . preg_replace(",[^a-z0-9]+,i", ".", $p); + } + return $ret; + } + + return $JUNIT['name'] . '.' . str_replace(array(DIRECTORY_SEPARATOR, '-'), '.', $file_name); } function junit_init_suite($suite_name) { - global $JUNIT; - if (!junit_enabled()) return; - - if (!empty($JUNIT['suites'][$suite_name])) { - return; - } - - $JUNIT['suites'][$suite_name] = array( - 'name' => $suite_name, - 'test_total' => 0, - 'test_pass' => 0, - 'test_fail' => 0, - 'test_error' => 0, - 'test_skip' => 0, - 'test_warn' => 0, - 'files' => array(), - 'execution_time' => 0, - ); + global $JUNIT; + if (!junit_enabled()) return; + + if (!empty($JUNIT['suites'][$suite_name])) { + return; + } + + $JUNIT['suites'][$suite_name] = array( + 'name' => $suite_name, + 'test_total' => 0, + 'test_pass' => 0, + 'test_fail' => 0, + 'test_error' => 0, + 'test_skip' => 0, + 'test_warn' => 0, + 'files' => array(), + 'execution_time' => 0, + ); } function junit_finish_timer($file_name) { - global $JUNIT; - if (!junit_enabled()) return; + global $JUNIT; + if (!junit_enabled()) return; - if (!isset($JUNIT['files'][$file_name]['start'])) { - error("Timer for $file_name was not started!"); - } + if (!isset($JUNIT['files'][$file_name]['start'])) { + error("Timer for $file_name was not started!"); + } - if (!isset($JUNIT['files'][$file_name]['total'])) { - $JUNIT['files'][$file_name]['total'] = 0; - } + if (!isset($JUNIT['files'][$file_name]['total'])) { + $JUNIT['files'][$file_name]['total'] = 0; + } - $start = $JUNIT['files'][$file_name]['start']; - $JUNIT['files'][$file_name]['total'] += microtime(true) - $start; - unset($JUNIT['files'][$file_name]['start']); + $start = $JUNIT['files'][$file_name]['start']; + $JUNIT['files'][$file_name]['total'] += microtime(true) - $start; + unset($JUNIT['files'][$file_name]['start']); } function junit_merge_results($junit) { - global $JUNIT; - $JUNIT['test_total'] += $junit['test_total']; - $JUNIT['test_pass'] += $junit['test_pass']; - $JUNIT['test_fail'] += $junit['test_fail']; - $JUNIT['test_error'] += $junit['test_error']; - $JUNIT['test_skip'] += $junit['test_skip']; - $JUNIT['test_warn'] += $junit['test_warn']; - $JUNIT['execution_time'] += $junit['execution_time']; - $JUNIT['files'] += $junit['files']; - foreach ($junit['suites'] as $name => $suite) { - if (!isset($JUNIT['suites'][$name])) { - $JUNIT['suites'][$name] = $suite; - continue; - } - - $SUITE =& $JUNIT['suites'][$name]; - $SUITE['test_total'] += $suite['test_total']; - $SUITE['test_pass'] += $suite['test_pass']; - $SUITE['test_fail'] += $suite['test_fail']; - $SUITE['test_error'] += $suite['test_error']; - $SUITE['test_skip'] += $suite['test_skip']; - $SUITE['test_warn'] += $suite['test_warn']; - $SUITE['execution_time'] += $suite['execution_time']; - $SUITE['files'] += $suite['files']; - } + global $JUNIT; + $JUNIT['test_total'] += $junit['test_total']; + $JUNIT['test_pass'] += $junit['test_pass']; + $JUNIT['test_fail'] += $junit['test_fail']; + $JUNIT['test_error'] += $junit['test_error']; + $JUNIT['test_skip'] += $junit['test_skip']; + $JUNIT['test_warn'] += $junit['test_warn']; + $JUNIT['execution_time'] += $junit['execution_time']; + $JUNIT['files'] += $junit['files']; + foreach ($junit['suites'] as $name => $suite) { + if (!isset($JUNIT['suites'][$name])) { + $JUNIT['suites'][$name] = $suite; + continue; + } + + $SUITE =& $JUNIT['suites'][$name]; + $SUITE['test_total'] += $suite['test_total']; + $SUITE['test_pass'] += $suite['test_pass']; + $SUITE['test_fail'] += $suite['test_fail']; + $SUITE['test_error'] += $suite['test_error']; + $SUITE['test_skip'] += $suite['test_skip']; + $SUITE['test_warn'] += $suite['test_warn']; + $SUITE['execution_time'] += $suite['execution_time']; + $SUITE['files'] += $suite['files']; + } } class RuntestsValgrind { - protected $version = ''; - protected $header = ''; - protected $version_3_3_0 = false; - protected $version_3_8_0 = false; - protected $tool = null; - - public function getVersion() - { - return $this->version; - } - - public function getHeader() - { - return $this->header; - } - - public function __construct(array $environment, string $tool = 'memcheck') - { - $this->tool = $tool; - $header = system_with_timeout("valgrind --tool={$this->tool} --version", $environment); - if (!$header) { - error("Valgrind returned no version info for {$this->tool}, cannot proceed.\n". + protected $version = ''; + protected $header = ''; + protected $version_3_3_0 = false; + protected $version_3_8_0 = false; + protected $tool = null; + + public function getVersion() + { + return $this->version; + } + + public function getHeader() + { + return $this->header; + } + + public function __construct(array $environment, string $tool = 'memcheck') + { + $this->tool = $tool; + $header = system_with_timeout("valgrind --tool={$this->tool} --version", $environment); + if (!$header) { + error("Valgrind returned no version info for {$this->tool}, cannot proceed.\n". "Please check if Valgrind is installed and the tool is named correctly."); - } - $count = 0; - $version = preg_replace("/valgrind-(\d+)\.(\d+)\.(\d+)([.\w_-]+)?(\s+)/", '$1.$2.$3', $header, 1, $count); - if ($count != 1) { - error("Valgrind returned invalid version info (\"{$header}\") for {$this->tool}, cannot proceed."); - } - $this->version = $version; - $this->header = sprintf( - "%s (%s)", trim($header), $this->tool); - $this->version_3_3_0 = version_compare($version, '3.3.0', '>='); - $this->version_3_8_0 = version_compare($version, '3.8.0', '>='); - } - - public function wrapCommand($cmd, $memcheck_filename, $check_all) - { - $vcmd = "valgrind -q --tool={$this->tool} --trace-children=yes"; - if ($check_all) { - $vcmd .= ' --smc-check=all'; - } - - /* --vex-iropt-register-updates=allregs-at-mem-access is necessary for phpdbg watchpoint tests */ - if ($this->version_3_8_0) { - /* valgrind 3.3.0+ doesn't have --log-file-exactly option */ - return "$vcmd --vex-iropt-register-updates=allregs-at-mem-access --log-file=$memcheck_filename $cmd"; - } elseif ($this->version_3_3_0) { - return "$vcmd --vex-iropt-precise-memory-exns=yes --log-file=$memcheck_filename $cmd"; - } else { - return "$vcmd --vex-iropt-precise-memory-exns=yes --log-file-exactly=$memcheck_filename $cmd"; - } - } + } + $count = 0; + $version = preg_replace("/valgrind-(\d+)\.(\d+)\.(\d+)([.\w_-]+)?(\s+)/", '$1.$2.$3', $header, 1, $count); + if ($count != 1) { + error("Valgrind returned invalid version info (\"{$header}\") for {$this->tool}, cannot proceed."); + } + $this->version = $version; + $this->header = sprintf( + "%s (%s)", trim($header), $this->tool); + $this->version_3_3_0 = version_compare($version, '3.3.0', '>='); + $this->version_3_8_0 = version_compare($version, '3.8.0', '>='); + } + + public function wrapCommand($cmd, $memcheck_filename, $check_all) + { + $vcmd = "valgrind -q --tool={$this->tool} --trace-children=yes"; + if ($check_all) { + $vcmd .= ' --smc-check=all'; + } + + /* --vex-iropt-register-updates=allregs-at-mem-access is necessary for phpdbg watchpoint tests */ + if ($this->version_3_8_0) { + /* valgrind 3.3.0+ doesn't have --log-file-exactly option */ + return "$vcmd --vex-iropt-register-updates=allregs-at-mem-access --log-file=$memcheck_filename $cmd"; + } elseif ($this->version_3_3_0) { + return "$vcmd --vex-iropt-precise-memory-exns=yes --log-file=$memcheck_filename $cmd"; + } else { + return "$vcmd --vex-iropt-precise-memory-exns=yes --log-file-exactly=$memcheck_filename $cmd"; + } + } } main(); diff --git a/sapi/cli/generate_mime_type_map.php b/sapi/cli/generate_mime_type_map.php index b0176bb524..40f546ef83 100755 --- a/sapi/cli/generate_mime_type_map.php +++ b/sapi/cli/generate_mime_type_map.php @@ -8,36 +8,36 @@ $source = count($_SERVER['argv']) > 1 ? $_SERVER['argv'][1] : 'https://raw.githu // See if we can actually load it. $types = @file($source); if ($types === false) { - fprintf(STDERR, "Error: unable to read $source\n"); - exit(1); + fprintf(STDERR, "Error: unable to read $source\n"); + exit(1); } // Remove comments and flip into an extensions array. $extensions = []; array_walk($types, function ($line) use (&$extensions) { - $line = trim($line); - if ($line && $line[0] != '#') { - $fields = preg_split('/\s+/', $line); - if (count($fields) > 1) { - $mime = array_shift($fields); - foreach ($fields as $extension) { - $extensions[$extension] = $mime; - } - } - } + $line = trim($line); + if ($line && $line[0] != '#') { + $fields = preg_split('/\s+/', $line); + if (count($fields) > 1) { + $mime = array_shift($fields); + foreach ($fields as $extension) { + $extensions[$extension] = $mime; + } + } + } }); $additional_mime_maps = [ - "map" => "application/json", // from commit: a0d62f08ae8cbebc88e5c92e08fca8d0cdc7309d - "jsm" => "application/javascript", + "map" => "application/json", // from commit: a0d62f08ae8cbebc88e5c92e08fca8d0cdc7309d + "jsm" => "application/javascript", ]; foreach($additional_mime_maps as $ext => $mime) { - if (!isset($extensions[$ext])) { - $extensions[$ext] = $mime; - } else { - printf(STDERR, "Ignored exist mime type: $ext => $mime\n"); - } + if (!isset($extensions[$ext])) { + $extensions[$ext] = $mime; + } else { + printf(STDERR, "Ignored exist mime type: $ext => $mime\n"); + } } ?> @@ -66,15 +66,15 @@ foreach($additional_mime_maps as $ext => $mime) { #define PHP_CLI_SERVER_MIME_TYPE_MAP_H typedef struct php_cli_server_ext_mime_type_pair { - const char *ext; - const char *mime_type; + const char *ext; + const char *mime_type; } php_cli_server_ext_mime_type_pair; static const php_cli_server_ext_mime_type_pair mime_type_map[] = { <?php foreach ($extensions as $extension => $mime): ?> - { "<?= addcslashes($extension, "\0..\37!@\@\177..\377") ?>", "<?= addcslashes($mime, "\0..\37!@\@\177..\377") ?>" }, + { "<?= addcslashes($extension, "\0..\37!@\@\177..\377") ?>", "<?= addcslashes($mime, "\0..\37!@\@\177..\377") ?>" }, <?php endforeach ?> - { NULL, NULL } + { NULL, NULL } }; #endif /* PHP_CLI_SERVER_MIME_TYPE_MAP_H */ diff --git a/sapi/cli/php_cli_server.c b/sapi/cli/php_cli_server.c index f00d8dee54..bd48afb1f7 100644 --- a/sapi/cli/php_cli_server.c +++ b/sapi/cli/php_cli_server.c @@ -510,7 +510,7 @@ static int sapi_cli_server_startup(sapi_module_struct *sapi_module) /* {{{ */ if (php_cli_server_workers_max > 1) { zend_long php_cli_server_worker; - + php_cli_server_workers = calloc( php_cli_server_workers_max, sizeof(pid_t)); if (!php_cli_server_workers) { @@ -528,7 +528,7 @@ static int sapi_cli_server_startup(sapi_module_struct *sapi_module) /* {{{ */ if (pid == FAILURE) { /* no more forks allowed, work with what we have ... */ - php_cli_server_workers_max = + php_cli_server_workers_max = php_cli_server_worker + 1; return SUCCESS; } else if (pid == SUCCESS) { @@ -2321,14 +2321,14 @@ static void php_cli_server_dtor(php_cli_server *server) /* {{{ */ int php_cli_server_worker_status; do { - if (waitpid(php_cli_server_workers[php_cli_server_worker], - &php_cli_server_worker_status, + if (waitpid(php_cli_server_workers[php_cli_server_worker], + &php_cli_server_worker_status, 0) == FAILURE) { /* an extremely bad thing happened */ break; } - } while (!WIFEXITED(php_cli_server_worker_status) && + } while (!WIFEXITED(php_cli_server_worker_status) && !WIFSIGNALED(php_cli_server_worker_status)); } diff --git a/sapi/phpdbg/create-test.php b/sapi/phpdbg/create-test.php index e5f7cfe2e9..3e2c8f0437 100755 --- a/sapi/phpdbg/create-test.php +++ b/sapi/phpdbg/create-test.php @@ -32,37 +32,37 @@ $file = ""; $cmdargv = ""; if (isset($argc) && $argc > 1) { - $post_ddash = false; - for ($i = 1; $i < $argc; $i++) { - if ($argv[$i][0] == "-" && !$post_ddash) { - switch (substr($argv[$i], 1)) { - case "p": - $phpdbg = $argv[++$i]; - break; - case "n": - $pass_options .= " -n"; - break; - case "d": - $pass_options .= " -d ".escapeshellarg($argv[++$i]); - $ini[] = $argv[$i]; - break; - case "-": - $post_ddash = true; - break; - } - } else { - $real_argv[] = $argv[$i]; - } - } - if (isset($real_argv[0])) { - $file = realpath($real_argv[0]); - $cmdargv = implode(" ", array_map("escapeshellarg", array_slice($real_argv, 1))); - } + $post_ddash = false; + for ($i = 1; $i < $argc; $i++) { + if ($argv[$i][0] == "-" && !$post_ddash) { + switch (substr($argv[$i], 1)) { + case "p": + $phpdbg = $argv[++$i]; + break; + case "n": + $pass_options .= " -n"; + break; + case "d": + $pass_options .= " -d ".escapeshellarg($argv[++$i]); + $ini[] = $argv[$i]; + break; + case "-": + $post_ddash = true; + break; + } + } else { + $real_argv[] = $argv[$i]; + } + } + if (isset($real_argv[0])) { + $file = realpath($real_argv[0]); + $cmdargv = implode(" ", array_map("escapeshellarg", array_slice($real_argv, 1))); + } } $proc = proc_open("$phpdbg $pass_options $file -- $cmdargv", [["pipe", "r"], ["pipe", "w"], ["pipe", "w"]], $pipes); if (!$proc) { - die("Couldn't start phpdbg\n"); + die("Couldn't start phpdbg\n"); } $input = $output = ""; @@ -70,47 +70,47 @@ $input = $output = ""; stream_set_blocking(STDIN, false); do { - $r = [$pipes[1], STDIN]; - $w = $e = null; - $n = @stream_select($r, $w, $e, null); - - if ($n > 0) { - if ("" != $in = fread(STDIN, 1024)) { - $input .= $in; - fwrite($pipes[0], $in); - continue; - } - - if (feof(STDIN)) { - die("stdin closed?!\n"); - } - - if (feof($pipes[1])) { - $n = false; - } else { - $output .= $c = fgetc($pipes[1]); - echo $c; - } - } + $r = [$pipes[1], STDIN]; + $w = $e = null; + $n = @stream_select($r, $w, $e, null); + + if ($n > 0) { + if ("" != $in = fread(STDIN, 1024)) { + $input .= $in; + fwrite($pipes[0], $in); + continue; + } + + if (feof(STDIN)) { + die("stdin closed?!\n"); + } + + if (feof($pipes[1])) { + $n = false; + } else { + $output .= $c = fgetc($pipes[1]); + echo $c; + } + } } while ($n !== false); stream_set_blocking(STDIN, true); print "\n"; if (!isset($name)) { - print "Specify the test description: "; - $desc = trim(fgets(STDIN)); + print "Specify the test description: "; + $desc = trim(fgets(STDIN)); } while (!isset($testfile)) { - print "Specify the test file name (leave empty to write to stderr): "; - $testfile = trim(fgets(STDIN)); - if ($testfile != "" && file_exists($testfile)) { - print "That file already exists. Type y or yes to overwrite: "; - $y = trim(fgets(STDIN)); - if ($y !== "y" && $y !== "yes") { - unset($testfile); - } - } + print "Specify the test file name (leave empty to write to stderr): "; + $testfile = trim(fgets(STDIN)); + if ($testfile != "" && file_exists($testfile)) { + print "That file already exists. Type y or yes to overwrite: "; + $y = trim(fgets(STDIN)); + if ($y !== "y" && $y !== "yes") { + unset($testfile); + } + } } $output = str_replace("string(".strlen($file).") \"$file\"", 'string(%d) "%s"', $output); @@ -127,24 +127,24 @@ $output TEST; if (!empty($ini)) { - $testdata .= "\n--INI--\n".implode("\n", $ini); + $testdata .= "\n--INI--\n".implode("\n", $ini); } if ($cmdargv != "") { - $testdata .= "\n--ARGS--\n$cmdargv"; + $testdata .= "\n--ARGS--\n$cmdargv"; } if ($file != "") { - $testdata .= "\n--FILE--\n".file_get_contents($file); + $testdata .= "\n--FILE--\n".file_get_contents($file); } if ($testfile == "") { - print "\n"; + print "\n"; } elseif (file_put_contents($testfile, $testdata)) { - print "Test saved to $testfile\n"; + print "Test saved to $testfile\n"; } else { - print "The test could not be saved to $testfile; outputting on stderr now\n"; - $testfile = ""; + print "The test could not be saved to $testfile; outputting on stderr now\n"; + $testfile = ""; } if ($testfile == "") { - fwrite(STDERR, $testdata); + fwrite(STDERR, $testdata); } diff --git a/sapi/phpdbg/phpdbg_bp.c b/sapi/phpdbg/phpdbg_bp.c index 3a47c78470..738967f907 100644 --- a/sapi/phpdbg/phpdbg_bp.c +++ b/sapi/phpdbg/phpdbg_bp.c @@ -198,19 +198,19 @@ PHPDBG_API void phpdbg_export_breakpoints_to_string(char **str) /* {{{ */ "%sbreak at %s#%ld if %s\n", *str, conditional->param.str, conditional->param.num, conditional->code); break; - + case NUMERIC_METHOD_PARAM: phpdbg_asprintf(&new_str, "%sbreak at %s::%s#%ld if %s\n", *str, conditional->param.method.class, conditional->param.method.name, conditional->param.num, conditional->code); break; - + case ADDR_PARAM: phpdbg_asprintf(&new_str, "%sbreak at 0X%lx if %s\n", *str, conditional->param.addr, conditional->code); break; - + case STR_PARAM: phpdbg_asprintf(&new_str, "%sbreak at %s if %s\n", *str, conditional->param.str, conditional->code); @@ -841,7 +841,7 @@ static inline void phpdbg_create_conditional_break(phpdbg_breakcond_t *brake, co case ADDR_PARAM: /* do nothing */ break; - + default: phpdbg_error("eval", "type=\"invalidparameter\"", "Invalid parameter type for conditional breakpoint"); return; @@ -857,10 +857,10 @@ static inline void phpdbg_create_conditional_break(phpdbg_breakcond_t *brake, co if (new_break.param.type == FILE_PARAM || new_break.param.type == NUMERIC_FILE_PARAM) { char realpath[MAXPATHLEN]; - + if (VCWD_REALPATH(new_break.param.file.name, realpath)) { efree(new_break.param.file.name); - + new_break.param.file.name = estrdup(realpath); } else { phpdbg_error("eval", "type=\"invalidparameter\"", "Invalid file for conditional break %s", new_break.param.file.name); diff --git a/sapi/phpdbg/test.php b/sapi/phpdbg/test.php index d93c81a89a..265ea9697c 100644 --- a/sapi/phpdbg/test.php +++ b/sapi/phpdbg/test.php @@ -1,35 +1,35 @@ <?php if (isset($include)) { - include (sprintf("%s/web-bootstrap.php", dirname(__FILE__))); + include (sprintf("%s/web-bootstrap.php", dirname(__FILE__))); } $stdout = fopen("php://stdout", "w+"); class phpdbg { - private $sprintf = "%s: %s\n"; + private $sprintf = "%s: %s\n"; - public function isGreat($greeting = null) { - printf($this->sprintf, __METHOD__, $greeting); - return $this; - } + public function isGreat($greeting = null) { + printf($this->sprintf, __METHOD__, $greeting); + return $this; + } } function mine() { - var_dump(func_get_args()); + var_dump(func_get_args()); } function test($x, $y = 0) { - $var = $x + 1; - $var += 2; - $var <<= 3; + $var = $x + 1; + $var += 2; + $var <<= 3; - $foo = function () { - echo "bar!\n"; - }; + $foo = function () { + echo "bar!\n"; + }; - $foo(); + $foo(); - yield $var; + yield $var; } $dbg = new phpdbg(); @@ -38,43 +38,43 @@ var_dump( $dbg->isGreat("PHP Rocks!!")); foreach (test(1,2) as $gen) - continue; + continue; echo "it works!\n"; if (isset($dump)) - var_dump($_SERVER); + var_dump($_SERVER); function phpdbg_test_ob() { - echo 'Start'; - ob_start(); - echo 'Hello'; - $b = ob_get_clean(); - echo 'End'; - echo $b; + echo 'Start'; + ob_start(); + echo 'Hello'; + $b = ob_get_clean(); + echo 'End'; + echo $b; } $array = [ - 1, - 2, - [3, 4], - [5, 6], + 1, + 2, + [3, 4], + [5, 6], ]; $array[] = 7; array_walk($array, function (&$item) { - if (is_array($item)) - $item[0] += 2; - else - $item -= 1; + if (is_array($item)) + $item[0] += 2; + else + $item -= 1; }); class testClass { - public $a = 2; - protected $b = [1, 3]; - private $c = 7; + public $a = 2; + protected $b = [1, 3]; + private $c = 7; } $obj = new testClass; diff --git a/scripts/dev/check_parameters.php b/scripts/dev/check_parameters.php index 8c8d6dff40..e779d3daee 100755 --- a/scripts/dev/check_parameters.php +++ b/scripts/dev/check_parameters.php @@ -31,349 +31,349 @@ ini_set('pcre.backtrack_limit', 10000000); $API_params = array( - 'a' => array('zval**'), // array - 'A' => array('zval**'), // array or object - 'b' => array('zend_bool*'), // boolean - 'd' => array('double*'), // double - 'f' => array('zend_fcall_info*', 'zend_fcall_info_cache*'), // function - 'h' => array('HashTable**'), // array as an HashTable* - 'H' => array('HashTable**'), // array or HASH_OF(object) - 'l' => array('zend_long*'), // long - //TODO 'L' => array('zend_long*, '), // long - 'o' => array('zval**'), //object - 'O' => array('zval**', 'zend_class_entry*'), // object of given type - 'P' => array('zend_string**'), // valid path - 'r' => array('zval**'), // resource - 'S' => array('zend_string**'), // string - 'z' => array('zval**'), // zval* - 'Z' => array('zval***') // zval** - // 's', 'p', 'C' handled separately + 'a' => array('zval**'), // array + 'A' => array('zval**'), // array or object + 'b' => array('zend_bool*'), // boolean + 'd' => array('double*'), // double + 'f' => array('zend_fcall_info*', 'zend_fcall_info_cache*'), // function + 'h' => array('HashTable**'), // array as an HashTable* + 'H' => array('HashTable**'), // array or HASH_OF(object) + 'l' => array('zend_long*'), // long + //TODO 'L' => array('zend_long*, '), // long + 'o' => array('zval**'), //object + 'O' => array('zval**', 'zend_class_entry*'), // object of given type + 'P' => array('zend_string**'), // valid path + 'r' => array('zval**'), // resource + 'S' => array('zend_string**'), // string + 'z' => array('zval**'), // zval* + 'Z' => array('zval***') // zval** + // 's', 'p', 'C' handled separately ); /** reports an error, according to its level */ function error($str, $level = 0) { - global $current_file, $current_function, $line; - - if ($level <= REPORT_LEVEL) { - if (strpos($current_file,PHPDIR) === 0) { - $filename = substr($current_file, strlen(PHPDIR)+1); - } else { - $filename = $current_file; - } - echo $filename , " [$line] $current_function : $str\n"; - } + global $current_file, $current_function, $line; + + if ($level <= REPORT_LEVEL) { + if (strpos($current_file,PHPDIR) === 0) { + $filename = substr($current_file, strlen(PHPDIR)+1); + } else { + $filename = $current_file; + } + echo $filename , " [$line] $current_function : $str\n"; + } } /** this updates the global var $line (for error reporting) */ function update_lineno($offset) { - global $lines_offset, $line; - - $left = 0; - $right = $count = count($lines_offset)-1; - - // a nice binary search :) - do { - $mid = intval(($left + $right)/2); - $val = $lines_offset[$mid]; - - if ($val < $offset) { - if (++$mid > $count || $lines_offset[$mid] > $offset) { - $line = $mid; - return; - } else { - $left = $mid; - } - } else if ($val > $offset) { - if ($lines_offset[--$mid] < $offset) { - $line = $mid+1; - return; - } else { - $right = $mid; - } - } else { - $line = $mid+1; - return; - } - } while (true); + global $lines_offset, $line; + + $left = 0; + $right = $count = count($lines_offset)-1; + + // a nice binary search :) + do { + $mid = intval(($left + $right)/2); + $val = $lines_offset[$mid]; + + if ($val < $offset) { + if (++$mid > $count || $lines_offset[$mid] > $offset) { + $line = $mid; + return; + } else { + $left = $mid; + } + } else if ($val > $offset) { + if ($lines_offset[--$mid] < $offset) { + $line = $mid+1; + return; + } else { + $right = $mid; + } + } else { + $line = $mid+1; + return; + } + } while (true); } /** parses the sources and fetches its vars name, type and if they are initialized or not */ function get_vars($txt) { - $ret = array(); - preg_match_all('/((?:(?:unsigned|struct)\s+)?\w+)(?:\s*(\*+)\s+|\s+(\**))(\w+(?:\[\s*\w*\s*\])?)\s*(?:(=)[^,;]+)?((?:\s*,\s*\**\s*\w+(?:\[\s*\w*\s*\])?\s*(?:=[^,;]+)?)*)\s*;/S', $txt, $m, PREG_SET_ORDER); - - foreach ($m as $x) { - // the first parameter is special - if (!in_array($x[1], array('else', 'endif', 'return'))) // hack to skip reserved words - $ret[$x[4]] = array($x[1] . $x[2] . $x[3], $x[5]); - - // are there more vars? - if ($x[6]) { - preg_match_all('/(\**)\s*(\w+(?:\[\s*\w*\s*\])?)\s*(=?)/S', $x[6], $y, PREG_SET_ORDER); - foreach ($y as $z) { - $ret[$z[2]] = array($x[1] . $z[1], $z[3]); - } - } - } + $ret = array(); + preg_match_all('/((?:(?:unsigned|struct)\s+)?\w+)(?:\s*(\*+)\s+|\s+(\**))(\w+(?:\[\s*\w*\s*\])?)\s*(?:(=)[^,;]+)?((?:\s*,\s*\**\s*\w+(?:\[\s*\w*\s*\])?\s*(?:=[^,;]+)?)*)\s*;/S', $txt, $m, PREG_SET_ORDER); + + foreach ($m as $x) { + // the first parameter is special + if (!in_array($x[1], array('else', 'endif', 'return'))) // hack to skip reserved words + $ret[$x[4]] = array($x[1] . $x[2] . $x[3], $x[5]); + + // are there more vars? + if ($x[6]) { + preg_match_all('/(\**)\s*(\w+(?:\[\s*\w*\s*\])?)\s*(=?)/S', $x[6], $y, PREG_SET_ORDER); + foreach ($y as $z) { + $ret[$z[2]] = array($x[1] . $z[1], $z[3]); + } + } + } // if ($GLOBALS['current_function'] == 'for_debugging') { print_r($m);print_r($ret); } - return $ret; + return $ret; } /** run diagnostic checks against one var. */ function check_param($db, $idx, $exp, $optional, $allow_uninit = false) { - global $error_few_vars_given; - - if ($idx >= count($db)) { - if (!$error_few_vars_given) { - error("too few variables passed to function"); - $error_few_vars_given = true; - } - return; - } elseif ($db[$idx][0] === '**dummy**') { - return; - } - - if ($db[$idx][1] != $exp) { - error("{$db[$idx][0]}: expected '$exp' but got '{$db[$idx][1]}' [".($idx+1).']'); - } - - if (!$optional && $db[$idx][2]) { - error("not optional var is initialized: {$db[$idx][0]} [".($idx+1).']', 2); - } - if (!$allow_uninit && $optional && !$db[$idx][2]) { - error("optional var not initialized: {$db[$idx][0]} [".($idx+1).']', 1); - } + global $error_few_vars_given; + + if ($idx >= count($db)) { + if (!$error_few_vars_given) { + error("too few variables passed to function"); + $error_few_vars_given = true; + } + return; + } elseif ($db[$idx][0] === '**dummy**') { + return; + } + + if ($db[$idx][1] != $exp) { + error("{$db[$idx][0]}: expected '$exp' but got '{$db[$idx][1]}' [".($idx+1).']'); + } + + if (!$optional && $db[$idx][2]) { + error("not optional var is initialized: {$db[$idx][0]} [".($idx+1).']', 2); + } + if (!$allow_uninit && $optional && !$db[$idx][2]) { + error("optional var not initialized: {$db[$idx][0]} [".($idx+1).']', 1); + } } /** fetch params passed to zend_parse_params*() */ function get_params($vars, $str) { - $ret = array(); - preg_match_all('/(?:\([^)]+\))?(&?)([\w>.()-]+(?:\[\w+\])?)\s*,?((?:\)*\s*=)?)/S', $str, $m, PREG_SET_ORDER); + $ret = array(); + preg_match_all('/(?:\([^)]+\))?(&?)([\w>.()-]+(?:\[\w+\])?)\s*,?((?:\)*\s*=)?)/S', $str, $m, PREG_SET_ORDER); - foreach ($m as $x) { - $name = $x[2]; + foreach ($m as $x) { + $name = $x[2]; - // little hack for last parameter - if (strpos($name, '(') === false) { - $name = rtrim($name, ')'); - } + // little hack for last parameter + if (strpos($name, '(') === false) { + $name = rtrim($name, ')'); + } - if (empty($vars[$name][0])) { - error("variable not found: '$name'", 3); - $ret[][] = '**dummy**'; + if (empty($vars[$name][0])) { + error("variable not found: '$name'", 3); + $ret[][] = '**dummy**'; - } else { - $ret[] = array($name, $vars[$name][0] . ($x[1] ? '*' : ''), $vars[$name][1]); - } + } else { + $ret[] = array($name, $vars[$name][0] . ($x[1] ? '*' : ''), $vars[$name][1]); + } - // the end (yes, this is a little hack :P) - if ($x[3]) { - break; - } - } + // the end (yes, this is a little hack :P) + if ($x[3]) { + break; + } + } // if ($GLOBALS['current_function'] == 'for_debugging') { var_dump($m); var_dump($ret); } - return $ret; + return $ret; } /** run tests on a function. the code is passed in $txt */ function check_function($name, $txt, $offset) { - global $API_params; - - $regex = '/ - (?: zend_parse_parameters(?:_throw)? \s*\([^,]+ - | zend_parse_(?:parameters_ex|method_parameters) \s*\([^,]+,[^,]+ - | zend_parse_method_parameters_ex \s*\([^,]+,[^,]+,[^,+] - ) - ,\s*"([^"]*)"\s* - ,\s*([^{;]*) - /Sx'; - if (preg_match_all($regex, $txt, $matches, PREG_SET_ORDER | PREG_OFFSET_CAPTURE)) { - - $GLOBALS['current_function'] = $name; - - foreach ($matches as $m) { - $GLOBALS['error_few_vars_given'] = false; - update_lineno($offset + $m[2][1]); - - $vars = get_vars(substr($txt, 0, $m[0][1])); // limit var search to current location - $params = get_params($vars, $m[2][0]); - $optional = $varargs = false; - $last_char = ''; - $j = -1; - - $spec = $m[1][0]; - $len = strlen($spec); - for ($i = 0; $i < $len; ++$i) { - $char = $spec[$i]; - switch ($char = $spec[$i]) { - // separator for optional parameters - case '|': - if ($optional) { - error("more than one optional separator at char #$i"); - } else { - $optional = true; - if ($i == $len-1) { - error("unnecessary optional separator"); - } - } - break; - - // separate_zval_if_not_ref - case '/': - if (in_array($last_char, array('l', 'L', 'd', 'b'))) { - error("the '/' specifier should not be applied to '$last_char'"); - } - break; - - // nullable arguments - case '!': - if (in_array($last_char, array('l', 'L', 'd', 'b'))) { - check_param($params, ++$j, 'zend_bool*', $optional); - } - break; - - // variadic arguments - case '+': - case '*': - if ($varargs) { - error("A varargs specifier can only be used once. repeated char at column $i"); - } else { - check_param($params, ++$j, 'zval**', $optional); - check_param($params, ++$j, 'int*', $optional); - $varargs = true; - } - break; - - case 's': - case 'p': - check_param($params, ++$j, 'char**', $optional, $allow_uninit=true); - check_param($params, ++$j, 'size_t*', $optional, $allow_uninit=true); - if ($optional && !$params[$j-1][2] && !$params[$j][2] - && $params[$j-1][0] !== '**dummy**' && $params[$j][0] !== '**dummy**') { - error("one of optional vars {$params[$j-1][0]} or {$params[$j][0]} must be initialized", 1); - } - break; - - case 'C': - // C must always be initialized, independently of whether it's optional - check_param($params, ++$j, 'zend_class_entry**', false); - break; - - default: - if (!isset($API_params[$char])) { - error("unknown char ('$char') at column $i"); - } - - // If an is_null flag is in use, only that flag is required to be - // initialized - $allow_uninit = $i+1 < $len && $spec[$i+1] === '!' - && in_array($char, array('l', 'L', 'd', 'b')); - - foreach ($API_params[$char] as $exp) { - check_param($params, ++$j, $exp, $optional, $allow_uninit); - } - } - - $last_char = $char; - } - } - } + global $API_params; + + $regex = '/ + (?: zend_parse_parameters(?:_throw)? \s*\([^,]+ + | zend_parse_(?:parameters_ex|method_parameters) \s*\([^,]+,[^,]+ + | zend_parse_method_parameters_ex \s*\([^,]+,[^,]+,[^,+] + ) + ,\s*"([^"]*)"\s* + ,\s*([^{;]*) + /Sx'; + if (preg_match_all($regex, $txt, $matches, PREG_SET_ORDER | PREG_OFFSET_CAPTURE)) { + + $GLOBALS['current_function'] = $name; + + foreach ($matches as $m) { + $GLOBALS['error_few_vars_given'] = false; + update_lineno($offset + $m[2][1]); + + $vars = get_vars(substr($txt, 0, $m[0][1])); // limit var search to current location + $params = get_params($vars, $m[2][0]); + $optional = $varargs = false; + $last_char = ''; + $j = -1; + + $spec = $m[1][0]; + $len = strlen($spec); + for ($i = 0; $i < $len; ++$i) { + $char = $spec[$i]; + switch ($char = $spec[$i]) { + // separator for optional parameters + case '|': + if ($optional) { + error("more than one optional separator at char #$i"); + } else { + $optional = true; + if ($i == $len-1) { + error("unnecessary optional separator"); + } + } + break; + + // separate_zval_if_not_ref + case '/': + if (in_array($last_char, array('l', 'L', 'd', 'b'))) { + error("the '/' specifier should not be applied to '$last_char'"); + } + break; + + // nullable arguments + case '!': + if (in_array($last_char, array('l', 'L', 'd', 'b'))) { + check_param($params, ++$j, 'zend_bool*', $optional); + } + break; + + // variadic arguments + case '+': + case '*': + if ($varargs) { + error("A varargs specifier can only be used once. repeated char at column $i"); + } else { + check_param($params, ++$j, 'zval**', $optional); + check_param($params, ++$j, 'int*', $optional); + $varargs = true; + } + break; + + case 's': + case 'p': + check_param($params, ++$j, 'char**', $optional, $allow_uninit=true); + check_param($params, ++$j, 'size_t*', $optional, $allow_uninit=true); + if ($optional && !$params[$j-1][2] && !$params[$j][2] + && $params[$j-1][0] !== '**dummy**' && $params[$j][0] !== '**dummy**') { + error("one of optional vars {$params[$j-1][0]} or {$params[$j][0]} must be initialized", 1); + } + break; + + case 'C': + // C must always be initialized, independently of whether it's optional + check_param($params, ++$j, 'zend_class_entry**', false); + break; + + default: + if (!isset($API_params[$char])) { + error("unknown char ('$char') at column $i"); + } + + // If an is_null flag is in use, only that flag is required to be + // initialized + $allow_uninit = $i+1 < $len && $spec[$i+1] === '!' + && in_array($char, array('l', 'L', 'd', 'b')); + + foreach ($API_params[$char] as $exp) { + check_param($params, ++$j, $exp, $optional, $allow_uninit); + } + } + + $last_char = $char; + } + } + } } /** the main recursion function. splits files in functions and calls the other functions */ function recurse($path) { - foreach (scandir($path) as $file) { - if ($file == '.' || $file == '..' || $file == 'CVS') continue; + foreach (scandir($path) as $file) { + if ($file == '.' || $file == '..' || $file == 'CVS') continue; - $file = "$path/$file"; - if (is_dir($file)) { - recurse($file); - continue; - } + $file = "$path/$file"; + if (is_dir($file)) { + recurse($file); + continue; + } - // parse only .c and .cpp files - if (substr_compare($file, '.c', -2) && substr_compare($file, '.cpp', -4)) continue; + // parse only .c and .cpp files + if (substr_compare($file, '.c', -2) && substr_compare($file, '.cpp', -4)) continue; - $txt = file_get_contents($file); - // remove comments (but preserve the number of lines) - $txt = preg_replace('@//.*@S', '', $txt); - $txt = preg_replace_callback('@/\*.*\*/@SsU', function($matches) { - return preg_replace("/[^\r\n]+/S", "", $matches[0]); - }, $txt); + $txt = file_get_contents($file); + // remove comments (but preserve the number of lines) + $txt = preg_replace('@//.*@S', '', $txt); + $txt = preg_replace_callback('@/\*.*\*/@SsU', function($matches) { + return preg_replace("/[^\r\n]+/S", "", $matches[0]); + }, $txt); - $split = preg_split('/PHP_(?:NAMED_)?(?:FUNCTION|METHOD)\s*\((\w+(?:,\s*\w+)?)\)/S', $txt, -1, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_OFFSET_CAPTURE); + $split = preg_split('/PHP_(?:NAMED_)?(?:FUNCTION|METHOD)\s*\((\w+(?:,\s*\w+)?)\)/S', $txt, -1, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_OFFSET_CAPTURE); - if (count($split) < 2) continue; // no functions defined on this file - array_shift($split); // the first part isn't relevant + if (count($split) < 2) continue; // no functions defined on this file + array_shift($split); // the first part isn't relevant - // generate the line offsets array - $j = 0; - $lines = preg_split("/(\r\n?|\n)/S", $txt, -1, PREG_SPLIT_DELIM_CAPTURE); - $lines_offset = array(); + // generate the line offsets array + $j = 0; + $lines = preg_split("/(\r\n?|\n)/S", $txt, -1, PREG_SPLIT_DELIM_CAPTURE); + $lines_offset = array(); - for ($i = 0; $i < count($lines); ++$i) { - $j += strlen($lines[$i]) + strlen(@$lines[++$i]); - $lines_offset[] = $j; - } + for ($i = 0; $i < count($lines); ++$i) { + $j += strlen($lines[$i]) + strlen(@$lines[++$i]); + $lines_offset[] = $j; + } - $GLOBALS['lines_offset'] = $lines_offset; - $GLOBALS['current_file'] = $file; + $GLOBALS['lines_offset'] = $lines_offset; + $GLOBALS['current_file'] = $file; - for ($i = 0; $i < count($split); $i+=2) { - // if the /* }}} */ comment is found use it to reduce false positives - // TODO: check the other indexes - list($f) = preg_split('@/\*\s*}}}\s*\*/@S', $split[$i+1][0]); - check_function(preg_replace('/\s*,\s*/S', '::', $split[$i][0]), $f, $split[$i][1]); - } - } + for ($i = 0; $i < count($split); $i+=2) { + // if the /* }}} */ comment is found use it to reduce false positives + // TODO: check the other indexes + list($f) = preg_split('@/\*\s*}}}\s*\*/@S', $split[$i+1][0]); + check_function(preg_replace('/\s*,\s*/S', '::', $split[$i][0]), $f, $split[$i][1]); + } + } } $dirs = array(); if (isset($argc) && $argc > 1) { - if ($argv[1] == '-h' || $argv[1] == '-help' || $argv[1] == '--help') { - echo <<<HELP + if ($argv[1] == '-h' || $argv[1] == '-help' || $argv[1] == '--help') { + echo <<<HELP Synopsis: php check_parameters.php [directories] HELP; - exit(0); - } - for ($i = 1; $i < $argc; $i++) { - $dirs[] = $argv[$i]; - } + exit(0); + } + for ($i = 1; $i < $argc; $i++) { + $dirs[] = $argv[$i]; + } } else { - $dirs[] = PHPDIR; + $dirs[] = PHPDIR; } foreach($dirs as $dir) { - if (is_dir($dir)) { - if (!is_readable($dir)) { - echo "ERROR: directory '", $dir ,"' is not readable\n"; - exit(1); - } - } else { - echo "ERROR: bogus directory '", $dir ,"'\n"; - exit(1); - } + if (is_dir($dir)) { + if (!is_readable($dir)) { + echo "ERROR: directory '", $dir ,"' is not readable\n"; + exit(1); + } + } else { + echo "ERROR: bogus directory '", $dir ,"'\n"; + exit(1); + } } foreach ($dirs as $dir) { - recurse(realpath($dir)); + recurse(realpath($dir)); } diff --git a/scripts/dev/find_tested.php b/scripts/dev/find_tested.php index 9368ad3796..3b18879d2f 100755 --- a/scripts/dev/find_tested.php +++ b/scripts/dev/find_tested.php @@ -201,27 +201,27 @@ function get_phpt_files($dir, &$phpt_file_count, &$all_phpt) * Extract tests from a specified file, returns an array of tested function tokens */ function extract_tests($file) { - $code = file_get_contents($file); + $code = file_get_contents($file); - if (!preg_match('/--FILE--\s*(.*)\s*--(EXPECTF|EXPECTREGEX|EXPECT)?--/is', $code, $r)) { - //print "Unable to get code in ".$file."\n"; - return array(); - } + if (!preg_match('/--FILE--\s*(.*)\s*--(EXPECTF|EXPECTREGEX|EXPECT)?--/is', $code, $r)) { + //print "Unable to get code in ".$file."\n"; + return array(); + } - $tokens = token_get_all($r[1]); - $functions = array_filter($tokens, 'filter_functions'); - $functions = array_map( 'map_token_value',$functions); - $functions = array_unique($functions); + $tokens = token_get_all($r[1]); + $functions = array_filter($tokens, 'filter_functions'); + $functions = array_map( 'map_token_value',$functions); + $functions = array_unique($functions); - return $functions; + return $functions; } function filter_functions($x) { - return $x[0] == 307; + return $x[0] == 307; } function map_token_value($x) { - return $x[1]; + return $x[1]; } diff --git a/scripts/dev/search_underscores.php b/scripts/dev/search_underscores.php index 5c2016e489..ff766bcf1f 100755 --- a/scripts/dev/search_underscores.php +++ b/scripts/dev/search_underscores.php @@ -34,38 +34,38 @@ $classes = array_merge(get_declared_classes(), get_declared_interfaces()); $extensions = array(); foreach(get_loaded_extensions() as $ext) { - $cnt_modules++; - if (strpos($ext, "_") !== false) { - $err++; - $extensions[$ext] = array(); - } + $cnt_modules++; + if (strpos($ext, "_") !== false) { + $err++; + $extensions[$ext] = array(); + } } $cnt_classes = count($classes); foreach($classes as $c) { - if (strpos($c, "_") !== false) { - $err++; - $ref = new ReflectionClass($c); - if (!($ext = $ref->getExtensionName())) {; - $ext = $ref->isInternal() ? "<internal>" : "<user>"; - } - if (!array_key_exists($ext, $extensions)) { - $extensions[$ext] = array(); - } - $extensions[$ext][$c] = array(); - foreach(get_class_methods($c) as $method) { - $cnt_methods++; - if (strpos(substr($method, substr($method, 0, 2) != "__" ? 0 : 2), "_") !== false) { - $err++; - $extensions[$ext][$c][] = $method; - } - } - } - else - { - $cnt_methods += count(get_class_methods($c)); - } + if (strpos($c, "_") !== false) { + $err++; + $ref = new ReflectionClass($c); + if (!($ext = $ref->getExtensionName())) {; + $ext = $ref->isInternal() ? "<internal>" : "<user>"; + } + if (!array_key_exists($ext, $extensions)) { + $extensions[$ext] = array(); + } + $extensions[$ext][$c] = array(); + foreach(get_class_methods($c) as $method) { + $cnt_methods++; + if (strpos(substr($method, substr($method, 0, 2) != "__" ? 0 : 2), "_") !== false) { + $err++; + $extensions[$ext][$c][] = $method; + } + } + } + else + { + $cnt_methods += count(get_class_methods($c)); + } } $cnt = $cnt_modules + $cnt_classes + $cnt_methods; @@ -81,15 +81,15 @@ printf("\n"); ksort($extensions); foreach($extensions as $ext => &$classes) { - echo "Extension: $ext\n"; - ksort($classes); - foreach($classes as $classname => &$methods) { - echo " Class: $classname\n"; - ksort($methods); - foreach($methods as $method) { - echo " Method: $method\n"; - } - } + echo "Extension: $ext\n"; + ksort($classes); + foreach($classes as $classname => &$methods) { + echo " Class: $classname\n"; + ksort($methods); + foreach($methods as $method) { + echo " Method: $method\n"; + } + } } printf("\n"); diff --git a/win32/build/mkdist.php b/win32/build/mkdist.php index f4155308af..d5fb9d1e7b 100644 --- a/win32/build/mkdist.php +++ b/win32/build/mkdist.php @@ -31,136 +31,136 @@ $pecl_dll_deps = array(); function get_depends($module) { - static $no_dist = array( - /* windows system dlls that should not be bundled */ - 'advapi32.dll', 'comdlg32.dll', 'crypt32.dll', 'gdi32.dll', 'kernel32.dll', 'ntdll.dll', - 'odbc32.dll', 'ole32.dll', 'oleaut32.dll', 'rpcrt4.dll', - 'shell32.dll', 'shlwapi.dll', 'user32.dll', 'ws2_32.dll', 'ws2help.dll', - 'comctl32.dll', 'winmm.dll', 'wsock32.dll', 'winspool.drv', 'msasn1.dll', - 'secur32.dll', 'netapi32.dll', 'dnsapi.dll', 'psapi.dll', 'normaliz.dll', - 'iphlpapi.dll', 'bcrypt.dll', - - /* apache */ - 'apachecore.dll', - - /* apache 2 */ - 'libhttpd.dll', 'libapr.dll', 'libaprutil.dll','libapr-1.dll', 'libaprutil-1.dll', - - /* oracle */ - 'oci.dll', 'ociw32.dll', - - /* sybase */ - 'libcs.dll', 'libct.dll', - - /* firebird */ - 'fbclient.dll', - - /* visual C++; mscvrt.dll is present on everyones system, - * but the debug version (msvcrtd.dll) and those from visual studio.net - * (msvcrt7x.dll) are not */ - 'msvcrt.dll', - 'msvcr90.dll', - 'wldap32.dll', - 'vcruntime140.dll', - 'msvcp140.dll', - ); - static $no_dist_re = array( - "api-ms-win-crt-.+\.dll", - ); - global $build_dir, $extra_dll_deps, $ext_targets, $sapi_targets, $pecl_targets, $phpdll, $per_module_deps, $pecl_dll_deps; - - $bd = strtolower(realpath($build_dir)); - - $is_pecl = in_array($module, $pecl_targets); - - $cmd = "$GLOBALS[build_dir]\\deplister.exe \"$module\" \"$GLOBALS[build_dir]\""; - $proc = proc_open($cmd, - array(1 => array("pipe", "w")), - $pipes); - - $n = 0; - while (($line = fgetcsv($pipes[1]))) { - $n++; - - $dep = strtolower($line[0]); - $depbase = basename($dep); - /* ignore stuff in our build dir, but only if it is - * one of our targets */ - if (((in_array($depbase, $sapi_targets) || - in_array($depbase, $ext_targets) || in_array($depbase, $pecl_targets)) || - $depbase == $phpdll) && file_exists($GLOBALS['build_dir'] . "/$depbase")) { - continue; - } - /* ignore some well-known system dlls */ - if (in_array(basename($dep), $no_dist)) { - continue; - } else { - $skip = false; - foreach ($no_dist_re as $re) { - if (preg_match(",$re,", basename($dep)) > 0) { - $skip = true; - break; - } - } - if ($skip) { - continue; - } - } - - if ($is_pecl) { - if (!in_array($dep, $pecl_dll_deps)) { - $pecl_dll_deps[] = $dep; - } - } else { - if (!in_array($dep, $extra_dll_deps)) { - $extra_dll_deps[] = $dep; - } - } - - if (!isset($per_module_deps[basename($module)]) || !in_array($dep, $per_module_deps[basename($module)])) { - $per_module_deps[basename($module)][] = $dep; - //recursively check dll dependencies - get_depends($dep); - } - } - fclose($pipes[1]); - proc_close($proc); + static $no_dist = array( + /* windows system dlls that should not be bundled */ + 'advapi32.dll', 'comdlg32.dll', 'crypt32.dll', 'gdi32.dll', 'kernel32.dll', 'ntdll.dll', + 'odbc32.dll', 'ole32.dll', 'oleaut32.dll', 'rpcrt4.dll', + 'shell32.dll', 'shlwapi.dll', 'user32.dll', 'ws2_32.dll', 'ws2help.dll', + 'comctl32.dll', 'winmm.dll', 'wsock32.dll', 'winspool.drv', 'msasn1.dll', + 'secur32.dll', 'netapi32.dll', 'dnsapi.dll', 'psapi.dll', 'normaliz.dll', + 'iphlpapi.dll', 'bcrypt.dll', + + /* apache */ + 'apachecore.dll', + + /* apache 2 */ + 'libhttpd.dll', 'libapr.dll', 'libaprutil.dll','libapr-1.dll', 'libaprutil-1.dll', + + /* oracle */ + 'oci.dll', 'ociw32.dll', + + /* sybase */ + 'libcs.dll', 'libct.dll', + + /* firebird */ + 'fbclient.dll', + + /* visual C++; mscvrt.dll is present on everyones system, + * but the debug version (msvcrtd.dll) and those from visual studio.net + * (msvcrt7x.dll) are not */ + 'msvcrt.dll', + 'msvcr90.dll', + 'wldap32.dll', + 'vcruntime140.dll', + 'msvcp140.dll', + ); + static $no_dist_re = array( + "api-ms-win-crt-.+\.dll", + ); + global $build_dir, $extra_dll_deps, $ext_targets, $sapi_targets, $pecl_targets, $phpdll, $per_module_deps, $pecl_dll_deps; + + $bd = strtolower(realpath($build_dir)); + + $is_pecl = in_array($module, $pecl_targets); + + $cmd = "$GLOBALS[build_dir]\\deplister.exe \"$module\" \"$GLOBALS[build_dir]\""; + $proc = proc_open($cmd, + array(1 => array("pipe", "w")), + $pipes); + + $n = 0; + while (($line = fgetcsv($pipes[1]))) { + $n++; + + $dep = strtolower($line[0]); + $depbase = basename($dep); + /* ignore stuff in our build dir, but only if it is + * one of our targets */ + if (((in_array($depbase, $sapi_targets) || + in_array($depbase, $ext_targets) || in_array($depbase, $pecl_targets)) || + $depbase == $phpdll) && file_exists($GLOBALS['build_dir'] . "/$depbase")) { + continue; + } + /* ignore some well-known system dlls */ + if (in_array(basename($dep), $no_dist)) { + continue; + } else { + $skip = false; + foreach ($no_dist_re as $re) { + if (preg_match(",$re,", basename($dep)) > 0) { + $skip = true; + break; + } + } + if ($skip) { + continue; + } + } + + if ($is_pecl) { + if (!in_array($dep, $pecl_dll_deps)) { + $pecl_dll_deps[] = $dep; + } + } else { + if (!in_array($dep, $extra_dll_deps)) { + $extra_dll_deps[] = $dep; + } + } + + if (!isset($per_module_deps[basename($module)]) || !in_array($dep, $per_module_deps[basename($module)])) { + $per_module_deps[basename($module)][] = $dep; + //recursively check dll dependencies + get_depends($dep); + } + } + fclose($pipes[1]); + proc_close($proc); //echo "Module $module [$n lines]\n"; } function copy_file_list($source_dir, $dest_dir, $list) { - global $is_debug, $dist_dir; - - foreach ($list as $item) { - if (empty($item)) { - continue; - } elseif (!is_file($source_dir . DIRECTORY_SEPARATOR . $item)) { - echo "WARNING: $item not found\n"; - continue; - } - - echo "Copying $item from $source_dir to $dest_dir\n"; - copy($source_dir . DIRECTORY_SEPARATOR . $item, $dest_dir . DIRECTORY_SEPARATOR . $item); - if ($is_debug) { - $itemdb = preg_replace("/\.(exe|dll|lib)$/i", ".pdb", $item); - if (file_exists("$source_dir/$itemdb")) { - copy("$source_dir/$itemdb", "$dist_dir/dev/$itemdb"); - } - } - if (preg_match("/\.(exe|dll)$/i", $item)) { - get_depends($source_dir . '/' . $item); - } - } + global $is_debug, $dist_dir; + + foreach ($list as $item) { + if (empty($item)) { + continue; + } elseif (!is_file($source_dir . DIRECTORY_SEPARATOR . $item)) { + echo "WARNING: $item not found\n"; + continue; + } + + echo "Copying $item from $source_dir to $dest_dir\n"; + copy($source_dir . DIRECTORY_SEPARATOR . $item, $dest_dir . DIRECTORY_SEPARATOR . $item); + if ($is_debug) { + $itemdb = preg_replace("/\.(exe|dll|lib)$/i", ".pdb", $item); + if (file_exists("$source_dir/$itemdb")) { + copy("$source_dir/$itemdb", "$dist_dir/dev/$itemdb"); + } + } + if (preg_match("/\.(exe|dll)$/i", $item)) { + get_depends($source_dir . '/' . $item); + } + } } function copy_text_file($source, $dest) { - $text = file_get_contents($source); - $text = preg_replace("/(\r\n?)|\n/", "\r\n", $text); - $fp = fopen($dest, "w"); - fwrite($fp, $text); - fclose($fp); + $text = file_get_contents($source); + $text = preg_replace("/(\r\n?)|\n/", "\r\n", $text); + $fp = fopen($dest, "w"); + fwrite($fp, $text); + fclose($fp); } /* very light-weight function to extract a single named file from @@ -168,57 +168,57 @@ function copy_text_file($source, $dest) * based on the PEAR info set in $packages. */ function extract_file_from_tarball($pkg, $filename, $dest_dir) /* {{{ */ { - global $packages; - - $name = $pkg . '-' . $packages[$pkg]; - $tarball = $dest_dir . "/" . $name . '.tgz'; - $filename = $name . '/' . $filename; - $destfilename = $dest_dir . "/" . basename($filename); - - $fp = gzopen($tarball, 'rb'); - - $done = false; - do { - /* read the header */ - $hdr_data = gzread($fp, 512); - if (strlen($hdr_data) == 0) - break; - $checksum = 0; - for ($i = 0; $i < 148; $i++) - $checksum += ord($hdr_data{$i}); - for ($i = 148; $i < 156; $i++) - $checksum += 32; - for ($i = 156; $i < 512; $i++) - $checksum += ord($hdr_data{$i}); - - $hdr = unpack("a100filename/a8mode/a8uid/a8gid/a12size/a12mtime/a8checksum/a1typeflag/a100link/a6magic/a2version/a32uname/a32gname/a8devmajor/a8devminor", $hdr_data); - - $hdr['checksum'] = octdec(trim($hdr['checksum'])); - - if ($hdr['checksum'] != $checksum) { - echo "Checksum for $tarball $hdr[filename] is invalid\n"; - print_r($hdr); - return; - } - - $hdr['size'] = octdec(trim($hdr['size'])); - echo "File: $hdr[filename] $hdr[size]\n"; - - if ($filename == $hdr['filename']) { - echo "Found the file we want\n"; - $dest = fopen($destfilename, 'wb'); - $x = stream_copy_to_stream($fp, $dest, $hdr['size']); - fclose($dest); - echo "Wrote $x bytes into $destfilename\n"; - break; - } - - /* skip body of the file */ - $size = 512 * ceil((int)$hdr['size'] / 512); - echo "Skipping $size bytes\n"; - gzseek($fp, gztell($fp) + $size); - - } while (!$done); + global $packages; + + $name = $pkg . '-' . $packages[$pkg]; + $tarball = $dest_dir . "/" . $name . '.tgz'; + $filename = $name . '/' . $filename; + $destfilename = $dest_dir . "/" . basename($filename); + + $fp = gzopen($tarball, 'rb'); + + $done = false; + do { + /* read the header */ + $hdr_data = gzread($fp, 512); + if (strlen($hdr_data) == 0) + break; + $checksum = 0; + for ($i = 0; $i < 148; $i++) + $checksum += ord($hdr_data{$i}); + for ($i = 148; $i < 156; $i++) + $checksum += 32; + for ($i = 156; $i < 512; $i++) + $checksum += ord($hdr_data{$i}); + + $hdr = unpack("a100filename/a8mode/a8uid/a8gid/a12size/a12mtime/a8checksum/a1typeflag/a100link/a6magic/a2version/a32uname/a32gname/a8devmajor/a8devminor", $hdr_data); + + $hdr['checksum'] = octdec(trim($hdr['checksum'])); + + if ($hdr['checksum'] != $checksum) { + echo "Checksum for $tarball $hdr[filename] is invalid\n"; + print_r($hdr); + return; + } + + $hdr['size'] = octdec(trim($hdr['size'])); + echo "File: $hdr[filename] $hdr[size]\n"; + + if ($filename == $hdr['filename']) { + echo "Found the file we want\n"; + $dest = fopen($destfilename, 'wb'); + $x = stream_copy_to_stream($fp, $dest, $hdr['size']); + fclose($dest); + echo "Wrote $x bytes into $destfilename\n"; + break; + } + + /* skip body of the file */ + $size = 512 * ceil((int)$hdr['size'] / 512); + echo "Skipping $size bytes\n"; + gzseek($fp, gztell($fp) + $size); + + } while (!$done); } /* }}} */ @@ -233,8 +233,8 @@ $phplib = str_replace(".dll", ".lib", $phpdll); copy("$build_dir/$phplib", "$dist_dir/dev/$phplib"); /* debug builds; copy the symbols too */ if ($is_debug) { - $phppdb = str_replace(".dll", ".pdb", $phpdll); - copy("$build_dir/$phppdb", "$dist_dir/dev/$phppdb"); + $phppdb = str_replace(".dll", ".pdb", $phpdll); + copy("$build_dir/$phppdb", "$dist_dir/dev/$phppdb"); } /* copy the sapi */ copy_file_list($build_dir, "$dist_dir", $sapi_targets); @@ -244,30 +244,30 @@ copy_file_list($build_dir, "$dist_dir/ext", $ext_targets); /* pecl sapi and extensions */ if(sizeof($pecl_targets)) { - copy_file_list($build_dir, $pecl_dir, $pecl_targets); + copy_file_list($build_dir, $pecl_dir, $pecl_targets); } /* populate reading material */ $text_files = array( - "LICENSE" => "license.txt", - "NEWS" => "news.txt", - "README.md" => "README.md", - "README.REDIST.BINS" => "readme-redist-bins.txt", - "php.ini-development" => "php.ini-development", - "php.ini-production" => "php.ini-production" + "LICENSE" => "license.txt", + "NEWS" => "news.txt", + "README.md" => "README.md", + "README.REDIST.BINS" => "readme-redist-bins.txt", + "php.ini-development" => "php.ini-development", + "php.ini-production" => "php.ini-production" ); foreach ($text_files as $src => $dest) { - copy_text_file($src, $dist_dir . '/' . $dest); + copy_text_file($src, $dist_dir . '/' . $dest); } /* general other files */ $general_files = array( - "$GLOBALS[build_dir]\\deplister.exe" => "deplister.exe", + "$GLOBALS[build_dir]\\deplister.exe" => "deplister.exe", ); foreach ($general_files as $src => $dest) { - copy($src, $dist_dir . '/' . $dest); + copy($src, $dist_dir . '/' . $dest); } /* include a snapshot identifier */ @@ -289,40 +289,40 @@ $exts = get_loaded_extensions(); fprintf($fp, "\r\nBuilt-in Extensions\r\n"); fwrite($fp, "===========================\r\n"); foreach ($exts as $ext) { - fprintf($fp, "%s\r\n", $ext); + fprintf($fp, "%s\r\n", $ext); } fwrite($fp, "\r\n\r\n"); /* list dependencies */ fprintf($fp, "Dependency information:\r\n"); foreach ($per_module_deps as $modulename => $deps) { - if (in_array($modulename, $pecl_targets)) - continue; - - fprintf($fp, "Module: %s\r\n", $modulename); - fwrite($fp, "===========================\r\n"); - foreach ($deps as $dll) { - fprintf($fp, "\t%s\r\n", basename($dll)); - } - fwrite($fp, "\r\n"); + if (in_array($modulename, $pecl_targets)) + continue; + + fprintf($fp, "Module: %s\r\n", $modulename); + fwrite($fp, "===========================\r\n"); + foreach ($deps as $dll) { + fprintf($fp, "\t%s\r\n", basename($dll)); + } + fwrite($fp, "\r\n"); } fclose($fp); /* Now add those dependencies */ foreach ($extra_dll_deps as $dll) { - if (!file_exists($dll)) { - /* try template dir */ - $tdll = $snapshot_template . "/dlls/" . basename($dll); - if (!file_exists($tdll)) { - $tdll = $php_build_dir . '/bin/' . basename($dll); - if (!file_exists($tdll)) { - echo "WARNING: distro depends on $dll, but could not find it on your system\n"; - continue; - } - } - $dll = $tdll; - } - copy($dll, "$dist_dir/" . basename($dll)); + if (!file_exists($dll)) { + /* try template dir */ + $tdll = $snapshot_template . "/dlls/" . basename($dll); + if (!file_exists($tdll)) { + $tdll = $php_build_dir . '/bin/' . basename($dll); + if (!file_exists($tdll)) { + echo "WARNING: distro depends on $dll, but could not find it on your system\n"; + continue; + } + } + $dll = $tdll; + } + copy($dll, "$dist_dir/" . basename($dll)); } /* TODO: @@ -333,168 +333,168 @@ deps. For example, libenchant.dll loads libenchant_myspell.dll or libenchant_ispell.dll */ $ENCHANT_DLLS = array( - array('', 'glib-2.dll'), - array('', 'gmodule-2.dll'), - array('lib/enchant', 'libenchant_myspell.dll'), - array('lib/enchant', 'libenchant_ispell.dll'), + array('', 'glib-2.dll'), + array('', 'gmodule-2.dll'), + array('lib/enchant', 'libenchant_myspell.dll'), + array('lib/enchant', 'libenchant_ispell.dll'), ); foreach ($ENCHANT_DLLS as $dll) { - $dest = "$dist_dir/$dll[0]"; - $filename = $dll[1]; - - if (!file_exists("$dest") || !is_dir("$dest")) { - if (!mkdir("$dest", 0777, true)) { - echo "WARNING: couldn't create '$dest' for enchant plugins "; - } - } - - if (!copy($php_build_dir . '/bin/' . $filename, "$dest/" . basename($filename))) { - echo "WARNING: couldn't copy $filename into the dist dir"; - } + $dest = "$dist_dir/$dll[0]"; + $filename = $dll[1]; + + if (!file_exists("$dest") || !is_dir("$dest")) { + if (!mkdir("$dest", 0777, true)) { + echo "WARNING: couldn't create '$dest' for enchant plugins "; + } + } + + if (!copy($php_build_dir . '/bin/' . $filename, "$dest/" . basename($filename))) { + echo "WARNING: couldn't copy $filename into the dist dir"; + } } $SASL_DLLS = $php_build_dir . "/bin/sasl2/sasl*.dll"; $fls = glob($SASL_DLLS); if (!empty($fls)) { - $sasl_dest_dir = "$dist_dir/sasl2"; - if (!file_exists($sasl_dest_dir) || !is_dir($sasl_dest_dir)) { - if (!mkdir("$sasl_dest_dir", 0777, true)) { - echo "WARNING: couldn't create '$sasl_dest_dir' for SASL2 auth plugins "; - } - } - foreach ($fls as $fl) { - if (!copy($fl, "$sasl_dest_dir/" . basename($fl))) { - echo "WARNING: couldn't copy $fl into the $sasl_dest_dir"; - } - } + $sasl_dest_dir = "$dist_dir/sasl2"; + if (!file_exists($sasl_dest_dir) || !is_dir($sasl_dest_dir)) { + if (!mkdir("$sasl_dest_dir", 0777, true)) { + echo "WARNING: couldn't create '$sasl_dest_dir' for SASL2 auth plugins "; + } + } + foreach ($fls as $fl) { + if (!copy($fl, "$sasl_dest_dir/" . basename($fl))) { + echo "WARNING: couldn't copy $fl into the $sasl_dest_dir"; + } + } } /* and those for pecl */ foreach ($pecl_dll_deps as $dll) { - if (in_array($dll, $extra_dll_deps)) { - /* already in main distro */ - continue; - } - if (!file_exists($dll)) { - /* try template dir */ - $tdll = $snapshot_template . "/dlls/" . basename($dll); - if (!file_exists($tdll)) { - echo "WARNING: distro depends on $dll, but could not find it on your system\n"; - continue; - } - $dll = $tdll; - } - copy($dll, "$pecl_dir/" . basename($dll)); + if (in_array($dll, $extra_dll_deps)) { + /* already in main distro */ + continue; + } + if (!file_exists($dll)) { + /* try template dir */ + $tdll = $snapshot_template . "/dlls/" . basename($dll); + if (!file_exists($tdll)) { + echo "WARNING: distro depends on $dll, but could not find it on your system\n"; + continue; + } + $dll = $tdll; + } + copy($dll, "$pecl_dir/" . basename($dll)); } function copy_dir($source, $dest) { - if (!is_dir($dest)) { - if (!mkdir($dest)) { - return false; - } - } - - $d = opendir($source); - while (($f = readdir($d)) !== false) { - if ($f == '.' || $f == '..' || $f == '.svn') { - continue; - } - $fs = $source . '/' . $f; - $fd = $dest . '/' . $f; - if (is_dir($fs)) { - copy_dir($fs, $fd); - } else { - copy($fs, $fd); - } - } - closedir($d); + if (!is_dir($dest)) { + if (!mkdir($dest)) { + return false; + } + } + + $d = opendir($source); + while (($f = readdir($d)) !== false) { + if ($f == '.' || $f == '..' || $f == '.svn') { + continue; + } + $fs = $source . '/' . $f; + $fd = $dest . '/' . $f; + if (is_dir($fs)) { + copy_dir($fs, $fd); + } else { + copy($fs, $fd); + } + } + closedir($d); } function copy_test_dir($directory, $dest) { - if(substr($directory,-1) == '/') { - $directory = substr($directory,0,-1); - } - - if ($directory == 'tests' || $directory == 'examples') { - if (!is_dir($dest . '/tests')) { - mkdir($dest . '/tests', 0775, true); - } - copy_dir($directory, $dest . '/tests/'); - - return false; - } - - if(!file_exists($directory) || !is_dir($directory)) { - echo "failed... $directory\n"; - return FALSE; - } - - $directory_list = opendir($directory); - - while (FALSE !== ($file = readdir($directory_list))) { - $full_path = $directory . '/' . $file; - if($file != '.' && $file != '..' && $file != '.svn' && is_dir($full_path)) { - if ($file == 'tests' || $file == 'examples') { - if (!is_dir($dest . '/' . $full_path)) { - mkdir($dest . '/' . $full_path , 0775, true); - } - copy_dir($full_path, $dest . '/' . $full_path . '/'); - continue; - } else { - copy_test_dir($full_path, $dest); - } - } - } - - closedir($directory_list); + if(substr($directory,-1) == '/') { + $directory = substr($directory,0,-1); + } + + if ($directory == 'tests' || $directory == 'examples') { + if (!is_dir($dest . '/tests')) { + mkdir($dest . '/tests', 0775, true); + } + copy_dir($directory, $dest . '/tests/'); + + return false; + } + + if(!file_exists($directory) || !is_dir($directory)) { + echo "failed... $directory\n"; + return FALSE; + } + + $directory_list = opendir($directory); + + while (FALSE !== ($file = readdir($directory_list))) { + $full_path = $directory . '/' . $file; + if($file != '.' && $file != '..' && $file != '.svn' && is_dir($full_path)) { + if ($file == 'tests' || $file == 'examples') { + if (!is_dir($dest . '/' . $full_path)) { + mkdir($dest . '/' . $full_path , 0775, true); + } + copy_dir($full_path, $dest . '/' . $full_path . '/'); + continue; + } else { + copy_test_dir($full_path, $dest); + } + } + } + + closedir($directory_list); } function make_phar_dot_phar($dist_dir) { - if (!extension_loaded('phar')) { - return; - } + if (!extension_loaded('phar')) { + return; + } - $path_to_phar = realpath(__DIR__ . '/../../ext/phar'); + $path_to_phar = realpath(__DIR__ . '/../../ext/phar'); - echo "Generating pharcommand.phar\n"; - $phar = new Phar($dist_dir . '/pharcommand.phar', 0, 'pharcommand'); + echo "Generating pharcommand.phar\n"; + $phar = new Phar($dist_dir . '/pharcommand.phar', 0, 'pharcommand'); - foreach (new DirectoryIterator($path_to_phar . '/phar') as $file) { - if ($file->isDir() || $file == 'phar.php') { - continue; - } + foreach (new DirectoryIterator($path_to_phar . '/phar') as $file) { + if ($file->isDir() || $file == 'phar.php') { + continue; + } - echo 'adding ', $file, "\n"; - $phar[(string) $file] = file_get_contents($path_to_phar. '/phar/' . $file); - } + echo 'adding ', $file, "\n"; + $phar[(string) $file] = file_get_contents($path_to_phar. '/phar/' . $file); + } - $phar->setSignatureAlgorithm(Phar::SHA1); - $stub = file($path_to_phar . '/phar/phar.php'); + $phar->setSignatureAlgorithm(Phar::SHA1); + $stub = file($path_to_phar . '/phar/phar.php'); - unset($stub[0]); // remove hashbang - $phar->setStub(implode('', $stub)); + unset($stub[0]); // remove hashbang + $phar->setStub(implode('', $stub)); - echo "Creating phar.phar.bat\n"; - file_put_contents($dist_dir . '/phar.phar.bat', "\"%~dp0php.exe\" \"%~dp0pharcommand.phar\" %*\r\n"); + echo "Creating phar.phar.bat\n"; + file_put_contents($dist_dir . '/phar.phar.bat', "\"%~dp0php.exe\" \"%~dp0pharcommand.phar\" %*\r\n"); } if (!is_dir($test_dir)) { - mkdir($test_dir); + mkdir($test_dir); } $dirs = array( - 'ext', - 'Sapi', - 'Zend', - 'tests' + 'ext', + 'Sapi', + 'Zend', + 'tests' ); foreach ($dirs as $dir) { - copy_test_dir($dir, $test_dir); + copy_test_dir($dir, $test_dir); } copy('run-tests.php', $test_dir . '/run-test.php'); @@ -503,82 +503,82 @@ copy('run-tests.php', $test_dir . '/run-test.php'); $use_pear_template = true; if (!$use_pear_template) { - /* Let's do a PEAR-less pear setup */ - mkdir("$dist_dir/PEAR"); - mkdir("$dist_dir/PEAR/go-pear-bundle"); - - /* grab the bootstrap script */ - echo "Downloading go-pear\n"; - copy("https://pear.php.net/go-pear.phar", "$dist_dir/PEAR/go-pear.php"); - - /* import the package list -- sets $packages variable */ - include "pear/go-pear-list.php"; - - /* download the packages into the destination */ - echo "Fetching packages\n"; - - foreach ($packages as $name => $version) { - $filename = "$name-$version.tgz"; - $destfilename = "$dist_dir/PEAR/go-pear-bundle/$filename"; - if (file_exists($destfilename)) - continue; - $url = "http://pear.php.net/get/$filename"; - echo "Downloading $name from $url\n"; - flush(); - copy($url, $destfilename); - } - - echo "Download complete. Extracting bootstrap files\n"; - - /* Now, we want PEAR.php, Getopt.php (Console_Getopt) and Tar.php (Archive_Tar) - * broken out of the tarballs */ - extract_file_from_tarball('PEAR', 'PEAR.php', "$dist_dir/PEAR/go-pear-bundle"); - extract_file_from_tarball('Archive_Tar', 'Archive/Tar.php', "$dist_dir/PEAR/go-pear-bundle"); - extract_file_from_tarball('Console_Getopt', 'Console/Getopt.php', "$dist_dir/PEAR/go-pear-bundle"); + /* Let's do a PEAR-less pear setup */ + mkdir("$dist_dir/PEAR"); + mkdir("$dist_dir/PEAR/go-pear-bundle"); + + /* grab the bootstrap script */ + echo "Downloading go-pear\n"; + copy("https://pear.php.net/go-pear.phar", "$dist_dir/PEAR/go-pear.php"); + + /* import the package list -- sets $packages variable */ + include "pear/go-pear-list.php"; + + /* download the packages into the destination */ + echo "Fetching packages\n"; + + foreach ($packages as $name => $version) { + $filename = "$name-$version.tgz"; + $destfilename = "$dist_dir/PEAR/go-pear-bundle/$filename"; + if (file_exists($destfilename)) + continue; + $url = "http://pear.php.net/get/$filename"; + echo "Downloading $name from $url\n"; + flush(); + copy($url, $destfilename); + } + + echo "Download complete. Extracting bootstrap files\n"; + + /* Now, we want PEAR.php, Getopt.php (Console_Getopt) and Tar.php (Archive_Tar) + * broken out of the tarballs */ + extract_file_from_tarball('PEAR', 'PEAR.php', "$dist_dir/PEAR/go-pear-bundle"); + extract_file_from_tarball('Archive_Tar', 'Archive/Tar.php', "$dist_dir/PEAR/go-pear-bundle"); + extract_file_from_tarball('Console_Getopt', 'Console/Getopt.php', "$dist_dir/PEAR/go-pear-bundle"); } /* add extras from the template dir */ if (file_exists($snapshot_template)) { - $items = glob("$snapshot_template/*"); - print_r($items); - - foreach ($items as $item) { - $bi = basename($item); - if (is_dir($item)) { - if ($bi == 'dlls' || $bi == 'symbols') { - continue; - } else if ($bi == 'PEAR') { - if ($use_pear_template) { - /* copy to top level */ - copy_dir($item, "$dist_dir/$bi"); - } - } else { - /* copy that dir into extras */ - copy_dir($item, "$dist_dir/extras/$bi"); - } - } else { - if ($bi == 'go-pear.bat') { - /* copy to top level */ - copy($item, "$dist_dir/$bi"); - } else { - /* copy to extras */ - copy($item, "$dist_dir/extras/$bi"); - } - } - } - - /* copy c++ runtime */ - $items = glob("$snapshot_template/dlls/*.CRT"); - - foreach ($items as $item) { - $bi = basename($item); - if (is_dir($item)) { - copy_dir($item, "$dist_dir/$bi"); - copy_dir($item, "$dist_dir/ext/$bi"); - } - } + $items = glob("$snapshot_template/*"); + print_r($items); + + foreach ($items as $item) { + $bi = basename($item); + if (is_dir($item)) { + if ($bi == 'dlls' || $bi == 'symbols') { + continue; + } else if ($bi == 'PEAR') { + if ($use_pear_template) { + /* copy to top level */ + copy_dir($item, "$dist_dir/$bi"); + } + } else { + /* copy that dir into extras */ + copy_dir($item, "$dist_dir/extras/$bi"); + } + } else { + if ($bi == 'go-pear.bat') { + /* copy to top level */ + copy($item, "$dist_dir/$bi"); + } else { + /* copy to extras */ + copy($item, "$dist_dir/extras/$bi"); + } + } + } + + /* copy c++ runtime */ + $items = glob("$snapshot_template/dlls/*.CRT"); + + foreach ($items as $item) { + $bi = basename($item); + if (is_dir($item)) { + copy_dir($item, "$dist_dir/$bi"); + copy_dir($item, "$dist_dir/ext/$bi"); + } + } } else { - echo "WARNING: you don't have a snapshot template, your dist will not be complete\n"; + echo "WARNING: you don't have a snapshot template, your dist will not be complete\n"; } make_phar_dot_phar($dist_dir); diff --git a/win32/codepage.c b/win32/codepage.c index 48f60595b4..0543a057a5 100644 --- a/win32/codepage.c +++ b/win32/codepage.c @@ -110,7 +110,7 @@ PW32CP wchar_t *php_win32_cp_conv_ascii_to_w(const char* in, size_t in_len, size #if PHP_DEBUG size_t save_in_len = in_len; #endif - + assert(in && in_len ? in[in_len] == '\0' : 1); if (!in) { diff --git a/win32/ioutil.c b/win32/ioutil.c index 63645314dd..48e65d918f 100644 --- a/win32/ioutil.c +++ b/win32/ioutil.c @@ -1163,8 +1163,8 @@ PW32IO ssize_t php_win32_ioutil_readlink_w(const wchar_t *path, wchar_t *buf, si ret = php_win32_ioutil_readlink_int(h, buf, buf_len); - if (ret < 0) { - wchar_t target[PHP_WIN32_IOUTIL_MAXPATHLEN]; + if (ret < 0) { + wchar_t target[PHP_WIN32_IOUTIL_MAXPATHLEN]; size_t target_len; size_t offset = 0; diff --git a/win32/winutil.c b/win32/winutil.c index 578e66c074..c04664bab3 100644 --- a/win32/winutil.c +++ b/win32/winutil.c @@ -449,7 +449,7 @@ static zend_always_inline BOOL is_compatible(const char *name, BOOL is_smaller, free(err_txt); return FALSE; } - + DWORD major = img->FileHeader->OptionalHeader.MajorLinkerVersion; DWORD minor = img->FileHeader->OptionalHeader.MinorLinkerVersion; @@ -461,7 +461,7 @@ static zend_always_inline BOOL is_compatible(const char *name, BOOL is_smaller, is used with a newer CRT, but not the other way round. Otherwise, if the linker major version is not same, it is an error, as per the current knowledge. - + This check is to be extended as new VS versions come out. */ DWORD core_minor = (DWORD)(PHP_LINKER_MINOR/10); DWORD comp_minor = (DWORD)(minor/10); |