2012-04-27 16:26:15 +00:00
/*
+ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
| PHP Version 5 |
+ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
2012-04-27 16:41:32 +00:00
| Copyright ( c ) 1997 - 2012 The PHP Group |
2012-04-27 16:26:15 +00:00
+ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
| This source file is subject to version 3.01 of the PHP license , |
| that is bundled with this package in the file LICENSE , and is |
| available through the world - wide - web at the following url : |
| http : //www.php.net/license/3_01.txt |
| If you did not receive a copy of the PHP license and are unable to |
| obtain it through the world - wide - web , please send a note to |
| license @ php . net so we can mail you a copy immediately . |
+ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
| Author : Jani Taskinen < jani . taskinen @ iki . fi > |
2012-04-27 16:41:32 +00:00
| Author : Patrick Reilly < preilly @ php . net > |
2012-04-27 16:26:15 +00:00
+ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
*/
2012-07-07 00:12:53 +00:00
/* $Id$ */
2012-04-27 16:26:15 +00:00
# define V8JS_DEBUG 0
2013-05-16 23:59:41 +00:00
//#define PHP_V8_VERSION "0.1.4"
2012-04-27 16:26:15 +00:00
# ifdef HAVE_CONFIG_H
# include "config.h"
# endif
2013-04-12 23:00:27 +00:00
# include "php_v8js_macros.h"
2012-04-27 16:26:15 +00:00
extern " C " {
# include "php_ini.h"
# include "ext/standard/info.h"
# include "ext/standard/php_string.h"
# include "ext/standard/php_smart_str.h"
# include "zend_exceptions.h"
}
/* Forward declarations */
2013-04-10 23:23:47 +00:00
static void php_v8js_throw_script_exception ( v8 : : TryCatch * TSRMLS_DC ) ;
static void php_v8js_create_script_exception ( zval * , v8 : : TryCatch * TSRMLS_DC ) ;
2012-04-27 16:26:15 +00:00
ZEND_DECLARE_MODULE_GLOBALS ( v8js )
/* {{{ INI Settings */
static ZEND_INI_MH ( v8js_OnUpdateMaxDisposedContexts ) /* { { { */
{
int max_disposed = zend_atoi ( new_value , new_value_length ) ;
if ( max_disposed < = 0 ) {
return FAILURE ;
}
V8JSG ( max_disposed_contexts ) = max_disposed ;
return SUCCESS ;
}
/* }}} */
static ZEND_INI_MH ( v8js_OnUpdateV8Flags ) /* { { { */
{
if ( new_value ) {
if ( V8JSG ( v8_flags ) ) {
free ( V8JSG ( v8_flags ) ) ;
V8JSG ( v8_flags ) = NULL ;
}
if ( ! new_value [ 0 ] ) {
return FAILURE ;
}
V8JSG ( v8_flags ) = zend_strndup ( new_value , new_value_length ) ;
}
return SUCCESS ;
}
/* }}} */
ZEND_INI_BEGIN ( ) /* {{{ */
ZEND_INI_ENTRY ( " v8js.max_disposed_contexts " , " 25 " , ZEND_INI_ALL , v8js_OnUpdateMaxDisposedContexts )
ZEND_INI_ENTRY ( " v8js.flags " , NULL , ZEND_INI_ALL , v8js_OnUpdateV8Flags )
ZEND_INI_END ( )
/* }}} */
/* }}} INI */
/* {{{ Class Entries */
zend_class_entry * php_ce_v8_object ;
zend_class_entry * php_ce_v8_function ;
static zend_class_entry * php_ce_v8js ;
2013-04-10 23:23:47 +00:00
static zend_class_entry * php_ce_v8js_script_exception ;
static zend_class_entry * php_ce_v8js_time_limit_exception ;
static zend_class_entry * php_ce_v8js_memory_limit_exception ;
2012-04-27 16:26:15 +00:00
/* }}} */
/* {{{ Object Handlers */
static zend_object_handlers v8js_object_handlers ;
static zend_object_handlers v8_object_handlers ;
/* }}} */
/* {{{ Extension container */
struct php_v8js_jsext {
zend_bool auto_enable ;
HashTable * deps_ht ;
const char * * deps ;
int deps_count ;
char * name ;
char * source ;
} ;
/* }}} */
/* {{{ Object container */
struct php_v8js_object {
zend_object std ;
v8 : : Persistent < v8 : : Value > v8obj ;
int flags ;
2013-04-13 23:36:05 +00:00
v8 : : Isolate * isolate ;
2012-04-27 16:26:15 +00:00
} ;
/* }}} */
# ifdef COMPILE_DL_V8JS
ZEND_GET_MODULE ( v8js )
# endif
/* {{{ Class: V8 */
# define V8JS_V8_INVOKE_FUNC_NAME "V8Js::V8::Invoke"
/* V8 Object handlers */
2012-07-07 00:12:53 +00:00
static zval * php_v8js_v8_read_property ( zval * object , zval * member , int type ZEND_HASH_KEY_DC TSRMLS_DC ) /* { { { */
2012-04-27 16:26:15 +00:00
{
zval * retval = NULL ;
php_v8js_object * obj = ( php_v8js_object * ) zend_object_store_get_object ( object TSRMLS_CC ) ;
if ( Z_TYPE_P ( member ) = = IS_STRING & & obj - > v8obj - > IsObject ( ) & & ! obj - > v8obj - > IsFunction ( ) )
{
v8 : : Local < v8 : : Object > jsObj = obj - > v8obj - > ToObject ( ) ;
v8 : : Local < v8 : : String > jsKey = V8JS_STRL ( Z_STRVAL_P ( member ) , Z_STRLEN_P ( member ) ) ;
v8 : : Local < v8 : : Value > jsVal ;
/* Skip any prototype properties */
if ( jsObj - > HasRealNamedProperty ( jsKey ) | | jsObj - > HasRealNamedCallbackProperty ( jsKey ) ) {
jsVal = jsObj - > Get ( jsKey ) ;
if ( jsVal - > IsObject ( ) ) {
ALLOC_INIT_ZVAL ( retval ) ;
Z_SET_REFCOUNT_P ( retval , 0 ) ;
} else {
MAKE_STD_ZVAL ( retval ) ;
}
2013-04-13 23:36:05 +00:00
if ( v8js_to_zval ( jsVal , retval , obj - > flags , obj - > isolate TSRMLS_CC ) = = SUCCESS ) {
2012-04-27 16:26:15 +00:00
return retval ;
}
}
}
ALLOC_INIT_ZVAL ( retval ) ;
return retval ;
}
/* }}} */
2012-07-07 00:12:53 +00:00
static void php_v8js_v8_write_property ( zval * object , zval * member , zval * value ZEND_HASH_KEY_DC TSRMLS_DC ) /* { { { */
2012-04-27 16:26:15 +00:00
{
php_v8js_object * obj = ( php_v8js_object * ) zend_object_store_get_object ( object TSRMLS_CC ) ;
if ( obj - > v8obj - > IsObject ( ) & & ! obj - > v8obj - > IsFunction ( ) ) {
2013-04-13 23:36:05 +00:00
obj - > v8obj - > ToObject ( ) - > ForceSet ( V8JS_SYML ( Z_STRVAL_P ( member ) , Z_STRLEN_P ( member ) ) , zval_to_v8js ( value , obj - > isolate TSRMLS_CC ) ) ;
2012-04-27 16:26:15 +00:00
}
}
/* }}} */
2012-07-07 00:12:53 +00:00
static void php_v8js_v8_unset_property ( zval * object , zval * member ZEND_HASH_KEY_DC TSRMLS_DC ) /* { { { */
2012-04-27 16:26:15 +00:00
{
php_v8js_object * obj = ( php_v8js_object * ) zend_object_store_get_object ( object TSRMLS_CC ) ;
if ( obj - > v8obj - > IsObject ( ) & & ! obj - > v8obj - > IsFunction ( ) ) {
obj - > v8obj - > ToObject ( ) - > ForceDelete ( V8JS_SYML ( Z_STRVAL_P ( member ) , Z_STRLEN_P ( member ) ) ) ;
}
}
/* }}} */
2013-04-13 23:36:05 +00:00
int php_v8js_v8_get_properties_hash ( v8 : : Handle < v8 : : Value > jsValue , HashTable * retval , int flags , v8 : : Isolate * isolate TSRMLS_DC ) /* { { { */
2012-04-27 16:26:15 +00:00
{
v8 : : Local < v8 : : Object > jsObj = jsValue - > ToObject ( ) ;
if ( ! jsObj . IsEmpty ( ) ) {
v8 : : Local < v8 : : Array > jsKeys = jsObj - > GetPropertyNames ( ) ;
for ( unsigned i = 0 ; i < jsKeys - > Length ( ) ; i + + )
{
v8 : : Local < v8 : : String > jsKey = jsKeys - > Get ( i ) - > ToString ( ) ;
/* Skip any prototype properties */
if ( ! jsObj - > HasRealNamedProperty ( jsKey ) & & ! jsObj - > HasRealNamedCallbackProperty ( jsKey ) & & ! jsObj - > HasRealIndexedProperty ( i ) ) {
continue ;
}
v8 : : Local < v8 : : Value > jsVal = jsObj - > Get ( jsKey ) ;
v8 : : String : : Utf8Value cstr ( jsKey ) ;
const char * key = ToCString ( cstr ) ;
zval * value = NULL ;
MAKE_STD_ZVAL ( value ) ;
2013-04-13 23:36:05 +00:00
if ( v8js_to_zval ( jsVal , value , flags , isolate TSRMLS_CC ) = = FAILURE ) {
2012-04-27 16:26:15 +00:00
zval_ptr_dtor ( & value ) ;
return FAILURE ;
}
if ( ( flags & V8JS_FLAG_FORCE_ARRAY ) | | jsValue - > IsArray ( ) ) {
zend_symtable_update ( retval , key , strlen ( key ) + 1 , ( void * ) & value , sizeof ( zval * ) , NULL ) ;
} else {
zend_hash_update ( retval , key , strlen ( key ) + 1 , ( void * ) & value , sizeof ( zval * ) , NULL ) ;
}
}
return SUCCESS ;
}
return FAILURE ;
}
/* }}} */
static HashTable * php_v8js_v8_get_properties ( zval * object TSRMLS_DC ) /* { { { */
{
php_v8js_object * obj = ( php_v8js_object * ) zend_object_store_get_object ( object TSRMLS_CC ) ;
HashTable * retval ;
2013-04-13 23:36:05 +00:00
2012-04-27 16:26:15 +00:00
ALLOC_HASHTABLE ( retval ) ;
zend_hash_init ( retval , 0 , NULL , ZVAL_PTR_DTOR , 0 ) ;
2013-04-13 23:36:05 +00:00
v8 : : Locker locker ( obj - > isolate ) ;
v8 : : Isolate : : Scope isolate_scope ( obj - > isolate ) ;
v8 : : HandleScope local_scope ( obj - > isolate ) ;
2012-04-27 16:26:15 +00:00
v8 : : Handle < v8 : : Context > temp_context = v8 : : Context : : New ( ) ;
v8 : : Context : : Scope temp_scope ( temp_context ) ;
2013-04-13 23:36:05 +00:00
if ( php_v8js_v8_get_properties_hash ( obj - > v8obj , retval , obj - > flags , obj - > isolate TSRMLS_CC ) = = SUCCESS ) {
2012-04-27 16:26:15 +00:00
return retval ;
}
return NULL ;
}
/* }}} */
static HashTable * php_v8js_v8_get_debug_info ( zval * object , int * is_temp TSRMLS_DC ) /* { { { */
{
* is_temp = 1 ;
return php_v8js_v8_get_properties ( object TSRMLS_CC ) ;
}
/* }}} */
2012-07-07 00:12:53 +00:00
static zend_function * php_v8js_v8_get_method ( zval * * object_ptr , char * method , int method_len ZEND_HASH_KEY_DC TSRMLS_DC ) /* { { { */
2012-04-27 16:26:15 +00:00
{
zend_function * f ;
v8 : : Local < v8 : : String > jsKey = V8JS_STRL ( method , method_len ) ;
php_v8js_object * obj = ( php_v8js_object * ) zend_object_store_get_object ( * object_ptr TSRMLS_CC ) ;
if ( ! obj - > v8obj . IsEmpty ( ) & & obj - > v8obj - > IsObject ( ) & & ! obj - > v8obj - > IsFunction ( ) ) {
v8 : : Local < v8 : : Object > jsObj = obj - > v8obj - > ToObject ( ) ;
if ( jsObj - > Has ( jsKey ) & & jsObj - > Get ( jsKey ) - > IsFunction ( ) ) {
f = ( zend_function * ) ecalloc ( 1 , sizeof ( * f ) ) ;
f - > type = ZEND_OVERLOADED_FUNCTION_TEMPORARY ;
f - > common . function_name = estrndup ( method , method_len ) ;
return f ;
}
}
return NULL ;
}
/* }}} */
2012-07-07 00:12:53 +00:00
# if PHP_VERSION_ID >= 50400
2012-05-10 10:47:39 +00:00
static int php_v8js_v8_call_method ( const char * method , INTERNAL_FUNCTION_PARAMETERS ) /* { { { */
2012-07-07 00:12:53 +00:00
# else
static int php_v8js_v8_call_method ( char * method , INTERNAL_FUNCTION_PARAMETERS ) /* { { { */
# endif
2012-04-27 16:26:15 +00:00
{
zval * object = this_ptr , * * * argv = NULL ;
int i = 0 , argc = ZEND_NUM_ARGS ( ) ;
php_v8js_object * obj ;
obj = ( php_v8js_object * ) zend_object_store_get_object ( object TSRMLS_CC ) ;
if ( obj - > v8obj . IsEmpty ( ) ) {
zval_ptr_dtor ( & object ) ;
return FAILURE ;
}
if ( argc > 0 ) {
argv = ( zval * * * ) safe_emalloc ( sizeof ( zval * * ) , argc , 0 ) ;
zend_get_parameters_array_ex ( argc , argv ) ;
}
v8 : : Local < v8 : : String > method_name = V8JS_SYML ( method , strlen ( method ) ) ;
v8 : : Local < v8 : : Object > v8obj = obj - > v8obj - > ToObject ( ) ;
v8 : : Local < v8 : : Function > cb ;
if ( method_name - > Equals ( V8JS_SYM ( V8JS_V8_INVOKE_FUNC_NAME ) ) ) {
cb = v8 : : Local < v8 : : Function > : : Cast ( v8obj ) ;
} else {
cb = v8 : : Local < v8 : : Function > : : Cast ( v8obj - > Get ( method_name ) ) ;
}
v8 : : Local < v8 : : Value > * jsArgv = new v8 : : Local < v8 : : Value > [ argc ] ;
v8 : : Local < v8 : : Value > js_retval ;
for ( i = 0 ; i < argc ; i + + ) {
2013-04-13 23:36:05 +00:00
jsArgv [ i ] = v8 : : Local < v8 : : Value > : : New ( zval_to_v8js ( * argv [ i ] , obj - > isolate TSRMLS_CC ) ) ;
2012-04-27 16:26:15 +00:00
}
js_retval = cb - > Call ( V8JS_GLOBAL , argc , jsArgv ) ;
zval_ptr_dtor ( & object ) ;
if ( argc > 0 ) {
efree ( argv ) ;
}
if ( return_value_used ) {
2013-04-13 23:36:05 +00:00
return v8js_to_zval ( js_retval , return_value , obj - > flags , obj - > isolate TSRMLS_CC ) ;
2012-04-27 16:26:15 +00:00
}
return SUCCESS ;
}
/* }}} */
static int php_v8js_v8_get_closure ( zval * object , zend_class_entry * * ce_ptr , zend_function * * fptr_ptr , zval * * zobj_ptr TSRMLS_DC ) /* { { { */
{
zend_function * invoke ;
php_v8js_object * obj = ( php_v8js_object * ) zend_object_store_get_object ( object TSRMLS_CC ) ;
if ( ! obj - > v8obj - > IsFunction ( ) ) {
return FAILURE ;
}
invoke = ( zend_function * ) ecalloc ( 1 , sizeof ( * invoke ) ) ;
invoke - > type = ZEND_OVERLOADED_FUNCTION_TEMPORARY ;
invoke - > common . function_name = estrndup ( V8JS_V8_INVOKE_FUNC_NAME , sizeof ( V8JS_V8_INVOKE_FUNC_NAME ) - 1 ) ;
* fptr_ptr = invoke ;
if ( zobj_ptr ) {
* zobj_ptr = object ;
}
* ce_ptr = NULL ;
return SUCCESS ;
}
/* }}} */
static void php_v8js_v8_free_storage ( void * object , zend_object_handle handle TSRMLS_DC ) /* { { { */
{
php_v8js_object * c = ( php_v8js_object * ) object ;
zend_object_std_dtor ( & c - > std TSRMLS_CC ) ;
if ( ! c - > v8obj . IsEmpty ( ) ) {
c - > v8obj . Dispose ( ) ;
}
efree ( object ) ;
}
/* }}} */
static zend_object_value php_v8js_v8_new ( zend_class_entry * ce TSRMLS_DC ) /* { { { */
{
zend_object_value retval ;
php_v8js_object * c ;
c = ( php_v8js_object * ) ecalloc ( 1 , sizeof ( * c ) ) ;
zend_object_std_init ( & c - > std , ce TSRMLS_CC ) ;
retval . handle = zend_objects_store_put ( c , NULL , ( zend_objects_free_object_storage_t ) php_v8js_v8_free_storage , NULL TSRMLS_CC ) ;
retval . handlers = & v8_object_handlers ;
return retval ;
}
/* }}} */
2013-04-13 23:36:05 +00:00
void php_v8js_create_v8 ( zval * res , v8 : : Handle < v8 : : Value > value , int flags , v8 : : Isolate * isolate TSRMLS_DC ) /* { { { */
2012-04-27 16:26:15 +00:00
{
php_v8js_object * c ;
object_init_ex ( res , value - > IsFunction ( ) ? php_ce_v8_function : php_ce_v8_object ) ;
c = ( php_v8js_object * ) zend_object_store_get_object ( res TSRMLS_CC ) ;
c - > v8obj = v8 : : Persistent < v8 : : Value > : : New ( value ) ;
c - > flags = flags ;
2013-04-13 23:36:05 +00:00
c - > isolate = isolate ;
2012-04-27 16:26:15 +00:00
}
/* }}} */
/* }}} V8 */
/* {{{ Class: V8Js */
static void php_v8js_free_storage ( void * object TSRMLS_DC ) /* { { { */
{
php_v8js_ctx * c = ( php_v8js_ctx * ) object ;
zend_object_std_dtor ( & c - > std TSRMLS_CC ) ;
if ( c - > pending_exception ) {
zval_ptr_dtor ( & c - > pending_exception ) ;
}
c - > object_name . Dispose ( ) ;
/* Clear global object, dispose context */
if ( ! c - > context . IsEmpty ( ) ) {
c - > context . Dispose ( ) ;
c - > context . Clear ( ) ;
V8JSG ( disposed_contexts ) = v8 : : V8 : : ContextDisposedNotification ( ) ;
# if V8JS_DEBUG
fprintf ( stderr , " Context dispose notification sent (%d) \n " , V8JSG ( disposed_contexts ) ) ;
fflush ( stderr ) ;
# endif
}
efree ( object ) ;
}
/* }}} */
static zend_object_value php_v8js_new ( zend_class_entry * ce TSRMLS_DC ) /* { { { */
{
zend_object_value retval ;
php_v8js_ctx * c ;
c = ( php_v8js_ctx * ) ecalloc ( 1 , sizeof ( * c ) ) ;
zend_object_std_init ( & c - > std , ce TSRMLS_CC ) ;
retval . handle = zend_objects_store_put ( c , NULL , ( zend_objects_free_object_storage_t ) php_v8js_free_storage , NULL TSRMLS_CC ) ;
retval . handlers = & v8js_object_handlers ;
return retval ;
}
/* }}} */
static void _php_v8js_free_ext_strarr ( const char * * arr , int count ) /* { { { */
{
int i ;
if ( arr ) {
for ( i = 0 ; i < count ; i + + ) {
if ( arr [ i ] ) {
free ( ( void * ) arr [ i ] ) ;
}
}
free ( arr ) ;
}
}
/* }}} */
static void php_v8js_jsext_dtor ( php_v8js_jsext * jsext ) /* { { { */
{
if ( jsext - > deps_ht ) {
zend_hash_destroy ( jsext - > deps_ht ) ;
free ( jsext - > deps_ht ) ;
}
if ( jsext - > deps ) {
_php_v8js_free_ext_strarr ( jsext - > deps , jsext - > deps_count ) ;
}
free ( jsext - > name ) ;
free ( jsext - > source ) ;
}
/* }}} */
static int _php_v8js_create_ext_strarr ( const char * * * retval , int count , HashTable * ht ) /* { { { */
{
const char * * exts = NULL ;
HashPosition pos ;
zval * * tmp ;
int i = 0 ;
exts = ( const char * * ) calloc ( 1 , count * sizeof ( char * ) ) ;
zend_hash_internal_pointer_reset_ex ( ht , & pos ) ;
while ( zend_hash_get_current_data_ex ( ht , ( void * * ) & tmp , & pos ) = = SUCCESS ) {
if ( Z_TYPE_PP ( tmp ) = = IS_STRING ) {
exts [ i + + ] = zend_strndup ( Z_STRVAL_PP ( tmp ) , Z_STRLEN_PP ( tmp ) ) ;
} else {
_php_v8js_free_ext_strarr ( exts , i ) ;
return FAILURE ;
}
zend_hash_move_forward_ex ( ht , & pos ) ;
}
* retval = exts ;
return SUCCESS ;
}
/* }}} */
static void php_v8js_fatal_error_handler ( const char * location , const char * message ) /* { { { */
{
if ( location ) {
zend_error ( E_ERROR , " %s %s " , location , message ) ;
} else {
zend_error ( E_ERROR , " %s " , message ) ;
}
}
/* }}} */
static void php_v8js_init ( TSRMLS_D ) /* { { { */
{
/* Run only once */
if ( V8JSG ( v8_initialized ) ) {
return ;
}
/* Set V8 command line flags (must be done before V8::Initialize()!) */
if ( V8JSG ( v8_flags ) ) {
v8 : : V8 : : SetFlagsFromString ( V8JSG ( v8_flags ) , strlen ( V8JSG ( v8_flags ) ) ) ;
}
/* Initialize V8 */
v8 : : V8 : : Initialize ( ) ;
/* Run only once */
V8JSG ( v8_initialized ) = 1 ;
}
/* }}} */
/* {{{ proto void V8Js::__construct([string object_name [, array variables [, array extensions [, bool report_uncaught_exceptions]]])
__construct for V8Js */
static PHP_METHOD ( V8Js , __construct )
{
2012-07-07 00:12:53 +00:00
char * object_name = NULL , * class_name = NULL ;
2012-04-27 16:26:15 +00:00
int object_name_len = 0 , free = 0 ;
zend_uint class_name_len = 0 ;
zend_bool report_uncaught = 1 ;
zval * vars_arr = NULL , * exts_arr = NULL ;
const char * * exts = NULL ;
int exts_count = 0 ;
php_v8js_ctx * c = ( php_v8js_ctx * ) zend_object_store_get_object ( getThis ( ) TSRMLS_CC ) ;
if ( ! c - > context . IsEmpty ( ) ) {
/* called __construct() twice, bail out */
return ;
}
if ( zend_parse_parameters ( ZEND_NUM_ARGS ( ) TSRMLS_CC , " |saab " , & object_name , & object_name_len , & vars_arr , & exts_arr , & report_uncaught ) = = FAILURE ) {
return ;
}
/* Throw PHP exception if uncaught exceptions exist */
c - > report_uncaught = report_uncaught ;
c - > pending_exception = NULL ;
c - > in_execution = 0 ;
2013-04-09 21:52:42 +00:00
c - > isolate = v8 : : Isolate : : New ( ) ;
2013-04-10 23:08:05 +00:00
c - > time_limit_hit = false ;
c - > memory_limit_hit = false ;
2013-03-24 16:27:13 +00:00
c - > module_loader = NULL ;
2012-04-27 16:26:15 +00:00
/* Initialize V8 */
php_v8js_init ( TSRMLS_C ) ;
/* Include extensions used by this context */
/* Note: Extensions registered with auto_enable do not need to be added separately like this. */
if ( exts_arr )
{
exts_count = zend_hash_num_elements ( Z_ARRVAL_P ( exts_arr ) ) ;
if ( _php_v8js_create_ext_strarr ( & exts , exts_count , Z_ARRVAL_P ( exts_arr ) ) = = FAILURE ) {
php_error_docref ( NULL TSRMLS_CC , E_WARNING , " Invalid extensions array passed " ) ;
return ;
}
}
/* Declare configuration for extensions */
v8 : : ExtensionConfiguration extension_conf ( exts_count , exts ) ;
2013-04-09 21:52:42 +00:00
// Isolate execution
v8 : : Locker locker ( c - > isolate ) ;
v8 : : Isolate : : Scope isolate_scope ( c - > isolate ) ;
2012-04-27 16:26:15 +00:00
/* Handle scope */
2013-04-10 23:08:05 +00:00
v8 : : HandleScope handle_scope ( c - > isolate ) ;
2012-04-27 16:26:15 +00:00
2013-04-14 10:19:50 +00:00
/* Redirect fatal errors to PHP error handler */
// This needs to be done within the context isolate
v8 : : V8 : : SetFatalErrorHandler ( php_v8js_fatal_error_handler ) ;
2012-04-27 16:26:15 +00:00
/* Create global template for global object */
2013-04-10 23:08:05 +00:00
// Now we are using multiple isolates this needs to be created for every context
2012-04-27 16:26:15 +00:00
2013-04-10 23:08:05 +00:00
c - > global_template = v8 : : Persistent < v8 : : FunctionTemplate > : : New ( v8 : : FunctionTemplate : : New ( ) ) ;
c - > global_template - > SetClassName ( V8JS_SYM ( " V8Js " ) ) ;
/* Register builtin methods */
2013-04-11 16:15:55 +00:00
php_v8js_register_methods ( c - > global_template - > InstanceTemplate ( ) , c ) ;
2012-04-27 16:26:15 +00:00
/* Create context */
2013-04-10 23:08:05 +00:00
c - > context = v8 : : Context : : New ( & extension_conf , c - > global_template - > InstanceTemplate ( ) ) ;
c - > context - > SetAlignedPointerInEmbedderData ( 1 , c ) ;
2012-04-27 16:26:15 +00:00
if ( exts ) {
_php_v8js_free_ext_strarr ( exts , exts_count ) ;
}
/* If extensions have errors, context will be empty. (NOTE: This is V8 stuff, they expect the passed sources to compile :) */
if ( c - > context . IsEmpty ( ) ) {
php_error_docref ( NULL TSRMLS_CC , E_WARNING , " Failed to create V8 context. Check that registered extensions do not have errors. " ) ;
ZVAL_NULL ( getThis ( ) ) ;
return ;
}
/* Enter context */
v8 : : Context : : Scope context_scope ( c - > context ) ;
/* Create the PHP container object's function template */
v8 : : Local < v8 : : FunctionTemplate > php_obj_t = v8 : : FunctionTemplate : : New ( ) ;
/* Set class name for PHP object */
2012-07-07 00:12:53 +00:00
# if PHP_VERSION_ID >= 50400
free = ! zend_get_object_classname ( getThis ( ) , const_cast < const char * * > ( & class_name ) , & class_name_len TSRMLS_CC ) ;
# else
2012-04-27 16:26:15 +00:00
free = ! zend_get_object_classname ( getThis ( ) , & class_name , & class_name_len TSRMLS_CC ) ;
2012-07-07 00:12:53 +00:00
# endif
2012-04-27 16:26:15 +00:00
php_obj_t - > SetClassName ( V8JS_SYML ( class_name , class_name_len ) ) ;
if ( free ) {
2012-07-07 00:12:53 +00:00
efree ( class_name ) ;
2012-04-27 16:26:15 +00:00
}
2013-04-10 23:08:05 +00:00
2012-04-27 16:26:15 +00:00
/* Register Get accessor for passed variables */
if ( vars_arr & & zend_hash_num_elements ( Z_ARRVAL_P ( vars_arr ) ) > 0 ) {
2013-04-13 23:36:05 +00:00
php_v8js_register_accessors ( php_obj_t - > InstanceTemplate ( ) , vars_arr , c - > isolate TSRMLS_CC ) ;
2012-04-27 16:26:15 +00:00
}
/* Set name for the PHP JS object */
c - > object_name = v8 : : Persistent < v8 : : String > : : New ( ( object_name_len ) ? V8JS_SYML ( object_name , object_name_len ) : V8JS_SYM ( " PHP " ) ) ;
/* Add the PHP object into global object */
V8JS_GLOBAL - > Set ( c - > object_name , php_obj_t - > InstanceTemplate ( ) - > NewInstance ( ) , v8 : : ReadOnly ) ;
}
/* }}} */
# define V8JS_BEGIN_CTX(ctx, object) \
php_v8js_ctx * ( ctx ) ; \
\
if ( ! V8JSG ( v8_initialized ) ) { \
zend_error ( E_ERROR , " V8 not initialized " ) ; \
return ; \
} \
\
( ctx ) = ( php_v8js_ctx * ) zend_object_store_get_object ( object TSRMLS_CC ) ; \
2013-04-09 21:52:42 +00:00
v8 : : Locker locker ( ( ctx ) - > isolate ) ; \
v8 : : Isolate : : Scope isolate_scope ( ( ctx ) - > isolate ) ; \
2012-04-27 16:26:15 +00:00
v8 : : Context : : Scope context_scope ( ( ctx ) - > context ) ;
2013-04-10 23:08:05 +00:00
static void php_v8js_timer_push ( long time_limit , long memory_limit , php_v8js_ctx * c )
2013-04-09 21:52:42 +00:00
{
2013-04-10 23:08:05 +00:00
V8JSG ( timer_mutex ) . lock ( ) ;
2013-04-09 21:52:42 +00:00
// Create context for this timer
2013-04-12 15:49:07 +00:00
php_v8js_timer_ctx * timer_ctx = ( php_v8js_timer_ctx * ) emalloc ( sizeof ( php_v8js_timer_ctx ) ) ;
2013-04-09 21:52:42 +00:00
2013-04-10 23:08:05 +00:00
// Calculate the time point when the time limit is exceeded
std : : chrono : : milliseconds duration ( time_limit ) ;
2013-04-09 21:52:42 +00:00
std : : chrono : : time_point < std : : chrono : : high_resolution_clock > from = std : : chrono : : high_resolution_clock : : now ( ) ;
// Push the timer context
2013-04-10 23:08:05 +00:00
timer_ctx - > time_limit = time_limit ;
timer_ctx - > memory_limit = memory_limit ;
2013-04-09 21:52:42 +00:00
timer_ctx - > time_point = from + duration ;
timer_ctx - > v8js_ctx = c ;
V8JSG ( timer_stack ) . push ( timer_ctx ) ;
2013-04-10 23:08:05 +00:00
V8JSG ( timer_mutex ) . unlock ( ) ;
2013-04-09 21:52:42 +00:00
}
2013-04-10 23:08:05 +00:00
static void php_v8js_timer_pop ( )
2013-04-09 21:52:42 +00:00
{
2013-04-10 23:08:05 +00:00
V8JSG ( timer_mutex ) . lock ( ) ;
2013-04-09 21:52:42 +00:00
if ( V8JSG ( timer_stack ) . size ( ) ) {
// Free the timer context memory
php_v8js_timer_ctx * timer_ctx = V8JSG ( timer_stack ) . top ( ) ;
2013-04-12 15:49:07 +00:00
efree ( timer_ctx ) ;
2013-04-09 21:52:42 +00:00
// Remove the timer context from the stack
V8JSG ( timer_stack ) . pop ( ) ;
}
2013-04-10 23:08:05 +00:00
V8JSG ( timer_mutex ) . unlock ( ) ;
}
static void php_v8js_terminate_execution ( php_v8js_ctx * c )
{
// Forcefully terminate the current thread of V8 execution in the isolate
v8 : : V8 : : TerminateExecution ( c - > isolate ) ;
// Remove this timer from the stack
php_v8js_timer_pop ( ) ;
2013-04-09 21:52:42 +00:00
}
static void php_v8js_timer_thread ( )
{
while ( ! V8JSG ( timer_stop ) ) {
2013-04-10 23:08:05 +00:00
v8 : : Locker locker ;
2013-04-09 21:52:42 +00:00
std : : chrono : : time_point < std : : chrono : : high_resolution_clock > now = std : : chrono : : high_resolution_clock : : now ( ) ;
2013-04-10 23:08:05 +00:00
v8 : : HeapStatistics hs ;
2013-04-09 21:52:42 +00:00
if ( V8JSG ( timer_stack ) . size ( ) ) {
// Get the current timer context
php_v8js_timer_ctx * timer_ctx = V8JSG ( timer_stack ) . top ( ) ;
php_v8js_ctx * c = timer_ctx - > v8js_ctx ;
2013-04-10 23:08:05 +00:00
// Get memory usage statistics for the isolate
c - > isolate - > GetHeapStatistics ( & hs ) ;
2013-04-09 21:52:42 +00:00
2013-04-10 23:08:05 +00:00
if ( timer_ctx - > time_limit > 0 & & now > timer_ctx - > time_point ) {
php_v8js_terminate_execution ( c ) ;
2013-04-09 21:52:42 +00:00
2013-04-10 23:08:05 +00:00
V8JSG ( timer_mutex ) . lock ( ) ;
c - > time_limit_hit = true ;
V8JSG ( timer_mutex ) . unlock ( ) ;
}
if ( timer_ctx - > memory_limit > 0 & & hs . used_heap_size ( ) > timer_ctx - > memory_limit ) {
php_v8js_terminate_execution ( c ) ;
V8JSG ( timer_mutex ) . lock ( ) ;
c - > memory_limit_hit = true ;
V8JSG ( timer_mutex ) . unlock ( ) ;
2013-04-09 21:52:42 +00:00
}
}
// Sleep for 10ms
std : : chrono : : milliseconds duration ( 10 ) ;
std : : this_thread : : sleep_for ( duration ) ;
}
}
2012-04-27 16:26:15 +00:00
/* {{{ proto mixed V8Js::executeString(string script [, string identifier [, int flags]])
*/
static PHP_METHOD ( V8Js , executeString )
{
char * str = NULL , * identifier = NULL ;
int str_len = 0 , identifier_len = 0 ;
2013-04-10 23:08:05 +00:00
long flags = V8JS_FLAG_NONE , time_limit = 0 , memory_limit = 0 ;
2012-04-27 16:26:15 +00:00
2013-04-10 23:08:05 +00:00
if ( zend_parse_parameters ( ZEND_NUM_ARGS ( ) TSRMLS_CC , " s|slll " , & str , & str_len , & identifier , & identifier_len , & flags , & time_limit , & memory_limit ) = = FAILURE ) {
2012-04-27 16:26:15 +00:00
return ;
}
V8JS_BEGIN_CTX ( c , getThis ( ) )
2013-04-10 23:08:05 +00:00
V8JSG ( timer_mutex ) . lock ( ) ;
c - > time_limit_hit = false ;
c - > memory_limit_hit = false ;
V8JSG ( timer_mutex ) . unlock ( ) ;
2012-04-27 16:26:15 +00:00
/* Catch JS exceptions */
v8 : : TryCatch try_catch ;
2013-04-10 23:08:05 +00:00
v8 : : HandleScope handle_scope ( c - > isolate ) ;
2012-04-27 16:26:15 +00:00
/* Set script identifier */
v8 : : Local < v8 : : String > sname = identifier_len ? V8JS_SYML ( identifier , identifier_len ) : V8JS_SYM ( " V8Js::executeString() " ) ;
/* Compiles a string context independently. TODO: Add a php function which calls this and returns the result as resource which can be executed later. */
v8 : : Local < v8 : : String > source = v8 : : String : : New ( str , str_len ) ;
v8 : : Local < v8 : : Script > script = v8 : : Script : : New ( source , sname ) ;
/* Compile errors? */
if ( script . IsEmpty ( ) ) {
2013-04-10 23:23:47 +00:00
php_v8js_throw_script_exception ( & try_catch TSRMLS_CC ) ;
2012-04-27 16:26:15 +00:00
return ;
}
/* Set flags for runtime use */
V8JS_GLOBAL_SET_FLAGS ( flags ) ;
2013-04-14 11:23:39 +00:00
if ( time_limit > 0 | | memory_limit > 0 ) {
2013-04-09 21:52:42 +00:00
// If timer thread is not running then start it
if ( ! V8JSG ( timer_thread ) ) {
// If not, start timer thread
V8JSG ( timer_thread ) = new std : : thread ( php_v8js_timer_thread ) ;
}
2013-04-10 23:08:05 +00:00
php_v8js_timer_push ( time_limit , memory_limit , c ) ;
2013-04-09 21:52:42 +00:00
}
2012-04-27 16:26:15 +00:00
/* Execute script */
c - > in_execution + + ;
v8 : : Local < v8 : : Value > result = script - > Run ( ) ;
c - > in_execution - - ;
2013-04-10 23:08:05 +00:00
if ( time_limit > 0 ) {
php_v8js_timer_pop ( ) ;
}
2013-04-10 23:23:47 +00:00
char exception_string [ 64 ] ;
2013-04-10 23:08:05 +00:00
if ( c - > time_limit_hit ) {
// Execution has been terminated due to time limit
2013-04-10 23:23:47 +00:00
sprintf ( exception_string , " Script time limit of %lu milliseconds exceeded " , time_limit ) ;
zend_throw_exception ( php_ce_v8js_time_limit_exception , exception_string , 0 TSRMLS_CC ) ;
2013-04-10 23:08:05 +00:00
return ;
2013-04-09 21:52:42 +00:00
}
2013-04-10 23:08:05 +00:00
if ( c - > memory_limit_hit ) {
// Execution has been terminated due to memory limit
2013-04-10 23:23:47 +00:00
sprintf ( exception_string , " Script memory limit of %lu bytes exceeded " , memory_limit ) ;
zend_throw_exception ( php_ce_v8js_memory_limit_exception , exception_string , 0 TSRMLS_CC ) ;
2013-04-10 23:08:05 +00:00
return ;
2013-04-09 21:52:42 +00:00
}
2012-04-27 16:26:15 +00:00
if ( ! try_catch . CanContinue ( ) ) {
2013-04-09 21:52:42 +00:00
// At this point we can't re-throw the exception
2012-04-27 16:26:15 +00:00
return ;
}
/* There was pending exception left from earlier executions -> throw to PHP */
if ( c - > pending_exception ) {
zend_throw_exception_object ( c - > pending_exception TSRMLS_CC ) ;
c - > pending_exception = NULL ;
}
/* Handle runtime JS exceptions */
if ( try_catch . HasCaught ( ) ) {
/* Pending exceptions are set only in outer caller, inner caller exceptions are always rethrown */
if ( c - > in_execution < 1 ) {
/* Report immediately if report_uncaught is true */
if ( c - > report_uncaught ) {
2013-04-10 23:23:47 +00:00
php_v8js_throw_script_exception ( & try_catch TSRMLS_CC ) ;
2012-04-27 16:26:15 +00:00
return ;
}
/* Exception thrown from JS, preserve it for future execution */
if ( result . IsEmpty ( ) ) {
MAKE_STD_ZVAL ( c - > pending_exception ) ;
2013-04-10 23:23:47 +00:00
php_v8js_create_script_exception ( c - > pending_exception , & try_catch TSRMLS_CC ) ;
2012-04-27 16:26:15 +00:00
}
}
/* Rethrow back to JS */
try_catch . ReThrow ( ) ;
return ;
}
/* Convert V8 value to PHP value */
if ( ! result . IsEmpty ( ) ) {
2013-04-13 23:36:05 +00:00
v8js_to_zval ( result , return_value , flags , c - > isolate TSRMLS_CC ) ;
2012-04-27 16:26:15 +00:00
}
}
/* }}} */
/* {{{ proto mixed V8Js::getPendingException()
*/
static PHP_METHOD ( V8Js , getPendingException )
{
php_v8js_ctx * c ;
if ( zend_parse_parameters_none ( ) = = FAILURE ) {
return ;
}
c = ( php_v8js_ctx * ) zend_object_store_get_object ( getThis ( ) TSRMLS_CC ) ;
if ( c - > pending_exception ) {
RETURN_ZVAL ( c - > pending_exception , 1 , 0 ) ;
}
}
/* }}} */
2013-03-24 16:27:13 +00:00
/* {{{ proto void V8Js::setModuleLoader(string module)
*/
static PHP_METHOD ( V8Js , setModuleLoader )
{
php_v8js_ctx * c ;
zval * callable ;
if ( zend_parse_parameters ( ZEND_NUM_ARGS ( ) TSRMLS_CC , " z " , & callable ) = = FAILURE ) {
return ;
}
c = ( php_v8js_ctx * ) zend_object_store_get_object ( getThis ( ) TSRMLS_CC ) ;
c - > module_loader = callable ;
Z_ADDREF_P ( c - > module_loader ) ;
}
/* }}} */
2012-04-27 16:26:15 +00:00
static void php_v8js_persistent_zval_ctor ( zval * * p ) /* { { { */
{
zval * orig_ptr = * p ;
* p = ( zval * ) malloc ( sizeof ( zval ) ) ;
* * p = * orig_ptr ;
switch ( Z_TYPE_P ( * p ) ) {
case IS_STRING :
Z_STRVAL_P ( * p ) = ( char * ) zend_strndup ( Z_STRVAL_P ( * p ) , Z_STRLEN_P ( * p ) ) ;
break ;
default :
zend_bailout ( ) ;
}
INIT_PZVAL ( * p ) ;
}
/* }}} */
static void php_v8js_persistent_zval_dtor ( zval * * p ) /* { { { */
{
switch ( Z_TYPE_P ( * p ) ) {
case IS_STRING :
free ( Z_STRVAL_P ( * p ) ) ;
break ;
default :
zend_bailout ( ) ;
}
free ( * p ) ;
}
/* }}} */
static int php_v8js_register_extension ( char * name , uint name_len , char * source , uint source_len , zval * deps_arr , zend_bool auto_enable TSRMLS_DC ) /* { { { */
{
php_v8js_jsext * jsext = NULL ;
if ( ! V8JSG ( extensions ) ) {
V8JSG ( extensions ) = ( HashTable * ) malloc ( sizeof ( HashTable ) ) ;
zend_hash_init ( V8JSG ( extensions ) , 1 , NULL , ( dtor_func_t ) php_v8js_jsext_dtor , 1 ) ;
} else if ( zend_hash_exists ( V8JSG ( extensions ) , name , name_len + 1 ) ) {
return FAILURE ;
}
jsext = ( php_v8js_jsext * ) calloc ( 1 , sizeof ( php_v8js_jsext ) ) ;
if ( deps_arr ) {
jsext - > deps_count = zend_hash_num_elements ( Z_ARRVAL_P ( deps_arr ) ) ;
if ( _php_v8js_create_ext_strarr ( & jsext - > deps , jsext - > deps_count , Z_ARRVAL_P ( deps_arr ) ) = = FAILURE ) {
php_error_docref ( NULL TSRMLS_CC , E_WARNING , " Invalid dependancy array passed " ) ;
php_v8js_jsext_dtor ( jsext ) ;
free ( jsext ) ;
return FAILURE ;
}
}
jsext - > auto_enable = auto_enable ;
jsext - > name = zend_strndup ( name , name_len ) ;
jsext - > source = zend_strndup ( source , source_len ) ;
if ( jsext - > deps ) {
jsext - > deps_ht = ( HashTable * ) malloc ( sizeof ( HashTable ) ) ;
zend_hash_init ( jsext - > deps_ht , jsext - > deps_count , NULL , ( dtor_func_t ) php_v8js_persistent_zval_dtor , 1 ) ;
zend_hash_copy ( jsext - > deps_ht , Z_ARRVAL_P ( deps_arr ) , ( copy_ctor_func_t ) php_v8js_persistent_zval_ctor , NULL , sizeof ( zval * ) ) ;
}
if ( zend_hash_add ( V8JSG ( extensions ) , name , name_len + 1 , jsext , sizeof ( php_v8js_jsext ) , NULL ) = = FAILURE ) {
php_v8js_jsext_dtor ( jsext ) ;
free ( jsext ) ;
return FAILURE ;
}
v8 : : Extension * extension = new v8 : : Extension ( jsext - > name , jsext - > source , jsext - > deps_count , jsext - > deps ) ;
extension - > set_auto_enable ( auto_enable ? true : false ) ;
v8 : : RegisterExtension ( extension ) ;
free ( jsext ) ;
return SUCCESS ;
}
/* }}} */
/* {{{ proto bool V8Js::registerExtension(string ext_name, string script [, array deps [, bool auto_enable]])
*/
static PHP_METHOD ( V8Js , registerExtension )
{
char * ext_name , * script ;
zval * deps_arr = NULL ;
int ext_name_len , script_len ;
zend_bool auto_enable = 0 ;
if ( zend_parse_parameters ( ZEND_NUM_ARGS ( ) TSRMLS_CC , " ss|ab " , & ext_name , & ext_name_len , & script , & script_len , & deps_arr , & auto_enable ) = = FAILURE ) {
return ;
}
if ( ! ext_name_len ) {
php_error_docref ( NULL TSRMLS_CC , E_WARNING , " Extension name cannot be empty " ) ;
} else if ( ! script_len ) {
php_error_docref ( NULL TSRMLS_CC , E_WARNING , " Script cannot be empty " ) ;
} else if ( php_v8js_register_extension ( ext_name , ext_name_len , script , script_len , deps_arr , auto_enable TSRMLS_CC ) = = SUCCESS ) {
RETURN_TRUE ;
}
RETURN_FALSE ;
}
/* }}} */
/* ## Static methods ## */
/* {{{ proto array V8Js::getExtensions()
*/
static PHP_METHOD ( V8Js , getExtensions )
{
php_v8js_jsext * jsext ;
zval * ext , * deps_arr ;
HashPosition pos ;
ulong index ;
char * key ;
uint key_len ;
if ( zend_parse_parameters_none ( ) = = FAILURE ) {
return ;
}
array_init ( return_value ) ;
if ( V8JSG ( extensions ) ) {
zend_hash_internal_pointer_reset_ex ( V8JSG ( extensions ) , & pos ) ;
while ( zend_hash_get_current_data_ex ( V8JSG ( extensions ) , ( void * * ) & jsext , & pos ) = = SUCCESS ) {
if ( zend_hash_get_current_key_ex ( V8JSG ( extensions ) , & key , & key_len , & index , 0 , & pos ) = = HASH_KEY_IS_STRING ) {
MAKE_STD_ZVAL ( ext )
array_init ( ext ) ;
add_assoc_bool_ex ( ext , ZEND_STRS ( " auto_enable " ) , jsext - > auto_enable ) ;
if ( jsext - > deps_ht ) {
MAKE_STD_ZVAL ( deps_arr ) ;
array_init ( deps_arr ) ;
zend_hash_copy ( Z_ARRVAL_P ( deps_arr ) , jsext - > deps_ht , ( copy_ctor_func_t ) zval_add_ref , NULL , sizeof ( zval * ) ) ;
add_assoc_zval_ex ( ext , ZEND_STRS ( " deps " ) , deps_arr ) ;
}
add_assoc_zval_ex ( return_value , key , key_len , ext ) ;
}
zend_hash_move_forward_ex ( V8JSG ( extensions ) , & pos ) ;
}
}
}
/* }}} */
/* {{{ arginfo */
ZEND_BEGIN_ARG_INFO_EX ( arginfo_v8js_construct , 0 , 0 , 0 )
ZEND_ARG_INFO ( 0 , object_name )
ZEND_ARG_INFO ( 0 , variables )
ZEND_ARG_INFO ( 0 , extensions )
ZEND_ARG_INFO ( 0 , report_uncaught_exceptions )
ZEND_END_ARG_INFO ( )
ZEND_BEGIN_ARG_INFO_EX ( arginfo_v8js_executestring , 0 , 0 , 1 )
ZEND_ARG_INFO ( 0 , script )
ZEND_ARG_INFO ( 0 , identifier )
ZEND_ARG_INFO ( 0 , flags )
2013-04-10 23:08:05 +00:00
ZEND_ARG_INFO ( 0 , time_limit )
ZEND_ARG_INFO ( 0 , memory_limit )
2012-04-27 16:26:15 +00:00
ZEND_END_ARG_INFO ( )
ZEND_BEGIN_ARG_INFO ( arginfo_v8js_getpendingexception , 0 )
ZEND_END_ARG_INFO ( )
2013-03-24 16:27:13 +00:00
ZEND_BEGIN_ARG_INFO_EX ( arginfo_v8js_setmoduleloader , 0 , 0 , 1 )
ZEND_ARG_INFO ( 0 , callable )
ZEND_END_ARG_INFO ( )
2012-04-27 16:26:15 +00:00
ZEND_BEGIN_ARG_INFO_EX ( arginfo_v8js_registerextension , 0 , 0 , 2 )
ZEND_ARG_INFO ( 0 , extension_name )
ZEND_ARG_INFO ( 0 , script )
ZEND_ARG_INFO ( 0 , dependencies )
ZEND_ARG_INFO ( 0 , auto_enable )
ZEND_END_ARG_INFO ( )
ZEND_BEGIN_ARG_INFO ( arginfo_v8js_getextensions , 0 )
ZEND_END_ARG_INFO ( )
2013-04-10 23:23:47 +00:00
ZEND_BEGIN_ARG_INFO ( arginfo_v8jsscriptexception_no_args , 0 )
2012-04-27 16:26:15 +00:00
ZEND_END_ARG_INFO ( )
/* }}} */
static const zend_function_entry v8js_methods [ ] = { /* {{{ */
PHP_ME ( V8Js , __construct , arginfo_v8js_construct , ZEND_ACC_PUBLIC | ZEND_ACC_CTOR )
PHP_ME ( V8Js , executeString , arginfo_v8js_executestring , ZEND_ACC_PUBLIC )
PHP_ME ( V8Js , getPendingException , arginfo_v8js_getpendingexception , ZEND_ACC_PUBLIC )
2013-03-24 16:27:13 +00:00
PHP_ME ( V8Js , setModuleLoader , arginfo_v8js_setmoduleloader , ZEND_ACC_PUBLIC )
2012-04-27 16:26:15 +00:00
PHP_ME ( V8Js , registerExtension , arginfo_v8js_registerextension , ZEND_ACC_PUBLIC | ZEND_ACC_STATIC )
PHP_ME ( V8Js , getExtensions , arginfo_v8js_getextensions , ZEND_ACC_PUBLIC | ZEND_ACC_STATIC )
{ NULL , NULL , NULL }
} ;
/* }}} */
/* V8Js object handlers */
2012-07-07 00:12:53 +00:00
static void php_v8js_write_property ( zval * object , zval * member , zval * value ZEND_HASH_KEY_DC TSRMLS_DC ) /* { { { */
2012-04-27 16:26:15 +00:00
{
V8JS_BEGIN_CTX ( c , object )
2013-04-10 23:08:05 +00:00
v8 : : HandleScope handle_scope ( c - > isolate ) ;
2012-04-27 16:26:15 +00:00
/* Global PHP JS object */
v8 : : Local < v8 : : Object > jsobj = V8JS_GLOBAL - > Get ( c - > object_name ) - > ToObject ( ) ;
/* Write value to PHP JS object */
2013-04-13 23:36:05 +00:00
jsobj - > ForceSet ( V8JS_SYML ( Z_STRVAL_P ( member ) , Z_STRLEN_P ( member ) ) , zval_to_v8js ( value , c - > isolate TSRMLS_CC ) , v8 : : ReadOnly ) ;
2012-04-27 16:26:15 +00:00
/* Write value to PHP object */
2012-07-07 00:12:53 +00:00
std_object_handlers . write_property ( object , member , value ZEND_HASH_KEY_CC TSRMLS_CC ) ;
2012-04-27 16:26:15 +00:00
}
/* }}} */
2012-07-07 00:12:53 +00:00
static void php_v8js_unset_property ( zval * object , zval * member ZEND_HASH_KEY_DC TSRMLS_DC ) /* { { { */
2012-04-27 16:26:15 +00:00
{
V8JS_BEGIN_CTX ( c , object )
2013-04-10 23:08:05 +00:00
v8 : : HandleScope handle_scope ( c - > isolate ) ;
2012-04-27 16:26:15 +00:00
/* Global PHP JS object */
v8 : : Local < v8 : : Object > jsobj = V8JS_GLOBAL - > Get ( c - > object_name ) - > ToObject ( ) ;
/* Delete value from PHP JS object */
jsobj - > ForceDelete ( V8JS_SYML ( Z_STRVAL_P ( member ) , Z_STRLEN_P ( member ) ) ) ;
/* Unset from PHP object */
2012-07-07 00:12:53 +00:00
std_object_handlers . unset_property ( object , member ZEND_HASH_KEY_CC TSRMLS_CC ) ;
2012-04-27 16:26:15 +00:00
}
/* }}} */
/* }}} V8Js */
2013-04-10 23:23:47 +00:00
/* {{{ Class: V8JsScriptException */
2012-04-27 16:26:15 +00:00
2013-04-10 23:23:47 +00:00
static void php_v8js_create_script_exception ( zval * return_value , v8 : : TryCatch * try_catch TSRMLS_DC ) /* { { { */
2012-04-27 16:26:15 +00:00
{
v8 : : String : : Utf8Value exception ( try_catch - > Exception ( ) ) ;
const char * exception_string = ToCString ( exception ) ;
v8 : : Handle < v8 : : Message > tc_message = try_catch - > Message ( ) ;
const char * filename_string , * sourceline_string ;
char * message_string ;
int linenum , message_len ;
2013-04-10 23:23:47 +00:00
object_init_ex ( return_value , php_ce_v8js_script_exception ) ;
2012-04-27 16:26:15 +00:00
# define PHPV8_EXPROP(type, name, value) \
2013-04-10 23:23:47 +00:00
zend_update_property # # type ( php_ce_v8js_script_exception , return_value , # name , sizeof ( # name ) - 1 , value TSRMLS_CC ) ;
2012-04-27 16:26:15 +00:00
if ( tc_message . IsEmpty ( ) ) {
message_len = spprintf ( & message_string , 0 , " %s " , exception_string ) ;
}
else
{
v8 : : String : : Utf8Value filename ( tc_message - > GetScriptResourceName ( ) ) ;
filename_string = ToCString ( filename ) ;
PHPV8_EXPROP ( _string , JsFileName , filename_string ) ;
v8 : : String : : Utf8Value sourceline ( tc_message - > GetSourceLine ( ) ) ;
sourceline_string = ToCString ( sourceline ) ;
PHPV8_EXPROP ( _string , JsSourceLine , sourceline_string ) ;
linenum = tc_message - > GetLineNumber ( ) ;
PHPV8_EXPROP ( _long , JsLineNumber , linenum ) ;
message_len = spprintf ( & message_string , 0 , " %s:%d: %s " , filename_string , linenum , exception_string ) ;
v8 : : String : : Utf8Value stacktrace ( try_catch - > StackTrace ( ) ) ;
if ( stacktrace . length ( ) > 0 ) {
const char * stacktrace_string = ToCString ( stacktrace ) ;
PHPV8_EXPROP ( _string , JsTrace , stacktrace_string ) ;
}
}
PHPV8_EXPROP ( _string , message , message_string ) ;
efree ( message_string ) ;
}
/* }}} */
2013-04-10 23:23:47 +00:00
static void php_v8js_throw_script_exception ( v8 : : TryCatch * try_catch TSRMLS_DC ) /* { { { */
2012-04-27 16:26:15 +00:00
{
v8 : : String : : Utf8Value exception ( try_catch - > Exception ( ) ) ;
const char * exception_string = ToCString ( exception ) ;
zval * zexception = NULL ;
if ( try_catch - > Message ( ) . IsEmpty ( ) ) {
2013-04-10 23:23:47 +00:00
zend_throw_exception ( php_ce_v8js_script_exception , ( char * ) exception_string , 0 TSRMLS_CC ) ;
2012-04-27 16:26:15 +00:00
} else {
MAKE_STD_ZVAL ( zexception ) ;
2013-04-10 23:23:47 +00:00
php_v8js_create_script_exception ( zexception , try_catch TSRMLS_CC ) ;
2012-04-27 16:26:15 +00:00
zend_throw_exception_object ( zexception TSRMLS_CC ) ;
}
}
/* }}} */
# define V8JS_EXCEPTION_METHOD(property) \
2013-04-10 23:23:47 +00:00
static PHP_METHOD ( V8JsScriptException , get # # property ) \
2012-04-27 16:26:15 +00:00
{ \
zval * value ; \
\
if ( zend_parse_parameters_none ( ) = = FAILURE ) { \
return ; \
} \
2013-04-10 23:23:47 +00:00
value = zend_read_property ( php_ce_v8js_script_exception , getThis ( ) , # property , sizeof ( # property ) - 1 , 0 TSRMLS_CC ) ; \
2012-04-27 16:26:15 +00:00
* return_value = * value ; \
zval_copy_ctor ( return_value ) ; \
INIT_PZVAL ( return_value ) ; \
}
2013-04-10 23:23:47 +00:00
/* {{{ proto string V8JsEScriptxception::getJsFileName()
2012-04-27 16:26:15 +00:00
*/
V8JS_EXCEPTION_METHOD ( JsFileName ) ;
/* }}} */
2013-04-10 23:23:47 +00:00
/* {{{ proto string V8JsScriptException::getJsLineNumber()
2012-04-27 16:26:15 +00:00
*/
V8JS_EXCEPTION_METHOD ( JsLineNumber ) ;
/* }}} */
2013-04-10 23:23:47 +00:00
/* {{{ proto string V8JsScriptException::getJsSourceLine()
2012-04-27 16:26:15 +00:00
*/
V8JS_EXCEPTION_METHOD ( JsSourceLine ) ;
/* }}} */
2013-04-10 23:23:47 +00:00
/* {{{ proto string V8JsScriptException::getJsTrace()
2012-04-27 16:26:15 +00:00
*/
V8JS_EXCEPTION_METHOD ( JsTrace ) ;
/* }}} */
2013-04-10 23:23:47 +00:00
static const zend_function_entry v8js_script_exception_methods [ ] = { /* {{{ */
PHP_ME ( V8JsScriptException , getJsFileName , arginfo_v8jsscriptexception_no_args , ZEND_ACC_PUBLIC | ZEND_ACC_FINAL )
PHP_ME ( V8JsScriptException , getJsLineNumber , arginfo_v8jsscriptexception_no_args , ZEND_ACC_PUBLIC | ZEND_ACC_FINAL )
PHP_ME ( V8JsScriptException , getJsSourceLine , arginfo_v8jsscriptexception_no_args , ZEND_ACC_PUBLIC | ZEND_ACC_FINAL )
PHP_ME ( V8JsScriptException , getJsTrace , arginfo_v8jsscriptexception_no_args , ZEND_ACC_PUBLIC | ZEND_ACC_FINAL )
2012-04-27 16:26:15 +00:00
{ NULL , NULL , NULL }
} ;
/* }}} */
2013-04-10 23:23:47 +00:00
/* }}} V8JsScriptException */
/* {{{ Class: V8JsTimeLimitException */
static const zend_function_entry v8js_time_limit_exception_methods [ ] = { /* {{{ */
2012-04-27 16:26:15 +00:00
{ NULL , NULL , NULL }
} ;
2013-04-10 23:23:47 +00:00
/* }}} */
/* }}} V8JsTimeLimitException */
/* {{{ Class: V8JsMemoryLimitException */
static const zend_function_entry v8js_memory_limit_exception_methods [ ] = { /* {{{ */
{ NULL , NULL , NULL }
} ;
2012-04-27 16:26:15 +00:00
/* }}} */
2013-04-10 23:23:47 +00:00
/* }}} V8JsMemoryLimitException */
2012-04-27 16:26:15 +00:00
/* {{{ PHP_MINIT_FUNCTION
*/
static PHP_MINIT_FUNCTION ( v8js )
{
zend_class_entry ce ;
/* V8Object Class */
INIT_CLASS_ENTRY ( ce , " V8Object " , NULL ) ;
php_ce_v8_object = zend_register_internal_class ( & ce TSRMLS_CC ) ;
php_ce_v8_object - > ce_flags | = ZEND_ACC_FINAL ;
php_ce_v8_object - > create_object = php_v8js_v8_new ;
/* V8Function Class */
INIT_CLASS_ENTRY ( ce , " V8Function " , NULL ) ;
php_ce_v8_function = zend_register_internal_class ( & ce TSRMLS_CC ) ;
php_ce_v8_function - > ce_flags | = ZEND_ACC_FINAL ;
php_ce_v8_function - > create_object = php_v8js_v8_new ;
/* V8<Object|Function> handlers */
memcpy ( & v8_object_handlers , zend_get_std_object_handlers ( ) , sizeof ( zend_object_handlers ) ) ;
v8_object_handlers . clone_obj = NULL ;
v8_object_handlers . cast_object = NULL ;
v8_object_handlers . get_constructor = NULL ;
v8_object_handlers . get_property_ptr_ptr = NULL ;
// v8_object_handlers.has_property = php_v8js_v8_has_property; // Not implemented yet
v8_object_handlers . read_property = php_v8js_v8_read_property ;
v8_object_handlers . write_property = php_v8js_v8_write_property ;
v8_object_handlers . unset_property = php_v8js_v8_unset_property ;
v8_object_handlers . get_properties = php_v8js_v8_get_properties ;
v8_object_handlers . get_method = php_v8js_v8_get_method ;
v8_object_handlers . call_method = php_v8js_v8_call_method ;
v8_object_handlers . get_debug_info = php_v8js_v8_get_debug_info ;
v8_object_handlers . get_closure = php_v8js_v8_get_closure ;
/* V8Js Class */
INIT_CLASS_ENTRY ( ce , " V8Js " , v8js_methods ) ;
php_ce_v8js = zend_register_internal_class ( & ce TSRMLS_CC ) ;
php_ce_v8js - > create_object = php_v8js_new ;
/* V8Js handlers */
memcpy ( & v8js_object_handlers , zend_get_std_object_handlers ( ) , sizeof ( zend_object_handlers ) ) ;
v8js_object_handlers . clone_obj = NULL ;
v8js_object_handlers . write_property = php_v8js_write_property ;
v8js_object_handlers . unset_property = php_v8js_unset_property ;
/* V8Js Class Constants */
zend_declare_class_constant_string ( php_ce_v8js , ZEND_STRL ( " V8_VERSION " ) , PHP_V8_VERSION TSRMLS_CC ) ;
zend_declare_class_constant_long ( php_ce_v8js , ZEND_STRL ( " FLAG_NONE " ) , V8JS_FLAG_NONE TSRMLS_CC ) ;
zend_declare_class_constant_long ( php_ce_v8js , ZEND_STRL ( " FLAG_FORCE_ARRAY " ) , V8JS_FLAG_FORCE_ARRAY TSRMLS_CC ) ;
2013-04-10 23:23:47 +00:00
/* V8JsScriptException Class */
INIT_CLASS_ENTRY ( ce , " V8JsScriptException " , v8js_script_exception_methods ) ;
php_ce_v8js_script_exception = zend_register_internal_class_ex ( & ce , zend_exception_get_default ( TSRMLS_C ) , NULL TSRMLS_CC ) ;
php_ce_v8js_script_exception - > ce_flags | = ZEND_ACC_FINAL ;
2012-04-27 16:26:15 +00:00
/* Add custom JS specific properties */
2013-04-10 23:23:47 +00:00
zend_declare_property_null ( php_ce_v8js_script_exception , ZEND_STRL ( " JsFileName " ) , ZEND_ACC_PROTECTED TSRMLS_CC ) ;
zend_declare_property_null ( php_ce_v8js_script_exception , ZEND_STRL ( " JsLineNumber " ) , ZEND_ACC_PROTECTED TSRMLS_CC ) ;
zend_declare_property_null ( php_ce_v8js_script_exception , ZEND_STRL ( " JsSourceLine " ) , ZEND_ACC_PROTECTED TSRMLS_CC ) ;
zend_declare_property_null ( php_ce_v8js_script_exception , ZEND_STRL ( " JsTrace " ) , ZEND_ACC_PROTECTED TSRMLS_CC ) ;
/* V8JsTimeLimitException Class */
INIT_CLASS_ENTRY ( ce , " V8JsTimeLimitException " , v8js_time_limit_exception_methods ) ;
php_ce_v8js_time_limit_exception = zend_register_internal_class_ex ( & ce , zend_exception_get_default ( TSRMLS_C ) , NULL TSRMLS_CC ) ;
php_ce_v8js_time_limit_exception - > ce_flags | = ZEND_ACC_FINAL ;
/* V8JsMemoryLimitException Class */
INIT_CLASS_ENTRY ( ce , " V8JsMemoryLimitException " , v8js_memory_limit_exception_methods ) ;
php_ce_v8js_memory_limit_exception = zend_register_internal_class_ex ( & ce , zend_exception_get_default ( TSRMLS_C ) , NULL TSRMLS_CC ) ;
php_ce_v8js_memory_limit_exception - > ce_flags | = ZEND_ACC_FINAL ;
2012-04-27 16:26:15 +00:00
REGISTER_INI_ENTRIES ( ) ;
return SUCCESS ;
}
/* }}} */
static void php_v8js_force_v8_gc ( void ) /* { { { */
{
# if V8JS_DEBUG
TSRMLS_FETCH ( ) ;
fprintf ( stderr , " ############ Running V8 Idle notification: disposed/max_disposed %d/%d ############ \n " , V8JSG ( disposed_contexts ) , V8JSG ( max_disposed_contexts ) ) ;
fflush ( stderr ) ;
# endif
while ( ! v8 : : V8 : : IdleNotification ( ) ) {
# if V8JS_DEBUG
fprintf ( stderr , " . " ) ;
fflush ( stderr ) ;
# endif
}
# if V8JS_DEBUG
fprintf ( stderr , " \n " ) ;
fflush ( stderr ) ;
# endif
}
/* }}} */
/* {{{ PHP_MSHUTDOWN_FUNCTION
*/
static PHP_MSHUTDOWN_FUNCTION ( v8js )
{
UNREGISTER_INI_ENTRIES ( ) ;
if ( V8JSG ( extensions ) ) {
zend_hash_destroy ( V8JSG ( extensions ) ) ;
free ( V8JSG ( extensions ) ) ;
V8JSG ( extensions ) = NULL ;
}
if ( V8JSG ( v8_flags ) ) {
free ( V8JSG ( v8_flags ) ) ;
V8JSG ( v8_flags ) = NULL ;
}
return SUCCESS ;
}
/* }}} */
/* {{{ PHP_RSHUTDOWN_FUNCTION
*/
static PHP_RSHUTDOWN_FUNCTION ( v8js )
{
2013-04-09 21:52:42 +00:00
// If the timer thread is running then stop it
if ( V8JSG ( timer_thread ) ) {
V8JSG ( timer_stop ) = true ;
V8JSG ( timer_thread ) - > join ( ) ;
}
2012-04-27 16:26:15 +00:00
# if V8JS_DEBUG
v8 : : HeapStatistics stats ;
v8 : : V8 : : GetHeapStatistics ( & stats ) ;
float used = stats . used_heap_size ( ) / 1024.0 / 1024.0 ;
float total = stats . total_heap_size ( ) / 1024.0 / 1024.0 ;
fprintf ( stderr , " ### RSHUTDOWN ### \n " ) ;
fprintf ( stderr , " ############ Heap Used/Total %.2f/%.2f MB ############ \n " , used , total ) ;
fflush ( stderr ) ;
# endif
/* Force V8 to do as much GC as possible */
if ( V8JSG ( max_disposed_contexts ) & & ( V8JSG ( disposed_contexts ) > V8JSG ( max_disposed_contexts ) ) ) {
php_v8js_force_v8_gc ( ) ;
}
return SUCCESS ;
}
/* }}} */
/* {{{ PHP_MINFO_FUNCTION
*/
static PHP_MINFO_FUNCTION ( v8js )
{
php_info_print_table_start ( ) ;
php_info_print_table_header ( 2 , " V8 Javascript Engine " , " enabled " ) ;
php_info_print_table_header ( 2 , " V8 Engine Compiled Version " , PHP_V8_VERSION ) ;
php_info_print_table_header ( 2 , " V8 Engine Linked Version " , v8 : : V8 : : GetVersion ( ) ) ;
php_info_print_table_header ( 2 , " Version " , V8JS_VERSION ) ;
php_info_print_table_end ( ) ;
DISPLAY_INI_ENTRIES ( ) ;
}
/* }}} */
/* {{{ PHP_GINIT_FUNCTION
*/
static PHP_GINIT_FUNCTION ( v8js )
{
v8js_globals - > extensions = NULL ;
v8js_globals - > disposed_contexts = 0 ;
v8js_globals - > v8_initialized = 0 ;
v8js_globals - > v8_flags = NULL ;
2013-04-09 21:52:42 +00:00
v8js_globals - > timer_thread = NULL ;
v8js_globals - > timer_stop = false ;
2012-04-27 16:26:15 +00:00
}
/* }}} */
/* {{{ v8js_functions[] */
static const zend_function_entry v8js_functions [ ] = {
{ NULL , NULL , NULL }
} ;
/* }}} */
/* {{{ v8js_module_entry
*/
zend_module_entry v8js_module_entry = {
STANDARD_MODULE_HEADER_EX ,
NULL ,
NULL ,
" v8js " ,
v8js_functions ,
PHP_MINIT ( v8js ) ,
PHP_MSHUTDOWN ( v8js ) ,
NULL ,
PHP_RSHUTDOWN ( v8js ) ,
PHP_MINFO ( v8js ) ,
V8JS_VERSION ,
PHP_MODULE_GLOBALS ( v8js ) ,
PHP_GINIT ( v8js ) ,
NULL ,
NULL ,
STANDARD_MODULE_PROPERTIES_EX
} ;
/* }}} */
/*
* Local variables :
* tab - width : 4
* c - basic - offset : 4
* End :
* vim600 : noet sw = 4 ts = 4 fdm = marker
* vim < 600 : noet sw = 4 ts = 4
*/