summaryrefslogtreecommitdiff
path: root/zend/opcodes.h
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 /zend/opcodes.h
parent74388e2735e806837cd31052c513451ec3942c0a (diff)
fixed compiling in ZTS environments (reported in issue #57)
Diffstat (limited to 'zend/opcodes.h')
-rw-r--r--zend/opcodes.h132
1 files changed, 132 insertions, 0 deletions
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
+ */
+}
+