禁止 foreach 中添加全局变量的同名变量

pull/1/head
韩天峰 8 months ago
parent bf09f600ba
commit 74a3778426
  1. 178
      examples/spectralnorm.php
  2. 15
      src/Php/Translator.php
  3. 1
      src/functions.php

@ -0,0 +1,178 @@
<?php
/*
The Computer Language Benchmarks Game
https://salsa.debian.org/benchmarksgame-team/benchmarksgame/
contributed by Nikita Popov
*/
function A($i, $j)
{
return 1.0 / (((($i + $j) * ($i + $j + 1)) >> 1) + $i + 1);
}
function Av($n, $v, $start, $end)
{
global $_tpl;
$Av = $_tpl;
for ($i = $start; $i < $end; ++$i) {
$sum = 0.0;
foreach ($v as $j => $v_j) {
$sum += A($i, $j) * $v_j;
}
$Av[$i] = $sum;
}
return $Av;
}
function Atv($n, $v, $start, $end)
{
global $_tpl;
$Atv = $_tpl;
for ($i = $start; $i < $end; ++$i) {
$sum = 0.0;
foreach ($v as $j => $v_j) {
$sum += A($j, $i) * $v_j;
}
$Atv[$i] = $sum;
}
return $Atv;
}
function AtAv($n, $v, $start, $end, $sync)
{
$tmp = Av($n, $v, $start, $end);
if ($sync) $tmp = sync($tmp);
$tmp = Atv($n, $tmp, $start, $end);
if ($sync) $tmp = sync($tmp);
return $tmp;
}
function sync($tmp)
{
global $parent, $chunk_data_size, $total_data_size, $pipe, $pipes;
if (!$parent) {
$data = call_user_func_array('pack', array_merge(['d*'], $tmp));
safe_write($pipe, $data);
return array_values(unpack('d*', safe_read($pipe, $total_data_size)));
} else {
$tmps = array();
foreach ($pipes as $_pipe) {
$tmps[] = unpack('d*', safe_read($_pipe, $chunk_data_size));
}
$tmps[] = $tmp;
$tmp = call_user_func_array('array_merge', $tmps);
$data = call_user_func_array('pack', array_merge(['d*'], $tmp));
foreach ($pipes as $_pipe) {
safe_write($_pipe, $data);
}
return $tmp;
}
}
function safe_write($fd, $data)
{
$len = strlen($data);
do {
$w = fwrite($fd, $data);
$len -= $w;
} while ($len && ($data = substr($data, $w)) !== FALSE);
}
function safe_read($fd, $len)
{
$data = '';
while ($len > 0) {
$d = fread($fd, $len);
$len -= strlen($d);
$data .= $d;
}
return $data;
}
function pipe()
{
return stream_socket_pair(STREAM_PF_UNIX, STREAM_SOCK_STREAM, 0);
}
function main()
{
$begin = microtime(TRUE);
global $argc, $argv, $parent, $chunk_data_size, $total_data_size, $pipe, $pipes, $_tpl;
$n = $argc > 2 ? $argv[2] : 1;
$procs = 1;
if (file_exists('/proc/cpuinfo')) {
$procs = preg_match_all('/^processor\s/m', file_get_contents('/proc/cpuinfo'), $discard);
}
if ($n < $procs) {
$procs = 1;
}
$chunk_size = (int)($n / $procs);
$double_size = strlen(pack('d', 0.0));
$chunk_data_size = $double_size * $chunk_size;
$total_data_size = $double_size * $n;
$pipes = array();
$parent = FALSE;
for ($i = 0; $i < $procs; ++$i) {
$range_begin = $i * $chunk_size;
if ($i < ($procs - 1)) {
$pipe = pipe();
if (!$pipe) {
die('could not create pipe');
}
$pipes[] = $pipe[0];
$pipe = $pipe[1];
$range_end = $range_begin + $chunk_size;
$pid = pcntl_fork();
if ($pid === -1) {
die('could not fork');
} else if ($pid) {
continue;
}
break;
} else {
$range_end = $n;
$parent = TRUE;
}
}
$u = array_fill(0, $n, 1.0);
$_tpl = array_fill($range_begin, $range_end - $range_begin, 0.0);
$sync = $procs > 0;
for ($i = 0; $i < 10; $i++) {
$v = AtAv($n, $u, $range_begin, $range_end, $sync);
$u = AtAv($n, $v, $range_begin, $range_end, $sync);
}
if (!$parent) {
exit(0);
}
$childs = $procs - 1;
while ($childs--) {
pcntl_wait($s);
}
$vBv = 0.0;
$vv = 0.0;
$i = 0;
foreach ($v as $val) {
$vBv += $u[$i] * $val;
$vv += $val * $val;
++$i;
}
printf("%0.9f\n", sqrt($vBv / $vv));
printf("Time: %.9f\n", microtime(TRUE) - $begin);
}

