Browse Source

Decompiler: simple cover test, make sure all opcode is tested

git-svn-id: svn://svn.lighttpd.net/xcache/trunk@761 c26eb9a1-5813-0410-bd6c-c2e55f420ca7
3.0
Xuefer 11 years ago
parent
commit
1be06bf44c
  1. 87
      Decompiler.class.php
  2. 45
      decompilesample.php

87
Decompiler.class.php

@ -70,13 +70,13 @@ function value($value) // {{{
return $value;
}
// }}}
function unquoteName_($str, $asProperty, $indent = '') // {{{
function unquoteName_($str, $asVariableName, $indent = '') // {{{
{
$str = str($str, $indent);
if (preg_match("!^'[\\w_][\\w\\d_\\\\]*'\$!", $str)) {
return str_replace('\\\\', '\\', substr($str, 1, -1));
}
else if ($asProperty) {
else if ($asVariableName) {
return "{" . $str . "}";
}
else {
@ -84,7 +84,7 @@ function unquoteName_($str, $asProperty, $indent = '') // {{{
}
}
// }}}
function unquoteProperty($str, $indent = '') // {{{
function unquoteVariableName($str, $indent = '') // {{{
{
return unquoteName_($str, true, $indent);
}
@ -246,7 +246,7 @@ class Decompiler_Dim extends Decompiler_Value // {{{
$last = count($this->offsets) - 1;
foreach ($this->offsets as $i => $dim) {
if ($this->isObject && $i == $last) {
$exp .= '->' . unquoteProperty($dim, $indent);
$exp .= '->' . unquoteVariableName($dim, $indent);
}
else {
$exp .= '[' . str($dim, $indent) . ']';
@ -436,6 +436,20 @@ class Decompiler
function Decompiler()
{
// {{{ testing
// XC_UNDEF XC_OP_DATA
$this->test = !empty($_ENV['XCACHE_DECOMPILER_TEST']);
$this->usedOps = array();
if ($this->test) {
$content = file_get_contents(__FILE__);
for ($i = 0; $opname = xcache_get_opcode($i); $i ++) {
if (!preg_match("/\\bXC_" . $opname . "\\b(?!')/", $content)) {
echo "not recognized opcode ", $opname, "\n";
}
}
}
// }}}
// {{{ opinfo
$this->unaryops = array(
XC_BW_NOT => '~',
@ -618,6 +632,7 @@ class Decompiler
if ($removeTailing) {
$last = count($opcodes) - 1;
if ($opcodes[$last]['opcode'] == XC_HANDLE_EXCEPTION) {
$this->usedOps[XC_HANDLE_EXCEPTION] = true;
unset($opcodes[$last]);
--$last;
}
@ -881,6 +896,7 @@ class Decompiler
$op = &$opcodes[$i];
$opc = $op['opcode'];
if ($opc == XC_NOP) {
$this->usedOps[$opc] = true;
continue;
}
@ -910,9 +926,11 @@ class Decompiler
$call = array(&$this, $opname);
if (is_callable($call)) {
$this->usedOps[$opc] = true;
$this->{$opname}($op, $EX);
}
else if (isset($this->binops[$opc])) { // {{{
$this->usedOps[$opc] = true;
$op1val = $this->getOpVal($op1, $EX, false);
$op2val = $this->getOpVal($op2, $EX, false);
$rvalue = new Decompiler_Binop($this, $op1val, $opc, $op2val);
@ -920,6 +938,7 @@ class Decompiler
// }}}
}
else if (isset($this->unaryops[$opc])) { // {{{
$this->usedOps[$opc] = true;
$op1val = $this->getOpVal($op1, $EX);
$myop = $this->unaryops[$opc];
$rvalue = $myop . str($op1val);
@ -927,6 +946,7 @@ class Decompiler
// }}}
}
else {
$covered = true;
switch ($opc) {
case XC_NEW: // {{{
array_push($EX['arg_types_stack'], array($EX['fbc'], $EX['object'], $EX['called_scope']));
@ -1164,7 +1184,7 @@ class Decompiler
if (!isset($obj)) {
$obj = '$this';
}
$rvalue = str($obj) . "->" . unquoteProperty($this->getOpVal($op2, $EX), $EX);
$rvalue = str($obj) . "->" . unquoteVariableName($this->getOpVal($op2, $EX), $EX);
if ($res['op_type'] != XC_IS_UNUSED) {
$resvar = $rvalue;
}
@ -1181,13 +1201,7 @@ class Decompiler
case XC_ISSET_ISEMPTY:
case XC_ISSET_ISEMPTY_VAR: // {{{
if ($opc == XC_ISSET_ISEMPTY_VAR) {
$rvalue = $this->getOpVal($op1, $EX);;
if (preg_match($this->rQuotedName, $rvalue)) {
$rvalue = '$' . substr($rvalue, 1, -1);
}
else {
$rvalue = '${' . $rvalue . '}';
}
$rvalue = $this->getOpVal($op1, $EX);
if ($op2['EA.type'] == ZEND_FETCH_STATIC_MEMBER) {
$class = $this->getOpVal($op2, $EX);
$rvalue = $class . '::' . $rvalue;
@ -1200,15 +1214,13 @@ class Decompiler
$container = $this->getOpVal($op1, $EX);
$dim = $this->getOpVal($op2, $EX);
if ($opc == XC_ISSET_ISEMPTY_PROP_OBJ) {
if (preg_match($this->rQuotedName, $dim)) {
$rvalue = $container . "->" . substr($dim, 1, -1);
}
else {
$rvalue = $container . "->{" . $dim . "}";
if (!isset($container)) {
$container = '$this';
}
$rvalue = $container . "->" . unquoteVariableName($dim);
}
else {
$rvalue = $container . "[$dim]";
$rvalue = $container . '[' . str($dim) .']';
}
}
@ -1356,6 +1368,7 @@ class Decompiler
else {
break;
}
$this->usedOps[XC_ADD_INTERFACE] = true;
$fetchop = &$opcodes[$i + 1];
$interface = $this->stripNamespace(unquoteName($this->getOpVal($fetchop['op2'], $EX), $EX));
@ -1401,7 +1414,7 @@ class Decompiler
break;
case XC_PRINT: // {{{
$op1val = $this->getOpVal($op1, $EX);
$resvar = "print($op1val)";
$resvar = "print(" . str($op1val) . ")";
break;
// }}}
case XC_ECHO: // {{{
@ -1583,7 +1596,7 @@ class Decompiler
case XC_PRE_INC_OBJ: // {{{
$flags = array_flip(explode('_', $opname));
if (isset($flags['OBJ'])) {
$resvar = $this->getOpVal($op1, $EX) . '->' . unquoteProperty($this->getOpVal($op2, $EX), $EX);
$resvar = $this->getOpVal($op1, $EX) . '->' . unquoteVariableName($this->getOpVal($op2, $EX), $EX);
}
else {
$resvar = $this->getOpVal($op1, $EX);
@ -1660,8 +1673,12 @@ class Decompiler
break;
default: // {{{
echo "\x1B[31m * TODO ", $opname, "\x1B[0m\n";
$covered = false;
// }}}
}
if ($covered) {
$this->usedOps[$opc] = true;
}
}
if (isset($resvar)) {
if ($istmpres) {
@ -2078,9 +2095,26 @@ class Decompiler
$this->dop_array($this->dc['op_array']);
echo "\n?" . ">\n";
if (!empty($this->test)) {
$this->outputUnusedOp();
}
return true;
}
// }}}
function outputUnusedOp() // {{{
{
for ($i = 0; $opname = xcache_get_opcode($i); $i ++) {
if ($opname == 'UNDEF') {
continue;
}
if (!isset($this->usedOps[$i])) {
echo "not covered opcode ", $opname, "\n";
}
}
}
// }}}
}
// {{{ defines
@ -2186,10 +2220,10 @@ define('BYREF_FORCE_REST', 3);
define('IS_NULL', 0);
define('IS_LONG', 1);
define('IS_DOUBLE', 2);
define('IS_STRING', 3);
define('IS_BOOL', ZEND_ENGINE_2 ? 3 : 6);
define('IS_ARRAY', 4);
define('IS_OBJECT', 5);
define('IS_BOOL', 6);
define('IS_STRING', ZEND_ENGINE_2 ? 6 : 3);
define('IS_RESOURCE', 7);
define('IS_CONSTANT', 8);
define('IS_CONSTANT_ARRAY', 9);
@ -2256,14 +2290,5 @@ foreach (array (
define($k, $v);
}
}
//* XC_UNDEF XC_OP_DATA
$content = file_get_contents(__FILE__);
for ($i = 0; $opname = xcache_get_opcode($i); $i ++) {
if (!preg_match("/\\bXC_" . $opname . "\\b(?!')/", $content)) {
echo "not done ", $opname, "\n";
}
}
// */
// }}}

45
decompilesample.php

@ -205,6 +205,50 @@ $a = $obj->b--;
$a = --$obj->b;
$a = $b xor $c;
$a = !$b;
$a = $b === $c;
$a = $b !== $c;
$a = $b << 2;
$a = $b >> 3;
$a += $b;
$a -= $b;
$a *= $b;
$a /= $b;
$a <<= $b;
$a >>= $b;
$a &= $b;
$a |= $b;
$a .= $b;
$a %= $b;
$a ^= $b;
$a = 'a' . 'b';
$a = 'a' . 'abc';
@f1();
print('1');
ref(&$a);
$a = $array['index'];
$a = $object->prop;
$a = $this->prop;
$array['index'] = 1;
$object->prop = 1;
$this->prop = 1;
$a = isset($b);
$a = empty($b);
$a = isset($array['index']);
$a = empty($array['index']);
$a = isset($object->prop);
$a = empty($object->prop);
$a = isset($this->prop);
$a = empty($this->prop);
$a = (int) $b;
$a = (double) $b;
$a = (string) $b;
$a = (array) $b;
$a = (object) $b;
$a = (bool) $b;
$a = (unset) $b;
$a = (array) $b;
$a = (object) $b;
// PHP6+ $a = (scalar) $b;
$a = $b ? $c : $d;
$a = f1() ? f2() : f3();
$a = $b and $c;
@ -322,5 +366,6 @@ $callback = function ($quantity, $product) use ($tax, &$total) {
$total += $pricePerItem * $quantity * ($tax + 1);
};
// */
exit();
?>

Loading…
Cancel
Save