source: trunk/Decompiler.class.php @ 757

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

Decompiler: improves operator decompile

  • Property svn:eol-style set to native
File size: 54.5 KB
Line 
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
11function str($code, $indent = '') // {{{
12{
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    }
20    if (is_object($code)) {
21        $code = foldToCode($code, $indent);
22        return $code->toCode($indent);
23    }
24
25    return (string) $code;
26}
27// }}}
28function foldToCode($src, $indent = '') // {{{ wrap or rewrap anything to Decompiler_Code
29{
30    if (is_array($indent)) {
31        $indent = $indent['indent'];
32    }
33
34    if (!is_object($src)) {
35        return new Decompiler_Code($src);
36    }
37
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;
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
61    if (is_a($value, 'Decompiler_Object')) {
62        // use as is
63    }
64    else if (is_array($value)) {
65        $value = new Decompiler_ConstArray($value);
66    }
67    else {
68        $value = new Decompiler_Value($value);
69    }
70    return $value;
71}
72// }}}
73function unquoteName_($str, $asProperty, $indent = '') // {{{
74{
75    $str = str($str, $indent);
76    if (preg_match("!^'[\\w_][\\w\\d_\\\\]*'\$!", $str)) {
77        return str_replace('\\\\', '\\', substr($str, 1, -1));
78    }
79    else if ($asProperty) {
80        return "{" . $str . "}";
81    }
82    else {
83        return $str;
84    }
85}
86// }}}
87function unquoteProperty($str, $indent = '') // {{{
88{
89    return unquoteName_($str, true, $indent);
90}
91// }}}
92function unquoteName($str, $indent = '') // {{{
93{
94    return unquoteName_($str, false, $indent);
95}
96// }}}
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
110    function toCode($indent)
111    {
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;
127    }
128}
129// }}}
130class Decompiler_Code extends Decompiler_Object // {{{
131{
132    var $src;
133
134    function Decompiler_Code($src)
135    {
136        assert('isset($src)');
137        $this->src = $src;
138    }
139
140    function toCode($indent)
141    {
142        return $this->src;
143    }
144}
145// }}}
146class Decompiler_Binop extends Decompiler_Code // {{{
147{
148    var $opc;
149    var $op1;
150    var $op2;
151    var $parent;
152    var $indent;
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
162    function toCode($indent)
163    {
164        $opstr = $this->parent->binops[$this->opc];
165
166        $op1 = foldToCode($this->op1, $indent);
167        if (is_a($this->op1, 'Decompiler_Binop') && $this->op1->opc != $this->opc) {
168            $op1 = "(" . str($op1, $indent) . ")";
169        }
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) . ")";
173        }
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);
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
195    function toCode($indent)
196    {
197        switch ($this->fetchType) {
198        case ZEND_FETCH_LOCAL:
199            return '$' . substr($this->src, 1, -1);
200        case ZEND_FETCH_STATIC:
201            if (ZEND_ENGINE_2_3) {
202                // closure local variable?
203                return str($this->src);
204            }
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
225    function toCode($indent)
226    {
227        return $this->obj->toCode($indent);
228    }
229}
230// }}}
231class Decompiler_Dim extends Decompiler_Value // {{{
232{
233    var $offsets = array();
234    var $isLast = false;
235    var $isObject = false;
236    var $assign = null;
237
238    function toCode($indent)
239    {
240        if (is_a($this->value, 'Decompiler_ListBox')) {
241            $exp = str($this->value->obj->src, $indent);
242        }
243        else {
244            $exp = str($this->value, $indent);
245        }
246        $last = count($this->offsets) - 1;
247        foreach ($this->offsets as $i => $dim) {
248            if ($this->isObject && $i == $last) {
249                $exp .= '->' . unquoteProperty($dim, $indent);
250            }
251            else {
252                $exp .= '[' . str($dim, $indent) . ']';
253            }
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
269    function toCode($indent)
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)) {
276                return str($dim, $indent);
277            }
278            return str($this->dims[0]->assign, $indent) . ' = ' . str($dim, $indent);
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            }
287            $assign = foldToCode($dim->assign, $indent);
288        }
289        return str($this->toList($assigns)) . ' = ' . str($this->src, $indent);
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{
324    // emenets
325    function Decompiler_Array()
326    {
327        $this->value = array();
328    }
329
330    function toCode($indent)
331    {
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
344        $exp = "array(";
345        $indent = $indent . INDENT;
346        $assocWidth = 0;
347        $multiline = 0;
348        $i = 0;
349        foreach ($elementsCode as $element) {
350            list($keyCode, $valueCode) = $element;
351            if ((string) $i !== $keyCode) {
352                $assocWidth = 1;
353                break;
354            }
355            ++$i;
356        }
357        foreach ($elementsCode as $element) {
358            list($keyCode, $valueCode, $key, $value) = $element;
359            if ($assocWidth) {
360                $len = strlen($keyCode);
361                if ($assocWidth < $len) {
362                    $assocWidth = $len;
363                }
364            }
365            if (is_array($value) || is_a($value, 'Decompiler_Array')) {
366                $multiline ++;
367            }
368        }
369
370        $i = 0;
371        foreach ($elementsCode as $element) {
372            list($keyCode, $value) = $element;
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
386            if ($assocWidth) {
387                if ($multiline) {
388                    $exp .= sprintf("%-{$assocWidth}s => ", $keyCode);
389                }
390                else {
391                    $exp .= $keyCode . ' => ';
392                }
393            }
394
395            $exp .= $value;
396
397            $i ++;
398        }
399        if ($multiline) {
400            $exp .= "\n$indent)";
401        }
402        else {
403            $exp .= ")";
404        }
405        return $exp;
406    }
407}
408// }}}
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// }}}
421class Decompiler_ForeachBox extends Decompiler_Box // {{{
422{
423    var $iskey;
424
425    function toCode($indent)
426    {
427        return 'foreach (' . '';
428    }
429}
430// }}}
431
432class Decompiler
433{
434    var $namespace;
435    var $namespaceDecided;
436
437    function Decompiler()
438    {
439        // {{{ opinfo
440        $this->unaryops = array(
441                XC_BW_NOT   => '~',
442                XC_BOOL_NOT => '!',
443                );
444        $this->binops = array(
445                XC_ADD                 => "+",
446                XC_ASSIGN_ADD          => "+=",
447                XC_SUB                 => "-",
448                XC_ASSIGN_SUB          => "-=",
449                XC_MUL                 => "*",
450                XC_ASSIGN_MUL          => "*=",
451                XC_DIV                 => "/",
452                XC_ASSIGN_DIV          => "/=",
453                XC_MOD                 => "%",
454                XC_ASSIGN_MOD          => "%=",
455                XC_SL                  => "<<",
456                XC_ASSIGN_SL           => "<<=",
457                XC_SR                  => ">>",
458                XC_ASSIGN_SR           => ">>=",
459                XC_CONCAT              => ".",
460                XC_ASSIGN_CONCAT       => ".=",
461                XC_IS_IDENTICAL        => "===",
462                XC_IS_NOT_IDENTICAL    => "!==",
463                XC_IS_EQUAL            => "==",
464                XC_IS_NOT_EQUAL        => "!=",
465                XC_IS_SMALLER          => "<",
466                XC_IS_SMALLER_OR_EQUAL => "<=",
467                XC_BW_OR               => "|",
468                XC_ASSIGN_BW_OR        => "|=",
469                XC_BW_AND              => "&",
470                XC_ASSIGN_BW_AND       => "&=",
471                XC_BW_XOR              => "^",
472                XC_ASSIGN_BW_XOR       => "^=",
473                XC_BOOL_XOR            => "xor",
474                );
475        // }}}
476        $this->includeTypes = array( // {{{
477                ZEND_EVAL         => 'eval',
478                ZEND_INCLUDE      => 'include',
479                ZEND_INCLUDE_ONCE => 'include_once',
480                ZEND_REQUIRE      => 'require',
481                ZEND_REQUIRE_ONCE => 'require_once',
482                );
483                // }}}
484    }
485    function detectNamespace($name) // {{{
486    {
487        if ($this->namespaceDecided) {
488            return;
489        }
490
491        if (strpos($name, '\\') !== false) {
492            $this->namespace = strtok($name, '\\');
493            echo 'namespace ', $this->namespace, ";\n\n";
494        }
495
496        $this->namespaceDecided = true;
497    }
498    // }}}
499    function stripNamespace($name) // {{{
500    {
501        $len = strlen($this->namespace) + 1;
502        if (substr($name, 0, $len) == $this->namespace . '\\') {
503            return substr($name, $len);
504        }
505        else {
506            return $name;
507        }
508    }
509    // }}}
510    function outputPhp(&$opcodes, $opline, $last, $indent) // {{{
511    {
512        $origindent = $indent;
513        $curticks = 0;
514        for ($i = $opline; $i <= $last; $i ++) {
515            $op = $opcodes[$i];
516            if (isset($op['php'])) {
517                $toticks = isset($op['ticks']) ? (int) str($op['ticks']) : 0;
518                if ($curticks != $toticks) {
519                    $oldticks = $curticks;
520                    $curticks = $toticks;
521                    if (!$curticks) {
522                        echo $origindent, "}\n\n";
523                        $indent = $origindent;
524                    }
525                    else {
526                        if ($oldticks) {
527                            echo $origindent, "}\n\n";
528                        }
529                        else if (!$oldticks) {
530                            $indent .= INDENT;
531                        }
532                        echo $origindent, "declare (ticks=$curticks) {\n";
533                    }
534                }
535                echo $indent, str($op['php'], $indent), ";\n";
536            }
537        }
538        if ($curticks) {
539            echo $origindent, "}\n";
540        }
541    }
542    // }}}
543    function getOpVal($op, &$EX, $tostr = true, $free = false) // {{{
544    {
545        switch ($op['op_type']) {
546        case XC_IS_CONST:
547            return foldToCode(value($op['constant']), $EX);
548
549        case XC_IS_VAR:
550        case XC_IS_TMP_VAR:
551            $T = &$EX['Ts'];
552            $ret = $T[$op['var']];
553            if ($tostr) {
554                $ret = foldToCode($ret, $EX);
555            }
556            if ($free) {
557                unset($T[$op['var']]);
558            }
559            return $ret;
560
561        case XC_IS_CV:
562            $var = $op['var'];
563            $var = $EX['op_array']['vars'][$var];
564            return '$' . $var['name'];
565
566        case XC_IS_UNUSED:
567            return null;
568        }
569    }
570    // }}}
571    function removeKeyPrefix($array, $prefix) // {{{
572    {
573        $prefixLen = strlen($prefix);
574        $ret = array();
575        foreach ($array as $key => $value) {
576            if (substr($key, 0, $prefixLen) == $prefix) {
577                $key = substr($key, $prefixLen);
578            }
579            $ret[$key] = $value;
580        }
581        return $ret;
582    }
583    // }}}
584    function &fixOpcode($opcodes, $removeTailing = false, $defaultReturnValue = null) // {{{
585    {
586        for ($i = 0, $cnt = count($opcodes); $i < $cnt; $i ++) {
587            if (function_exists('xcache_get_fixed_opcode')) {
588                $opcodes[$i]['opcode'] = xcache_get_fixed_opcode($opcodes[$i]['opcode'], $i);
589            }
590            if (isset($opcodes[$i]['op1'])) {
591                $opcodes[$i]['op1'] = $this->removeKeyPrefix($opcodes[$i]['op1'], 'u.');
592                $opcodes[$i]['op2'] = $this->removeKeyPrefix($opcodes[$i]['op2'], 'u.');
593                $opcodes[$i]['result'] = $this->removeKeyPrefix($opcodes[$i]['result'], 'u.');
594            }
595            else {
596                $op = array(
597                    'op1' => array(),
598                    'op2' => array(),
599                    'op3' => array(),
600                );
601                foreach ($opcodes[$i] as $name => $value) {
602                    if (preg_match('!^(op1|op2|result)\\.(.*)!', $name, $m)) {
603                        list(, $which, $field) = $m;
604                        $op[$which][$field] = $value;
605                    }
606                    else if (preg_match('!^(op1|op2|result)_type$!', $name, $m)) {
607                        list(, $which) = $m;
608                        $op[$which]['op_type'] = $value;
609                    }
610                    else {
611                        $op[$name] = $value;
612                    }
613                }
614                $opcodes[$i] = $op;
615            }
616        }
617
618        if ($removeTailing) {
619            $last = count($opcodes) - 1;
620            if ($opcodes[$last]['opcode'] == XC_HANDLE_EXCEPTION) {
621                unset($opcodes[$last]);
622                --$last;
623            }
624            if ($opcodes[$last]['opcode'] == XC_RETURN) {
625                $op1 = $opcodes[$last]['op1'];
626                if ($op1['op_type'] == XC_IS_CONST && array_key_exists('constant', $op1) && $op1['constant'] === $defaultReturnValue) {
627                    unset($opcodes[$last]);
628                    --$last;
629                }
630            }
631        }
632        return $opcodes;
633    }
634    // }}}
635    function &dop_array($op_array, $indent = '') // {{{
636    {
637        $op_array['opcodes'] = $this->fixOpcode($op_array['opcodes'], true, $indent == '' ? 1 : null);
638        $opcodes = &$op_array['opcodes'];
639        $EX['indent'] = '';
640        // {{{ build jmp array
641        for ($i = 0, $cnt = count($opcodes); $i < $cnt; $i ++) {
642            $op = &$opcodes[$i];
643            /*
644            if ($op['opcode'] == XC_JMPZ) {
645                $this->dumpop($op, $EX);
646                var_dump($op);
647            }
648            continue;
649            */
650            $op['line'] = $i;
651            switch ($op['opcode']) {
652            case XC_GOTO:
653            case XC_JMP:
654                $target = $op['op1']['var'];
655                $op['jmpouts'] = array($target);
656                $opcodes[$target]['jmpins'][] = $i;
657                break;
658
659            case XC_JMPZNZ:
660                $jmpz = $op['op2']['opline_num'];
661                $jmpnz = $op['extended_value'];
662                $op['jmpouts'] = array($jmpz, $jmpnz);
663                $opcodes[$jmpz]['jmpins'][] = $i;
664                $opcodes[$jmpnz]['jmpins'][] = $i;
665                break;
666
667            case XC_JMPZ:
668            case XC_JMPNZ:
669            case XC_JMPZ_EX:
670            case XC_JMPNZ_EX:
671            case XC_JMP_SET:
672            // case XC_FE_RESET:
673            case XC_FE_FETCH:
674            // case XC_JMP_NO_CTOR:
675                $target = $op['op2']['opline_num'];
676                //if (!isset($target)) {
677                //  $this->dumpop($op, $EX);
678                //  var_dump($op); exit;
679                //}
680                $op['jmpouts'] = array($target);
681                $opcodes[$target]['jmpins'][] = $i;
682                break;
683
684            /*
685            case XC_RETURN:
686                $op['jmpouts'] = array();
687                break;
688            */
689            }
690        }
691        unset($op);
692        // }}}
693        // build semi-basic blocks
694        $nextbbs = array();
695        $starti = 0;
696        for ($i = 1, $cnt = count($opcodes); $i < $cnt; $i ++) {
697            if (isset($opcodes[$i]['jmpins'])
698             || isset($opcodes[$i - 1]['jmpouts'])) {
699                $nextbbs[$starti] = $i;
700                $starti = $i;
701            }
702        }
703        $nextbbs[$starti] = $cnt;
704
705        $EX = array();
706        $EX['Ts'] = array();
707        $EX['indent'] = $indent;
708        $EX['nextbbs'] = $nextbbs;
709        $EX['op_array'] = &$op_array;
710        $EX['opcodes'] = &$opcodes;
711        // func call
712        $EX['object'] = null;
713        $EX['called_scope'] = null;
714        $EX['fbc'] = null;
715        $EX['argstack'] = array();
716        $EX['arg_types_stack'] = array();
717        $EX['last'] = count($opcodes) - 1;
718        $EX['silence'] = 0;
719
720        for ($next = 0, $last = $EX['last'];
721                $loop = $this->outputCode($EX, $next, $last, $indent, true);
722                list($next, $last) = $loop) {
723            // empty
724        }
725        return $EX;
726    }
727    // }}}
728    function outputCode(&$EX, $opline, $last, $indent, $loop = false) // {{{
729    {
730        $op = &$EX['opcodes'][$opline];
731        $next = $EX['nextbbs'][$opline];
732
733        $end = $next - 1;
734        if ($end > $last) {
735            $end = $last;
736        }
737
738        if (isset($op['jmpins'])) {
739            echo "\nline", $op['line'], ":\n";
740        }
741        else {
742            // echo ";;;\n";
743        }
744        $this->dasmBasicBlock($EX, $opline, $end);
745        $this->outputPhp($EX['opcodes'], $opline, $end, $indent);
746        // jmpout op
747        $op = &$EX['opcodes'][$end];
748        $op1 = $op['op1'];
749        $op2 = $op['op2'];
750        $ext = $op['extended_value'];
751        $line = $op['line'];
752
753        if (isset($EX['opcodes'][$next])) {
754            if (isset($last) && $next > $last) {
755                $next = null;
756            }
757        }
758        else {
759            $next = null;
760        }
761        if ($op['opcode'] == XC_FE_FETCH) {
762            $opline = $next;
763            $next = $op['op2']['opline_num'];
764            $end = $next - 1;
765
766            ob_start();
767            $this->outputCode($EX, $opline, $end /* - 1 skip last jmp */, $indent . INDENT);
768            $body = ob_get_clean();
769
770            $as = foldToCode($op['fe_as'], $EX);
771            if (isset($op['fe_key'])) {
772                $as = str($op['fe_key'], $EX) . ' => ' . str($as);
773            }
774            echo "{$indent}foreach (" . str($op['fe_src'], $EX) . " as $as) {\n";
775            echo $body;
776            echo "{$indent}}";
777            // $this->outputCode($EX, $next, $last, $indent);
778            // return;
779        }
780        /*
781        if ($op['opcode'] == XC_JMPZ) {
782            $target = $op2['opline_num'];
783            if ($line + 1) {
784                $nextblock = $EX['nextbbs'][$next];
785                $jmpop = end($nextblock);
786                if ($jmpop['opcode'] == XC_JMP) {
787                    $ifendline = $op2['opline_num'];
788                    if ($ifendline >= $line) {
789                        $cond = $op['cond'];
790                        echo "{$indent}if ($cond) {\n";
791                        $this->outputCode($EX, $next, $last, INDENT . $indent);
792                        echo "$indent}\n";
793                        $this->outputCode($EX, $target, $last, $indent);
794                        return;
795                    }
796                }
797            }
798        }
799        */
800        if (!isset($next)) {
801            return;
802        }
803        if (!empty($op['jmpouts']) && isset($op['isjmp'])) {
804            if (isset($op['cond'])) {
805                echo "{$indent}check (" . str($op["cond"]) . ") {\n";
806                echo INDENT;
807            }
808            echo $indent;
809            echo xcache_get_opcode($op['opcode']), ' line', $op['jmpouts'][0];
810            if (isset($op['jmpouts'][1])) {
811                echo ', line', $op['jmpouts'][1];
812            }
813            echo ";";
814            // echo ' // <- line', $op['line'];
815            echo "\n";
816            if (isset($op['cond'])) echo "$indent}\n";
817        }
818
819        // proces JMPZ_EX/JMPNZ_EX for AND,OR
820        $op = &$EX['opcodes'][$next];
821        /*
822        if (isset($op['jmpins'])) {
823            foreach (array_reverse($op['jmpins']) as $fromline) {
824                $fromop = $EX['opcodes'][$fromline];
825                switch ($fromop['opcode']) {
826                case XC_JMPZ_EX: $opstr = 'and'; break;
827                case XC_JMPNZ_EX: $opstr = 'or'; break;
828                case XC_JMPZNZ: var_dump($fromop); exit;
829                default: continue 2;
830                }
831
832                $var = $fromop['result']['var'];
833                var_dump($EX['Ts'][$var]);
834                $EX['Ts'][$var] = '(' . $fromop['and_or'] . " $opstr " . $EX['Ts'][$var] . ')';
835            }
836            #$this->outputCode($EX, $next, $last, $indent);
837            #return;
838        }
839        */
840        if (isset($op['cond_false'])) {
841            // $this->dumpop($op, $EX);
842            // any true comes here, so it's a "or"
843            $cond = implode(' and ', str($op['cond_false']));
844            // var_dump($op['cond'] = $cond);
845            /*
846            $rvalue = implode(' or ', $op['cond_true']) . ' or ' . $rvalue;
847            unset($op['cond_true']);
848            */
849        }
850
851        if ($loop) {
852            return array($next, $last);
853        }
854        $this->outputCode($EX, $next, $last, $indent);
855    }
856    // }}}
857    function dasmBasicBlock(&$EX, $opline, $last) // {{{
858    {
859        $T = &$EX['Ts'];
860        $opcodes = &$EX['opcodes'];
861        $lastphpop = null;
862
863        for ($i = $opline, $ic = $last + 1; $i < $ic; $i ++) {
864            // {{{ prepair
865            $op = &$opcodes[$i];
866            $opc = $op['opcode'];
867            if ($opc == XC_NOP) {
868                continue;
869            }
870
871            $op1 = $op['op1'];
872            $op2 = $op['op2'];
873            $res = $op['result'];
874            $ext = $op['extended_value'];
875
876            $opname = xcache_get_opcode($opc);
877
878            if ($opname == 'UNDEF' || !isset($opname)) {
879                echo 'UNDEF OP:';
880                $this->dumpop($op, $EX);
881                continue;
882            }
883            // $this->dumpop($op, $EX); //var_dump($op);
884
885            $resvar = null;
886            if ((ZEND_ENGINE_2_4 ? ($res['op_type'] & EXT_TYPE_UNUSED) : ($res['EA.type'] & EXT_TYPE_UNUSED)) || $res['op_type'] == XC_IS_UNUSED) {
887                $istmpres = false;
888            }
889            else {
890                $istmpres = true;
891            }
892            // }}}
893            // echo $opname, "\n";
894
895            $call = array(&$this, $opname);
896            if (is_callable($call)) {
897                $this->{$opname}($op, $EX);
898            }
899            else if (isset($this->binops[$opc])) { // {{{
900                $op1val = $this->getOpVal($op1, $EX, false);
901                $op2val = $this->getOpVal($op2, $EX, false);
902                $rvalue = new Decompiler_Binop($this, $op1val, $opc, $op2val);
903                $resvar = $rvalue;
904                // }}}
905            }
906            else if (isset($this->unaryops[$opc])) { // {{{
907                $op1val = $this->getOpVal($op1, $EX);
908                $myop = $this->unaryops[$opc];
909                $rvalue = $myop . str($op1val);
910                $resvar = $rvalue;
911                // }}}
912            }
913            else {
914                switch ($opc) {
915                case XC_NEW: // {{{
916                    array_push($EX['arg_types_stack'], array($EX['fbc'], $EX['object'], $EX['called_scope']));
917                    $EX['object'] = (int) $res['var'];
918                    $EX['called_scope'] = null;
919                    $EX['fbc'] = 'new ' . unquoteName($this->getOpVal($op1, $EX), $EX);
920                    if (!ZEND_ENGINE_2) {
921                        $resvar = '$new object$';
922                    }
923                    break;
924                    // }}}
925                case XC_THROW: // {{{
926                    $resvar = 'throw ' . str($this->getOpVal($op1, $EX));
927                    break;
928                    // }}}
929                case XC_CLONE: // {{{
930                    $resvar = 'clone ' . str($this->getOpVal($op1, $EX));
931                    break;
932                    // }}}
933                case XC_CATCH: // {{{
934                    $resvar = 'catch (' . str($this->getOpVal($op1, $EX)) . ' ' . str($this->getOpVal($op2, $EX)) . ')';
935                    break;
936                    // }}}
937                case XC_INSTANCEOF: // {{{
938                    $resvar = str($this->getOpVal($op1, $EX)) . ' instanceof ' . str($this->getOpVal($op2, $EX));
939                    break;
940                    // }}}
941                case XC_FETCH_CLASS: // {{{
942                    if ($op2['op_type'] == XC_IS_UNUSED) {
943                        switch (($ext & (defined('ZEND_FETCH_CLASS_MASK') ? ZEND_FETCH_CLASS_MASK : 0xFF))) {
944                        case ZEND_FETCH_CLASS_SELF:
945                            $class = 'self';
946                            break;
947                        case ZEND_FETCH_CLASS_PARENT:
948                            $class = 'parent';
949                            break;
950                        case ZEND_FETCH_CLASS_STATIC:
951                            $class = 'static';
952                            break;
953                        }
954                        $istmpres = true;
955                    }
956                    else {
957                        $class = $this->getOpVal($op2, $EX);
958                        if (isset($op2['constant'])) {
959                            $class = $this->stripNamespace(unquoteName($class));
960                        }
961                    }
962                    $resvar = $class;
963                    break;
964                    // }}}
965                case XC_FETCH_CONSTANT: // {{{
966                    if ($op1['op_type'] == XC_IS_UNUSED) {
967                        $resvar = $this->stripNamespace($op2['constant']);
968                        break;
969                    }
970
971                    if ($op1['op_type'] == XC_IS_CONST) {
972                        $resvar = $this->stripNamespace($op1['constant']);
973                    }
974                    else {
975                        $resvar = $this->getOpVal($op1, $EX);
976                    }
977
978                    $resvar = str($resvar) . '::' . unquoteName($this->getOpVal($op2, $EX));
979                    break;
980                    // }}}
981                    // {{{ case XC_FETCH_*
982                case XC_FETCH_R:
983                case XC_FETCH_W:
984                case XC_FETCH_RW:
985                case XC_FETCH_FUNC_ARG:
986                case XC_FETCH_UNSET:
987                case XC_FETCH_IS:
988                case XC_UNSET_VAR:
989                    $rvalue = $this->getOpVal($op1, $EX);
990                    if (defined('ZEND_FETCH_TYPE_MASK')) {
991                        $fetchtype = ($ext & ZEND_FETCH_TYPE_MASK);
992                    }
993                    else {
994                        $fetchtype = $op2[!ZEND_ENGINE_2 ? 'fetch_type' : 'EA.type'];
995                    }
996                    switch ($fetchtype) {
997                    case ZEND_FETCH_STATIC_MEMBER:
998                        $class = $this->getOpVal($op2, $EX);
999                        $rvalue = str($class) . '::$' . unquoteName($rvalue, $EX);
1000                        break;
1001                    default:
1002                        $name = unquoteName($rvalue, $EX);
1003                        $globalname = xcache_is_autoglobal($name) ? "\$$name" : "\$GLOBALS[" . str($rvalue) . "]";
1004                        $rvalue = new Decompiler_Fetch($rvalue, $fetchtype, $globalname);
1005                        break;
1006                    }
1007                    if ($opc == XC_UNSET_VAR) {
1008                        $op['php'] = "unset(" . str($rvalue, $EX) . ")";
1009                        $lastphpop = &$op;
1010                    }
1011                    else if ($res['op_type'] != XC_IS_UNUSED) {
1012                        $resvar = $rvalue;
1013                    }
1014                    break;
1015                    // }}}
1016                    // {{{ case XC_FETCH_DIM_*
1017                case XC_FETCH_DIM_TMP_VAR:
1018                case XC_FETCH_DIM_R:
1019                case XC_FETCH_DIM_W:
1020                case XC_FETCH_DIM_RW:
1021                case XC_FETCH_DIM_FUNC_ARG:
1022                case XC_FETCH_DIM_UNSET:
1023                case XC_FETCH_DIM_IS:
1024                case XC_ASSIGN_DIM:
1025                case XC_UNSET_DIM_OBJ: // PHP 4 only
1026                case XC_UNSET_DIM:
1027                case XC_UNSET_OBJ:
1028                    $src = $this->getOpVal($op1, $EX, false);
1029                    if (is_a($src, "Decompiler_ForeachBox")) {
1030                        $src->iskey = $this->getOpVal($op2, $EX);
1031                        $resvar = $src;
1032                        break;
1033                    }
1034
1035                    if (is_a($src, "Decompiler_DimBox")) {
1036                        $dimbox = $src;
1037                    }
1038                    else {
1039                        if (!is_a($src, "Decompiler_ListBox")) {
1040                            $op1val = $this->getOpVal($op1, $EX, false);
1041                            $list = new Decompiler_List(isset($op1val) ? $op1val : '$this');
1042
1043                            $src = new Decompiler_ListBox($list);
1044                            if (!isset($op1['var'])) {
1045                                $this->dumpop($op, $EX);
1046                                var_dump($op);
1047                                die('missing var');
1048                            }
1049                            $T[$op1['var']] = $src;
1050                            unset($list);
1051                        }
1052                        $dim = new Decompiler_Dim($src);
1053                        $src->obj->dims[] = &$dim;
1054
1055                        $dimbox = new Decompiler_DimBox($dim);
1056                    }
1057                    $dim = &$dimbox->obj;
1058                    $dim->offsets[] = $this->getOpVal($op2, $EX);
1059                    if ($ext == ZEND_FETCH_ADD_LOCK) {
1060                        $src->obj->everLocked = true;
1061                    }
1062                    else if ($ext == ZEND_FETCH_STANDARD) {
1063                        $dim->isLast = true;
1064                    }
1065                    if ($opc == XC_UNSET_OBJ) {
1066                        $dim->isObject = true;
1067                    }
1068                    unset($dim);
1069                    $rvalue = $dimbox;
1070                    unset($dimbox);
1071
1072                    if ($opc == XC_ASSIGN_DIM) {
1073                        $lvalue = $rvalue;
1074                        ++ $i;
1075                        $rvalue = $this->getOpVal($opcodes[$i]['op1'], $EX);
1076                        $resvar = str($lvalue, $EX) . ' = ' . str($rvalue);
1077                    }
1078                    else if ($opc == XC_UNSET_DIM || $opc == XC_UNSET_OBJ) {
1079                        $op['php'] = "unset(" . str($rvalue, $EX) . ")";
1080                        $lastphpop = &$op;
1081                    }
1082                    else if ($res['op_type'] != XC_IS_UNUSED) {
1083                        $resvar = $rvalue;
1084                    }
1085                    break;
1086                    // }}}
1087                case XC_ASSIGN: // {{{
1088                    $lvalue = $this->getOpVal($op1, $EX);
1089                    $rvalue = $this->getOpVal($op2, $EX, false);
1090                    if (is_a($rvalue, 'Decompiler_ForeachBox')) {
1091                        $type = $rvalue->iskey ? 'fe_key' : 'fe_as';
1092                        $rvalue->obj[$type] = $lvalue;
1093                        unset($T[$op2['var']]);
1094                        break;
1095                    }
1096                    if (is_a($rvalue, "Decompiler_DimBox")) {
1097                        $dim = &$rvalue->obj;
1098                        $dim->assign = $lvalue;
1099                        if ($dim->isLast) {
1100                            $resvar = foldToCode($dim->value, $EX);
1101                        }
1102                        unset($dim);
1103                        break;
1104                    }
1105                    $resvar = "$lvalue = " . str($rvalue, $EX);
1106                    break;
1107                    // }}}
1108                case XC_ASSIGN_REF: // {{{
1109                    $lvalue = $this->getOpVal($op1, $EX);
1110                    $rvalue = $this->getOpVal($op2, $EX, false);
1111                    if (is_a($rvalue, 'Decompiler_Fetch')) {
1112                        $src = str($rvalue->src, $EX);
1113                        if ('$' . unquoteName($src) == $lvalue) {
1114                            switch ($rvalue->fetchType) {
1115                            case ZEND_FETCH_GLOBAL:
1116                            case ZEND_FETCH_GLOBAL_LOCK:
1117                                $resvar = 'global ' . $lvalue;
1118                                break 2;
1119                            case ZEND_FETCH_STATIC:
1120                                $statics = &$EX['op_array']['static_variables'];
1121                                $resvar = 'static ' . $lvalue;
1122                                $name = unquoteName($src);
1123                                if (isset($statics[$name])) {
1124                                    $var = $statics[$name];
1125                                    $resvar .= ' = ';
1126                                    $resvar .= str(value($var), $EX);
1127                                }
1128                                unset($statics);
1129                                break 2;
1130                            default:
1131                            }
1132                        }
1133                    }
1134                    // TODO: PHP_6 global
1135                    $rvalue = str($rvalue, $EX);
1136                    $resvar = "$lvalue = &$rvalue";
1137                    break;
1138                    // }}}
1139                // {{{ case XC_FETCH_OBJ_*
1140                case XC_FETCH_OBJ_R:
1141                case XC_FETCH_OBJ_W:
1142                case XC_FETCH_OBJ_RW:
1143                case XC_FETCH_OBJ_FUNC_ARG:
1144                case XC_FETCH_OBJ_UNSET:
1145                case XC_FETCH_OBJ_IS:
1146                case XC_ASSIGN_OBJ:
1147                    $obj = $this->getOpVal($op1, $EX);
1148                    if (!isset($obj)) {
1149                        $obj = '$this';
1150                    }
1151                    $rvalue = str($obj) . "->" . unquoteProperty($this->getOpVal($op2, $EX), $EX);
1152                    if ($res['op_type'] != XC_IS_UNUSED) {
1153                        $resvar = $rvalue;
1154                    }
1155                    if ($opc == XC_ASSIGN_OBJ) {
1156                        ++ $i;
1157                        $lvalue = $rvalue;
1158                        $rvalue = $this->getOpVal($opcodes[$i]['op1'], $EX);
1159                        $resvar = "$lvalue = " . str($rvalue);
1160                    }
1161                    break;
1162                    // }}}
1163                case XC_ISSET_ISEMPTY_DIM_OBJ:
1164                case XC_ISSET_ISEMPTY_PROP_OBJ:
1165                case XC_ISSET_ISEMPTY:
1166                case XC_ISSET_ISEMPTY_VAR: // {{{
1167                    if ($opc == XC_ISSET_ISEMPTY_VAR) {
1168                        $rvalue = $this->getOpVal($op1, $EX);;
1169                        if (preg_match($this->rQuotedName, $rvalue)) {
1170                            $rvalue = '$' . substr($rvalue, 1, -1);
1171                        }
1172                        else {
1173                            $rvalue = '${' . $rvalue . '}';
1174                        }
1175                        if ($op2['EA.type'] == ZEND_FETCH_STATIC_MEMBER) {
1176                            $class = $this->getOpVal($op2, $EX);
1177                            $rvalue = $class . '::' . $rvalue;
1178                        }
1179                    }
1180                    else if ($opc == XC_ISSET_ISEMPTY) {
1181                        $rvalue = $this->getOpVal($op1, $EX);
1182                    }
1183                    else {
1184                        $container = $this->getOpVal($op1, $EX);
1185                        $dim = $this->getOpVal($op2, $EX);
1186                        if ($opc == XC_ISSET_ISEMPTY_PROP_OBJ) {
1187                            if (preg_match($this->rQuotedName, $dim)) {
1188                                $rvalue = $container . "->" . substr($dim, 1, -1);
1189                            }
1190                            else {
1191                                $rvalue = $container . "->{" . $dim . "}";
1192                            }
1193                        }
1194                        else {
1195                            $rvalue = $container . "[$dim]";
1196                        }
1197                    }
1198
1199                    switch ((!ZEND_ENGINE_2 ? $op['op2']['var'] /* constant */ : $ext) & (ZEND_ISSET|ZEND_ISEMPTY)) {
1200                    case ZEND_ISSET:
1201                        $rvalue = "isset($rvalue)";
1202                        break;
1203                    case ZEND_ISEMPTY:
1204                        $rvalue = "empty($rvalue)";
1205                        break;
1206                    }
1207                    $resvar = $rvalue;
1208                    break;
1209                    // }}}
1210                case XC_SEND_VAR_NO_REF:
1211                case XC_SEND_VAL:
1212                case XC_SEND_REF:
1213                case XC_SEND_VAR: // {{{
1214                    $ref = ($opc == XC_SEND_REF ? '&' : '');
1215                    $EX['argstack'][] = $ref . str($this->getOpVal($op1, $EX));
1216                    break;
1217                    // }}}
1218                case XC_INIT_STATIC_METHOD_CALL:
1219                case XC_INIT_METHOD_CALL: // {{{
1220                    array_push($EX['arg_types_stack'], array($EX['fbc'], $EX['object'], $EX['called_scope']));
1221                    if ($opc == XC_INIT_STATIC_METHOD_CALL || $opc == XC_INIT_METHOD_CALL || $op1['op_type'] != XC_IS_UNUSED) {
1222                        $obj = $this->getOpVal($op1, $EX);
1223                        if (!isset($obj)) {
1224                            $obj = '$this';
1225                        }
1226                        if ($opc == XC_INIT_STATIC_METHOD_CALL || /* PHP4 */ isset($op1['constant'])) {
1227                            $EX['object'] = null;
1228                            $EX['called_scope'] = $this->stripNamespace(unquoteName($obj, $EX));
1229                        }
1230                        else {
1231                            $EX['object'] = $obj;
1232                            $EX['called_scope'] = null;
1233                        }
1234                        if ($res['op_type'] != XC_IS_UNUSED) {
1235                            $resvar = '$obj call$';
1236                        }
1237                    }
1238                    else {
1239                        $EX['object'] = null;
1240                        $EX['called_scope'] = null;
1241                    }
1242
1243                    $EX['fbc'] = $this->getOpVal($op2, $EX, false);
1244                    if (($opc == XC_INIT_STATIC_METHOD_CALL || $opc == XC_INIT_METHOD_CALL) && !isset($EX['fbc'])) {
1245                        $EX['fbc'] = '__construct';
1246                    }
1247                    break;
1248                    // }}}
1249                case XC_INIT_NS_FCALL_BY_NAME:
1250                case XC_INIT_FCALL_BY_NAME: // {{{
1251                    array_push($EX['arg_types_stack'], array($EX['fbc'], $EX['object'], $EX['called_scope']));
1252                    if (!ZEND_ENGINE_2 && ($ext & ZEND_CTOR_CALL)) {
1253                        break;
1254                    }
1255                    $EX['object'] = null;
1256                    $EX['called_scope'] = null;
1257                    $EX['fbc'] = $this->getOpVal($op2, $EX);
1258                    break;
1259                    // }}}
1260                case XC_INIT_FCALL_BY_FUNC: // {{{ deprecated even in PHP 4?
1261                    $EX['object'] = null;
1262                    $EX['called_scope'] = null;
1263                    $which = $op1['var'];
1264                    $EX['fbc'] = $EX['op_array']['funcs'][$which]['name'];
1265                    break;
1266                    // }}}
1267                case XC_DO_FCALL_BY_FUNC:
1268                    $which = $op1['var'];
1269                    $fname = $EX['op_array']['funcs'][$which]['name'];
1270                    $args = $this->popargs($EX, $ext);
1271                    $resvar = $fname . "($args)";
1272                    break;
1273                case XC_DO_FCALL:
1274                    $fname = unquoteName($this->getOpVal($op1, $EX, false), $EX);
1275                    $args = $this->popargs($EX, $ext);
1276                    $resvar = $fname . "($args)";
1277                    break;
1278                case XC_DO_FCALL_BY_NAME: // {{{
1279                    $object = null;
1280
1281                    $fname = unquoteName($EX['fbc'], $EX);
1282                    if (!is_int($EX['object'])) {
1283                        $object = $EX['object'];
1284                    }
1285
1286                    $args = $this->popargs($EX, $ext);
1287
1288                    $prefix = (isset($object) ? $object . '->' : '' )
1289                        . (isset($EX['called_scope']) ? $EX['called_scope'] . '::' : '' );
1290                    $resvar = $prefix
1291                        . (!$prefix ? $this->stripNamespace($fname) : $fname)
1292                        . "($args)";
1293                    unset($args);
1294
1295                    if (is_int($EX['object'])) {
1296                        $T[$EX['object']] = $resvar;
1297                        $resvar = null;
1298                    }
1299                    list($EX['fbc'], $EX['object'], $EX['called_scope']) = array_pop($EX['arg_types_stack']);
1300                    break;
1301                    // }}}
1302                case XC_VERIFY_ABSTRACT_CLASS: // {{{
1303                    //unset($T[$op1['var']]);
1304                    break;
1305                    // }}}
1306                case XC_DECLARE_CLASS: 
1307                case XC_DECLARE_INHERITED_CLASS:
1308                case XC_DECLARE_INHERITED_CLASS_DELAYED: // {{{
1309                    $key = $op1['constant'];
1310                    if (!isset($this->dc['class_table'][$key])) {
1311                        echo 'class not found: ', $key, 'existing classes are:', "\n";
1312                        var_dump(array_keys($this->dc['class_table']));
1313                        exit;
1314                    }
1315                    $class = &$this->dc['class_table'][$key];
1316                    if (!isset($class['name'])) {
1317                        $class['name'] = unquoteName($this->getOpVal($op2, $EX), $EX);
1318                    }
1319                    if ($opc == XC_DECLARE_INHERITED_CLASS || $opc == XC_DECLARE_INHERITED_CLASS_DELAYED) {
1320                        $ext /= XC_SIZEOF_TEMP_VARIABLE;
1321                        $class['parent'] = $T[$ext];
1322                        unset($T[$ext]);
1323                    }
1324                    else {
1325                        $class['parent'] = null;
1326                    }
1327
1328                    for (;;) {
1329                        if ($i + 1 < $ic
1330                         && $opcodes[$i + 1]['opcode'] == XC_ADD_INTERFACE
1331                         && $opcodes[$i + 1]['op1']['var'] == $res['var']) {
1332                            // continue
1333                        }
1334                        else if ($i + 2 < $ic
1335                         && $opcodes[$i + 2]['opcode'] == XC_ADD_INTERFACE
1336                         && $opcodes[$i + 2]['op1']['var'] == $res['var']
1337                         && $opcodes[$i + 1]['opcode'] == XC_FETCH_CLASS) {
1338                            // continue
1339                        }
1340                        else {
1341                            break;
1342                        }
1343
1344                        $fetchop = &$opcodes[$i + 1];
1345                        $interface = $this->stripNamespace(unquoteName($this->getOpVal($fetchop['op2'], $EX), $EX));
1346                        $addop = &$opcodes[$i + 2];
1347                        $class['interfaces'][$addop['extended_value']] = $interface;
1348                        unset($fetchop, $addop);
1349                        $i += 2;
1350                    }
1351                    $this->dclass($class);
1352                    echo "\n";
1353                    unset($class);
1354                    break;
1355                    // }}}
1356                case XC_INIT_STRING: // {{{
1357                    $resvar = "''";
1358                    break;
1359                    // }}}
1360                case XC_ADD_CHAR:
1361                case XC_ADD_STRING:
1362                case XC_ADD_VAR: // {{{
1363                    $op1val = $this->getOpVal($op1, $EX);
1364                    $op2val = $this->getOpVal($op2, $EX);
1365                    switch ($opc) {
1366                    case XC_ADD_CHAR:
1367                        $op2val = value(chr(str($op2val)));
1368                        break;
1369                    case XC_ADD_STRING:
1370                        break;
1371                    case XC_ADD_VAR:
1372                        break;
1373                    }
1374                    if (str($op1val) == "''") {
1375                        $rvalue = $op2val;
1376                    }
1377                    else if (str($op2val) == "''") {
1378                        $rvalue = $op1val;
1379                    }
1380                    else {
1381                        $rvalue = str($op1val) . ' . ' . str($op2val);
1382                    }
1383                    $resvar = $rvalue;
1384                    // }}}
1385                    break;
1386                case XC_PRINT: // {{{
1387                    $op1val = $this->getOpVal($op1, $EX);
1388                    $resvar = "print($op1val)";
1389                    break;
1390                    // }}}
1391                case XC_ECHO: // {{{
1392                    $op1val = $this->getOpVal($op1, $EX);
1393                    $resvar = "echo " . str($op1val);
1394                    break;
1395                    // }}}
1396                case XC_EXIT: // {{{
1397                    $op1val = $this->getOpVal($op1, $EX);
1398                    $resvar = "exit($op1val)";
1399                    break;
1400                    // }}}
1401                case XC_INIT_ARRAY:
1402                case XC_ADD_ARRAY_ELEMENT: // {{{
1403                    $rvalue = $this->getOpVal($op1, $EX, false, true);
1404
1405                    if ($opc == XC_ADD_ARRAY_ELEMENT) {
1406                        $assoc = $this->getOpVal($op2, $EX);
1407                        if (isset($assoc)) {
1408                            $T[$res['var']]->value[] = array($assoc, $rvalue);
1409                        }
1410                        else {
1411                            $T[$res['var']]->value[] = array(null, $rvalue);
1412                        }
1413                    }
1414                    else {
1415                        if ($opc == XC_INIT_ARRAY) {
1416                            $resvar = new Decompiler_Array();
1417                            if (!isset($rvalue)) {
1418                                continue;
1419                            }
1420                        }
1421
1422                        $assoc = $this->getOpVal($op2, $EX);
1423                        if (isset($assoc)) {
1424                            $resvar->value[] = array($assoc, $rvalue);
1425                        }
1426                        else {
1427                            $resvar->value[] = array(null, $rvalue);
1428                        }
1429                    }
1430                    break;
1431                    // }}}
1432                case XC_QM_ASSIGN: // {{{
1433                    $resvar = $this->getOpVal($op1, $EX);
1434                    break;
1435                    // }}}
1436                case XC_BOOL: // {{{
1437                    $resvar = /*'(bool) ' .*/ $this->getOpVal($op1, $EX);
1438                    break;
1439                    // }}}
1440                case XC_RETURN: // {{{
1441                    $resvar = "return " . str($this->getOpVal($op1, $EX));
1442                    break;
1443                    // }}}
1444                case XC_INCLUDE_OR_EVAL: // {{{
1445                    $type = $op2['var']; // hack
1446                    $keyword = $this->includeTypes[$type];
1447                    $resvar = "$keyword " . str($this->getOpVal($op1, $EX));
1448                    break;
1449                    // }}}
1450                case XC_FE_RESET: // {{{
1451                    $resvar = $this->getOpVal($op1, $EX);
1452                    break;
1453                    // }}}
1454                case XC_FE_FETCH: // {{{
1455                    $op['fe_src'] = $this->getOpVal($op1, $EX);
1456                    $fe = new Decompiler_ForeachBox($op);
1457                    $fe->iskey = false;
1458                    $T[$res['var']] = $fe;
1459
1460                    ++ $i;
1461                    if (($ext & ZEND_FE_FETCH_WITH_KEY)) {
1462                        $fe = new Decompiler_ForeachBox($op);
1463                        $fe->iskey = true;
1464
1465                        $res = $opcodes[$i]['result'];
1466                        $T[$res['var']] = $fe;
1467                    }
1468                    break;
1469                    // }}}
1470                case XC_SWITCH_FREE: // {{{
1471                    // unset($T[$op1['var']]);
1472                    break;
1473                    // }}}
1474                case XC_FREE: // {{{
1475                    $free = $T[$op1['var']];
1476                    if (!is_a($free, 'Decompiler_Array') && !is_a($free, 'Decompiler_Box')) {
1477                        $op['php'] = is_object($free) ? $free : $this->unquote($free, '(', ')');
1478                        $lastphpop = &$op;
1479                    }
1480                    unset($T[$op1['var']], $free);
1481                    break;
1482                    // }}}
1483                case XC_JMP_NO_CTOR:
1484                    break;
1485                case XC_JMP_SET: // ?:
1486                case XC_JMPNZ: // while
1487                case XC_JMPZNZ: // for
1488                case XC_JMPZ_EX: // and
1489                case XC_JMPNZ_EX: // or
1490                case XC_JMPZ: // {{{
1491                    if ($opc == XC_JMP_NO_CTOR && $EX['object']) {
1492                        $rvalue = $EX['object'];
1493                    }
1494                    else {
1495                        $rvalue = $this->getOpVal($op1, $EX);
1496                    }
1497
1498                    if (isset($op['cond_true'])) {
1499                        // any true comes here, so it's a "or"
1500                        $rvalue = implode(' or ', $op['cond_true']) . ' or ' . $rvalue;
1501                        unset($op['cond_true']);
1502                    }
1503                    if (isset($op['cond_false'])) {
1504                        echo "TODO(cond_false):\n";
1505                        var_dump($op);// exit;
1506                    }
1507                    if ($opc == XC_JMPZ_EX || $opc == XC_JMPNZ_EX || $opc == XC_JMPZ) {
1508                        $targetop = &$EX['opcodes'][$op2['opline_num']];
1509                        if ($opc == XC_JMPNZ_EX) {
1510                            $targetop['cond_true'][] = foldToCode($rvalue, $EX);
1511                        }
1512                        else {
1513                            $targetop['cond_false'][] = foldToCode($rvalue, $EX);
1514                        }
1515                        unset($targetop);
1516                    }
1517                    else {
1518                        $op['cond'] = $rvalue; 
1519                        $op['isjmp'] = true;
1520                    }
1521                    break;
1522                    // }}}
1523                case XC_GOTO:
1524                case XC_JMP: // {{{
1525                    $op['cond'] = null;
1526                    $op['isjmp'] = true;
1527                    break;
1528                    // }}}
1529                case XC_CASE:
1530                    $switchValue = $this->getOpVal($op1, $EX);
1531                    $caseValue = $this->getOpVal($op2, $EX);
1532                    $resvar = str($switchValue) . ' == ' . str($caseValue);
1533                    break;
1534                case XC_BRK:
1535                    break;
1536                case XC_RECV_INIT:
1537                case XC_RECV:
1538                    $offset = $this->getOpVal($op1, $EX);
1539                    $lvalue = $this->getOpVal($op['result'], $EX);
1540                    if ($opc == XC_RECV_INIT) {
1541                        $default = value($op['op2']['constant']);
1542                    }
1543                    else {
1544                        $default = null;
1545                    }
1546                    $EX['recvs'][str($offset)] = array($lvalue, $default);
1547                    break;
1548                case XC_POST_DEC:
1549                case XC_POST_INC:
1550                case XC_POST_DEC_OBJ:
1551                case XC_POST_INC_OBJ:
1552                case XC_PRE_DEC:
1553                case XC_PRE_INC:
1554                case XC_PRE_DEC_OBJ:
1555                case XC_PRE_INC_OBJ: // {{{
1556                    $flags = array_flip(explode('_', $opname));
1557                    if (isset($flags['OBJ'])) {
1558                        $resvar = $this->getOpVal($op1, $EX) . '->' . unquoteProperty($this->getOpVal($op2, $EX), $EX);
1559                    }
1560                    else {
1561                        $resvar = $this->getOpVal($op1, $EX);
1562                    }
1563                    $opstr = isset($flags['DEC']) ? '--' : '++';
1564                    if (isset($flags['POST'])) {
1565                        $resvar .= $opstr;
1566                    }
1567                    else {
1568                        $resvar = "$opstr$resvar";
1569                    }
1570                    break;
1571                    // }}}
1572
1573                case XC_BEGIN_SILENCE: // {{{
1574                    $EX['silence'] ++;
1575                    break;
1576                    // }}}
1577                case XC_END_SILENCE: // {{{
1578                    $EX['silence'] --;
1579                    $lastresvar = '@' . str($lastresvar, $EX);
1580                    break;
1581                    // }}}
1582                case XC_CONT: // {{{
1583                    break;
1584                    // }}}
1585                case XC_CAST: // {{{
1586                    $type = $ext;
1587                    static $type2cast = array(
1588                            IS_LONG   => '(int)',
1589                            IS_DOUBLE => '(double)',
1590                            IS_STRING => '(string)',
1591                            IS_ARRAY  => '(array)',
1592                            IS_OBJECT => '(object)',
1593                            IS_BOOL   => '(bool)',
1594                            IS_NULL   => '(unset)',
1595                            );
1596                    assert(isset($type2cast[$type]));
1597                    $cast = $type2cast[$type];
1598                    $resvar = $cast . ' ' . $this->getOpVal($op1, $EX);
1599                    break;
1600                    // }}}
1601                case XC_EXT_STMT:
1602                case XC_EXT_FCALL_BEGIN:
1603                case XC_EXT_FCALL_END:
1604                case XC_EXT_NOP:
1605                    break;
1606                case XC_DECLARE_FUNCTION:
1607                    $this->dfunction($this->dc['function_table'][$op1['constant']], $EX['indent']);
1608                    break;
1609                case XC_DECLARE_LAMBDA_FUNCTION: // {{{
1610                    ob_start();
1611                    $this->dfunction($this->dc['function_table'][$op1['constant']], $EX['indent']);
1612                    $resvar = ob_get_clean();
1613                    $istmpres = true;
1614                    break;
1615                    // }}}
1616                case XC_DECLARE_CONST:
1617                    $name = $this->stripNamespace(unquoteName($this->getOpVal($op1, $EX), $EX));
1618                    $value = str($this->getOpVal($op2, $EX));
1619                    $resvar = 'const ' . $name . ' = ' . $value;
1620                    break;
1621                case XC_DECLARE_FUNCTION_OR_CLASS:
1622                    /* always removed by compiler */
1623                    break;
1624                case XC_TICKS:
1625                    $lastphpop['ticks'] = $this->getOpVal($op1, $EX);
1626                    // $EX['tickschanged'] = true;
1627                    break;
1628                case XC_RAISE_ABSTRACT_ERROR:
1629                    // abstract function body is empty, don't need this code
1630                    break;
1631                case XC_USER_OPCODE:
1632                    echo '// ZEND_USER_OPCODE, impossible to decompile';
1633                    break;
1634                case XC_OP_DATA:
1635                    break;
1636                default: // {{{
1637                    echo "\x1B[31m * TODO ", $opname, "\x1B[0m\n";
1638                    // }}}
1639                }
1640            }
1641            if (isset($resvar)) {
1642                if ($istmpres) {
1643                    $T[$res['var']] = $resvar;
1644                    $lastresvar = &$T[$res['var']];
1645                }
1646                else {
1647                    $op['php'] = $resvar;
1648                    $lastphpop = &$op;
1649                    $lastresvar = &$op['php'];
1650                }
1651            }
1652        }
1653        return $T;
1654    }
1655    // }}}
1656    function unquote($str, $st, $ed) // {{{
1657    {
1658        $l1 = strlen($st);
1659        $l2 = strlen($ed);
1660        if (substr($str, 0, $l1) === $st && substr($str, -$l2) === $ed) {
1661            $str = substr($str, $l1, -$l2);
1662        }
1663        return $str;
1664    }
1665    // }}}
1666    function popargs(&$EX, $n) // {{{
1667    {
1668        $args = array();
1669        for ($i = 0; $i < $n; $i ++) {
1670            $a = array_pop($EX['argstack']);
1671            if (is_array($a)) {
1672                array_unshift($args, foldToCode($a, $EX));
1673            }
1674            else {
1675                array_unshift($args, $a);
1676            }
1677        }
1678        return implode(', ', $args);
1679    }
1680    // }}}
1681    function dumpop($op, &$EX) // {{{
1682    {
1683        $op1 = $op['op1'];
1684        $op2 = $op['op2'];
1685        $d = array('opname' => xcache_get_opcode($op['opcode']), 'opcode' => $op['opcode']);
1686
1687        foreach (array('op1' => 'op1', 'op2' => 'op2', 'result' => 'res') as $k => $kk) {
1688            switch ($op[$k]['op_type']) {
1689            case XC_IS_UNUSED:
1690                $d[$kk] = '*UNUSED* ' . $op[$k]['opline_num'];
1691                break;
1692
1693            case XC_IS_VAR:
1694                $d[$kk] = '$' . $op[$k]['var'];
1695                if ($kk != 'res') {
1696                    $d[$kk] .= ':' . str($this->getOpVal($op[$k], $EX));
1697                }
1698                break;
1699
1700            case XC_IS_TMP_VAR:
1701                $d[$kk] = '#' . $op[$k]['var'];
1702                if ($kk != 'res') {
1703                    $d[$kk] .= ':' . str($this->getOpVal($op[$k], $EX));
1704                }
1705                break;
1706
1707            case XC_IS_CV:
1708                $d[$kk] = $this->getOpVal($op[$k], $EX);
1709                break;
1710
1711            default:
1712                if ($kk == 'res') {
1713                    var_dump($op);
1714                    exit;
1715                    assert(0);
1716                }
1717                else {
1718                    $d[$kk] = $this->getOpVal($op[$k], $EX);
1719                }
1720            }
1721        }
1722        $d['ext'] = $op['extended_value'];
1723
1724        var_dump($d);
1725    }
1726    // }}}
1727    function dargs(&$EX, $indent) // {{{
1728    {
1729        $op_array = &$EX['op_array'];
1730
1731        if (isset($op_array['num_args'])) {
1732            $c = $op_array['num_args'];
1733        }
1734        else if ($op_array['arg_types']) {
1735            $c = count($op_array['arg_types']);
1736        }
1737        else {
1738            // php4
1739            $c = count($EX['recvs']);
1740        }
1741
1742        $refrest = false;
1743        for ($i = 0; $i < $c; $i ++) {
1744            if ($i) {
1745                echo ', ';
1746            }
1747            $arg = $EX['recvs'][$i + 1];
1748            if (isset($op_array['arg_info'])) {
1749                $ai = $op_array['arg_info'][$i];
1750                if (!empty($ai['class_name'])) {
1751                    echo $this->stripNamespace($ai['class_name']), ' ';
1752                    if (!ZEND_ENGINE_2_2 && $ai['allow_null']) {
1753                        echo 'or NULL ';
1754                    }
1755                }
1756                else if (!empty($ai['array_type_hint'])) {
1757                    echo 'array ';
1758                    if (!ZEND_ENGINE_2_2 && $ai['allow_null']) {
1759                        echo 'or NULL ';
1760                    }
1761                }
1762                if ($ai['pass_by_reference']) {
1763                    echo '&';
1764                }
1765                printf("\$%s", $ai['name']);
1766            }
1767            else {
1768                if ($refrest) {
1769                    echo '&';
1770                }
1771                else if (isset($op_array['arg_types'][$i])) {
1772                    switch ($op_array['arg_types'][$i]) {
1773                    case BYREF_FORCE_REST:
1774                        $refrest = true;
1775                        /* fall */
1776                    case BYREF_FORCE:
1777                        echo '&';
1778                        break;
1779
1780                    case BYREF_NONE:
1781                    case BYREF_ALLOW:
1782                        break;
1783                    default:
1784                        assert(0);
1785                    }
1786                }
1787                echo str($arg[0], $indent);
1788            }
1789            if (isset($arg[1])) {
1790                echo ' = ', str($arg[1], $indent);
1791            }
1792        }
1793    }
1794    // }}}
1795    function dfunction($func, $indent = '', $nobody = false) // {{{
1796    {
1797        $this->detectNamespace($func['op_array']['function_name']);
1798
1799        if ($nobody) {
1800            $EX = array();
1801            $EX['op_array'] = &$func['op_array'];
1802            $EX['recvs'] = array();
1803        }
1804        else {
1805            ob_start();
1806            $newindent = INDENT . $indent;
1807            $EX = &$this->dop_array($func['op_array'], $newindent);
1808            $body = ob_get_clean();
1809            if (!isset($EX['recvs'])) {
1810                $EX['recvs'] = array();
1811            }
1812        }
1813
1814        $functionName = $this->stripNamespace($func['op_array']['function_name']);
1815        if ($functionName == '{closure}') {
1816            $functionName = '';
1817        }
1818        echo 'function ', $functionName, '(';
1819        $this->dargs($EX, $indent);
1820        echo ")";
1821        if ($nobody) {
1822            echo ";\n";
1823        }
1824        else {
1825            if ($functionName !== '') {
1826                echo "\n";
1827                echo $indent, "{\n";
1828            }
1829            else {
1830                echo " {\n";
1831            }
1832
1833            echo $body;
1834            echo "$indent}";
1835            if ($functionName !== '') {
1836                echo "\n";
1837            }
1838        }
1839    }
1840    // }}}
1841    function dclass($class, $indent = '') // {{{
1842    {
1843        $this->detectNamespace($class['name']);
1844
1845        // {{{ class decl
1846        if (!empty($class['doc_comment'])) {
1847            echo $indent;
1848            echo $class['doc_comment'];
1849            echo "\n";
1850        }
1851        $isinterface = false;
1852        if (!empty($class['ce_flags'])) {
1853            if ($class['ce_flags'] & ZEND_ACC_INTERFACE) {
1854                $isinterface = true;
1855            }
1856            else {
1857                if ($class['ce_flags'] & ZEND_ACC_IMPLICIT_ABSTRACT_CLASS) {
1858                    echo "abstract ";
1859                }
1860                if ($class['ce_flags'] & ZEND_ACC_FINAL_CLASS) {
1861                    echo "final ";
1862                }
1863            }
1864        }
1865        echo $isinterface ? 'interface ' : 'class ', $this->stripNamespace($class['name']);
1866        if ($class['parent']) {
1867            echo ' extends ', $class['parent'];
1868        }
1869        /* TODO */
1870        if (!empty($class['interfaces'])) {
1871            echo ' implements ';
1872            echo implode(', ', $class['interfaces']);
1873        }
1874        echo "\n";
1875        echo $indent, "{";
1876        // }}}
1877        $newindent = INDENT . $indent;
1878        // {{{ const, static
1879        foreach (array('constants_table' => 'const '
1880                    , 'static_members' => 'static $') as $type => $prefix) {
1881            if (!empty($class[$type])) {
1882                echo "\n";
1883                // TODO: skip shadow?
1884                foreach ($class[$type] as $name => $v) {
1885                    echo $newindent;
1886                    echo $prefix, $name, ' = ';
1887                    echo str(value($v), $newindent);
1888                    echo ";\n";
1889                }
1890            }
1891        }
1892        // }}}
1893        // {{{ properties
1894        $member_variables = isset($class['properties_info']) ? $class['properties_info'] : ($class['default_static_members'] + $class['default_properties']);
1895        if ($member_variables) {
1896            echo "\n";
1897            $infos = !empty($class['properties_info']) ? $class['properties_info'] : null;
1898            foreach ($member_variables as $name => $dummy) {
1899                $info = (isset($infos) && isset($infos[$name])) ? $infos[$name] : null;
1900                if (isset($info)) {
1901                    if (!empty($info['doc_comment'])) {
1902                        echo $newindent;
1903                        echo $info['doc_comment'];
1904                        echo "\n";
1905                    }
1906                }
1907
1908                echo $newindent;
1909                $static = false;
1910                if (isset($info)) {
1911                    if ($info['flags'] & ZEND_ACC_STATIC) {
1912                        $static = true;
1913                    }
1914                }
1915                else if (isset($class['default_static_members'][$name])) {
1916                    $static = true;
1917                }
1918
1919                if ($static) {
1920                    echo "static ";
1921                }
1922
1923                $mangled = false;
1924                if (!ZEND_ENGINE_2) {
1925                    echo 'var ';
1926                }
1927                else if (!isset($info)) {
1928                    echo 'public ';
1929                }
1930                else {
1931                    if ($info['flags'] & ZEND_ACC_SHADOW) {
1932                        continue;
1933                    }
1934                    switch ($info['flags'] & ZEND_ACC_PPP_MASK) {
1935                    case ZEND_ACC_PUBLIC:
1936                        echo "public ";
1937                        break;
1938                    case ZEND_ACC_PRIVATE:
1939                        echo "private ";
1940                        $mangled = true;
1941                        break;
1942                    case ZEND_ACC_PROTECTED:
1943                        echo "protected ";
1944                        $mangled = true;
1945                        break;
1946                    }
1947                }
1948
1949                echo '$', $name;
1950
1951                if (isset($info['offset'])) {
1952                    $value = $class[$static ? 'default_static_members_table' : 'default_properties_table'][$info['offset']];
1953                }
1954                else {
1955                    $key = isset($info) ? $info['name'] . ($mangled ? "\000" : "") : $name;
1956
1957                    $value = $class[$static ? 'default_static_members' : 'default_properties'][$key];
1958                }
1959                if (isset($value)) {
1960                    echo ' = ';
1961                    echo str(value($value), $newindent);
1962                }
1963                echo ";\n";
1964            }
1965        }
1966        // }}}
1967        // {{{ function_table
1968        if (isset($class['function_table'])) {
1969            foreach ($class['function_table'] as $func) {
1970                if (!isset($func['scope']) || $func['scope'] == $class['name']) {
1971                    // TODO: skip shadow here
1972                    echo "\n";
1973                    $opa = $func['op_array'];
1974                    if (!empty($opa['doc_comment'])) {
1975                        echo $newindent;
1976                        echo $opa['doc_comment'];
1977                        echo "\n";
1978                    }
1979                    echo $newindent;
1980                    $isAbstractMethod = false;
1981                    if (isset($opa['fn_flags'])) {
1982                        if (($opa['fn_flags'] & ZEND_ACC_ABSTRACT) && !$isinterface) {
1983                            echo "abstract ";
1984                            $isAbstractMethod = true;
1985                        }
1986                        if ($opa['fn_flags'] & ZEND_ACC_FINAL) {
1987                            echo "final ";
1988                        }
1989                        if ($opa['fn_flags'] & ZEND_ACC_STATIC) {
1990                            echo "static ";
1991                        }
1992
1993                        switch ($opa['fn_flags'] & ZEND_ACC_PPP_MASK) {
1994                            case ZEND_ACC_PUBLIC:
1995                                echo "public ";
1996                                break;
1997                            case ZEND_ACC_PRIVATE:
1998                                echo "private ";
1999                                break;
2000                            case ZEND_ACC_PROTECTED:
2001                                echo "protected ";
2002                                break;
2003                            default:
2004                                echo "<visibility error> ";
2005                                break;
2006                        }
2007                    }
2008                    $this->dfunction($func, $newindent, $isinterface || $isAbstractMethod);
2009                    if ($opa['function_name'] == 'Decompiler') {
2010                        //exit;
2011                    }
2012                }
2013            }
2014        }
2015        // }}}
2016        echo $indent, "}\n";
2017    }
2018    // }}}
2019    function decompileString($string) // {{{
2020    {
2021        $this->dc = xcache_dasm_string($string);
2022        if ($this->dc === false) {
2023            echo "error compling string\n";
2024            return false;
2025        }
2026    }
2027    // }}}
2028    function decompileFile($file) // {{{
2029    {
2030        $this->dc = xcache_dasm_file($file);
2031        if ($this->dc === false) {
2032            echo "error compling $file\n";
2033            return false;
2034        }
2035    }
2036    // }}}
2037    function output() // {{{
2038    {
2039        echo "<?". "php\n\n";
2040        foreach ($this->dc['class_table'] as $key => $class) {
2041            if ($key{0} != "\0") {
2042                $this->dclass($class);
2043                echo "\n";
2044            }
2045        }
2046
2047        foreach ($this->dc['function_table'] as $key => $func) {
2048            if ($key{0} != "\0") {
2049                $this->dfunction($func);
2050                echo "\n";
2051            }
2052        }
2053
2054        $this->dop_array($this->dc['op_array']);
2055        echo "\n?" . ">\n";
2056        return true;
2057    }
2058    // }}}
2059}
2060
2061// {{{ defines
2062define('ZEND_ENGINE_2_4', PHP_VERSION >= "5.3.99");
2063define('ZEND_ENGINE_2_3', ZEND_ENGINE_2_4 || PHP_VERSION >= "5.3.");
2064define('ZEND_ENGINE_2_2', ZEND_ENGINE_2_3 || PHP_VERSION >= "5.2.");
2065define('ZEND_ENGINE_2_1', ZEND_ENGINE_2_2 || PHP_VERSION >= "5.1.");
2066define('ZEND_ENGINE_2',   ZEND_ENGINE_2_1 || PHP_VERSION >= "5.0.");
2067
2068define('ZEND_ACC_STATIC',         0x01);
2069define('ZEND_ACC_ABSTRACT',       0x02);
2070define('ZEND_ACC_FINAL',          0x04);
2071define('ZEND_ACC_IMPLEMENTED_ABSTRACT',       0x08);
2072
2073define('ZEND_ACC_IMPLICIT_ABSTRACT_CLASS',    0x10);
2074define('ZEND_ACC_EXPLICIT_ABSTRACT_CLASS',    0x20);
2075define('ZEND_ACC_FINAL_CLASS',                0x40);
2076define('ZEND_ACC_INTERFACE',                  0x80);
2077if (ZEND_ENGINE_2_4) {
2078    define('ZEND_ACC_TRAIT',                  0x120);
2079}
2080define('ZEND_ACC_PUBLIC',     0x100);
2081define('ZEND_ACC_PROTECTED',  0x200);
2082define('ZEND_ACC_PRIVATE',    0x400);
2083define('ZEND_ACC_PPP_MASK',  (ZEND_ACC_PUBLIC | ZEND_ACC_PROTECTED | ZEND_ACC_PRIVATE));
2084
2085define('ZEND_ACC_CHANGED',    0x800);
2086define('ZEND_ACC_IMPLICIT_PUBLIC',    0x1000);
2087
2088define('ZEND_ACC_CTOR',       0x2000);
2089define('ZEND_ACC_DTOR',       0x4000);
2090define('ZEND_ACC_CLONE',      0x8000);
2091
2092define('ZEND_ACC_ALLOW_STATIC',   0x10000);
2093
2094define('ZEND_ACC_SHADOW', 0x2000);
2095
2096if (ZEND_ENGINE_2_4) {
2097    define('ZEND_FETCH_GLOBAL',           0x00000000);
2098    define('ZEND_FETCH_LOCAL',            0x10000000);
2099    define('ZEND_FETCH_STATIC',           0x20000000);
2100    define('ZEND_FETCH_STATIC_MEMBER',    0x30000000);
2101    define('ZEND_FETCH_GLOBAL_LOCK',      0x40000000);
2102    define('ZEND_FETCH_LEXICAL',          0x50000000);
2103
2104    define('ZEND_FETCH_TYPE_MASK',        0x70000000);
2105}
2106else {
2107    define('ZEND_FETCH_GLOBAL',           0);
2108    define('ZEND_FETCH_LOCAL',            1);
2109    define('ZEND_FETCH_STATIC',           2);
2110    define('ZEND_FETCH_STATIC_MEMBER',    3);
2111    define('ZEND_FETCH_GLOBAL_LOCK',      4);
2112}
2113
2114define('ZEND_FETCH_CLASS_DEFAULT',    0);
2115define('ZEND_FETCH_CLASS_SELF',       1);
2116define('ZEND_FETCH_CLASS_PARENT',     2);
2117define('ZEND_FETCH_CLASS_MAIN',       3);
2118define('ZEND_FETCH_CLASS_GLOBAL',     4);
2119define('ZEND_FETCH_CLASS_AUTO',       5);
2120define('ZEND_FETCH_CLASS_INTERFACE',  6);
2121define('ZEND_FETCH_CLASS_STATIC',     7);
2122if (ZEND_ENGINE_2_4) {
2123    define('ZEND_FETCH_CLASS_TRAIT',     14);
2124}
2125if (ZEND_ENGINE_2_3) {
2126    define('ZEND_FETCH_CLASS_MASK',     0xF);
2127}
2128
2129define('ZEND_EVAL',               (1<<0));
2130define('ZEND_INCLUDE',            (1<<1));
2131define('ZEND_INCLUDE_ONCE',       (1<<2));
2132define('ZEND_REQUIRE',            (1<<3));
2133define('ZEND_REQUIRE_ONCE',       (1<<4));
2134
2135define('ZEND_ISSET',              (1<<0));
2136define('ZEND_ISEMPTY',            (1<<1));
2137if (ZEND_ENGINE_2_4) {
2138    define('EXT_TYPE_UNUSED',     (1<<5));
2139}
2140else {
2141    define('EXT_TYPE_UNUSED',     (1<<0));
2142}
2143
2144define('ZEND_FETCH_STANDARD',     0);
2145define('ZEND_FETCH_ADD_LOCK',     1);
2146
2147define('ZEND_FE_FETCH_BYREF',     1);
2148define('ZEND_FE_FETCH_WITH_KEY',  2);
2149
2150define('ZEND_MEMBER_FUNC_CALL',   1<<0);
2151define('ZEND_CTOR_CALL',          1<<1);
2152
2153define('ZEND_ARG_SEND_BY_REF',        (1<<0));
2154define('ZEND_ARG_COMPILE_TIME_BOUND', (1<<1));
2155define('ZEND_ARG_SEND_FUNCTION',      (1<<2));
2156
2157define('BYREF_NONE',       0);
2158define('BYREF_FORCE',      1);
2159define('BYREF_ALLOW',      2);
2160define('BYREF_FORCE_REST', 3);
2161define('IS_NULL',     0);
2162define('IS_LONG',     1);
2163define('IS_DOUBLE',   2);
2164define('IS_STRING',   3);
2165define('IS_ARRAY',    4);
2166define('IS_OBJECT',   5);
2167define('IS_BOOL',     6);
2168define('IS_RESOURCE', 7);
2169define('IS_CONSTANT', 8);
2170define('IS_CONSTANT_ARRAY',   9);
2171
2172@define('XC_IS_CV', 16);
2173
2174/*
2175if (preg_match_all('!XC_[A-Z_]+!', file_get_contents(__FILE__), $ms)) {
2176    $verdiff = array();
2177    foreach ($ms[0] as $k) {
2178        if (!defined($k)) {
2179            $verdiff[$k] = -1;
2180            define($k, -1);
2181        }
2182    }
2183    var_export($verdiff);
2184}
2185/*/
2186foreach (array (
2187    'XC_HANDLE_EXCEPTION' => -1,
2188    'XC_FETCH_CLASS' => -1,
2189    'XC_FETCH_' => -1,
2190    'XC_FETCH_DIM_' => -1,
2191    'XC_ASSIGN_DIM' => -1,
2192    'XC_UNSET_DIM' => -1,
2193    'XC_UNSET_OBJ' => -1,
2194    'XC_ASSIGN_OBJ' => -1,
2195    'XC_ISSET_ISEMPTY_DIM_OBJ' => -1,
2196    'XC_ISSET_ISEMPTY_PROP_OBJ' => -1,
2197    'XC_ISSET_ISEMPTY_VAR' => -1,
2198    'XC_INIT_STATIC_METHOD_CALL' => -1,
2199    'XC_INIT_METHOD_CALL' => -1,
2200    'XC_VERIFY_ABSTRACT_CLASS' => -1,
2201    'XC_DECLARE_CLASS' => -1,
2202    'XC_DECLARE_INHERITED_CLASS' => -1,
2203    'XC_DECLARE_INHERITED_CLASS_DELAYED' => -1,
2204    'XC_ADD_INTERFACE' => -1,
2205    'XC_POST_DEC_OBJ' => -1,
2206    'XC_POST_INC_OBJ' => -1,
2207    'XC_PRE_DEC_OBJ' => -1,
2208    'XC_PRE_INC_OBJ' => -1,
2209    'XC_UNSET_OBJ' => -1,
2210    'XC_JMP_NO_CTOR' => -1,
2211    'XC_FETCH_' => -1,
2212    'XC_FETCH_DIM_' => -1,
2213    'XC_UNSET_DIM_OBJ' => -1,
2214    'XC_ISSET_ISEMPTY' => -1,
2215    'XC_INIT_FCALL_BY_FUNC' => -1,
2216    'XC_DO_FCALL_BY_FUNC' => -1,
2217    'XC_DECLARE_FUNCTION_OR_CLASS' => -1,
2218    'XC_INIT_NS_FCALL_BY_NAME' => -1,
2219    'XC_GOTO' => -1,
2220    'XC_CATCH' => -1,
2221    'XC_THROW' => -1,
2222    'XC_INSTANCEOF' => -1,
2223    'XC_DECLARE_FUNCTION' => -1,
2224    'XC_RAISE_ABSTRACT_ERROR' => -1,
2225    'XC_DECLARE_CONST' => -1,
2226    'XC_USER_OPCODE' => -1,
2227    'XC_JMP_SET' => -1,
2228    'XC_DECLARE_LAMBDA_FUNCTION' => -1,
2229) as $k => $v) {
2230    if (!defined($k)) {
2231        define($k, $v);
2232    }
2233}
2234
2235//* XC_UNDEF XC_OP_DATA
2236$content = file_get_contents(__FILE__);
2237for ($i = 0; $opname = xcache_get_opcode($i); $i ++) {
2238    if (!preg_match("/\\bXC_" . $opname . "\\b(?!')/", $content)) {
2239        echo "not done ", $opname, "\n";
2240    }
2241}
2242// */
2243// }}}
2244
Note: See TracBrowser for help on using the repository browser.