@ -1334,8 +1334,8 @@ class Translator extends \PhpAot\Core\Translator
if (!$this->hasVar($name)) { if (!$this->hasVar($name)) {
$this->addLocalVar($name, self::TYPE_REF); $this->addLocalVar($name, self::TYPE_REF);
$this->beforeStmtLines[] = $name . ' = php::newReference();'; $this->beforeStmtLines[] = $name . ' = php::newReference();';
} else if ($funcName) { } else if (!$nativeFunction and $funcName) {
$funcArg = Reflection::getFunctionParameter($funcName, 0); $funcArg = Reflection::getFunctionParameter($funcName, $i);
// 需要引用类型的参数,使用临时变量作为引用,并替换掉实际的参数 // 需要引用类型的参数,使用临时变量作为引用,并替换掉实际的参数
if ($funcArg and $funcArg->isPassedByReference()) { if ($funcArg and $funcArg->isPassedByReference()) {
$tmpVar = $this->genTmpVarName(); $tmpVar = $this->genTmpVarName();
@ -1733,6 +1733,11 @@ class Translator extends \PhpAot\Core\Translator
} }
} }
private function unescapeVarName(string $name)
{
return str_replace('_php__var__', '', $name);
}
private function parseInterpolatedStringPart(Node $expr): string private function parseInterpolatedStringPart(Node $expr): string
{ {
return '"' . $this->escapeString($expr->value) . '"'; return '"' . $this->escapeString($expr->value) . '"';
@ -1844,6 +1849,9 @@ class Translator extends \PhpAot\Core\Translator
$code .= 'for (auto iter = ' . $iteratorVar . '.begin(); iter != ' . $iteratorVar . '.end(); ++iter) {' . PHP_EOL; $code .= 'for (auto iter = ' . $iteratorVar . '.begin(); iter != ' . $iteratorVar . '.end(); ++iter) {' . PHP_EOL;
$this->indentLevel++; $this->indentLevel++;
if ($node->keyVar) { if ($node->keyVar) {
if ($this->hasGlobalVar($keyVar)) {
$this->fatalError($node->keyVar, 'Cannot redefine key variable: ' . $this->unescapeVarName($keyVar));
}
$code .= $this->getIndent() . self::TYPE_VAR . ' ' . $keyVar . ' = iter.key();' . PHP_EOL; $code .= $this->getIndent() . self::TYPE_VAR . ' ' . $keyVar . ' = iter.key();' . PHP_EOL;
$this->addLocalVar($keyVar, self::TYPE_VAR); $this->addLocalVar($keyVar, self::TYPE_VAR);
} }
@ -1856,6 +1864,9 @@ class Translator extends \PhpAot\Core\Translator
$dim = $this->parseIdentifier($node->valueVar->dim); $dim = $this->parseIdentifier($node->valueVar->dim);
$code .= $this->getIndent() . "$array.offsetSet($dim, iter.value());"; $code .= $this->getIndent() . "$array.offsetSet($dim, iter.value());";
} else { } else {
if ($this->hasGlobalVar($valueVar)) {
$this->fatalError($node->valueVar, 'Cannot redefine value variable: ' . $this->unescapeVarName($valueVar));
}
$code .= $this->getIndent() . self::TYPE_VAR . ' ' . $valueVar . ' = iter.value();' . PHP_EOL; $code .= $this->getIndent() . self::TYPE_VAR . ' ' . $valueVar . ' = iter.value();' . PHP_EOL;
$this->addLocalVar($valueVar, self::TYPE_VAR); $this->addLocalVar($valueVar, self::TYPE_VAR);
} }

@ -43,5 +43,6 @@ function debug()
foreach(func_get_args() as $arg) { foreach(func_get_args() as $arg) {
var_dump($arg); var_dump($arg);
} }
debug_print_backtrace();
exit; exit;
} }
Loading…
Cancel
Save