source: trunk/Decompiler.class.php @ 799

Last change on this file since 799 was 799, checked in by moo, 3 years ago

Decompiler: ?: and ? :

  • Property svn:eol-style set to native
File size: 69.1 KB
RevLine 
[1]1<?php
2
3define('INDENT', "\t");
4ini_set('error_reporting', E_ALL);
5
6function color($str, $color = 33)
7{
8    return "\x1B[{$color}m$str\x1B[0m";
9}
10
[737]11function str($code, $indent = '') // {{{
12{
[744]13    if (is_array($code)) {
14        $array = array();
15        foreach ($code as $key => $value) {
16            $array[$key] = str($value, $indent);
17        }
18        return $array;
19    }
[737]20    if (is_object($code)) {
[744]21        $code = foldToCode($code, $indent);
22        return $code->toCode($indent);
[737]23    }
24
25    return (string) $code;
26}
27// }}}
[744]28function foldToCode($src, $indent = '') // {{{ wrap or rewrap anything to Decompiler_Code
[1]29{
30    if (is_array($indent)) {
31        $indent = $indent['indent'];
32    }
33
[741]34    if (!is_object($src)) {
35        return new Decompiler_Code($src);
[1]36    }
37
[741]38    if (!method_exists($src, 'toCode')) {
39        var_dump($src);
40        exit('no toCode');
41    }
42    if (get_class($src) != 'Decompiler_Code') {
43        // rewrap it
44        $src = new Decompiler_Code($src->toCode($indent));
45    }
46
47    return $src;
[1]48}
49// }}}
50function value($value) // {{{
51{
52    $spec = xcache_get_special_value($value);
53    if (isset($spec)) {
54        $value = $spec;
55        if (!is_array($value)) {
56            // constant
57            return $value;
58        }
59    }
60
[737]61    if (is_a($value, 'Decompiler_Object')) {
[723]62        // use as is
63    }
64    else if (is_array($value)) {
[737]65        $value = new Decompiler_ConstArray($value);
[1]66    }
67    else {
[713]68        $value = new Decompiler_Value($value);
[1]69    }
70    return $value;
71}
72// }}}
[761]73function unquoteName_($str, $asVariableName, $indent = '') // {{{
[749]74{
75    $str = str($str, $indent);
[753]76    if (preg_match("!^'[\\w_][\\w\\d_\\\\]*'\$!", $str)) {
77        return str_replace('\\\\', '\\', substr($str, 1, -1));
[749]78    }
[761]79    else if ($asVariableName) {
[749]80        return "{" . $str . "}";
81    }
[753]82    else {
83        return $str;
84    }
[749]85}
86// }}}
[761]87function unquoteVariableName($str, $indent = '') // {{{
[753]88{
89    return unquoteName_($str, true, $indent);
90}
91// }}}
[749]92function unquoteName($str, $indent = '') // {{{
93{
[753]94    return unquoteName_($str, false, $indent);
[749]95}
96// }}}
[1]97class Decompiler_Object // {{{
98{
99}
100// }}}
101class Decompiler_Value extends Decompiler_Object // {{{
102{
103    var $value;
104
105    function Decompiler_Value($value = null)
106    {
107        $this->value = $value;
108    }
109
[732]110    function toCode($indent)
[1]111    {
[750]112        $code = var_export($this->value, true);
113        if (gettype($this->value) == 'string') {
114            switch ($this->value) {
115            case "\r":
116                return '"\\r"';
117            case "\n":
118                return '"\\n"';
119            case "\r\n":
120                return '"\\r\\n"';
121            }
122            $code = str_replace("\r\n", '\' . "\\r\\n" . \'', $code);
123            $code = str_replace("\r", '\' . "\\r" . \'', $code);
124            $code = str_replace("\n", '\' . "\\n" . \'', $code);
125        }
126        return $code;
[1]127    }
128}
129// }}}
130class Decompiler_Code extends Decompiler_Object // {{{
131{
132    var $src;
133
134    function Decompiler_Code($src)
135    {
[743]136        assert('isset($src)');
[1]137        $this->src = $src;
138    }
139
[732]140    function toCode($indent)
[1]141    {
[741]142        return $this->src;
[737]143    }
[1]144}
145// }}}
146class Decompiler_Binop extends Decompiler_Code // {{{
147{
148    var $opc;
149    var $op1;
150    var $op2;
151    var $parent;
152
153    function Decompiler_Binop($parent, $op1, $opc, $op2)
154    {
155        $this->parent = &$parent;
156        $this->opc = $opc;
157        $this->op1 = $op1;
158        $this->op2 = $op2;
159    }
160
[732]161    function toCode($indent)
[1]162    {
[757]163        $opstr = $this->parent->binops[$this->opc];
164
[799]165        if (is_a($this->op1, 'Decompiler_TriOp') || is_a($this->op1, 'Decompiler_Binop') && $this->op1->opc != $this->opc) {
166            $op1 = "(" . str($this->op1, $indent) . ")";
[1]167        }
[799]168        else {
169            $op1 = $this->op1;
[1]170        }
[757]171
[799]172        if (is_a($this->op2, 'Decompiler_TriOp') || is_a($this->op2, 'Decompiler_Binop') && $this->op2->opc != $this->opc && substr($opstr, -1) != '=') {
173            $op2 = "(" . str($this->op2, $indent) . ")";
174        }
175        else {
176            $op2 = $this->op2;
177        }
178
[757]179        if (str($op1) == '0' && ($this->opc == XC_ADD || $this->opc == XC_SUB)) {
180            return $opstr . str($op2, $indent);
181        }
182
[799]183        return str($op1, $indent) . ' ' . $opstr . ' ' . str($op2, $indent);
[1]184    }
185}
186// }}}
[799]187class Decompiler_TriOp extends Decompiler_Code // {{{
188{
189    var $condition;
190    var $trueValue;
191    var $falseValue;
192
193    function Decompiler_TriOp($condition, $trueValue, $falseValue)
194    {
195        $this->condition = $condition;
196        $this->trueValue = $trueValue;
197        $this->falseValue = $falseValue;
198    }
199
200    function toCode($indent)
201    {
202        $trueValue = $this->trueValue;
203        if (is_a($this->trueValue, 'Decompiler_TriOp')) {
204            $trueValue = "(" . str($trueValue, $indent) . ")";
205        }
206        $falseValue = $this->falseValue;
207        if (is_a($this->falseValue, 'Decompiler_TriOp')) {
208            $falseValue = "(" . str($falseValue, $indent) . ")";
209        }
210
211        return str($this->condition) . ' ? ' . str($trueValue) . ' : ' . str($falseValue);
212    }
213}
214// }}}
[1]215class Decompiler_Fetch extends Decompiler_Code // {{{
216{
217    var $src;
218    var $fetchType;
219
220    function Decompiler_Fetch($src, $type, $globalsrc)
221    {
222        $this->src = $src;
223        $this->fetchType = $type;
224        $this->globalsrc = $globalsrc;
225    }
226
[732]227    function toCode($indent)
[1]228    {
229        switch ($this->fetchType) {
230        case ZEND_FETCH_LOCAL:
231            return '$' . substr($this->src, 1, -1);
232        case ZEND_FETCH_STATIC:
[749]233            if (ZEND_ENGINE_2_3) {
234                // closure local variable?
235                return str($this->src);
236            }
[1]237            die('static fetch cant to string');
238        case ZEND_FETCH_GLOBAL:
239        case ZEND_FETCH_GLOBAL_LOCK:
240            return $this->globalsrc;
241        default:
242            var_dump($this->fetchType);
243            assert(0);
244        }
245    }
246}
247// }}}
248class Decompiler_Box // {{{
249{
250    var $obj;
251
252    function Decompiler_Box(&$obj)
253    {
254        $this->obj = &$obj;
255    }
256
[732]257    function toCode($indent)
[1]258    {
[732]259        return $this->obj->toCode($indent);
[1]260    }
261}
262// }}}
263class Decompiler_Dim extends Decompiler_Value // {{{
264{
265    var $offsets = array();
266    var $isLast = false;
[749]267    var $isObject = false;
[1]268    var $assign = null;
269
[732]270    function toCode($indent)
[1]271    {
272        if (is_a($this->value, 'Decompiler_ListBox')) {
[749]273            $exp = str($this->value->obj->src, $indent);
[1]274        }
275        else {
[749]276            $exp = str($this->value, $indent);
[1]277        }
[749]278        $last = count($this->offsets) - 1;
279        foreach ($this->offsets as $i => $dim) {
280            if ($this->isObject && $i == $last) {
[761]281                $exp .= '->' . unquoteVariableName($dim, $indent);
[749]282            }
283            else {
284                $exp .= '[' . str($dim, $indent) . ']';
285            }
[1]286        }
287        return $exp;
288    }
289}
290// }}}
291class Decompiler_DimBox extends Decompiler_Box // {{{
292{
293}
294// }}}
295class Decompiler_List extends Decompiler_Code // {{{
296{
297    var $src;
298    var $dims = array();
299    var $everLocked = false;
300
[732]301    function toCode($indent)
[1]302    {
303        if (count($this->dims) == 1 && !$this->everLocked) {
304            $dim = $this->dims[0];
305            unset($dim->value);
306            $dim->value = $this->src;
307            if (!isset($dim->assign)) {
[754]308                return str($dim, $indent);
[1]309            }
[754]310            return str($this->dims[0]->assign, $indent) . ' = ' . str($dim, $indent);
[1]311        }
312        /* flatten dims */
313        $assigns = array();
314        foreach ($this->dims as $dim) {
315            $assign = &$assigns;
316            foreach ($dim->offsets as $offset) {
317                $assign = &$assign[$offset];
318            }
[744]319            $assign = foldToCode($dim->assign, $indent);
[1]320        }
[754]321        return str($this->toList($assigns)) . ' = ' . str($this->src, $indent);
[1]322    }
323
324    function toList($assigns)
325    {
326        $keys = array_keys($assigns);
327        if (count($keys) < 2) {
328            $keys[] = 0;
329        }
330        $max = call_user_func_array('max', $keys);
331        $list = 'list(';
332        for ($i = 0; $i <= $max; $i ++) {
333            if ($i) {
334                $list .= ', ';
335            }
336            if (!isset($assigns[$i])) {
337                continue;
338            }
339            if (is_array($assigns[$i])) {
340                $list .= $this->toList($assigns[$i]);
341            }
342            else {
343                $list .= $assigns[$i];
344            }
345        }
346        return $list . ')';
347    }
348}
349// }}}
350class Decompiler_ListBox extends Decompiler_Box // {{{
351{
352}
353// }}}
354class Decompiler_Array extends Decompiler_Value // {{{
355{
[737]356    // emenets
357    function Decompiler_Array()
[1]358    {
[737]359        $this->value = array();
[1]360    }
361
[732]362    function toCode($indent)
[1]363    {
[737]364        $subindent = $indent . INDENT;
365
366        $elementsCode = array();
367        $index = 0;
368        foreach ($this->value as $element) {
369            list($key, $value) = $element;
370            if (!isset($key)) {
371                $key = $index++;
372            }
373            $elementsCode[] = array(str($key, $subindent), str($value, $subindent), $key, $value);
374        }
375
[1]376        $exp = "array(";
[732]377        $indent = $indent . INDENT;
[735]378        $assocWidth = 0;
[1]379        $multiline = 0;
380        $i = 0;
[737]381        foreach ($elementsCode as $element) {
382            list($keyCode, $valueCode) = $element;
383            if ((string) $i !== $keyCode) {
[735]384                $assocWidth = 1;
[737]385                break;
[735]386            }
387            ++$i;
388        }
[737]389        foreach ($elementsCode as $element) {
390            list($keyCode, $valueCode, $key, $value) = $element;
[735]391            if ($assocWidth) {
[737]392                $len = strlen($keyCode);
[735]393                if ($assocWidth < $len) {
394                    $assocWidth = $len;
[1]395                }
396            }
[737]397            if (is_array($value) || is_a($value, 'Decompiler_Array')) {
[1]398                $multiline ++;
399            }
400        }
401
402        $i = 0;
[737]403        foreach ($elementsCode as $element) {
404            list($keyCode, $value) = $element;
[1]405            if ($multiline) {
406                if ($i) {
407                    $exp .= ",";
408                }
409                $exp .= "\n";
410                $exp .= $indent;
411            }
412            else {
413                if ($i) {
414                    $exp .= ", ";
415                }
416            }
417
[735]418            if ($assocWidth) {
419                if ($multiline) {
[737]420                    $exp .= sprintf("%-{$assocWidth}s => ", $keyCode);
[735]421                }
422                else {
[737]423                    $exp .= $keyCode . ' => ';
[735]424                }
[1]425            }
426
[737]427            $exp .= $value;
[1]428
429            $i ++;
430        }
431        if ($multiline) {
[732]432            $exp .= "\n$indent)";
[1]433        }
434        else {
435            $exp .= ")";
436        }
437        return $exp;
438    }
439}
440// }}}
[737]441class Decompiler_ConstArray extends Decompiler_Array // {{{
442{
443    function Decompiler_ConstArray($array)
444    {
445        $elements = array();
446        foreach ($array as $key => $value) {
447            $elements[] = array(value($key), value($value));
448        }
449        $this->value = $elements;
450    }
451}
452// }}}
[1]453class Decompiler_ForeachBox extends Decompiler_Box // {{{
454{
455    var $iskey;
456
[732]457    function toCode($indent)
[1]458    {
459        return 'foreach (' . '';
460    }
461}
462// }}}
463
464class Decompiler
465{
[753]466    var $namespace;
467    var $namespaceDecided;
[1]468
469    function Decompiler()
470    {
[761]471        // {{{ testing
472        // XC_UNDEF XC_OP_DATA
473        $this->test = !empty($_ENV['XCACHE_DECOMPILER_TEST']);
474        $this->usedOps = array();
475
476        if ($this->test) {
477            $content = file_get_contents(__FILE__);
478            for ($i = 0; $opname = xcache_get_opcode($i); $i ++) {
479                if (!preg_match("/\\bXC_" . $opname . "\\b(?!')/", $content)) {
480                    echo "not recognized opcode ", $opname, "\n";
481                }
482            }
483        }
484        // }}}
[1]485        // {{{ opinfo
486        $this->unaryops = array(
487                XC_BW_NOT   => '~',
488                XC_BOOL_NOT => '!',
489                );
490        $this->binops = array(
491                XC_ADD                 => "+",
492                XC_ASSIGN_ADD          => "+=",
493                XC_SUB                 => "-",
494                XC_ASSIGN_SUB          => "-=",
495                XC_MUL                 => "*",
496                XC_ASSIGN_MUL          => "*=",
497                XC_DIV                 => "/",
498                XC_ASSIGN_DIV          => "/=",
499                XC_MOD                 => "%",
500                XC_ASSIGN_MOD          => "%=",
501                XC_SL                  => "<<",
502                XC_ASSIGN_SL           => "<<=",
503                XC_SR                  => ">>",
504                XC_ASSIGN_SR           => ">>=",
505                XC_CONCAT              => ".",
506                XC_ASSIGN_CONCAT       => ".=",
507                XC_IS_IDENTICAL        => "===",
508                XC_IS_NOT_IDENTICAL    => "!==",
509                XC_IS_EQUAL            => "==",
510                XC_IS_NOT_EQUAL        => "!=",
511                XC_IS_SMALLER          => "<",
512                XC_IS_SMALLER_OR_EQUAL => "<=",
513                XC_BW_OR               => "|",
514                XC_ASSIGN_BW_OR        => "|=",
515                XC_BW_AND              => "&",
516                XC_ASSIGN_BW_AND       => "&=",
517                XC_BW_XOR              => "^",
518                XC_ASSIGN_BW_XOR       => "^=",
519                XC_BOOL_XOR            => "xor",
[799]520                XC_JMP_SET             => "?:",
[1]521                );
522        // }}}
523        $this->includeTypes = array( // {{{
524                ZEND_EVAL         => 'eval',
525                ZEND_INCLUDE      => 'include',
526                ZEND_INCLUDE_ONCE => 'include_once',
527                ZEND_REQUIRE      => 'require',
528                ZEND_REQUIRE_ONCE => 'require_once',
529                );
530                // }}}
531    }
[753]532    function detectNamespace($name) // {{{
533    {
534        if ($this->namespaceDecided) {
535            return;
536        }
537
538        if (strpos($name, '\\') !== false) {
539            $this->namespace = strtok($name, '\\');
540            echo 'namespace ', $this->namespace, ";\n\n";
541        }
542
543        $this->namespaceDecided = true;
544    }
545    // }}}
546    function stripNamespace($name) // {{{
547    {
548        $len = strlen($this->namespace) + 1;
549        if (substr($name, 0, $len) == $this->namespace . '\\') {
550            return substr($name, $len);
551        }
552        else {
553            return $name;
554        }
555    }
556    // }}}
[787]557    function outputPhp(&$EX, $opline, $last, $indent) // {{{
[1]558    {
[789]559        $needBlankline = isset($EX['lastBlock']);
[1]560        $origindent = $indent;
561        $curticks = 0;
562        for ($i = $opline; $i <= $last; $i ++) {
[787]563            $op = $EX['opcodes'][$i];
564            if (isset($op['gofrom'])) {
[789]565                if ($needBlankline) {
566                    $needBlankline = false;
567                    echo PHP_EOL;
568                }
[787]569                echo 'label' . $i, ":\n";
570            }
[1]571            if (isset($op['php'])) {
[746]572                $toticks = isset($op['ticks']) ? (int) str($op['ticks']) : 0;
[1]573                if ($curticks != $toticks) {
[746]574                    $oldticks = $curticks;
575                    $curticks = $toticks;
576                    if (!$curticks) {
[749]577                        echo $origindent, "}\n\n";
[1]578                        $indent = $origindent;
579                    }
580                    else {
[746]581                        if ($oldticks) {
[749]582                            echo $origindent, "}\n\n";
[1]583                        }
[746]584                        else if (!$oldticks) {
[1]585                            $indent .= INDENT;
586                        }
[789]587                        if ($needBlankline) {
588                            $needBlankline = false;
589                            echo PHP_EOL;
590                        }
[746]591                        echo $origindent, "declare (ticks=$curticks) {\n";
[1]592                    }
593                }
[789]594                if ($needBlankline) {
595                    $needBlankline = false;
596                    echo PHP_EOL;
597                }
[744]598                echo $indent, str($op['php'], $indent), ";\n";
[790]599                $EX['lastBlock'] = 'basic';
[1]600            }
601        }
602        if ($curticks) {
603            echo $origindent, "}\n";
604        }
605    }
606    // }}}
607    function getOpVal($op, &$EX, $tostr = true, $free = false) // {{{
608    {
609        switch ($op['op_type']) {
610        case XC_IS_CONST:
[744]611            return foldToCode(value($op['constant']), $EX);
[1]612
613        case XC_IS_VAR:
614        case XC_IS_TMP_VAR:
615            $T = &$EX['Ts'];
[716]616            $ret = $T[$op['var']];
[1]617            if ($tostr) {
[744]618                $ret = foldToCode($ret, $EX);
[1]619            }
[791]620            if ($free && empty($this->keepTs)) {
[716]621                unset($T[$op['var']]);
[1]622            }
623            return $ret;
624
625        case XC_IS_CV:
[716]626            $var = $op['var'];
[1]627            $var = $EX['op_array']['vars'][$var];
628            return '$' . $var['name'];
629
630        case XC_IS_UNUSED:
631            return null;
632        }
633    }
634    // }}}
[716]635    function removeKeyPrefix($array, $prefix) // {{{
636    {
637        $prefixLen = strlen($prefix);
638        $ret = array();
639        foreach ($array as $key => $value) {
640            if (substr($key, 0, $prefixLen) == $prefix) {
641                $key = substr($key, $prefixLen);
642            }
643            $ret[$key] = $value;
644        }
645        return $ret;
646    }
647    // }}}
[735]648    function &fixOpcode($opcodes, $removeTailing = false, $defaultReturnValue = null) // {{{
[1]649    {
[795]650        $last = count($opcodes) - 1;
651        for ($i = 0; $i <= $last; $i ++) {
[716]652            if (function_exists('xcache_get_fixed_opcode')) {
653                $opcodes[$i]['opcode'] = xcache_get_fixed_opcode($opcodes[$i]['opcode'], $i);
654            }
655            if (isset($opcodes[$i]['op1'])) {
656                $opcodes[$i]['op1'] = $this->removeKeyPrefix($opcodes[$i]['op1'], 'u.');
657                $opcodes[$i]['op2'] = $this->removeKeyPrefix($opcodes[$i]['op2'], 'u.');
658                $opcodes[$i]['result'] = $this->removeKeyPrefix($opcodes[$i]['result'], 'u.');
659            }
660            else {
661                $op = array(
662                    'op1' => array(),
663                    'op2' => array(),
664                    'op3' => array(),
665                );
666                foreach ($opcodes[$i] as $name => $value) {
667                    if (preg_match('!^(op1|op2|result)\\.(.*)!', $name, $m)) {
668                        list(, $which, $field) = $m;
669                        $op[$which][$field] = $value;
670                    }
671                    else if (preg_match('!^(op1|op2|result)_type$!', $name, $m)) {
672                        list(, $which) = $m;
673                        $op[$which]['op_type'] = $value;
674                    }
675                    else {
676                        $op[$name] = $value;
677                    }
678                }
679                $opcodes[$i] = $op;
680            }
681        }
[735]682
683        if ($removeTailing) {
684            $last = count($opcodes) - 1;
685            if ($opcodes[$last]['opcode'] == XC_HANDLE_EXCEPTION) {
[761]686                $this->usedOps[XC_HANDLE_EXCEPTION] = true;
[762]687                $opcodes[$last]['opcode'] = XC_NOP;
[735]688                --$last;
689            }
690            if ($opcodes[$last]['opcode'] == XC_RETURN) {
691                $op1 = $opcodes[$last]['op1'];
692                if ($op1['op_type'] == XC_IS_CONST && array_key_exists('constant', $op1) && $op1['constant'] === $defaultReturnValue) {
[762]693                    $opcodes[$last]['opcode'] = XC_NOP;
[735]694                    --$last;
695                }
696            }
697        }
[731]698        return $opcodes;
699    }
700    // }}}
[787]701    function decompileBasicBlock(&$EX, $first, $last, $indent) // {{{
702    {
703        $this->dasmBasicBlock($EX, $first, $last);
[790]704        // $this->dumpRange($EX, $first, $last, $indent);
[787]705        $this->outputPhp($EX, $first, $last, $indent);
706    }
707    // }}}
708    function removeJmpInfo(&$EX, $line) // {{{
709    {
710        $opcodes = &$EX['opcodes'];
711        foreach ($opcodes[$line]['jmpouts'] as $jmpTo) {
712            $jmpins = &$opcodes[$jmpTo]['jmpins'];
713            $jmpins = array_flip($jmpins);
714            unset($jmpins[$line]);
715            $jmpins = array_keys($jmpins);
716        }
[789]717        // $opcodes[$line]['opcode'] = XC_NOP;
[787]718        unset($opcodes[$line]['jmpouts']);
719    }
720    // }}}
[788]721    function beginComplexBlock(&$EX) // {{{
722    {
723        if (isset($EX['lastBlock'])) {
724            echo PHP_EOL;
725            $EX['lastBlock'] = null;
726        }
727    }
728    // }}}
729    function endComplexBlock(&$EX) // {{{
730    {
731        $EX['lastBlock'] = 'complex';
732    }
733    // }}}
[787]734    function decompileComplexBlock(&$EX, $first, $last, $indent) // {{{
735    {
[790]736        $T = &$EX['Ts'];
[787]737        $opcodes = &$EX['opcodes'];
738
739        $firstOp = &$opcodes[$first];
740        $lastOp = &$opcodes[$last];
741
[799]742        // {{{ ?: excludign JMP_SET
743        if ($firstOp['opcode'] == XC_JMPZ && !empty($firstOp['jmpouts'])
744         && $last >= $first + 3
745         && $opcodes[$firstOp['jmpouts'][0] - 2]['opcode'] == XC_QM_ASSIGN
746         && $opcodes[$firstOp['jmpouts'][0] - 1]['opcode'] == XC_JMP && $opcodes[$firstOp['jmpouts'][0] - 1]['jmpouts'][0] == $last + 1
747         && $lastOp['opcode'] == XC_QM_ASSIGN
748        ) {
749            $trueFirst = $first + 1;
750            $trueLast = $firstOp['jmpouts'][0] - 2;
751            $falseFirst = $firstOp['jmpouts'][0];
752            $falseLast = $last;
753            $this->removeJmpInfo($EX, $first);
754
755            $condition = $this->getOpVal($firstOp['op1'], $EX);
756            $this->recognizeAndDecompileClosedBlocks($EX, $trueFirst, $trueLast, $indent . INDENT);
757            $trueValue = $this->getOpVal($opcodes[$trueLast]['op1'], $EX, false, true);
758            $this->recognizeAndDecompileClosedBlocks($EX, $falseFirst, $falseLast, $indent . INDENT);
759            $falseValue = $this->getOpVal($opcodes[$falseLast]['op1'], $EX, false, true);
760            $T[$opcodes[$trueLast]['result']['var']] = new Decompiler_TriOp($condition, $trueValue, $falseValue);
761            return false;
762        }
763        // }}}
[795]764        // {{{ try/catch
765        if (!empty($firstOp['jmpins']) && !empty($opcodes[$firstOp['jmpins'][0]]['isCatchBegin'])) {
766            $catchBlocks = array();
767            $catchFirst = $firstOp['jmpins'][0];
768
769            $tryFirst = $first;
770            $tryLast = $catchFirst - 1;
771
772            // search for XC_CATCH
773            $this->removeJmpInfo($EX, $catchFirst);
774            for ($i = $catchFirst; $i <= $last; ) {
775                if ($opcodes[$i]['opcode'] == XC_CATCH) {
776                    $catchOpLine = $i;
777                    $this->removeJmpInfo($EX, $catchOpLine);
778
779                    $catchNext = $opcodes[$catchOpLine]['extended_value'];
780                    $catchBodyLast = $catchNext - 1;
781                    if ($opcodes[$catchBodyLast]['opcode'] == XC_JMP) {
782                        --$catchBodyLast;
783                    }
784
785                    $catchBlocks[$catchFirst] = array($catchOpLine, $catchBodyLast);
786
787                    $i = $catchFirst = $catchNext;
788                }
789                else {
790                    ++$i;
791                }
792            }
793
794            if ($opcodes[$tryLast]['opcode'] == XC_JMP) {
795                --$tryLast;
796            }
797
798            $this->beginComplexBlock($EX);
[796]799            echo $indent, "try {", PHP_EOL;
[795]800            $this->recognizeAndDecompileClosedBlocks($EX, $tryFirst, $tryLast, $indent . INDENT);
801            echo $indent, '}', PHP_EOL;
802            foreach ($catchBlocks as $catchFirst => $catchInfo) {
803                list($catchOpLine, $catchBodyLast) = $catchInfo;
804                $catchBodyFirst = $catchOpLine + 1;
805                $this->recognizeAndDecompileClosedBlocks($EX, $catchFirst, $catchOpLine, $indent);
806                $catchOp = &$opcodes[$catchOpLine];
[796]807                echo $indent, 'catch (', str($this->getOpVal($catchOp['op1'], $EX)), ' ', str($this->getOpVal($catchOp['op2'], $EX)), ") {", PHP_EOL;
[795]808                unset($catchOp);
809
810                $EX['lastBlock'] = null;
811                $this->recognizeAndDecompileClosedBlocks($EX, $catchBodyFirst, $catchBodyLast, $indent . INDENT);
812                echo $indent, '}', PHP_EOL;
813            }
814            $this->endComplexBlock($EX);
815            return;
816        }
817        // }}}
[796]818        // {{{ switch/case
[790]819        if ($firstOp['opcode'] == XC_SWITCH_FREE && isset($T[$firstOp['op1']['var']])) {
820            // TODO: merge this code to CASE code. use SWITCH_FREE to detect begin of switch by using $Ts if possible
821            $this->beginComplexBlock($EX);
[796]822            echo $indent, 'switch (', str($this->getOpVal($firstOp['op1'], $EX)), ") {", PHP_EOL;
[790]823            echo $indent, '}', PHP_EOL;
824            $this->endComplexBlock($EX);
825            return;
826        }
827
828        if (
829            ($firstOp['opcode'] == XC_CASE
830            || $firstOp['opcode'] == XC_JMP && !empty($firstOp['jmpouts']) && $opcodes[$firstOp['jmpouts'][0]]['opcode'] == XC_CASE
831            )
832             && !empty($lastOp['jmpouts'])
833        ) {
834            $cases = array();
835            $caseDefault = null;
836            $caseOp = null;
[795]837            for ($i = $first; $i <= $last; ) {
[790]838                $op = $opcodes[$i];
839                if ($op['opcode'] == XC_CASE) {
840                    if (!isset($caseOp)) {
841                        $caseOp = $op;
842                    }
843                    $jmpz = $opcodes[$i + 1];
844                    assert('$jmpz["opcode"] == XC_JMPZ');
845                    $caseNext = $jmpz['jmpouts'][0];
[795]846                    $cases[$i] = $caseNext - 1;
847                    $i = $caseNext;
[790]848                }
[795]849                else if ($op['opcode'] == XC_JMP && $op['jmpouts'][0] >= $i) {
[790]850                    // default
[795]851                    $caseNext = $op['jmpouts'][0];
852                    $caseDefault = $i;
853                    $cases[$i] = $caseNext - 1;
854                    $i = $caseNext;
[790]855                }
[795]856                else {
857                    ++$i;
858                }
[790]859            }
860
861            $this->beginComplexBlock($EX);
862
[796]863            echo $indent, 'switch (', str($this->getOpVal($caseOp['op1'], $EX, true, true), $EX), ") {", PHP_EOL;
[790]864            $caseIsOut = false;
865            foreach ($cases as $caseFirst => $caseLast) {
866                if ($caseIsOut && !empty($EX['lastBlock']) && empty($lastCaseFall)) {
867                    echo PHP_EOL;
868                }
869                unset($EX['lastBlock']);
870
871                $caseOp = $opcodes[$caseFirst];
872
873                echo $indent;
874                if ($caseOp['opcode'] == XC_CASE) {
875                    echo 'case ';
876                    echo str($this->getOpVal($caseOp['op2'], $EX), $EX);
877                    echo ':', PHP_EOL;
878
879                    $this->removeJmpInfo($EX, $caseFirst);
880                    ++$caseFirst;
881
882                    assert('$opcodes[$caseFirst]["opcode"] == XC_JMPZ');
883                    $this->removeJmpInfo($EX, $caseFirst);
884                    ++$caseFirst;
885                }
886                else {
887                    echo 'default';
888                    echo ':', PHP_EOL;
889
890                    assert('$opcodes[$caseFirst]["opcode"] == XC_JMP');
891                    $this->removeJmpInfo($EX, $caseFirst);
892                    ++$caseFirst;
893                }
894
895                assert('$opcodes[$caseLast]["opcode"] == XC_JMP');
896                $this->removeJmpInfo($EX, $caseLast);
897                --$caseLast;
898                switch ($opcodes[$caseLast]['opcode']) {
899                case XC_BRK:
900                case XC_CONT:
901                case XC_GOTO:
902                    $lastCaseFall = false;
903                    break;
904
905                default:
906                    $lastCaseFall = true;
907                }
908
909                $this->recognizeAndDecompileClosedBlocks($EX, $caseFirst, $caseLast, $indent . INDENT);
910                $caseIsOut = true;
911            }
912            echo $indent, '}', PHP_EOL;
913
914            $this->endComplexBlock($EX);
915            return;
916        }
[796]917        // }}}
918        // {{{ do/while
[789]919        if ($lastOp['opcode'] == XC_JMPNZ && !empty($lastOp['jmpouts'])
[787]920         && $lastOp['jmpouts'][0] == $first) {
921            $this->removeJmpInfo($EX, $last);
[788]922            $this->beginComplexBlock($EX);
[789]923
[796]924            echo $indent, "do {", PHP_EOL;
[787]925            $this->recognizeAndDecompileClosedBlocks($EX, $first, $last, $indent . INDENT);
[796]926            echo $indent, "} while (", str($this->getOpVal($lastOp['op1'], $EX)), ');', PHP_EOL;
[789]927
[788]928            $this->endComplexBlock($EX);
[787]929            return;
930        }
[796]931        // }}}
[787]932
[796]933        // {{{ search firstJmpOp
[787]934        $firstJmp = null;
935        $firstJmpOp = null;
936        for ($i = $first; $i <= $last; ++$i) {
937            if (!empty($opcodes[$i]['jmpouts'])) {
938                $firstJmp = $i;
939                $firstJmpOp = &$opcodes[$firstJmp];
940                break;
941            }
942        }
[796]943        // }}}
[787]944
[796]945        // {{{ while
[787]946        if (isset($firstJmpOp)
947         && $firstJmpOp['opcode'] == XC_JMPZ
[789]948         && $firstJmpOp['jmpouts'][0] > $last
949         && $lastOp['opcode'] == XC_JMP && !empty($lastOp['jmpouts'])
[787]950         && $lastOp['jmpouts'][0] == $first) {
951            $this->removeJmpInfo($EX, $firstJmp);
952            $this->removeJmpInfo($EX, $last);
[789]953            $this->beginComplexBlock($EX);
[787]954
955            ob_start();
956            $this->recognizeAndDecompileClosedBlocks($EX, $first, $last, $indent . INDENT);
[789]957            $body = ob_get_clean();
958
[796]959            echo $indent, 'while (', str($this->getOpVal($firstJmpOp['op1'], $EX)), ") {", PHP_EOL;
[789]960            echo $body;
[787]961            echo $indent, '}', PHP_EOL;
[789]962
[788]963            $this->endComplexBlock($EX);
[787]964            return;
965        }
[796]966        // }}}
967        // {{{ foreach
[789]968        if (isset($firstJmpOp)
969         && $firstJmpOp['opcode'] == XC_FE_FETCH
970         && $firstJmpOp['jmpouts'][0] > $last
971         && $lastOp['opcode'] == XC_JMP && !empty($lastOp['jmpouts'])
972         && $lastOp['jmpouts'][0] == $firstJmp) {
973            $this->removeJmpInfo($EX, $firstJmp);
974            $this->removeJmpInfo($EX, $last);
975            $this->beginComplexBlock($EX);
976
977            ob_start();
978            $this->recognizeAndDecompileClosedBlocks($EX, $first, $last, $indent . INDENT);
979            $body = ob_get_clean();
980
981            $as = foldToCode($firstJmpOp['fe_as'], $EX);
982            if (isset($firstJmpOp['fe_key'])) {
983                $as = str($firstJmpOp['fe_key'], $EX) . ' => ' . str($as);
984            }
985
986            echo $indent, 'foreach (', str($firstJmpOp['fe_src'], $EX), " as $as) {", PHP_EOL;
987            echo $body;
988            echo $indent, '}', PHP_EOL;
989
990            $this->endComplexBlock($EX);
991            return;
992        }
[796]993        // }}}
[789]994
[787]995        $this->decompileBasicBlock($EX, $first, $last, $indent);
996    }
997    // }}}
998    function recognizeAndDecompileClosedBlocks(&$EX, $first, $last, $indent) // {{{ decompile in a tree way
999    {
1000        $opcodes = &$EX['opcodes'];
1001
[791]1002        $starti = $first;
[795]1003        for ($i = $starti; $i <= $last; ) {
1004            if (!empty($opcodes[$i]['jmpins']) || !empty($opcodes[$i]['jmpouts'])) {
[787]1005                $blockFirst = $i;
1006                $blockLast = -1;
[791]1007                $j = $blockFirst;
[787]1008                do {
[791]1009                    $op = $opcodes[$j];
[787]1010                    if (!empty($op['jmpins'])) {
1011                        // care about jumping from blocks behind, not before
1012                        foreach ($op['jmpins'] as $oplineNumber) {
1013                            if ($oplineNumber <= $last && $blockLast < $oplineNumber) {
1014                                $blockLast = $oplineNumber;
1015                            }
1016                        }
1017                    }
1018                    if (!empty($op['jmpouts'])) {
1019                        $blockLast = max($blockLast, max($op['jmpouts']) - 1);
1020                    }
[791]1021                    ++$j;
1022                } while ($j <= $blockLast);
[795]1023                if (!assert('$blockLast <= $last')) {
1024                    var_dump($blockLast, $last);
1025                }
[787]1026
1027                if ($blockLast >= $blockFirst) {
1028                    if ($blockFirst > $starti) {
1029                        $this->decompileBasicBlock($EX, $starti, $blockFirst - 1, $indent);
1030                    }
[799]1031                    if ($this->decompileComplexBlock($EX, $blockFirst, $blockLast, $indent) === false) {
1032                        if ($EX['lastBlock'] == 'complex') {
1033                            echo PHP_EOL;
1034                        }
1035                        $EX['lastBlock'] = null;
1036                    }
[791]1037                    $starti = $blockLast + 1;
[795]1038                    $i = $starti;
[787]1039                }
[795]1040                else {
1041                    ++$i;
1042                }
[787]1043            }
[795]1044            else {
1045                ++$i;
1046            }
[787]1047        }
1048        if ($starti <= $last) {
1049            $this->decompileBasicBlock($EX, $starti, $last, $indent);
1050        }
1051    }
1052    // }}}
[731]1053    function &dop_array($op_array, $indent = '') // {{{
1054    {
[735]1055        $op_array['opcodes'] = $this->fixOpcode($op_array['opcodes'], true, $indent == '' ? 1 : null);
[731]1056        $opcodes = &$op_array['opcodes'];
[795]1057        $last = count($opcodes) - 1;
[787]1058        // {{{ build jmpins/jmpouts to op_array
[795]1059        for ($i = 0; $i <= $last; $i ++) {
[1]1060            $op = &$opcodes[$i];
1061            $op['line'] = $i;
1062            switch ($op['opcode']) {
[758]1063            case XC_CONT:
1064            case XC_BRK:
1065                $op['jmpouts'] = array();
1066                break;
1067
[749]1068            case XC_GOTO:
[787]1069                $target = $op['op1']['var'];
1070                $op['goto'] = $target;
1071                $opcodes[$target]['gofrom'][] = $i;
1072                break;
1073
[1]1074            case XC_JMP:
[716]1075                $target = $op['op1']['var'];
[1]1076                $op['jmpouts'] = array($target);
1077                $opcodes[$target]['jmpins'][] = $i;
1078                break;
1079
1080            case XC_JMPZNZ:
[716]1081                $jmpz = $op['op2']['opline_num'];
[1]1082                $jmpnz = $op['extended_value'];
1083                $op['jmpouts'] = array($jmpz, $jmpnz);
1084                $opcodes[$jmpz]['jmpins'][] = $i;
1085                $opcodes[$jmpnz]['jmpins'][] = $i;
1086                break;
1087
1088            case XC_JMPZ:
1089            case XC_JMPNZ:
1090            case XC_JMPZ_EX:
1091            case XC_JMPNZ_EX:
[799]1092            // case XC_JMP_SET:
[1]1093            // case XC_FE_RESET:
1094            case XC_FE_FETCH:
1095            // case XC_JMP_NO_CTOR:
[716]1096                $target = $op['op2']['opline_num'];
[1]1097                //if (!isset($target)) {
1098                //  $this->dumpop($op, $EX);
1099                //  var_dump($op); exit;
1100                //}
1101                $op['jmpouts'] = array($target);
1102                $opcodes[$target]['jmpins'][] = $i;
1103                break;
1104
1105            /*
1106            case XC_RETURN:
1107                $op['jmpouts'] = array();
1108                break;
1109            */
[790]1110
1111            case XC_SWITCH_FREE:
1112                $op['jmpouts'] = array($i + 1);
1113                $opcodes[$i + 1]['jmpins'][] = $i;
1114                break;
1115
1116            case XC_CASE:
1117                // just to link together
1118                $op['jmpouts'] = array($i + 2);
1119                $opcodes[$i + 2]['jmpins'][] = $i;
1120                break;
[795]1121
1122            case XC_CATCH:
1123                $catchNext = $op['extended_value'];
1124                $op['jmpouts'] = array($catchNext);
1125                $opcodes[$catchNext]['jmpins'][] = $i;
1126                break;
[1]1127            }
[787]1128            /*
1129            if (!empty($op['jmpouts']) || !empty($op['jmpins'])) {
1130                echo $i, "\t", xcache_get_opcode($op['opcode']), PHP_EOL;
1131            }
1132            // */
[1]1133        }
1134        unset($op);
[795]1135        if ($op_array['try_catch_array']) {
1136            foreach ($op_array['try_catch_array'] as $try_catch_element) {
1137                $catch_op = $try_catch_element['catch_op'];
1138                $try_op = $try_catch_element['try_op'];
1139                $opcodes[$try_op]['jmpins'][] = $catch_op;
1140                $opcodes[$catch_op]['jmpouts'][] = $try_op;
1141                $opcodes[$catch_op]['isCatchBegin'] = true;
1142            }
1143        }
[1]1144        // }}}
1145        // build semi-basic blocks
1146        $nextbbs = array();
1147        $starti = 0;
[795]1148        for ($i = 1; $i <= $last; $i ++) {
[1]1149            if (isset($opcodes[$i]['jmpins'])
1150             || isset($opcodes[$i - 1]['jmpouts'])) {
1151                $nextbbs[$starti] = $i;
1152                $starti = $i;
1153            }
1154        }
[795]1155        $nextbbs[$starti] = $last + 1;
[1]1156
1157        $EX = array();
1158        $EX['Ts'] = array();
1159        $EX['indent'] = $indent;
1160        $EX['nextbbs'] = $nextbbs;
1161        $EX['op_array'] = &$op_array;
1162        $EX['opcodes'] = &$opcodes;
1163        // func call
1164        $EX['object'] = null;
[720]1165        $EX['called_scope'] = null;
[1]1166        $EX['fbc'] = null;
1167        $EX['argstack'] = array();
1168        $EX['arg_types_stack'] = array();
1169        $EX['last'] = count($opcodes) - 1;
1170        $EX['silence'] = 0;
[780]1171        $EX['recvs'] = array();
1172        $EX['uses'] = array();
[799]1173        $EX['lastBlock'] = null;
[1]1174
[790]1175        $first = 0;
1176        $last = count($opcodes) - 1;
1177
1178        /* dump whole array
[791]1179        $this->keepTs = true;
[790]1180        $this->dasmBasicBlock($EX, $first, $last);
1181        for ($i = $first; $i <= $last; ++$i) {
1182            echo $i, "\t", $this->dumpop($opcodes[$i], $EX);
1183        }
1184        // */
[787]1185        // decompile in a tree way
[790]1186        $this->recognizeAndDecompileClosedBlocks($EX, $first, $last, $EX['indent']);
[1]1187        return $EX;
1188    }
1189    // }}}
1190    function outputCode(&$EX, $opline, $last, $indent, $loop = false) // {{{
1191    {
1192        $op = &$EX['opcodes'][$opline];
1193        $next = $EX['nextbbs'][$opline];
1194
1195        $end = $next - 1;
1196        if ($end > $last) {
1197            $end = $last;
1198        }
1199
1200        if (isset($op['jmpins'])) {
1201            echo "\nline", $op['line'], ":\n";
1202        }
1203        else {
1204            // echo ";;;\n";
1205        }
1206        $this->dasmBasicBlock($EX, $opline, $end);
[787]1207        $this->outputPhp($EX, $opline, $end, $indent);
[1]1208        // jmpout op
1209        $op = &$EX['opcodes'][$end];
1210        $op1 = $op['op1'];
1211        $op2 = $op['op2'];
1212        $ext = $op['extended_value'];
1213        $line = $op['line'];
1214
1215        if (isset($EX['opcodes'][$next])) {
1216            if (isset($last) && $next > $last) {
1217                $next = null;
1218            }
1219        }
1220        else {
1221            $next = null;
1222        }
1223        /*
1224        if ($op['opcode'] == XC_JMPZ) {
[716]1225            $target = $op2['opline_num'];
[1]1226            if ($line + 1) {
1227                $nextblock = $EX['nextbbs'][$next];
1228                $jmpop = end($nextblock);
1229                if ($jmpop['opcode'] == XC_JMP) {
[716]1230                    $ifendline = $op2['opline_num'];
[1]1231                    if ($ifendline >= $line) {
1232                        $cond = $op['cond'];
1233                        echo "{$indent}if ($cond) {\n";
1234                        $this->outputCode($EX, $next, $last, INDENT . $indent);
1235                        echo "$indent}\n";
1236                        $this->outputCode($EX, $target, $last, $indent);
1237                        return;
1238                    }
1239                }
1240            }
1241        }
1242        */
1243        if (!isset($next)) {
1244            return;
1245        }
[758]1246        if (isset($op['jmpouts']) && isset($op['isjmp'])) {
[1]1247            if (isset($op['cond'])) {
[746]1248                echo "{$indent}check (" . str($op["cond"]) . ") {\n";
[1]1249                echo INDENT;
1250            }
[758]1251            switch ($op['opcode']) {
1252            case XC_CONT:
1253            case XC_BRK:
1254                break;
1255
1256            default:
1257                echo $indent;
1258                echo xcache_get_opcode($op['opcode']), ' line', $op['jmpouts'][0];
1259                if (isset($op['jmpouts'][1])) {
1260                    echo ', line', $op['jmpouts'][1];
1261                }
1262                echo ";";
1263                // echo ' // <- line', $op['line'];
1264                echo "\n";
[1]1265            }
1266            if (isset($op['cond'])) echo "$indent}\n";
1267        }
1268
1269        // proces JMPZ_EX/JMPNZ_EX for AND,OR
1270        $op = &$EX['opcodes'][$next];
1271        /*
1272        if (isset($op['jmpins'])) {
1273            foreach (array_reverse($op['jmpins']) as $fromline) {
1274                $fromop = $EX['opcodes'][$fromline];
1275                switch ($fromop['opcode']) {
1276                case XC_JMPZ_EX: $opstr = 'and'; break;
1277                case XC_JMPNZ_EX: $opstr = 'or'; break;
1278                case XC_JMPZNZ: var_dump($fromop); exit;
1279                default: continue 2;
1280                }
1281
[716]1282                $var = $fromop['result']['var'];
[1]1283                var_dump($EX['Ts'][$var]);
1284                $EX['Ts'][$var] = '(' . $fromop['and_or'] . " $opstr " . $EX['Ts'][$var] . ')';
1285            }
1286            #$this->outputCode($EX, $next, $last, $indent);
1287            #return;
1288        }
1289        */
1290        if (isset($op['cond_false'])) {
1291            // $this->dumpop($op, $EX);
1292            // any true comes here, so it's a "or"
[744]1293            $cond = implode(' and ', str($op['cond_false']));
[1]1294            // var_dump($op['cond'] = $cond);
1295            /*
1296            $rvalue = implode(' or ', $op['cond_true']) . ' or ' . $rvalue;
1297            unset($op['cond_true']);
1298            */
1299        }
1300
1301        if ($loop) {
1302            return array($next, $last);
1303        }
1304        $this->outputCode($EX, $next, $last, $indent);
1305    }
1306    // }}}
1307    function dasmBasicBlock(&$EX, $opline, $last) // {{{
1308    {
1309        $T = &$EX['Ts'];
1310        $opcodes = &$EX['opcodes'];
1311        $lastphpop = null;
1312
[787]1313        for ($i = $opline; $i <= $last; $i ++) {
[1]1314            // {{{ prepair
1315            $op = &$opcodes[$i];
1316            $opc = $op['opcode'];
1317            if ($opc == XC_NOP) {
[761]1318                $this->usedOps[$opc] = true;
[1]1319                continue;
1320            }
1321
1322            $op1 = $op['op1'];
1323            $op2 = $op['op2'];
1324            $res = $op['result'];
1325            $ext = $op['extended_value'];
1326
1327            $opname = xcache_get_opcode($opc);
1328
1329            if ($opname == 'UNDEF' || !isset($opname)) {
1330                echo 'UNDEF OP:';
1331                $this->dumpop($op, $EX);
1332                continue;
1333            }
[762]1334            // echo $i, ' '; $this->dumpop($op, $EX); //var_dump($op);
[1]1335
1336            $resvar = null;
[799]1337            unset($curResVar);
1338            if (array_key_exists($res['var'], $T)) {
1339                $curResVar = &$T[$res['var']];
1340            }
[731]1341            if ((ZEND_ENGINE_2_4 ? ($res['op_type'] & EXT_TYPE_UNUSED) : ($res['EA.type'] & EXT_TYPE_UNUSED)) || $res['op_type'] == XC_IS_UNUSED) {
[1]1342                $istmpres = false;
1343            }
1344            else {
1345                $istmpres = true;
1346            }
1347            // }}}
1348            // echo $opname, "\n";
1349
1350            $call = array(&$this, $opname);
1351            if (is_callable($call)) {
[761]1352                $this->usedOps[$opc] = true;
[1]1353                $this->{$opname}($op, $EX);
1354            }
1355            else if (isset($this->binops[$opc])) { // {{{
[761]1356                $this->usedOps[$opc] = true;
[1]1357                $op1val = $this->getOpVal($op1, $EX, false);
1358                $op2val = $this->getOpVal($op2, $EX, false);
1359                $rvalue = new Decompiler_Binop($this, $op1val, $opc, $op2val);
1360                $resvar = $rvalue;
1361                // }}}
1362            }
1363            else if (isset($this->unaryops[$opc])) { // {{{
[761]1364                $this->usedOps[$opc] = true;
[1]1365                $op1val = $this->getOpVal($op1, $EX);
1366                $myop = $this->unaryops[$opc];
[757]1367                $rvalue = $myop . str($op1val);
[1]1368                $resvar = $rvalue;
1369                // }}}
1370            }
1371            else {
[761]1372                $covered = true;
[1]1373                switch ($opc) {
1374                case XC_NEW: // {{{
[720]1375                    array_push($EX['arg_types_stack'], array($EX['fbc'], $EX['object'], $EX['called_scope']));
[716]1376                    $EX['object'] = (int) $res['var'];
[720]1377                    $EX['called_scope'] = null;
[749]1378                    $EX['fbc'] = 'new ' . unquoteName($this->getOpVal($op1, $EX), $EX);
[731]1379                    if (!ZEND_ENGINE_2) {
[1]1380                        $resvar = '$new object$';
1381                    }
1382                    break;
1383                    // }}}
[749]1384                case XC_THROW: // {{{
1385                    $resvar = 'throw ' . str($this->getOpVal($op1, $EX));
1386                    break;
1387                    // }}}
1388                case XC_CLONE: // {{{
1389                    $resvar = 'clone ' . str($this->getOpVal($op1, $EX));
1390                    break;
1391                    // }}}
1392                case XC_CATCH: // {{{
1393                    break;
1394                    // }}}
1395                case XC_INSTANCEOF: // {{{
1396                    $resvar = str($this->getOpVal($op1, $EX)) . ' instanceof ' . str($this->getOpVal($op2, $EX));
1397                    break;
1398                    // }}}
[1]1399                case XC_FETCH_CLASS: // {{{
1400                    if ($op2['op_type'] == XC_IS_UNUSED) {
[731]1401                        switch (($ext & (defined('ZEND_FETCH_CLASS_MASK') ? ZEND_FETCH_CLASS_MASK : 0xFF))) {
[1]1402                        case ZEND_FETCH_CLASS_SELF:
1403                            $class = 'self';
1404                            break;
1405                        case ZEND_FETCH_CLASS_PARENT:
1406                            $class = 'parent';
[722]1407                            break;
1408                        case ZEND_FETCH_CLASS_STATIC:
1409                            $class = 'static';
1410                            break;
[1]1411                        }
[722]1412                        $istmpres = true;
[1]1413                    }
1414                    else {
[749]1415                        $class = $this->getOpVal($op2, $EX);
1416                        if (isset($op2['constant'])) {
[753]1417                            $class = $this->stripNamespace(unquoteName($class));
[1]1418                        }
1419                    }
1420                    $resvar = $class;
1421                    break;
1422                    // }}}
1423                case XC_FETCH_CONSTANT: // {{{
[749]1424                    if ($op1['op_type'] == XC_IS_UNUSED) {
[753]1425                        $resvar = $this->stripNamespace($op2['constant']);
[749]1426                        break;
1427                    }
1428
[1]1429                    if ($op1['op_type'] == XC_IS_CONST) {
[753]1430                        $resvar = $this->stripNamespace($op1['constant']);
[1]1431                    }
1432                    else {
[749]1433                        $resvar = $this->getOpVal($op1, $EX);
[1]1434                    }
[749]1435
1436                    $resvar = str($resvar) . '::' . unquoteName($this->getOpVal($op2, $EX));
[1]1437                    break;
1438                    // }}}
1439                    // {{{ case XC_FETCH_*
1440                case XC_FETCH_R:
1441                case XC_FETCH_W:
1442                case XC_FETCH_RW:
1443                case XC_FETCH_FUNC_ARG:
1444                case XC_FETCH_UNSET:
1445                case XC_FETCH_IS:
1446                case XC_UNSET_VAR:
1447                    $rvalue = $this->getOpVal($op1, $EX);
[731]1448                    if (defined('ZEND_FETCH_TYPE_MASK')) {
1449                        $fetchtype = ($ext & ZEND_FETCH_TYPE_MASK);
1450                    }
1451                    else {
1452                        $fetchtype = $op2[!ZEND_ENGINE_2 ? 'fetch_type' : 'EA.type'];
1453                    }
[1]1454                    switch ($fetchtype) {
1455                    case ZEND_FETCH_STATIC_MEMBER:
1456                        $class = $this->getOpVal($op2, $EX);
[749]1457                        $rvalue = str($class) . '::$' . unquoteName($rvalue, $EX);
[1]1458                        break;
1459                    default:
[749]1460                        $name = unquoteName($rvalue, $EX);
1461                        $globalname = xcache_is_autoglobal($name) ? "\$$name" : "\$GLOBALS[" . str($rvalue) . "]";
[1]1462                        $rvalue = new Decompiler_Fetch($rvalue, $fetchtype, $globalname);
1463                        break;
1464                    }
1465                    if ($opc == XC_UNSET_VAR) {
[744]1466                        $op['php'] = "unset(" . str($rvalue, $EX) . ")";
[1]1467                        $lastphpop = &$op;
1468                    }
1469                    else if ($res['op_type'] != XC_IS_UNUSED) {
1470                        $resvar = $rvalue;
1471                    }
1472                    break;
1473                    // }}}
1474                    // {{{ case XC_FETCH_DIM_*
1475                case XC_FETCH_DIM_TMP_VAR:
1476                case XC_FETCH_DIM_R:
1477                case XC_FETCH_DIM_W:
1478                case XC_FETCH_DIM_RW:
1479                case XC_FETCH_DIM_FUNC_ARG:
1480                case XC_FETCH_DIM_UNSET:
1481                case XC_FETCH_DIM_IS:
1482                case XC_ASSIGN_DIM:
[749]1483                case XC_UNSET_DIM_OBJ: // PHP 4 only
[1]1484                case XC_UNSET_DIM:
[749]1485                case XC_UNSET_OBJ:
[1]1486                    $src = $this->getOpVal($op1, $EX, false);
1487                    if (is_a($src, "Decompiler_ForeachBox")) {
1488                        $src->iskey = $this->getOpVal($op2, $EX);
1489                        $resvar = $src;
1490                        break;
1491                    }
[749]1492
1493                    if (is_a($src, "Decompiler_DimBox")) {
[1]1494                        $dimbox = $src;
1495                    }
1496                    else {
1497                        if (!is_a($src, "Decompiler_ListBox")) {
[749]1498                            $op1val = $this->getOpVal($op1, $EX, false);
1499                            $list = new Decompiler_List(isset($op1val) ? $op1val : '$this');
[1]1500
1501                            $src = new Decompiler_ListBox($list);
[716]1502                            if (!isset($op1['var'])) {
[1]1503                                $this->dumpop($op, $EX);
1504                                var_dump($op);
[716]1505                                die('missing var');
[1]1506                            }
[716]1507                            $T[$op1['var']] = $src;
[1]1508                            unset($list);
1509                        }
1510                        $dim = new Decompiler_Dim($src);
1511                        $src->obj->dims[] = &$dim;
1512
1513                        $dimbox = new Decompiler_DimBox($dim);
1514                    }
1515                    $dim = &$dimbox->obj;
1516                    $dim->offsets[] = $this->getOpVal($op2, $EX);
1517                    if ($ext == ZEND_FETCH_ADD_LOCK) {
1518                        $src->obj->everLocked = true;
1519                    }
1520                    else if ($ext == ZEND_FETCH_STANDARD) {
1521                        $dim->isLast = true;
1522                    }
[749]1523                    if ($opc == XC_UNSET_OBJ) {
1524                        $dim->isObject = true;
1525                    }
[1]1526                    unset($dim);
1527                    $rvalue = $dimbox;
[749]1528                    unset($dimbox);
[1]1529
1530                    if ($opc == XC_ASSIGN_DIM) {
1531                        $lvalue = $rvalue;
1532                        ++ $i;
1533                        $rvalue = $this->getOpVal($opcodes[$i]['op1'], $EX);
[749]1534                        $resvar = str($lvalue, $EX) . ' = ' . str($rvalue);
[1]1535                    }
[749]1536                    else if ($opc == XC_UNSET_DIM || $opc == XC_UNSET_OBJ) {
[744]1537                        $op['php'] = "unset(" . str($rvalue, $EX) . ")";
[1]1538                        $lastphpop = &$op;
1539                    }
1540                    else if ($res['op_type'] != XC_IS_UNUSED) {
1541                        $resvar = $rvalue;
1542                    }
1543                    break;
1544                    // }}}
1545                case XC_ASSIGN: // {{{
1546                    $lvalue = $this->getOpVal($op1, $EX);
1547                    $rvalue = $this->getOpVal($op2, $EX, false);
1548                    if (is_a($rvalue, 'Decompiler_ForeachBox')) {
1549                        $type = $rvalue->iskey ? 'fe_key' : 'fe_as';
1550                        $rvalue->obj[$type] = $lvalue;
[716]1551                        unset($T[$op2['var']]);
[1]1552                        break;
1553                    }
1554                    if (is_a($rvalue, "Decompiler_DimBox")) {
1555                        $dim = &$rvalue->obj;
1556                        $dim->assign = $lvalue;
1557                        if ($dim->isLast) {
[744]1558                            $resvar = foldToCode($dim->value, $EX);
[1]1559                        }
1560                        unset($dim);
1561                        break;
1562                    }
[781]1563                    if (is_a($rvalue, 'Decompiler_Fetch')) {
1564                        $src = str($rvalue->src, $EX);
1565                        if ('$' . unquoteName($src) == $lvalue) {
1566                            switch ($rvalue->fetchType) {
1567                            case ZEND_FETCH_STATIC:
1568                                $statics = &$EX['op_array']['static_variables'];
1569                                if ((xcache_get_type($statics[$name]) & IS_LEXICAL_VAR)) {
1570                                    $EX['uses'][] = str($lvalue);
1571                                    unset($statics);
1572                                    break 2;
1573                                }
1574                                unset($statics);
1575                            }
1576                        }
1577                    }
[744]1578                    $resvar = "$lvalue = " . str($rvalue, $EX);
[1]1579                    break;
1580                    // }}}
1581                case XC_ASSIGN_REF: // {{{
1582                    $lvalue = $this->getOpVal($op1, $EX);
1583                    $rvalue = $this->getOpVal($op2, $EX, false);
1584                    if (is_a($rvalue, 'Decompiler_Fetch')) {
[749]1585                        $src = str($rvalue->src, $EX);
[754]1586                        if ('$' . unquoteName($src) == $lvalue) {
[1]1587                            switch ($rvalue->fetchType) {
1588                            case ZEND_FETCH_GLOBAL:
[731]1589                            case ZEND_FETCH_GLOBAL_LOCK:
[1]1590                                $resvar = 'global ' . $lvalue;
1591                                break 2;
1592                            case ZEND_FETCH_STATIC:
1593                                $statics = &$EX['op_array']['static_variables'];
[781]1594                                if ((xcache_get_type($statics[$name]) & IS_LEXICAL_REF)) {
1595                                    $EX['uses'][] = '&' . str($lvalue);
1596                                    unset($statics);
1597                                    break 2;
1598                                }
1599
[1]1600                                $resvar = 'static ' . $lvalue;
[754]1601                                $name = unquoteName($src);
[1]1602                                if (isset($statics[$name])) {
1603                                    $var = $statics[$name];
1604                                    $resvar .= ' = ';
[744]1605                                    $resvar .= str(value($var), $EX);
[1]1606                                }
1607                                unset($statics);
1608                                break 2;
[731]1609                            default:
[1]1610                            }
1611                        }
1612                    }
[731]1613                    // TODO: PHP_6 global
[754]1614                    $rvalue = str($rvalue, $EX);
[1]1615                    $resvar = "$lvalue = &$rvalue";
1616                    break;
1617                    // }}}
1618                // {{{ case XC_FETCH_OBJ_*
1619                case XC_FETCH_OBJ_R:
1620                case XC_FETCH_OBJ_W:
1621                case XC_FETCH_OBJ_RW:
1622                case XC_FETCH_OBJ_FUNC_ARG:
1623                case XC_FETCH_OBJ_UNSET:
1624                case XC_FETCH_OBJ_IS:
1625                case XC_ASSIGN_OBJ:
1626                    $obj = $this->getOpVal($op1, $EX);
1627                    if (!isset($obj)) {
1628                        $obj = '$this';
1629                    }
[761]1630                    $rvalue = str($obj) . "->" . unquoteVariableName($this->getOpVal($op2, $EX), $EX);
[1]1631                    if ($res['op_type'] != XC_IS_UNUSED) {
1632                        $resvar = $rvalue;
1633                    }
1634                    if ($opc == XC_ASSIGN_OBJ) {
1635                        ++ $i;
1636                        $lvalue = $rvalue;
1637                        $rvalue = $this->getOpVal($opcodes[$i]['op1'], $EX);
[749]1638                        $resvar = "$lvalue = " . str($rvalue);
[1]1639                    }
1640                    break;
1641                    // }}}
1642                case XC_ISSET_ISEMPTY_DIM_OBJ:
1643                case XC_ISSET_ISEMPTY_PROP_OBJ:
1644                case XC_ISSET_ISEMPTY:
1645                case XC_ISSET_ISEMPTY_VAR: // {{{
1646                    if ($opc == XC_ISSET_ISEMPTY_VAR) {
[777]1647                        $rvalue = $this->getOpVal($op1, $EX);
1648                        // for < PHP_5_3
1649                        if ($op1['op_type'] == XC_IS_CONST) {
1650                            $rvalue = '$' . unquoteVariableName($this->getOpVal($op1, $EX));
1651                        }
[716]1652                        if ($op2['EA.type'] == ZEND_FETCH_STATIC_MEMBER) {
[1]1653                            $class = $this->getOpVal($op2, $EX);
1654                            $rvalue = $class . '::' . $rvalue;
1655                        }
1656                    }
1657                    else if ($opc == XC_ISSET_ISEMPTY) {
1658                        $rvalue = $this->getOpVal($op1, $EX);
1659                    }
1660                    else {
1661                        $container = $this->getOpVal($op1, $EX);
1662                        $dim = $this->getOpVal($op2, $EX);
[717]1663                        if ($opc == XC_ISSET_ISEMPTY_PROP_OBJ) {
[761]1664                            if (!isset($container)) {
1665                                $container = '$this';
[717]1666                            }
[761]1667                            $rvalue = $container . "->" . unquoteVariableName($dim);
[717]1668                        }
1669                        else {
[761]1670                            $rvalue = $container . '[' . str($dim) .']';
[717]1671                        }
[1]1672                    }
1673
[731]1674                    switch ((!ZEND_ENGINE_2 ? $op['op2']['var'] /* constant */ : $ext) & (ZEND_ISSET|ZEND_ISEMPTY)) {
[1]1675                    case ZEND_ISSET:
[775]1676                        $rvalue = "isset(" . str($rvalue) . ")";
[1]1677                        break;
1678                    case ZEND_ISEMPTY:
[775]1679                        $rvalue = "empty(" . str($rvalue) . ")";
[1]1680                        break;
1681                    }
1682                    $resvar = $rvalue;
1683                    break;
1684                    // }}}
1685                case XC_SEND_VAR_NO_REF:
1686                case XC_SEND_VAL:
1687                case XC_SEND_REF:
1688                case XC_SEND_VAR: // {{{
1689                    $ref = ($opc == XC_SEND_REF ? '&' : '');
[744]1690                    $EX['argstack'][] = $ref . str($this->getOpVal($op1, $EX));
[1]1691                    break;
1692                    // }}}
[720]1693                case XC_INIT_STATIC_METHOD_CALL:
[749]1694                case XC_INIT_METHOD_CALL: // {{{
[720]1695                    array_push($EX['arg_types_stack'], array($EX['fbc'], $EX['object'], $EX['called_scope']));
[722]1696                    if ($opc == XC_INIT_STATIC_METHOD_CALL || $opc == XC_INIT_METHOD_CALL || $op1['op_type'] != XC_IS_UNUSED) {
[1]1697                        $obj = $this->getOpVal($op1, $EX);
1698                        if (!isset($obj)) {
1699                            $obj = '$this';
1700                        }
[722]1701                        if ($opc == XC_INIT_STATIC_METHOD_CALL || /* PHP4 */ isset($op1['constant'])) {
[720]1702                            $EX['object'] = null;
[753]1703                            $EX['called_scope'] = $this->stripNamespace(unquoteName($obj, $EX));
[720]1704                        }
1705                        else {
1706                            $EX['object'] = $obj;
1707                            $EX['called_scope'] = null;
1708                        }
[1]1709                        if ($res['op_type'] != XC_IS_UNUSED) {
1710                            $resvar = '$obj call$';
1711                        }
1712                    }
1713                    else {
1714                        $EX['object'] = null;
[720]1715                        $EX['called_scope'] = null;
[1]1716                    }
1717
[749]1718                    $EX['fbc'] = $this->getOpVal($op2, $EX, false);
1719                    if (($opc == XC_INIT_STATIC_METHOD_CALL || $opc == XC_INIT_METHOD_CALL) && !isset($EX['fbc'])) {
1720                        $EX['fbc'] = '__construct';
[1]1721                    }
[749]1722                    break;
1723                    // }}}
[753]1724                case XC_INIT_NS_FCALL_BY_NAME:
[749]1725                case XC_INIT_FCALL_BY_NAME: // {{{
[755]1726                    array_push($EX['arg_types_stack'], array($EX['fbc'], $EX['object'], $EX['called_scope']));
[749]1727                    if (!ZEND_ENGINE_2 && ($ext & ZEND_CTOR_CALL)) {
1728                        break;
[1]1729                    }
[749]1730                    $EX['object'] = null;
1731                    $EX['called_scope'] = null;
1732                    $EX['fbc'] = $this->getOpVal($op2, $EX);
[1]1733                    break;
1734                    // }}}
[749]1735                case XC_INIT_FCALL_BY_FUNC: // {{{ deprecated even in PHP 4?
1736                    $EX['object'] = null;
1737                    $EX['called_scope'] = null;
1738                    $which = $op1['var'];
1739                    $EX['fbc'] = $EX['op_array']['funcs'][$which]['name'];
1740                    break;
1741                    // }}}
[1]1742                case XC_DO_FCALL_BY_FUNC:
[716]1743                    $which = $op1['var'];
[1]1744                    $fname = $EX['op_array']['funcs'][$which]['name'];
1745                    $args = $this->popargs($EX, $ext);
1746                    $resvar = $fname . "($args)";
1747                    break;
1748                case XC_DO_FCALL:
[749]1749                    $fname = unquoteName($this->getOpVal($op1, $EX, false), $EX);
[1]1750                    $args = $this->popargs($EX, $ext);
1751                    $resvar = $fname . "($args)";
1752                    break;
1753                case XC_DO_FCALL_BY_NAME: // {{{
1754                    $object = null;
1755
[749]1756                    $fname = unquoteName($EX['fbc'], $EX);
[1]1757                    if (!is_int($EX['object'])) {
1758                        $object = $EX['object'];
1759                    }
1760
1761                    $args = $this->popargs($EX, $ext);
1762
[753]1763                    $prefix = (isset($object) ? $object . '->' : '' )
1764                        . (isset($EX['called_scope']) ? $EX['called_scope'] . '::' : '' );
1765                    $resvar = $prefix
1766                        . (!$prefix ? $this->stripNamespace($fname) : $fname)
1767                        . "($args)";
[1]1768                    unset($args);
1769
1770                    if (is_int($EX['object'])) {
1771                        $T[$EX['object']] = $resvar;
1772                        $resvar = null;
1773                    }
[720]1774                    list($EX['fbc'], $EX['object'], $EX['called_scope']) = array_pop($EX['arg_types_stack']);
[1]1775                    break;
1776                    // }}}
1777                case XC_VERIFY_ABSTRACT_CLASS: // {{{
[716]1778                    //unset($T[$op1['var']]);
[1]1779                    break;
1780                    // }}}
1781                case XC_DECLARE_CLASS: 
[714]1782                case XC_DECLARE_INHERITED_CLASS:
1783                case XC_DECLARE_INHERITED_CLASS_DELAYED: // {{{
[716]1784                    $key = $op1['constant'];
[714]1785                    if (!isset($this->dc['class_table'][$key])) {
1786                        echo 'class not found: ', $key, 'existing classes are:', "\n";
1787                        var_dump(array_keys($this->dc['class_table']));
[1]1788                        exit;
1789                    }
[714]1790                    $class = &$this->dc['class_table'][$key];
[751]1791                    if (!isset($class['name'])) {
1792                        $class['name'] = unquoteName($this->getOpVal($op2, $EX), $EX);
1793                    }
[714]1794                    if ($opc == XC_DECLARE_INHERITED_CLASS || $opc == XC_DECLARE_INHERITED_CLASS_DELAYED) {
[1]1795                        $ext /= XC_SIZEOF_TEMP_VARIABLE;
1796                        $class['parent'] = $T[$ext];
1797                        unset($T[$ext]);
1798                    }
1799                    else {
1800                        $class['parent'] = null;
1801                    }
1802
[749]1803                    for (;;) {
[787]1804                        if ($i + 1 <= $last
[749]1805                         && $opcodes[$i + 1]['opcode'] == XC_ADD_INTERFACE
1806                         && $opcodes[$i + 1]['op1']['var'] == $res['var']) {
1807                            // continue
1808                        }
[787]1809                        else if ($i + 2 <= $last
[749]1810                         && $opcodes[$i + 2]['opcode'] == XC_ADD_INTERFACE
1811                         && $opcodes[$i + 2]['op1']['var'] == $res['var']
1812                         && $opcodes[$i + 1]['opcode'] == XC_FETCH_CLASS) {
1813                            // continue
1814                        }
1815                        else {
1816                            break;
1817                        }
[761]1818                        $this->usedOps[XC_ADD_INTERFACE] = true;
[749]1819
[1]1820                        $fetchop = &$opcodes[$i + 1];
[753]1821                        $interface = $this->stripNamespace(unquoteName($this->getOpVal($fetchop['op2'], $EX), $EX));
[1]1822                        $addop = &$opcodes[$i + 2];
[753]1823                        $class['interfaces'][$addop['extended_value']] = $interface;
[1]1824                        unset($fetchop, $addop);
1825                        $i += 2;
1826                    }
1827                    $this->dclass($class);
[749]1828                    echo "\n";
[1]1829                    unset($class);
1830                    break;
1831                    // }}}
1832                case XC_INIT_STRING: // {{{
1833                    $resvar = "''";
1834                    break;
1835                    // }}}
1836                case XC_ADD_CHAR:
1837                case XC_ADD_STRING:
1838                case XC_ADD_VAR: // {{{
1839                    $op1val = $this->getOpVal($op1, $EX);
1840                    $op2val = $this->getOpVal($op2, $EX);
1841                    switch ($opc) {
1842                    case XC_ADD_CHAR:
[749]1843                        $op2val = value(chr(str($op2val)));
[1]1844                        break;
1845                    case XC_ADD_STRING:
1846                        break;
1847                    case XC_ADD_VAR:
1848                        break;
1849                    }
[749]1850                    if (str($op1val) == "''") {
[1]1851                        $rvalue = $op2val;
1852                    }
[749]1853                    else if (str($op2val) == "''") {
[1]1854                        $rvalue = $op1val;
1855                    }
1856                    else {
[744]1857                        $rvalue = str($op1val) . ' . ' . str($op2val);
[1]1858                    }
1859                    $resvar = $rvalue;
1860                    // }}}
1861                    break;
1862                case XC_PRINT: // {{{
1863                    $op1val = $this->getOpVal($op1, $EX);
[761]1864                    $resvar = "print(" . str($op1val) . ")";
[1]1865                    break;
1866                    // }}}
1867                case XC_ECHO: // {{{
1868                    $op1val = $this->getOpVal($op1, $EX);
[744]1869                    $resvar = "echo " . str($op1val);
[1]1870                    break;
1871                    // }}}
1872                case XC_EXIT: // {{{
1873                    $op1val = $this->getOpVal($op1, $EX);
1874                    $resvar = "exit($op1val)";
1875                    break;
1876                    // }}}
1877                case XC_INIT_ARRAY:
1878                case XC_ADD_ARRAY_ELEMENT: // {{{
1879                    $rvalue = $this->getOpVal($op1, $EX, false, true);
1880
1881                    if ($opc == XC_ADD_ARRAY_ELEMENT) {
[737]1882                        $assoc = $this->getOpVal($op2, $EX);
1883                        if (isset($assoc)) {
[799]1884                            $curResVar->value[] = array($assoc, $rvalue);
[1]1885                        }
1886                        else {
[799]1887                            $curResVar->value[] = array(null, $rvalue);
[1]1888                        }
1889                    }
1890                    else {
1891                        if ($opc == XC_INIT_ARRAY) {
1892                            $resvar = new Decompiler_Array();
1893                            if (!isset($rvalue)) {
1894                                continue;
1895                            }
1896                        }
1897
[737]1898                        $assoc = $this->getOpVal($op2, $EX);
1899                        if (isset($assoc)) {
1900                            $resvar->value[] = array($assoc, $rvalue);
[1]1901                        }
1902                        else {
[737]1903                            $resvar->value[] = array(null, $rvalue);
[1]1904                        }
1905                    }
1906                    break;
1907                    // }}}
1908                case XC_QM_ASSIGN: // {{{
[799]1909                    if (isset($curResVar) && is_a($curResVar, 'Decompiler_Binop')) {
1910                        $curResVar->op2 = $this->getOpVal($op1, $EX);
1911                    }
1912                    else {
1913                        $resvar = $this->getOpVal($op1, $EX);
1914                    }
[1]1915                    break;
1916                    // }}}
1917                case XC_BOOL: // {{{
1918                    $resvar = /*'(bool) ' .*/ $this->getOpVal($op1, $EX);
1919                    break;
1920                    // }}}
1921                case XC_RETURN: // {{{
[744]1922                    $resvar = "return " . str($this->getOpVal($op1, $EX));
[1]1923                    break;
1924                    // }}}
1925                case XC_INCLUDE_OR_EVAL: // {{{
[716]1926                    $type = $op2['var']; // hack
[1]1927                    $keyword = $this->includeTypes[$type];
[749]1928                    $resvar = "$keyword " . str($this->getOpVal($op1, $EX));
[1]1929                    break;
1930                    // }}}
1931                case XC_FE_RESET: // {{{
1932                    $resvar = $this->getOpVal($op1, $EX);
1933                    break;
1934                    // }}}
1935                case XC_FE_FETCH: // {{{
[791]1936                    $op['fe_src'] = $this->getOpVal($op1, $EX, false, true);
[1]1937                    $fe = new Decompiler_ForeachBox($op);
1938                    $fe->iskey = false;
[716]1939                    $T[$res['var']] = $fe;
[1]1940
1941                    ++ $i;
1942                    if (($ext & ZEND_FE_FETCH_WITH_KEY)) {
1943                        $fe = new Decompiler_ForeachBox($op);
1944                        $fe->iskey = true;
1945
1946                        $res = $opcodes[$i]['result'];
[716]1947                        $T[$res['var']] = $fe;
[1]1948                    }
1949                    break;
1950                    // }}}
1951                case XC_SWITCH_FREE: // {{{
1952                    break;
1953                    // }}}
1954                case XC_FREE: // {{{
[716]1955                    $free = $T[$op1['var']];
[1]1956                    if (!is_a($free, 'Decompiler_Array') && !is_a($free, 'Decompiler_Box')) {
1957                        $op['php'] = is_object($free) ? $free : $this->unquote($free, '(', ')');
1958                        $lastphpop = &$op;
1959                    }
[716]1960                    unset($T[$op1['var']], $free);
[1]1961                    break;
1962                    // }}}
1963                case XC_JMP_NO_CTOR:
1964                    break;
[749]1965                case XC_JMP_SET: // ?:
[799]1966                    $resvar = new Decompiler_Binop($this, $this->getOpVal($op1, $EX), XC_JMP_SET, null);
[760]1967                    break;
[1]1968                case XC_JMPNZ: // while
1969                case XC_JMPZNZ: // for
1970                case XC_JMPZ_EX: // and
1971                case XC_JMPNZ_EX: // or
1972                case XC_JMPZ: // {{{
1973                    if ($opc == XC_JMP_NO_CTOR && $EX['object']) {
1974                        $rvalue = $EX['object'];
1975                    }
1976                    else {
1977                        $rvalue = $this->getOpVal($op1, $EX);
1978                    }
1979
1980                    if (isset($op['cond_true'])) {
1981                        // any true comes here, so it's a "or"
1982                        $rvalue = implode(' or ', $op['cond_true']) . ' or ' . $rvalue;
1983                        unset($op['cond_true']);
1984                    }
1985                    if (isset($op['cond_false'])) {
[723]1986                        echo "TODO(cond_false):\n";
[1]1987                        var_dump($op);// exit;
1988                    }
[760]1989                    if ($opc == XC_JMPZ_EX || $opc == XC_JMPNZ_EX) {
[716]1990                        $targetop = &$EX['opcodes'][$op2['opline_num']];
[1]1991                        if ($opc == XC_JMPNZ_EX) {
[744]1992                            $targetop['cond_true'][] = foldToCode($rvalue, $EX);
[1]1993                        }
1994                        else {
[744]1995                            $targetop['cond_false'][] = foldToCode($rvalue, $EX);
[1]1996                        }
1997                        unset($targetop);
1998                    }
1999                    else {
2000                        $op['cond'] = $rvalue; 
2001                        $op['isjmp'] = true;
2002                    }
2003                    break;
2004                    // }}}
[758]2005                case XC_CONT:
2006                case XC_BRK:
2007                    $op['cond'] = null;
2008                    $op['isjmp'] = true;
2009                    $resvar = $opc == XC_CONT ? 'continue' : 'break';
2010                    $count = str($this->getOpVal($op2, $EX));
2011                    if ($count != '1') {
2012                        $resvar .= ' ' . $count;
2013                    }
2014                    break;
[749]2015                case XC_GOTO:
[787]2016                    $resvar = 'goto label' . $op['op1']['var'];
2017                    $istmpres = false;
2018                    break;
2019
[1]2020                case XC_JMP: // {{{
2021                    $op['cond'] = null;
2022                    $op['isjmp'] = true;
2023                    break;
2024                    // }}}
2025                case XC_CASE:
[790]2026                    // $switchValue = $this->getOpVal($op1, $EX);
[743]2027                    $caseValue = $this->getOpVal($op2, $EX);
[790]2028                    $resvar = $caseValue;
[743]2029                    break;
[1]2030                case XC_RECV_INIT:
2031                case XC_RECV:
2032                    $offset = $this->getOpVal($op1, $EX);
2033                    $lvalue = $this->getOpVal($op['result'], $EX);
2034                    if ($opc == XC_RECV_INIT) {
[716]2035                        $default = value($op['op2']['constant']);
[1]2036                    }
2037                    else {
2038                        $default = null;
2039                    }
[737]2040                    $EX['recvs'][str($offset)] = array($lvalue, $default);
[1]2041                    break;
2042                case XC_POST_DEC:
2043                case XC_POST_INC:
2044                case XC_POST_DEC_OBJ:
2045                case XC_POST_INC_OBJ:
2046                case XC_PRE_DEC:
2047                case XC_PRE_INC:
2048                case XC_PRE_DEC_OBJ:
2049                case XC_PRE_INC_OBJ: // {{{
2050                    $flags = array_flip(explode('_', $opname));
2051                    if (isset($flags['OBJ'])) {
[761]2052                        $resvar = $this->getOpVal($op1, $EX) . '->' . unquoteVariableName($this->getOpVal($op2, $EX), $EX);
[1]2053                    }
2054                    else {
2055                        $resvar = $this->getOpVal($op1, $EX);
2056                    }
2057                    $opstr = isset($flags['DEC']) ? '--' : '++';
2058                    if (isset($flags['POST'])) {
[749]2059                        $resvar .= $opstr;
[1]2060                    }
2061                    else {
[749]2062                        $resvar = "$opstr$resvar";
[1]2063                    }
2064                    break;
2065                    // }}}
2066
2067                case XC_BEGIN_SILENCE: // {{{
2068                    $EX['silence'] ++;
2069                    break;
2070                    // }}}
2071                case XC_END_SILENCE: // {{{
2072                    $EX['silence'] --;
[744]2073                    $lastresvar = '@' . str($lastresvar, $EX);
[1]2074                    break;
2075                    // }}}
2076                case XC_CAST: // {{{
2077                    $type = $ext;
2078                    static $type2cast = array(
2079                            IS_LONG   => '(int)',
2080                            IS_DOUBLE => '(double)',
2081                            IS_STRING => '(string)',
2082                            IS_ARRAY  => '(array)',
2083                            IS_OBJECT => '(object)',
2084                            IS_BOOL   => '(bool)',
2085                            IS_NULL   => '(unset)',
2086                            );
2087                    assert(isset($type2cast[$type]));
2088                    $cast = $type2cast[$type];
2089                    $resvar = $cast . ' ' . $this->getOpVal($op1, $EX);
2090                    break;
2091                    // }}}
2092                case XC_EXT_STMT:
2093                case XC_EXT_FCALL_BEGIN:
2094                case XC_EXT_FCALL_END:
2095                case XC_EXT_NOP:
2096                    break;
[751]2097                case XC_DECLARE_FUNCTION:
2098                    $this->dfunction($this->dc['function_table'][$op1['constant']], $EX['indent']);
2099                    break;
[752]2100                case XC_DECLARE_LAMBDA_FUNCTION: // {{{
[749]2101                    ob_start();
2102                    $this->dfunction($this->dc['function_table'][$op1['constant']], $EX['indent']);
2103                    $resvar = ob_get_clean();
2104                    $istmpres = true;
2105                    break;
[752]2106                    // }}}
2107                case XC_DECLARE_CONST:
[753]2108                    $name = $this->stripNamespace(unquoteName($this->getOpVal($op1, $EX), $EX));
2109                    $value = str($this->getOpVal($op2, $EX));
2110                    $resvar = 'const ' . $name . ' = ' . $value;
[752]2111                    break;
[1]2112                case XC_DECLARE_FUNCTION_OR_CLASS:
2113                    /* always removed by compiler */
2114                    break;
2115                case XC_TICKS:
2116                    $lastphpop['ticks'] = $this->getOpVal($op1, $EX);
2117                    // $EX['tickschanged'] = true;
2118                    break;
[749]2119                case XC_RAISE_ABSTRACT_ERROR:
2120                    // abstract function body is empty, don't need this code
2121                    break;
2122                case XC_USER_OPCODE:
2123                    echo '// ZEND_USER_OPCODE, impossible to decompile';
2124                    break;
2125                case XC_OP_DATA:
2126                    break;
[1]2127                default: // {{{
2128                    echo "\x1B[31m * TODO ", $opname, "\x1B[0m\n";
[761]2129                    $covered = false;
[1]2130                    // }}}
2131                }
[761]2132                if ($covered) {
2133                    $this->usedOps[$opc] = true;
2134                }
[1]2135            }
2136            if (isset($resvar)) {
2137                if ($istmpres) {
[716]2138                    $T[$res['var']] = $resvar;
2139                    $lastresvar = &$T[$res['var']];
[1]2140                }
2141                else {
2142                    $op['php'] = $resvar;
2143                    $lastphpop = &$op;
2144                    $lastresvar = &$op['php'];
2145                }
2146            }
2147        }
2148        return $T;
2149    }
2150    // }}}
2151    function unquote($str, $st, $ed) // {{{
2152    {
2153        $l1 = strlen($st);
2154        $l2 = strlen($ed);
2155        if (substr($str, 0, $l1) === $st && substr($str, -$l2) === $ed) {
2156            $str = substr($str, $l1, -$l2);
2157        }
2158        return $str;
2159    }
2160    // }}}
2161    function popargs(&$EX, $n) // {{{
2162    {
2163        $args = array();
2164        for ($i = 0; $i < $n; $i ++) {
2165            $a = array_pop($EX['argstack']);
2166            if (is_array($a)) {
[744]2167                array_unshift($args, foldToCode($a, $EX));
[1]2168            }
2169            else {
2170                array_unshift($args, $a);
2171            }
2172        }
2173        return implode(', ', $args);
2174    }
2175    // }}}
2176    function dumpop($op, &$EX) // {{{
2177    {
[795]2178        assert('isset($op)');
[1]2179        $op1 = $op['op1'];
2180        $op2 = $op['op2'];
[763]2181        $d = array(xcache_get_opcode($op['opcode']), $op['opcode']);
[1]2182
[762]2183        foreach (array('op1' => '1:', 'op2' => '2:', 'result' => '>') as $k => $kk) {
[1]2184            switch ($op[$k]['op_type']) {
2185            case XC_IS_UNUSED:
[762]2186                $d[$kk] = 'U:' . $op[$k]['opline_num'];
[1]2187                break;
2188
2189            case XC_IS_VAR:
[716]2190                $d[$kk] = '$' . $op[$k]['var'];
[762]2191                if ($k != 'result') {
[749]2192                    $d[$kk] .= ':' . str($this->getOpVal($op[$k], $EX));
[1]2193                }
2194                break;
2195
2196            case XC_IS_TMP_VAR:
[716]2197                $d[$kk] = '#' . $op[$k]['var'];
[762]2198                if ($k != 'result') {
[749]2199                    $d[$kk] .= ':' . str($this->getOpVal($op[$k], $EX));
[1]2200                }
2201                break;
2202
2203            case XC_IS_CV:
2204                $d[$kk] = $this->getOpVal($op[$k], $EX);
2205                break;
2206
2207            default:
[762]2208                if ($k == 'result') {
[731]2209                    var_dump($op);
[795]2210                    assert(0);
[731]2211                    exit;
[1]2212                }
2213                else {
2214                    $d[$kk] = $this->getOpVal($op[$k], $EX);
2215                }
2216            }
2217        }
[762]2218        $d[';'] = $op['extended_value'];
[795]2219        if (!empty($op['jmpouts'])) {
2220            $d['>>'] = implode(',', $op['jmpouts']);
2221        }
2222        if (!empty($op['jmpins'])) {
2223            $d['<<'] = implode(',', $op['jmpins']);
2224        }
[1]2225
[762]2226        foreach ($d as $k => $v) {
[763]2227            echo is_int($k) ? '' : $k, str($v), "\t";
[762]2228        }
2229        echo PHP_EOL;
[1]2230    }
2231    // }}}
[790]2232    function dumpRange(&$EX, $first, $last, $indent = '') // {{{
[787]2233    {
2234        for ($i = $first; $i <= $last; ++$i) {
[790]2235            echo $indent, $i, "\t"; $this->dumpop($EX['opcodes'][$i], $EX);
[787]2236        }
[790]2237        echo $indent, "==", PHP_EOL;
[787]2238    }
2239    // }}}
[1]2240    function dargs(&$EX, $indent) // {{{
2241    {
2242        $op_array = &$EX['op_array'];
2243
2244        if (isset($op_array['num_args'])) {
2245            $c = $op_array['num_args'];
2246        }
2247        else if ($op_array['arg_types']) {
2248            $c = count($op_array['arg_types']);
2249        }
2250        else {
2251            // php4
2252            $c = count($EX['recvs']);
2253        }
2254
2255        $refrest = false;
2256        for ($i = 0; $i < $c; $i ++) {
2257            if ($i) {
2258                echo ', ';
2259            }
[736]2260            $arg = $EX['recvs'][$i + 1];
[1]2261            if (isset($op_array['arg_info'])) {
2262                $ai = $op_array['arg_info'][$i];
2263                if (!empty($ai['class_name'])) {
[753]2264                    echo $this->stripNamespace($ai['class_name']), ' ';
[736]2265                    if (!ZEND_ENGINE_2_2 && $ai['allow_null']) {
[1]2266                        echo 'or NULL ';
2267                    }
2268                }
2269                else if (!empty($ai['array_type_hint'])) {
2270                    echo 'array ';
[736]2271                    if (!ZEND_ENGINE_2_2 && $ai['allow_null']) {
[1]2272                        echo 'or NULL ';
2273                    }
2274                }
2275                if ($ai['pass_by_reference']) {
2276                    echo '&';
2277                }
2278                printf("\$%s", $ai['name']);
2279            }
2280            else {
2281                if ($refrest) {
2282                    echo '&';
2283                }
2284                else if (isset($op_array['arg_types'][$i])) {
2285                    switch ($op_array['arg_types'][$i]) {
2286                    case BYREF_FORCE_REST:
2287                        $refrest = true;
2288                        /* fall */
2289                    case BYREF_FORCE:
2290                        echo '&';
2291                        break;
2292
2293                    case BYREF_NONE:
2294                    case BYREF_ALLOW:
2295                        break;
2296                    default:
2297                        assert(0);
2298                    }
2299                }
[744]2300                echo str($arg[0], $indent);
[1]2301            }
[736]2302            if (isset($arg[1])) {
[744]2303                echo ' = ', str($arg[1], $indent);
[736]2304            }
[1]2305        }
2306    }
2307    // }}}
[780]2308    function duses(&$EX, $indent) // {{{
2309    {
[781]2310        if ($EX['uses']) {
2311            echo ' use(', implode(', ', $EX['uses']), ')';
[780]2312        }
2313    }
2314    // }}}
[1]2315    function dfunction($func, $indent = '', $nobody = false) // {{{
2316    {
[753]2317        $this->detectNamespace($func['op_array']['function_name']);
2318
[1]2319        if ($nobody) {
2320            $EX = array();
2321            $EX['op_array'] = &$func['op_array'];
2322            $EX['recvs'] = array();
[780]2323            $EX['uses'] = array();
[1]2324        }
2325        else {
2326            ob_start();
2327            $newindent = INDENT . $indent;
2328            $EX = &$this->dop_array($func['op_array'], $newindent);
2329            $body = ob_get_clean();
2330        }
2331
[753]2332        $functionName = $this->stripNamespace($func['op_array']['function_name']);
[749]2333        if ($functionName == '{closure}') {
2334            $functionName = '';
2335        }
[781]2336        echo 'function', $functionName ? ' ' . $functionName : '', '(';
[1]2337        $this->dargs($EX, $indent);
[749]2338        echo ")";
[780]2339        $this->duses($EX, $indent);
[749]2340        if ($nobody) {
2341            echo ";\n";
2342        }
2343        else {
2344            if ($functionName !== '') {
2345                echo "\n";
2346                echo $indent, "{\n";
2347            }
2348            else {
2349                echo " {\n";
2350            }
2351
2352            echo $body;
2353            echo "$indent}";
2354            if ($functionName !== '') {
2355                echo "\n";
2356            }
2357        }
[1]2358    }
2359    // }}}
2360    function dclass($class, $indent = '') // {{{
2361    {
[753]2362        $this->detectNamespace($class['name']);
2363
[1]2364        // {{{ class decl
2365        if (!empty($class['doc_comment'])) {
2366            echo $indent;
2367            echo $class['doc_comment'];
2368            echo "\n";
2369        }
2370        $isinterface = false;
2371        if (!empty($class['ce_flags'])) {
2372            if ($class['ce_flags'] & ZEND_ACC_INTERFACE) {
2373                $isinterface = true;
2374            }
2375            else {
[749]2376                if ($class['ce_flags'] & ZEND_ACC_IMPLICIT_ABSTRACT_CLASS) {
[1]2377                    echo "abstract ";
2378                }
[749]2379                if ($class['ce_flags'] & ZEND_ACC_FINAL_CLASS) {
[1]2380                    echo "final ";
2381                }
2382            }
2383        }
[753]2384        echo $isinterface ? 'interface ' : 'class ', $this->stripNamespace($class['name']);
[1]2385        if ($class['parent']) {
2386            echo ' extends ', $class['parent'];
2387        }
2388        /* TODO */
2389        if (!empty($class['interfaces'])) {
2390            echo ' implements ';
2391            echo implode(', ', $class['interfaces']);
2392        }
2393        echo "\n";
2394        echo $indent, "{";
2395        // }}}
2396        $newindent = INDENT . $indent;
2397        // {{{ const, static
2398        foreach (array('constants_table' => 'const '
2399                    , 'static_members' => 'static $') as $type => $prefix) {
2400            if (!empty($class[$type])) {
2401                echo "\n";
2402                // TODO: skip shadow?
2403                foreach ($class[$type] as $name => $v) {
2404                    echo $newindent;
2405                    echo $prefix, $name, ' = ';
[744]2406                    echo str(value($v), $newindent);
[1]2407                    echo ";\n";
2408                }
2409            }
2410        }
2411        // }}}
2412        // {{{ properties
[730]2413        $member_variables = isset($class['properties_info']) ? $class['properties_info'] : ($class['default_static_members'] + $class['default_properties']);
2414        if ($member_variables) {
[1]2415            echo "\n";
[713]2416            $infos = !empty($class['properties_info']) ? $class['properties_info'] : null;
[730]2417            foreach ($member_variables as $name => $dummy) {
[1]2418                $info = (isset($infos) && isset($infos[$name])) ? $infos[$name] : null;
2419                if (isset($info)) {
2420                    if (!empty($info['doc_comment'])) {
2421                        echo $newindent;
2422                        echo $info['doc_comment'];
2423                        echo "\n";
2424                    }
2425                }
2426
2427                echo $newindent;
[713]2428                $static = false;
2429                if (isset($info)) {
2430                    if ($info['flags'] & ZEND_ACC_STATIC) {
2431                        $static = true;
2432                    }
2433                }
2434                else if (isset($class['default_static_members'][$name])) {
2435                    $static = true;
2436                }
2437
2438                if ($static) {
2439                    echo "static ";
2440                }
2441
2442                $mangled = false;
[731]2443                if (!ZEND_ENGINE_2) {
[1]2444                    echo 'var ';
2445                }
2446                else if (!isset($info)) {
2447                    echo 'public ';
2448                }
2449                else {
2450                    if ($info['flags'] & ZEND_ACC_SHADOW) {
2451                        continue;
2452                    }
2453                    switch ($info['flags'] & ZEND_ACC_PPP_MASK) {
2454                    case ZEND_ACC_PUBLIC:
2455                        echo "public ";
2456                        break;
2457                    case ZEND_ACC_PRIVATE:
2458                        echo "private ";
[713]2459                        $mangled = true;
[1]2460                        break;
2461                    case ZEND_ACC_PROTECTED:
2462                        echo "protected ";
[713]2463                        $mangled = true;
[1]2464                        break;
2465                    }
2466                }
2467
2468                echo '$', $name;
[713]2469
[730]2470                if (isset($info['offset'])) {
2471                    $value = $class[$static ? 'default_static_members_table' : 'default_properties_table'][$info['offset']];
2472                }
2473                else {
2474                    $key = isset($info) ? $info['name'] . ($mangled ? "\000" : "") : $name;
[713]2475
[730]2476                    $value = $class[$static ? 'default_static_members' : 'default_properties'][$key];
2477                }
[713]2478                if (isset($value)) {
[1]2479                    echo ' = ';
[744]2480                    echo str(value($value), $newindent);
[1]2481                }
2482                echo ";\n";
2483            }
2484        }
2485        // }}}
2486        // {{{ function_table
2487        if (isset($class['function_table'])) {
2488            foreach ($class['function_table'] as $func) {
2489                if (!isset($func['scope']) || $func['scope'] == $class['name']) {
2490                    // TODO: skip shadow here
2491                    echo "\n";
2492                    $opa = $func['op_array'];
2493                    if (!empty($opa['doc_comment'])) {
2494                        echo $newindent;
2495                        echo $opa['doc_comment'];
2496                        echo "\n";
2497                    }
2498                    echo $newindent;
[749]2499                    $isAbstractMethod = false;
[1]2500                    if (isset($opa['fn_flags'])) {
[749]2501                        if (($opa['fn_flags'] & ZEND_ACC_ABSTRACT) && !$isinterface) {
[1]2502                            echo "abstract ";
[749]2503                            $isAbstractMethod = true;
[1]2504                        }
2505                        if ($opa['fn_flags'] & ZEND_ACC_FINAL) {
2506                            echo "final ";
2507                        }
2508                        if ($opa['fn_flags'] & ZEND_ACC_STATIC) {
2509                            echo "static ";
2510                        }
2511
2512                        switch ($opa['fn_flags'] & ZEND_ACC_PPP_MASK) {
2513                            case ZEND_ACC_PUBLIC:
2514                                echo "public ";
2515                                break;
2516                            case ZEND_ACC_PRIVATE:
2517                                echo "private ";
2518                                break;
2519                            case ZEND_ACC_PROTECTED:
2520                                echo "protected ";
2521                                break;
2522                            default:
2523                                echo "<visibility error> ";
2524                                break;
2525                        }
2526                    }
[749]2527                    $this->dfunction($func, $newindent, $isinterface || $isAbstractMethod);
[1]2528                    if ($opa['function_name'] == 'Decompiler') {
2529                        //exit;
2530                    }
2531                }
2532            }
2533        }
2534        // }}}
2535        echo $indent, "}\n";
2536    }
2537    // }}}
2538    function decompileString($string) // {{{
2539    {
2540        $this->dc = xcache_dasm_string($string);
2541        if ($this->dc === false) {
2542            echo "error compling string\n";
2543            return false;
2544        }
2545    }
2546    // }}}
2547    function decompileFile($file) // {{{
2548    {
2549        $this->dc = xcache_dasm_file($file);
2550        if ($this->dc === false) {
2551            echo "error compling $file\n";
2552            return false;
2553        }
2554    }
2555    // }}}
2556    function output() // {{{
2557    {
[749]2558        echo "<?". "php\n\n";
[1]2559        foreach ($this->dc['class_table'] as $key => $class) {
2560            if ($key{0} != "\0") {
[749]2561                $this->dclass($class);
[1]2562                echo "\n";
2563            }
2564        }
2565
2566        foreach ($this->dc['function_table'] as $key => $func) {
2567            if ($key{0} != "\0") {
[749]2568                $this->dfunction($func);
[1]2569                echo "\n";
2570            }
2571        }
2572
2573        $this->dop_array($this->dc['op_array']);
2574        echo "\n?" . ">\n";
[761]2575
2576        if (!empty($this->test)) {
2577            $this->outputUnusedOp();
2578        }
[1]2579        return true;
2580    }
2581    // }}}
[761]2582    function outputUnusedOp() // {{{
2583    {
2584        for ($i = 0; $opname = xcache_get_opcode($i); $i ++) {
2585            if ($opname == 'UNDEF')  {
2586                continue;
2587            }
2588
2589            if (!isset($this->usedOps[$i])) {
2590                echo "not covered opcode ", $opname, "\n";
2591            }
2592        }
2593    }
2594    // }}}
[1]2595}
2596
2597// {{{ defines
[749]2598define('ZEND_ENGINE_2_4', PHP_VERSION >= "5.3.99");
2599define('ZEND_ENGINE_2_3', ZEND_ENGINE_2_4 || PHP_VERSION >= "5.3.");
2600define('ZEND_ENGINE_2_2', ZEND_ENGINE_2_3 || PHP_VERSION >= "5.2.");
2601define('ZEND_ENGINE_2_1', ZEND_ENGINE_2_2 || PHP_VERSION >= "5.1.");
2602define('ZEND_ENGINE_2',   ZEND_ENGINE_2_1 || PHP_VERSION >= "5.0.");
2603
[1]2604define('ZEND_ACC_STATIC',         0x01);
2605define('ZEND_ACC_ABSTRACT',       0x02);
2606define('ZEND_ACC_FINAL',          0x04);
2607define('ZEND_ACC_IMPLEMENTED_ABSTRACT',       0x08);
2608
2609define('ZEND_ACC_IMPLICIT_ABSTRACT_CLASS',    0x10);
2610define('ZEND_ACC_EXPLICIT_ABSTRACT_CLASS',    0x20);
2611define('ZEND_ACC_FINAL_CLASS',                0x40);
2612define('ZEND_ACC_INTERFACE',                  0x80);
[749]2613if (ZEND_ENGINE_2_4) {
2614    define('ZEND_ACC_TRAIT',                  0x120);
2615}
[1]2616define('ZEND_ACC_PUBLIC',     0x100);
2617define('ZEND_ACC_PROTECTED',  0x200);
2618define('ZEND_ACC_PRIVATE',    0x400);
2619define('ZEND_ACC_PPP_MASK',  (ZEND_ACC_PUBLIC | ZEND_ACC_PROTECTED | ZEND_ACC_PRIVATE));
2620
2621define('ZEND_ACC_CHANGED',    0x800);
2622define('ZEND_ACC_IMPLICIT_PUBLIC',    0x1000);
2623
2624define('ZEND_ACC_CTOR',       0x2000);
2625define('ZEND_ACC_DTOR',       0x4000);
2626define('ZEND_ACC_CLONE',      0x8000);
2627
2628define('ZEND_ACC_ALLOW_STATIC',   0x10000);
2629
2630define('ZEND_ACC_SHADOW', 0x2000);
2631
[731]2632if (ZEND_ENGINE_2_4) {
2633    define('ZEND_FETCH_GLOBAL',           0x00000000);
2634    define('ZEND_FETCH_LOCAL',            0x10000000);
2635    define('ZEND_FETCH_STATIC',           0x20000000);
2636    define('ZEND_FETCH_STATIC_MEMBER',    0x30000000);
2637    define('ZEND_FETCH_GLOBAL_LOCK',      0x40000000);
2638    define('ZEND_FETCH_LEXICAL',          0x50000000);
2639
2640    define('ZEND_FETCH_TYPE_MASK',        0x70000000);
2641}
2642else {
2643    define('ZEND_FETCH_GLOBAL',           0);
2644    define('ZEND_FETCH_LOCAL',            1);
2645    define('ZEND_FETCH_STATIC',           2);
2646    define('ZEND_FETCH_STATIC_MEMBER',    3);
2647    define('ZEND_FETCH_GLOBAL_LOCK',      4);
2648}
2649
[1]2650define('ZEND_FETCH_CLASS_DEFAULT',    0);
2651define('ZEND_FETCH_CLASS_SELF',       1);
2652define('ZEND_FETCH_CLASS_PARENT',     2);
2653define('ZEND_FETCH_CLASS_MAIN',       3);
2654define('ZEND_FETCH_CLASS_GLOBAL',     4);
2655define('ZEND_FETCH_CLASS_AUTO',       5);
2656define('ZEND_FETCH_CLASS_INTERFACE',  6);
[722]2657define('ZEND_FETCH_CLASS_STATIC',     7);
[731]2658if (ZEND_ENGINE_2_4) {
2659    define('ZEND_FETCH_CLASS_TRAIT',     14);
2660}
2661if (ZEND_ENGINE_2_3) {
2662    define('ZEND_FETCH_CLASS_MASK',     0xF);
2663}
[1]2664
2665define('ZEND_EVAL',               (1<<0));
2666define('ZEND_INCLUDE',            (1<<1));
2667define('ZEND_INCLUDE_ONCE',       (1<<2));
2668define('ZEND_REQUIRE',            (1<<3));
2669define('ZEND_REQUIRE_ONCE',       (1<<4));
2670
2671define('ZEND_ISSET',              (1<<0));
2672define('ZEND_ISEMPTY',            (1<<1));
[731]2673if (ZEND_ENGINE_2_4) {
2674    define('EXT_TYPE_UNUSED',     (1<<5));
2675}
2676else {
2677    define('EXT_TYPE_UNUSED',     (1<<0));
2678}
[1]2679
2680define('ZEND_FETCH_STANDARD',     0);
2681define('ZEND_FETCH_ADD_LOCK',     1);
2682
2683define('ZEND_FE_FETCH_BYREF',     1);
2684define('ZEND_FE_FETCH_WITH_KEY',  2);
2685
2686define('ZEND_MEMBER_FUNC_CALL',   1<<0);
2687define('ZEND_CTOR_CALL',          1<<1);
2688
2689define('ZEND_ARG_SEND_BY_REF',        (1<<0));
2690define('ZEND_ARG_COMPILE_TIME_BOUND', (1<<1));
2691define('ZEND_ARG_SEND_FUNCTION',      (1<<2));
2692
2693define('BYREF_NONE',       0);
2694define('BYREF_FORCE',      1);
2695define('BYREF_ALLOW',      2);
2696define('BYREF_FORCE_REST', 3);
2697define('IS_NULL',     0);
2698define('IS_LONG',     1);
2699define('IS_DOUBLE',   2);
[761]2700define('IS_BOOL',     ZEND_ENGINE_2 ? 3 : 6);
[1]2701define('IS_ARRAY',    4);
2702define('IS_OBJECT',   5);
[761]2703define('IS_STRING',   ZEND_ENGINE_2 ? 6 : 3);
[1]2704define('IS_RESOURCE', 7);
2705define('IS_CONSTANT', 8);
2706define('IS_CONSTANT_ARRAY',   9);
[781]2707/* Ugly hack to support constants as static array indices */
2708define('IS_CONSTANT_TYPE_MASK',   0x0f);
2709define('IS_CONSTANT_UNQUALIFIED', 0x10);
2710define('IS_CONSTANT_INDEX',       0x80);
2711define('IS_LEXICAL_VAR',          0x20);
2712define('IS_LEXICAL_REF',          0x40);
[1]2713
2714@define('XC_IS_CV', 16);
2715
2716/*
2717if (preg_match_all('!XC_[A-Z_]+!', file_get_contents(__FILE__), $ms)) {
2718    $verdiff = array();
2719    foreach ($ms[0] as $k) {
2720        if (!defined($k)) {
2721            $verdiff[$k] = -1;
2722            define($k, -1);
2723        }
2724    }
2725    var_export($verdiff);
2726}
2727/*/
2728foreach (array (
2729    'XC_HANDLE_EXCEPTION' => -1,
2730    'XC_FETCH_CLASS' => -1,
2731    'XC_FETCH_' => -1,
2732    'XC_FETCH_DIM_' => -1,
2733    'XC_ASSIGN_DIM' => -1,
2734    'XC_UNSET_DIM' => -1,
[749]2735    'XC_UNSET_OBJ' => -1,
[1]2736    'XC_ASSIGN_OBJ' => -1,
2737    'XC_ISSET_ISEMPTY_DIM_OBJ' => -1,
2738    'XC_ISSET_ISEMPTY_PROP_OBJ' => -1,
2739    'XC_ISSET_ISEMPTY_VAR' => -1,
[720]2740    'XC_INIT_STATIC_METHOD_CALL' => -1,
[1]2741    'XC_INIT_METHOD_CALL' => -1,
2742    'XC_VERIFY_ABSTRACT_CLASS' => -1,
2743    'XC_DECLARE_CLASS' => -1,
2744    'XC_DECLARE_INHERITED_CLASS' => -1,
[714]2745    'XC_DECLARE_INHERITED_CLASS_DELAYED' => -1,
[1]2746    'XC_ADD_INTERFACE' => -1,
2747    'XC_POST_DEC_OBJ' => -1,
2748    'XC_POST_INC_OBJ' => -1,
2749    'XC_PRE_DEC_OBJ' => -1,
2750    'XC_PRE_INC_OBJ' => -1,
2751    'XC_UNSET_OBJ' => -1,
2752    'XC_JMP_NO_CTOR' => -1,
2753    'XC_FETCH_' => -1,
2754    'XC_FETCH_DIM_' => -1,
2755    'XC_UNSET_DIM_OBJ' => -1,
2756    'XC_ISSET_ISEMPTY' => -1,
2757    'XC_INIT_FCALL_BY_FUNC' => -1,
2758    'XC_DO_FCALL_BY_FUNC' => -1,
2759    'XC_DECLARE_FUNCTION_OR_CLASS' => -1,
[749]2760    'XC_INIT_NS_FCALL_BY_NAME' => -1,
2761    'XC_GOTO' => -1,
2762    'XC_CATCH' => -1,
2763    'XC_THROW' => -1,
2764    'XC_INSTANCEOF' => -1,
2765    'XC_DECLARE_FUNCTION' => -1,
2766    'XC_RAISE_ABSTRACT_ERROR' => -1,
2767    'XC_DECLARE_CONST' => -1,
2768    'XC_USER_OPCODE' => -1,
2769    'XC_JMP_SET' => -1,
2770    'XC_DECLARE_LAMBDA_FUNCTION' => -1,
[1]2771) as $k => $v) {
2772    if (!defined($k)) {
2773        define($k, $v);
2774    }
2775}
2776// }}}
2777
Note: See TracBrowser for help on using the repository browser.