1
0
Fork 0

Decompiler: ?: and ? :

git-svn-id: svn://svn.lighttpd.net/xcache/trunk@799 c26eb9a1-5813-0410-bd6c-c2e55f420ca7
This commit is contained in:
Xuefer 2011-04-26 08:50:28 +00:00
parent 79015d6a30
commit 674e498132
2 changed files with 87 additions and 17 deletions

View File

@ -149,7 +149,6 @@ class Decompiler_Binop extends Decompiler_Code // {{{
var $op1;
var $op2;
var $parent;
var $indent;
function Decompiler_Binop($parent, $op1, $opc, $op2)
{
@ -163,20 +162,53 @@ class Decompiler_Binop extends Decompiler_Code // {{{
{
$opstr = $this->parent->binops[$this->opc];
$op1 = foldToCode($this->op1, $indent);
if (is_a($this->op1, 'Decompiler_Binop') && $this->op1->opc != $this->opc) {
$op1 = "(" . str($op1, $indent) . ")";
if (is_a($this->op1, 'Decompiler_TriOp') || is_a($this->op1, 'Decompiler_Binop') && $this->op1->opc != $this->opc) {
$op1 = "(" . str($this->op1, $indent) . ")";
}
$op2 = foldToCode($this->op2, $indent);
if (is_a($this->op2, 'Decompiler_Binop') && $this->op2->opc != $this->opc && substr($opstr, -1) != '=') {
$op2 = "(" . str($op2, $indent) . ")";
else {
$op1 = $this->op1;
}
if (is_a($this->op2, 'Decompiler_TriOp') || is_a($this->op2, 'Decompiler_Binop') && $this->op2->opc != $this->opc && substr($opstr, -1) != '=') {
$op2 = "(" . str($this->op2, $indent) . ")";
}
else {
$op2 = $this->op2;
}
if (str($op1) == '0' && ($this->opc == XC_ADD || $this->opc == XC_SUB)) {
return $opstr . str($op2, $indent);
}
return str($op1) . ' ' . $opstr . ' ' . str($op2);
return str($op1, $indent) . ' ' . $opstr . ' ' . str($op2, $indent);
}
}
// }}}
class Decompiler_TriOp extends Decompiler_Code // {{{
{
var $condition;
var $trueValue;
var $falseValue;
function Decompiler_TriOp($condition, $trueValue, $falseValue)
{
$this->condition = $condition;
$this->trueValue = $trueValue;
$this->falseValue = $falseValue;
}
function toCode($indent)
{
$trueValue = $this->trueValue;
if (is_a($this->trueValue, 'Decompiler_TriOp')) {
$trueValue = "(" . str($trueValue, $indent) . ")";
}
$falseValue = $this->falseValue;
if (is_a($this->falseValue, 'Decompiler_TriOp')) {
$falseValue = "(" . str($falseValue, $indent) . ")";
}
return str($this->condition) . ' ? ' . str($trueValue) . ' : ' . str($falseValue);
}
}
// }}}
@ -485,6 +517,7 @@ class Decompiler
XC_BW_XOR => "^",
XC_ASSIGN_BW_XOR => "^=",
XC_BOOL_XOR => "xor",
XC_JMP_SET => "?:",
);
// }}}
$this->includeTypes = array( // {{{
@ -706,6 +739,28 @@ class Decompiler
$firstOp = &$opcodes[$first];
$lastOp = &$opcodes[$last];
// {{{ ?: excludign JMP_SET
if ($firstOp['opcode'] == XC_JMPZ && !empty($firstOp['jmpouts'])
&& $last >= $first + 3
&& $opcodes[$firstOp['jmpouts'][0] - 2]['opcode'] == XC_QM_ASSIGN
&& $opcodes[$firstOp['jmpouts'][0] - 1]['opcode'] == XC_JMP && $opcodes[$firstOp['jmpouts'][0] - 1]['jmpouts'][0] == $last + 1
&& $lastOp['opcode'] == XC_QM_ASSIGN
) {
$trueFirst = $first + 1;
$trueLast = $firstOp['jmpouts'][0] - 2;
$falseFirst = $firstOp['jmpouts'][0];
$falseLast = $last;
$this->removeJmpInfo($EX, $first);
$condition = $this->getOpVal($firstOp['op1'], $EX);
$this->recognizeAndDecompileClosedBlocks($EX, $trueFirst, $trueLast, $indent . INDENT);
$trueValue = $this->getOpVal($opcodes[$trueLast]['op1'], $EX, false, true);
$this->recognizeAndDecompileClosedBlocks($EX, $falseFirst, $falseLast, $indent . INDENT);
$falseValue = $this->getOpVal($opcodes[$falseLast]['op1'], $EX, false, true);
$T[$opcodes[$trueLast]['result']['var']] = new Decompiler_TriOp($condition, $trueValue, $falseValue);
return false;
}
// }}}
// {{{ try/catch
if (!empty($firstOp['jmpins']) && !empty($opcodes[$firstOp['jmpins'][0]]['isCatchBegin'])) {
$catchBlocks = array();
@ -973,7 +1028,12 @@ class Decompiler
if ($blockFirst > $starti) {
$this->decompileBasicBlock($EX, $starti, $blockFirst - 1, $indent);
}
$this->decompileComplexBlock($EX, $blockFirst, $blockLast, $indent);
if ($this->decompileComplexBlock($EX, $blockFirst, $blockLast, $indent) === false) {
if ($EX['lastBlock'] == 'complex') {
echo PHP_EOL;
}
$EX['lastBlock'] = null;
}
$starti = $blockLast + 1;
$i = $starti;
}
@ -1029,7 +1089,7 @@ class Decompiler
case XC_JMPNZ:
case XC_JMPZ_EX:
case XC_JMPNZ_EX:
case XC_JMP_SET:
// case XC_JMP_SET:
// case XC_FE_RESET:
case XC_FE_FETCH:
// case XC_JMP_NO_CTOR:
@ -1110,6 +1170,7 @@ class Decompiler
$EX['silence'] = 0;
$EX['recvs'] = array();
$EX['uses'] = array();
$EX['lastBlock'] = null;
$first = 0;
$last = count($opcodes) - 1;
@ -1273,6 +1334,10 @@ class Decompiler
// echo $i, ' '; $this->dumpop($op, $EX); //var_dump($op);
$resvar = null;
unset($curResVar);
if (array_key_exists($res['var'], $T)) {
$curResVar = &$T[$res['var']];
}
if ((ZEND_ENGINE_2_4 ? ($res['op_type'] & EXT_TYPE_UNUSED) : ($res['EA.type'] & EXT_TYPE_UNUSED)) || $res['op_type'] == XC_IS_UNUSED) {
$istmpres = false;
}
@ -1816,10 +1881,10 @@ class Decompiler
if ($opc == XC_ADD_ARRAY_ELEMENT) {
$assoc = $this->getOpVal($op2, $EX);
if (isset($assoc)) {
$T[$res['var']]->value[] = array($assoc, $rvalue);
$curResVar->value[] = array($assoc, $rvalue);
}
else {
$T[$res['var']]->value[] = array(null, $rvalue);
$curResVar->value[] = array(null, $rvalue);
}
}
else {
@ -1841,7 +1906,12 @@ class Decompiler
break;
// }}}
case XC_QM_ASSIGN: // {{{
$resvar = $this->getOpVal($op1, $EX);
if (isset($curResVar) && is_a($curResVar, 'Decompiler_Binop')) {
$curResVar->op2 = $this->getOpVal($op1, $EX);
}
else {
$resvar = $this->getOpVal($op1, $EX);
}
break;
// }}}
case XC_BOOL: // {{{
@ -1893,9 +1963,7 @@ class Decompiler
case XC_JMP_NO_CTOR:
break;
case XC_JMP_SET: // ?:
$resvar = $this->getOpVal($op1, $EX);
$op['cond'] = $resvar;
$op['isjmp'] = true;
$resvar = new Decompiler_Binop($this, $this->getOpVal($op1, $EX), XC_JMP_SET, null);
break;
case XC_JMPNZ: // while
case XC_JMPZNZ: // for

View File

@ -404,10 +404,12 @@ echo $a::CONST_VALUE;
echo CONST_VALUE;
$this::__construct();
$obj::__construct();
$a = $b ?: $d;
$a = ($b ?: $d) + $c;
$a = f1() ?: f2();
$a = $b ? $c : $d;
$a = ($b ? $c : $d) + $c;
$a = f1() ? f3() : f2();
if ($b ?: $d) {
echo 'if ($b ?: $d)';