Changeset 817 in svn for branches/1.3


Ignore:
Timestamp:
2011-06-04T03:34:36Z (4 years ago)
Author:
Xuefer
Message:

merge from trunk: disassembler/decompiler improvements

Location:
branches/1.3
Files:
6 edited

Legend:

Unmodified
Added
Removed
  • branches/1.3

  • branches/1.3/ChangeLog

    r814 r817  
    44 * adds 30 seconds timeout to "compiling" flag
    55 * decompiler: improves decompiling
     6 * disassembler: improper handling of null field
    67 * disassembler: DECLARE_INHERITED_CLASS/DELAYED class not found
    78 * disassembler: don't dump builtin functions
  • branches/1.3/Decompiler.class.php

    r784 r817  
    150150    var $op2;
    151151    var $parent;
    152     var $indent;
    153152
    154153    function Decompiler_Binop($parent, $op1, $opc, $op2)
     
    164163        $opstr = $this->parent->binops[$this->opc];
    165164
    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) . ")";
     165        if (is_a($this->op1, 'Decompiler_TriOp') || is_a($this->op1, 'Decompiler_Binop') && $this->op1->opc != $this->opc) {
     166            $op1 = "(" . str($this->op1, $indent) . ")";
     167        }
     168        else {
     169            $op1 = $this->op1;
     170        }
     171
     172        if (is_a($this->op2, 'Decompiler_TriOp') || is_a($this->op2, 'Decompiler_Binop') && $this->op2->opc != $this->opc && substr($opstr, -1) != '=') {
     173            $op2 = "(" . str($this->op2, $indent) . ")";
     174        }
     175        else {
     176            $op2 = $this->op2;
    173177        }
    174178
     
    177181        }
    178182
    179         return str($op1) . ' ' . $opstr . ' ' . str($op2);
     183        return str($op1, $indent) . ' ' . $opstr . ($this->opc == XC_ASSIGN_REF ? '' : ' ') . str($op2, $indent);
     184    }
     185}
     186// }}}
     187class Decompiler_TriOp extends Decompiler_Code // {{{
     188{
     189    var $condition;
     190    var $trueValue;
     191    var $falseValue;
     192
     193    function Decompiler_TriOp($condition, $trueValue, $falseValue)
     194    {
     195        $this->condition = $condition;
     196        $this->trueValue = $trueValue;
     197        $this->falseValue = $falseValue;
     198    }
     199
     200    function toCode($indent)
     201    {
     202        $trueValue = $this->trueValue;
     203        if (is_a($this->trueValue, 'Decompiler_TriOp')) {
     204            $trueValue = "(" . str($trueValue, $indent) . ")";
     205        }
     206        $falseValue = $this->falseValue;
     207        if (is_a($this->falseValue, 'Decompiler_TriOp')) {
     208            $falseValue = "(" . str($falseValue, $indent) . ")";
     209        }
     210
     211        return str($this->condition) . ' ? ' . str($trueValue) . ' : ' . str($falseValue);
    180212    }
    181213}
     
    486518                XC_ASSIGN_BW_XOR       => "^=",
    487519                XC_BOOL_XOR            => "xor",
     520                XC_ASSIGN              => "=",
     521                XC_ASSIGN_REF          => "= &",
     522                XC_JMP_SET             => "?:",
     523                XC_JMPZ_EX             => "&&",
     524                XC_JMPNZ_EX            => "||",
    488525                );
    489526        // }}}
     
    522559    }
    523560    // }}}
    524     function outputPhp(&$opcodes, $opline, $last, $indent) // {{{
    525     {
    526         $origindent = $indent;
     561    function outputPhp(&$EX, $range) // {{{
     562    {
     563        $needBlankline = isset($EX['lastBlock']);
     564        $indent = $EX['indent'];
    527565        $curticks = 0;
    528         for ($i = $opline; $i <= $last; $i ++) {
    529             $op = $opcodes[$i];
     566        for ($i = $range[0]; $i <= $range[1]; $i ++) {
     567            $op = $EX['opcodes'][$i];
     568            if (isset($op['gofrom'])) {
     569                if ($needBlankline) {
     570                    $needBlankline = false;
     571                    echo PHP_EOL;
     572                }
     573                echo 'label' . $i, ":\n";
     574            }
    530575            if (isset($op['php'])) {
    531576                $toticks = isset($op['ticks']) ? (int) str($op['ticks']) : 0;
     
    534579                    $curticks = $toticks;
    535580                    if (!$curticks) {
    536                         echo $origindent, "}\n\n";
    537                         $indent = $origindent;
     581                        echo $EX['indent'], "}\n\n";
     582                        $indent = $EX['indent'];
    538583                    }
    539584                    else {
    540585                        if ($oldticks) {
    541                             echo $origindent, "}\n\n";
     586                            echo $EX['indent'], "}\n\n";
    542587                        }
    543588                        else if (!$oldticks) {
    544589                            $indent .= INDENT;
    545590                        }
    546                         echo $origindent, "declare (ticks=$curticks) {\n";
    547                     }
     591                        if ($needBlankline) {
     592                            $needBlankline = false;
     593                            echo PHP_EOL;
     594                        }
     595                        echo $EX['indent'], "declare (ticks=$curticks) {\n";
     596                    }
     597                }
     598                if ($needBlankline) {
     599                    $needBlankline = false;
     600                    echo PHP_EOL;
    548601                }
    549602                echo $indent, str($op['php'], $indent), ";\n";
     603                $EX['lastBlock'] = 'basic';
    550604            }
    551605        }
    552606        if ($curticks) {
    553             echo $origindent, "}\n";
    554         }
    555     }
    556     // }}}
    557     function getOpVal($op, &$EX, $tostr = true, $free = false) // {{{
     607            echo $EX['indent'], "}\n";
     608        }
     609    }
     610    // }}}
     611    function getOpVal($op, &$EX, $free = false) // {{{
    558612    {
    559613        switch ($op['op_type']) {
    560614        case XC_IS_CONST:
    561             return foldToCode(value($op['constant']), $EX);
     615            return value($op['constant']);
    562616
    563617        case XC_IS_VAR:
     
    565619            $T = &$EX['Ts'];
    566620            $ret = $T[$op['var']];
    567             if ($tostr) {
    568                 $ret = foldToCode($ret, $EX);
    569             }
    570             if ($free) {
     621            if ($free && empty($this->keepTs)) {
    571622                unset($T[$op['var']]);
    572623            }
     
    598649    function &fixOpcode($opcodes, $removeTailing = false, $defaultReturnValue = null) // {{{
    599650    {
    600         for ($i = 0, $cnt = count($opcodes); $i < $cnt; $i ++) {
     651        $last = count($opcodes) - 1;
     652        for ($i = 0; $i <= $last; $i ++) {
    601653            if (function_exists('xcache_get_fixed_opcode')) {
    602654                $opcodes[$i]['opcode'] = xcache_get_fixed_opcode($opcodes[$i]['opcode'], $i);
     
    648700    }
    649701    // }}}
     702    function decompileBasicBlock(&$EX, $range, $unhandled = false) // {{{
     703    {
     704        $this->dasmBasicBlock($EX, $range);
     705        if ($unhandled) {
     706            $this->dumpRange($EX, $range);
     707        }
     708        $this->outputPhp($EX, $range);
     709    }
     710    // }}}
     711    function isIfCondition(&$EX, $range) // {{{
     712    {
     713        $opcodes = &$EX['opcodes'];
     714        $firstOp = &$opcodes[$range[0]];
     715        return $firstOp['opcode'] == XC_JMPZ && !empty($firstOp['jmpouts']) && $opcodes[$firstOp['jmpouts'][0] - 1]['opcode'] == XC_JMP
     716         && !empty($opcodes[$firstOp['jmpouts'][0] - 1]['jmpouts'])
     717         && $opcodes[$firstOp['jmpouts'][0] - 1]['jmpouts'][0] == $range[1] + 1;
     718    }
     719    // }}}
     720    function removeJmpInfo(&$EX, $line) // {{{
     721    {
     722        $opcodes = &$EX['opcodes'];
     723        foreach ($opcodes[$line]['jmpouts'] as $jmpTo) {
     724            $jmpins = &$opcodes[$jmpTo]['jmpins'];
     725            $jmpins = array_flip($jmpins);
     726            unset($jmpins[$line]);
     727            $jmpins = array_keys($jmpins);
     728        }
     729        // $opcodes[$line]['opcode'] = XC_NOP;
     730        unset($opcodes[$line]['jmpouts']);
     731    }
     732    // }}}
     733    function beginScope(&$EX, $doIndent = true) // {{{
     734    {
     735        array_push($EX['scopeStack'], array($EX['lastBlock'], $EX['indent']));
     736        if ($doIndent) {
     737            $EX['indent'] .= INDENT;
     738        }
     739        $EX['lastBlock'] = null;
     740    }
     741    // }}}
     742    function endScope(&$EX) // {{{
     743    {
     744        list($EX['lastBlock'], $EX['indent']) = array_pop($EX['scopeStack']);
     745    }
     746    // }}}
     747    function beginComplexBlock(&$EX) // {{{
     748    {
     749        if (isset($EX['lastBlock'])) {
     750            echo PHP_EOL;
     751            $EX['lastBlock'] = null;
     752        }
     753    }
     754    // }}}
     755    function endComplexBlock(&$EX) // {{{
     756    {
     757        $EX['lastBlock'] = 'complex';
     758    }
     759    // }}}
     760    function decompileComplexBlock(&$EX, $range) // {{{
     761    {
     762        $T = &$EX['Ts'];
     763        $opcodes = &$EX['opcodes'];
     764        $indent = $EX['indent'];
     765
     766        $firstOp = &$opcodes[$range[0]];
     767        $lastOp = &$opcodes[$range[1]];
     768
     769        // {{{ && || and or
     770        if (($firstOp['opcode'] == XC_JMPZ_EX || $firstOp['opcode'] == XC_JMPNZ_EX) && !empty($firstOp['jmpouts'])
     771         && $firstOp['jmpouts'][0] == $range[1] + 1
     772         && $lastOp['opcode'] == XC_BOOL
     773         && $firstOp['opcode']['result']['var'] == $lastOp['opcode']['result']['var']
     774        ) {
     775            $this->removeJmpInfo($EX, $range[0]);
     776
     777            $this->recognizeAndDecompileClosedBlocks($EX, array($range[0], $range[0]));
     778            $op1 = $this->getOpVal($firstOp['result'], $EX, true);
     779
     780            $this->recognizeAndDecompileClosedBlocks($EX, array($range[0] + 1, $range[1]));
     781            $op2 = $this->getOpVal($lastOp['result'], $EX, true);
     782
     783            $T[$firstOp['result']['var']] = new Decompiler_Binop($this, $op1, $firstOp['opcode'], $op2);
     784            return false;
     785        }
     786        // }}}
     787        // {{{ ?: excluding JMP_SET
     788        if ($firstOp['opcode'] == XC_JMPZ && !empty($firstOp['jmpouts'])
     789         && $range[1] >= $range[0] + 3
     790         && $opcodes[$firstOp['jmpouts'][0] - 2]['opcode'] == XC_QM_ASSIGN
     791         && $opcodes[$firstOp['jmpouts'][0] - 1]['opcode'] == XC_JMP && $opcodes[$firstOp['jmpouts'][0] - 1]['jmpouts'][0] == $range[1] + 1
     792         && $lastOp['opcode'] == XC_QM_ASSIGN
     793        ) {
     794            $trueRange = array($range[0] + 1, $firstOp['jmpouts'][0] - 2);
     795            $falseRange = array($firstOp['jmpouts'][0], $range[1]);
     796            $this->removeJmpInfo($EX, $range[0]);
     797
     798            $condition = $this->getOpVal($firstOp['op1'], $EX);
     799            $this->recognizeAndDecompileClosedBlocks($EX, $trueRange);
     800            $trueValue = $this->getOpVal($opcodes[$trueRange[1]]['result'], $EX, true);
     801            $this->recognizeAndDecompileClosedBlocks($EX, $falseRange);
     802            $falseValue = $this->getOpVal($opcodes[$falseRange[1]]['result'], $EX, true);
     803            $T[$opcodes[$trueRange[1]]['result']['var']] = new Decompiler_TriOp($condition, $trueValue, $falseValue);
     804            return false;
     805        }
     806        // }}}
     807        // {{{ goto
     808        if ($firstOp['opcode'] == XC_JMP && !empty($firstOp['jmpouts']) && $firstOp['jmpouts'][0] == $range[1] + 1) {
     809            $this->removeJmpInfo($EX, $range[0]);
     810            $firstOp['opcode'] = XC_GOTO;
     811            $target = $firstOp['op1']['var'];
     812            $firstOp['goto'] = $target;
     813            $opcodes[$target]['gofrom'][] = $range[0];
     814
     815            $this->recognizeAndDecompileClosedBlocks($EX, $range);
     816            return false;
     817        }
     818        // }}}
     819        // {{{ for
     820        if (!empty($firstOp['jmpins']) && $opcodes[$firstOp['jmpins'][0]]['opcode'] == XC_JMP
     821         && $lastOp['opcode'] == XC_JMP && !empty($lastOp['jmpouts']) && $lastOp['jmpouts'][0] <= $firstOp['jmpins'][0]
     822         && !empty($opcodes[$range[1] + 1]['jmpins']) && $opcodes[$opcodes[$range[1] + 1]['jmpins'][0]]['opcode'] == XC_JMPZNZ
     823        ) {
     824            $nextRange = array($lastOp['jmpouts'][0], $firstOp['jmpins'][0]);
     825            $conditionRange = array($range[0], $nextRange[0] - 1);
     826            $this->removeJmpInfo($EX, $conditionRange[1]);
     827            $bodyRange = array($nextRange[1], $range[1]);
     828            $this->removeJmpInfo($EX, $bodyRange[1]);
     829
     830            $initial = '';
     831            $this->beginScope($EX);
     832            $this->dasmBasicBlock($EX, $conditionRange);
     833            $conditionCodes = array();
     834            for ($i = $conditionRange[0]; $i <= $conditionRange[1]; ++$i) {
     835                if (isset($opcodes[$i]['php'])) {
     836                    $conditionCodes[] = str($opcodes[$i]['php'], $EX);
     837                }
     838            }
     839            $conditionCodes[] = str($this->getOpVal($opcodes[$conditionRange[1]]['op1'], $EX), $EX);
     840            if (implode(',', $conditionCodes) == 'true') {
     841                $conditionCodes = array();
     842            }
     843            $this->endScope($EX);
     844
     845            $this->beginScope($EX);
     846            $this->dasmBasicBlock($EX, $nextRange);
     847            $nextCodes = array();
     848            for ($i = $nextRange[0]; $i <= $nextRange[1]; ++$i) {
     849                if (isset($opcodes[$i]['php'])) {
     850                    $nextCodes[] = str($opcodes[$i]['php'], $EX);
     851                }
     852            }
     853            $this->endScope($EX);
     854
     855            $this->beginComplexBlock($EX);
     856            echo $indent, 'for (', str($initial, $EX), '; ', implode(', ', $conditionCodes), '; ', implode(', ', $nextCodes), ') ', '{', PHP_EOL;
     857            $this->beginScope($EX);
     858            $this->recognizeAndDecompileClosedBlocks($EX, $bodyRange);
     859            $this->endScope($EX);
     860            echo $indent, '}', PHP_EOL;
     861            $this->endComplexBlock($EX);
     862            return;
     863        }
     864        // }}}
     865        // {{{ if/elseif/else
     866        if ($this->isIfCondition($EX, $range)) {
     867            $this->beginComplexBlock($EX);
     868            $isElseIf = false;
     869            do {
     870                $ifRange = array($range[0], $opcodes[$range[0]]['jmpouts'][0] - 1);
     871                $this->removeJmpInfo($EX, $ifRange[0]);
     872                $this->removeJmpInfo($EX, $ifRange[1]);
     873                $condition = $this->getOpVal($opcodes[$ifRange[0]]['op1'], $EX);
     874
     875                echo $indent, $isElseIf ? 'else if' : 'if', ' (', str($condition, $EX), ') ', '{', PHP_EOL;
     876                $this->beginScope($EX);
     877                $this->recognizeAndDecompileClosedBlocks($EX, $ifRange);
     878                $this->endScope($EX);
     879                $EX['lastBlock'] = null;
     880                echo $indent, '}', PHP_EOL;
     881
     882                $isElseIf = true;
     883                // search for else if
     884                $range[0] = $ifRange[1] + 1;
     885                for ($i = $ifRange[1] + 1; $i <= $range[1]; ++$i) {
     886                    // find first jmpout
     887                    if (!empty($opcodes[$i]['jmpouts'])) {
     888                        if ($this->isIfCondition($EX, array($i, $range[1]))) {
     889                            $this->dasmBasicBlock($EX, array($range[0], $i));
     890                            $range[0] = $i;
     891                        }
     892                        break;
     893                    }
     894                }
     895            } while ($this->isIfCondition($EX, $range));
     896            if ($ifRange[1] < $range[1]) {
     897                $elseRange = array($ifRange[1], $range[1]);
     898                echo $indent, 'else ', '{', PHP_EOL;
     899                $this->beginScope($EX);
     900                $this->recognizeAndDecompileClosedBlocks($EX, $elseRange);
     901                $this->endScope($EX);
     902                $EX['lastBlock'] = null;
     903                echo $indent, '}', PHP_EOL;
     904            }
     905            $this->endComplexBlock($EX);
     906            return;
     907        }
     908        // }}}
     909        // {{{ try/catch
     910        if (!empty($firstOp['jmpins']) && !empty($opcodes[$firstOp['jmpins'][0]]['isCatchBegin'])) {
     911            $catchBlocks = array();
     912            $catchFirst = $firstOp['jmpins'][0];
     913
     914            $tryRange = array($range[0], $catchFirst - 1);
     915
     916            // search for XC_CATCH
     917            $this->removeJmpInfo($EX, $catchFirst);
     918            for ($i = $catchFirst; $i <= $range[1]; ) {
     919                if ($opcodes[$i]['opcode'] == XC_CATCH) {
     920                    $catchOpLine = $i;
     921                    $this->removeJmpInfo($EX, $catchOpLine);
     922
     923                    $catchNext = $opcodes[$catchOpLine]['extended_value'];
     924                    $catchBodyLast = $catchNext - 1;
     925                    if ($opcodes[$catchBodyLast]['opcode'] == XC_JMP) {
     926                        --$catchBodyLast;
     927                    }
     928
     929                    $catchBlocks[$catchFirst] = array($catchOpLine, $catchBodyLast);
     930
     931                    $i = $catchFirst = $catchNext;
     932                }
     933                else {
     934                    ++$i;
     935                }
     936            }
     937
     938            if ($opcodes[$tryRange[1]]['opcode'] == XC_JMP) {
     939                --$tryRange[1];
     940            }
     941
     942            $this->beginComplexBlock($EX);
     943            echo $indent, "try {", PHP_EOL;
     944            $this->beginScope($EX);
     945            $this->recognizeAndDecompileClosedBlocks($EX, $tryRange);
     946            $this->endScope($EX);
     947            echo $indent, '}', PHP_EOL;
     948            foreach ($catchBlocks as $catchFirst => $catchInfo) {
     949                list($catchOpLine, $catchBodyLast) = $catchInfo;
     950                $catchBodyFirst = $catchOpLine + 1;
     951                $this->dasmBasicBlock($EX, array($catchFirst, $catchOpLine));
     952                $catchOp = &$opcodes[$catchOpLine];
     953                echo $indent, 'catch (', str($this->getOpVal($catchOp['op1'], $EX)), ' ', str($this->getOpVal($catchOp['op2'], $EX)), ") {", PHP_EOL;
     954                unset($catchOp);
     955
     956                $EX['lastBlock'] = null;
     957                $this->beginScope($EX);
     958                $this->recognizeAndDecompileClosedBlocks($EX, array($catchBodyFirst, $catchBodyLast));
     959                $this->endScope($EX);
     960                echo $indent, '}', PHP_EOL;
     961            }
     962            $this->endComplexBlock($EX);
     963            return;
     964        }
     965        // }}}
     966        // {{{ switch/case
     967        if ($firstOp['opcode'] == XC_SWITCH_FREE && isset($T[$firstOp['op1']['var']])) {
     968            // TODO: merge this code to CASE code. use SWITCH_FREE to detect begin of switch by using $Ts if possible
     969            $this->beginComplexBlock($EX);
     970            echo $indent, 'switch (', str($this->getOpVal($firstOp['op1'], $EX)), ") {", PHP_EOL;
     971            echo $indent, '}', PHP_EOL;
     972            $this->endComplexBlock($EX);
     973            return;
     974        }
     975
     976        if (
     977            ($firstOp['opcode'] == XC_CASE
     978            || $firstOp['opcode'] == XC_JMP && !empty($firstOp['jmpouts']) && $opcodes[$firstOp['jmpouts'][0]]['opcode'] == XC_CASE
     979            )
     980             && !empty($lastOp['jmpouts'])
     981        ) {
     982            $cases = array();
     983            $caseDefault = null;
     984            $caseOp = null;
     985            for ($i = $range[0]; $i <= $range[1]; ) {
     986                $op = $opcodes[$i];
     987                if ($op['opcode'] == XC_CASE) {
     988                    if (!isset($caseOp)) {
     989                        $caseOp = $op;
     990                    }
     991                    $jmpz = $opcodes[$i + 1];
     992                    assert('$jmpz["opcode"] == XC_JMPZ');
     993                    $caseNext = $jmpz['jmpouts'][0];
     994                    $cases[$i] = $caseNext - 1;
     995                    $i = $caseNext;
     996                }
     997                else if ($op['opcode'] == XC_JMP && $op['jmpouts'][0] >= $i) {
     998                    // default
     999                    $caseNext = $op['jmpouts'][0];
     1000                    $caseDefault = $i;
     1001                    $cases[$i] = $caseNext - 1;
     1002                    $i = $caseNext;
     1003                }
     1004                else {
     1005                    ++$i;
     1006                }
     1007            }
     1008
     1009            $this->beginComplexBlock($EX);
     1010
     1011            echo $indent, 'switch (', str($this->getOpVal($caseOp['op1'], $EX), $EX), ") {", PHP_EOL;
     1012            $caseIsOut = false;
     1013            foreach ($cases as $caseFirst => $caseLast) {
     1014                if ($caseIsOut && empty($lastCaseFall)) {
     1015                    echo PHP_EOL;
     1016                }
     1017
     1018                $caseOp = $opcodes[$caseFirst];
     1019
     1020                echo $indent;
     1021                if ($caseOp['opcode'] == XC_CASE) {
     1022                    echo 'case ';
     1023                    echo str($this->getOpVal($caseOp['op2'], $EX), $EX);
     1024                    echo ':', PHP_EOL;
     1025
     1026                    $this->removeJmpInfo($EX, $caseFirst);
     1027                    ++$caseFirst;
     1028
     1029                    assert('$opcodes[$caseFirst]["opcode"] == XC_JMPZ');
     1030                    $this->removeJmpInfo($EX, $caseFirst);
     1031                    ++$caseFirst;
     1032                }
     1033                else {
     1034                    echo 'default';
     1035                    echo ':', PHP_EOL;
     1036
     1037                    assert('$opcodes[$caseFirst]["opcode"] == XC_JMP');
     1038                    $this->removeJmpInfo($EX, $caseFirst);
     1039                    ++$caseFirst;
     1040                }
     1041
     1042                assert('$opcodes[$caseLast]["opcode"] == XC_JMP');
     1043                $this->removeJmpInfo($EX, $caseLast);
     1044                --$caseLast;
     1045                switch ($opcodes[$caseLast]['opcode']) {
     1046                case XC_BRK:
     1047                case XC_CONT:
     1048                case XC_GOTO:
     1049                    $lastCaseFall = false;
     1050                    break;
     1051
     1052                default:
     1053                    $lastCaseFall = true;
     1054                }
     1055
     1056                $this->beginScope($EX);
     1057                $this->recognizeAndDecompileClosedBlocks($EX, array($caseFirst, $caseLast));
     1058                $this->endScope($EX);
     1059                $caseIsOut = true;
     1060            }
     1061            echo $indent, '}', PHP_EOL;
     1062
     1063            $this->endComplexBlock($EX);
     1064            return;
     1065        }
     1066        // }}}
     1067        // {{{ do/while
     1068        if ($lastOp['opcode'] == XC_JMPNZ && !empty($lastOp['jmpouts'])
     1069         && $lastOp['jmpouts'][0] == $range[0]) {
     1070            $this->removeJmpInfo($EX, $range[1]);
     1071            $this->beginComplexBlock($EX);
     1072
     1073            echo $indent, "do {", PHP_EOL;
     1074            $this->beginScope($EX);
     1075            $this->recognizeAndDecompileClosedBlocks($EX, $range);
     1076            $this->endScope($EX);
     1077            echo $indent, "} while (", str($this->getOpVal($lastOp['op1'], $EX)), ');', PHP_EOL;
     1078
     1079            $this->endComplexBlock($EX);
     1080            return;
     1081        }
     1082        // }}}
     1083
     1084        // {{{ search firstJmpOp
     1085        $firstJmp = null;
     1086        $firstJmpOp = null;
     1087        for ($i = $range[0]; $i <= $range[1]; ++$i) {
     1088            if (!empty($opcodes[$i]['jmpouts'])) {
     1089                $firstJmp = $i;
     1090                $firstJmpOp = &$opcodes[$firstJmp];
     1091                break;
     1092            }
     1093        }
     1094        // }}}
     1095
     1096        // {{{ while
     1097        if (isset($firstJmpOp)
     1098         && $firstJmpOp['opcode'] == XC_JMPZ
     1099         && $firstJmpOp['jmpouts'][0] > $range[1]
     1100         && $lastOp['opcode'] == XC_JMP && !empty($lastOp['jmpouts'])
     1101         && $lastOp['jmpouts'][0] == $range[0]) {
     1102            $this->removeJmpInfo($EX, $firstJmp);
     1103            $this->removeJmpInfo($EX, $range[1]);
     1104            $this->beginComplexBlock($EX);
     1105
     1106            ob_start();
     1107            $this->beginScope($EX);
     1108            $this->recognizeAndDecompileClosedBlocks($EX, $range);
     1109            $this->endScope($EX);
     1110            $body = ob_get_clean();
     1111
     1112            echo $indent, 'while (', str($this->getOpVal($firstJmpOp['op1'], $EX)), ") {", PHP_EOL;
     1113            echo $body;
     1114            echo $indent, '}', PHP_EOL;
     1115
     1116            $this->endComplexBlock($EX);
     1117            return;
     1118        }
     1119        // }}}
     1120        // {{{ foreach
     1121        if (isset($firstJmpOp)
     1122         && $firstJmpOp['opcode'] == XC_FE_FETCH
     1123         && $firstJmpOp['jmpouts'][0] > $range[1]
     1124         && $lastOp['opcode'] == XC_JMP && !empty($lastOp['jmpouts'])
     1125         && $lastOp['jmpouts'][0] == $firstJmp) {
     1126            $this->removeJmpInfo($EX, $firstJmp);
     1127            $this->removeJmpInfo($EX, $range[1]);
     1128            $this->beginComplexBlock($EX);
     1129
     1130            ob_start();
     1131            $this->beginScope($EX);
     1132            $this->recognizeAndDecompileClosedBlocks($EX, $range);
     1133            $this->endScope($EX);
     1134            $body = ob_get_clean();
     1135
     1136            $as = foldToCode($firstJmpOp['fe_as'], $EX);
     1137            if (isset($firstJmpOp['fe_key'])) {
     1138                $as = str($firstJmpOp['fe_key'], $EX) . ' => ' . str($as);
     1139            }
     1140
     1141            echo $indent, 'foreach (', str($firstJmpOp['fe_src'], $EX), " as $as) {", PHP_EOL;
     1142            echo $body;
     1143            echo $indent, '}', PHP_EOL;
     1144
     1145            $this->endComplexBlock($EX);
     1146            if ($opcodes[$range[1] + 1]['opcode'] == XC_SWITCH_FREE) {
     1147                $this->removeJmpInfo($EX, $range[1] + 1);
     1148            }
     1149            return;
     1150        }
     1151        // }}}
     1152
     1153        $this->decompileBasicBlock($EX, $range, true);
     1154    }
     1155    // }}}
     1156    function recognizeAndDecompileClosedBlocks(&$EX, $range) // {{{ decompile in a tree way
     1157    {
     1158        $opcodes = &$EX['opcodes'];
     1159
     1160        $starti = $range[0];
     1161        for ($i = $starti; $i <= $range[1]; ) {
     1162            if (!empty($opcodes[$i]['jmpins']) || !empty($opcodes[$i]['jmpouts'])) {
     1163                $blockFirst = $i;
     1164                $blockLast = -1;
     1165                $j = $blockFirst;
     1166                do {
     1167                    $op = $opcodes[$j];
     1168                    if (!empty($op['jmpins'])) {
     1169                        // care about jumping from blocks behind, not before
     1170                        foreach ($op['jmpins'] as $oplineNumber) {
     1171                            if ($oplineNumber <= $range[1] && $blockLast < $oplineNumber) {
     1172                                $blockLast = $oplineNumber;
     1173                            }
     1174                        }
     1175                    }
     1176                    if (!empty($op['jmpouts'])) {
     1177                        $blockLast = max($blockLast, max($op['jmpouts']) - 1);
     1178                    }
     1179                    ++$j;
     1180                } while ($j <= $blockLast);
     1181                if (!assert('$blockLast <= $range[1]')) {
     1182                    var_dump($blockLast, $range[1]);
     1183                }
     1184
     1185                if ($blockLast >= $blockFirst) {
     1186                    if ($blockFirst > $starti) {
     1187                        $this->decompileBasicBlock($EX, array($starti, $blockFirst - 1));
     1188                    }
     1189                    if ($this->decompileComplexBlock($EX, array($blockFirst, $blockLast)) === false) {
     1190                        if ($EX['lastBlock'] == 'complex') {
     1191                            echo PHP_EOL;
     1192                        }
     1193                        $EX['lastBlock'] = null;
     1194                    }
     1195                    $starti = $blockLast + 1;
     1196                    $i = $starti;
     1197                }
     1198                else {
     1199                    ++$i;
     1200                }
     1201            }
     1202            else {
     1203                ++$i;
     1204            }
     1205        }
     1206        if ($starti <= $range[1]) {
     1207            $this->decompileBasicBlock($EX, array($starti, $range[1]));
     1208        }
     1209    }
     1210    // }}}
    6501211    function &dop_array($op_array, $indent = '') // {{{
    6511212    {
    6521213        $op_array['opcodes'] = $this->fixOpcode($op_array['opcodes'], true, $indent == '' ? 1 : null);
    6531214        $opcodes = &$op_array['opcodes'];
    654         $EX['indent'] = '';
    655         // {{{ build jmp array
    656         for ($i = 0, $cnt = count($opcodes); $i < $cnt; $i ++) {
     1215        $last = count($opcodes) - 1;
     1216        // {{{ build jmpins/jmpouts to op_array
     1217        for ($i = 0; $i <= $last; $i ++) {
    6571218            $op = &$opcodes[$i];
    658             /*
    659             if ($op['opcode'] == XC_JMPZ) {
    660                 $this->dumpop($op, $EX);
    661                 var_dump($op);
    662             }
    663             continue;
    664             */
    6651219            $op['line'] = $i;
    6661220            switch ($op['opcode']) {
     
    6711225
    6721226            case XC_GOTO:
     1227                $target = $op['op1']['var'];
     1228                $op['goto'] = $target;
     1229                $opcodes[$target]['gofrom'][] = $i;
     1230                break;
     1231
    6731232            case XC_JMP:
    6741233                $target = $op['op1']['var'];
     
    6891248            case XC_JMPZ_EX:
    6901249            case XC_JMPNZ_EX:
    691             case XC_JMP_SET:
     1250            // case XC_JMP_SET:
    6921251            // case XC_FE_RESET:
    6931252            case XC_FE_FETCH:
     
    7071266                break;
    7081267            */
    709             }
     1268
     1269            case XC_SWITCH_FREE:
     1270                $op['jmpouts'] = array($i + 1);
     1271                $opcodes[$i + 1]['jmpins'][] = $i;
     1272                break;
     1273
     1274            case XC_CASE:
     1275                // just to link together
     1276                $op['jmpouts'] = array($i + 2);
     1277                $opcodes[$i + 2]['jmpins'][] = $i;
     1278                break;
     1279
     1280            case XC_CATCH:
     1281                $catchNext = $op['extended_value'];
     1282                $op['jmpouts'] = array($catchNext);
     1283                $opcodes[$catchNext]['jmpins'][] = $i;
     1284                break;
     1285            }
     1286            /*
     1287            if (!empty($op['jmpouts']) || !empty($op['jmpins'])) {
     1288                echo $i, "\t", xcache_get_opcode($op['opcode']), PHP_EOL;
     1289            }
     1290            // */
    7101291        }
    7111292        unset($op);
     1293        if ($op_array['try_catch_array']) {
     1294            foreach ($op_array['try_catch_array'] as $try_catch_element) {
     1295                $catch_op = $try_catch_element['catch_op'];
     1296                $try_op = $try_catch_element['try_op'];
     1297                $opcodes[$try_op]['jmpins'][] = $catch_op;
     1298                $opcodes[$catch_op]['jmpouts'][] = $try_op;
     1299                $opcodes[$catch_op]['isCatchBegin'] = true;
     1300            }
     1301        }
    7121302        // }}}
    7131303        // build semi-basic blocks
    7141304        $nextbbs = array();
    7151305        $starti = 0;
    716         for ($i = 1, $cnt = count($opcodes); $i < $cnt; $i ++) {
     1306        for ($i = 1; $i <= $last; $i ++) {
    7171307            if (isset($opcodes[$i]['jmpins'])
    7181308             || isset($opcodes[$i - 1]['jmpouts'])) {
     
    7211311            }
    7221312        }
    723         $nextbbs[$starti] = $cnt;
     1313        $nextbbs[$starti] = $last + 1;
    7241314
    7251315        $EX = array();
     
    7291319        $EX['op_array'] = &$op_array;
    7301320        $EX['opcodes'] = &$opcodes;
     1321        $EX['range'] = array(0, count($opcodes) - 1);
    7311322        // func call
    7321323        $EX['object'] = null;
     
    7351326        $EX['argstack'] = array();
    7361327        $EX['arg_types_stack'] = array();
    737         $EX['last'] = count($opcodes) - 1;
     1328        $EX['scopeStack'] = array();
    7381329        $EX['silence'] = 0;
    7391330        $EX['recvs'] = array();
    7401331        $EX['uses'] = array();
    741 
    742         for ($next = 0, $last = $EX['last'];
    743                 $loop = $this->outputCode($EX, $next, $last, $indent, true);
    744                 list($next, $last) = $loop) {
    745             // empty
    746         }
     1332        $EX['lastBlock'] = null;
     1333
     1334        /* dump whole array
     1335        $this->keepTs = true;
     1336        $this->dasmBasicBlock($EX, $range);
     1337        for ($i = $range[0]; $i <= $range[1]; ++$i) {
     1338            echo $i, "\t", $this->dumpop($opcodes[$i], $EX);
     1339        }
     1340        // */
     1341        // decompile in a tree way
     1342        $this->recognizeAndDecompileClosedBlocks($EX, $EX['range'], $EX['indent']);
    7471343        return $EX;
    7481344    }
    7491345    // }}}
    750     function outputCode(&$EX, $opline, $last, $indent, $loop = false) // {{{
    751     {
    752         $op = &$EX['opcodes'][$opline];
    753         $next = $EX['nextbbs'][$opline];
    754 
    755         $end = $next - 1;
    756         if ($end > $last) {
    757             $end = $last;
    758         }
    759 
    760         if (isset($op['jmpins'])) {
    761             echo "\nline", $op['line'], ":\n";
    762         }
    763         else {
    764             // echo ";;;\n";
    765         }
    766         $this->dasmBasicBlock($EX, $opline, $end);
    767         $this->outputPhp($EX['opcodes'], $opline, $end, $indent);
    768         // jmpout op
    769         $op = &$EX['opcodes'][$end];
    770         $op1 = $op['op1'];
    771         $op2 = $op['op2'];
    772         $ext = $op['extended_value'];
    773         $line = $op['line'];
    774 
    775         if (isset($EX['opcodes'][$next])) {
    776             if (isset($last) && $next > $last) {
    777                 $next = null;
    778             }
    779         }
    780         else {
    781             $next = null;
    782         }
    783         if ($op['opcode'] == XC_FE_FETCH) {
    784             $opline = $next;
    785             $next = $op['op2']['opline_num'];
    786             $end = $next - 1;
    787 
    788             ob_start();
    789             $this->outputCode($EX, $opline, $end /* - 1 skip last jmp */, $indent . INDENT);
    790             $body = ob_get_clean();
    791 
    792             $as = foldToCode($op['fe_as'], $EX);
    793             if (isset($op['fe_key'])) {
    794                 $as = str($op['fe_key'], $EX) . ' => ' . str($as);
    795             }
    796             echo "{$indent}foreach (" . str($op['fe_src'], $EX) . " as $as) {\n";
    797             echo $body;
    798             echo "{$indent}}";
    799             // $this->outputCode($EX, $next, $last, $indent);
    800             // return;
    801         }
    802         /*
    803         if ($op['opcode'] == XC_JMPZ) {
    804             $target = $op2['opline_num'];
    805             if ($line + 1) {
    806                 $nextblock = $EX['nextbbs'][$next];
    807                 $jmpop = end($nextblock);
    808                 if ($jmpop['opcode'] == XC_JMP) {
    809                     $ifendline = $op2['opline_num'];
    810                     if ($ifendline >= $line) {
    811                         $cond = $op['cond'];
    812                         echo "{$indent}if ($cond) {\n";
    813                         $this->outputCode($EX, $next, $last, INDENT . $indent);
    814                         echo "$indent}\n";
    815                         $this->outputCode($EX, $target, $last, $indent);
    816                         return;
    817                     }
    818                 }
    819             }
    820         }
    821         */
    822         if (!isset($next)) {
    823             return;
    824         }
    825         if (isset($op['jmpouts']) && isset($op['isjmp'])) {
    826             if (isset($op['cond'])) {
    827                 echo "{$indent}check (" . str($op["cond"]) . ") {\n";
    828                 echo INDENT;
    829             }
    830             switch ($op['opcode']) {
    831             case XC_CONT:
    832             case XC_BRK:
    833                 break;
    834 
    835             case XC_GOTO:
    836                 echo $indent, 'goto', ' line', $op['jmpouts'][0], ';', "\n";
    837                 break;
    838 
    839             default:
    840                 echo $indent;
    841                 echo xcache_get_opcode($op['opcode']), ' line', $op['jmpouts'][0];
    842                 if (isset($op['jmpouts'][1])) {
    843                     echo ', line', $op['jmpouts'][1];
    844                 }
    845                 echo ";";
    846                 // echo ' // <- line', $op['line'];
    847                 echo "\n";
    848             }
    849             if (isset($op['cond'])) echo "$indent}\n";
    850         }
    851 
    852         // proces JMPZ_EX/JMPNZ_EX for AND,OR
    853         $op = &$EX['opcodes'][$next];
    854         /*
    855         if (isset($op['jmpins'])) {
    856             foreach (array_reverse($op['jmpins']) as $fromline) {
    857                 $fromop = $EX['opcodes'][$fromline];
    858                 switch ($fromop['opcode']) {
    859                 case XC_JMPZ_EX: $opstr = 'and'; break;
    860                 case XC_JMPNZ_EX: $opstr = 'or'; break;
    861                 case XC_JMPZNZ: var_dump($fromop); exit;
    862                 default: continue 2;
    863                 }
    864 
    865                 $var = $fromop['result']['var'];
    866                 var_dump($EX['Ts'][$var]);
    867                 $EX['Ts'][$var] = '(' . $fromop['and_or'] . " $opstr " . $EX['Ts'][$var] . ')';
    868             }
    869             #$this->outputCode($EX, $next, $last, $indent);
    870             #return;
    871         }
    872         */
    873         if (isset($op['cond_false'])) {
    874             // $this->dumpop($op, $EX);
    875             // any true comes here, so it's a "or"
    876             $cond = implode(' and ', str($op['cond_false']));
    877             // var_dump($op['cond'] = $cond);
    878             /*
    879             $rvalue = implode(' or ', $op['cond_true']) . ' or ' . $rvalue;
    880             unset($op['cond_true']);
    881             */
    882         }
    883 
    884         if ($loop) {
    885             return array($next, $last);
    886         }
    887         $this->outputCode($EX, $next, $last, $indent);
    888     }
    889     // }}}
    890     function dasmBasicBlock(&$EX, $opline, $last) // {{{
     1346    function dasmBasicBlock(&$EX, $range) // {{{
    8911347    {
    8921348        $T = &$EX['Ts'];
     
    8941350        $lastphpop = null;
    8951351
    896         for ($i = $opline, $ic = $last + 1; $i < $ic; $i ++) {
     1352        for ($i = $range[0]; $i <= $range[1]; $i ++) {
    8971353            // {{{ prepair
    8981354            $op = &$opcodes[$i];
     
    9181374
    9191375            $resvar = null;
     1376            unset($curResVar);
     1377            if (array_key_exists($res['var'], $T)) {
     1378                $curResVar = &$T[$res['var']];
     1379            }
    9201380            if ((ZEND_ENGINE_2_4 ? ($res['op_type'] & EXT_TYPE_UNUSED) : ($res['EA.type'] & EXT_TYPE_UNUSED)) || $res['op_type'] == XC_IS_UNUSED) {
    9211381                $istmpres = false;
     
    9271387            // echo $opname, "\n";
    9281388
    929             $call = array(&$this, $opname);
    930             if (is_callable($call)) {
    931                 $this->usedOps[$opc] = true;
    932                 $this->{$opname}($op, $EX);
    933             }
    934             else if (isset($this->binops[$opc])) { // {{{
    935                 $this->usedOps[$opc] = true;
    936                 $op1val = $this->getOpVal($op1, $EX, false);
    937                 $op2val = $this->getOpVal($op2, $EX, false);
    938                 $rvalue = new Decompiler_Binop($this, $op1val, $opc, $op2val);
    939                 $resvar = $rvalue;
    940                 // }}}
    941             }
    942             else if (isset($this->unaryops[$opc])) { // {{{
    943                 $this->usedOps[$opc] = true;
    944                 $op1val = $this->getOpVal($op1, $EX);
    945                 $myop = $this->unaryops[$opc];
    946                 $rvalue = $myop . str($op1val);
    947                 $resvar = $rvalue;
    948                 // }}}
    949             }
    950             else {
    951                 $covered = true;
    952                 switch ($opc) {
    953                 case XC_NEW: // {{{
    954                     array_push($EX['arg_types_stack'], array($EX['fbc'], $EX['object'], $EX['called_scope']));
    955                     $EX['object'] = (int) $res['var'];
    956                     $EX['called_scope'] = null;
    957                     $EX['fbc'] = 'new ' . unquoteName($this->getOpVal($op1, $EX), $EX);
    958                     if (!ZEND_ENGINE_2) {
    959                         $resvar = '$new object$';
    960                     }
     1389            $notHandled = false;
     1390            switch ($opc) {
     1391            case XC_NEW: // {{{
     1392                array_push($EX['arg_types_stack'], array($EX['fbc'], $EX['object'], $EX['called_scope']));
     1393                $EX['object'] = (int) $res['var'];
     1394                $EX['called_scope'] = null;
     1395                $EX['fbc'] = 'new ' . unquoteName($this->getOpVal($op1, $EX), $EX);
     1396                if (!ZEND_ENGINE_2) {
     1397                    $resvar = '$new object$';
     1398                }
     1399                break;
     1400                // }}}
     1401            case XC_THROW: // {{{
     1402                $resvar = 'throw ' . str($this->getOpVal($op1, $EX));
     1403                break;
     1404                // }}}
     1405            case XC_CLONE: // {{{
     1406                $resvar = 'clone ' . str($this->getOpVal($op1, $EX));
     1407                break;
     1408                // }}}
     1409            case XC_CATCH: // {{{
     1410                break;
     1411                // }}}
     1412            case XC_INSTANCEOF: // {{{
     1413                $resvar = str($this->getOpVal($op1, $EX)) . ' instanceof ' . str($this->getOpVal($op2, $EX));
     1414                break;
     1415                // }}}
     1416            case XC_FETCH_CLASS: // {{{
     1417                if ($op2['op_type'] == XC_IS_UNUSED) {
     1418                    switch (($ext & (defined('ZEND_FETCH_CLASS_MASK') ? ZEND_FETCH_CLASS_MASK : 0xFF))) {
     1419                    case ZEND_FETCH_CLASS_SELF:
     1420                        $class = 'self';
     1421                        break;
     1422                    case ZEND_FETCH_CLASS_PARENT:
     1423                        $class = 'parent';
     1424                        break;
     1425                    case ZEND_FETCH_CLASS_STATIC:
     1426                        $class = 'static';
     1427                        break;
     1428                    }
     1429                    $istmpres = true;
     1430                }
     1431                else {
     1432                    $class = $this->getOpVal($op2, $EX);
     1433                    if (isset($op2['constant'])) {
     1434                        $class = $this->stripNamespace(unquoteName($class));
     1435                    }
     1436                }
     1437                $resvar = $class;
     1438                break;
     1439                // }}}
     1440            case XC_FETCH_CONSTANT: // {{{
     1441                if ($op1['op_type'] == XC_IS_UNUSED) {
     1442                    $resvar = $this->stripNamespace($op2['constant']);
    9611443                    break;
    962                     // }}}
    963                 case XC_THROW: // {{{
    964                     $resvar = 'throw ' . str($this->getOpVal($op1, $EX));
     1444                }
     1445
     1446                if ($op1['op_type'] == XC_IS_CONST) {
     1447                    $resvar = $this->stripNamespace($op1['constant']);
     1448                }
     1449                else {
     1450                    $resvar = $this->getOpVal($op1, $EX);
     1451                }
     1452
     1453                $resvar = str($resvar) . '::' . unquoteName($this->getOpVal($op2, $EX));
     1454                break;
     1455                // }}}
     1456                // {{{ case XC_FETCH_*
     1457            case XC_FETCH_R:
     1458            case XC_FETCH_W:
     1459            case XC_FETCH_RW:
     1460            case XC_FETCH_FUNC_ARG:
     1461            case XC_FETCH_UNSET:
     1462            case XC_FETCH_IS:
     1463            case XC_UNSET_VAR:
     1464                $rvalue = $this->getOpVal($op1, $EX);
     1465                if (defined('ZEND_FETCH_TYPE_MASK')) {
     1466                    $fetchtype = ($ext & ZEND_FETCH_TYPE_MASK);
     1467                }
     1468                else {
     1469                    $fetchtype = $op2[!ZEND_ENGINE_2 ? 'fetch_type' : 'EA.type'];
     1470                }
     1471                switch ($fetchtype) {
     1472                case ZEND_FETCH_STATIC_MEMBER:
     1473                    $class = $this->getOpVal($op2, $EX);
     1474                    $rvalue = str($class) . '::$' . unquoteName($rvalue, $EX);
    9651475                    break;
    966                     // }}}
    967                 case XC_CLONE: // {{{
    968                     $resvar = 'clone ' . str($this->getOpVal($op1, $EX));
     1476                default:
     1477                    $name = unquoteName($rvalue, $EX);
     1478                    $globalname = xcache_is_autoglobal($name) ? "\$$name" : "\$GLOBALS[" . str($rvalue) . "]";
     1479                    $rvalue = new Decompiler_Fetch($rvalue, $fetchtype, $globalname);
    9691480                    break;
    970                     // }}}
    971                 case XC_CATCH: // {{{
    972                     $resvar = 'catch (' . str($this->getOpVal($op1, $EX)) . ' ' . str($this->getOpVal($op2, $EX)) . ')';
     1481                }
     1482                if ($opc == XC_UNSET_VAR) {
     1483                    $op['php'] = "unset(" . str($rvalue, $EX) . ")";
     1484                    $lastphpop = &$op;
     1485                }
     1486                else if ($res['op_type'] != XC_IS_UNUSED) {
     1487                    $resvar = $rvalue;
     1488                }
     1489                break;
     1490                // }}}
     1491                // {{{ case XC_FETCH_DIM_*
     1492            case XC_FETCH_DIM_TMP_VAR:
     1493            case XC_FETCH_DIM_R:
     1494            case XC_FETCH_DIM_W:
     1495            case XC_FETCH_DIM_RW:
     1496            case XC_FETCH_DIM_FUNC_ARG:
     1497            case XC_FETCH_DIM_UNSET:
     1498            case XC_FETCH_DIM_IS:
     1499            case XC_ASSIGN_DIM:
     1500            case XC_UNSET_DIM_OBJ: // PHP 4 only
     1501            case XC_UNSET_DIM:
     1502            case XC_UNSET_OBJ:
     1503                $src = $this->getOpVal($op1, $EX);
     1504                if (is_a($src, "Decompiler_ForeachBox")) {
     1505                    $src->iskey = $this->getOpVal($op2, $EX);
     1506                    $resvar = $src;
    9731507                    break;
    974                     // }}}
    975                 case XC_INSTANCEOF: // {{{
    976                     $resvar = str($this->getOpVal($op1, $EX)) . ' instanceof ' . str($this->getOpVal($op2, $EX));
     1508                }
     1509
     1510                if (is_a($src, "Decompiler_DimBox")) {
     1511                    $dimbox = $src;
     1512                }
     1513                else {
     1514                    if (!is_a($src, "Decompiler_ListBox")) {
     1515                        $op1val = $this->getOpVal($op1, $EX);
     1516                        $list = new Decompiler_List(isset($op1val) ? $op1val : '$this');
     1517
     1518                        $src = new Decompiler_ListBox($list);
     1519                        if (!isset($op1['var'])) {
     1520                            $this->dumpop($op, $EX);
     1521                            var_dump($op);
     1522                            die('missing var');
     1523                        }
     1524                        $T[$op1['var']] = $src;
     1525                        unset($list);
     1526                    }
     1527                    $dim = new Decompiler_Dim($src);
     1528                    $src->obj->dims[] = &$dim;
     1529
     1530                    $dimbox = new Decompiler_DimBox($dim);
     1531                }
     1532                $dim = &$dimbox->obj;
     1533                $dim->offsets[] = $this->getOpVal($op2, $EX);
     1534                if ($ext == ZEND_FETCH_ADD_LOCK) {
     1535                    $src->obj->everLocked = true;
     1536                }
     1537                else if ($ext == ZEND_FETCH_STANDARD) {
     1538                    $dim->isLast = true;
     1539                }
     1540                if ($opc == XC_UNSET_OBJ) {
     1541                    $dim->isObject = true;
     1542                }
     1543                unset($dim);
     1544                $rvalue = $dimbox;
     1545                unset($dimbox);
     1546
     1547                if ($opc == XC_ASSIGN_DIM) {
     1548                    $lvalue = $rvalue;
     1549                    ++ $i;
     1550                    $rvalue = $this->getOpVal($opcodes[$i]['op1'], $EX);
     1551                    $resvar = str($lvalue, $EX) . ' = ' . str($rvalue);
     1552                }
     1553                else if ($opc == XC_UNSET_DIM || $opc == XC_UNSET_OBJ) {
     1554                    $op['php'] = "unset(" . str($rvalue, $EX) . ")";
     1555                    $lastphpop = &$op;
     1556                }
     1557                else if ($res['op_type'] != XC_IS_UNUSED) {
     1558                    $resvar = $rvalue;
     1559                }
     1560                break;
     1561                // }}}
     1562            case XC_ASSIGN: // {{{
     1563                $lvalue = $this->getOpVal($op1, $EX);
     1564                $rvalue = $this->getOpVal($op2, $EX);
     1565                if (is_a($rvalue, 'Decompiler_ForeachBox')) {
     1566                    $type = $rvalue->iskey ? 'fe_key' : 'fe_as';
     1567                    $rvalue->obj[$type] = $lvalue;
     1568                    unset($T[$op2['var']]);
    9771569                    break;
    978                     // }}}
    979                 case XC_FETCH_CLASS: // {{{
    980                     if ($op2['op_type'] == XC_IS_UNUSED) {
    981                         switch (($ext & (defined('ZEND_FETCH_CLASS_MASK') ? ZEND_FETCH_CLASS_MASK : 0xFF))) {
    982                         case ZEND_FETCH_CLASS_SELF:
    983                             $class = 'self';
    984                             break;
    985                         case ZEND_FETCH_CLASS_PARENT:
    986                             $class = 'parent';
    987                             break;
    988                         case ZEND_FETCH_CLASS_STATIC:
    989                             $class = 'static';
    990                             break;
    991                         }
    992                         $istmpres = true;
    993                     }
    994                     else {
    995                         $class = $this->getOpVal($op2, $EX);
    996                         if (isset($op2['constant'])) {
    997                             $class = $this->stripNamespace(unquoteName($class));
    998                         }
    999                     }
    1000                     $resvar = $class;
     1570                }
     1571                if (is_a($rvalue, "Decompiler_DimBox")) {
     1572                    $dim = &$rvalue->obj;
     1573                    $dim->assign = $lvalue;
     1574                    if ($dim->isLast) {
     1575                        $resvar = foldToCode($dim->value, $EX);
     1576                    }
     1577                    unset($dim);
    10011578                    break;
    1002                     // }}}
    1003                 case XC_FETCH_CONSTANT: // {{{
    1004                     if ($op1['op_type'] == XC_IS_UNUSED) {
    1005                         $resvar = $this->stripNamespace($op2['constant']);
    1006                         break;
    1007                     }
    1008 
    1009                     if ($op1['op_type'] == XC_IS_CONST) {
    1010                         $resvar = $this->stripNamespace($op1['constant']);
    1011                     }
    1012                     else {
    1013                         $resvar = $this->getOpVal($op1, $EX);
    1014                     }
    1015 
    1016                     $resvar = str($resvar) . '::' . unquoteName($this->getOpVal($op2, $EX));
    1017                     break;
    1018                     // }}}
    1019                     // {{{ case XC_FETCH_*
    1020                 case XC_FETCH_R:
    1021                 case XC_FETCH_W:
    1022                 case XC_FETCH_RW:
    1023                 case XC_FETCH_FUNC_ARG:
    1024                 case XC_FETCH_UNSET:
    1025                 case XC_FETCH_IS:
    1026                 case XC_UNSET_VAR:
    1027                     $rvalue = $this->getOpVal($op1, $EX);
    1028                     if (defined('ZEND_FETCH_TYPE_MASK')) {
    1029                         $fetchtype = ($ext & ZEND_FETCH_TYPE_MASK);
    1030                     }
    1031                     else {
    1032                         $fetchtype = $op2[!ZEND_ENGINE_2 ? 'fetch_type' : 'EA.type'];
    1033                     }
    1034                     switch ($fetchtype) {
    1035                     case ZEND_FETCH_STATIC_MEMBER:
    1036                         $class = $this->getOpVal($op2, $EX);
    1037                         $rvalue = str($class) . '::$' . unquoteName($rvalue, $EX);
    1038                         break;
    1039                     default:
    1040                         $name = unquoteName($rvalue, $EX);
    1041                         $globalname = xcache_is_autoglobal($name) ? "\$$name" : "\$GLOBALS[" . str($rvalue) . "]";
    1042                         $rvalue = new Decompiler_Fetch($rvalue, $fetchtype, $globalname);
    1043                         break;
    1044                     }
    1045                     if ($opc == XC_UNSET_VAR) {
    1046                         $op['php'] = "unset(" . str($rvalue, $EX) . ")";
    1047                         $lastphpop = &$op;
    1048                     }
    1049                     else if ($res['op_type'] != XC_IS_UNUSED) {
    1050                         $resvar = $rvalue;
    1051                     }
    1052                     break;
    1053                     // }}}
    1054                     // {{{ case XC_FETCH_DIM_*
    1055                 case XC_FETCH_DIM_TMP_VAR:
    1056                 case XC_FETCH_DIM_R:
    1057                 case XC_FETCH_DIM_W:
    1058                 case XC_FETCH_DIM_RW:
    1059                 case XC_FETCH_DIM_FUNC_ARG:
    1060                 case XC_FETCH_DIM_UNSET:
    1061                 case XC_FETCH_DIM_IS:
    1062                 case XC_ASSIGN_DIM:
    1063                 case XC_UNSET_DIM_OBJ: // PHP 4 only
    1064                 case XC_UNSET_DIM:
    1065                 case XC_UNSET_OBJ:
    1066                     $src = $this->getOpVal($op1, $EX, false);
    1067                     if (is_a($src, "Decompiler_ForeachBox")) {
    1068                         $src->iskey = $this->getOpVal($op2, $EX);
    1069                         $resvar = $src;
    1070                         break;
    1071                     }
    1072 
    1073                     if (is_a($src, "Decompiler_DimBox")) {
    1074                         $dimbox = $src;
    1075                     }
    1076                     else {
    1077                         if (!is_a($src, "Decompiler_ListBox")) {
    1078                             $op1val = $this->getOpVal($op1, $EX, false);
    1079                             $list = new Decompiler_List(isset($op1val) ? $op1val : '$this');
    1080 
    1081                             $src = new Decompiler_ListBox($list);
    1082                             if (!isset($op1['var'])) {
    1083                                 $this->dumpop($op, $EX);
    1084                                 var_dump($op);
    1085                                 die('missing var');
    1086                             }
    1087                             $T[$op1['var']] = $src;
    1088                             unset($list);
    1089                         }
    1090                         $dim = new Decompiler_Dim($src);
    1091                         $src->obj->dims[] = &$dim;
    1092 
    1093                         $dimbox = new Decompiler_DimBox($dim);
    1094                     }
    1095                     $dim = &$dimbox->obj;
    1096                     $dim->offsets[] = $this->getOpVal($op2, $EX);
    1097                     if ($ext == ZEND_FETCH_ADD_LOCK) {
    1098                         $src->obj->everLocked = true;
    1099                     }
    1100                     else if ($ext == ZEND_FETCH_STANDARD) {
    1101                         $dim->isLast = true;
    1102                     }
    1103                     if ($opc == XC_UNSET_OBJ) {
    1104                         $dim->isObject = true;
    1105                     }
    1106                     unset($dim);
    1107                     $rvalue = $dimbox;
    1108                     unset($dimbox);
    1109 
    1110                     if ($opc == XC_ASSIGN_DIM) {
    1111                         $lvalue = $rvalue;
    1112                         ++ $i;
    1113                         $rvalue = $this->getOpVal($opcodes[$i]['op1'], $EX);
    1114                         $resvar = str($lvalue, $EX) . ' = ' . str($rvalue);
    1115                     }
    1116                     else if ($opc == XC_UNSET_DIM || $opc == XC_UNSET_OBJ) {
    1117                         $op['php'] = "unset(" . str($rvalue, $EX) . ")";
    1118                         $lastphpop = &$op;
    1119                     }
    1120                     else if ($res['op_type'] != XC_IS_UNUSED) {
    1121                         $resvar = $rvalue;
    1122                     }
    1123                     break;
    1124                     // }}}
    1125                 case XC_ASSIGN: // {{{
    1126                     $lvalue = $this->getOpVal($op1, $EX);
    1127                     $rvalue = $this->getOpVal($op2, $EX, false);
    1128                     if (is_a($rvalue, 'Decompiler_ForeachBox')) {
    1129                         $type = $rvalue->iskey ? 'fe_key' : 'fe_as';
    1130                         $rvalue->obj[$type] = $lvalue;
    1131                         unset($T[$op2['var']]);
    1132                         break;
    1133                     }
    1134                     if (is_a($rvalue, "Decompiler_DimBox")) {
    1135                         $dim = &$rvalue->obj;
    1136                         $dim->assign = $lvalue;
    1137                         if ($dim->isLast) {
    1138                             $resvar = foldToCode($dim->value, $EX);
    1139                         }
    1140                         unset($dim);
    1141                         break;
    1142                     }
    1143                     if (is_a($rvalue, 'Decompiler_Fetch')) {
    1144                         $src = str($rvalue->src, $EX);
    1145                         if ('$' . unquoteName($src) == $lvalue) {
    1146                             switch ($rvalue->fetchType) {
    1147                             case ZEND_FETCH_STATIC:
    1148                                 $statics = &$EX['op_array']['static_variables'];
    1149                                 if ((xcache_get_type($statics[$name]) & IS_LEXICAL_VAR)) {
    1150                                     $EX['uses'][] = str($lvalue);
    1151                                     unset($statics);
    1152                                     break 2;
    1153                                 }
    1154                                 unset($statics);
    1155                             }
    1156                         }
    1157                     }
    1158                     $resvar = "$lvalue = " . str($rvalue, $EX);
    1159                     break;
    1160                     // }}}
    1161                 case XC_ASSIGN_REF: // {{{
    1162                     $lvalue = $this->getOpVal($op1, $EX);
    1163                     $rvalue = $this->getOpVal($op2, $EX, false);
    1164                     if (is_a($rvalue, 'Decompiler_Fetch')) {
    1165                         $src = str($rvalue->src, $EX);
    1166                         if ('$' . unquoteName($src) == $lvalue) {
    1167                             switch ($rvalue->fetchType) {
    1168                             case ZEND_FETCH_GLOBAL:
    1169                             case ZEND_FETCH_GLOBAL_LOCK:
    1170                                 $resvar = 'global ' . $lvalue;
    1171                                 break 2;
    1172                             case ZEND_FETCH_STATIC:
    1173                                 $statics = &$EX['op_array']['static_variables'];
    1174                                 if ((xcache_get_type($statics[$name]) & IS_LEXICAL_REF)) {
    1175                                     $EX['uses'][] = '&' . str($lvalue);
    1176                                     unset($statics);
    1177                                     break 2;
    1178                                 }
    1179 
    1180                                 $resvar = 'static ' . $lvalue;
    1181                                 $name = unquoteName($src);
    1182                                 if (isset($statics[$name])) {
    1183                                     $var = $statics[$name];
    1184                                     $resvar .= ' = ';
    1185                                     $resvar .= str(value($var), $EX);
    1186                                 }
     1579                }
     1580                if (is_a($rvalue, 'Decompiler_Fetch')) {
     1581                    $src = str($rvalue->src, $EX);
     1582                    if ('$' . unquoteName($src) == $lvalue) {
     1583                        switch ($rvalue->fetchType) {
     1584                        case ZEND_FETCH_STATIC:
     1585                            $statics = &$EX['op_array']['static_variables'];
     1586                            if ((xcache_get_type($statics[$name]) & IS_LEXICAL_VAR)) {
     1587                                $EX['uses'][] = str($lvalue);
    11871588                                unset($statics);
    11881589                                break 2;
    1189                             default:
    11901590                            }
     1591                            unset($statics);
    11911592                        }
    11921593                    }
    1193                     // TODO: PHP_6 global
    1194                     $rvalue = str($rvalue, $EX);
    1195                     $resvar = "$lvalue = &$rvalue";
     1594                }
     1595                $resvar = new Decompiler_Binop($this, $lvalue, XC_ASSIGN, $rvalue);
     1596                break;
     1597                // }}}
     1598            case XC_ASSIGN_REF: // {{{
     1599                $lvalue = $this->getOpVal($op1, $EX);
     1600                $rvalue = $this->getOpVal($op2, $EX);
     1601                if (is_a($rvalue, 'Decompiler_Fetch')) {
     1602                    $src = str($rvalue->src, $EX);
     1603                    if ('$' . unquoteName($src) == $lvalue) {
     1604                        switch ($rvalue->fetchType) {
     1605                        case ZEND_FETCH_GLOBAL:
     1606                        case ZEND_FETCH_GLOBAL_LOCK:
     1607                            $resvar = 'global ' . $lvalue;
     1608                            break 2;
     1609                        case ZEND_FETCH_STATIC:
     1610                            $statics = &$EX['op_array']['static_variables'];
     1611                            if ((xcache_get_type($statics[$name]) & IS_LEXICAL_REF)) {
     1612                                $EX['uses'][] = '&' . str($lvalue);
     1613                                unset($statics);
     1614                                break 2;
     1615                            }
     1616
     1617                            $resvar = 'static ' . $lvalue;
     1618                            $name = unquoteName($src);
     1619                            if (isset($statics[$name])) {
     1620                                $var = $statics[$name];
     1621                                $resvar .= ' = ';
     1622                                $resvar .= str(value($var), $EX);
     1623                            }
     1624                            unset($statics);
     1625                            break 2;
     1626                        default:
     1627                        }
     1628                    }
     1629                }
     1630                // TODO: PHP_6 global
     1631                $resvar = new Decompiler_Binop($this, $lvalue, XC_ASSIGN_REF, $rvalue);
     1632                break;
     1633                // }}}
     1634            // {{{ case XC_FETCH_OBJ_*
     1635            case XC_FETCH_OBJ_R:
     1636            case XC_FETCH_OBJ_W:
     1637            case XC_FETCH_OBJ_RW:
     1638            case XC_FETCH_OBJ_FUNC_ARG:
     1639            case XC_FETCH_OBJ_UNSET:
     1640            case XC_FETCH_OBJ_IS:
     1641            case XC_ASSIGN_OBJ:
     1642                $obj = $this->getOpVal($op1, $EX);
     1643                if (!isset($obj)) {
     1644                    $obj = '$this';
     1645                }
     1646                $rvalue = str($obj) . "->" . unquoteVariableName($this->getOpVal($op2, $EX), $EX);
     1647                if ($res['op_type'] != XC_IS_UNUSED) {
     1648                    $resvar = $rvalue;
     1649                }
     1650                if ($opc == XC_ASSIGN_OBJ) {
     1651                    ++ $i;
     1652                    $lvalue = $rvalue;
     1653                    $rvalue = $this->getOpVal($opcodes[$i]['op1'], $EX);
     1654                    $resvar = "$lvalue = " . str($rvalue);
     1655                }
     1656                break;
     1657                // }}}
     1658            case XC_ISSET_ISEMPTY_DIM_OBJ:
     1659            case XC_ISSET_ISEMPTY_PROP_OBJ:
     1660            case XC_ISSET_ISEMPTY:
     1661            case XC_ISSET_ISEMPTY_VAR: // {{{
     1662                if ($opc == XC_ISSET_ISEMPTY_VAR) {
     1663                    $rvalue = $this->getOpVal($op1, $EX);
     1664                    // for < PHP_5_3
     1665                    if ($op1['op_type'] == XC_IS_CONST) {
     1666                        $rvalue = '$' . unquoteVariableName($this->getOpVal($op1, $EX));
     1667                    }
     1668                    if ($op2['EA.type'] == ZEND_FETCH_STATIC_MEMBER) {
     1669                        $class = $this->getOpVal($op2, $EX);
     1670                        $rvalue = $class . '::' . $rvalue;
     1671                    }
     1672                }
     1673                else if ($opc == XC_ISSET_ISEMPTY) {
     1674                    $rvalue = $this->getOpVal($op1, $EX);
     1675                }
     1676                else {
     1677                    $container = $this->getOpVal($op1, $EX);
     1678                    $dim = $this->getOpVal($op2, $EX);
     1679                    if ($opc == XC_ISSET_ISEMPTY_PROP_OBJ) {
     1680                        if (!isset($container)) {
     1681                            $container = '$this';
     1682                        }
     1683                        $rvalue = $container . "->" . unquoteVariableName($dim);
     1684                    }
     1685                    else {
     1686                        $rvalue = $container . '[' . str($dim) .']';
     1687                    }
     1688                }
     1689
     1690                switch ((!ZEND_ENGINE_2 ? $op['op2']['var'] /* constant */ : $ext) & (ZEND_ISSET|ZEND_ISEMPTY)) {
     1691                case ZEND_ISSET:
     1692                    $rvalue = "isset(" . str($rvalue) . ")";
    11961693                    break;
    1197                     // }}}
    1198                 // {{{ case XC_FETCH_OBJ_*
    1199                 case XC_FETCH_OBJ_R:
    1200                 case XC_FETCH_OBJ_W:
    1201                 case XC_FETCH_OBJ_RW:
    1202                 case XC_FETCH_OBJ_FUNC_ARG:
    1203                 case XC_FETCH_OBJ_UNSET:
    1204                 case XC_FETCH_OBJ_IS:
    1205                 case XC_ASSIGN_OBJ:
     1694                case ZEND_ISEMPTY:
     1695                    $rvalue = "empty(" . str($rvalue) . ")";
     1696                    break;
     1697                }
     1698                $resvar = $rvalue;
     1699                break;
     1700                // }}}
     1701            case XC_SEND_VAR_NO_REF:
     1702            case XC_SEND_VAL:
     1703            case XC_SEND_REF:
     1704            case XC_SEND_VAR: // {{{
     1705                $ref = ($opc == XC_SEND_REF ? '&' : '');
     1706                $EX['argstack'][] = $ref . str($this->getOpVal($op1, $EX));
     1707                break;
     1708                // }}}
     1709            case XC_INIT_STATIC_METHOD_CALL:
     1710            case XC_INIT_METHOD_CALL: // {{{
     1711                array_push($EX['arg_types_stack'], array($EX['fbc'], $EX['object'], $EX['called_scope']));
     1712                if ($opc == XC_INIT_STATIC_METHOD_CALL || $opc == XC_INIT_METHOD_CALL || $op1['op_type'] != XC_IS_UNUSED) {
    12061713                    $obj = $this->getOpVal($op1, $EX);
    12071714                    if (!isset($obj)) {
    12081715                        $obj = '$this';
    12091716                    }
    1210                     $rvalue = str($obj) . "->" . unquoteVariableName($this->getOpVal($op2, $EX), $EX);
     1717                    if ($opc == XC_INIT_STATIC_METHOD_CALL || /* PHP4 */ isset($op1['constant'])) {
     1718                        $EX['object'] = null;
     1719                        $EX['called_scope'] = $this->stripNamespace(unquoteName($obj, $EX));
     1720                    }
     1721                    else {
     1722                        $EX['object'] = $obj;
     1723                        $EX['called_scope'] = null;
     1724                    }
    12111725                    if ($res['op_type'] != XC_IS_UNUSED) {
    1212                         $resvar = $rvalue;
    1213                     }
    1214                     if ($opc == XC_ASSIGN_OBJ) {
    1215                         ++ $i;
    1216                         $lvalue = $rvalue;
    1217                         $rvalue = $this->getOpVal($opcodes[$i]['op1'], $EX);
    1218                         $resvar = "$lvalue = " . str($rvalue);
    1219                     }
    1220                     break;
    1221                     // }}}
    1222                 case XC_ISSET_ISEMPTY_DIM_OBJ:
    1223                 case XC_ISSET_ISEMPTY_PROP_OBJ:
    1224                 case XC_ISSET_ISEMPTY:
    1225                 case XC_ISSET_ISEMPTY_VAR: // {{{
    1226                     if ($opc == XC_ISSET_ISEMPTY_VAR) {
    1227                         $rvalue = $this->getOpVal($op1, $EX);
    1228                         // for < PHP_5_3
    1229                         if ($op1['op_type'] == XC_IS_CONST) {
    1230                             $rvalue = '$' . unquoteVariableName($this->getOpVal($op1, $EX));
    1231                         }
    1232                         if ($op2['EA.type'] == ZEND_FETCH_STATIC_MEMBER) {
    1233                             $class = $this->getOpVal($op2, $EX);
    1234                             $rvalue = $class . '::' . $rvalue;
    1235                         }
    1236                     }
    1237                     else if ($opc == XC_ISSET_ISEMPTY) {
    1238                         $rvalue = $this->getOpVal($op1, $EX);
    1239                     }
    1240                     else {
    1241                         $container = $this->getOpVal($op1, $EX);
    1242                         $dim = $this->getOpVal($op2, $EX);
    1243                         if ($opc == XC_ISSET_ISEMPTY_PROP_OBJ) {
    1244                             if (!isset($container)) {
    1245                                 $container = '$this';
    1246                             }
    1247                             $rvalue = $container . "->" . unquoteVariableName($dim);
    1248                         }
    1249                         else {
    1250                             $rvalue = $container . '[' . str($dim) .']';
    1251                         }
    1252                     }
    1253 
    1254                     switch ((!ZEND_ENGINE_2 ? $op['op2']['var'] /* constant */ : $ext) & (ZEND_ISSET|ZEND_ISEMPTY)) {
    1255                     case ZEND_ISSET:
    1256                         $rvalue = "isset(" . str($rvalue) . ")";
    1257                         break;
    1258                     case ZEND_ISEMPTY:
    1259                         $rvalue = "empty(" . str($rvalue) . ")";
    1260                         break;
    1261                     }
    1262                     $resvar = $rvalue;
    1263                     break;
    1264                     // }}}
    1265                 case XC_SEND_VAR_NO_REF:
    1266                 case XC_SEND_VAL:
    1267                 case XC_SEND_REF:
    1268                 case XC_SEND_VAR: // {{{
    1269                     $ref = ($opc == XC_SEND_REF ? '&' : '');
    1270                     $EX['argstack'][] = $ref . str($this->getOpVal($op1, $EX));
    1271                     break;
    1272                     // }}}
    1273                 case XC_INIT_STATIC_METHOD_CALL:
    1274                 case XC_INIT_METHOD_CALL: // {{{
    1275                     array_push($EX['arg_types_stack'], array($EX['fbc'], $EX['object'], $EX['called_scope']));
    1276                     if ($opc == XC_INIT_STATIC_METHOD_CALL || $opc == XC_INIT_METHOD_CALL || $op1['op_type'] != XC_IS_UNUSED) {
    1277                         $obj = $this->getOpVal($op1, $EX);
    1278                         if (!isset($obj)) {
    1279                             $obj = '$this';
    1280                         }
    1281                         if ($opc == XC_INIT_STATIC_METHOD_CALL || /* PHP4 */ isset($op1['constant'])) {
    1282                             $EX['object'] = null;
    1283                             $EX['called_scope'] = $this->stripNamespace(unquoteName($obj, $EX));
    1284                         }
    1285                         else {
    1286                             $EX['object'] = $obj;
    1287                             $EX['called_scope'] = null;
    1288                         }
    1289                         if ($res['op_type'] != XC_IS_UNUSED) {
    1290                             $resvar = '$obj call$';
    1291                         }
    1292                     }
    1293                     else {
    1294                         $EX['object'] = null;
    1295                         $EX['called_scope'] = null;
    1296                     }
    1297 
    1298                     $EX['fbc'] = $this->getOpVal($op2, $EX, false);
    1299                     if (($opc == XC_INIT_STATIC_METHOD_CALL || $opc == XC_INIT_METHOD_CALL) && !isset($EX['fbc'])) {
    1300                         $EX['fbc'] = '__construct';
    1301                     }
    1302                     break;
    1303                     // }}}
    1304                 case XC_INIT_NS_FCALL_BY_NAME:
    1305                 case XC_INIT_FCALL_BY_NAME: // {{{
    1306                     array_push($EX['arg_types_stack'], array($EX['fbc'], $EX['object'], $EX['called_scope']));
    1307                     if (!ZEND_ENGINE_2 && ($ext & ZEND_CTOR_CALL)) {
    1308                         break;
    1309                     }
     1726                        $resvar = '$obj call$';
     1727                    }
     1728                }
     1729                else {
    13101730                    $EX['object'] = null;
    13111731                    $EX['called_scope'] = null;
    1312                     $EX['fbc'] = $this->getOpVal($op2, $EX);
     1732                }
     1733
     1734                $EX['fbc'] = $this->getOpVal($op2, $EX);
     1735                if (($opc == XC_INIT_STATIC_METHOD_CALL || $opc == XC_INIT_METHOD_CALL) && !isset($EX['fbc'])) {
     1736                    $EX['fbc'] = '__construct';
     1737                }
     1738                break;
     1739                // }}}
     1740            case XC_INIT_NS_FCALL_BY_NAME:
     1741            case XC_INIT_FCALL_BY_NAME: // {{{
     1742                array_push($EX['arg_types_stack'], array($EX['fbc'], $EX['object'], $EX['called_scope']));
     1743                if (!ZEND_ENGINE_2 && ($ext & ZEND_CTOR_CALL)) {
    13131744                    break;
    1314                     // }}}
    1315                 case XC_INIT_FCALL_BY_FUNC: // {{{ deprecated even in PHP 4?
    1316                     $EX['object'] = null;
    1317                     $EX['called_scope'] = null;
    1318                     $which = $op1['var'];
    1319                     $EX['fbc'] = $EX['op_array']['funcs'][$which]['name'];
     1745                }
     1746                $EX['object'] = null;
     1747                $EX['called_scope'] = null;
     1748                $EX['fbc'] = $this->getOpVal($op2, $EX);
     1749                break;
     1750                // }}}
     1751            case XC_INIT_FCALL_BY_FUNC: // {{{ deprecated even in PHP 4?
     1752                $EX['object'] = null;
     1753                $EX['called_scope'] = null;
     1754                $which = $op1['var'];
     1755                $EX['fbc'] = $EX['op_array']['funcs'][$which]['name'];
     1756                break;
     1757                // }}}
     1758            case XC_DO_FCALL_BY_FUNC:
     1759                $which = $op1['var'];
     1760                $fname = $EX['op_array']['funcs'][$which]['name'];
     1761                $args = $this->popargs($EX, $ext);
     1762                $resvar = $fname . "($args)";
     1763                break;
     1764            case XC_DO_FCALL:
     1765                $fname = unquoteName($this->getOpVal($op1, $EX), $EX);
     1766                $args = $this->popargs($EX, $ext);
     1767                $resvar = $fname . "($args)";
     1768                break;
     1769            case XC_DO_FCALL_BY_NAME: // {{{
     1770                $object = null;
     1771
     1772                $fname = unquoteName($EX['fbc'], $EX);
     1773                if (!is_int($EX['object'])) {
     1774                    $object = $EX['object'];
     1775                }
     1776
     1777                $args = $this->popargs($EX, $ext);
     1778
     1779                $prefix = (isset($object) ? $object . '->' : '' )
     1780                    . (isset($EX['called_scope']) ? $EX['called_scope'] . '::' : '' );
     1781                $resvar = $prefix
     1782                    . (!$prefix ? $this->stripNamespace($fname) : $fname)
     1783                    . "($args)";
     1784                unset($args);
     1785
     1786                if (is_int($EX['object'])) {
     1787                    $T[$EX['object']] = $resvar;
     1788                    $resvar = null;
     1789                }
     1790                list($EX['fbc'], $EX['object'], $EX['called_scope']) = array_pop($EX['arg_types_stack']);
     1791                break;
     1792                // }}}
     1793            case XC_VERIFY_ABSTRACT_CLASS: // {{{
     1794                //unset($T[$op1['var']]);
     1795                break;
     1796                // }}}
     1797            case XC_DECLARE_CLASS:
     1798            case XC_DECLARE_INHERITED_CLASS:
     1799            case XC_DECLARE_INHERITED_CLASS_DELAYED: // {{{
     1800                $key = $op1['constant'];
     1801                if (!isset($this->dc['class_table'][$key])) {
     1802                    echo 'class not found: ', $key, 'existing classes are:', "\n";
     1803                    var_dump(array_keys($this->dc['class_table']));
     1804                    exit;
     1805                }
     1806                $class = &$this->dc['class_table'][$key];
     1807                if (!isset($class['name'])) {
     1808                    $class['name'] = unquoteName($this->getOpVal($op2, $EX), $EX);
     1809                }
     1810                if ($opc == XC_DECLARE_INHERITED_CLASS || $opc == XC_DECLARE_INHERITED_CLASS_DELAYED) {
     1811                    $ext /= XC_SIZEOF_TEMP_VARIABLE;
     1812                    $class['parent'] = $T[$ext];
     1813                    unset($T[$ext]);
     1814                }
     1815                else {
     1816                    $class['parent'] = null;
     1817                }
     1818
     1819                for (;;) {
     1820                    if ($i + 1 <= $range[1]
     1821                     && $opcodes[$i + 1]['opcode'] == XC_ADD_INTERFACE
     1822                     && $opcodes[$i + 1]['op1']['var'] == $res['var']) {
     1823                        // continue
     1824                    }
     1825                    else if ($i + 2 <= $range[1]
     1826                     && $opcodes[$i + 2]['opcode'] == XC_ADD_INTERFACE
     1827                     && $opcodes[$i + 2]['op1']['var'] == $res['var']
     1828                     && $opcodes[$i + 1]['opcode'] == XC_FETCH_CLASS) {
     1829                        // continue
     1830                    }
     1831                    else {
     1832                        break;
     1833                    }
     1834                    $this->usedOps[XC_ADD_INTERFACE] = true;
     1835
     1836                    $fetchop = &$opcodes[$i + 1];
     1837                    $interface = $this->stripNamespace(unquoteName($this->getOpVal($fetchop['op2'], $EX), $EX));
     1838                    $addop = &$opcodes[$i + 2];
     1839                    $class['interfaces'][$addop['extended_value']] = $interface;
     1840                    unset($fetchop, $addop);
     1841                    $i += 2;
     1842                }
     1843                $this->dclass($class, $EX['indent']);
     1844                echo "\n";
     1845                unset($class);
     1846                break;
     1847                // }}}
     1848            case XC_INIT_STRING: // {{{
     1849                $resvar = "''";
     1850                break;
     1851                // }}}
     1852            case XC_ADD_CHAR:
     1853            case XC_ADD_STRING:
     1854            case XC_ADD_VAR: // {{{
     1855                $op1val = $this->getOpVal($op1, $EX);
     1856                $op2val = $this->getOpVal($op2, $EX);
     1857                switch ($opc) {
     1858                case XC_ADD_CHAR:
     1859                    $op2val = value(chr(str($op2val)));
    13201860                    break;
    1321                     // }}}
    1322                 case XC_DO_FCALL_BY_FUNC:
    1323                     $which = $op1['var'];
    1324                     $fname = $EX['op_array']['funcs'][$which]['name'];
    1325                     $args = $this->popargs($EX, $ext);
    1326                     $resvar = $fname . "($args)";
     1861                case XC_ADD_STRING:
    13271862                    break;
    1328                 case XC_DO_FCALL:
    1329                     $fname = unquoteName($this->getOpVal($op1, $EX, false), $EX);
    1330                     $args = $this->popargs($EX, $ext);
    1331                     $resvar = $fname . "($args)";
     1863                case XC_ADD_VAR:
    13321864                    break;
    1333                 case XC_DO_FCALL_BY_NAME: // {{{
    1334                     $object = null;
    1335 
    1336                     $fname = unquoteName($EX['fbc'], $EX);
    1337                     if (!is_int($EX['object'])) {
    1338                         $object = $EX['object'];
    1339                     }
    1340 
    1341                     $args = $this->popargs($EX, $ext);
    1342 
    1343                     $prefix = (isset($object) ? $object . '->' : '' )
    1344                         . (isset($EX['called_scope']) ? $EX['called_scope'] . '::' : '' );
    1345                     $resvar = $prefix
    1346                         . (!$prefix ? $this->stripNamespace($fname) : $fname)
    1347                         . "($args)";
    1348                     unset($args);
    1349 
    1350                     if (is_int($EX['object'])) {
    1351                         $T[$EX['object']] = $resvar;
    1352                         $resvar = null;
    1353                     }
    1354                     list($EX['fbc'], $EX['object'], $EX['called_scope']) = array_pop($EX['arg_types_stack']);
    1355                     break;
    1356                     // }}}
    1357                 case XC_VERIFY_ABSTRACT_CLASS: // {{{
    1358                     //unset($T[$op1['var']]);
    1359                     break;
    1360                     // }}}
    1361                 case XC_DECLARE_CLASS:
    1362                 case XC_DECLARE_INHERITED_CLASS:
    1363                 case XC_DECLARE_INHERITED_CLASS_DELAYED: // {{{
    1364                     $key = $op1['constant'];
    1365                     if (!isset($this->dc['class_table'][$key])) {
    1366                         echo 'class not found: ', $key, 'existing classes are:', "\n";
    1367                         var_dump(array_keys($this->dc['class_table']));
    1368                         exit;
    1369                     }
    1370                     $class = &$this->dc['class_table'][$key];
    1371                     if (!isset($class['name'])) {
    1372                         $class['name'] = unquoteName($this->getOpVal($op2, $EX), $EX);
    1373                     }
    1374                     if ($opc == XC_DECLARE_INHERITED_CLASS || $opc == XC_DECLARE_INHERITED_CLASS_DELAYED) {
    1375                         $ext /= XC_SIZEOF_TEMP_VARIABLE;
    1376                         $class['parent'] = $T[$ext];
    1377                         unset($T[$ext]);
     1865                }
     1866                if (str($op1val) == "''") {
     1867                    $rvalue = $op2val;
     1868                }
     1869                else if (str($op2val) == "''") {
     1870                    $rvalue = $op1val;
     1871                }
     1872                else {
     1873                    $rvalue = str($op1val) . ' . ' . str($op2val);
     1874                }
     1875                $resvar = $rvalue;
     1876                // }}}
     1877                break;
     1878            case XC_PRINT: // {{{
     1879                $op1val = $this->getOpVal($op1, $EX);
     1880                $resvar = "print(" . str($op1val) . ")";
     1881                break;
     1882                // }}}
     1883            case XC_ECHO: // {{{
     1884                $op1val = $this->getOpVal($op1, $EX);
     1885                $resvar = "echo " . str($op1val);
     1886                break;
     1887                // }}}
     1888            case XC_EXIT: // {{{
     1889                $op1val = $this->getOpVal($op1, $EX);
     1890                $resvar = "exit($op1val)";
     1891                break;
     1892                // }}}
     1893            case XC_INIT_ARRAY:
     1894            case XC_ADD_ARRAY_ELEMENT: // {{{
     1895                $rvalue = $this->getOpVal($op1, $EX, true);
     1896
     1897                if ($opc == XC_ADD_ARRAY_ELEMENT) {
     1898                    $assoc = $this->getOpVal($op2, $EX);
     1899                    if (isset($assoc)) {
     1900                        $curResVar->value[] = array($assoc, $rvalue);
    13781901                    }
    13791902                    else {
    1380                         $class['parent'] = null;
    1381                     }
    1382 
    1383                     for (;;) {
    1384                         if ($i + 1 < $ic
    1385                          && $opcodes[$i + 1]['opcode'] == XC_ADD_INTERFACE
    1386                          && $opcodes[$i + 1]['op1']['var'] == $res['var']) {
    1387                             // continue
     1903                        $curResVar->value[] = array(null, $rvalue);
     1904                    }
     1905                }
     1906                else {
     1907                    if ($opc == XC_INIT_ARRAY) {
     1908                        $resvar = new Decompiler_Array();
     1909                        if (!isset($rvalue)) {
     1910                            continue;
    13881911                        }
    1389                         else if ($i + 2 < $ic
    1390                          && $opcodes[$i + 2]['opcode'] == XC_ADD_INTERFACE
    1391                          && $opcodes[$i + 2]['op1']['var'] == $res['var']
    1392                          && $opcodes[$i + 1]['opcode'] == XC_FETCH_CLASS) {
    1393                             // continue
    1394                         }
    1395                         else {
    1396                             break;
    1397                         }
    1398                         $this->usedOps[XC_ADD_INTERFACE] = true;
    1399 
    1400                         $fetchop = &$opcodes[$i + 1];
    1401                         $interface = $this->stripNamespace(unquoteName($this->getOpVal($fetchop['op2'], $EX), $EX));
    1402                         $addop = &$opcodes[$i + 2];
    1403                         $class['interfaces'][$addop['extended_value']] = $interface;
    1404                         unset($fetchop, $addop);
    1405                         $i += 2;
    1406                     }
    1407                     $this->dclass($class);
    1408                     echo "\n";
    1409                     unset($class);
    1410                     break;
    1411                     // }}}
    1412                 case XC_INIT_STRING: // {{{
    1413                     $resvar = "''";
    1414                     break;
    1415                     // }}}
    1416                 case XC_ADD_CHAR:
    1417                 case XC_ADD_STRING:
    1418                 case XC_ADD_VAR: // {{{
     1912                    }
     1913
     1914                    $assoc = $this->getOpVal($op2, $EX);
     1915                    if (isset($assoc)) {
     1916                        $resvar->value[] = array($assoc, $rvalue);
     1917                    }
     1918                    else {
     1919                        $resvar->value[] = array(null, $rvalue);
     1920                    }
     1921                }
     1922                break;
     1923                // }}}
     1924            case XC_QM_ASSIGN: // {{{
     1925                if (isset($curResVar) && is_a($curResVar, 'Decompiler_Binop')) {
     1926                    $curResVar->op2 = $this->getOpVal($op1, $EX);
     1927                }
     1928                else {
     1929                    $resvar = $this->getOpVal($op1, $EX);
     1930                }
     1931                break;
     1932                // }}}
     1933            case XC_BOOL: // {{{
     1934                $resvar = /*'(bool) ' .*/ $this->getOpVal($op1, $EX);
     1935                break;
     1936                // }}}
     1937            case XC_RETURN: // {{{
     1938                $resvar = "return " . str($this->getOpVal($op1, $EX));
     1939                break;
     1940                // }}}
     1941            case XC_INCLUDE_OR_EVAL: // {{{
     1942                $type = $op2['var']; // hack
     1943                $keyword = $this->includeTypes[$type];
     1944                $resvar = "$keyword " . str($this->getOpVal($op1, $EX));
     1945                break;
     1946                // }}}
     1947            case XC_FE_RESET: // {{{
     1948                $resvar = $this->getOpVal($op1, $EX);
     1949                break;
     1950                // }}}
     1951            case XC_FE_FETCH: // {{{
     1952                $op['fe_src'] = $this->getOpVal($op1, $EX, true);
     1953                $fe = new Decompiler_ForeachBox($op);
     1954                $fe->iskey = false;
     1955                $T[$res['var']] = $fe;
     1956
     1957                ++ $i;
     1958                if (($ext & ZEND_FE_FETCH_WITH_KEY)) {
     1959                    $fe = new Decompiler_ForeachBox($op);
     1960                    $fe->iskey = true;
     1961
     1962                    $res = $opcodes[$i]['result'];
     1963                    $T[$res['var']] = $fe;
     1964                }
     1965                break;
     1966                // }}}
     1967            case XC_SWITCH_FREE: // {{{
     1968                break;
     1969                // }}}
     1970            case XC_FREE: // {{{
     1971                $free = $T[$op1['var']];
     1972                if (!is_a($free, 'Decompiler_Array') && !is_a($free, 'Decompiler_Box')) {
     1973                    $op['php'] = is_object($free) ? $free : $this->unquote($free, '(', ')');
     1974                    $lastphpop = &$op;
     1975                }
     1976                unset($T[$op1['var']], $free);
     1977                break;
     1978                // }}}
     1979            case XC_JMP_NO_CTOR:
     1980                break;
     1981            case XC_JMP_SET: // ?:
     1982                $resvar = new Decompiler_Binop($this, $this->getOpVal($op1, $EX), XC_JMP_SET, null);
     1983                break;
     1984            case XC_JMPZ_EX: // and
     1985            case XC_JMPNZ_EX: // or
     1986                $resvar = $this->getOpVal($op1, $EX);
     1987                break;
     1988
     1989            case XC_JMPNZ: // while
     1990            case XC_JMPZNZ: // for
     1991            case XC_JMPZ: // {{{
     1992                break;
     1993                // }}}
     1994            case XC_CONT:
     1995            case XC_BRK:
     1996                $resvar = $opc == XC_CONT ? 'continue' : 'break';
     1997                $count = str($this->getOpVal($op2, $EX));
     1998                if ($count != '1') {
     1999                    $resvar .= ' ' . $count;
     2000                }
     2001                break;
     2002            case XC_GOTO:
     2003                $resvar = 'goto label' . $op['op1']['var'];
     2004                $istmpres = false;
     2005                break;
     2006
     2007            case XC_JMP: // {{{
     2008                break;
     2009                // }}}
     2010            case XC_CASE:
     2011                // $switchValue = $this->getOpVal($op1, $EX);
     2012                $caseValue = $this->getOpVal($op2, $EX);
     2013                $resvar = $caseValue;
     2014                break;
     2015            case XC_RECV_INIT:
     2016            case XC_RECV:
     2017                $offset = $this->getOpVal($op1, $EX);
     2018                $lvalue = $this->getOpVal($op['result'], $EX);
     2019                if ($opc == XC_RECV_INIT) {
     2020                    $default = value($op['op2']['constant']);
     2021                }
     2022                else {
     2023                    $default = null;
     2024                }
     2025                $EX['recvs'][str($offset)] = array($lvalue, $default);
     2026                break;
     2027            case XC_POST_DEC:
     2028            case XC_POST_INC:
     2029            case XC_POST_DEC_OBJ:
     2030            case XC_POST_INC_OBJ:
     2031            case XC_PRE_DEC:
     2032            case XC_PRE_INC:
     2033            case XC_PRE_DEC_OBJ:
     2034            case XC_PRE_INC_OBJ: // {{{
     2035                $flags = array_flip(explode('_', $opname));
     2036                if (isset($flags['OBJ'])) {
     2037                    $resvar = $this->getOpVal($op1, $EX) . '->' . unquoteVariableName($this->getOpVal($op2, $EX), $EX);
     2038                }
     2039                else {
     2040                    $resvar = $this->getOpVal($op1, $EX);
     2041                }
     2042                $opstr = isset($flags['DEC']) ? '--' : '++';
     2043                if (isset($flags['POST'])) {
     2044                    $resvar .= $opstr;
     2045                }
     2046                else {
     2047                    $resvar = "$opstr$resvar";
     2048                }
     2049                break;
     2050                // }}}
     2051
     2052            case XC_BEGIN_SILENCE: // {{{
     2053                $EX['silence'] ++;
     2054                break;
     2055                // }}}
     2056            case XC_END_SILENCE: // {{{
     2057                $EX['silence'] --;
     2058                $lastresvar = '@' . str($lastresvar, $EX);
     2059                break;
     2060                // }}}
     2061            case XC_CAST: // {{{
     2062                $type = $ext;
     2063                static $type2cast = array(
     2064                        IS_LONG   => '(int)',
     2065                        IS_DOUBLE => '(double)',
     2066                        IS_STRING => '(string)',
     2067                        IS_ARRAY  => '(array)',
     2068                        IS_OBJECT => '(object)',
     2069                        IS_BOOL   => '(bool)',
     2070                        IS_NULL   => '(unset)',
     2071                        );
     2072                assert(isset($type2cast[$type]));
     2073                $cast = $type2cast[$type];
     2074                $resvar = $cast . ' ' . $this->getOpVal($op1, $EX);
     2075                break;
     2076                // }}}
     2077            case XC_EXT_STMT:
     2078            case XC_EXT_FCALL_BEGIN:
     2079            case XC_EXT_FCALL_END:
     2080            case XC_EXT_NOP:
     2081                break;
     2082            case XC_DECLARE_FUNCTION:
     2083                $this->dfunction($this->dc['function_table'][$op1['constant']], $EX['indent']);
     2084                break;
     2085            case XC_DECLARE_LAMBDA_FUNCTION: // {{{
     2086                ob_start();
     2087                $this->dfunction($this->dc['function_table'][$op1['constant']], $EX['indent']);
     2088                $resvar = ob_get_clean();
     2089                $istmpres = true;
     2090                break;
     2091                // }}}
     2092            case XC_DECLARE_CONST:
     2093                $name = $this->stripNamespace(unquoteName($this->getOpVal($op1, $EX), $EX));
     2094                $value = str($this->getOpVal($op2, $EX));
     2095                $resvar = 'const ' . $name . ' = ' . $value;
     2096                break;
     2097            case XC_DECLARE_FUNCTION_OR_CLASS:
     2098                /* always removed by compiler */
     2099                break;
     2100            case XC_TICKS:
     2101                $lastphpop['ticks'] = $this->getOpVal($op1, $EX);
     2102                // $EX['tickschanged'] = true;
     2103                break;
     2104            case XC_RAISE_ABSTRACT_ERROR:
     2105                // abstract function body is empty, don't need this code
     2106                break;
     2107            case XC_USER_OPCODE:
     2108                echo '// ZEND_USER_OPCODE, impossible to decompile';
     2109                break;
     2110            case XC_OP_DATA:
     2111                break;
     2112            default: // {{{
     2113                $call = array(&$this, $opname);
     2114                if (is_callable($call)) {
     2115                    $this->usedOps[$opc] = true;
     2116                    $this->{$opname}($op, $EX);
     2117                }
     2118                else if (isset($this->binops[$opc])) { // {{{
     2119                    $this->usedOps[$opc] = true;
    14192120                    $op1val = $this->getOpVal($op1, $EX);
    14202121                    $op2val = $this->getOpVal($op2, $EX);
    1421                     switch ($opc) {
    1422                     case XC_ADD_CHAR:
    1423                         $op2val = value(chr(str($op2val)));
    1424                         break;
    1425                     case XC_ADD_STRING:
    1426                         break;
    1427                     case XC_ADD_VAR:
    1428                         break;
    1429                     }
    1430                     if (str($op1val) == "''") {
    1431                         $rvalue = $op2val;
    1432                     }
    1433                     else if (str($op2val) == "''") {
    1434                         $rvalue = $op1val;
    1435                     }
    1436                     else {
    1437                         $rvalue = str($op1val) . ' . ' . str($op2val);
    1438                     }
     2122                    $rvalue = new Decompiler_Binop($this, $op1val, $opc, $op2val);
    14392123                    $resvar = $rvalue;
    14402124                    // }}}
    1441                     break;
    1442                 case XC_PRINT: // {{{
     2125                }
     2126                else if (isset($this->unaryops[$opc])) { // {{{
     2127                    $this->usedOps[$opc] = true;
    14432128                    $op1val = $this->getOpVal($op1, $EX);
    1444                     $resvar = "print(" . str($op1val) . ")";
    1445                     break;
     2129                    $myop = $this->unaryops[$opc];
     2130                    $rvalue = $myop . str($op1val);
     2131                    $resvar = $rvalue;
    14462132                    // }}}
    1447                 case XC_ECHO: // {{{
    1448                     $op1val = $this->getOpVal($op1, $EX);
    1449                     $resvar = "echo " . str($op1val);
    1450                     break;
    1451                     // }}}
    1452                 case XC_EXIT: // {{{
    1453                     $op1val = $this->getOpVal($op1, $EX);
    1454                     $resvar = "exit($op1val)";
    1455                     break;
    1456                     // }}}
    1457                 case XC_INIT_ARRAY:
    1458                 case XC_ADD_ARRAY_ELEMENT: // {{{
    1459                     $rvalue = $this->getOpVal($op1, $EX, false, true);
    1460 
    1461                     if ($opc == XC_ADD_ARRAY_ELEMENT) {
    1462                         $assoc = $this->getOpVal($op2, $EX);
    1463                         if (isset($assoc)) {
    1464                             $T[$res['var']]->value[] = array($assoc, $rvalue);
    1465                         }
    1466                         else {
    1467                             $T[$res['var']]->value[] = array(null, $rvalue);
    1468                         }
    1469                     }
    1470                     else {
    1471                         if ($opc == XC_INIT_ARRAY) {
    1472                             $resvar = new Decompiler_Array();
    1473                             if (!isset($rvalue)) {
    1474                                 continue;
    1475                             }
    1476                         }
    1477 
    1478                         $assoc = $this->getOpVal($op2, $EX);
    1479                         if (isset($assoc)) {
    1480                             $resvar->value[] = array($assoc, $rvalue);
    1481                         }
    1482                         else {
    1483                             $resvar->value[] = array(null, $rvalue);
    1484                         }
    1485                     }
    1486                     break;
    1487                     // }}}
    1488                 case XC_QM_ASSIGN: // {{{
    1489                     $resvar = $this->getOpVal($op1, $EX);
    1490                     break;
    1491                     // }}}
    1492                 case XC_BOOL: // {{{
    1493                     $resvar = /*'(bool) ' .*/ $this->getOpVal($op1, $EX);
    1494                     break;
    1495                     // }}}
    1496                 case XC_RETURN: // {{{
    1497                     $resvar = "return " . str($this->getOpVal($op1, $EX));
    1498                     break;
    1499                     // }}}
    1500                 case XC_INCLUDE_OR_EVAL: // {{{
    1501                     $type = $op2['var']; // hack
    1502                     $keyword = $this->includeTypes[$type];
    1503                     $resvar = "$keyword " . str($this->getOpVal($op1, $EX));
    1504                     break;
    1505                     // }}}
    1506                 case XC_FE_RESET: // {{{
    1507                     $resvar = $this->getOpVal($op1, $EX);
    1508                     break;
    1509                     // }}}
    1510                 case XC_FE_FETCH: // {{{
    1511                     $op['fe_src'] = $this->getOpVal($op1, $EX);
    1512                     $fe = new Decompiler_ForeachBox($op);
    1513                     $fe->iskey = false;
    1514                     $T[$res['var']] = $fe;
    1515 
    1516                     ++ $i;
    1517                     if (($ext & ZEND_FE_FETCH_WITH_KEY)) {
    1518                         $fe = new Decompiler_ForeachBox($op);
    1519                         $fe->iskey = true;
    1520 
    1521                         $res = $opcodes[$i]['result'];
    1522                         $T[$res['var']] = $fe;
    1523                     }
    1524                     break;
    1525                     // }}}
    1526                 case XC_SWITCH_FREE: // {{{
    1527                     // unset($T[$op1['var']]);
    1528                     break;
    1529                     // }}}
    1530                 case XC_FREE: // {{{
    1531                     $free = $T[$op1['var']];
    1532                     if (!is_a($free, 'Decompiler_Array') && !is_a($free, 'Decompiler_Box')) {
    1533                         $op['php'] = is_object($free) ? $free : $this->unquote($free, '(', ')');
    1534                         $lastphpop = &$op;
    1535                     }
    1536                     unset($T[$op1['var']], $free);
    1537                     break;
    1538                     // }}}
    1539                 case XC_JMP_NO_CTOR:
    1540                     break;
    1541                 case XC_JMP_SET: // ?:
    1542                     $resvar = $this->getOpVal($op1, $EX);
    1543                     $op['cond'] = $resvar;
    1544                     $op['isjmp'] = true;
    1545                     break;
    1546                 case XC_JMPNZ: // while
    1547                 case XC_JMPZNZ: // for
    1548                 case XC_JMPZ_EX: // and
    1549                 case XC_JMPNZ_EX: // or
    1550                 case XC_JMPZ: // {{{
    1551                     if ($opc == XC_JMP_NO_CTOR && $EX['object']) {
    1552                         $rvalue = $EX['object'];
    1553                     }
    1554                     else {
    1555                         $rvalue = $this->getOpVal($op1, $EX);
    1556                     }
    1557 
    1558                     if (isset($op['cond_true'])) {
    1559                         // any true comes here, so it's a "or"
    1560                         $rvalue = implode(' or ', $op['cond_true']) . ' or ' . $rvalue;
    1561                         unset($op['cond_true']);
    1562                     }
    1563                     if (isset($op['cond_false'])) {
    1564                         echo "TODO(cond_false):\n";
    1565                         var_dump($op);// exit;
    1566                     }
    1567                     if ($opc == XC_JMPZ_EX || $opc == XC_JMPNZ_EX) {
    1568                         $targetop = &$EX['opcodes'][$op2['opline_num']];
    1569                         if ($opc == XC_JMPNZ_EX) {
    1570                             $targetop['cond_true'][] = foldToCode($rvalue, $EX);
    1571                         }
    1572                         else {
    1573                             $targetop['cond_false'][] = foldToCode($rvalue, $EX);
    1574                         }
    1575                         unset($targetop);
    1576                     }
    1577                     else {
    1578                         $op['cond'] = $rvalue;
    1579                         $op['isjmp'] = true;
    1580                     }
    1581                     break;
    1582                     // }}}
    1583                 case XC_CONT:
    1584                 case XC_BRK:
    1585                     $op['cond'] = null;
    1586                     $op['isjmp'] = true;
    1587                     $resvar = $opc == XC_CONT ? 'continue' : 'break';
    1588                     $count = str($this->getOpVal($op2, $EX));
    1589                     if ($count != '1') {
    1590                         $resvar .= ' ' . $count;
    1591                     }
    1592                     break;
    1593                 case XC_GOTO:
    1594                 case XC_JMP: // {{{
    1595                     $op['cond'] = null;
    1596                     $op['isjmp'] = true;
    1597                     break;
    1598                     // }}}
    1599                 case XC_CASE:
    1600                     $switchValue = $this->getOpVal($op1, $EX);
    1601                     $caseValue = $this->getOpVal($op2, $EX);
    1602                     $resvar = str($switchValue) . ' == ' . str($caseValue);
    1603                     break;
    1604                 case XC_RECV_INIT:
    1605                 case XC_RECV:
    1606                     $offset = $this->getOpVal($op1, $EX);
    1607                     $lvalue = $this->getOpVal($op['result'], $EX);
    1608                     if ($opc == XC_RECV_INIT) {
    1609                         $default = value($op['op2']['constant']);
    1610                     }
    1611                     else {
    1612                         $default = null;
    1613                     }
    1614                     $EX['recvs'][str($offset)] = array($lvalue, $default);
    1615                     break;
    1616                 case XC_POST_DEC:
    1617                 case XC_POST_INC:
    1618                 case XC_POST_DEC_OBJ:
    1619                 case XC_POST_INC_OBJ:
    1620                 case XC_PRE_DEC:
    1621                 case XC_PRE_INC:
    1622                 case XC_PRE_DEC_OBJ:
    1623                 case XC_PRE_INC_OBJ: // {{{
    1624                     $flags = array_flip(explode('_', $opname));
    1625                     if (isset($flags['OBJ'])) {
    1626                         $resvar = $this->getOpVal($op1, $EX) . '->' . unquoteVariableName($this->getOpVal($op2, $EX), $EX);
    1627                     }
    1628                     else {
    1629                         $resvar = $this->getOpVal($op1, $EX);
    1630                     }
    1631                     $opstr = isset($flags['DEC']) ? '--' : '++';
    1632                     if (isset($flags['POST'])) {
    1633                         $resvar .= $opstr;
    1634                     }
    1635                     else {
    1636                         $resvar = "$opstr$resvar";
    1637                     }
    1638                     break;
    1639                     // }}}
    1640 
    1641                 case XC_BEGIN_SILENCE: // {{{
    1642                     $EX['silence'] ++;
    1643                     break;
    1644                     // }}}
    1645                 case XC_END_SILENCE: // {{{
    1646                     $EX['silence'] --;
    1647                     $lastresvar = '@' . str($lastresvar, $EX);
    1648                     break;
    1649                     // }}}
    1650                 case XC_CAST: // {{{
    1651                     $type = $ext;
    1652                     static $type2cast = array(
    1653                             IS_LONG   => '(int)',
    1654                             IS_DOUBLE => '(double)',
    1655                             IS_STRING => '(string)',
    1656                             IS_ARRAY  => '(array)',
    1657                             IS_OBJECT => '(object)',
    1658                             IS_BOOL   => '(bool)',
    1659                             IS_NULL   => '(unset)',
    1660                             );
    1661                     assert(isset($type2cast[$type]));
    1662                     $cast = $type2cast[$type];
    1663                     $resvar = $cast . ' ' . $this->getOpVal($op1, $EX);
    1664                     break;
    1665                     // }}}
    1666                 case XC_EXT_STMT:
    1667                 case XC_EXT_FCALL_BEGIN:
    1668                 case XC_EXT_FCALL_END:
    1669                 case XC_EXT_NOP:
    1670                     break;
    1671                 case XC_DECLARE_FUNCTION:
    1672                     $this->dfunction($this->dc['function_table'][$op1['constant']], $EX['indent']);
    1673                     break;
    1674                 case XC_DECLARE_LAMBDA_FUNCTION: // {{{
    1675                     ob_start();
    1676                     $this->dfunction($this->dc['function_table'][$op1['constant']], $EX['indent']);
    1677                     $resvar = ob_get_clean();
    1678                     $istmpres = true;
    1679                     break;
    1680                     // }}}
    1681                 case XC_DECLARE_CONST:
    1682                     $name = $this->stripNamespace(unquoteName($this->getOpVal($op1, $EX), $EX));
    1683                     $value = str($this->getOpVal($op2, $EX));
    1684                     $resvar = 'const ' . $name . ' = ' . $value;
    1685                     break;
    1686                 case XC_DECLARE_FUNCTION_OR_CLASS:
    1687                     /* always removed by compiler */
    1688                     break;
    1689                 case XC_TICKS:
    1690                     $lastphpop['ticks'] = $this->getOpVal($op1, $EX);
    1691                     // $EX['tickschanged'] = true;
    1692                     break;
    1693                 case XC_RAISE_ABSTRACT_ERROR:
    1694                     // abstract function body is empty, don't need this code
    1695                     break;
    1696                 case XC_USER_OPCODE:
    1697                     echo '// ZEND_USER_OPCODE, impossible to decompile';
    1698                     break;
    1699                 case XC_OP_DATA:
    1700                     break;
    1701                 default: // {{{
    1702                     echo "\x1B[31m * TODO ", $opname, "\x1B[0m\n";
    1703                     $covered = false;
    1704                     // }}}
    1705                 }
    1706                 if ($covered) {
    1707                     $this->usedOps[$opc] = true;
    1708                 }
    1709             }
     2133                }
     2134                else {
     2135                    $notHandled = true;
     2136                }
     2137                // }}}
     2138            }
     2139            if ($notHandled) {
     2140                echo "\x1B[31m * TODO ", $opname, "\x1B[0m\n";
     2141            }
     2142            else {
     2143                $this->usedOps[$opc] = true;
     2144            }
     2145
    17102146            if (isset($resvar)) {
    17112147                if ($istmpres) {
     
    17502186    function dumpop($op, &$EX) // {{{
    17512187    {
     2188        assert('isset($op)');
    17522189        $op1 = $op['op1'];
    17532190        $op2 = $op['op2'];
     
    17812218                if ($k == 'result') {
    17822219                    var_dump($op);
     2220                    assert(0);
    17832221                    exit;
    1784                     assert(0);
    17852222                }
    17862223                else {
     
    17902227        }
    17912228        $d[';'] = $op['extended_value'];
     2229        if (!empty($op['jmpouts'])) {
     2230            $d['>>'] = implode(',', $op['jmpouts']);
     2231        }
     2232        if (!empty($op['jmpins'])) {
     2233            $d['<<'] = implode(',', $op['jmpins']);
     2234        }
    17922235
    17932236        foreach ($d as $k => $v) {
     
    17972240    }
    17982241    // }}}
    1799     function dargs(&$EX, $indent) // {{{
     2242    function dumpRange(&$EX, $range) // {{{
     2243    {
     2244        for ($i = $range[0]; $i <= $range[1]; ++$i) {
     2245            echo $EX['indent'], $i, "\t"; $this->dumpop($EX['opcodes'][$i], $EX);
     2246        }
     2247        echo $EX['indent'], "==", PHP_EOL;
     2248    }
     2249    // }}}
     2250    function dargs(&$EX) // {{{
    18002251    {
    18012252        $op_array = &$EX['op_array'];
     
    18572308                    }
    18582309                }
    1859                 echo str($arg[0], $indent);
     2310                echo str($arg[0], $EX);
    18602311            }
    18612312            if (isset($arg[1])) {
    1862                 echo ' = ', str($arg[1], $indent);
    1863             }
    1864         }
    1865     }
    1866     // }}}
    1867     function duses(&$EX, $indent) // {{{
     2313                echo ' = ', str($arg[1], $EX);
     2314            }
     2315        }
     2316    }
     2317    // }}}
     2318    function duses(&$EX) // {{{
    18682319    {
    18692320        if ($EX['uses']) {
     
    18722323    }
    18732324    // }}}
    1874     function dfunction($func, $indent = '', $nobody = false) // {{{
     2325    function dfunction($func, $indent = '', $decorations = array(), $nobody = false) // {{{
    18752326    {
    18762327        $this->detectNamespace($func['op_array']['function_name']);
     
    18842335        else {
    18852336            ob_start();
    1886             $newindent = INDENT . $indent;
    1887             $EX = &$this->dop_array($func['op_array'], $newindent);
     2337            $EX = &$this->dop_array($func['op_array'], $indent . INDENT);
    18882338            $body = ob_get_clean();
    18892339        }
    18902340
    18912341        $functionName = $this->stripNamespace($func['op_array']['function_name']);
     2342        $isExpression = false;
    18922343        if ($functionName == '{closure}') {
    18932344            $functionName = '';
     2345            $isExpression = true;
     2346        }
     2347        echo $isExpression ? '' : $indent;
     2348        if ($decorations) {
     2349            echo implode(' ', $decorations), ' ';
    18942350        }
    18952351        echo 'function', $functionName ? ' ' . $functionName : '', '(';
    1896         $this->dargs($EX, $indent);
     2352        $this->dargs($EX);
    18972353        echo ")";
    1898         $this->duses($EX, $indent);
     2354        $this->duses($EX);
    18992355        if ($nobody) {
    19002356            echo ";\n";
    19012357        }
    19022358        else {
    1903             if ($functionName !== '') {
     2359            if (!$isExpression) {
    19042360                echo "\n";
    19052361                echo $indent, "{\n";
     
    19112367            echo $body;
    19122368            echo "$indent}";
    1913             if ($functionName !== '') {
     2369            if (!$isExpression) {
    19142370                echo "\n";
    19152371            }
     
    19272383            echo "\n";
    19282384        }
    1929         $isinterface = false;
     2385        $isInterface = false;
     2386        $decorations = array();
    19302387        if (!empty($class['ce_flags'])) {
    19312388            if ($class['ce_flags'] & ZEND_ACC_INTERFACE) {
    1932                 $isinterface = true;
     2389                $isInterface = true;
    19332390            }
    19342391            else {
    19352392                if ($class['ce_flags'] & ZEND_ACC_IMPLICIT_ABSTRACT_CLASS) {
    1936                     echo "abstract ";
     2393                    $decorations[] = "abstract";
    19372394                }
    19382395                if ($class['ce_flags'] & ZEND_ACC_FINAL_CLASS) {
    1939                     echo "final ";
    1940                 }
    1941             }
    1942         }
    1943         echo $isinterface ? 'interface ' : 'class ', $this->stripNamespace($class['name']);
     2396                    $decorations[] = "final";
     2397                }
     2398            }
     2399        }
     2400
     2401        echo $indent;
     2402        if ($decorations) {
     2403            echo implode(' ', $decorations), ' ';
     2404        }
     2405        echo $isInterface ? 'interface ' : 'class ', $this->stripNamespace($class['name']);
    19442406        if ($class['parent']) {
    19452407            echo ' extends ', $class['parent'];
     
    20552517                        echo "\n";
    20562518                    }
    2057                     echo $newindent;
    20582519                    $isAbstractMethod = false;
     2520                    $decorations = array();
    20592521                    if (isset($opa['fn_flags'])) {
    2060                         if (($opa['fn_flags'] & ZEND_ACC_ABSTRACT) && !$isinterface) {
    2061                             echo "abstract ";
     2522                        if (($opa['fn_flags'] & ZEND_ACC_ABSTRACT) && !$isInterface) {
     2523                            $decorations[] = "abstract";
    20622524                            $isAbstractMethod = true;
    20632525                        }
    20642526                        if ($opa['fn_flags'] & ZEND_ACC_FINAL) {
    2065                             echo "final ";
     2527                            $decorations[] = "final";
    20662528                        }
    20672529                        if ($opa['fn_flags'] & ZEND_ACC_STATIC) {
    2068                             echo "static ";
     2530                            $decorations[] = "static";
    20692531                        }
    20702532
    20712533                        switch ($opa['fn_flags'] & ZEND_ACC_PPP_MASK) {
    20722534                            case ZEND_ACC_PUBLIC:
    2073                                 echo "public ";
     2535                                $decorations[] = "public";
    20742536                                break;
    20752537                            case ZEND_ACC_PRIVATE:
    2076                                 echo "private ";
     2538                                $decorations[] = "private";
    20772539                                break;
    20782540                            case ZEND_ACC_PROTECTED:
    2079                                 echo "protected ";
     2541                                $decorations[] = "protected";
    20802542                                break;
    20812543                            default:
    2082                                 echo "<visibility error> ";
     2544                                $decorations[] = "<visibility error>";
    20832545                                break;
    20842546                        }
    20852547                    }
    2086                     $this->dfunction($func, $newindent, $isinterface || $isAbstractMethod);
     2548                    $this->dfunction($func, $newindent, $decorations, $isInterface || $isAbstractMethod);
    20872549                    if ($opa['function_name'] == 'Decompiler') {
    20882550                        //exit;
  • branches/1.3/decompilesample.php

    r784 r817  
    6565    /** doc */
    6666    protected function protectedMethod(ClassName $a, $b = array(
    67         array('array')
    68         ))
     67            array('array')
     68            ))
    6969    {
    7070        $runtimeArray = array('1');
     
    155155
    156156if ($late) {
    157 class LateBindingClass
    158 {}
    159 
    160 function lateBindingFunction($arg)
    161 {
    162     echo 'lateFunction';
    163 }
     157    class LateBindingClass
     158    {
     159        public function __construct()
     160        {
     161        }
     162    }
     163
     164    function lateBindingFunction($arg)
     165    {
     166        echo 'lateFunction';
     167    }
    164168}
    165169
     
    204208$a = $obj->b--;
    205209$a = --$obj->b;
    206 $a = $b xor $c;
    207210$a = !$b;
    208211$a = $b === $c;
     
    250253$a = (object) $b;
    251254// PHP6+ $a = (scalar) $b;
    252 $a = $b ? $c : $d;
    253 $a = f1() ? f2() : f3();
    254 $a = $b and $c;
    255 $a = $b or $c;
     255$a = ($b ? $c : $d);
     256$a = (f1() ? f2() : f3());
     257($a = $b) xor $c;
     258($a = $b) and $c;
     259($a = $b) or $c;
    256260$a = $b && $c;
    257261$a = $b || $c;
    258262
    259 try {
    260     echo 'outer try 1';
     263do {
    261264    try {
    262         echo 'inner try';
    263     }
    264     catch (InnerException $e) {
     265        echo 'outer try 1';
     266
     267        try {
     268            echo 'inner try';
     269        }
     270        catch (InnerException $e) {
     271            echo $e;
     272        }
     273
     274        echo 'outer try 2';
     275    }
     276    catch (OuterException $e) {
    265277        echo $e;
    266278    }
    267     echo 'outer try 2';
    268 }
    269 catch (OuterException $e) {
    270     echo $e;
    271 }
    272 
    273 if ($a) {
    274     echo 'if ($a)';
    275 }
    276 else if ($b) {
    277     echo 'else if ($b)';
     279} while (0);
     280
     281if (if_()) {
     282    echo 'if';
     283
     284    if (innerIf_()) {
     285        echo 'if innerIf';
     286    }
     287}
     288else if (elseif_()) {
     289    echo 'else if';
     290
     291    if (innerIf_()) {
     292        echo 'if innerIf';
     293    }
    278294}
    279295else {
     296    if (innerIf_()) {
     297        echo 'if innerIf';
     298    }
     299
    280300    echo 'else';
    281301}
     
    289309} while (false);
    290310
    291 for ($i = 1; $i < 10; ++$i) {
     311$i = 1;
     312
     313for (; $i < 10; ++$i) {
    292314    echo $i;
    293315    break;
     
    295317
    296318foreach ($array as $key => $value) {
    297     foreach ($array as $key => $value) {
     319    foreach ($value as $key => $value) {
    298320        echo $key . ' = ' . $value . "\n";
    299321        break 2;
     
    302324}
    303325
    304 switch ($switch) {
     326switch ($normalSwitch) {
    305327case 'case1':
    306328    echo 'case1';
     329
     330    switch ($nestedSwitch) {
     331    case 1:
     332    }
     333
    307334    break;
    308335
     
    312339
    313340default:
     341    switch ($nestedSwitch) {
     342    case 1:
     343    }
     344
    314345    echo 'default';
    315346    break;
     347}
     348
     349switch ($switchWithoutDefault) {
     350case 'case1':
     351    echo 'case1';
     352    break;
     353
     354case 'case2':
     355    echo 'case2';
     356    break;
     357}
     358
     359switch ($switchWithMiddleDefault) {
     360case 'case1':
     361    echo 'case1';
     362    break;
     363
     364default:
     365    echo 'default';
     366    break;
     367
     368case 'case2':
     369    echo 'case2';
     370    break;
     371}
     372
     373switch ($switchWithInitialDefault) {
     374default:
     375    echo 'default';
     376    break;
     377
     378case 'case1':
     379    echo 'case1';
     380    break;
     381
     382case 'case2':
     383    echo 'case2';
     384    break;
     385}
     386
     387switch (emptySwitch()) {
     388}
     389
     390switch (emptySwitch()) {
     391default:
    316392}
    317393
    318394declare (ticks=1) {
    319395    echo 1;
    320     echo 2;
     396    while (1) {
     397        echo 2;
     398    }
    321399}
    322400
     
    336414$this::__construct();
    337415$obj::__construct();
    338 
    339416$a = $b ?: $d;
    340417$a = ($b ?: $d) + $c;
    341418$a = f1() ?: f2();
     419$a = ($b ? $c : $d);
     420$a = ($b ? $c : $d) + $c;
     421$a = (f1() ? f3() : f2());
     422
     423if ($b ?: $d) {
     424    echo 'if ($b ?: $d)';
     425}
     426
     427if (($b ?: $d) + $c) {
     428    echo 'if (($b ?: $d) + $c)';
     429}
     430
     431if (f1() ?: f2()) {
     432    echo 'if (f1() ?: f2())';
     433}
    342434
    343435echo 'goto a';
    344436goto a;
    345437
    346 for ($i = 1; $i <= 2; ++$i) {
     438$i = 1;
     439
     440for (; $i <= 2; ++$i) {
    347441    goto a;
    348442}
     
    350444a:
    351445echo 'label a';
    352 echo preg_replace_callback('~-([a-z])~', function ($match) {
     446echo preg_replace_callback('~-([a-z])~', function($match) {
    353447    return strtoupper($match[1]);
    354448}, 'hello-world');
    355 $greet = function ($name) {
     449$greet = function($name) {
    356450    printf("Hello %s\r\n", $name);
    357451};
  • branches/1.3/processor/main.m4

    r726 r817  
    165165dnl {{{ COPYNULL(1:elm)
    166166define(`COPYNULL', `
    167     COPYNULL_EX(`dst->$1', `$2')DONE(`$1')
     167    COPYNULL_EX(`dst->$1', `$1')DONE(`$1')
    168168')
    169169dnl }}}
  • branches/1.3/utils.c

    r784 r817  
    150150#endif
    151151            case ZEND_JMP:
    152                 assert(Z_OP(opline->op1).jmp_addr - op_array->opcodes < op_array->last);
     152                assert(Z_OP(opline->op1).jmp_addr >= op_array->opcodes && Z_OP(opline->op1).jmp_addr - op_array->opcodes < op_array->last);
    153153                Z_OP(opline->op1).opline_num = Z_OP(opline->op1).jmp_addr - op_array->opcodes;
    154154                break;
     
    160160            case ZEND_JMP_SET:
    161161#endif
    162                 assert(Z_OP(opline->op2).jmp_addr - op_array->opcodes < op_array->last);
     162                assert(Z_OP(opline->op2).jmp_addr >= op_array->opcodes && Z_OP(opline->op2).jmp_addr - op_array->opcodes < op_array->last);
    163163                Z_OP(opline->op2).opline_num = Z_OP(opline->op2).jmp_addr - op_array->opcodes;
    164164                break;
Note: See TracChangeset for help on using the changeset viewer.