source: trunk/Decompiler.class.php @ 796

Last change on this file since 796 was 796, checked in by moo, 4 years ago

code format cleanup

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