diff --git a/Library/Compiler.php b/Library/Compiler.php index fc8d56e3e7..fbe297e8a1 100755 --- a/Library/Compiler.php +++ b/Library/Compiler.php @@ -29,7 +29,7 @@ */ class Compiler { - const VERSION = '0.3.10a'; + const VERSION = '0.4.0a'; /** * @var CompilerFile[] diff --git a/Library/FunctionCall.php b/Library/FunctionCall.php index 7671f026c9..67d4692d9c 100755 --- a/Library/FunctionCall.php +++ b/Library/FunctionCall.php @@ -379,6 +379,7 @@ protected function _callNormal($expression, $compilationContext) } else { if ($this->mustInitSymbolVariable()) { $symbolVariable->setMustInitNull(true); + $symbolVariable->trackVariant($compilationContext); } $codePrinter->output('ZEPHIR_CALL_FUNCTION(&' . $symbolVariable->getName() . ', "' . $funcName . '", ' . $cachePointer . ');'); } @@ -392,6 +393,7 @@ protected function _callNormal($expression, $compilationContext) } else { if ($this->mustInitSymbolVariable()) { $symbolVariable->setMustInitNull(true); + $symbolVariable->trackVariant($compilationContext); } $codePrinter->output('ZEPHIR_CALL_FUNCTION(&' . $symbolVariable->getName() . ', "' . $funcName . '", ' . $cachePointer . ', ' . join(', ', $params) . ');'); } @@ -503,6 +505,7 @@ protected function _callDynamic($expression, $compilationContext) } else { if ($this->mustInitSymbolVariable()) { $symbolVariable->setMustInitNull(true); + $symbolVariable->trackVariant($compilationContext); } $codePrinter->output('ZEPHIR_CALL_ZVAL_FUNCTION(&' . $symbolVariable->getName() . ', ' . $variable->getName() . ', NULL);'); } @@ -517,6 +520,7 @@ protected function _callDynamic($expression, $compilationContext) } else { if ($this->mustInitSymbolVariable()) { $symbolVariable->setMustInitNull(true); + $symbolVariable->trackVariant($compilationContext); } $codePrinter->output('ZEPHIR_CALL_ZVAL_FUNCTION(&' . $symbolVariable->getName() . ', ' . $variable->getName() . ', NULL, ' . join(', ', $params) . ');'); } @@ -530,6 +534,7 @@ protected function _callDynamic($expression, $compilationContext) } else { if ($this->mustInitSymbolVariable()) { $symbolVariable->setMustInitNull(true); + $symbolVariable->trackVariant($compilationContext); } $codePrinter->output('ZEPHIR_CALL_ZVAL_FUNCTION(&' . $symbolVariable->getName() . ', ' . $variable->getName() . ', NULL);'); } diff --git a/Library/MethodCall.php b/Library/MethodCall.php index cfc26a800d..bd5e4b03a7 100644 --- a/Library/MethodCall.php +++ b/Library/MethodCall.php @@ -468,6 +468,7 @@ public function compile(Expression $expr, CompilationContext $compilationContext if ($mustInit) { $symbolVariable->setMustInitNull(true); + $symbolVariable->trackVariant($compilationContext); } /** diff --git a/Library/StaticCall.php b/Library/StaticCall.php index f42db9fae2..2b7a5a1fec 100644 --- a/Library/StaticCall.php +++ b/Library/StaticCall.php @@ -53,6 +53,7 @@ protected function callSelf($methodName, array $expression, $symbolVariable, $mu if ($mustInit) { $symbolVariable->setMustInitNull(true); + $symbolVariable->trackVariant($compilationContext); } /** @@ -125,6 +126,7 @@ protected function callParent($methodName, array $expression, $symbolVariable, $ if ($mustInit) { $symbolVariable->setMustInitNull(true); + $symbolVariable->trackVariant($compilationContext); } /** @@ -209,6 +211,7 @@ protected function callFromClass($methodName, array $expression, $symbolVariable if ($mustInit) { $symbolVariable->setMustInitNull(true); + $symbolVariable->trackVariant($compilationContext); } /** diff --git a/Library/Variable.php b/Library/Variable.php index 42319b8609..d1a783fd4b 100644 --- a/Library/Variable.php +++ b/Library/Variable.php @@ -741,6 +741,50 @@ public function initVariant(CompilationContext $compilationContext) } } + /** + * Tells the compiler a generated code will track the variable + * + * @param CompilationContext $compilationContext + */ + public function trackVariant(CompilationContext $compilationContext) + { + if ($this->_numberSkips) { + $this->_numberSkips--; + return; + } + + /** + * Variables are allocated for the first time using ZEPHIR_INIT_VAR + * the second, third, etc times are allocated using ZEPHIR_INIT_NVAR + * Variables initialized for the first time in a cycle are always initialized using ZEPHIR_INIT_NVAR + */ + if ($this->getName() != 'this_ptr' && $this->getName() != 'return_value') { + + if ($this->_initBranch === false) { + $this->_initBranch = $compilationContext->currentBranch; + } + + if (!$this->isLocalOnly()) { + $compilationContext->symbolTable->mustGrownStack(true); + if ($compilationContext->insideCycle) { + $this->_mustInitNull = true; + } else { + if ($this->_variantInits > 0) { + if ($this->_initBranch !== 1) { + $this->_mustInitNull = true; + } + } + } + } else { + if ($this->_variantInits > 0 || $compilationContext->insideCycle) { + $this->_mustInitNull = true; + } + } + + $this->_variantInits++; + } + } + /** * Initializes a variant variable that is intended to have the special * behavior of only freed its body value instead of the full variable diff --git a/ext/kernel/object.c b/ext/kernel/object.c index 94d168e7ca..f8d555da80 100644 --- a/ext/kernel/object.c +++ b/ext/kernel/object.c @@ -507,93 +507,7 @@ int zephir_read_property(zval **result, zval *object, const char *property_name, return SUCCESS; } -/** - * Reads a property from this_ptr - * Variables must be defined in the class definition. This function ignores magic methods or dynamic properties - */ -int zephir_read_property_this(zval **result, zval *object, char *property_name, unsigned int property_length, int flags TSRMLS_DC) { - - return zephir_read_property_this_quick(result, object, property_name, property_length, zend_inline_hash_func(property_name, property_length + 1), flags TSRMLS_CC); -} - -/** - * Reads a property from this_ptr (with pre-calculated key) - * Variables must be defined in the class definition. This function ignores magic methods or dynamic properties - */ -int zephir_read_property_this_quick(zval **result, zval *object, char *property_name, unsigned int property_length, unsigned long key, int flags TSRMLS_DC) { - - zval *property; - zend_class_entry *ce, *old_scope; - - if (Z_TYPE_P(object) != IS_OBJECT) { - - if ((flags & PH_NOISY) == PH_NOISY) { - php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Trying to get property of non-object"); - } - - *result = ZEPHIR_GLOBAL(global_null); - Z_ADDREF_P(*result); - return FAILURE; - } - - ce = Z_OBJCE_P(object); - if (ce->parent) { - ce = zephir_lookup_class_ce(ce, property_name, property_length TSRMLS_CC); - } - - old_scope = EG(scope); - EG(scope) = ce; - - if (!Z_OBJ_HT_P(object)->read_property) { -#if PHP_VERSION_ID < 50400 - char *class_name; -#else - const char *class_name; -#endif - zend_uint class_name_len; - - zend_get_object_classname(object, &class_name, &class_name_len TSRMLS_CC); - zend_error(E_CORE_ERROR, "Property %s of class %s cannot be read", property_name, class_name); - } - - MAKE_STD_ZVAL(property); - ZVAL_STRINGL(property, property_name, property_length, 0); - -#if PHP_VERSION_ID < 50400 - *result = Z_OBJ_HT_P(object)->read_property(object, property, (flags & PH_NOISY) == PH_NOISY ? BP_VAR_IS : BP_VAR_R TSRMLS_CC); -#else - *result = Z_OBJ_HT_P(object)->read_property(object, property, (flags & PH_NOISY) == PH_NOISY ? BP_VAR_IS : BP_VAR_R, 0 TSRMLS_CC); -#endif - - Z_ADDREF_PP(result); - - if (Z_REFCOUNT_P(property) > 1) { - ZVAL_STRINGL(property, property_name, property_length, 1); - } else { - ZVAL_NULL(property); - } - - zval_ptr_dtor(&property); - - EG(scope) = old_scope; - return SUCCESS; -} - -zval* zephir_fetch_nproperty_this(zval *object, char *property_name, unsigned int property_length, int flags TSRMLS_DC) { - return zephir_fetch_nproperty_this_quick(object, property_name, property_length, zend_inline_hash_func(property_name, property_length + 1), flags TSRMLS_CC); -} - -zval* zephir_fetch_nproperty_this_quick(zval *object, char *property_name, unsigned int property_length, unsigned long key, int flags TSRMLS_DC) { - zval *result = zephir_fetch_property_this_quick(object, property_name, property_length, zend_inline_hash_func(property_name, property_length + 1), flags TSRMLS_CC); - return result ? result : ZEPHIR_GLOBAL(global_null); -} - - -zval* zephir_fetch_property_this(zval *object, char *property_name, unsigned int property_length, int flags TSRMLS_DC) { - return zephir_fetch_property_this_quick(object, property_name, property_length, zend_inline_hash_func(property_name, property_length + 1), flags TSRMLS_CC); -} - -zval* zephir_fetch_property_this_quick(zval *object, char *property_name, unsigned int property_length, unsigned long key, int flags TSRMLS_DC) { +zval* zephir_fetch_property_this_quick(zval *object, const char *property_name, zend_uint property_length, ulong key, int silent TSRMLS_DC) { zval **zv = NULL; zend_object *zobj; @@ -661,7 +575,7 @@ zval* zephir_fetch_property_this_quick(zval *object, char *property_name, unsign EG(scope) = old_scope; } else { - if ((flags & PH_NOISY) == PH_NOISY) { + if (silent == PH_NOISY) { php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Trying to get property of non-object"); } } diff --git a/ext/kernel/object.h b/ext/kernel/object.h index 384af3e6eb..652e5a1c7c 100644 --- a/ext/kernel/object.h +++ b/ext/kernel/object.h @@ -61,12 +61,7 @@ int zephir_isset_property_quick(zval *object, const char *property_name, unsigne int zephir_isset_property_zval(zval *object, const zval *property TSRMLS_DC); /** Reading properties */ -int zephir_read_property_this(zval **result, zval *object, char *property_name, unsigned int property_length, int silent TSRMLS_DC); -int zephir_read_property_this_quick(zval **result, zval *object, char *property_name, unsigned int property_length, unsigned long key, int silent TSRMLS_DC); -zval* zephir_fetch_nproperty_this(zval *object, char *property_name, unsigned int property_length, int silent TSRMLS_DC); -zval* zephir_fetch_nproperty_this_quick(zval *object, char *property_name, unsigned int property_length, unsigned long key, int silent TSRMLS_DC); -zval* zephir_fetch_property_this(zval *object, char *property_name, unsigned int property_length, int silent TSRMLS_DC); -zval* zephir_fetch_property_this_quick(zval *object, char *property_name, unsigned int property_length, unsigned long key, int silent TSRMLS_DC); +zval* zephir_fetch_property_this_quick(zval *object, const char *property_name, zend_uint property_length, ulong key, int silent TSRMLS_DC); int zephir_read_property(zval **result, zval *object, const char *property_name, zend_uint property_length, int silent TSRMLS_DC); int zephir_read_property_zval(zval **result, zval *object, zval *property, int silent TSRMLS_DC); int zephir_return_property(zval *return_value, zval **return_value_ptr, zval *object, char *property_name, unsigned int property_length TSRMLS_DC); @@ -107,4 +102,71 @@ zval* zephir_fetch_static_property_ce(zend_class_entry *ce, char *property, int int zephir_create_instance(zval *return_value, const zval *class_name TSRMLS_DC); int zephir_create_instance_params(zval *return_value, const zval *class_name, zval *params TSRMLS_DC); +/** + * Reads a property from this_ptr (with pre-calculated key) + * Variables must be defined in the class definition. This function ignores magic methods or dynamic properties + */ +ZEPHIR_ATTR_NONNULL static inline int zephir_read_property_this_quick(zval **result, zval *object, const char *property_name, zend_uint property_length, ulong key, int silent TSRMLS_DC) +{ + zval *tmp = zephir_fetch_property_this_quick(object, property_name, property_length, key, silent TSRMLS_CC); + if (EXPECTED(tmp != NULL)) { + *result = tmp; + Z_ADDREF_PP(result); + return SUCCESS; + } + + ALLOC_INIT_ZVAL(*result); + return FAILURE; +} + +/** + * Reads a property from this_ptr + * Variables must be defined in the class definition. This function ignores magic methods or dynamic properties + */ +ZEPHIR_ATTR_NONNULL static inline int zephir_read_property_this(zval **result, zval *object, const char *property_name, zend_uint property_length, int silent TSRMLS_DC) +{ +#ifdef __GNUC__ + if (__builtin_constant_p(property_name) && __builtin_constant_p(property_length)) { + return zephir_read_property_this_quick(result, object, property_name, property_length, zend_inline_hash_func(property_name, property_length + 1), silent TSRMLS_CC); + } #endif + + return zephir_read_property_this_quick(result, object, property_name, property_length, zend_hash_func(property_name, property_length + 1), silent TSRMLS_CC); +} + +ZEPHIR_ATTR_NONNULL static inline zval* zephir_fetch_nproperty_this_quick(zval *object, const char *property_name, zend_uint property_length, ulong key, int silent TSRMLS_DC) +{ +#ifdef __GNUC__ + if (__builtin_constant_p(property_name) && __builtin_constant_p(property_length)) { + zval *result = zephir_fetch_property_this_quick(object, property_name, property_length, zend_inline_hash_func(property_name, property_length + 1), silent TSRMLS_CC); + return result ? result : EG(uninitialized_zval_ptr); + } +#endif + + zval *result = zephir_fetch_property_this_quick(object, property_name, property_length, zend_hash_func(property_name, property_length + 1), silent TSRMLS_CC); + return result ? result : EG(uninitialized_zval_ptr); +} + +ZEPHIR_ATTR_NONNULL static inline zval* zephir_fetch_nproperty_this(zval *object, const char *property_name, zend_uint property_length, int silent TSRMLS_DC) +{ +#ifdef __GNUC__ + if (__builtin_constant_p(property_name) && __builtin_constant_p(property_length)) { + return zephir_fetch_nproperty_this_quick(object, property_name, property_length, zend_inline_hash_func(property_name, property_length + 1), silent TSRMLS_CC); + } +#endif + + return zephir_fetch_nproperty_this_quick(object, property_name, property_length, zend_hash_func(property_name, property_length + 1), silent TSRMLS_CC); +} + +ZEPHIR_ATTR_NONNULL static inline zval* zephir_fetch_property_this(zval *object, const char *property_name, zend_uint property_length, int silent TSRMLS_DC) +{ +#ifdef __GNUC__ + if (__builtin_constant_p(property_name) && __builtin_constant_p(property_length)) { + return zephir_fetch_property_this_quick(object, property_name, property_length, zend_inline_hash_func(property_name, property_length + 1), silent TSRMLS_CC); + } +#endif + + return zephir_fetch_property_this_quick(object, property_name, property_length, zend_hash_func(property_name, property_length + 1), silent TSRMLS_CC); +} + +#endif \ No newline at end of file