|
@@ -8,6 +8,7 @@
|
|
|
+----------------------------------------------------------------------+
|
|
|
| Author: Jani Taskinen <[email protected]> |
|
|
|
| Author: Patrick Reilly <[email protected]> |
|
|
|
+ | Author: Stefan Siegl <[email protected]> |
|
|
|
+----------------------------------------------------------------------+
|
|
|
*/
|
|
|
|
|
@@ -91,10 +92,20 @@ static void v8js_dumper(v8::Isolate *isolate, v8::Local<v8::Value> var, int leve
|
|
|
}
|
|
|
|
|
|
v8::TryCatch try_catch; /* object.toString() can throw an exception */
|
|
|
- v8::Local<v8::String> details = var->ToDetailString();
|
|
|
- if (try_catch.HasCaught()) {
|
|
|
- details = V8JS_SYM("<toString threw exception>");
|
|
|
+ v8::Local<v8::String> details;
|
|
|
+
|
|
|
+ if(var->IsRegExp()) {
|
|
|
+ v8::RegExp *re = v8::RegExp::Cast(*var);
|
|
|
+ details = re->GetSource();
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ details = var->ToDetailString();
|
|
|
+
|
|
|
+ if (try_catch.HasCaught()) {
|
|
|
+ details = V8JS_SYM("<toString threw exception>");
|
|
|
+ }
|
|
|
}
|
|
|
+
|
|
|
v8::String::Utf8Value str(details);
|
|
|
const char *valstr = ToCString(str);
|
|
|
size_t valstr_len = details->ToString()->Utf8Length();
|
|
@@ -112,7 +123,7 @@ static void v8js_dumper(v8::Isolate *isolate, v8::Local<v8::Value> var, int leve
|
|
|
}
|
|
|
else if (var->IsRegExp())
|
|
|
{
|
|
|
- php_printf("regexp(%s)\n", valstr);
|
|
|
+ php_printf("regexp(/%s/)\n", valstr);
|
|
|
}
|
|
|
else if (var->IsArray())
|
|
|
{
|
|
@@ -207,12 +218,100 @@ V8JS_METHOD(require)
|
|
|
}
|
|
|
|
|
|
v8::String::Utf8Value module_id_v8(info[0]);
|
|
|
-
|
|
|
const char *module_id = ToCString(module_id_v8);
|
|
|
- char *normalised_path = (char *)emalloc(PATH_MAX);
|
|
|
- char *module_name = (char *)emalloc(PATH_MAX);
|
|
|
+ char *normalised_path, *module_name;
|
|
|
+
|
|
|
+ if (Z_TYPE(c->module_normaliser) == IS_NULL) {
|
|
|
+ // No custom normalisation routine registered, use internal one
|
|
|
+ normalised_path = (char *)emalloc(PATH_MAX);
|
|
|
+ module_name = (char *)emalloc(PATH_MAX);
|
|
|
|
|
|
- v8js_commonjs_normalise_identifier(c->modules_base.back(), module_id, normalised_path, module_name);
|
|
|
+ v8js_commonjs_normalise_identifier(c->modules_base.back(), module_id, normalised_path, module_name);
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ // Call custom normaliser
|
|
|
+ int call_result;
|
|
|
+ zval params[2];
|
|
|
+ zval normaliser_result;
|
|
|
+
|
|
|
+ zend_try {
|
|
|
+ {
|
|
|
+ isolate->Exit();
|
|
|
+ v8::Unlocker unlocker(isolate);
|
|
|
+
|
|
|
+ ZVAL_STRING(¶ms[0], c->modules_base.back());
|
|
|
+ ZVAL_STRING(¶ms[1], module_id);
|
|
|
+
|
|
|
+ call_result = call_user_function_ex(EG(function_table), NULL, &c->module_normaliser,
|
|
|
+ &normaliser_result, 2, params, 0, NULL TSRMLS_CC);
|
|
|
+ }
|
|
|
+
|
|
|
+ isolate->Enter();
|
|
|
+
|
|
|
+ if (call_result == FAILURE) {
|
|
|
+ info.GetReturnValue().Set(isolate->ThrowException(V8JS_SYM("Module normaliser callback failed")));
|
|
|
+ }
|
|
|
+ }
|
|
|
+ zend_catch {
|
|
|
+ v8js_terminate_execution(isolate);
|
|
|
+ V8JSG(fatal_error_abort) = 1;
|
|
|
+ call_result = FAILURE;
|
|
|
+ }
|
|
|
+ zend_end_try();
|
|
|
+
|
|
|
+ zval_dtor(¶ms[0]);
|
|
|
+ zval_dtor(¶ms[1]);
|
|
|
+
|
|
|
+ if(call_result == FAILURE) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ // Check if an exception was thrown
|
|
|
+ if (EG(exception)) {
|
|
|
+ // Clear the PHP exception and throw it in V8 instead
|
|
|
+ zend_clear_exception(TSRMLS_C);
|
|
|
+ info.GetReturnValue().Set(isolate->ThrowException(V8JS_SYM("Module normaliser callback exception")));
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (Z_TYPE(normaliser_result) != IS_ARRAY) {
|
|
|
+ zval_dtor(&normaliser_result);
|
|
|
+ info.GetReturnValue().Set(isolate->ThrowException(V8JS_SYM("Module normaliser didn't return an array")));
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ HashTable *ht = HASH_OF(&normaliser_result);
|
|
|
+ int num_elements = zend_hash_num_elements(ht);
|
|
|
+
|
|
|
+ if(num_elements != 2) {
|
|
|
+ zval_dtor(&normaliser_result);
|
|
|
+ info.GetReturnValue().Set(isolate->ThrowException(V8JS_SYM("Module normaliser expected to return array of 2 strings")));
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ zval *data;
|
|
|
+ ulong index = 0;
|
|
|
+ HashPosition pos;
|
|
|
+
|
|
|
+ ZEND_HASH_FOREACH_VAL(ht, data) {
|
|
|
+ if (Z_TYPE_P(data) != IS_STRING) {
|
|
|
+ convert_to_string(data);
|
|
|
+ }
|
|
|
+
|
|
|
+ switch(index++) {
|
|
|
+ case 0: // normalised path
|
|
|
+ normalised_path = estrndup(Z_STRVAL_P(data), Z_STRLEN_P(data));
|
|
|
+ break;
|
|
|
+
|
|
|
+ case 1: // normalised module id
|
|
|
+ module_name = estrndup(Z_STRVAL_P(data), Z_STRLEN_P(data));
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ ZEND_HASH_FOREACH_END();
|
|
|
+
|
|
|
+ zval_dtor(&normaliser_result);
|
|
|
+ }
|
|
|
|
|
|
char *normalised_module_id = (char *)emalloc(strlen(normalised_path)+1+strlen(module_name)+1);
|
|
|
*normalised_module_id = 0;
|
|
@@ -252,19 +351,38 @@ V8JS_METHOD(require)
|
|
|
// Callback to PHP to load the module code
|
|
|
|
|
|
zval module_code;
|
|
|
-
|
|
|
+ int call_result;
|
|
|
zval params[1];
|
|
|
- ZVAL_STRING(¶ms[0], normalised_module_id);
|
|
|
|
|
|
- if (FAILURE == call_user_function_ex(EG(function_table), NULL, &c->module_loader, &module_code, 1, params, 0, NULL TSRMLS_CC)) {
|
|
|
- zval_dtor(¶ms[0]);
|
|
|
+ zend_try {
|
|
|
+ {
|
|
|
+ isolate->Exit();
|
|
|
+ v8::Unlocker unlocker(isolate);
|
|
|
+
|
|
|
+ ZVAL_STRING(¶ms[0], normalised_module_id);
|
|
|
+ call_result = call_user_function_ex(EG(function_table), NULL, &c->module_loader, &module_code, 1, params, 0, NULL TSRMLS_CC);
|
|
|
+ }
|
|
|
+
|
|
|
+ isolate->Enter();
|
|
|
+
|
|
|
+ if (call_result == FAILURE) {
|
|
|
+ info.GetReturnValue().Set(isolate->ThrowException(V8JS_SYM("Module loader callback failed")));
|
|
|
+ }
|
|
|
+ }
|
|
|
+ zend_catch {
|
|
|
+ v8js_terminate_execution(isolate);
|
|
|
+ V8JSG(fatal_error_abort) = 1;
|
|
|
+ call_result = FAILURE;
|
|
|
+ }
|
|
|
+ zend_end_try();
|
|
|
+
|
|
|
+ zval_dtor(¶ms[0]);
|
|
|
+
|
|
|
+ if (call_result == FAILURE) {
|
|
|
efree(normalised_module_id);
|
|
|
efree(normalised_path);
|
|
|
-
|
|
|
- info.GetReturnValue().Set(isolate->ThrowException(V8JS_SYM("Module loader callback failed")));
|
|
|
return;
|
|
|
}
|
|
|
- zval_dtor(¶ms[0]);
|
|
|
|
|
|
// Check if an exception was thrown
|
|
|
if (EG(exception)) {
|
|
@@ -282,19 +400,10 @@ V8JS_METHOD(require)
|
|
|
convert_to_string(&module_code);
|
|
|
}
|
|
|
|
|
|
- // Check that some code has been returned
|
|
|
- if (Z_STRLEN(module_code) == 0) {
|
|
|
- zval_dtor(&module_code);
|
|
|
- efree(normalised_module_id);
|
|
|
- efree(normalised_path);
|
|
|
-
|
|
|
- info.GetReturnValue().Set(isolate->ThrowException(V8JS_SYM("Module loader callback did not return code")));
|
|
|
- return;
|
|
|
- }
|
|
|
-
|
|
|
// Create a template for the global object and set the built-in global functions
|
|
|
v8::Handle<v8::ObjectTemplate> global = v8::ObjectTemplate::New();
|
|
|
global->Set(V8JS_SYM("print"), v8::FunctionTemplate::New(isolate, V8JS_MN(print)), v8::ReadOnly);
|
|
|
+ global->Set(V8JS_SYM("var_dump"), v8::FunctionTemplate::New(isolate, V8JS_MN(var_dump)), v8::ReadOnly);
|
|
|
global->Set(V8JS_SYM("sleep"), v8::FunctionTemplate::New(isolate, V8JS_MN(sleep)), v8::ReadOnly);
|
|
|
global->Set(V8JS_SYM("require"), v8::FunctionTemplate::New(isolate, V8JS_MN(require), v8::External::New(isolate, c)), v8::ReadOnly);
|
|
|
|
|
@@ -323,7 +432,7 @@ V8JS_METHOD(require)
|
|
|
// Enter the module context
|
|
|
v8::Context::Scope scope(context);
|
|
|
// Set script identifier
|
|
|
- v8::Local<v8::String> sname = V8JS_SYM("require");
|
|
|
+ v8::Local<v8::String> sname = V8JS_STR(normalised_module_id);
|
|
|
|
|
|
v8::Local<v8::String> source = V8JS_ZSTR(Z_STR(module_code));
|
|
|
zval_ptr_dtor(&module_code);
|