summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEmiel Bruijntjes <emiel.bruijntjes@copernica.com>2015-01-12 18:40:12 +0100
committerEmiel Bruijntjes <emiel.bruijntjes@copernica.com>2015-01-12 18:40:12 +0100
commita3007b9915a0ca3eec024b714cecc609e6356e17 (patch)
treee643f7ae433dbf12e6e1828950d694b855e4ec0a
parent74388e2735e806837cd31052c513451ec3942c0a (diff)
fixed compiling in ZTS environments (reported in issue #57)
-rw-r--r--include/opcodes.h69
-rw-r--r--include/script.h19
-rw-r--r--phpcpp.h1
-rw-r--r--zend/compileroptions.h15
-rw-r--r--zend/file.cpp16
-rw-r--r--zend/includes.h3
-rw-r--r--zend/opcodes.cpp131
-rw-r--r--zend/opcodes.h132
-rw-r--r--zend/script.cpp49
9 files changed, 212 insertions, 223 deletions
diff --git a/include/opcodes.h b/include/opcodes.h
deleted file mode 100644
index 5a40d05..0000000
--- a/include/opcodes.h
+++ /dev/null
@@ -1,69 +0,0 @@
-/**
- * Opcodes.h
- *
- * Class represents a set of opcodes of a PHP script that can be executed. This
- * is an internal file that you normally do not have to instantiate yourself.
- * Better use the Php::Script of Php::File classes.
- *
- * @author Emiel Bruijntjes <emiel.bruijntjes@copernica.com>
- * @copyright 2014 Copernica BV
- */
-
-/**
- * Forward declarations
- */
-struct _zend_op_array;
-
-/**
- * Namespace
- */
-namespace Php {
-
-/**
- * Class definition
- */
-class Opcodes
-{
-public:
- /**
- * Constructor
- * @param opcodes
- */
- Opcodes(struct _zend_op_array *opcodes) : _opcodes(opcodes)
- {
- // no other initialisation is necessary
- }
-
- /**
- * Destructor
- */
- virtual ~Opcodes();
-
- /**
- * Are the opcodes valid?
- * @return bool
- */
- bool valid() const
- {
- return _opcodes != nullptr;
- }
-
- /**
- * Execute the opcodes
- * @return Value
- */
- Value execute() const;
-
-private:
- /**
- * The opcodes
- * @var zend_op_array
- */
- struct _zend_op_array *_opcodes;
-};
-
-/**
- * End of namespace
- */
-}
-
diff --git a/include/script.h b/include/script.h
index a9c2921..af68a59 100644
--- a/include/script.h
+++ b/include/script.h
@@ -21,6 +21,11 @@ struct _zend_op_array;
namespace Php {
/**
+ * Forward declarations
+ */
+class Opcodes;
+
+/**
* Class definition
*/
class Script
@@ -62,33 +67,27 @@ public:
/**
* Destructor
*/
- virtual ~Script() {}
+ virtual ~Script();
/**
* Is the script a valid PHP script without syntax errors?
* @return bool
*/
- bool valid() const
- {
- return _opcodes.valid();
- }
+ bool valid() const;
/**
* Execute the script
* The return value of the script is returned
* @return Value
*/
- Value execute() const
- {
- return _opcodes.execute();
- }
+ Value execute() const;
private:
/**
* The opcodes
* @var Opcodes
*/
- Opcodes _opcodes;
+ Opcodes *_opcodes;
/**
* Helper function to compile the source code
diff --git a/phpcpp.h b/phpcpp.h
index 368018e..52c836c 100644
--- a/phpcpp.h
+++ b/phpcpp.h
@@ -61,7 +61,6 @@
#include <phpcpp/namespace.h>
#include <phpcpp/extension.h>
#include <phpcpp/call.h>
-#include <phpcpp/opcodes.h>
#include <phpcpp/script.h>
#include <phpcpp/file.h>
diff --git a/zend/compileroptions.h b/zend/compileroptions.h
index 798cb59..74ba053 100644
--- a/zend/compileroptions.h
+++ b/zend/compileroptions.h
@@ -25,19 +25,32 @@ private:
* @var int
*/
zend_uint _original;
+
+#ifdef ZTS
+ /**
+ * When in thread safety mode, we also keep track of the TSRM_LS var
+ * @var void***
+ */
+ void ***tsrm_ls;
+#endif
public:
/**
* Constructor
* @param options
*/
- CompilerOptions(zend_uint options)
+ CompilerOptions(zend_uint options TSRMLS_DC)
{
// remember the old compiler options before we set temporary compile options
_original = CG(compiler_options);
// we're going to evaluate only once
CG(compiler_options) = options;
+
+#ifdef ZTS
+ // copy tsrm_ls param
+ this->tsrm_ls = tsrm_ls;
+#endif
}
/**
diff --git a/zend/file.cpp b/zend/file.cpp
index 43c2d7a..2b7e77f 100644
--- a/zend/file.cpp
+++ b/zend/file.cpp
@@ -69,6 +69,9 @@ bool File::compile()
// we are going to open the file
zend_file_handle fileHandle;
+ // we need the tsrm_ls variable (@todo would it be better if this was a member?)
+ TSRMLS_FETCH();
+
// open the file
if (zend_stream_open(_path, &fileHandle TSRMLS_CC) == FAILURE) return false;
@@ -76,13 +79,10 @@ bool File::compile()
if (!fileHandle.opened_path) fileHandle.opened_path = estrdup(_path);
// we need temporary compiler options
- CompilerOptions options(ZEND_COMPILE_DEFAULT);
+ CompilerOptions options(ZEND_COMPILE_DEFAULT TSRMLS_CC);
- // we need the tsrm_ls variable
- TSRMLS_FETCH();
-
// create the opcodes
- _opcodes = new Opcodes(zend_compile_file(&fileHandle, ZEND_INCLUDE TSRMLS_CC));
+ _opcodes = new Opcodes(zend_compile_file(&fileHandle, ZEND_INCLUDE TSRMLS_CC) TSRMLS_CC);
// close the file handle
zend_destroy_file_handle(&fileHandle TSRMLS_CC);
@@ -130,6 +130,9 @@ Value File::execute()
// try compiling the file
if (!compile()) return nullptr;
+ // we need the tsrm_ls variable (@todo would it be better if this was a member?)
+ TSRMLS_FETCH();
+
// add the entry to the list of included files
zend_hash_add_empty_element(&EG(included_files), _path, ::strlen(_path) + 1);
@@ -145,6 +148,9 @@ Value File::once()
{
// skip if the path is invalid
if (!_path) return nullptr;
+
+ // we need the tsrm_ls variable (@todo would it be better if this was a member?)
+ TSRMLS_FETCH();
// check if this file was already included
if (zend_hash_exists(&EG(included_files), _path, ::strlen(_path) + 1)) return nullptr;
diff --git a/zend/includes.h b/zend/includes.h
index d6f2062..0b6a138 100644
--- a/zend/includes.h
+++ b/zend/includes.h
@@ -80,7 +80,6 @@
#include "../include/namespace.h"
#include "../include/extension.h"
#include "../include/call.h"
-#include "../include/opcodes.h"
#include "../include/script.h"
#include "../include/file.h"
@@ -117,6 +116,8 @@
#include "parametersimpl.h"
#include "extensionimpl.h"
#include "compileroptions.h"
+#include "executestate.h"
+#include "opcodes.h"
#ifndef ZVAL_COPY_VALUE
#define ZVAL_COPY_VALUE(z, v) \
diff --git a/zend/opcodes.cpp b/zend/opcodes.cpp
deleted file mode 100644
index 9e4525a..0000000
--- a/zend/opcodes.cpp
+++ /dev/null
@@ -1,131 +0,0 @@
-/**
- * Opcodes.cpp
- *
- * Implementation file for the opcodes class
- *
- * @author Emiel Bruijntjes <emiel.bruijntjes@copernica.com>
- * @copyright 2014 Copernica BV
- */
-
-/**
- * Dependencies
- */
-#include "includes.h"
-
-/**
- * Set up namespace
- */
-namespace Php {
-
-/**
- * Helper class to store and restore the current opcode state
- *
- * When we're going to execute a set of instructions, we need to store the
- * current state of the Zend engine. After the instructions have been processed,
- * we can switch back to the original instructions
- */
-class ExecuteState
-{
-private:
- /**
- * All the original settings
- */
- zend_op_array *_active_op_array;
- zval **_return_value_ptr_ptr;
- zend_op **_opline_ptr;
- int _interactive;
-
-public:
- /**
- * Constructor
- */
- ExecuteState()
- {
- // store all the original stuff
- _active_op_array = EG(active_op_array);
- _return_value_ptr_ptr = EG(return_value_ptr_ptr);
- _opline_ptr = EG(opline_ptr);
- _interactive = CG(interactive);
- }
-
- /**
- * Destructor
- */
- virtual ~ExecuteState()
- {
- // restore all settings
- CG(interactive) = _interactive;
- EG(no_extensions) = 0;
- EG(opline_ptr) = _opline_ptr;
- EG(active_op_array) = _active_op_array;
- EG(return_value_ptr_ptr) = _return_value_ptr_ptr;
- }
-};
-
-/**
- * Destructor
- */
-Opcodes::~Opcodes()
-{
- // leap out if opcodes were not valid
- if (!_opcodes) return;
-
- // clean up opcodes
- destroy_op_array(_opcodes TSRMLS_CC);
- efree(_opcodes);
-}
-
-/**
- * Execute the opcodes
- * @return Value
- */
-Value Opcodes::execute() const
-{
- // if the script could not be compiled, we return null
- if (!_opcodes) return nullptr;
-
- // pointer that is going to hold the return value of the script
- zval *retval_ptr = nullptr;
-
- // the zend engine is probably already busy processing opcodes, so we store
- // the current execute state before we're going to switch the runtime to
- // our own set of opcodes
- ExecuteState oldstate;
-
- // old execute state has been saved (and will automatically be restured when
- // the oldstate is destructed), so we can now safely overwrite all the settings
- EG(return_value_ptr_ptr) = &retval_ptr;
- EG(active_op_array) = _opcodes;
- EG(no_extensions) = 1;
- if (!EG(active_symbol_table)) zend_rebuild_symbol_table(TSRMLS_C);
- CG(interactive) = 0;
-
- // the current exception
- zval* oldException = EG(exception);
-
- // execute the code
- zend_execute(_opcodes TSRMLS_CC);
-
- // was an exception thrown inside the eval()'ed code? In that case we
- // throw a C++ new exception to give the C++ code the chance to catch it
- if (oldException != EG(exception) && EG(exception)) throw OrigException(EG(exception) TSRMLS_CC);
-
- // we're ready if there is no return value
- if (!retval_ptr) return nullptr;
-
- // wrap the return value
- Value result(retval_ptr);
-
- // destruct the zval (this function will decrement the reference counter,
- // and only destruct if there are no other references left)
- zval_ptr_dtor(&retval_ptr);
-
- // copy the pointer into a value object, and return that
- return result;
-}
-
-/**
- * End of namespace
- */
-}
-
diff --git a/zend/opcodes.h b/zend/opcodes.h
new file mode 100644
index 0000000..7e6d1ec
--- /dev/null
+++ b/zend/opcodes.h
@@ -0,0 +1,132 @@
+/**
+ * Opcodes.h
+ *
+ * Class represents a set of opcodes of a PHP script that can be executed. This
+ * is an internal file that you normally do not have to instantiate yourself.
+ * Better use the Php::Script of Php::File classes.
+ *
+ * @author Emiel Bruijntjes <emiel.bruijntjes@copernica.com>
+ * @copyright 2014 Copernica BV
+ */
+
+/**
+ * Forward declarations
+ */
+struct _zend_op_array;
+
+/**
+ * Namespace
+ */
+namespace Php {
+
+/**
+ * Class definition
+ */
+class Opcodes
+{
+public:
+ /**
+ * Constructor
+ * @param opcodes
+ */
+ Opcodes(struct _zend_op_array *opcodes TSRMLS_DC) : _opcodes(opcodes)
+ {
+#ifdef ZTS
+ // copy tsrm_ls param
+ this->tsrm_ls = tsrm_ls;
+#endif
+ }
+
+ /**
+ * Destructor
+ */
+ virtual ~Opcodes()
+ {
+ // leap out if opcodes were not valid
+ if (!_opcodes) return;
+
+ // clean up opcodes
+ destroy_op_array(_opcodes TSRMLS_CC);
+ efree(_opcodes);
+ }
+
+ /**
+ * Are the opcodes valid?
+ * @return bool
+ */
+ bool valid() const
+ {
+ return _opcodes != nullptr;
+ }
+
+ /**
+ * Execute the opcodes
+ * @return Value
+ */
+ Value execute() const
+ {
+ // if the script could not be compiled, we return null
+ if (!_opcodes) return nullptr;
+
+ // pointer that is going to hold the return value of the script
+ zval *retval_ptr = nullptr;
+
+ // the zend engine is probably already busy processing opcodes, so we store
+ // the current execute state before we're going to switch the runtime to
+ // our own set of opcodes
+ ExecuteState oldstate(TSRMLS_C);
+
+ // old execute state has been saved (and will automatically be restured when
+ // the oldstate is destructed), so we can now safely overwrite all the settings
+ EG(return_value_ptr_ptr) = &retval_ptr;
+ EG(active_op_array) = _opcodes;
+ EG(no_extensions) = 1;
+ if (!EG(active_symbol_table)) zend_rebuild_symbol_table(TSRMLS_C);
+ CG(interactive) = 0;
+
+ // the current exception
+ zval* oldException = EG(exception);
+
+ // execute the code
+ zend_execute(_opcodes TSRMLS_CC);
+
+ // was an exception thrown inside the eval()'ed code? In that case we
+ // throw a C++ new exception to give the C++ code the chance to catch it
+ if (oldException != EG(exception) && EG(exception)) throw OrigException(EG(exception) TSRMLS_CC);
+
+ // we're ready if there is no return value
+ if (!retval_ptr) return nullptr;
+
+ // wrap the return value
+ Value result(retval_ptr);
+
+ // destruct the zval (this function will decrement the reference counter,
+ // and only destruct if there are no other references left)
+ zval_ptr_dtor(&retval_ptr);
+
+ // copy the pointer into a value object, and return that
+ return result;
+ }
+
+private:
+ /**
+ * The opcodes
+ * @var zend_op_array
+ */
+ struct _zend_op_array *_opcodes;
+
+#ifdef ZTS
+ /**
+ * When in thread safety mode, we also keep track of the TSRM_LS var
+ * @var void***
+ */
+ void ***tsrm_ls;
+#endif
+
+};
+
+/**
+ * End of namespace
+ */
+}
+
diff --git a/zend/script.cpp b/zend/script.cpp
index 58ee376..a1b5b04 100644
--- a/zend/script.cpp
+++ b/zend/script.cpp
@@ -32,13 +32,14 @@ zend_op_array *Script::compile(const char *name, const char *phpcode, size_t siz
// found there is full of zval manipulation, for which we can use the much
// simpler Php::Value object
Php::Value source(phpcode, size);
-
- // remember the old compiler options, and set new compiler options
- CompilerOptions options(ZEND_COMPILE_DEFAULT_FOR_EVAL);
-
+
// we need the tsrm_ls variable
+ // @todo it would be better if this was passed as param to the compile() method
TSRMLS_FETCH();
+ // remember the old compiler options, and set new compiler options
+ CompilerOptions options(ZEND_COMPILE_DEFAULT_FOR_EVAL TSRMLS_CC);
+
// compile the string
return zend_compile_string(source._val, (char *)name TSRMLS_CC);
}
@@ -49,10 +50,48 @@ zend_op_array *Script::compile(const char *name, const char *phpcode, size_t siz
* @param script actual PHP code
* @param size length of the string
*/
-Script::Script(const char *name, const char *phpcode, size_t size) : _opcodes(compile(name, phpcode, size))
+Script::Script(const char *name, const char *phpcode, size_t size)
{
+ // we need the tsrm_ls variable
+ TSRMLS_FETCH();
+
+ // construct opcodes
+ _opcodes = new Opcodes(compile(name, phpcode, size) TSRMLS_CC);
}
+
+/**
+ * Destructor
+ */
+Script::~Script()
+{
+ // remove opcodes
+ delete _opcodes;
+}
+
+/**
+ * Is the script a valid PHP script without syntax errors?
+ * @return bool
+ */
+bool Script::valid() const
+{
+ // check opcodes
+ return _opcodes && _opcodes->valid();
+}
+
+/**
+ * Execute the script
+ * The return value of the script is returned
+ * @return Value
+ */
+Value Script::execute() const
+{
+ // pass on to opcodes
+ if (!_opcodes) return nullptr;
+ // execute opcodes
+ return _opcodes->execute();
+}
+
/**
* End of namespace
*/