|  | @@ -19,6 +19,8 @@
 | 
	
		
			
				|  |  |  #include "config.h"
 | 
	
		
			
				|  |  |  #endif
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +#include <v8-debug.h>
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |  #include "php_v8js_macros.h"
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  extern "C" {
 | 
	
	
		
			
				|  | @@ -101,6 +103,11 @@ struct php_v8js_jsext {
 | 
	
		
			
				|  |  |  };
 | 
	
		
			
				|  |  |  /* }}} */
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +#ifdef ENABLE_DEBUGGER_SUPPORT
 | 
	
		
			
				|  |  | +static php_v8js_ctx *v8js_debug_context;
 | 
	
		
			
				|  |  | +static int v8js_debug_auto_break_mode;
 | 
	
		
			
				|  |  | +#endif
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |  #ifdef COMPILE_DL_V8JS
 | 
	
		
			
				|  |  |  ZEND_GET_MODULE(v8js)
 | 
	
		
			
				|  |  |  #endif
 | 
	
	
		
			
				|  | @@ -598,6 +605,25 @@ static void php_v8js_fatal_error_handler(const char *location, const char *messa
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  /* }}} */
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +#ifdef ENABLE_DEBUGGER_SUPPORT
 | 
	
		
			
				|  |  | +static void DispatchDebugMessages() { /* {{{ */
 | 
	
		
			
				|  |  | +	if(v8js_debug_context == NULL) {
 | 
	
		
			
				|  |  | +		return;
 | 
	
		
			
				|  |  | +	}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	v8::Isolate* isolate = v8js_debug_context->isolate;
 | 
	
		
			
				|  |  | +	v8::Isolate::Scope isolate_scope(isolate);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	v8::HandleScope handle_scope(isolate);
 | 
	
		
			
				|  |  | +	v8::Local<v8::Context> context =
 | 
	
		
			
				|  |  | +		v8::Local<v8::Context>::New(isolate, v8js_debug_context->context);
 | 
	
		
			
				|  |  | +	v8::Context::Scope scope(context);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	v8::Debug::ProcessDebugMessages();
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +/* }}} */
 | 
	
		
			
				|  |  | +#endif  /* ENABLE_DEBUGGER_SUPPORT */
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |  static void php_v8js_init(TSRMLS_D) /* {{{ */
 | 
	
		
			
				|  |  |  {
 | 
	
		
			
				|  |  |  	/* Run only once */
 | 
	
	
		
			
				|  | @@ -641,6 +667,9 @@ static PHP_METHOD(V8Js, __construct)
 | 
	
		
			
				|  |  |  		return;
 | 
	
		
			
				|  |  |  	}
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +	/* Initialize V8 */
 | 
	
		
			
				|  |  | +	php_v8js_init(TSRMLS_C);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |  	/* Throw PHP exception if uncaught exceptions exist */
 | 
	
		
			
				|  |  |  	c->report_uncaught = report_uncaught;
 | 
	
		
			
				|  |  |  	c->pending_exception = NULL;
 | 
	
	
		
			
				|  | @@ -651,9 +680,6 @@ static PHP_METHOD(V8Js, __construct)
 | 
	
		
			
				|  |  |  	c->memory_limit_hit = false;
 | 
	
		
			
				|  |  |  	c->module_loader = NULL;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -	/* 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)
 | 
	
	
		
			
				|  | @@ -882,6 +908,17 @@ static PHP_METHOD(V8Js, executeString)
 | 
	
		
			
				|  |  |  		php_v8js_timer_push(time_limit, memory_limit, c TSRMLS_CC);
 | 
	
		
			
				|  |  |  	}
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +#ifdef ENABLE_DEBUGGER_SUPPORT
 | 
	
		
			
				|  |  | +	if(c == v8js_debug_context && v8js_debug_auto_break_mode != V8JS_DEBUG_AUTO_BREAK_NEVER) {
 | 
	
		
			
				|  |  | +		v8::Debug::DebugBreak(c->isolate);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +		if(v8js_debug_auto_break_mode == V8JS_DEBUG_AUTO_BREAK_ONCE) {
 | 
	
		
			
				|  |  | +			/* If break-once-mode was enabled, reset flag. */
 | 
	
		
			
				|  |  | +			v8js_debug_auto_break_mode = V8JS_DEBUG_AUTO_BREAK_NEVER;
 | 
	
		
			
				|  |  | +		}
 | 
	
		
			
				|  |  | +	}
 | 
	
		
			
				|  |  | +#endif  /* ENABLE_DEBUGGER_SUPPORT */
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |  	/* Execute script */
 | 
	
		
			
				|  |  |  	c->in_execution++;
 | 
	
		
			
				|  |  |  	v8::Local<v8::Value> result = script->Run();
 | 
	
	
		
			
				|  | @@ -949,6 +986,66 @@ static PHP_METHOD(V8Js, executeString)
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  /* }}} */
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +#ifdef ENABLE_DEBUGGER_SUPPORT
 | 
	
		
			
				|  |  | +/* {{{ proto void V8Js::__destruct()
 | 
	
		
			
				|  |  | +   __destruct for V8Js */
 | 
	
		
			
				|  |  | +static PHP_METHOD(V8Js, __destruct)
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +	V8JS_BEGIN_CTX(c, getThis());
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	if(v8js_debug_context == c) {
 | 
	
		
			
				|  |  | +		v8::Debug::DisableAgent();
 | 
	
		
			
				|  |  | +		v8js_debug_context = NULL;
 | 
	
		
			
				|  |  | +	}
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +/* }}} */
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +/* {{{ proto bool V8Js::startDebugAgent(string agent_name[, int port[, int auto_break]])
 | 
	
		
			
				|  |  | + */
 | 
	
		
			
				|  |  | +static PHP_METHOD(V8Js, startDebugAgent)
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +	char *str = NULL;
 | 
	
		
			
				|  |  | +	int str_len = 0;
 | 
	
		
			
				|  |  | +	long port = 0, auto_break = 0;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|sll", &str, &str_len, &port, &auto_break) == FAILURE) {
 | 
	
		
			
				|  |  | +		return;
 | 
	
		
			
				|  |  | +	}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	if(!port) {
 | 
	
		
			
				|  |  | +		port = 9222;
 | 
	
		
			
				|  |  | +	}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	V8JS_BEGIN_CTX(c, getThis());
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	if(v8js_debug_context == c) {
 | 
	
		
			
				|  |  | +		php_error_docref(NULL TSRMLS_CC, E_WARNING, "Debug agent already started for this V8Js instance");
 | 
	
		
			
				|  |  | +		RETURN_BOOL(0);
 | 
	
		
			
				|  |  | +	}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	if(v8js_debug_context != NULL) {
 | 
	
		
			
				|  |  | +		php_error_docref(NULL TSRMLS_CC, E_WARNING, "Debug agent already started for a different V8Js instance");
 | 
	
		
			
				|  |  | +		RETURN_BOOL(0);
 | 
	
		
			
				|  |  | +	}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	v8js_debug_context = c;
 | 
	
		
			
				|  |  | +	v8js_debug_auto_break_mode = auto_break;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	v8::Debug::SetDebugMessageDispatchHandler(DispatchDebugMessages, true);
 | 
	
		
			
				|  |  | +	v8::Debug::EnableAgent(str_len ? str : "V8Js", port, auto_break > 0);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	if(auto_break) {
 | 
	
		
			
				|  |  | +		/* v8::Debug::EnableAgent doesn't really do what we want it to do,
 | 
	
		
			
				|  |  | +		   since it only breaks processing on the default isolate.
 | 
	
		
			
				|  |  | +		   Hence just trigger another DebugBreak, no for our main isolate. */
 | 
	
		
			
				|  |  | +		v8::Debug::DebugBreak(c->isolate);
 | 
	
		
			
				|  |  | +	}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	RETURN_BOOL(1);
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +/* }}} */
 | 
	
		
			
				|  |  | +#endif  /* ENABLE_DEBUGGER_SUPPORT */
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |  /* {{{ proto mixed V8Js::getPendingException()
 | 
	
		
			
				|  |  |   */
 | 
	
		
			
				|  |  |  static PHP_METHOD(V8Js, getPendingException)
 | 
	
	
		
			
				|  | @@ -1143,6 +1240,17 @@ ZEND_BEGIN_ARG_INFO_EX(arginfo_v8js_executestring, 0, 0, 1)
 | 
	
		
			
				|  |  |  	ZEND_ARG_INFO(0, memory_limit)
 | 
	
		
			
				|  |  |  ZEND_END_ARG_INFO()
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +#ifdef ENABLE_DEBUGGER_SUPPORT
 | 
	
		
			
				|  |  | +ZEND_BEGIN_ARG_INFO_EX(arginfo_v8js_destruct, 0, 0, 0)
 | 
	
		
			
				|  |  | +ZEND_END_ARG_INFO()
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +ZEND_BEGIN_ARG_INFO_EX(arginfo_v8js_startdebugagent, 0, 0, 0)
 | 
	
		
			
				|  |  | +	ZEND_ARG_INFO(0, agentName)
 | 
	
		
			
				|  |  | +	ZEND_ARG_INFO(0, port)
 | 
	
		
			
				|  |  | +	ZEND_ARG_INFO(0, auto_break)
 | 
	
		
			
				|  |  | +ZEND_END_ARG_INFO()
 | 
	
		
			
				|  |  | +#endif  /* ENABLE_DEBUGGER_SUPPORT */
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |  ZEND_BEGIN_ARG_INFO(arginfo_v8js_getpendingexception, 0)
 | 
	
		
			
				|  |  |  ZEND_END_ARG_INFO()
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -1171,6 +1279,10 @@ static const zend_function_entry v8js_methods[] = { /* {{{ */
 | 
	
		
			
				|  |  |  	PHP_ME(V8Js,	setModuleLoader,		arginfo_v8js_setmoduleloader,		ZEND_ACC_PUBLIC)
 | 
	
		
			
				|  |  |  	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)
 | 
	
		
			
				|  |  | +#ifdef ENABLE_DEBUGGER_SUPPORT
 | 
	
		
			
				|  |  | +	PHP_ME(V8Js,	__destruct,				arginfo_v8js_destruct,				ZEND_ACC_PUBLIC|ZEND_ACC_DTOR)
 | 
	
		
			
				|  |  | +	PHP_ME(V8Js,	startDebugAgent,		arginfo_v8js_startdebugagent,		ZEND_ACC_PUBLIC)
 | 
	
		
			
				|  |  | +#endif
 | 
	
		
			
				|  |  |  	{NULL, NULL, NULL}
 | 
	
		
			
				|  |  |  };
 | 
	
		
			
				|  |  |  /* }}} */
 | 
	
	
		
			
				|  | @@ -1386,9 +1498,16 @@ static PHP_MINIT_FUNCTION(v8js)
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  	/* 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);
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +#ifdef ENABLE_DEBUGGER_SUPPORT
 | 
	
		
			
				|  |  | +	zend_declare_class_constant_long(php_ce_v8js, ZEND_STRL("DEBUG_AUTO_BREAK_NEVER"),	V8JS_DEBUG_AUTO_BREAK_NEVER			TSRMLS_CC);
 | 
	
		
			
				|  |  | +	zend_declare_class_constant_long(php_ce_v8js, ZEND_STRL("DEBUG_AUTO_BREAK_ONCE"),	V8JS_DEBUG_AUTO_BREAK_ONCE			TSRMLS_CC);
 | 
	
		
			
				|  |  | +	zend_declare_class_constant_long(php_ce_v8js, ZEND_STRL("DEBUG_AUTO_BREAK_ALWAYS"),	V8JS_DEBUG_AUTO_BREAK_ALWAYS		TSRMLS_CC);
 | 
	
		
			
				|  |  | +#endif
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |  	/* 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);
 |