summaryrefslogtreecommitdiff
path: root/Zend
diff options
context:
space:
mode:
Diffstat (limited to 'Zend')
-rw-r--r--Zend/tests/lsb_001.phpt61
-rw-r--r--Zend/tests/lsb_002.phpt66
-rw-r--r--Zend/tests/lsb_003.phpt24
-rw-r--r--Zend/tests/lsb_004.phpt21
-rw-r--r--Zend/tests/lsb_005.phpt51
-rw-r--r--Zend/tests/lsb_006.phpt12
-rw-r--r--Zend/tests/lsb_007.phpt12
-rw-r--r--Zend/tests/lsb_008.phpt8
-rw-r--r--Zend/tests/lsb_009.phpt8
-rw-r--r--Zend/tests/lsb_010.phpt38
-rw-r--r--Zend/tests/lsb_011.phpt23
-rw-r--r--Zend/tests/lsb_012.phpt23
-rw-r--r--Zend/tests/lsb_013.phpt24
-rw-r--r--Zend/tests/lsb_014.phpt24
-rw-r--r--Zend/tests/lsb_015.phpt92
-rw-r--r--Zend/tests/lsb_016.phpt41
-rw-r--r--Zend/tests/lsb_017.phpt29
-rw-r--r--Zend/zend_API.c3
-rw-r--r--Zend/zend_builtin_functions.c23
-rw-r--r--Zend/zend_compile.c10
-rw-r--r--Zend/zend_compile.h4
-rw-r--r--Zend/zend_constants.c8
-rw-r--r--Zend/zend_execute.c11
-rw-r--r--Zend/zend_execute_API.c27
-rw-r--r--Zend/zend_globals.h1
-rw-r--r--Zend/zend_language_parser.y1
-rw-r--r--Zend/zend_vm_def.h115
-rw-r--r--Zend/zend_vm_execute.h231
-rw-r--r--Zend/zend_vm_execute.skl7
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%}