source: trunk/Decompiler.class.php @ 795

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

Decompiler: decompile try/catch

  • Property svn:eol-style set to native
File size: 66.7 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);
744            echo $indent, 'try {', PHP_EOL;
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];
752                echo $indent, 'catch (', str($this->getOpVal($catchOp['op1'], $EX)), ' ', str($this->getOpVal($catchOp['op2'], $EX)), ') {', PHP_EOL;
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        // }}}
763
[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);
767            echo $indent, 'switch (' . str($this->getOpVal($firstOp['op1'], $EX)) . ') {', PHP_EOL;
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
808            echo $indent, 'switch (', str($this->getOpVal($caseOp['op1'], $EX, true, true), $EX), ') {', PHP_EOL;
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        }
862
[789]863        if ($lastOp['opcode'] == XC_JMPNZ && !empty($lastOp['jmpouts'])
[787]864         && $lastOp['jmpouts'][0] == $first) {
865            $this->removeJmpInfo($EX, $last);
[788]866            $this->beginComplexBlock($EX);
[789]867
[787]868            echo $indent, 'do {', PHP_EOL;
869            $this->recognizeAndDecompileClosedBlocks($EX, $first, $last, $indent . INDENT);
870            echo $indent, '} while (', str($this->getOpVal($lastOp['op1'], $EX)), ');', PHP_EOL;
[789]871
[788]872            $this->endComplexBlock($EX);
[787]873            return;
874        }
875
876        $firstJmp = null;
877        $firstJmpOp = null;
878        for ($i = $first; $i <= $last; ++$i) {
879            if (!empty($opcodes[$i]['jmpouts'])) {
880                $firstJmp = $i;
881                $firstJmpOp = &$opcodes[$firstJmp];
882                break;
883            }
884        }
885
886        if (isset($firstJmpOp)
887         && $firstJmpOp['opcode'] == XC_JMPZ
[789]888         && $firstJmpOp['jmpouts'][0] > $last
889         && $lastOp['opcode'] == XC_JMP && !empty($lastOp['jmpouts'])
[787]890         && $lastOp['jmpouts'][0] == $first) {
891            $this->removeJmpInfo($EX, $firstJmp);
892            $this->removeJmpInfo($EX, $last);
[789]893            $this->beginComplexBlock($EX);
[787]894
895            ob_start();
896            $this->recognizeAndDecompileClosedBlocks($EX, $first, $last, $indent . INDENT);
[789]897            $body = ob_get_clean();
898
[787]899            echo $indent, 'while (', str($this->getOpVal($firstJmpOp['op1'], $EX)), ') {', PHP_EOL;
[789]900            echo $body;
[787]901            echo $indent, '}', PHP_EOL;
[789]902
[788]903            $this->endComplexBlock($EX);
[787]904            return;
905        }
906
[789]907        if (isset($firstJmpOp)
908         && $firstJmpOp['opcode'] == XC_FE_FETCH
909         && $firstJmpOp['jmpouts'][0] > $last
910         && $lastOp['opcode'] == XC_JMP && !empty($lastOp['jmpouts'])
911         && $lastOp['jmpouts'][0] == $firstJmp) {
912            $this->removeJmpInfo($EX, $firstJmp);
913            $this->removeJmpInfo($EX, $last);
914            $this->beginComplexBlock($EX);
915
916            ob_start();
917            $this->recognizeAndDecompileClosedBlocks($EX, $first, $last, $indent . INDENT);
918            $body = ob_get_clean();
919
920            $as = foldToCode($firstJmpOp['fe_as'], $EX);
921            if (isset($firstJmpOp['fe_key'])) {
922                $as = str($firstJmpOp['fe_key'], $EX) . ' => ' . str($as);
923            }
924
925            echo $indent, 'foreach (', str($firstJmpOp['fe_src'], $EX), " as $as) {", PHP_EOL;
926            echo $body;
927            echo $indent, '}', PHP_EOL;
928
929            $this->endComplexBlock($EX);
930            return;
931        }
932
[787]933        $this->decompileBasicBlock($EX, $first, $last, $indent);
934    }
935    // }}}
936    function recognizeAndDecompileClosedBlocks(&$EX, $first, $last, $indent) // {{{ decompile in a tree way
937    {
938        $opcodes = &$EX['opcodes'];
939
[791]940        $starti = $first;
[795]941        for ($i = $starti; $i <= $last; ) {
942            if (!empty($opcodes[$i]['jmpins']) || !empty($opcodes[$i]['jmpouts'])) {
[787]943                $blockFirst = $i;
944                $blockLast = -1;
[791]945                $j = $blockFirst;
[787]946                do {
[791]947                    $op = $opcodes[$j];
[787]948                    if (!empty($op['jmpins'])) {
949                        // care about jumping from blocks behind, not before
950                        foreach ($op['jmpins'] as $oplineNumber) {
951                            if ($oplineNumber <= $last && $blockLast < $oplineNumber) {
952                                $blockLast = $oplineNumber;
953                            }
954                        }
955                    }
956                    if (!empty($op['jmpouts'])) {
957                        $blockLast = max($blockLast, max($op['jmpouts']) - 1);
958                    }
[791]959                    ++$j;
960                } while ($j <= $blockLast);
[795]961                if (!assert('$blockLast <= $last')) {
962                    var_dump($blockLast, $last);
963                }
[787]964
965                if ($blockLast >= $blockFirst) {
966                    if ($blockFirst > $starti) {
967                        $this->decompileBasicBlock($EX, $starti, $blockFirst - 1, $indent);
968                    }
969                    $this->decompileComplexBlock($EX, $blockFirst, $blockLast, $indent);
[791]970                    $starti = $blockLast + 1;
[795]971                    $i = $starti;
[787]972                }
[795]973                else {
974                    ++$i;
975                }
[787]976            }
[795]977            else {
978                ++$i;
979            }
[787]980        }
981        if ($starti <= $last) {
982            $this->decompileBasicBlock($EX, $starti, $last, $indent);
983        }
984    }
985    // }}}
[731]986    function &dop_array($op_array, $indent = '') // {{{
987    {
[735]988        $op_array['opcodes'] = $this->fixOpcode($op_array['opcodes'], true, $indent == '' ? 1 : null);
[731]989        $opcodes = &$op_array['opcodes'];
[795]990        $last = count($opcodes) - 1;
[787]991        // {{{ build jmpins/jmpouts to op_array
[795]992        for ($i = 0; $i <= $last; $i ++) {
[1]993            $op = &$opcodes[$i];
994            $op['line'] = $i;
995            switch ($op['opcode']) {
[758]996            case XC_CONT:
997            case XC_BRK:
998                $op['jmpouts'] = array();
999                break;
1000
[749]1001            case XC_GOTO:
[787]1002                $target = $op['op1']['var'];
1003                $op['goto'] = $target;
1004                $opcodes[$target]['gofrom'][] = $i;
1005                break;
1006
[1]1007            case XC_JMP:
[716]1008                $target = $op['op1']['var'];
[1]1009                $op['jmpouts'] = array($target);
1010                $opcodes[$target]['jmpins'][] = $i;
1011                break;
1012
1013            case XC_JMPZNZ:
[716]1014                $jmpz = $op['op2']['opline_num'];
[1]1015                $jmpnz = $op['extended_value'];
1016                $op['jmpouts'] = array($jmpz, $jmpnz);
1017                $opcodes[$jmpz]['jmpins'][] = $i;
1018                $opcodes[$jmpnz]['jmpins'][] = $i;
1019                break;
1020
1021            case XC_JMPZ:
1022            case XC_JMPNZ:
1023            case XC_JMPZ_EX:
1024            case XC_JMPNZ_EX:
[749]1025            case XC_JMP_SET:
[1]1026            // case XC_FE_RESET:
1027            case XC_FE_FETCH:
1028            // case XC_JMP_NO_CTOR:
[716]1029                $target = $op['op2']['opline_num'];
[1]1030                //if (!isset($target)) {
1031                //  $this->dumpop($op, $EX);
1032                //  var_dump($op); exit;
1033                //}
1034                $op['jmpouts'] = array($target);
1035                $opcodes[$target]['jmpins'][] = $i;
1036                break;
1037
1038            /*
1039            case XC_RETURN:
1040                $op['jmpouts'] = array();
1041                break;
1042            */
[790]1043
1044            case XC_SWITCH_FREE:
1045                $op['jmpouts'] = array($i + 1);
1046                $opcodes[$i + 1]['jmpins'][] = $i;
1047                break;
1048
1049            case XC_CASE:
1050                // just to link together
1051                $op['jmpouts'] = array($i + 2);
1052                $opcodes[$i + 2]['jmpins'][] = $i;
1053                break;
[795]1054
1055            case XC_CATCH:
1056                $catchNext = $op['extended_value'];
1057                $op['jmpouts'] = array($catchNext);
1058                $opcodes[$catchNext]['jmpins'][] = $i;
1059                break;
[1]1060            }
[787]1061            /*
1062            if (!empty($op['jmpouts']) || !empty($op['jmpins'])) {
1063                echo $i, "\t", xcache_get_opcode($op['opcode']), PHP_EOL;
1064            }
1065            // */
[1]1066        }
1067        unset($op);
[795]1068        if ($op_array['try_catch_array']) {
1069            foreach ($op_array['try_catch_array'] as $try_catch_element) {
1070                $catch_op = $try_catch_element['catch_op'];
1071                $try_op = $try_catch_element['try_op'];
1072                $opcodes[$try_op]['jmpins'][] = $catch_op;
1073                $opcodes[$catch_op]['jmpouts'][] = $try_op;
1074                $opcodes[$catch_op]['isCatchBegin'] = true;
1075            }
1076        }
[1]1077        // }}}
1078        // build semi-basic blocks
1079        $nextbbs = array();
1080        $starti = 0;
[795]1081        for ($i = 1; $i <= $last; $i ++) {
[1]1082            if (isset($opcodes[$i]['jmpins'])
1083             || isset($opcodes[$i - 1]['jmpouts'])) {
1084                $nextbbs[$starti] = $i;
1085                $starti = $i;
1086            }
1087        }
[795]1088        $nextbbs[$starti] = $last + 1;
[1]1089
1090        $EX = array();
1091        $EX['Ts'] = array();
1092        $EX['indent'] = $indent;
1093        $EX['nextbbs'] = $nextbbs;
1094        $EX['op_array'] = &$op_array;
1095        $EX['opcodes'] = &$opcodes;
1096        // func call
1097        $EX['object'] = null;
[720]1098        $EX['called_scope'] = null;
[1]1099        $EX['fbc'] = null;
1100        $EX['argstack'] = array();
1101        $EX['arg_types_stack'] = array();
1102        $EX['last'] = count($opcodes) - 1;
1103        $EX['silence'] = 0;
[780]1104        $EX['recvs'] = array();
1105        $EX['uses'] = array();
[1]1106
[790]1107        $first = 0;
1108        $last = count($opcodes) - 1;
1109
1110        /* dump whole array
[791]1111        $this->keepTs = true;
[790]1112        $this->dasmBasicBlock($EX, $first, $last);
1113        for ($i = $first; $i <= $last; ++$i) {
1114            echo $i, "\t", $this->dumpop($opcodes[$i], $EX);
1115        }
1116        // */
[787]1117        // decompile in a tree way
[790]1118        $this->recognizeAndDecompileClosedBlocks($EX, $first, $last, $EX['indent']);
[1]1119        return $EX;
1120    }
1121    // }}}
1122    function outputCode(&$EX, $opline, $last, $indent, $loop = false) // {{{
1123    {
1124        $op = &$EX['opcodes'][$opline];
1125        $next = $EX['nextbbs'][$opline];
1126
1127        $end = $next - 1;
1128        if ($end > $last) {
1129            $end = $last;
1130        }
1131
1132        if (isset($op['jmpins'])) {
1133            echo "\nline", $op['line'], ":\n";
1134        }
1135        else {
1136            // echo ";;;\n";
1137        }
1138        $this->dasmBasicBlock($EX, $opline, $end);
[787]1139        $this->outputPhp($EX, $opline, $end, $indent);
[1]1140        // jmpout op
1141        $op = &$EX['opcodes'][$end];
1142        $op1 = $op['op1'];
1143        $op2 = $op['op2'];
1144        $ext = $op['extended_value'];
1145        $line = $op['line'];
1146
1147        if (isset($EX['opcodes'][$next])) {
1148            if (isset($last) && $next > $last) {
1149                $next = null;
1150            }
1151        }
1152        else {
1153            $next = null;
1154        }
1155        /*
1156        if ($op['opcode'] == XC_JMPZ) {
[716]1157            $target = $op2['opline_num'];
[1]1158            if ($line + 1) {
1159                $nextblock = $EX['nextbbs'][$next];
1160                $jmpop = end($nextblock);
1161                if ($jmpop['opcode'] == XC_JMP) {
[716]1162                    $ifendline = $op2['opline_num'];
[1]1163                    if ($ifendline >= $line) {
1164                        $cond = $op['cond'];
1165                        echo "{$indent}if ($cond) {\n";
1166                        $this->outputCode($EX, $next, $last, INDENT . $indent);
1167                        echo "$indent}\n";
1168                        $this->outputCode($EX, $target, $last, $indent);
1169                        return;
1170                    }
1171                }
1172            }
1173        }
1174        */
1175        if (!isset($next)) {
1176            return;
1177        }
[758]1178        if (isset($op['jmpouts']) && isset($op['isjmp'])) {
[1]1179            if (isset($op['cond'])) {
[746]1180                echo "{$indent}check (" . str($op["cond"]) . ") {\n";
[1]1181                echo INDENT;
1182            }
[758]1183            switch ($op['opcode']) {
1184            case XC_CONT:
1185            case XC_BRK:
1186                break;
1187
1188            default:
1189                echo $indent;
1190                echo xcache_get_opcode($op['opcode']), ' line', $op['jmpouts'][0];
1191                if (isset($op['jmpouts'][1])) {
1192                    echo ', line', $op['jmpouts'][1];
1193                }
1194                echo ";";
1195                // echo ' // <- line', $op['line'];
1196                echo "\n";
[1]1197            }
1198            if (isset($op['cond'])) echo "$indent}\n";
1199        }
1200
1201        // proces JMPZ_EX/JMPNZ_EX for AND,OR
1202        $op = &$EX['opcodes'][$next];
1203        /*
1204        if (isset($op['jmpins'])) {
1205            foreach (array_reverse($op['jmpins']) as $fromline) {
1206                $fromop = $EX['opcodes'][$fromline];
1207                switch ($fromop['opcode']) {
1208                case XC_JMPZ_EX: $opstr = 'and'; break;
1209                case XC_JMPNZ_EX: $opstr = 'or'; break;
1210                case XC_JMPZNZ: var_dump($fromop); exit;
1211                default: continue 2;
1212                }
1213
[716]1214                $var = $fromop['result']['var'];
[1]1215                var_dump($EX['Ts'][$var]);
1216                $EX['Ts'][$var] = '(' . $fromop['and_or'] . " $opstr " . $EX['Ts'][$var] . ')';
1217            }
1218            #$this->outputCode($EX, $next, $last, $indent);
1219            #return;
1220        }
1221        */
1222        if (isset($op['cond_false'])) {
1223            // $this->dumpop($op, $EX);
1224            // any true comes here, so it's a "or"
[744]1225            $cond = implode(' and ', str($op['cond_false']));
[1]1226            // var_dump($op['cond'] = $cond);
1227            /*
1228            $rvalue = implode(' or ', $op['cond_true']) . ' or ' . $rvalue;
1229            unset($op['cond_true']);
1230            */
1231        }
1232
1233        if ($loop) {
1234            return array($next, $last);
1235        }
1236        $this->outputCode($EX, $next, $last, $indent);
1237    }
1238    // }}}
1239    function dasmBasicBlock(&$EX, $opline, $last) // {{{
1240    {
1241        $T = &$EX['Ts'];
1242        $opcodes = &$EX['opcodes'];
1243        $lastphpop = null;
1244
[787]1245        for ($i = $opline; $i <= $last; $i ++) {
[1]1246            // {{{ prepair
1247            $op = &$opcodes[$i];
1248            $opc = $op['opcode'];
1249            if ($opc == XC_NOP) {
[761]1250                $this->usedOps[$opc] = true;
[1]1251                continue;
1252            }
1253
1254            $op1 = $op['op1'];
1255            $op2 = $op['op2'];
1256            $res = $op['result'];
1257            $ext = $op['extended_value'];
1258
1259            $opname = xcache_get_opcode($opc);
1260
1261            if ($opname == 'UNDEF' || !isset($opname)) {
1262                echo 'UNDEF OP:';
1263                $this->dumpop($op, $EX);
1264                continue;
1265            }
[762]1266            // echo $i, ' '; $this->dumpop($op, $EX); //var_dump($op);
[1]1267
1268            $resvar = null;
[731]1269            if ((ZEND_ENGINE_2_4 ? ($res['op_type'] & EXT_TYPE_UNUSED) : ($res['EA.type'] & EXT_TYPE_UNUSED)) || $res['op_type'] == XC_IS_UNUSED) {
[1]1270                $istmpres = false;
1271            }
1272            else {
1273                $istmpres = true;
1274            }
1275            // }}}
1276            // echo $opname, "\n";
1277
1278            $call = array(&$this, $opname);
1279            if (is_callable($call)) {
[761]1280                $this->usedOps[$opc] = true;
[1]1281                $this->{$opname}($op, $EX);
1282            }
1283            else if (isset($this->binops[$opc])) { // {{{
[761]1284                $this->usedOps[$opc] = true;
[1]1285                $op1val = $this->getOpVal($op1, $EX, false);
1286                $op2val = $this->getOpVal($op2, $EX, false);
1287                $rvalue = new Decompiler_Binop($this, $op1val, $opc, $op2val);
1288                $resvar = $rvalue;
1289                // }}}
1290            }
1291            else if (isset($this->unaryops[$opc])) { // {{{
[761]1292                $this->usedOps[$opc] = true;
[1]1293                $op1val = $this->getOpVal($op1, $EX);
1294                $myop = $this->unaryops[$opc];
[757]1295                $rvalue = $myop . str($op1val);
[1]1296                $resvar = $rvalue;
1297                // }}}
1298            }
1299            else {
[761]1300                $covered = true;
[1]1301                switch ($opc) {
1302                case XC_NEW: // {{{
[720]1303                    array_push($EX['arg_types_stack'], array($EX['fbc'], $EX['object'], $EX['called_scope']));
[716]1304                    $EX['object'] = (int) $res['var'];
[720]1305                    $EX['called_scope'] = null;
[749]1306                    $EX['fbc'] = 'new ' . unquoteName($this->getOpVal($op1, $EX), $EX);
[731]1307                    if (!ZEND_ENGINE_2) {
[1]1308                        $resvar = '$new object$';
1309                    }
1310                    break;
1311                    // }}}
[749]1312                case XC_THROW: // {{{
1313                    $resvar = 'throw ' . str($this->getOpVal($op1, $EX));
1314                    break;
1315                    // }}}
1316                case XC_CLONE: // {{{
1317                    $resvar = 'clone ' . str($this->getOpVal($op1, $EX));
1318                    break;
1319                    // }}}
1320                case XC_CATCH: // {{{
1321                    break;
1322                    // }}}
1323                case XC_INSTANCEOF: // {{{
1324                    $resvar = str($this->getOpVal($op1, $EX)) . ' instanceof ' . str($this->getOpVal($op2, $EX));
1325                    break;
1326                    // }}}
[1]1327                case XC_FETCH_CLASS: // {{{
1328                    if ($op2['op_type'] == XC_IS_UNUSED) {
[731]1329                        switch (($ext & (defined('ZEND_FETCH_CLASS_MASK') ? ZEND_FETCH_CLASS_MASK : 0xFF))) {
[1]1330                        case ZEND_FETCH_CLASS_SELF:
1331                            $class = 'self';
1332                            break;
1333                        case ZEND_FETCH_CLASS_PARENT:
1334                            $class = 'parent';
[722]1335                            break;
1336                        case ZEND_FETCH_CLASS_STATIC:
1337                            $class = 'static';
1338                            break;
[1]1339                        }
[722]1340                        $istmpres = true;
[1]1341                    }
1342                    else {
[749]1343                        $class = $this->getOpVal($op2, $EX);
1344                        if (isset($op2['constant'])) {
[753]1345                            $class = $this->stripNamespace(unquoteName($class));
[1]1346                        }
1347                    }
1348                    $resvar = $class;
1349                    break;
1350                    // }}}
1351                case XC_FETCH_CONSTANT: // {{{
[749]1352                    if ($op1['op_type'] == XC_IS_UNUSED) {
[753]1353                        $resvar = $this->stripNamespace($op2['constant']);
[749]1354                        break;
1355                    }
1356
[1]1357                    if ($op1['op_type'] == XC_IS_CONST) {
[753]1358                        $resvar = $this->stripNamespace($op1['constant']);
[1]1359                    }
1360                    else {
[749]1361                        $resvar = $this->getOpVal($op1, $EX);
[1]1362                    }
[749]1363
1364                    $resvar = str($resvar) . '::' . unquoteName($this->getOpVal($op2, $EX));
[1]1365                    break;
1366                    // }}}
1367                    // {{{ case XC_FETCH_*
1368                case XC_FETCH_R:
1369                case XC_FETCH_W:
1370                case XC_FETCH_RW:
1371                case XC_FETCH_FUNC_ARG:
1372                case XC_FETCH_UNSET:
1373                case XC_FETCH_IS:
1374                case XC_UNSET_VAR:
1375                    $rvalue = $this->getOpVal($op1, $EX);
[731]1376                    if (defined('ZEND_FETCH_TYPE_MASK')) {
1377                        $fetchtype = ($ext & ZEND_FETCH_TYPE_MASK);
1378                    }
1379                    else {
1380                        $fetchtype = $op2[!ZEND_ENGINE_2 ? 'fetch_type' : 'EA.type'];
1381                    }
[1]1382                    switch ($fetchtype) {
1383                    case ZEND_FETCH_STATIC_MEMBER:
1384                        $class = $this->getOpVal($op2, $EX);
[749]1385                        $rvalue = str($class) . '::$' . unquoteName($rvalue, $EX);
[1]1386                        break;
1387                    default:
[749]1388                        $name = unquoteName($rvalue, $EX);
1389                        $globalname = xcache_is_autoglobal($name) ? "\$$name" : "\$GLOBALS[" . str($rvalue) . "]";
[1]1390                        $rvalue = new Decompiler_Fetch($rvalue, $fetchtype, $globalname);
1391                        break;
1392                    }
1393                    if ($opc == XC_UNSET_VAR) {
[744]1394                        $op['php'] = "unset(" . str($rvalue, $EX) . ")";
[1]1395                        $lastphpop = &$op;
1396                    }
1397                    else if ($res['op_type'] != XC_IS_UNUSED) {
1398                        $resvar = $rvalue;
1399                    }
1400                    break;
1401                    // }}}
1402                    // {{{ case XC_FETCH_DIM_*
1403                case XC_FETCH_DIM_TMP_VAR:
1404                case XC_FETCH_DIM_R:
1405                case XC_FETCH_DIM_W:
1406                case XC_FETCH_DIM_RW:
1407                case XC_FETCH_DIM_FUNC_ARG:
1408                case XC_FETCH_DIM_UNSET:
1409                case XC_FETCH_DIM_IS:
1410                case XC_ASSIGN_DIM:
[749]1411                case XC_UNSET_DIM_OBJ: // PHP 4 only
[1]1412                case XC_UNSET_DIM:
[749]1413                case XC_UNSET_OBJ:
[1]1414                    $src = $this->getOpVal($op1, $EX, false);
1415                    if (is_a($src, "Decompiler_ForeachBox")) {
1416                        $src->iskey = $this->getOpVal($op2, $EX);
1417                        $resvar = $src;
1418                        break;
1419                    }
[749]1420
1421                    if (is_a($src, "Decompiler_DimBox")) {
[1]1422                        $dimbox = $src;
1423                    }
1424                    else {
1425                        if (!is_a($src, "Decompiler_ListBox")) {
[749]1426                            $op1val = $this->getOpVal($op1, $EX, false);
1427                            $list = new Decompiler_List(isset($op1val) ? $op1val : '$this');
[1]1428
1429                            $src = new Decompiler_ListBox($list);
[716]1430                            if (!isset($op1['var'])) {
[1]1431                                $this->dumpop($op, $EX);
1432                                var_dump($op);
[716]1433                                die('missing var');
[1]1434                            }
[716]1435                            $T[$op1['var']] = $src;
[1]1436                            unset($list);
1437                        }
1438                        $dim = new Decompiler_Dim($src);
1439                        $src->obj->dims[] = &$dim;
1440
1441                        $dimbox = new Decompiler_DimBox($dim);
1442                    }
1443                    $dim = &$dimbox->obj;
1444                    $dim->offsets[] = $this->getOpVal($op2, $EX);
1445                    if ($ext == ZEND_FETCH_ADD_LOCK) {
1446                        $src->obj->everLocked = true;
1447                    }
1448                    else if ($ext == ZEND_FETCH_STANDARD) {
1449                        $dim->isLast = true;
1450                    }
[749]1451                    if ($opc == XC_UNSET_OBJ) {
1452                        $dim->isObject = true;
1453                    }
[1]1454                    unset($dim);
1455                    $rvalue = $dimbox;
[749]1456                    unset($dimbox);
[1]1457
1458                    if ($opc == XC_ASSIGN_DIM) {
1459                        $lvalue = $rvalue;
1460                        ++ $i;
1461                        $rvalue = $this->getOpVal($opcodes[$i]['op1'], $EX);
[749]1462                        $resvar = str($lvalue, $EX) . ' = ' . str($rvalue);
[1]1463                    }
[749]1464                    else if ($opc == XC_UNSET_DIM || $opc == XC_UNSET_OBJ) {
[744]1465                        $op['php'] = "unset(" . str($rvalue, $EX) . ")";
[1]1466                        $lastphpop = &$op;
1467                    }
1468                    else if ($res['op_type'] != XC_IS_UNUSED) {
1469                        $resvar = $rvalue;
1470                    }
1471                    break;
1472                    // }}}
1473                case XC_ASSIGN: // {{{
1474                    $lvalue = $this->getOpVal($op1, $EX);
1475                    $rvalue = $this->getOpVal($op2, $EX, false);
1476                    if (is_a($rvalue, 'Decompiler_ForeachBox')) {
1477                        $type = $rvalue->iskey ? 'fe_key' : 'fe_as';
1478                        $rvalue->obj[$type] = $lvalue;
[716]1479                        unset($T[$op2['var']]);
[1]1480                        break;
1481                    }
1482                    if (is_a($rvalue, "Decompiler_DimBox")) {
1483                        $dim = &$rvalue->obj;
1484                        $dim->assign = $lvalue;
1485                        if ($dim->isLast) {
[744]1486                            $resvar = foldToCode($dim->value, $EX);
[1]1487                        }
1488                        unset($dim);
1489                        break;
1490                    }
[781]1491                    if (is_a($rvalue, 'Decompiler_Fetch')) {
1492                        $src = str($rvalue->src, $EX);
1493                        if ('$' . unquoteName($src) == $lvalue) {
1494                            switch ($rvalue->fetchType) {
1495                            case ZEND_FETCH_STATIC:
1496                                $statics = &$EX['op_array']['static_variables'];
1497                                if ((xcache_get_type($statics[$name]) & IS_LEXICAL_VAR)) {
1498                                    $EX['uses'][] = str($lvalue);
1499                                    unset($statics);
1500                                    break 2;
1501                                }
1502                                unset($statics);
1503                            }
1504                        }
1505                    }
[744]1506                    $resvar = "$lvalue = " . str($rvalue, $EX);
[1]1507                    break;
1508                    // }}}
1509                case XC_ASSIGN_REF: // {{{
1510                    $lvalue = $this->getOpVal($op1, $EX);
1511                    $rvalue = $this->getOpVal($op2, $EX, false);
1512                    if (is_a($rvalue, 'Decompiler_Fetch')) {
[749]1513                        $src = str($rvalue->src, $EX);
[754]1514                        if ('$' . unquoteName($src) == $lvalue) {
[1]1515                            switch ($rvalue->fetchType) {
1516                            case ZEND_FETCH_GLOBAL:
[731]1517                            case ZEND_FETCH_GLOBAL_LOCK:
[1]1518                                $resvar = 'global ' . $lvalue;
1519                                break 2;
1520                            case ZEND_FETCH_STATIC:
1521                                $statics = &$EX['op_array']['static_variables'];
[781]1522                                if ((xcache_get_type($statics[$name]) & IS_LEXICAL_REF)) {
1523                                    $EX['uses'][] = '&' . str($lvalue);
1524                                    unset($statics);
1525                                    break 2;
1526                                }
1527
[1]1528                                $resvar = 'static ' . $lvalue;
[754]1529                                $name = unquoteName($src);
[1]1530                                if (isset($statics[$name])) {
1531                                    $var = $statics[$name];
1532                                    $resvar .= ' = ';
[744]1533                                    $resvar .= str(value($var), $EX);
[1]1534                                }
1535                                unset($statics);
1536                                break 2;
[731]1537                            default:
[1]1538                            }
1539                        }
1540                    }
[731]1541                    // TODO: PHP_6 global
[754]1542                    $rvalue = str($rvalue, $EX);
[1]1543                    $resvar = "$lvalue = &$rvalue";
1544                    break;
1545                    // }}}
1546                // {{{ case XC_FETCH_OBJ_*
1547                case XC_FETCH_OBJ_R:
1548                case XC_FETCH_OBJ_W:
1549                case XC_FETCH_OBJ_RW:
1550                case XC_FETCH_OBJ_FUNC_ARG:
1551                case XC_FETCH_OBJ_UNSET:
1552                case XC_FETCH_OBJ_IS:
1553                case XC_ASSIGN_OBJ:
1554                    $obj = $this->getOpVal($op1, $EX);
1555                    if (!isset($obj)) {
1556                        $obj = '$this';
1557                    }
[761]1558                    $rvalue = str($obj) . "->" . unquoteVariableName($this->getOpVal($op2, $EX), $EX);
[1]1559                    if ($res['op_type'] != XC_IS_UNUSED) {
1560                        $resvar = $rvalue;
1561                    }
1562                    if ($opc == XC_ASSIGN_OBJ) {
1563                        ++ $i;
1564                        $lvalue = $rvalue;
1565                        $rvalue = $this->getOpVal($opcodes[$i]['op1'], $EX);
[749]1566                        $resvar = "$lvalue = " . str($rvalue);
[1]1567                    }
1568                    break;
1569                    // }}}
1570                case XC_ISSET_ISEMPTY_DIM_OBJ:
1571                case XC_ISSET_ISEMPTY_PROP_OBJ:
1572                case XC_ISSET_ISEMPTY:
1573                case XC_ISSET_ISEMPTY_VAR: // {{{
1574                    if ($opc == XC_ISSET_ISEMPTY_VAR) {
[777]1575                        $rvalue = $this->getOpVal($op1, $EX);
1576                        // for < PHP_5_3
1577                        if ($op1['op_type'] == XC_IS_CONST) {
1578                            $rvalue = '$' . unquoteVariableName($this->getOpVal($op1, $EX));
1579                        }
[716]1580                        if ($op2['EA.type'] == ZEND_FETCH_STATIC_MEMBER) {
[1]1581                            $class = $this->getOpVal($op2, $EX);
1582                            $rvalue = $class . '::' . $rvalue;
1583                        }
1584                    }
1585                    else if ($opc == XC_ISSET_ISEMPTY) {
1586                        $rvalue = $this->getOpVal($op1, $EX);
1587                    }
1588                    else {
1589                        $container = $this->getOpVal($op1, $EX);
1590                        $dim = $this->getOpVal($op2, $EX);
[717]1591                        if ($opc == XC_ISSET_ISEMPTY_PROP_OBJ) {
[761]1592                            if (!isset($container)) {
1593                                $container = '$this';
[717]1594                            }
[761]1595                            $rvalue = $container . "->" . unquoteVariableName($dim);
[717]1596                        }
1597                        else {
[761]1598                            $rvalue = $container . '[' . str($dim) .']';
[717]1599                        }
[1]1600                    }
1601
[731]1602                    switch ((!ZEND_ENGINE_2 ? $op['op2']['var'] /* constant */ : $ext) & (ZEND_ISSET|ZEND_ISEMPTY)) {
[1]1603                    case ZEND_ISSET:
[775]1604                        $rvalue = "isset(" . str($rvalue) . ")";
[1]1605                        break;
1606                    case ZEND_ISEMPTY:
[775]1607                        $rvalue = "empty(" . str($rvalue) . ")";
[1]1608                        break;
1609                    }
1610                    $resvar = $rvalue;
1611                    break;
1612                    // }}}
1613                case XC_SEND_VAR_NO_REF:
1614                case XC_SEND_VAL:
1615                case XC_SEND_REF:
1616                case XC_SEND_VAR: // {{{
1617                    $ref = ($opc == XC_SEND_REF ? '&' : '');
[744]1618                    $EX['argstack'][] = $ref . str($this->getOpVal($op1, $EX));
[1]1619                    break;
1620                    // }}}
[720]1621                case XC_INIT_STATIC_METHOD_CALL:
[749]1622                case XC_INIT_METHOD_CALL: // {{{
[720]1623                    array_push($EX['arg_types_stack'], array($EX['fbc'], $EX['object'], $EX['called_scope']));
[722]1624                    if ($opc == XC_INIT_STATIC_METHOD_CALL || $opc == XC_INIT_METHOD_CALL || $op1['op_type'] != XC_IS_UNUSED) {
[1]1625                        $obj = $this->getOpVal($op1, $EX);
1626                        if (!isset($obj)) {
1627                            $obj = '$this';
1628                        }
[722]1629                        if ($opc == XC_INIT_STATIC_METHOD_CALL || /* PHP4 */ isset($op1['constant'])) {
[720]1630                            $EX['object'] = null;
[753]1631                            $EX['called_scope'] = $this->stripNamespace(unquoteName($obj, $EX));
[720]1632                        }
1633                        else {
1634                            $EX['object'] = $obj;
1635                            $EX['called_scope'] = null;
1636                        }
[1]1637                        if ($res['op_type'] != XC_IS_UNUSED) {
1638                            $resvar = '$obj call$';
1639                        }
1640                    }
1641                    else {
1642                        $EX['object'] = null;
[720]1643                        $EX['called_scope'] = null;
[1]1644                    }
1645
[749]1646                    $EX['fbc'] = $this->getOpVal($op2, $EX, false);
1647                    if (($opc == XC_INIT_STATIC_METHOD_CALL || $opc == XC_INIT_METHOD_CALL) && !isset($EX['fbc'])) {
1648                        $EX['fbc'] = '__construct';
[1]1649                    }
[749]1650                    break;
1651                    // }}}
[753]1652                case XC_INIT_NS_FCALL_BY_NAME:
[749]1653                case XC_INIT_FCALL_BY_NAME: // {{{
[755]1654                    array_push($EX['arg_types_stack'], array($EX['fbc'], $EX['object'], $EX['called_scope']));
[749]1655                    if (!ZEND_ENGINE_2 && ($ext & ZEND_CTOR_CALL)) {
1656                        break;
[1]1657                    }
[749]1658                    $EX['object'] = null;
1659                    $EX['called_scope'] = null;
1660                    $EX['fbc'] = $this->getOpVal($op2, $EX);
[1]1661                    break;
1662                    // }}}
[749]1663                case XC_INIT_FCALL_BY_FUNC: // {{{ deprecated even in PHP 4?
1664                    $EX['object'] = null;
1665                    $EX['called_scope'] = null;
1666                    $which = $op1['var'];
1667                    $EX['fbc'] = $EX['op_array']['funcs'][$which]['name'];
1668                    break;
1669                    // }}}
[1]1670                case XC_DO_FCALL_BY_FUNC:
[716]1671                    $which = $op1['var'];
[1]1672                    $fname = $EX['op_array']['funcs'][$which]['name'];
1673                    $args = $this->popargs($EX, $ext);
1674                    $resvar = $fname . "($args)";
1675                    break;
1676                case XC_DO_FCALL:
[749]1677                    $fname = unquoteName($this->getOpVal($op1, $EX, false), $EX);
[1]1678                    $args = $this->popargs($EX, $ext);
1679                    $resvar = $fname . "($args)";
1680                    break;
1681                case XC_DO_FCALL_BY_NAME: // {{{
1682                    $object = null;
1683
[749]1684                    $fname = unquoteName($EX['fbc'], $EX);
[1]1685                    if (!is_int($EX['object'])) {
1686                        $object = $EX['object'];
1687                    }
1688
1689                    $args = $this->popargs($EX, $ext);
1690
[753]1691                    $prefix = (isset($object) ? $object . '->' : '' )
1692                        . (isset($EX['called_scope']) ? $EX['called_scope'] . '::' : '' );
1693                    $resvar = $prefix
1694                        . (!$prefix ? $this->stripNamespace($fname) : $fname)
1695                        . "($args)";
[1]1696                    unset($args);
1697
1698                    if (is_int($EX['object'])) {
1699                        $T[$EX['object']] = $resvar;
1700                        $resvar = null;
1701                    }
[720]1702                    list($EX['fbc'], $EX['object'], $EX['called_scope']) = array_pop($EX['arg_types_stack']);
[1]1703                    break;
1704                    // }}}
1705                case XC_VERIFY_ABSTRACT_CLASS: // {{{
[716]1706                    //unset($T[$op1['var']]);
[1]1707                    break;
1708                    // }}}
1709                case XC_DECLARE_CLASS: 
[714]1710                case XC_DECLARE_INHERITED_CLASS:
1711                case XC_DECLARE_INHERITED_CLASS_DELAYED: // {{{
[716]1712                    $key = $op1['constant'];
[714]1713                    if (!isset($this->dc['class_table'][$key])) {
1714                        echo 'class not found: ', $key, 'existing classes are:', "\n";
1715                        var_dump(array_keys($this->dc['class_table']));
[1]1716                        exit;
1717                    }
[714]1718                    $class = &$this->dc['class_table'][$key];
[751]1719                    if (!isset($class['name'])) {
1720                        $class['name'] = unquoteName($this->getOpVal($op2, $EX), $EX);
1721                    }
[714]1722                    if ($opc == XC_DECLARE_INHERITED_CLASS || $opc == XC_DECLARE_INHERITED_CLASS_DELAYED) {
[1]1723                        $ext /= XC_SIZEOF_TEMP_VARIABLE;
1724                        $class['parent'] = $T[$ext];
1725                        unset($T[$ext]);
1726                    }
1727                    else {
1728                        $class['parent'] = null;
1729                    }
1730
[749]1731                    for (;;) {
[787]1732                        if ($i + 1 <= $last
[749]1733                         && $opcodes[$i + 1]['opcode'] == XC_ADD_INTERFACE
1734                         && $opcodes[$i + 1]['op1']['var'] == $res['var']) {
1735                            // continue
1736                        }
[787]1737                        else if ($i + 2 <= $last
[749]1738                         && $opcodes[$i + 2]['opcode'] == XC_ADD_INTERFACE
1739                         && $opcodes[$i + 2]['op1']['var'] == $res['var']
1740                         && $opcodes[$i + 1]['opcode'] == XC_FETCH_CLASS) {
1741                            // continue
1742                        }
1743                        else {
1744                            break;
1745                        }
[761]1746                        $this->usedOps[XC_ADD_INTERFACE] = true;
[749]1747
[1]1748                        $fetchop = &$opcodes[$i + 1];
[753]1749                        $interface = $this->stripNamespace(unquoteName($this->getOpVal($fetchop['op2'], $EX), $EX));
[1]1750                        $addop = &$opcodes[$i + 2];
[753]1751                        $class['interfaces'][$addop['extended_value']] = $interface;
[1]1752                        unset($fetchop, $addop);
1753                        $i += 2;
1754                    }
1755                    $this->dclass($class);
[749]1756                    echo "\n";
[1]1757                    unset($class);
1758                    break;
1759                    // }}}
1760                case XC_INIT_STRING: // {{{
1761                    $resvar = "''";
1762                    break;
1763                    // }}}
1764                case XC_ADD_CHAR:
1765                case XC_ADD_STRING:
1766                case XC_ADD_VAR: // {{{
1767                    $op1val = $this->getOpVal($op1, $EX);
1768                    $op2val = $this->getOpVal($op2, $EX);
1769                    switch ($opc) {
1770                    case XC_ADD_CHAR:
[749]1771                        $op2val = value(chr(str($op2val)));
[1]1772                        break;
1773                    case XC_ADD_STRING:
1774                        break;
1775                    case XC_ADD_VAR:
1776                        break;
1777                    }
[749]1778                    if (str($op1val) == "''") {
[1]1779                        $rvalue = $op2val;
1780                    }
[749]1781                    else if (str($op2val) == "''") {
[1]1782                        $rvalue = $op1val;
1783                    }
1784                    else {
[744]1785                        $rvalue = str($op1val) . ' . ' . str($op2val);
[1]1786                    }
1787                    $resvar = $rvalue;
1788                    // }}}
1789                    break;
1790                case XC_PRINT: // {{{
1791                    $op1val = $this->getOpVal($op1, $EX);
[761]1792                    $resvar = "print(" . str($op1val) . ")";
[1]1793                    break;
1794                    // }}}
1795                case XC_ECHO: // {{{
1796                    $op1val = $this->getOpVal($op1, $EX);
[744]1797                    $resvar = "echo " . str($op1val);
[1]1798                    break;
1799                    // }}}
1800                case XC_EXIT: // {{{
1801                    $op1val = $this->getOpVal($op1, $EX);
1802                    $resvar = "exit($op1val)";
1803                    break;
1804                    // }}}
1805                case XC_INIT_ARRAY:
1806                case XC_ADD_ARRAY_ELEMENT: // {{{
1807                    $rvalue = $this->getOpVal($op1, $EX, false, true);
1808
1809                    if ($opc == XC_ADD_ARRAY_ELEMENT) {
[737]1810                        $assoc = $this->getOpVal($op2, $EX);
1811                        if (isset($assoc)) {
1812                            $T[$res['var']]->value[] = array($assoc, $rvalue);
[1]1813                        }
1814                        else {
[737]1815                            $T[$res['var']]->value[] = array(null, $rvalue);
[1]1816                        }
1817                    }
1818                    else {
1819                        if ($opc == XC_INIT_ARRAY) {
1820                            $resvar = new Decompiler_Array();
1821                            if (!isset($rvalue)) {
1822                                continue;
1823                            }
1824                        }
1825
[737]1826                        $assoc = $this->getOpVal($op2, $EX);
1827                        if (isset($assoc)) {
1828                            $resvar->value[] = array($assoc, $rvalue);
[1]1829                        }
1830                        else {
[737]1831                            $resvar->value[] = array(null, $rvalue);
[1]1832                        }
1833                    }
1834                    break;
1835                    // }}}
1836                case XC_QM_ASSIGN: // {{{
1837                    $resvar = $this->getOpVal($op1, $EX);
1838                    break;
1839                    // }}}
1840                case XC_BOOL: // {{{
1841                    $resvar = /*'(bool) ' .*/ $this->getOpVal($op1, $EX);
1842                    break;
1843                    // }}}
1844                case XC_RETURN: // {{{
[744]1845                    $resvar = "return " . str($this->getOpVal($op1, $EX));
[1]1846                    break;
1847                    // }}}
1848                case XC_INCLUDE_OR_EVAL: // {{{
[716]1849                    $type = $op2['var']; // hack
[1]1850                    $keyword = $this->includeTypes[$type];
[749]1851                    $resvar = "$keyword " . str($this->getOpVal($op1, $EX));
[1]1852                    break;
1853                    // }}}
1854                case XC_FE_RESET: // {{{
1855                    $resvar = $this->getOpVal($op1, $EX);
1856                    break;
1857                    // }}}
1858                case XC_FE_FETCH: // {{{
[791]1859                    $op['fe_src'] = $this->getOpVal($op1, $EX, false, true);
[1]1860                    $fe = new Decompiler_ForeachBox($op);
1861                    $fe->iskey = false;
[716]1862                    $T[$res['var']] = $fe;
[1]1863
1864                    ++ $i;
1865                    if (($ext & ZEND_FE_FETCH_WITH_KEY)) {
1866                        $fe = new Decompiler_ForeachBox($op);
1867                        $fe->iskey = true;
1868
1869                        $res = $opcodes[$i]['result'];
[716]1870                        $T[$res['var']] = $fe;
[1]1871                    }
1872                    break;
1873                    // }}}
1874                case XC_SWITCH_FREE: // {{{
1875                    break;
1876                    // }}}
1877                case XC_FREE: // {{{
[716]1878                    $free = $T[$op1['var']];
[1]1879                    if (!is_a($free, 'Decompiler_Array') && !is_a($free, 'Decompiler_Box')) {
1880                        $op['php'] = is_object($free) ? $free : $this->unquote($free, '(', ')');
1881                        $lastphpop = &$op;
1882                    }
[716]1883                    unset($T[$op1['var']], $free);
[1]1884                    break;
1885                    // }}}
1886                case XC_JMP_NO_CTOR:
1887                    break;
[749]1888                case XC_JMP_SET: // ?:
[760]1889                    $resvar = $this->getOpVal($op1, $EX);
1890                    $op['cond'] = $resvar; 
1891                    $op['isjmp'] = true;
1892                    break;
[1]1893                case XC_JMPNZ: // while
1894                case XC_JMPZNZ: // for
1895                case XC_JMPZ_EX: // and
1896                case XC_JMPNZ_EX: // or
1897                case XC_JMPZ: // {{{
1898                    if ($opc == XC_JMP_NO_CTOR && $EX['object']) {
1899                        $rvalue = $EX['object'];
1900                    }
1901                    else {
1902                        $rvalue = $this->getOpVal($op1, $EX);
1903                    }
1904
1905                    if (isset($op['cond_true'])) {
1906                        // any true comes here, so it's a "or"
1907                        $rvalue = implode(' or ', $op['cond_true']) . ' or ' . $rvalue;
1908                        unset($op['cond_true']);
1909                    }
1910                    if (isset($op['cond_false'])) {
[723]1911                        echo "TODO(cond_false):\n";
[1]1912                        var_dump($op);// exit;
1913                    }
[760]1914                    if ($opc == XC_JMPZ_EX || $opc == XC_JMPNZ_EX) {
[716]1915                        $targetop = &$EX['opcodes'][$op2['opline_num']];
[1]1916                        if ($opc == XC_JMPNZ_EX) {
[744]1917                            $targetop['cond_true'][] = foldToCode($rvalue, $EX);
[1]1918                        }
1919                        else {
[744]1920                            $targetop['cond_false'][] = foldToCode($rvalue, $EX);
[1]1921                        }
1922                        unset($targetop);
1923                    }
1924                    else {
1925                        $op['cond'] = $rvalue; 
1926                        $op['isjmp'] = true;
1927                    }
1928                    break;
1929                    // }}}
[758]1930                case XC_CONT:
1931                case XC_BRK:
1932                    $op['cond'] = null;
1933                    $op['isjmp'] = true;
1934                    $resvar = $opc == XC_CONT ? 'continue' : 'break';
1935                    $count = str($this->getOpVal($op2, $EX));
1936                    if ($count != '1') {
1937                        $resvar .= ' ' . $count;
1938                    }
1939                    break;
[749]1940                case XC_GOTO:
[787]1941                    $resvar = 'goto label' . $op['op1']['var'];
1942                    $istmpres = false;
1943                    break;
1944
[1]1945                case XC_JMP: // {{{
1946                    $op['cond'] = null;
1947                    $op['isjmp'] = true;
1948                    break;
1949                    // }}}
1950                case XC_CASE:
[790]1951                    // $switchValue = $this->getOpVal($op1, $EX);
[743]1952                    $caseValue = $this->getOpVal($op2, $EX);
[790]1953                    $resvar = $caseValue;
[743]1954                    break;
[1]1955                case XC_RECV_INIT:
1956                case XC_RECV:
1957                    $offset = $this->getOpVal($op1, $EX);
1958                    $lvalue = $this->getOpVal($op['result'], $EX);
1959                    if ($opc == XC_RECV_INIT) {
[716]1960                        $default = value($op['op2']['constant']);
[1]1961                    }
1962                    else {
1963                        $default = null;
1964                    }
[737]1965                    $EX['recvs'][str($offset)] = array($lvalue, $default);
[1]1966                    break;
1967                case XC_POST_DEC:
1968                case XC_POST_INC:
1969                case XC_POST_DEC_OBJ:
1970                case XC_POST_INC_OBJ:
1971                case XC_PRE_DEC:
1972                case XC_PRE_INC:
1973                case XC_PRE_DEC_OBJ:
1974                case XC_PRE_INC_OBJ: // {{{
1975                    $flags = array_flip(explode('_', $opname));
1976                    if (isset($flags['OBJ'])) {
[761]1977                        $resvar = $this->getOpVal($op1, $EX) . '->' . unquoteVariableName($this->getOpVal($op2, $EX), $EX);
[1]1978                    }
1979                    else {
1980                        $resvar = $this->getOpVal($op1, $EX);
1981                    }
1982                    $opstr = isset($flags['DEC']) ? '--' : '++';
1983                    if (isset($flags['POST'])) {
[749]1984                        $resvar .= $opstr;
[1]1985                    }
1986                    else {
[749]1987                        $resvar = "$opstr$resvar";
[1]1988                    }
1989                    break;
1990                    // }}}
1991
1992                case XC_BEGIN_SILENCE: // {{{
1993                    $EX['silence'] ++;
1994                    break;
1995                    // }}}
1996                case XC_END_SILENCE: // {{{
1997                    $EX['silence'] --;
[744]1998                    $lastresvar = '@' . str($lastresvar, $EX);
[1]1999                    break;
2000                    // }}}
2001                case XC_CAST: // {{{
2002                    $type = $ext;
2003                    static $type2cast = array(
2004                            IS_LONG   => '(int)',
2005                            IS_DOUBLE => '(double)',
2006                            IS_STRING => '(string)',
2007                            IS_ARRAY  => '(array)',
2008                            IS_OBJECT => '(object)',
2009                            IS_BOOL   => '(bool)',
2010                            IS_NULL   => '(unset)',
2011                            );
2012                    assert(isset($type2cast[$type]));
2013                    $cast = $type2cast[$type];
2014                    $resvar = $cast . ' ' . $this->getOpVal($op1, $EX);
2015                    break;
2016                    // }}}
2017                case XC_EXT_STMT:
2018                case XC_EXT_FCALL_BEGIN:
2019                case XC_EXT_FCALL_END:
2020                case XC_EXT_NOP:
2021                    break;
[751]2022                case XC_DECLARE_FUNCTION:
2023                    $this->dfunction($this->dc['function_table'][$op1['constant']], $EX['indent']);
2024                    break;
[752]2025                case XC_DECLARE_LAMBDA_FUNCTION: // {{{
[749]2026                    ob_start();
2027                    $this->dfunction($this->dc['function_table'][$op1['constant']], $EX['indent']);
2028                    $resvar = ob_get_clean();
2029                    $istmpres = true;
2030                    break;
[752]2031                    // }}}
2032                case XC_DECLARE_CONST:
[753]2033                    $name = $this->stripNamespace(unquoteName($this->getOpVal($op1, $EX), $EX));
2034                    $value = str($this->getOpVal($op2, $EX));
2035                    $resvar = 'const ' . $name . ' = ' . $value;
[752]2036                    break;
[1]2037                case XC_DECLARE_FUNCTION_OR_CLASS:
2038                    /* always removed by compiler */
2039                    break;
2040                case XC_TICKS:
2041                    $lastphpop['ticks'] = $this->getOpVal($op1, $EX);
2042                    // $EX['tickschanged'] = true;
2043                    break;
[749]2044                case XC_RAISE_ABSTRACT_ERROR:
2045                    // abstract function body is empty, don't need this code
2046                    break;
2047                case XC_USER_OPCODE:
2048                    echo '// ZEND_USER_OPCODE, impossible to decompile';
2049                    break;
2050                case XC_OP_DATA:
2051                    break;
[1]2052                default: // {{{
2053                    echo "\x1B[31m * TODO ", $opname, "\x1B[0m\n";
[761]2054                    $covered = false;
[1]2055                    // }}}
2056                }
[761]2057                if ($covered) {
2058                    $this->usedOps[$opc] = true;
2059                }
[1]2060            }
2061            if (isset($resvar)) {
2062                if ($istmpres) {
[716]2063                    $T[$res['var']] = $resvar;
2064                    $lastresvar = &$T[$res['var']];
[1]2065                }
2066                else {
2067                    $op['php'] = $resvar;
2068                    $lastphpop = &$op;
2069                    $lastresvar = &$op['php'];
2070                }
2071            }
2072        }
2073        return $T;
2074    }
2075    // }}}
2076    function unquote($str, $st, $ed) // {{{
2077    {
2078        $l1 = strlen($st);
2079        $l2 = strlen($ed);
2080        if (substr($str, 0, $l1) === $st && substr($str, -$l2) === $ed) {
2081            $str = substr($str, $l1, -$l2);
2082        }
2083        return $str;
2084    }
2085    // }}}
2086    function popargs(&$EX, $n) // {{{
2087    {
2088        $args = array();
2089        for ($i = 0; $i < $n; $i ++) {
2090            $a = array_pop($EX['argstack']);
2091            if (is_array($a)) {
[744]2092                array_unshift($args, foldToCode($a, $EX));
[1]2093            }
2094            else {
2095                array_unshift($args, $a);
2096            }
2097        }
2098        return implode(', ', $args);
2099    }
2100    // }}}
2101    function dumpop($op, &$EX) // {{{
2102    {
[795]2103        assert('isset($op)');
[1]2104        $op1 = $op['op1'];
2105        $op2 = $op['op2'];
[763]2106        $d = array(xcache_get_opcode($op['opcode']), $op['opcode']);
[1]2107
[762]2108        foreach (array('op1' => '1:', 'op2' => '2:', 'result' => '>') as $k => $kk) {
[1]2109            switch ($op[$k]['op_type']) {
2110            case XC_IS_UNUSED:
[762]2111                $d[$kk] = 'U:' . $op[$k]['opline_num'];
[1]2112                break;
2113
2114            case XC_IS_VAR:
[716]2115                $d[$kk] = '$' . $op[$k]['var'];
[762]2116                if ($k != 'result') {
[749]2117                    $d[$kk] .= ':' . str($this->getOpVal($op[$k], $EX));
[1]2118                }
2119                break;
2120
2121            case XC_IS_TMP_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_CV:
2129                $d[$kk] = $this->getOpVal($op[$k], $EX);
2130                break;
2131
2132            default:
[762]2133                if ($k == 'result') {
[731]2134                    var_dump($op);
[795]2135                    assert(0);
[731]2136                    exit;
[1]2137                }
2138                else {
2139                    $d[$kk] = $this->getOpVal($op[$k], $EX);
2140                }
2141            }
2142        }
[762]2143        $d[';'] = $op['extended_value'];
[795]2144        if (!empty($op['jmpouts'])) {
2145            $d['>>'] = implode(',', $op['jmpouts']);
2146        }
2147        if (!empty($op['jmpins'])) {
2148            $d['<<'] = implode(',', $op['jmpins']);
2149        }
[1]2150
[762]2151        foreach ($d as $k => $v) {
[763]2152            echo is_int($k) ? '' : $k, str($v), "\t";
[762]2153        }
2154        echo PHP_EOL;
[1]2155    }
2156    // }}}
[790]2157    function dumpRange(&$EX, $first, $last, $indent = '') // {{{
[787]2158    {
2159        for ($i = $first; $i <= $last; ++$i) {
[790]2160            echo $indent, $i, "\t"; $this->dumpop($EX['opcodes'][$i], $EX);
[787]2161        }
[790]2162        echo $indent, "==", PHP_EOL;
[787]2163    }
2164    // }}}
[1]2165    function dargs(&$EX, $indent) // {{{
2166    {
2167        $op_array = &$EX['op_array'];
2168
2169        if (isset($op_array['num_args'])) {
2170            $c = $op_array['num_args'];
2171        }
2172        else if ($op_array['arg_types']) {
2173            $c = count($op_array['arg_types']);
2174        }
2175        else {
2176            // php4
2177            $c = count($EX['recvs']);
2178        }
2179
2180        $refrest = false;
2181        for ($i = 0; $i < $c; $i ++) {
2182            if ($i) {
2183                echo ', ';
2184            }
[736]2185            $arg = $EX['recvs'][$i + 1];
[1]2186            if (isset($op_array['arg_info'])) {
2187                $ai = $op_array['arg_info'][$i];
2188                if (!empty($ai['class_name'])) {
[753]2189                    echo $this->stripNamespace($ai['class_name']), ' ';
[736]2190                    if (!ZEND_ENGINE_2_2 && $ai['allow_null']) {
[1]2191                        echo 'or NULL ';
2192                    }
2193                }
2194                else if (!empty($ai['array_type_hint'])) {
2195                    echo 'array ';
[736]2196                    if (!ZEND_ENGINE_2_2 && $ai['allow_null']) {
[1]2197                        echo 'or NULL ';
2198                    }
2199                }
2200                if ($ai['pass_by_reference']) {
2201                    echo '&';
2202                }
2203                printf("\$%s", $ai['name']);
2204            }
2205            else {
2206                if ($refrest) {
2207                    echo '&';
2208                }
2209                else if (isset($op_array['arg_types'][$i])) {
2210                    switch ($op_array['arg_types'][$i]) {
2211                    case BYREF_FORCE_REST:
2212                        $refrest = true;
2213                        /* fall */
2214                    case BYREF_FORCE:
2215                        echo '&';
2216                        break;
2217
2218                    case BYREF_NONE:
2219                    case BYREF_ALLOW:
2220                        break;
2221                    default:
2222                        assert(0);
2223                    }
2224                }
[744]2225                echo str($arg[0], $indent);
[1]2226            }
[736]2227            if (isset($arg[1])) {
[744]2228                echo ' = ', str($arg[1], $indent);
[736]2229            }
[1]2230        }
2231    }
2232    // }}}
[780]2233    function duses(&$EX, $indent) // {{{
2234    {
[781]2235        if ($EX['uses']) {
2236            echo ' use(', implode(', ', $EX['uses']), ')';
[780]2237        }
2238    }
2239    // }}}
[1]2240    function dfunction($func, $indent = '', $nobody = false) // {{{
2241    {
[753]2242        $this->detectNamespace($func['op_array']['function_name']);
2243
[1]2244        if ($nobody) {
2245            $EX = array();
2246            $EX['op_array'] = &$func['op_array'];
2247            $EX['recvs'] = array();
[780]2248            $EX['uses'] = array();
[1]2249        }
2250        else {
2251            ob_start();
2252            $newindent = INDENT . $indent;
2253            $EX = &$this->dop_array($func['op_array'], $newindent);
2254            $body = ob_get_clean();
2255        }
2256
[753]2257        $functionName = $this->stripNamespace($func['op_array']['function_name']);
[749]2258        if ($functionName == '{closure}') {
2259            $functionName = '';
2260        }
[781]2261        echo 'function', $functionName ? ' ' . $functionName : '', '(';
[1]2262        $this->dargs($EX, $indent);
[749]2263        echo ")";
[780]2264        $this->duses($EX, $indent);
[749]2265        if ($nobody) {
2266            echo ";\n";
2267        }
2268        else {
2269            if ($functionName !== '') {
2270                echo "\n";
2271                echo $indent, "{\n";
2272            }
2273            else {
2274                echo " {\n";
2275            }
2276
2277            echo $body;
2278            echo "$indent}";
2279            if ($functionName !== '') {
2280                echo "\n";
2281            }
2282        }
[1]2283    }
2284    // }}}
2285    function dclass($class, $indent = '') // {{{
2286    {
[753]2287        $this->detectNamespace($class['name']);
2288
[1]2289        // {{{ class decl
2290        if (!empty($class['doc_comment'])) {
2291            echo $indent;
2292            echo $class['doc_comment'];
2293            echo "\n";
2294        }
2295        $isinterface = false;
2296        if (!empty($class['ce_flags'])) {
2297            if ($class['ce_flags'] & ZEND_ACC_INTERFACE) {
2298                $isinterface = true;
2299            }
2300            else {
[749]2301                if ($class['ce_flags'] & ZEND_ACC_IMPLICIT_ABSTRACT_CLASS) {
[1]2302                    echo "abstract ";
2303                }
[749]2304                if ($class['ce_flags'] & ZEND_ACC_FINAL_CLASS) {
[1]2305                    echo "final ";
2306                }
2307            }
2308        }
[753]2309        echo $isinterface ? 'interface ' : 'class ', $this->stripNamespace($class['name']);
[1]2310        if ($class['parent']) {
2311            echo ' extends ', $class['parent'];
2312        }
2313        /* TODO */
2314        if (!empty($class['interfaces'])) {
2315            echo ' implements ';
2316            echo implode(', ', $class['interfaces']);
2317        }
2318        echo "\n";
2319        echo $indent, "{";
2320        // }}}
2321        $newindent = INDENT . $indent;
2322        // {{{ const, static
2323        foreach (array('constants_table' => 'const '
2324                    , 'static_members' => 'static $') as $type => $prefix) {
2325            if (!empty($class[$type])) {
2326                echo "\n";
2327                // TODO: skip shadow?
2328                foreach ($class[$type] as $name => $v) {
2329                    echo $newindent;
2330                    echo $prefix, $name, ' = ';
[744]2331                    echo str(value($v), $newindent);
[1]2332                    echo ";\n";
2333                }
2334            }
2335        }
2336        // }}}
2337        // {{{ properties
[730]2338        $member_variables = isset($class['properties_info']) ? $class['properties_info'] : ($class['default_static_members'] + $class['default_properties']);
2339        if ($member_variables) {
[1]2340            echo "\n";
[713]2341            $infos = !empty($class['properties_info']) ? $class['properties_info'] : null;
[730]2342            foreach ($member_variables as $name => $dummy) {
[1]2343                $info = (isset($infos) && isset($infos[$name])) ? $infos[$name] : null;
2344                if (isset($info)) {
2345                    if (!empty($info['doc_comment'])) {
2346                        echo $newindent;
2347                        echo $info['doc_comment'];
2348                        echo "\n";
2349                    }
2350                }
2351
2352                echo $newindent;
[713]2353                $static = false;
2354                if (isset($info)) {
2355                    if ($info['flags'] & ZEND_ACC_STATIC) {
2356                        $static = true;
2357                    }
2358                }
2359                else if (isset($class['default_static_members'][$name])) {
2360                    $static = true;
2361                }
2362
2363                if ($static) {
2364                    echo "static ";
2365                }
2366
2367                $mangled = false;
[731]2368                if (!ZEND_ENGINE_2) {
[1]2369                    echo 'var ';
2370                }
2371                else if (!isset($info)) {
2372                    echo 'public ';
2373                }
2374                else {
2375                    if ($info['flags'] & ZEND_ACC_SHADOW) {
2376                        continue;
2377                    }
2378                    switch ($info['flags'] & ZEND_ACC_PPP_MASK) {
2379                    case ZEND_ACC_PUBLIC:
2380                        echo "public ";
2381                        break;
2382                    case ZEND_ACC_PRIVATE:
2383                        echo "private ";
[713]2384                        $mangled = true;
[1]2385                        break;
2386                    case ZEND_ACC_PROTECTED:
2387                        echo "protected ";
[713]2388                        $mangled = true;
[1]2389                        break;
2390                    }
2391                }
2392
2393                echo '$', $name;
[713]2394
[730]2395                if (isset($info['offset'])) {
2396                    $value = $class[$static ? 'default_static_members_table' : 'default_properties_table'][$info['offset']];
2397                }
2398                else {
2399                    $key = isset($info) ? $info['name'] . ($mangled ? "\000" : "") : $name;
[713]2400
[730]2401                    $value = $class[$static ? 'default_static_members' : 'default_properties'][$key];
2402                }
[713]2403                if (isset($value)) {
[1]2404                    echo ' = ';
[744]2405                    echo str(value($value), $newindent);
[1]2406                }
2407                echo ";\n";
2408            }
2409        }
2410        // }}}
2411        // {{{ function_table
2412        if (isset($class['function_table'])) {
2413            foreach ($class['function_table'] as $func) {
2414                if (!isset($func['scope']) || $func['scope'] == $class['name']) {
2415                    // TODO: skip shadow here
2416                    echo "\n";
2417                    $opa = $func['op_array'];
2418                    if (!empty($opa['doc_comment'])) {
2419                        echo $newindent;
2420                        echo $opa['doc_comment'];
2421                        echo "\n";
2422                    }
2423                    echo $newindent;
[749]2424                    $isAbstractMethod = false;
[1]2425                    if (isset($opa['fn_flags'])) {
[749]2426                        if (($opa['fn_flags'] & ZEND_ACC_ABSTRACT) && !$isinterface) {
[1]2427                            echo "abstract ";
[749]2428                            $isAbstractMethod = true;
[1]2429                        }
2430                        if ($opa['fn_flags'] & ZEND_ACC_FINAL) {
2431                            echo "final ";
2432                        }
2433                        if ($opa['fn_flags'] & ZEND_ACC_STATIC) {
2434                            echo "static ";
2435                        }
2436
2437                        switch ($opa['fn_flags'] & ZEND_ACC_PPP_MASK) {
2438                            case ZEND_ACC_PUBLIC:
2439                                echo "public ";
2440                                break;
2441                            case ZEND_ACC_PRIVATE:
2442                                echo "private ";
2443                                break;
2444                            case ZEND_ACC_PROTECTED:
2445                                echo "protected ";
2446                                break;
2447                            default:
2448                                echo "<visibility error> ";
2449                                break;
2450                        }
2451                    }
[749]2452                    $this->dfunction($func, $newindent, $isinterface || $isAbstractMethod);
[1]2453                    if ($opa['function_name'] == 'Decompiler') {
2454                        //exit;
2455                    }
2456                }
2457            }
2458        }
2459        // }}}
2460        echo $indent, "}\n";
2461    }
2462    // }}}
2463    function decompileString($string) // {{{
2464    {
2465        $this->dc = xcache_dasm_string($string);
2466        if ($this->dc === false) {
2467            echo "error compling string\n";
2468            return false;
2469        }
2470    }
2471    // }}}
2472    function decompileFile($file) // {{{
2473    {
2474        $this->dc = xcache_dasm_file($file);
2475        if ($this->dc === false) {
2476            echo "error compling $file\n";
2477            return false;
2478        }
2479    }
2480    // }}}
2481    function output() // {{{
2482    {
[749]2483        echo "<?". "php\n\n";
[1]2484        foreach ($this->dc['class_table'] as $key => $class) {
2485            if ($key{0} != "\0") {
[749]2486                $this->dclass($class);
[1]2487                echo "\n";
2488            }
2489        }
2490
2491        foreach ($this->dc['function_table'] as $key => $func) {
2492            if ($key{0} != "\0") {
[749]2493                $this->dfunction($func);
[1]2494                echo "\n";
2495            }
2496        }
2497
2498        $this->dop_array($this->dc['op_array']);
2499        echo "\n?" . ">\n";
[761]2500
2501        if (!empty($this->test)) {
2502            $this->outputUnusedOp();
2503        }
[1]2504        return true;
2505    }
2506    // }}}
[761]2507    function outputUnusedOp() // {{{
2508    {
2509        for ($i = 0; $opname = xcache_get_opcode($i); $i ++) {
2510            if ($opname == 'UNDEF')  {
2511                continue;
2512            }
2513
2514            if (!isset($this->usedOps[$i])) {
2515                echo "not covered opcode ", $opname, "\n";
2516            }
2517        }
2518    }
2519    // }}}
[1]2520}
2521
2522// {{{ defines
[749]2523define('ZEND_ENGINE_2_4', PHP_VERSION >= "5.3.99");
2524define('ZEND_ENGINE_2_3', ZEND_ENGINE_2_4 || PHP_VERSION >= "5.3.");
2525define('ZEND_ENGINE_2_2', ZEND_ENGINE_2_3 || PHP_VERSION >= "5.2.");
2526define('ZEND_ENGINE_2_1', ZEND_ENGINE_2_2 || PHP_VERSION >= "5.1.");
2527define('ZEND_ENGINE_2',   ZEND_ENGINE_2_1 || PHP_VERSION >= "5.0.");
2528
[1]2529define('ZEND_ACC_STATIC',         0x01);
2530define('ZEND_ACC_ABSTRACT',       0x02);
2531define('ZEND_ACC_FINAL',          0x04);
2532define('ZEND_ACC_IMPLEMENTED_ABSTRACT',       0x08);
2533
2534define('ZEND_ACC_IMPLICIT_ABSTRACT_CLASS',    0x10);
2535define('ZEND_ACC_EXPLICIT_ABSTRACT_CLASS',    0x20);
2536define('ZEND_ACC_FINAL_CLASS',                0x40);
2537define('ZEND_ACC_INTERFACE',                  0x80);
[749]2538if (ZEND_ENGINE_2_4) {
2539    define('ZEND_ACC_TRAIT',                  0x120);
2540}
[1]2541define('ZEND_ACC_PUBLIC',     0x100);
2542define('ZEND_ACC_PROTECTED',  0x200);
2543define('ZEND_ACC_PRIVATE',    0x400);
2544define('ZEND_ACC_PPP_MASK',  (ZEND_ACC_PUBLIC | ZEND_ACC_PROTECTED | ZEND_ACC_PRIVATE));
2545
2546define('ZEND_ACC_CHANGED',    0x800);
2547define('ZEND_ACC_IMPLICIT_PUBLIC',    0x1000);
2548
2549define('ZEND_ACC_CTOR',       0x2000);
2550define('ZEND_ACC_DTOR',       0x4000);
2551define('ZEND_ACC_CLONE',      0x8000);
2552
2553define('ZEND_ACC_ALLOW_STATIC',   0x10000);
2554
2555define('ZEND_ACC_SHADOW', 0x2000);
2556
[731]2557if (ZEND_ENGINE_2_4) {
2558    define('ZEND_FETCH_GLOBAL',           0x00000000);
2559    define('ZEND_FETCH_LOCAL',            0x10000000);
2560    define('ZEND_FETCH_STATIC',           0x20000000);
2561    define('ZEND_FETCH_STATIC_MEMBER',    0x30000000);
2562    define('ZEND_FETCH_GLOBAL_LOCK',      0x40000000);
2563    define('ZEND_FETCH_LEXICAL',          0x50000000);
2564
2565    define('ZEND_FETCH_TYPE_MASK',        0x70000000);
2566}
2567else {
2568    define('ZEND_FETCH_GLOBAL',           0);
2569    define('ZEND_FETCH_LOCAL',            1);
2570    define('ZEND_FETCH_STATIC',           2);
2571    define('ZEND_FETCH_STATIC_MEMBER',    3);
2572    define('ZEND_FETCH_GLOBAL_LOCK',      4);
2573}
2574
[1]2575define('ZEND_FETCH_CLASS_DEFAULT',    0);
2576define('ZEND_FETCH_CLASS_SELF',       1);
2577define('ZEND_FETCH_CLASS_PARENT',     2);
2578define('ZEND_FETCH_CLASS_MAIN',       3);
2579define('ZEND_FETCH_CLASS_GLOBAL',     4);
2580define('ZEND_FETCH_CLASS_AUTO',       5);
2581define('ZEND_FETCH_CLASS_INTERFACE',  6);
[722]2582define('ZEND_FETCH_CLASS_STATIC',     7);
[731]2583if (ZEND_ENGINE_2_4) {
2584    define('ZEND_FETCH_CLASS_TRAIT',     14);
2585}
2586if (ZEND_ENGINE_2_3) {
2587    define('ZEND_FETCH_CLASS_MASK',     0xF);
2588}
[1]2589
2590define('ZEND_EVAL',               (1<<0));
2591define('ZEND_INCLUDE',            (1<<1));
2592define('ZEND_INCLUDE_ONCE',       (1<<2));
2593define('ZEND_REQUIRE',            (1<<3));
2594define('ZEND_REQUIRE_ONCE',       (1<<4));
2595
2596define('ZEND_ISSET',              (1<<0));
2597define('ZEND_ISEMPTY',            (1<<1));
[731]2598if (ZEND_ENGINE_2_4) {
2599    define('EXT_TYPE_UNUSED',     (1<<5));
2600}
2601else {
2602    define('EXT_TYPE_UNUSED',     (1<<0));
2603}
[1]2604
2605define('ZEND_FETCH_STANDARD',     0);
2606define('ZEND_FETCH_ADD_LOCK',     1);
2607
2608define('ZEND_FE_FETCH_BYREF',     1);
2609define('ZEND_FE_FETCH_WITH_KEY',  2);
2610
2611define('ZEND_MEMBER_FUNC_CALL',   1<<0);
2612define('ZEND_CTOR_CALL',          1<<1);
2613
2614define('ZEND_ARG_SEND_BY_REF',        (1<<0));
2615define('ZEND_ARG_COMPILE_TIME_BOUND', (1<<1));
2616define('ZEND_ARG_SEND_FUNCTION',      (1<<2));
2617
2618define('BYREF_NONE',       0);
2619define('BYREF_FORCE',      1);
2620define('BYREF_ALLOW',      2);
2621define('BYREF_FORCE_REST', 3);
2622define('IS_NULL',     0);
2623define('IS_LONG',     1);
2624define('IS_DOUBLE',   2);
[761]2625define('IS_BOOL',     ZEND_ENGINE_2 ? 3 : 6);
[1]2626define('IS_ARRAY',    4);
2627define('IS_OBJECT',   5);
[761]2628define('IS_STRING',   ZEND_ENGINE_2 ? 6 : 3);
[1]2629define('IS_RESOURCE', 7);
2630define('IS_CONSTANT', 8);
2631define('IS_CONSTANT_ARRAY',   9);
[781]2632/* Ugly hack to support constants as static array indices */
2633define('IS_CONSTANT_TYPE_MASK',   0x0f);
2634define('IS_CONSTANT_UNQUALIFIED', 0x10);
2635define('IS_CONSTANT_INDEX',       0x80);
2636define('IS_LEXICAL_VAR',          0x20);
2637define('IS_LEXICAL_REF',          0x40);
[1]2638
2639@define('XC_IS_CV', 16);
2640
2641/*
2642if (preg_match_all('!XC_[A-Z_]+!', file_get_contents(__FILE__), $ms)) {
2643    $verdiff = array();
2644    foreach ($ms[0] as $k) {
2645        if (!defined($k)) {
2646            $verdiff[$k] = -1;
2647            define($k, -1);
2648        }
2649    }
2650    var_export($verdiff);
2651}
2652/*/
2653foreach (array (
2654    'XC_HANDLE_EXCEPTION' => -1,
2655    'XC_FETCH_CLASS' => -1,
2656    'XC_FETCH_' => -1,
2657    'XC_FETCH_DIM_' => -1,
2658    'XC_ASSIGN_DIM' => -1,
2659    'XC_UNSET_DIM' => -1,
[749]2660    'XC_UNSET_OBJ' => -1,
[1]2661    'XC_ASSIGN_OBJ' => -1,
2662    'XC_ISSET_ISEMPTY_DIM_OBJ' => -1,
2663    'XC_ISSET_ISEMPTY_PROP_OBJ' => -1,
2664    'XC_ISSET_ISEMPTY_VAR' => -1,
[720]2665    'XC_INIT_STATIC_METHOD_CALL' => -1,
[1]2666    'XC_INIT_METHOD_CALL' => -1,
2667    'XC_VERIFY_ABSTRACT_CLASS' => -1,
2668    'XC_DECLARE_CLASS' => -1,
2669    'XC_DECLARE_INHERITED_CLASS' => -1,
[714]2670    'XC_DECLARE_INHERITED_CLASS_DELAYED' => -1,
[1]2671    'XC_ADD_INTERFACE' => -1,
2672    'XC_POST_DEC_OBJ' => -1,
2673    'XC_POST_INC_OBJ' => -1,
2674    'XC_PRE_DEC_OBJ' => -1,
2675    'XC_PRE_INC_OBJ' => -1,
2676    'XC_UNSET_OBJ' => -1,
2677    'XC_JMP_NO_CTOR' => -1,
2678    'XC_FETCH_' => -1,
2679    'XC_FETCH_DIM_' => -1,
2680    'XC_UNSET_DIM_OBJ' => -1,
2681    'XC_ISSET_ISEMPTY' => -1,
2682    'XC_INIT_FCALL_BY_FUNC' => -1,
2683    'XC_DO_FCALL_BY_FUNC' => -1,
2684    'XC_DECLARE_FUNCTION_OR_CLASS' => -1,
[749]2685    'XC_INIT_NS_FCALL_BY_NAME' => -1,
2686    'XC_GOTO' => -1,
2687    'XC_CATCH' => -1,
2688    'XC_THROW' => -1,
2689    'XC_INSTANCEOF' => -1,
2690    'XC_DECLARE_FUNCTION' => -1,
2691    'XC_RAISE_ABSTRACT_ERROR' => -1,
2692    'XC_DECLARE_CONST' => -1,
2693    'XC_USER_OPCODE' => -1,
2694    'XC_JMP_SET' => -1,
2695    'XC_DECLARE_LAMBDA_FUNCTION' => -1,
[1]2696) as $k => $v) {
2697    if (!defined($k)) {
2698        define($k, $v);
2699    }
2700}
2701// }}}
2702
Note: See TracBrowser for help on using the repository browser.