From ffbdf9f62a085ef12e6a0fca342453091a1cd4e7 Mon Sep 17 00:00:00 2001 From: phalcon Date: Wed, 13 Aug 2014 18:33:12 -0500 Subject: [PATCH] Allowing to call methods/functions passing values by reference, more aggresive detect of functions/methods that don't allow pass global constants --- Library/Call.php | 59 +++++++++++++++++++++++++++++++------- Library/Compiler.php | 2 +- Library/FunctionCall.php | 20 ++++++------- Library/GlobalConstant.php | 15 ++++++++++ ext/kernel/object.c | 2 +- parser/parser.h | 3 +- parser/parser.lemon | 21 ++++++++++++-- 7 files changed, 94 insertions(+), 28 deletions(-) diff --git a/Library/Call.php b/Library/Call.php index c0ab574404..873c4a148c 100644 --- a/Library/Call.php +++ b/Library/Call.php @@ -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'])) { @@ -316,6 +316,8 @@ public function getResolvedParams($parameters, CompilationContext $compilationCo case 'long': case 'char': case 'uchar': + case 'boolean': + case 'bool': $readOnlyParameters[$position] = true; break; } @@ -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; @@ -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; @@ -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(); @@ -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; diff --git a/Library/Compiler.php b/Library/Compiler.php index eb611eeb35..c9b720da8f 100755 --- a/Library/Compiler.php +++ b/Library/Compiler.php @@ -29,7 +29,7 @@ */ class Compiler { - const VERSION = '0.4.4a'; + const VERSION = '0.4.5a'; /** * @var CompilerFile[] diff --git a/Library/FunctionCall.php b/Library/FunctionCall.php index f326502889..28669a3921 100755 --- a/Library/FunctionCall.php +++ b/Library/FunctionCall.php @@ -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; @@ -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; } @@ -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']); @@ -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); diff --git a/Library/GlobalConstant.php b/Library/GlobalConstant.php index 6099cc5c9c..9ff1ca068f 100644 --- a/Library/GlobalConstant.php +++ b/Library/GlobalConstant.php @@ -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; diff --git a/ext/kernel/object.c b/ext/kernel/object.c index e5b5ec55a7..997cf25cab 100644 --- a/ext/kernel/object.c +++ b/ext/kernel/object.c @@ -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; } diff --git a/parser/parser.h b/parser/parser.h index 7b127db67f..c1fa9c295d 100644 --- a/parser/parser.h +++ b/parser/parser.h @@ -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 diff --git a/parser/parser.lemon b/parser/parser.lemon index 7d55498602..d052102ba0 100644 --- a/parser/parser.lemon +++ b/parser/parser.lemon @@ -1092,7 +1092,7 @@ 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(); @@ -1100,6 +1100,9 @@ static json_object *xx_ret_call_parameter(xx_parser_token *N, json_object *param 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)); @@ -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) . {