Skip to content

Commit

Permalink
Allowing to call methods/functions passing values by reference, more …
Browse files Browse the repository at this point in the history
…aggresive detect of functions/methods that don't allow pass global constants
  • Loading branch information
phalcon committed Aug 13, 2014
1 parent b44411d commit ffbdf9f
Show file tree
Hide file tree
Showing 7 changed files with 94 additions and 28 deletions.
59 changes: 49 additions & 10 deletions Library/Call.php
Original file line number Diff line number Diff line change
Expand Up @@ -292,20 +292,20 @@ public function getResolvedParamsAsExpr($parameters, CompilationContext $compila
* @param array $calleeDefinition
* @return array
*/
public function getResolvedParams($parameters, CompilationContext $compilationContext, $expression, $calleeDefinition = null)
public function getResolvedParams($parameters, CompilationContext $compilationContext, array $expression, $calleeDefinition = null)
{
$codePrinter = &$compilationContext->codePrinter;
$exprParams = $this->getResolvedParamsAsExpr($parameters, $compilationContext, $expression);

/**
* Static typed parameters in final methods are promotable to read only parameters
* Static typed parameters in final/private methods are promotable to read only parameters
* Recursive calls with static typed methods also also promotable
*/
$isFinal = false;
$readOnlyParameters = array();
if (is_object($calleeDefinition)) {
if ($calleeDefinition instanceof ClassMethod) {
if ($calleeDefinition->isFinal() || $compilationContext->currentMethod == $calleeDefinition) {
if ($calleeDefinition->isFinal() || $calleeDefinition->isPrivate() || $compilationContext->currentMethod == $calleeDefinition) {
$isFinal = true;
foreach ($calleeDefinition->getParameters() as $position => $parameter) {
if (isset($parameter['data-type'])) {
Expand All @@ -316,6 +316,8 @@ public function getResolvedParams($parameters, CompilationContext $compilationCo
case 'long':
case 'char':
case 'uchar':
case 'boolean':
case 'bool':
$readOnlyParameters[$position] = true;
break;
}
Expand All @@ -335,7 +337,15 @@ public function getResolvedParams($parameters, CompilationContext $compilationCo
switch ($compiledExpression->getType()) {

case 'null':
$params[] = 'ZEPHIR_GLOBAL(global_null)';
if (isset($readOnlyParameters[$position])) {
$parameterVariable = $compilationContext->symbolTable->getTempLocalVariableForWrite('variable', $compilationContext, $expression);
$params[] = '&' . $parameterVariable->getName();
$codePrinter->output('ZVAL_NULL(&' . $parameterVariable->getName() . ');');
} else {
$parameterVariable = $compilationContext->symbolTable->getTempVariableForWrite('variable', $compilationContext, $expression);
$params[] = $parameterVariable->getName();
$codePrinter->output('ZVAL_NULL(' . $parameterVariable->getName() . ');');
}
$types[] = $compiledExpression->getType();
$dynamicTypes[] = $compiledExpression->getType();
break;
Expand Down Expand Up @@ -373,14 +383,39 @@ public function getResolvedParams($parameters, CompilationContext $compilationCo

case 'bool':
if ($compiledExpression->getCode() == 'true') {
$params[] = 'ZEPHIR_GLOBAL(global_true)';
if (isset($readOnlyParameters[$position])) {
$parameterVariable = $compilationContext->symbolTable->getTempLocalVariableForWrite('variable', $compilationContext, $expression);
$codePrinter->output('ZVAL_BOOL(&' . $parameterVariable->getName() . ', 1);');
$params[] = '&' . $parameterVariable->getName();
} else {
$parameterVariable = $compilationContext->symbolTable->getTempVariableForWrite('variable', $compilationContext, $expression);
$codePrinter->output('ZVAL_BOOL(' . $parameterVariable->getName() . ', 1);');
$params[] = $parameterVariable->getName();
}
} else {
if ($compiledExpression->getCode() == 'false') {
$params[] = 'ZEPHIR_GLOBAL(global_false)';
if (isset($readOnlyParameters[$position])) {
$parameterVariable = $compilationContext->symbolTable->getTempLocalVariableForWrite('variable', $compilationContext, $expression);
$codePrinter->output('ZVAL_BOOL(&' . $parameterVariable->getName() . ', 0);');
$params[] = '&' . $parameterVariable->getName();
} else {
$parameterVariable = $compilationContext->symbolTable->getTempVariableForWrite('variable', $compilationContext, $expression);
$codePrinter->output('ZVAL_BOOL(' . $parameterVariable->getName() . ', 0);');
$params[] = $parameterVariable->getName();
}
} else {
$params[] = '(' . $compiledExpression->getBooleanCode() . ' ? ZEPHIR_GLOBAL(global_true) : ZEPHIR_GLOBAL(global_false))';
if (isset($readOnlyParameters[$position])) {
$parameterVariable = $compilationContext->symbolTable->getTempLocalVariableForWrite('variable', $compilationContext, $expression);
$codePrinter->output('ZVAL_BOOL(&' . $parameterVariable->getName() . ', ' . $compiledExpression->getBooleanCode() . ');');
$params[] = '&' . $parameterVariable->getName();
} else {
$parameterVariable = $compilationContext->symbolTable->getTempVariableForWrite('variable', $compilationContext, $expression);
$codePrinter->output('ZVAL_BOOL(' . $parameterVariable->getName() . ', ' . $compiledExpression->getBooleanCode() . ');');
$params[] = $parameterVariable->getName();
}
}
}

$types[] = $compiledExpression->getType();
$dynamicTypes[] = $compiledExpression->getType();
break;
Expand Down Expand Up @@ -488,9 +523,9 @@ public function getResolvedParams($parameters, CompilationContext $compilationCo
* @param array $expression
* @return array
*/
public function getReadOnlyResolvedParams($parameters, CompilationContext $compilationContext, $expression)
public function getReadOnlyResolvedParams($parameters, CompilationContext $compilationContext, array $expression)
{
$codePrinter = &$compilationContext->codePrinter;
$codePrinter = $compilationContext->codePrinter;
$exprParams = $this->getResolvedParamsAsExpr($parameters, $compilationContext, $expression, true);

$params = array();
Expand Down Expand Up @@ -530,7 +565,11 @@ public function getReadOnlyResolvedParams($parameters, CompilationContext $compi
if ($compiledExpression->getCode() == 'true') {
$params[] = 'ZEPHIR_GLOBAL(global_true)';
} else {
$params[] = 'ZEPHIR_GLOBAL(global_false)';
if ($compiledExpression->getCode() == 'false') {
$params[] = 'ZEPHIR_GLOBAL(global_false)';
} else {
throw new Exception('?');
}
}
break;

Expand Down
2 changes: 1 addition & 1 deletion Library/Compiler.php
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
*/
class Compiler
{
const VERSION = '0.4.4a';
const VERSION = '0.4.5a';

/**
* @var CompilerFile[]
Expand Down
20 changes: 8 additions & 12 deletions Library/FunctionCall.php
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ public function getReflector($funcName)
* @param array $expression
* @return boolean
*/
protected function isReadOnly($funcName, $expression)
protected function isReadOnly($funcName, array $expression)
{
if ($this->isBuiltInFunction($funcName)) {
return false;
Expand All @@ -112,20 +112,16 @@ protected function isReadOnly($funcName, $expression)
}
}

if ($numberParameters > 0) {
$n = 1;
$parameters = $reflector->getParameters();
foreach ($parameters as $parameter) {
if ($numberParameters >= $n) {
if ($parameter->isPassedByReference()) {
return false;
}
if ($reflector->getNumberOfParameters() > 0) {
foreach ($reflector->getParameters() as $parameter) {
if ($parameter->isPassedByReference()) {
return false;
}
$n++;
}
}
return true;
}

return false;
}

Expand Down Expand Up @@ -282,7 +278,7 @@ public function functionExists($functionName)
* @param array $expression
* @param CompilationContext $compilationContext
*/
protected function _callNormal($expression, $compilationContext)
protected function _callNormal(array $expression, $compilationContext)
{
$funcName = strtolower($expression['name']);

Expand Down Expand Up @@ -440,7 +436,7 @@ protected function _callNormal($expression, $compilationContext)
* @param array $expression
* @param CompilationContext $compilationContext
*/
protected function _callDynamic($expression, $compilationContext)
protected function _callDynamic(array $expression, $compilationContext)
{

$variable = $compilationContext->symbolTable->getVariableForRead($expression['name'], $compilationContext, $expression);
Expand Down
15 changes: 15 additions & 0 deletions Library/GlobalConstant.php
Original file line number Diff line number Diff line change
Expand Up @@ -29,16 +29,31 @@ class GlobalConstant
{
private $_name;

/**
* Creates a new global constant
*
* @param string $name
*/
public function __construct($name)
{
$this->_name = $name;
}

/**
* Returns global constant name
*
* @return string
*/
public function getName()
{
return $this->_name;
}

/**
* Check if the global constant is temporal
*
* @return boolean
*/
public function isTemporal()
{
return false;
Expand Down
2 changes: 1 addition & 1 deletion ext/kernel/object.c
Original file line number Diff line number Diff line change
Expand Up @@ -1328,7 +1328,7 @@ int zephir_unset_property_array(zval *object, char *property, unsigned int prope
int zephir_method_exists(const zval *object, const zval *method_name TSRMLS_DC){

char *lcname = zend_str_tolower_dup(Z_STRVAL_P(method_name), Z_STRLEN_P(method_name));
int res = zephir_method_exists_ex(object, lcname, Z_STRLEN_P(method_name)+1 TSRMLS_CC);
int res = zephir_method_exists_ex(object, lcname, Z_STRLEN_P(method_name) + 1 TSRMLS_CC);
efree(lcname);
return res;
}
Expand Down
3 changes: 2 additions & 1 deletion parser/parser.h
Original file line number Diff line number Diff line change
Expand Up @@ -115,4 +115,5 @@
#define XX_DOUBLE 115
#define XX_TRUE 116
#define XX_FALSE 117
#define XX_CBLOCK 118
#define XX_XX_T_BITWISE_AND 118
#define XX_CBLOCK 119
21 changes: 18 additions & 3 deletions parser/parser.lemon
Original file line number Diff line number Diff line change
Expand Up @@ -1092,14 +1092,17 @@ static json_object *xx_ret_scall(int dynamic_class, xx_parser_token *O, int dyna
return ret;
}

static json_object *xx_ret_call_parameter(xx_parser_token *N, json_object *parameter, xx_scanner_state *state)
static json_object *xx_ret_call_parameter(xx_parser_token *N, json_object *parameter, xx_scanner_state *state, int reference)
{
json_object *ret = json_object_new_object();

if (N) {
json_object_object_add(ret, "name", json_object_new_string(N->token));
}
json_object_object_add(ret, "parameter", parameter);
if (reference) {
json_object_object_add(ret, "reference", json_object_new_int(reference));
}

json_object_object_add(ret, "file", json_object_new_string(state->active_file));
json_object_object_add(ret, "line", json_object_new_int(state->active_line));
Expand Down Expand Up @@ -2758,12 +2761,24 @@ xx_call_parameters(R) ::= xx_call_parameter(P) . {
R = xx_ret_list(NULL, P);
}

/* func(expr) */
xx_call_parameter(R) ::= xx_common_expr(E) . {
R = xx_ret_call_parameter(NULL, E, status->scanner_state);
R = xx_ret_call_parameter(NULL, E, status->scanner_state, 0);
}

/* func(name: expr) */
xx_call_parameter(R) ::= IDENTIFIER(I) COLON xx_common_expr(E) . {
R = xx_ret_call_parameter(I, E, status->scanner_state);
R = xx_ret_call_parameter(I, E, status->scanner_state, 0);
}

/* func(&expr) */
xx_call_parameter(R) ::= XX_T_BITWISE_AND xx_common_expr(E) . {
R = xx_ret_call_parameter(NULL, E, status->scanner_state, 1);
}

/* func(name: &expr) */
xx_call_parameter(R) ::= IDENTIFIER(I) COLON XX_T_BITWISE_AND xx_common_expr(E) . {
R = xx_ret_call_parameter(I, E, status->scanner_state, 0);
}

xx_array_list(R) ::= xx_array_list(L) COMMA xx_array_item(I) . {
Expand Down

0 comments on commit ffbdf9f

Please sign in to comment.