diff options
Diffstat (limited to 'Zend')
29 files changed, 850 insertions, 148 deletions
diff --git a/Zend/tests/lsb_001.phpt b/Zend/tests/lsb_001.phpt new file mode 100644 index 0000000000..20a2fd83bb --- /dev/null +++ b/Zend/tests/lsb_001.phpt @@ -0,0 +1,61 @@ +--TEST-- +ZE2 Late Static Binding in a static function +--FILE-- +<?php + +class TestClass { + protected static $staticVar = 'TestClassStatic'; + const CLASS_CONST = 'TestClassConst'; + + protected static function staticFunction() { + return 'TestClassFunction'; + } + + public static function testStaticVar() { + return static::$staticVar; + } + + public static function testClassConst() { + return static::CLASS_CONST; + } + + public static function testStaticFunction() { + return static::staticFunction(); + } +} + +class ChildClass1 extends TestClass { + protected static $staticVar = 'ChildClassStatic'; + const CLASS_CONST = 'ChildClassConst'; + + protected static function staticFunction() { + return 'ChildClassFunction'; + } +} + +class ChildClass2 extends TestClass {} + +echo TestClass::testStaticVar() . "\n"; +echo TestClass::testClassConst() . "\n"; +echo TestClass::testStaticFunction() . "\n"; + +echo ChildClass1::testStaticVar() . "\n"; +echo ChildClass1::testClassConst() . "\n"; +echo ChildClass1::testStaticFunction() . "\n"; + +echo ChildClass2::testStaticVar() . "\n"; +echo ChildClass2::testClassConst() . "\n"; +echo ChildClass2::testStaticFunction() . "\n"; +?> +==DONE== +--EXPECTF-- +TestClassStatic +TestClassConst +TestClassFunction +ChildClassStatic +ChildClassConst +ChildClassFunction +TestClassStatic +TestClassConst +TestClassFunction +==DONE== diff --git a/Zend/tests/lsb_002.phpt b/Zend/tests/lsb_002.phpt new file mode 100644 index 0000000000..4fca6ddd72 --- /dev/null +++ b/Zend/tests/lsb_002.phpt @@ -0,0 +1,66 @@ +--TEST-- +ZE2 Late Static Binding in an instance function +--FILE-- +<?php + +class TestClass { + protected static $staticVar = 'TestClassStatic'; + const CLASS_CONST = 'TestClassConst'; + + protected static function staticFunction() { + return 'TestClassFunction'; + } + + public function testStaticVar() { + return static::$staticVar; + } + + public function testClassConst() { + return static::CLASS_CONST; + } + + public function testStaticFunction() { + return static::staticFunction(); + } +} + +class ChildClass1 extends TestClass { + protected static $staticVar = 'ChildClassStatic'; + const CLASS_CONST = 'ChildClassConst'; + + protected static function staticFunction() { + return 'ChildClassFunction'; + } +} + +class ChildClass2 extends TestClass {} + +$testClass = new TestClass(); +$childClass1 = new ChildClass1(); +$childClass2 = new ChildClass2(); + + +echo $testClass->testStaticVar() . "\n"; +echo $testClass->testClassConst() . "\n"; +echo $testClass->testStaticFunction() . "\n"; + +echo $childClass1->testStaticVar() . "\n"; +echo $childClass1->testClassConst() . "\n"; +echo $childClass1->testStaticFunction() . "\n"; + +echo $childClass2->testStaticVar() . "\n"; +echo $childClass2->testClassConst() . "\n"; +echo $childClass2->testStaticFunction() . "\n"; +?> +==DONE== +--EXPECTF-- +TestClassStatic +TestClassConst +TestClassFunction +ChildClassStatic +ChildClassConst +ChildClassFunction +TestClassStatic +TestClassConst +TestClassFunction +==DONE== diff --git a/Zend/tests/lsb_003.phpt b/Zend/tests/lsb_003.phpt new file mode 100644 index 0000000000..4e9fe1f7c8 --- /dev/null +++ b/Zend/tests/lsb_003.phpt @@ -0,0 +1,24 @@ +--TEST-- +ZE2 Late Static Binding creating a new class with 'static' +--FILE-- +<?php + +class TestClass { + public static function createInstance() { + return new static(); + } +} + +class ChildClass extends TestClass {} + +$testClass = TestClass::createInstance(); +$childClass = ChildClass::createInstance(); + +echo get_class($testClass) . "\n"; +echo get_class($childClass) . "\n"; +?> +==DONE== +--EXPECTF-- +TestClass +ChildClass +==DONE== diff --git a/Zend/tests/lsb_004.phpt b/Zend/tests/lsb_004.phpt new file mode 100644 index 0000000000..6baeba00bd --- /dev/null +++ b/Zend/tests/lsb_004.phpt @@ -0,0 +1,21 @@ +--TEST-- +ZE2 Late Static Binding testing get_called_class() +--FILE-- +<?php + +class TestClass { + public static function getClassName() { + return get_called_class(); + } +} + +class ChildClass extends TestClass {} + +echo TestClass::getClassName() . "\n"; +echo ChildClass::getClassName() . "\n"; +?> +==DONE== +--EXPECTF-- +TestClass +ChildClass +==DONE== diff --git a/Zend/tests/lsb_005.phpt b/Zend/tests/lsb_005.phpt new file mode 100644 index 0000000000..00647a5c70 --- /dev/null +++ b/Zend/tests/lsb_005.phpt @@ -0,0 +1,51 @@ +--TEST-- +ZE2 Late Static Binding stacking static calleds +--FILE-- +<?php + +class TestA { + public static function test() { + echo get_class(new static()) . "\n"; + TestB::test(); + echo get_class(new static()) . "\n"; + TestC::test(); + echo get_class(new static()) . "\n"; + TestBB::test(); + echo get_class(new static()) . "\n"; + } +} + +class TestB { + public static function test() { + echo get_class(new static()) . "\n"; + TestC::test(); + echo get_class(new static()) . "\n"; + } +} + +class TestC { + public static function test() { + echo get_class(new static()) . "\n"; + } +} + +class TestBB extends TestB { +} + +TestA::test(); + +?> +==DONE== +--EXPECTF-- +TestA +TestB +TestC +TestB +TestA +TestC +TestA +TestBB +TestC +TestBB +TestA +==DONE== diff --git a/Zend/tests/lsb_006.phpt b/Zend/tests/lsb_006.phpt new file mode 100644 index 0000000000..f5e2b045eb --- /dev/null +++ b/Zend/tests/lsb_006.phpt @@ -0,0 +1,12 @@ +--TEST-- +ZE2 Late Static Binding ensuring extending 'static' is not allowed +--FILE-- +<?php + +class Foo extends static { +} + +?> +==DONE== +--EXPECTF-- +Fatal error: Cannot use 'static' as class name as it is reserved in %s on line %d diff --git a/Zend/tests/lsb_007.phpt b/Zend/tests/lsb_007.phpt new file mode 100644 index 0000000000..a20a826166 --- /dev/null +++ b/Zend/tests/lsb_007.phpt @@ -0,0 +1,12 @@ +--TEST-- +ZE2 Late Static Binding ensuring implementing 'static' is not allowed +--FILE-- +<?php + +class Foo implements static { +} + +?> +==DONE== +--EXPECTF-- +Fatal error: Cannot use 'static' as interface name as it is reserved in %s on line %d diff --git a/Zend/tests/lsb_008.phpt b/Zend/tests/lsb_008.phpt new file mode 100644 index 0000000000..88507b3266 --- /dev/null +++ b/Zend/tests/lsb_008.phpt @@ -0,0 +1,8 @@ +--TEST-- +ZE2 Late Static Binding class name "static" +--FILE-- +<?php +class static { +} +--EXPECTF-- +Parse error: syntax error, unexpected T_STATIC, expecting T_STRING in %slsb_008.php on line 2 diff --git a/Zend/tests/lsb_009.phpt b/Zend/tests/lsb_009.phpt new file mode 100644 index 0000000000..7bf308676c --- /dev/null +++ b/Zend/tests/lsb_009.phpt @@ -0,0 +1,8 @@ +--TEST-- +ZE2 Late Static Binding interface name "static" +--FILE-- +<?php +interface static { +} +--EXPECTF-- +Parse error: syntax error, unexpected T_STATIC, expecting T_STRING in %slsb_009.php on line 2 diff --git a/Zend/tests/lsb_010.phpt b/Zend/tests/lsb_010.phpt new file mode 100644 index 0000000000..2ac0306120 --- /dev/null +++ b/Zend/tests/lsb_010.phpt @@ -0,0 +1,38 @@ +--TEST-- +ZE2 Late Static Binding using static:: in functions called by non execute() calls and constructors. +--FILE-- +<?php + +class Foo { + protected static $className = 'Foo'; + public static function bar() { + echo static::$className . "::bar\n"; + } + public function __construct() { + echo static::$className . "::__construct\n"; + } + public function __destruct() { + echo static::$className . "::__destruct\n"; + } +} + +class FooChild extends Foo { + protected static $className = 'FooChild'; +} + +register_shutdown_function(array('Foo', 'bar')); +register_shutdown_function(array('FooChild', 'bar')); + +$foo = new Foo(); +$fooChild = new FooChild(); +unset($foo); +unset($fooChild); + +?> +--EXPECTF-- +Foo::__construct +FooChild::__construct +Foo::__destruct +FooChild::__destruct +Foo::bar +FooChild::bar diff --git a/Zend/tests/lsb_011.phpt b/Zend/tests/lsb_011.phpt new file mode 100644 index 0000000000..3c5bbbeb6f --- /dev/null +++ b/Zend/tests/lsb_011.phpt @@ -0,0 +1,23 @@ +--TEST-- +ZE2 Late Static Binding call to static::method() from internal function (array) +--FILE-- +<?php + +class Test1 { + static function ok() { + echo "bug"; + } + static function test() { + call_user_func(array("static","ok")); + } +} + +class Test2 extends Test1 { + static function ok() { + echo "ok"; + } +} +Test2::test(); +?> +--EXPECT-- +ok diff --git a/Zend/tests/lsb_012.phpt b/Zend/tests/lsb_012.phpt new file mode 100644 index 0000000000..3ac8d38840 --- /dev/null +++ b/Zend/tests/lsb_012.phpt @@ -0,0 +1,23 @@ +--TEST-- +ZE2 Late Static Binding call to static::method() from internal function (string) +--FILE-- +<?php + +class Test1 { + static function ok() { + echo "bug"; + } + static function test() { + call_user_func("static::ok"); + } +} + +class Test2 extends Test1 { + static function ok() { + echo "ok"; + } +} +Test2::test(); +?> +--EXPECT-- +ok diff --git a/Zend/tests/lsb_013.phpt b/Zend/tests/lsb_013.phpt new file mode 100644 index 0000000000..3f32dc3a66 --- /dev/null +++ b/Zend/tests/lsb_013.phpt @@ -0,0 +1,24 @@ +--TEST-- +ZE2 Late Static Binding is_callable() and static::method() +--FILE-- +<?php + +class Test1 { + static function test() { + var_dump(is_callable("static::ok")); + var_dump(is_callable(array("static","ok"))); + } +} + +class Test2 extends Test1 { + static function ok() { + } +} +Test1::test(); +Test2::test(); +?> +--EXPECT-- +bool(false) +bool(false) +bool(true) +bool(true) diff --git a/Zend/tests/lsb_014.phpt b/Zend/tests/lsb_014.phpt new file mode 100644 index 0000000000..34ee7b48ce --- /dev/null +++ b/Zend/tests/lsb_014.phpt @@ -0,0 +1,24 @@ +--TEST-- +ZE2 Late Static Binding access to static::const through defined() anf get_constant() +--FILE-- +<?php + +class Test1 { + static function test() { + var_dump(defined("static::ok")); + if (defined("static::ok")) { + echo constant("static::ok"); + } + } +} + +class Test2 extends Test1 { + const ok = "ok"; +} +Test1::test(); +Test2::test(); +?> +--EXPECT-- +bool(false) +bool(true) +ok diff --git a/Zend/tests/lsb_015.phpt b/Zend/tests/lsb_015.phpt new file mode 100644 index 0000000000..8077a4fb26 --- /dev/null +++ b/Zend/tests/lsb_015.phpt @@ -0,0 +1,92 @@ +--TEST-- +ZE2 Late Static Binding with exceptions +--FILE-- +<?php +function foo() { + B::throwException(); +} +class C { + public static function bla() { + B::throwException(); + } + public static function getException() { + return new Exception(); + + } +} +class A { + + public static function throwException_after() { + C::bla(); + } + public static function throwException() { + throw C::getException(); + } + public static function test() { + static::who(); + } + public static function who() { + echo "A\n"; + } + + public static function mycatch() { + try { + static::who(); + B::throwException_after(); + } catch(Exception $e) { + static::who(); + A::test(); + static::who(); + B::test(); + static::who(); + + self::simpleCatch(); + static::who(); + } + } + + public static function simpleCatch() { + try { + static::who(); + throw new Exception(); + } catch (Exception $e) { + static::who(); + } + } +} + +class B extends A { + public static function who() { + echo "B\n"; + } + +} + +echo "via A:\n"; +A::myCatch(); +echo "via B:\n"; +B::myCatch(); +?> +==DONE== +--EXPECTF-- +via A: +A +A +A +A +B +A +A +A +A +via B: +B +B +A +B +B +B +A +A +B +==DONE== diff --git a/Zend/tests/lsb_016.phpt b/Zend/tests/lsb_016.phpt new file mode 100644 index 0000000000..f19c6aada8 --- /dev/null +++ b/Zend/tests/lsb_016.phpt @@ -0,0 +1,41 @@ +--TEST-- +ZE2 Late Static Binding within hooks/magic methods +--FILE-- +<?php + +class TestChild extends TestParent { + + public static function who() { + echo __CLASS__."\n"; + } +} + +class TestParent { + + public function __get($var) { + static::who(); + } + + public function __set($var, $val) { + static::who(); + } + + public function __call($name, $args) { + static::who(); + } + + public static function who() { + echo __CLASS__."\n"; + } +} +$o = new TestChild; +$o->test(); +$o->a = "b"; +echo $o->a; +?> +==DONE== +--EXPECTF-- +TestChild +TestChild +TestChild +==DONE== diff --git a/Zend/tests/lsb_017.phpt b/Zend/tests/lsb_017.phpt new file mode 100644 index 0000000000..5f5ca4351f --- /dev/null +++ b/Zend/tests/lsb_017.phpt @@ -0,0 +1,29 @@ +--TEST-- +ZE2 Late Static Binding nested calls +--FILE-- +<?php +class A { + public static function test($x=null) { + if (!is_null($x)) { + echo "$x\n"; + } + return get_called_class(); + } +} + +class B extends A { +} +class C extends A { +} +class D extends A { +} + +echo A::test(B::test(C::test(D::test())))."\n"; +?> +==DONE== +--EXPECT-- +D +C +B +A +==DONE== diff --git a/Zend/zend_API.c b/Zend/zend_API.c index 09863d2685..7a5f3892d4 100644 --- a/Zend/zend_API.c +++ b/Zend/zend_API.c @@ -2860,6 +2860,9 @@ ZEND_API zend_bool zend_is_callable_ex(zval *callable, uint check_flags, zval *c lcname_len == sizeof("parent")-1 && ZEND_U_EQUAL(Z_TYPE_PP(obj), lcname, lcname_len, "parent", sizeof("parent")-1)) { ce = EG(active_op_array)->scope->parent; + } else if (lcname_len == sizeof("static")-1 && + ZEND_U_EQUAL(Z_TYPE_PP(obj), lcname, lcname_len, "static", sizeof("static")-1)) { + ce = EG(called_scope); } else if (zend_u_lookup_class(Z_TYPE_PP(obj), Z_UNIVAL_PP(obj), Z_UNILEN_PP(obj), &pce TSRMLS_CC) == SUCCESS) { ce = *pce; } diff --git a/Zend/zend_builtin_functions.c b/Zend/zend_builtin_functions.c index d5f764c5c0..059867e60c 100644 --- a/Zend/zend_builtin_functions.c +++ b/Zend/zend_builtin_functions.c @@ -43,6 +43,7 @@ static ZEND_FUNCTION(error_reporting); static ZEND_FUNCTION(define); static ZEND_FUNCTION(defined); static ZEND_FUNCTION(get_class); +static ZEND_FUNCTION(get_called_class); static ZEND_FUNCTION(get_parent_class); static ZEND_FUNCTION(method_exists); static ZEND_FUNCTION(property_exists); @@ -103,6 +104,7 @@ static zend_function_entry builtin_functions[] = { /* {{{ */ ZEND_FE(define, NULL) ZEND_FE(defined, NULL) ZEND_FE(get_class, NULL) + ZEND_FE(get_called_class, NULL) ZEND_FE(get_parent_class, NULL) ZEND_FE(method_exists, NULL) ZEND_FE(property_exists, NULL) @@ -614,6 +616,27 @@ ZEND_FUNCTION(get_class) } /* }}} */ +/* {{{ proto string get_called_class() + Retrieves the class name */ +ZEND_FUNCTION(get_called_class) +{ + int dup; + + if (!ZEND_NUM_ARGS()) { + if (EG(called_scope)) { + RETURN_TEXTL(EG(called_scope)->name, EG(called_scope)->name_length, 1); + } else { + zend_error(E_WARNING, "get_called_class() called from outside a class"); + RETURN_FALSE; + } + } else { + ZEND_WRONG_PARAM_COUNT(); + RETURN_FALSE; + } +} +/* }}} */ + + /* {{{ proto string get_parent_class([mixed object]) U Retrieves the parent class name for object or class or current scope. */ ZEND_FUNCTION(get_parent_class) diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c index dc7b2c7f1a..bda7271ed6 100644 --- a/Zend/zend_compile.c +++ b/Zend/zend_compile.c @@ -1702,6 +1702,7 @@ void zend_do_fetch_class(znode *result, znode *class_name TSRMLS_DC) /* {{{ */ switch (fetch_type) { case ZEND_FETCH_CLASS_SELF: case ZEND_FETCH_CLASS_PARENT: + case ZEND_FETCH_CLASS_STATIC: SET_UNUSED(opline->op2); opline->extended_value = fetch_type; zval_dtor(&class_name->u.constant); @@ -3220,6 +3221,9 @@ void zend_do_begin_class_declaration(znode *class_token, znode *class_name, znod case ZEND_FETCH_CLASS_PARENT: zend_error(E_COMPILE_ERROR, "Cannot use 'parent' as class name as it is reserved"); break; + case ZEND_FETCH_CLASS_STATIC: + zend_error(E_COMPILE_ERROR, "Cannot use 'static' as class name as it is reserved"); + break; default: break; } @@ -3332,6 +3336,9 @@ void zend_do_implements_interface(znode *interface_name TSRMLS_DC) /* {{{ */ case ZEND_FETCH_CLASS_PARENT: zend_error(E_COMPILE_ERROR, "Cannot use 'parent' as interface name as it is reserved"); break; + case ZEND_FETCH_CLASS_STATIC: + zend_error(E_COMPILE_ERROR, "Cannot use 'static' as interface name as it is reserved"); + break; default: if (CG(active_op_array)->last > 0) { opline = &CG(active_op_array)->opcodes[CG(active_op_array)->last-1]; @@ -4876,6 +4883,9 @@ int zend_get_class_fetch_type(zend_uchar type, zstr class_name, uint class_name_ } else if ((class_name_len == sizeof("parent")-1) && ZEND_U_EQUAL(type, class_name, class_name_len, "parent", sizeof("parent")-1)) { return ZEND_FETCH_CLASS_PARENT; + } else if ((class_name_len == sizeof("static")-1) && + ZEND_U_EQUAL(type, class_name, class_name_len, "static", sizeof("static")-1)) { + return ZEND_FETCH_CLASS_STATIC; } else { return ZEND_FETCH_CLASS_DEFAULT; } diff --git a/Zend/zend_compile.h b/Zend/zend_compile.h index a8caf053f3..6ae2bc5bcb 100644 --- a/Zend/zend_compile.h +++ b/Zend/zend_compile.h @@ -275,9 +275,7 @@ typedef union _zend_function { typedef struct _zend_function_state { - HashTable *function_symbol_table; zend_function *function; - void *reserved[ZEND_MAX_RESERVED_RESOURCES]; } zend_function_state; @@ -300,6 +298,7 @@ struct _zend_execute_data { struct _zend_op *opline; zend_function_state function_state; zend_function *fbc; /* Function Being Called */ + zend_class_entry *called_scope; zend_op_array *op_array; zval *object; union _temp_variable *Ts; @@ -632,6 +631,7 @@ int zendlex(znode *zendlval TSRMLS_DC); #define ZEND_FETCH_CLASS_GLOBAL 4 #define ZEND_FETCH_CLASS_AUTO 5 #define ZEND_FETCH_CLASS_INTERFACE 6 +#define ZEND_FETCH_CLASS_STATIC 7 #define ZEND_FETCH_CLASS_FLAGS 0xF0 #define ZEND_FETCH_CLASS_NO_NORMALIZE 0x10 #define ZEND_FETCH_CLASS_RT_NS_CHECK 0x20 diff --git a/Zend/zend_constants.c b/Zend/zend_constants.c index 85bbc5e728..06b25c3a20 100644 --- a/Zend/zend_constants.c +++ b/Zend/zend_constants.c @@ -382,6 +382,14 @@ ZEND_API int zend_u_get_constant_ex(zend_uchar type, zstr name, uint name_len, z ce = scope->parent; } efree(lcname.v); + } else if (lcname_len == sizeof("static")-1 && + ZEND_U_EQUAL(type, lcname, lcname_len, "static", sizeof("static")-1)) { + if (EG(called_scope)) { + ce = EG(called_scope); + } else { + zend_error(E_ERROR, "Cannot access static:: when no class scope is active"); + } + efree(lcname.v); } else { /* Check for namespace constant */ zstr nsname; diff --git a/Zend/zend_execute.c b/Zend/zend_execute.c index 3d3a5fe43b..3663199b8e 100644 --- a/Zend/zend_execute.c +++ b/Zend/zend_execute.c @@ -150,6 +150,17 @@ static inline void zend_pzval_unlock_free_func(zval *z) /* {{{ */ #define CV_OF(i) (EG(current_execute_data)->CVs[i]) #define CV_DEF_OF(i) (EG(active_op_array)->vars[i]) +#define CTOR_CALL_BIT 0x1 +#define CTOR_USED_BIT 0x2 + +#define IS_CTOR_CALL(ce) (((zend_uintptr_t)(ce)) & CTOR_CALL_BIT) +#define IS_CTOR_USED(ce) (((zend_uintptr_t)(ce)) & CTOR_USED_BIT) + +#define ENCODE_CTOR(ce, used) \ + ((zend_class_entry*)(((zend_uintptr_t)(ce)) | CTOR_CALL_BIT | ((used) ? CTOR_USED_BIT : 0))) +#define DECODE_CTOR(ce) \ + ((zend_class_entry*)(((zend_uintptr_t)(ce)) & ~(CTOR_CALL_BIT|CTOR_USED_BIT))) + ZEND_API zval** zend_get_compiled_variable_value(zend_execute_data *execute_data_ptr, zend_uint var) /* {{{ */ { return execute_data_ptr->CVs[var]; diff --git a/Zend/zend_execute_API.c b/Zend/zend_execute_API.c index 76c31ce7d1..80312c406d 100644 --- a/Zend/zend_execute_API.c +++ b/Zend/zend_execute_API.c @@ -201,6 +201,7 @@ void init_executor(TSRMLS_D) /* {{{ */ EG(exception) = NULL; EG(scope) = NULL; + EG(called_scope) = NULL; EG(This) = NULL; @@ -676,6 +677,7 @@ int zend_call_function(zend_fcall_info *fci, zend_fcall_info_cache *fci_cache TS zend_op_array *original_op_array; zend_op **original_opline_ptr; zend_class_entry *current_scope; + zend_class_entry *current_called_scope; zend_class_entry *calling_scope = NULL; zend_class_entry *check_scope_or_static = NULL; zval *current_this; @@ -784,6 +786,15 @@ int zend_call_function(zend_fcall_info *fci, zend_fcall_info_cache *fci_cache TS found = (*ce != NULL?SUCCESS:FAILURE); fci->object_pp = EG(This)?&EG(This):NULL; EX(object) = EG(This); + } else if (Z_UNILEN_PP(fci->object_pp) == sizeof("static")-1 && + ZEND_U_EQUAL(Z_TYPE_PP(fci->object_pp), Z_UNIVAL_PP(fci->object_pp), Z_UNILEN_PP(fci->object_pp), "static", sizeof("static")-1)) { + if (!EG(called_scope)) { + zend_error(E_ERROR, "Cannot access static:: when no class scope is active"); + } + ce = &(EG(called_scope)); + found = (*ce != NULL?SUCCESS:FAILURE); + fci->object_pp = EG(This)?&EG(This):NULL; + EX(object) = EG(This); } else { zend_class_entry *scope; scope = EG(active_op_array) ? EG(active_op_array)->scope : NULL; @@ -852,6 +863,9 @@ int zend_call_function(zend_fcall_info *fci, zend_fcall_info_cache *fci_cache TS } else if (calling_scope && clen == sizeof("parent") - 1 && ZEND_U_EQUAL(Z_TYPE_P(fci->function_name), lcname, clen, "parent", sizeof("parent")-1)) { ce_child = EG(active_op_array) && EG(active_op_array)->scope ? EG(scope)->parent : NULL; + } else if (clen == sizeof("static") - 1 && + ZEND_U_EQUAL(Z_TYPE_P(fci->function_name), lcname, clen, "static", sizeof("static")-1)) { + ce_child = EG(called_scope); } else if (zend_u_lookup_class_ex(Z_TYPE_P(fci->function_name), lcname, clen, Z_UNIVAL_P(fci->function_name), 0, &pce TSRMLS_CC) == SUCCESS) { ce_child = *pce; } @@ -1028,6 +1042,13 @@ int zend_call_function(zend_fcall_info *fci, zend_fcall_info_cache *fci_cache TS current_this = EG(This); + current_called_scope = EG(called_scope); + if (calling_scope) { + EG(called_scope) = calling_scope; + } else if (EX(function_state).function->type != ZEND_INTERNAL_FUNCTION) { + EG(called_scope) = NULL; + } + if (fci->object_pp) { if ((EX(function_state).function->common.fn_flags & ZEND_ACC_STATIC)) { EG(This) = NULL; @@ -1109,6 +1130,7 @@ int zend_call_function(zend_fcall_info *fci, zend_fcall_info_cache *fci_cache TS if (EG(This)) { zval_ptr_dtor(&EG(This)); } + EG(called_scope) = current_called_scope; EG(scope) = current_scope; EG(This) = current_this; EG(current_execute_data) = EX(prev_execute_data); @@ -1679,6 +1701,11 @@ check_fetch_type: zend_error(E_ERROR, "Cannot access parent:: when current class scope has no parent"); } return EG(scope)->parent; + case ZEND_FETCH_CLASS_STATIC: + if (!EG(called_scope)) { + zend_error(E_ERROR, "Cannot access static:: when no class scope is active"); + } + return EG(called_scope); case ZEND_FETCH_CLASS_AUTO: { if (do_normalize) { lcname = zend_u_str_case_fold(type, class_name, class_name_len, 1, &class_name_len); diff --git a/Zend/zend_globals.h b/Zend/zend_globals.h index 95b5ea94f8..89e2527a31 100644 --- a/Zend/zend_globals.h +++ b/Zend/zend_globals.h @@ -185,6 +185,7 @@ struct _zend_executor_globals { HashTable *zend_constants; /* constants table */ zend_class_entry *scope; + zend_class_entry *called_scope; /* Scope of the calling class */ zval *This; diff --git a/Zend/zend_language_parser.y b/Zend/zend_language_parser.y index 9b11308b1a..bf6b472d24 100644 --- a/Zend/zend_language_parser.y +++ b/Zend/zend_language_parser.y @@ -670,6 +670,7 @@ function_call: fully_qualified_class_name: T_STRING { $$ = $1; } + | T_STATIC { $$.op_type = IS_CONST; ZVAL_ASCII_STRINGL(&$$.u.constant, "static", sizeof("static")-1, 1);} | T_PAAMAYIM_NEKUDOTAYIM T_STRING { zend_do_build_namespace_name(&$$, NULL, &$2 TSRMLS_CC); } | fully_qualified_class_name T_PAAMAYIM_NEKUDOTAYIM T_STRING { zend_do_build_namespace_name(&$$, &$1, &$3 TSRMLS_CC); } ; diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h index 043e9983ea..abcd9fea4f 100644 --- a/Zend/zend_vm_def.h +++ b/Zend/zend_vm_def.h @@ -1736,7 +1736,7 @@ ZEND_VM_HANDLER(112, ZEND_INIT_METHOD_CALL, TMP|VAR|UNUSED|CV, CONST|TMP|VAR|CV) /* FIXME: type is default */ zend_uchar type = UG(unicode)?IS_UNICODE:IS_STRING; - zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), NULL); + zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), EX(called_scope)); function_name = GET_OP2_ZVAL_PTR(BP_VAR_R); @@ -1763,6 +1763,8 @@ ZEND_VM_HANDLER(112, ZEND_INIT_METHOD_CALL, TMP|VAR|UNUSED|CV, CONST|TMP|VAR|CV) zend_error_noreturn(E_ERROR, "Call to a member function %R() on a non-object", Z_TYPE_P(function_name), function_name_strval); } + EX(called_scope) = Z_OBJCE_P(EX(object)); + if (EX(fbc)->common.fn_flags & ZEND_ACC_STATIC) { EX(object) = NULL; } else { @@ -1789,7 +1791,7 @@ ZEND_VM_HANDLER(113, ZEND_INIT_STATIC_METHOD_CALL, CONST|VAR, CONST|TMP|VAR|UNUS zval *function_name; zend_class_entry *ce; - zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), NULL); + zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), EX(called_scope)); if (OP1_TYPE == IS_CONST && OP2_TYPE == IS_CONST) { /* try a function in namespace */ @@ -1850,6 +1852,8 @@ ZEND_VM_HANDLER(113, ZEND_INIT_STATIC_METHOD_CALL, CONST|VAR, CONST|TMP|VAR|UNUS EX(fbc) = ce->constructor; } + EX(called_scope) = ce; + if (EX(fbc)->common.fn_flags & ZEND_ACC_STATIC) { EX(object) = NULL; } else { @@ -1864,6 +1868,7 @@ ZEND_VM_HANDLER(113, ZEND_INIT_STATIC_METHOD_CALL, CONST|VAR, CONST|TMP|VAR|UNUS } if ((EX(object) = EG(This))) { EX(object)->refcount++; + EX(called_scope) = Z_OBJCE_P(EX(object)); } } @@ -1879,7 +1884,7 @@ ZEND_VM_HANDLER(59, ZEND_INIT_FCALL_BY_NAME, ANY, CONST|TMP|VAR|CV) unsigned int function_name_strlen, lcname_len; zend_free_op free_op2; - zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), NULL); + zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), EX(called_scope)); if (OP2_TYPE == IS_CONST) { function_name = &opline->op2.u.constant; @@ -1956,11 +1961,12 @@ ZEND_VM_HELPER(zend_do_fcall_common_helper, ANY, ANY) { zend_op *opline = EX(opline); zval **original_return_value; - zend_class_entry *current_scope = NULL; - zval *current_this = NULL; + zend_class_entry *current_scope; + zend_class_entry *current_called_scope; + zval *current_this; int return_value_used = RETURN_VALUE_USED(opline); zend_bool should_change_scope; - zend_op *ctor_opline; + zval *ex_object; if (EX(function_state).function->common.fn_flags & (ZEND_ACC_ABSTRACT|ZEND_ACC_DEPRECATED)) { if (EX(function_state).function->common.fn_flags & ZEND_ACC_ABSTRACT) { @@ -1975,42 +1981,38 @@ ZEND_VM_HELPER(zend_do_fcall_common_helper, ANY, ANY) EX(function_state).function->common.function_name); } } + if (EX(function_state).function->common.scope && + !(EX(function_state).function->common.fn_flags & ZEND_ACC_STATIC) && + !EX(object)) { + + if (EX(function_state).function->common.fn_flags & ZEND_ACC_ALLOW_STATIC) { + /* FIXME: output identifiers properly */ + zend_error(E_STRICT, "Non-static method %v::%v() should not be called statically", EX(function_state).function->common.scope->name, EX(function_state).function->common.function_name); + } else { + /* FIXME: output identifiers properly */ + zend_error_noreturn(E_ERROR, "Non-static method %v::%v() cannot be called statically", EX(function_state).function->common.scope->name, EX(function_state).function->common.function_name); + } + } - zend_ptr_stack_2_push(&EG(argument_stack), (void *)(zend_uintptr_t)opline->extended_value, NULL); - - EX_T(opline->result.u.var).var.ptr_ptr = &EX_T(opline->result.u.var).var.ptr; - - if (EX(function_state).function->type == ZEND_USER_FUNCTION - || EX(function_state).function->common.scope) { + if (EX(function_state).function->type == ZEND_USER_FUNCTION || + EX(function_state).function->common.scope) { should_change_scope = 1; current_this = EG(This); - EG(This) = EX(object); current_scope = EG(scope); + current_called_scope = EG(called_scope); + EG(This) = EX(object); EG(scope) = (EX(function_state).function->type == ZEND_USER_FUNCTION || !EX(object)) ? EX(function_state).function->common.scope : NULL; + EG(called_scope) = EX(called_scope); } else { should_change_scope = 0; } - EX_T(opline->result.u.var).var.fcall_returned_reference = 0; + zend_ptr_stack_3_pop(&EG(arg_types_stack), (void*)&EX(called_scope), (void**)&ex_object, (void**)&EX(fbc)); + zend_ptr_stack_2_push(&EG(argument_stack), (void *)(zend_uintptr_t)opline->extended_value, NULL); - if (EX(function_state).function->common.scope) { - if (!EG(This) && !(EX(function_state).function->common.fn_flags & ZEND_ACC_STATIC)) { - int severity; - char *severity_word; - if (EX(function_state).function->common.fn_flags & ZEND_ACC_ALLOW_STATIC) { - severity = E_STRICT; - severity_word = "should not"; - } else { - severity = E_ERROR; - severity_word = "cannot"; - } - /* FIXME: output identifiers properly */ - zend_error(severity, "Non-static method %v::%v() %s be called statically", EX(function_state).function->common.scope->name, EX(function_state).function->common.function_name, severity_word); - } - } - if (EX(function_state).function->type == ZEND_INTERNAL_FUNCTION) { - unsigned char return_reference = EX(function_state).function->common.return_reference; + EX_T(opline->result.u.var).var.ptr_ptr = &EX_T(opline->result.u.var).var.ptr; + if (EX(function_state).function->type == ZEND_INTERNAL_FUNCTION) { ALLOC_ZVAL(EX_T(opline->result.u.var).var.ptr); INIT_ZVAL(*(EX_T(opline->result.u.var).var.ptr)); @@ -2046,21 +2048,23 @@ ZEND_VM_HELPER(zend_do_fcall_common_helper, ANY, ANY) if (!return_value_used) { zval_ptr_dtor(&EX_T(opline->result.u.var).var.ptr); } else { - EX_T(opline->result.u.var).var.fcall_returned_reference = return_reference; + EX_T(opline->result.u.var).var.fcall_returned_reference = EX(function_state).function->common.return_reference; } } else if (EX(function_state).function->type == ZEND_USER_FUNCTION) { + HashTable *function_symbol_table; + EX_T(opline->result.u.var).var.ptr = NULL; if (EG(symtable_cache_ptr)>=EG(symtable_cache)) { /*printf("Cache hit! Reusing %x\n", symtable_cache[symtable_cache_ptr]);*/ - EX(function_state).function_symbol_table = *(EG(symtable_cache_ptr)--); + function_symbol_table = *(EG(symtable_cache_ptr)--); } else { - ALLOC_HASHTABLE(EX(function_state).function_symbol_table); - zend_u_hash_init(EX(function_state).function_symbol_table, 0, NULL, ZVAL_PTR_DTOR, 0, UG(unicode)); - /*printf("Cache miss! Initialized %x\n", function_state.function_symbol_table);*/ + ALLOC_HASHTABLE(function_symbol_table); + zend_u_hash_init(function_symbol_table, 0, NULL, ZVAL_PTR_DTOR, 0, UG(unicode)); + /*printf("Cache miss! Initialized %x\n", function_symbol_table);*/ } - EG(active_symbol_table) = EX(function_state).function_symbol_table; + EG(active_symbol_table) = function_symbol_table; original_return_value = EG(return_value_ptr_ptr); - EG(return_value_ptr_ptr) = EX_T(opline->result.u.var).var.ptr_ptr; + EG(return_value_ptr_ptr) = &EX_T(opline->result.u.var).var.ptr; EG(active_op_array) = (zend_op_array *) EX(function_state).function; zend_execute(EG(active_op_array) TSRMLS_CC); @@ -2079,13 +2083,13 @@ ZEND_VM_HELPER(zend_do_fcall_common_helper, ANY, ANY) EG(active_op_array) = EX(op_array); EG(return_value_ptr_ptr)=original_return_value; if (EG(symtable_cache_ptr)>=EG(symtable_cache_limit)) { - zend_hash_destroy(EX(function_state).function_symbol_table); - FREE_HASHTABLE(EX(function_state).function_symbol_table); + zend_hash_destroy(function_symbol_table); + FREE_HASHTABLE(function_symbol_table); } else { /* clean before putting into the cache, since clean could call dtors, which could use cached hash */ - zend_hash_clean(EX(function_state).function_symbol_table); - *(++EG(symtable_cache_ptr)) = EX(function_state).function_symbol_table; + zend_hash_clean(function_symbol_table); + *(++EG(symtable_cache_ptr)) = function_symbol_table; } EG(active_symbol_table) = EX(symbol_table); } else { /* ZEND_OVERLOADED_FUNCTION */ @@ -2094,7 +2098,7 @@ ZEND_VM_HELPER(zend_do_fcall_common_helper, ANY, ANY) /* Not sure what should be done here if it's a static method */ if (EX(object)) { - Z_OBJ_HT_P(EX(object))->call_method(EX(fbc)->common.function_name, opline->extended_value, EX_T(opline->result.u.var).var.ptr, &EX_T(opline->result.u.var).var.ptr, EX(object), return_value_used TSRMLS_CC); + Z_OBJ_HT_P(EX(object))->call_method(EX(function_state).function->common.function_name, opline->extended_value, EX_T(opline->result.u.var).var.ptr, &EX_T(opline->result.u.var).var.ptr, EX(object), return_value_used TSRMLS_CC); } else { zend_error_noreturn(E_ERROR, "Cannot call overloaded function for non-object"); } @@ -2102,21 +2106,20 @@ ZEND_VM_HELPER(zend_do_fcall_common_helper, ANY, ANY) if (EX(function_state).function->type == ZEND_OVERLOADED_FUNCTION_TEMPORARY) { efree(EX(function_state).function->common.function_name.v); } - efree(EX(fbc)); + efree(EX(function_state).function); if (!return_value_used) { zval_ptr_dtor(&EX_T(opline->result.u.var).var.ptr); } else { EX_T(opline->result.u.var).var.ptr->is_ref = 0; EX_T(opline->result.u.var).var.ptr->refcount = 1; + EX_T(opline->result.u.var).var.fcall_returned_reference = 0; } } - ctor_opline = (zend_op*)zend_ptr_stack_pop(&EG(arg_types_stack)); - if (EG(This)) { - if (EG(exception) && ctor_opline) { - if (RETURN_VALUE_USED(ctor_opline)) { + if (EG(exception) && IS_CTOR_CALL(EX(called_scope))) { + if (IS_CTOR_USED(EX(called_scope))) { EG(This)->refcount--; } if (EG(This)->refcount == 1) { @@ -2128,11 +2131,14 @@ ZEND_VM_HELPER(zend_do_fcall_common_helper, ANY, ANY) } } + EX(object) = ex_object; + EX(called_scope) = DECODE_CTOR(EX(called_scope)); + if (should_change_scope) { EG(This) = current_this; EG(scope) = current_scope; + EG(called_scope) = current_called_scope; } - zend_ptr_stack_2_pop(&EG(arg_types_stack), (void**)&EX(object), (void**)&EX(fbc)); EX(function_state).function = (zend_function *) EX(op_array); EG(function_state_ptr) = &EX(function_state); @@ -2160,7 +2166,7 @@ ZEND_VM_HANDLER(60, ZEND_DO_FCALL, CONST, ANY) zend_free_op free_op1; zval *fname = GET_OP1_ZVAL_PTR(BP_VAR_R); - zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), NULL); + zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), EX(called_scope)); if (zend_u_hash_find(EG(function_table), Z_TYPE_P(fname), Z_UNIVAL_P(fname), Z_UNILEN_P(fname)+1, (void **) &EX(function_state).function)==FAILURE) { /* FIXME: output identifiers properly */ @@ -2631,11 +2637,12 @@ ZEND_VM_HANDLER(68, ZEND_NEW, ANY, ANY) EX_T(opline->result.u.var).var.ptr_ptr = &EX_T(opline->result.u.var).var.ptr; EX_T(opline->result.u.var).var.ptr = object_zval; - zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), opline); + zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), ENCODE_CTOR(EX(called_scope), RETURN_VALUE_USED(opline))); /* We are not handling overloaded classes right now */ EX(object) = object_zval; EX(fbc) = constructor; + EX(called_scope) = EX_T(opline->op1.u.var).class_entry; ZEND_VM_NEXT_OPCODE(); } @@ -4030,14 +4037,14 @@ ZEND_VM_HANDLER(149, ZEND_HANDLE_EXCEPTION, ANY, ANY) } while (EX(fbc)) { - zend_op *ctor_opline = (zend_op*)zend_ptr_stack_pop(&EG(arg_types_stack)); - + EX(called_scope) = (zend_class_entry*)zend_ptr_stack_pop(&EG(arg_types_stack)); if (EX(object)) { - if (ctor_opline && RETURN_VALUE_USED(ctor_opline)) { + if (IS_CTOR_USED(EX(called_scope))) { EX(object)->refcount--; } zval_ptr_dtor(&EX(object)); } + EX(called_scope) = DECODE_CTOR(EX(called_scope)); zend_ptr_stack_2_pop(&EG(arg_types_stack), (void**)&EX(object), (void**)&EX(fbc)); } diff --git a/Zend/zend_vm_execute.h b/Zend/zend_vm_execute.h index 1756076a38..0fafe11e82 100644 --- a/Zend/zend_vm_execute.h +++ b/Zend/zend_vm_execute.h @@ -42,6 +42,7 @@ ZEND_API void execute(zend_op_array *op_array TSRMLS_DC) /* Initialize execute_data */ EX(fbc) = NULL; + EX(called_scope) = NULL; EX(object) = NULL; EX(old_error_reporting) = NULL; if (op_array->T < TEMP_VAR_STACK_LIMIT) { @@ -75,12 +76,6 @@ ZEND_API void execute(zend_op_array *op_array TSRMLS_DC) EX(function_state).function = (zend_function *) op_array; EG(function_state_ptr) = &EX(function_state); -#if ZEND_DEBUG - /* function_state.function_symbol_table is saved as-is to a stack, - * which is an intentional UMR. Shut it up if we're in DEBUG. - */ - EX(function_state).function_symbol_table = NULL; -#endif while (1) { #ifdef ZEND_WIN32 @@ -133,11 +128,12 @@ static int zend_do_fcall_common_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS) { zend_op *opline = EX(opline); zval **original_return_value; - zend_class_entry *current_scope = NULL; - zval *current_this = NULL; + zend_class_entry *current_scope; + zend_class_entry *current_called_scope; + zval *current_this; int return_value_used = RETURN_VALUE_USED(opline); zend_bool should_change_scope; - zend_op *ctor_opline; + zval *ex_object; if (EX(function_state).function->common.fn_flags & (ZEND_ACC_ABSTRACT|ZEND_ACC_DEPRECATED)) { if (EX(function_state).function->common.fn_flags & ZEND_ACC_ABSTRACT) { @@ -152,42 +148,38 @@ static int zend_do_fcall_common_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS) EX(function_state).function->common.function_name); } } + if (EX(function_state).function->common.scope && + !(EX(function_state).function->common.fn_flags & ZEND_ACC_STATIC) && + !EX(object)) { - zend_ptr_stack_2_push(&EG(argument_stack), (void *)(zend_uintptr_t)opline->extended_value, NULL); - - EX_T(opline->result.u.var).var.ptr_ptr = &EX_T(opline->result.u.var).var.ptr; + if (EX(function_state).function->common.fn_flags & ZEND_ACC_ALLOW_STATIC) { + /* FIXME: output identifiers properly */ + zend_error(E_STRICT, "Non-static method %v::%v() should not be called statically", EX(function_state).function->common.scope->name, EX(function_state).function->common.function_name); + } else { + /* FIXME: output identifiers properly */ + zend_error_noreturn(E_ERROR, "Non-static method %v::%v() cannot be called statically", EX(function_state).function->common.scope->name, EX(function_state).function->common.function_name); + } + } - if (EX(function_state).function->type == ZEND_USER_FUNCTION - || EX(function_state).function->common.scope) { + if (EX(function_state).function->type == ZEND_USER_FUNCTION || + EX(function_state).function->common.scope) { should_change_scope = 1; current_this = EG(This); - EG(This) = EX(object); current_scope = EG(scope); + current_called_scope = EG(called_scope); + EG(This) = EX(object); EG(scope) = (EX(function_state).function->type == ZEND_USER_FUNCTION || !EX(object)) ? EX(function_state).function->common.scope : NULL; + EG(called_scope) = EX(called_scope); } else { should_change_scope = 0; } - EX_T(opline->result.u.var).var.fcall_returned_reference = 0; + zend_ptr_stack_3_pop(&EG(arg_types_stack), (void*)&EX(called_scope), (void**)&ex_object, (void**)&EX(fbc)); + zend_ptr_stack_2_push(&EG(argument_stack), (void *)(zend_uintptr_t)opline->extended_value, NULL); + + EX_T(opline->result.u.var).var.ptr_ptr = &EX_T(opline->result.u.var).var.ptr; - if (EX(function_state).function->common.scope) { - if (!EG(This) && !(EX(function_state).function->common.fn_flags & ZEND_ACC_STATIC)) { - int severity; - char *severity_word; - if (EX(function_state).function->common.fn_flags & ZEND_ACC_ALLOW_STATIC) { - severity = E_STRICT; - severity_word = "should not"; - } else { - severity = E_ERROR; - severity_word = "cannot"; - } - /* FIXME: output identifiers properly */ - zend_error(severity, "Non-static method %v::%v() %s be called statically", EX(function_state).function->common.scope->name, EX(function_state).function->common.function_name, severity_word); - } - } if (EX(function_state).function->type == ZEND_INTERNAL_FUNCTION) { - unsigned char return_reference = EX(function_state).function->common.return_reference; - ALLOC_ZVAL(EX_T(opline->result.u.var).var.ptr); INIT_ZVAL(*(EX_T(opline->result.u.var).var.ptr)); @@ -223,21 +215,23 @@ static int zend_do_fcall_common_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS) if (!return_value_used) { zval_ptr_dtor(&EX_T(opline->result.u.var).var.ptr); } else { - EX_T(opline->result.u.var).var.fcall_returned_reference = return_reference; + EX_T(opline->result.u.var).var.fcall_returned_reference = EX(function_state).function->common.return_reference; } } else if (EX(function_state).function->type == ZEND_USER_FUNCTION) { + HashTable *function_symbol_table; + EX_T(opline->result.u.var).var.ptr = NULL; if (EG(symtable_cache_ptr)>=EG(symtable_cache)) { /*printf("Cache hit! Reusing %x\n", symtable_cache[symtable_cache_ptr]);*/ - EX(function_state).function_symbol_table = *(EG(symtable_cache_ptr)--); + function_symbol_table = *(EG(symtable_cache_ptr)--); } else { - ALLOC_HASHTABLE(EX(function_state).function_symbol_table); - zend_u_hash_init(EX(function_state).function_symbol_table, 0, NULL, ZVAL_PTR_DTOR, 0, UG(unicode)); - /*printf("Cache miss! Initialized %x\n", function_state.function_symbol_table);*/ + ALLOC_HASHTABLE(function_symbol_table); + zend_u_hash_init(function_symbol_table, 0, NULL, ZVAL_PTR_DTOR, 0, UG(unicode)); + /*printf("Cache miss! Initialized %x\n", function_symbol_table);*/ } - EG(active_symbol_table) = EX(function_state).function_symbol_table; + EG(active_symbol_table) = function_symbol_table; original_return_value = EG(return_value_ptr_ptr); - EG(return_value_ptr_ptr) = EX_T(opline->result.u.var).var.ptr_ptr; + EG(return_value_ptr_ptr) = &EX_T(opline->result.u.var).var.ptr; EG(active_op_array) = (zend_op_array *) EX(function_state).function; zend_execute(EG(active_op_array) TSRMLS_CC); @@ -256,13 +250,13 @@ static int zend_do_fcall_common_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS) EG(active_op_array) = EX(op_array); EG(return_value_ptr_ptr)=original_return_value; if (EG(symtable_cache_ptr)>=EG(symtable_cache_limit)) { - zend_hash_destroy(EX(function_state).function_symbol_table); - FREE_HASHTABLE(EX(function_state).function_symbol_table); + zend_hash_destroy(function_symbol_table); + FREE_HASHTABLE(function_symbol_table); } else { /* clean before putting into the cache, since clean could call dtors, which could use cached hash */ - zend_hash_clean(EX(function_state).function_symbol_table); - *(++EG(symtable_cache_ptr)) = EX(function_state).function_symbol_table; + zend_hash_clean(function_symbol_table); + *(++EG(symtable_cache_ptr)) = function_symbol_table; } EG(active_symbol_table) = EX(symbol_table); } else { /* ZEND_OVERLOADED_FUNCTION */ @@ -271,7 +265,7 @@ static int zend_do_fcall_common_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS) /* Not sure what should be done here if it's a static method */ if (EX(object)) { - Z_OBJ_HT_P(EX(object))->call_method(EX(fbc)->common.function_name, opline->extended_value, EX_T(opline->result.u.var).var.ptr, &EX_T(opline->result.u.var).var.ptr, EX(object), return_value_used TSRMLS_CC); + Z_OBJ_HT_P(EX(object))->call_method(EX(function_state).function->common.function_name, opline->extended_value, EX_T(opline->result.u.var).var.ptr, &EX_T(opline->result.u.var).var.ptr, EX(object), return_value_used TSRMLS_CC); } else { zend_error_noreturn(E_ERROR, "Cannot call overloaded function for non-object"); } @@ -279,21 +273,20 @@ static int zend_do_fcall_common_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS) if (EX(function_state).function->type == ZEND_OVERLOADED_FUNCTION_TEMPORARY) { efree(EX(function_state).function->common.function_name.v); } - efree(EX(fbc)); + efree(EX(function_state).function); if (!return_value_used) { zval_ptr_dtor(&EX_T(opline->result.u.var).var.ptr); } else { EX_T(opline->result.u.var).var.ptr->is_ref = 0; EX_T(opline->result.u.var).var.ptr->refcount = 1; + EX_T(opline->result.u.var).var.fcall_returned_reference = 0; } } - ctor_opline = (zend_op*)zend_ptr_stack_pop(&EG(arg_types_stack)); - if (EG(This)) { - if (EG(exception) && ctor_opline) { - if (RETURN_VALUE_USED(ctor_opline)) { + if (EG(exception) && IS_CTOR_CALL(EX(called_scope))) { + if (IS_CTOR_USED(EX(called_scope))) { EG(This)->refcount--; } if (EG(This)->refcount == 1) { @@ -305,11 +298,14 @@ static int zend_do_fcall_common_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS) } } + EX(object) = ex_object; + EX(called_scope) = DECODE_CTOR(EX(called_scope)); + if (should_change_scope) { EG(This) = current_this; EG(scope) = current_scope; + EG(called_scope) = current_called_scope; } - zend_ptr_stack_2_pop(&EG(arg_types_stack), (void**)&EX(object), (void**)&EX(fbc)); EX(function_state).function = (zend_function *) EX(op_array); EG(function_state_ptr) = &EX(function_state); @@ -431,11 +427,12 @@ static int ZEND_NEW_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ARGS) EX_T(opline->result.u.var).var.ptr_ptr = &EX_T(opline->result.u.var).var.ptr; EX_T(opline->result.u.var).var.ptr = object_zval; - zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), opline); + zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), ENCODE_CTOR(EX(called_scope), RETURN_VALUE_USED(opline))); /* We are not handling overloaded classes right now */ EX(object) = object_zval; EX(fbc) = constructor; + EX(called_scope) = EX_T(opline->op1.u.var).class_entry; ZEND_VM_NEXT_OPCODE(); } @@ -564,14 +561,14 @@ static int ZEND_HANDLE_EXCEPTION_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ARGS) } while (EX(fbc)) { - zend_op *ctor_opline = (zend_op*)zend_ptr_stack_pop(&EG(arg_types_stack)); - + EX(called_scope) = (zend_class_entry*)zend_ptr_stack_pop(&EG(arg_types_stack)); if (EX(object)) { - if (ctor_opline && RETURN_VALUE_USED(ctor_opline)) { + if (IS_CTOR_USED(EX(called_scope))) { EX(object)->refcount--; } zval_ptr_dtor(&EX(object)); } + EX(called_scope) = DECODE_CTOR(EX(called_scope)); zend_ptr_stack_2_pop(&EG(arg_types_stack), (void**)&EX(object), (void**)&EX(fbc)); } @@ -676,7 +673,7 @@ static int ZEND_INIT_FCALL_BY_NAME_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) unsigned int function_name_strlen, lcname_len; - zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), NULL); + zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), EX(called_scope)); if (IS_CONST == IS_CONST) { function_name = &opline->op2.u.constant; @@ -874,7 +871,7 @@ static int ZEND_INIT_FCALL_BY_NAME_SPEC_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS) unsigned int function_name_strlen, lcname_len; zend_free_op free_op2; - zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), NULL); + zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), EX(called_scope)); if (IS_TMP_VAR == IS_CONST) { function_name = &opline->op2.u.constant; @@ -987,7 +984,7 @@ static int ZEND_INIT_FCALL_BY_NAME_SPEC_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) unsigned int function_name_strlen, lcname_len; zend_free_op free_op2; - zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), NULL); + zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), EX(called_scope)); if (IS_VAR == IS_CONST) { function_name = &opline->op2.u.constant; @@ -1129,7 +1126,7 @@ static int ZEND_INIT_FCALL_BY_NAME_SPEC_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) unsigned int function_name_strlen, lcname_len; - zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), NULL); + zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), EX(called_scope)); if (IS_CV == IS_CONST) { function_name = &opline->op2.u.constant; @@ -1501,7 +1498,7 @@ static int ZEND_DO_FCALL_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) zval *fname = &opline->op1.u.constant; - zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), NULL); + zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), EX(called_scope)); if (zend_u_hash_find(EG(function_table), Z_TYPE_P(fname), Z_UNIVAL_P(fname), Z_UNILEN_P(fname)+1, (void **) &EX(function_state).function)==FAILURE) { /* FIXME: output identifiers properly */ @@ -2541,7 +2538,7 @@ static int ZEND_INIT_STATIC_METHOD_CALL_SPEC_CONST_CONST_HANDLER(ZEND_OPCODE_HAN zval *function_name; zend_class_entry *ce; - zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), NULL); + zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), EX(called_scope)); if (IS_CONST == IS_CONST && IS_CONST == IS_CONST) { /* try a function in namespace */ @@ -2602,6 +2599,8 @@ static int ZEND_INIT_STATIC_METHOD_CALL_SPEC_CONST_CONST_HANDLER(ZEND_OPCODE_HAN EX(fbc) = ce->constructor; } + EX(called_scope) = ce; + if (EX(fbc)->common.fn_flags & ZEND_ACC_STATIC) { EX(object) = NULL; } else { @@ -2616,6 +2615,7 @@ static int ZEND_INIT_STATIC_METHOD_CALL_SPEC_CONST_CONST_HANDLER(ZEND_OPCODE_HAN } if ((EX(object) = EG(This))) { EX(object)->refcount++; + EX(called_scope) = Z_OBJCE_P(EX(object)); } } @@ -3092,7 +3092,7 @@ static int ZEND_INIT_STATIC_METHOD_CALL_SPEC_CONST_TMP_HANDLER(ZEND_OPCODE_HANDL zval *function_name; zend_class_entry *ce; - zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), NULL); + zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), EX(called_scope)); if (IS_CONST == IS_CONST && IS_TMP_VAR == IS_CONST) { /* try a function in namespace */ @@ -3153,6 +3153,8 @@ static int ZEND_INIT_STATIC_METHOD_CALL_SPEC_CONST_TMP_HANDLER(ZEND_OPCODE_HANDL EX(fbc) = ce->constructor; } + EX(called_scope) = ce; + if (EX(fbc)->common.fn_flags & ZEND_ACC_STATIC) { EX(object) = NULL; } else { @@ -3167,6 +3169,7 @@ static int ZEND_INIT_STATIC_METHOD_CALL_SPEC_CONST_TMP_HANDLER(ZEND_OPCODE_HANDL } if ((EX(object) = EG(This))) { EX(object)->refcount++; + EX(called_scope) = Z_OBJCE_P(EX(object)); } } @@ -3539,7 +3542,7 @@ static int ZEND_INIT_STATIC_METHOD_CALL_SPEC_CONST_VAR_HANDLER(ZEND_OPCODE_HANDL zval *function_name; zend_class_entry *ce; - zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), NULL); + zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), EX(called_scope)); if (IS_CONST == IS_CONST && IS_VAR == IS_CONST) { /* try a function in namespace */ @@ -3600,6 +3603,8 @@ static int ZEND_INIT_STATIC_METHOD_CALL_SPEC_CONST_VAR_HANDLER(ZEND_OPCODE_HANDL EX(fbc) = ce->constructor; } + EX(called_scope) = ce; + if (EX(fbc)->common.fn_flags & ZEND_ACC_STATIC) { EX(object) = NULL; } else { @@ -3614,6 +3619,7 @@ static int ZEND_INIT_STATIC_METHOD_CALL_SPEC_CONST_VAR_HANDLER(ZEND_OPCODE_HANDL } if ((EX(object) = EG(This))) { EX(object)->refcount++; + EX(called_scope) = Z_OBJCE_P(EX(object)); } } @@ -3752,7 +3758,7 @@ static int ZEND_INIT_STATIC_METHOD_CALL_SPEC_CONST_UNUSED_HANDLER(ZEND_OPCODE_HA zval *function_name; zend_class_entry *ce; - zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), NULL); + zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), EX(called_scope)); if (IS_CONST == IS_CONST && IS_UNUSED == IS_CONST) { /* try a function in namespace */ @@ -3813,6 +3819,8 @@ static int ZEND_INIT_STATIC_METHOD_CALL_SPEC_CONST_UNUSED_HANDLER(ZEND_OPCODE_HA EX(fbc) = ce->constructor; } + EX(called_scope) = ce; + if (EX(fbc)->common.fn_flags & ZEND_ACC_STATIC) { EX(object) = NULL; } else { @@ -3827,6 +3835,7 @@ static int ZEND_INIT_STATIC_METHOD_CALL_SPEC_CONST_UNUSED_HANDLER(ZEND_OPCODE_HA } if ((EX(object) = EG(This))) { EX(object)->refcount++; + EX(called_scope) = Z_OBJCE_P(EX(object)); } } @@ -4167,7 +4176,7 @@ static int ZEND_INIT_STATIC_METHOD_CALL_SPEC_CONST_CV_HANDLER(ZEND_OPCODE_HANDLE zval *function_name; zend_class_entry *ce; - zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), NULL); + zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), EX(called_scope)); if (IS_CONST == IS_CONST && IS_CV == IS_CONST) { /* try a function in namespace */ @@ -4228,6 +4237,8 @@ static int ZEND_INIT_STATIC_METHOD_CALL_SPEC_CONST_CV_HANDLER(ZEND_OPCODE_HANDLE EX(fbc) = ce->constructor; } + EX(called_scope) = ce; + if (EX(fbc)->common.fn_flags & ZEND_ACC_STATIC) { EX(object) = NULL; } else { @@ -4242,6 +4253,7 @@ static int ZEND_INIT_STATIC_METHOD_CALL_SPEC_CONST_CV_HANDLER(ZEND_OPCODE_HANDLE } if ((EX(object) = EG(This))) { EX(object)->refcount++; + EX(called_scope) = Z_OBJCE_P(EX(object)); } } @@ -5766,7 +5778,7 @@ static int ZEND_INIT_METHOD_CALL_SPEC_TMP_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS /* FIXME: type is default */ zend_uchar type = UG(unicode)?IS_UNICODE:IS_STRING; - zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), NULL); + zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), EX(called_scope)); function_name = &opline->op2.u.constant; @@ -5793,6 +5805,8 @@ static int ZEND_INIT_METHOD_CALL_SPEC_TMP_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS zend_error_noreturn(E_ERROR, "Call to a member function %R() on a non-object", Z_TYPE_P(function_name), function_name_strval); } + EX(called_scope) = Z_OBJCE_P(EX(object)); + if (EX(fbc)->common.fn_flags & ZEND_ACC_STATIC) { EX(object) = NULL; } else { @@ -6215,7 +6229,7 @@ static int ZEND_INIT_METHOD_CALL_SPEC_TMP_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS) /* FIXME: type is default */ zend_uchar type = UG(unicode)?IS_UNICODE:IS_STRING; - zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), NULL); + zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), EX(called_scope)); function_name = _get_zval_ptr_tmp(&opline->op2, EX(Ts), &free_op2 TSRMLS_CC); @@ -6242,6 +6256,8 @@ static int ZEND_INIT_METHOD_CALL_SPEC_TMP_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS) zend_error_noreturn(E_ERROR, "Call to a member function %R() on a non-object", Z_TYPE_P(function_name), function_name_strval); } + EX(called_scope) = Z_OBJCE_P(EX(object)); + if (EX(fbc)->common.fn_flags & ZEND_ACC_STATIC) { EX(object) = NULL; } else { @@ -6666,7 +6682,7 @@ static int ZEND_INIT_METHOD_CALL_SPEC_TMP_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) /* FIXME: type is default */ zend_uchar type = UG(unicode)?IS_UNICODE:IS_STRING; - zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), NULL); + zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), EX(called_scope)); function_name = _get_zval_ptr_var(&opline->op2, EX(Ts), &free_op2 TSRMLS_CC); @@ -6693,6 +6709,8 @@ static int ZEND_INIT_METHOD_CALL_SPEC_TMP_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) zend_error_noreturn(E_ERROR, "Call to a member function %R() on a non-object", Z_TYPE_P(function_name), function_name_strval); } + EX(called_scope) = Z_OBJCE_P(EX(object)); + if (EX(fbc)->common.fn_flags & ZEND_ACC_STATIC) { EX(object) = NULL; } else { @@ -7210,7 +7228,7 @@ static int ZEND_INIT_METHOD_CALL_SPEC_TMP_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) /* FIXME: type is default */ zend_uchar type = UG(unicode)?IS_UNICODE:IS_STRING; - zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), NULL); + zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), EX(called_scope)); function_name = _get_zval_ptr_cv(&opline->op2, EX(Ts), BP_VAR_R TSRMLS_CC); @@ -7237,6 +7255,8 @@ static int ZEND_INIT_METHOD_CALL_SPEC_TMP_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) zend_error_noreturn(E_ERROR, "Call to a member function %R() on a non-object", Z_TYPE_P(function_name), function_name_strval); } + EX(called_scope) = Z_OBJCE_P(EX(object)); + if (EX(fbc)->common.fn_flags & ZEND_ACC_STATIC) { EX(object) = NULL; } else { @@ -9962,7 +9982,7 @@ static int ZEND_INIT_METHOD_CALL_SPEC_VAR_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS /* FIXME: type is default */ zend_uchar type = UG(unicode)?IS_UNICODE:IS_STRING; - zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), NULL); + zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), EX(called_scope)); function_name = &opline->op2.u.constant; @@ -9989,6 +10009,8 @@ static int ZEND_INIT_METHOD_CALL_SPEC_VAR_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS zend_error_noreturn(E_ERROR, "Call to a member function %R() on a non-object", Z_TYPE_P(function_name), function_name_strval); } + EX(called_scope) = Z_OBJCE_P(EX(object)); + if (EX(fbc)->common.fn_flags & ZEND_ACC_STATIC) { EX(object) = NULL; } else { @@ -10014,7 +10036,7 @@ static int ZEND_INIT_STATIC_METHOD_CALL_SPEC_VAR_CONST_HANDLER(ZEND_OPCODE_HANDL zval *function_name; zend_class_entry *ce; - zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), NULL); + zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), EX(called_scope)); if (IS_VAR == IS_CONST && IS_CONST == IS_CONST) { /* try a function in namespace */ @@ -10075,6 +10097,8 @@ static int ZEND_INIT_STATIC_METHOD_CALL_SPEC_VAR_CONST_HANDLER(ZEND_OPCODE_HANDL EX(fbc) = ce->constructor; } + EX(called_scope) = ce; + if (EX(fbc)->common.fn_flags & ZEND_ACC_STATIC) { EX(object) = NULL; } else { @@ -10089,6 +10113,7 @@ static int ZEND_INIT_STATIC_METHOD_CALL_SPEC_VAR_CONST_HANDLER(ZEND_OPCODE_HANDL } if ((EX(object) = EG(This))) { EX(object)->refcount++; + EX(called_scope) = Z_OBJCE_P(EX(object)); } } @@ -11659,7 +11684,7 @@ static int ZEND_INIT_METHOD_CALL_SPEC_VAR_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS) /* FIXME: type is default */ zend_uchar type = UG(unicode)?IS_UNICODE:IS_STRING; - zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), NULL); + zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), EX(called_scope)); function_name = _get_zval_ptr_tmp(&opline->op2, EX(Ts), &free_op2 TSRMLS_CC); @@ -11686,6 +11711,8 @@ static int ZEND_INIT_METHOD_CALL_SPEC_VAR_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS) zend_error_noreturn(E_ERROR, "Call to a member function %R() on a non-object", Z_TYPE_P(function_name), function_name_strval); } + EX(called_scope) = Z_OBJCE_P(EX(object)); + if (EX(fbc)->common.fn_flags & ZEND_ACC_STATIC) { EX(object) = NULL; } else { @@ -11712,7 +11739,7 @@ static int ZEND_INIT_STATIC_METHOD_CALL_SPEC_VAR_TMP_HANDLER(ZEND_OPCODE_HANDLER zval *function_name; zend_class_entry *ce; - zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), NULL); + zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), EX(called_scope)); if (IS_VAR == IS_CONST && IS_TMP_VAR == IS_CONST) { /* try a function in namespace */ @@ -11773,6 +11800,8 @@ static int ZEND_INIT_STATIC_METHOD_CALL_SPEC_VAR_TMP_HANDLER(ZEND_OPCODE_HANDLER EX(fbc) = ce->constructor; } + EX(called_scope) = ce; + if (EX(fbc)->common.fn_flags & ZEND_ACC_STATIC) { EX(object) = NULL; } else { @@ -11787,6 +11816,7 @@ static int ZEND_INIT_STATIC_METHOD_CALL_SPEC_VAR_TMP_HANDLER(ZEND_OPCODE_HANDLER } if ((EX(object) = EG(This))) { EX(object)->refcount++; + EX(called_scope) = Z_OBJCE_P(EX(object)); } } @@ -13329,7 +13359,7 @@ static int ZEND_INIT_METHOD_CALL_SPEC_VAR_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) /* FIXME: type is default */ zend_uchar type = UG(unicode)?IS_UNICODE:IS_STRING; - zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), NULL); + zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), EX(called_scope)); function_name = _get_zval_ptr_var(&opline->op2, EX(Ts), &free_op2 TSRMLS_CC); @@ -13356,6 +13386,8 @@ static int ZEND_INIT_METHOD_CALL_SPEC_VAR_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) zend_error_noreturn(E_ERROR, "Call to a member function %R() on a non-object", Z_TYPE_P(function_name), function_name_strval); } + EX(called_scope) = Z_OBJCE_P(EX(object)); + if (EX(fbc)->common.fn_flags & ZEND_ACC_STATIC) { EX(object) = NULL; } else { @@ -13382,7 +13414,7 @@ static int ZEND_INIT_STATIC_METHOD_CALL_SPEC_VAR_VAR_HANDLER(ZEND_OPCODE_HANDLER zval *function_name; zend_class_entry *ce; - zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), NULL); + zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), EX(called_scope)); if (IS_VAR == IS_CONST && IS_VAR == IS_CONST) { /* try a function in namespace */ @@ -13443,6 +13475,8 @@ static int ZEND_INIT_STATIC_METHOD_CALL_SPEC_VAR_VAR_HANDLER(ZEND_OPCODE_HANDLER EX(fbc) = ce->constructor; } + EX(called_scope) = ce; + if (EX(fbc)->common.fn_flags & ZEND_ACC_STATIC) { EX(object) = NULL; } else { @@ -13457,6 +13491,7 @@ static int ZEND_INIT_STATIC_METHOD_CALL_SPEC_VAR_VAR_HANDLER(ZEND_OPCODE_HANDLER } if ((EX(object) = EG(This))) { EX(object)->refcount++; + EX(called_scope) = Z_OBJCE_P(EX(object)); } } @@ -14250,7 +14285,7 @@ static int ZEND_INIT_STATIC_METHOD_CALL_SPEC_VAR_UNUSED_HANDLER(ZEND_OPCODE_HAND zval *function_name; zend_class_entry *ce; - zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), NULL); + zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), EX(called_scope)); if (IS_VAR == IS_CONST && IS_UNUSED == IS_CONST) { /* try a function in namespace */ @@ -14311,6 +14346,8 @@ static int ZEND_INIT_STATIC_METHOD_CALL_SPEC_VAR_UNUSED_HANDLER(ZEND_OPCODE_HAND EX(fbc) = ce->constructor; } + EX(called_scope) = ce; + if (EX(fbc)->common.fn_flags & ZEND_ACC_STATIC) { EX(object) = NULL; } else { @@ -14325,6 +14362,7 @@ static int ZEND_INIT_STATIC_METHOD_CALL_SPEC_VAR_UNUSED_HANDLER(ZEND_OPCODE_HAND } if ((EX(object) = EG(This))) { EX(object)->refcount++; + EX(called_scope) = Z_OBJCE_P(EX(object)); } } @@ -15518,7 +15556,7 @@ static int ZEND_INIT_METHOD_CALL_SPEC_VAR_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) /* FIXME: type is default */ zend_uchar type = UG(unicode)?IS_UNICODE:IS_STRING; - zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), NULL); + zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), EX(called_scope)); function_name = _get_zval_ptr_cv(&opline->op2, EX(Ts), BP_VAR_R TSRMLS_CC); @@ -15545,6 +15583,8 @@ static int ZEND_INIT_METHOD_CALL_SPEC_VAR_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) zend_error_noreturn(E_ERROR, "Call to a member function %R() on a non-object", Z_TYPE_P(function_name), function_name_strval); } + EX(called_scope) = Z_OBJCE_P(EX(object)); + if (EX(fbc)->common.fn_flags & ZEND_ACC_STATIC) { EX(object) = NULL; } else { @@ -15570,7 +15610,7 @@ static int ZEND_INIT_STATIC_METHOD_CALL_SPEC_VAR_CV_HANDLER(ZEND_OPCODE_HANDLER_ zval *function_name; zend_class_entry *ce; - zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), NULL); + zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), EX(called_scope)); if (IS_VAR == IS_CONST && IS_CV == IS_CONST) { /* try a function in namespace */ @@ -15631,6 +15671,8 @@ static int ZEND_INIT_STATIC_METHOD_CALL_SPEC_VAR_CV_HANDLER(ZEND_OPCODE_HANDLER_ EX(fbc) = ce->constructor; } + EX(called_scope) = ce; + if (EX(fbc)->common.fn_flags & ZEND_ACC_STATIC) { EX(object) = NULL; } else { @@ -15645,6 +15687,7 @@ static int ZEND_INIT_STATIC_METHOD_CALL_SPEC_VAR_CV_HANDLER(ZEND_OPCODE_HANDLER_ } if ((EX(object) = EG(This))) { EX(object)->refcount++; + EX(called_scope) = Z_OBJCE_P(EX(object)); } } @@ -16817,7 +16860,7 @@ static int ZEND_INIT_METHOD_CALL_SPEC_UNUSED_CONST_HANDLER(ZEND_OPCODE_HANDLER_A /* FIXME: type is default */ zend_uchar type = UG(unicode)?IS_UNICODE:IS_STRING; - zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), NULL); + zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), EX(called_scope)); function_name = &opline->op2.u.constant; @@ -16844,6 +16887,8 @@ static int ZEND_INIT_METHOD_CALL_SPEC_UNUSED_CONST_HANDLER(ZEND_OPCODE_HANDLER_A zend_error_noreturn(E_ERROR, "Call to a member function %R() on a non-object", Z_TYPE_P(function_name), function_name_strval); } + EX(called_scope) = Z_OBJCE_P(EX(object)); + if (EX(fbc)->common.fn_flags & ZEND_ACC_STATIC) { EX(object) = NULL; } else { @@ -17900,7 +17945,7 @@ static int ZEND_INIT_METHOD_CALL_SPEC_UNUSED_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARG /* FIXME: type is default */ zend_uchar type = UG(unicode)?IS_UNICODE:IS_STRING; - zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), NULL); + zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), EX(called_scope)); function_name = _get_zval_ptr_tmp(&opline->op2, EX(Ts), &free_op2 TSRMLS_CC); @@ -17927,6 +17972,8 @@ static int ZEND_INIT_METHOD_CALL_SPEC_UNUSED_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARG zend_error_noreturn(E_ERROR, "Call to a member function %R() on a non-object", Z_TYPE_P(function_name), function_name_strval); } + EX(called_scope) = Z_OBJCE_P(EX(object)); + if (EX(fbc)->common.fn_flags & ZEND_ACC_STATIC) { EX(object) = NULL; } else { @@ -18917,7 +18964,7 @@ static int ZEND_INIT_METHOD_CALL_SPEC_UNUSED_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARG /* FIXME: type is default */ zend_uchar type = UG(unicode)?IS_UNICODE:IS_STRING; - zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), NULL); + zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), EX(called_scope)); function_name = _get_zval_ptr_var(&opline->op2, EX(Ts), &free_op2 TSRMLS_CC); @@ -18944,6 +18991,8 @@ static int ZEND_INIT_METHOD_CALL_SPEC_UNUSED_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARG zend_error_noreturn(E_ERROR, "Call to a member function %R() on a non-object", Z_TYPE_P(function_name), function_name_strval); } + EX(called_scope) = Z_OBJCE_P(EX(object)); + if (EX(fbc)->common.fn_flags & ZEND_ACC_STATIC) { EX(object) = NULL; } else { @@ -20199,7 +20248,7 @@ static int ZEND_INIT_METHOD_CALL_SPEC_UNUSED_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS /* FIXME: type is default */ zend_uchar type = UG(unicode)?IS_UNICODE:IS_STRING; - zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), NULL); + zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), EX(called_scope)); function_name = _get_zval_ptr_cv(&opline->op2, EX(Ts), BP_VAR_R TSRMLS_CC); @@ -20226,6 +20275,8 @@ static int ZEND_INIT_METHOD_CALL_SPEC_UNUSED_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS zend_error_noreturn(E_ERROR, "Call to a member function %R() on a non-object", Z_TYPE_P(function_name), function_name_strval); } + EX(called_scope) = Z_OBJCE_P(EX(object)); + if (EX(fbc)->common.fn_flags & ZEND_ACC_STATIC) { EX(object) = NULL; } else { @@ -22969,7 +23020,7 @@ static int ZEND_INIT_METHOD_CALL_SPEC_CV_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) /* FIXME: type is default */ zend_uchar type = UG(unicode)?IS_UNICODE:IS_STRING; - zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), NULL); + zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), EX(called_scope)); function_name = &opline->op2.u.constant; @@ -22996,6 +23047,8 @@ static int ZEND_INIT_METHOD_CALL_SPEC_CV_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) zend_error_noreturn(E_ERROR, "Call to a member function %R() on a non-object", Z_TYPE_P(function_name), function_name_strval); } + EX(called_scope) = Z_OBJCE_P(EX(object)); + if (EX(fbc)->common.fn_flags & ZEND_ACC_STATIC) { EX(object) = NULL; } else { @@ -24504,7 +24557,7 @@ static int ZEND_INIT_METHOD_CALL_SPEC_CV_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS) /* FIXME: type is default */ zend_uchar type = UG(unicode)?IS_UNICODE:IS_STRING; - zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), NULL); + zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), EX(called_scope)); function_name = _get_zval_ptr_tmp(&opline->op2, EX(Ts), &free_op2 TSRMLS_CC); @@ -24531,6 +24584,8 @@ static int ZEND_INIT_METHOD_CALL_SPEC_CV_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS) zend_error_noreturn(E_ERROR, "Call to a member function %R() on a non-object", Z_TYPE_P(function_name), function_name_strval); } + EX(called_scope) = Z_OBJCE_P(EX(object)); + if (EX(fbc)->common.fn_flags & ZEND_ACC_STATIC) { EX(object) = NULL; } else { @@ -26078,7 +26133,7 @@ static int ZEND_INIT_METHOD_CALL_SPEC_CV_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) /* FIXME: type is default */ zend_uchar type = UG(unicode)?IS_UNICODE:IS_STRING; - zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), NULL); + zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), EX(called_scope)); function_name = _get_zval_ptr_var(&opline->op2, EX(Ts), &free_op2 TSRMLS_CC); @@ -26105,6 +26160,8 @@ static int ZEND_INIT_METHOD_CALL_SPEC_CV_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) zend_error_noreturn(E_ERROR, "Call to a member function %R() on a non-object", Z_TYPE_P(function_name), function_name_strval); } + EX(called_scope) = Z_OBJCE_P(EX(object)); + if (EX(fbc)->common.fn_flags & ZEND_ACC_STATIC) { EX(object) = NULL; } else { @@ -28083,7 +28140,7 @@ static int ZEND_INIT_METHOD_CALL_SPEC_CV_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) /* FIXME: type is default */ zend_uchar type = UG(unicode)?IS_UNICODE:IS_STRING; - zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), NULL); + zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), EX(called_scope)); function_name = _get_zval_ptr_cv(&opline->op2, EX(Ts), BP_VAR_R TSRMLS_CC); @@ -28110,6 +28167,8 @@ static int ZEND_INIT_METHOD_CALL_SPEC_CV_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) zend_error_noreturn(E_ERROR, "Call to a member function %R() on a non-object", Z_TYPE_P(function_name), function_name_strval); } + EX(called_scope) = Z_OBJCE_P(EX(object)); + if (EX(fbc)->common.fn_flags & ZEND_ACC_STATIC) { EX(object) = NULL; } else { diff --git a/Zend/zend_vm_execute.skl b/Zend/zend_vm_execute.skl index 5118a36a89..1376567793 100644 --- a/Zend/zend_vm_execute.skl +++ b/Zend/zend_vm_execute.skl @@ -13,6 +13,7 @@ ZEND_API void {%EXECUTOR_NAME%}(zend_op_array *op_array TSRMLS_DC) /* Initialize execute_data */ EX(fbc) = NULL; + EX(called_scope) = NULL; EX(object) = NULL; EX(old_error_reporting) = NULL; if (op_array->T < TEMP_VAR_STACK_LIMIT) { @@ -46,12 +47,6 @@ ZEND_API void {%EXECUTOR_NAME%}(zend_op_array *op_array TSRMLS_DC) EX(function_state).function = (zend_function *) op_array; EG(function_state_ptr) = &EX(function_state); -#if ZEND_DEBUG - /* function_state.function_symbol_table is saved as-is to a stack, - * which is an intentional UMR. Shut it up if we're in DEBUG. - */ - EX(function_state).function_symbol_table = NULL; -#endif while (1) { {%ZEND_VM_CONTINUE_LABEL%} |