Skip to content

Commit 6fc0c21

Browse files
authored
Merge pull request #352 from stesie/issue-349
Issue 349
2 parents cf5e638 + 313ad1e commit 6fc0c21

File tree

5 files changed

+107
-16
lines changed

5 files changed

+107
-16
lines changed

Commandfile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ command 'clean',
2626
command 'build',
2727
description: 'executes "make"',
2828
script: <<-eof
29-
cd /data/build; `which gmake || which make`
29+
cd /data/build; `which gmake || which make` -j4
3030
eof
3131

3232
command 'test',

tests/issue_349_basic.phpt

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
--TEST--
2+
Test V8Js::setModuleNormaliser : Custom normalisation #005
3+
--SKIPIF--
4+
<?php require_once(dirname(__FILE__) . '/skipif.inc'); ?>
5+
--FILE--
6+
<?php
7+
8+
$v8 = new V8Js();
9+
10+
$v8->setModuleNormaliser(function ($base, $moduleName) {
11+
var_dump($base, $moduleName);
12+
if ($base == '' && $moduleName == './tags') {
13+
return ['./tags', 'index.js'];
14+
}
15+
if ($base == './tags' && $moduleName == './if.js') {
16+
return ['./tags', 'if.js'];
17+
}
18+
return [$base, $moduleName];
19+
});
20+
21+
$v8->setModuleLoader(function ($moduleName) {
22+
print("setModuleLoader called for ".$moduleName."\n");
23+
switch ($moduleName) {
24+
case './app.js':
25+
return "require('./tags')";
26+
case './tags/index.js':
27+
return "require('./if.js')";
28+
}
29+
});
30+
31+
$v8->executeString("require('./app.js')");
32+
33+
echo "------------------------------------------------\n";
34+
35+
$v8 = new V8Js();
36+
37+
$v8->setModuleNormaliser(function ($base, $moduleName) {
38+
var_dump($base, $moduleName);
39+
if ($base == '' && $moduleName == './tags') {
40+
return ['./tags', 'index.js'];
41+
}
42+
if ($base == './tags' && $moduleName == './if.js') {
43+
return ['./tags', 'if.js'];
44+
}
45+
return [$base, $moduleName];
46+
});
47+
48+
$v8->setModuleLoader(function ($moduleName) {
49+
print("setModuleLoader called for ".$moduleName."\n");
50+
switch ($moduleName) {
51+
case './app.js':
52+
return "require('./tags')()"; // different
53+
case './tags/index.js':
54+
return "module.exports = function() {require('./if.js')}"; // different
55+
}
56+
});
57+
58+
$v8->executeString("require('./app.js')");
59+
60+
?>
61+
===EOF===
62+
--EXPECT--
63+
string(0) ""
64+
string(8) "./app.js"
65+
setModuleLoader called for ./app.js
66+
string(0) ""
67+
string(6) "./tags"
68+
setModuleLoader called for ./tags/index.js
69+
string(6) "./tags"
70+
string(7) "./if.js"
71+
setModuleLoader called for ./tags/if.js
72+
------------------------------------------------
73+
string(0) ""
74+
string(8) "./app.js"
75+
setModuleLoader called for ./app.js
76+
string(0) ""
77+
string(6) "./tags"
78+
setModuleLoader called for ./tags/index.js
79+
string(6) "./tags"
80+
string(7) "./if.js"
81+
setModuleLoader called for ./tags/if.js
82+
===EOF===

v8js_class.cc

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -200,7 +200,6 @@ static void v8js_free_storage(zend_object *object) /* {{{ */
200200
}
201201

202202
c->modules_stack.~vector();
203-
c->modules_base.~vector();
204203

205204
zval_ptr_dtor(&c->zval_snapshot_blob);
206205

@@ -226,7 +225,6 @@ static zend_object* v8js_new(zend_class_entry *ce) /* {{{ */
226225
new(&c->array_tmpl) v8::Persistent<v8::FunctionTemplate>();
227226

228227
new(&c->modules_stack) std::vector<char*>();
229-
new(&c->modules_base) std::vector<char*>();
230228
new(&c->modules_loaded) std::map<char *, v8js_persistent_value_t, cmp_str>;
231229

232230
new(&c->template_cache) std::map<const zend_string *,v8js_function_tmpl_t>();

v8js_class.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,6 @@ struct v8js_ctx {
5757
zval module_loader;
5858

5959
std::vector<char *> modules_stack;
60-
std::vector<char *> modules_base;
6160
std::map<char *, v8js_persistent_value_t, cmp_str> modules_loaded;
6261
std::map<const zend_string *,v8js_function_tmpl_t> template_cache;
6362

v8js_methods.cc

Lines changed: 24 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -205,10 +205,10 @@ V8JS_METHOD(var_dump) /* {{{ */
205205
V8JS_METHOD(require)
206206
{
207207
v8::Isolate *isolate = info.GetIsolate();
208+
v8js_ctx *c = (v8js_ctx *) isolate->GetData(0);
208209

209-
// Get the extension context
210-
v8::Local<v8::External> data = v8::Local<v8::External>::Cast(info.Data());
211-
v8js_ctx *c = static_cast<v8js_ctx*>(data->Value());
210+
v8::String::Utf8Value module_base(info.Data());
211+
const char *module_base_cstr = ToCString(module_base);
212212

213213
// Check that we have a module loader
214214
if(Z_TYPE(c->module_loader) == IS_NULL) {
@@ -225,7 +225,7 @@ V8JS_METHOD(require)
225225
normalised_path = (char *)emalloc(PATH_MAX);
226226
module_name = (char *)emalloc(PATH_MAX);
227227

228-
v8js_commonjs_normalise_identifier(c->modules_base.back(), module_id, normalised_path, module_name);
228+
v8js_commonjs_normalise_identifier(module_base_cstr, module_id, normalised_path, module_name);
229229
}
230230
else {
231231
// Call custom normaliser
@@ -238,7 +238,7 @@ V8JS_METHOD(require)
238238
isolate->Exit();
239239
v8::Unlocker unlocker(isolate);
240240

241-
ZVAL_STRING(&params[0], c->modules_base.back());
241+
ZVAL_STRING(&params[0], module_base_cstr);
242242
ZVAL_STRING(&params[1], module_id);
243243

244244
call_result = call_user_function_ex(EG(function_table), NULL, &c->module_normaliser,
@@ -445,7 +445,7 @@ V8JS_METHOD(require)
445445
v8::Local<v8::String> source = V8JS_ZSTR(Z_STR(module_code));
446446
zval_ptr_dtor(&module_code);
447447

448-
source = v8::String::Concat(V8JS_SYM("(function (exports, module) {"), source);
448+
source = v8::String::Concat(V8JS_SYM("(function (exports, module, require) {"), source);
449449
source = v8::String::Concat(source, V8JS_SYM("\n});"));
450450

451451
// Create and compile script
@@ -459,9 +459,19 @@ V8JS_METHOD(require)
459459
return;
460460
}
461461

462+
v8::Local<v8::String> base_path = V8JS_STR(normalised_path);
463+
v8::MaybeLocal<v8::Function> require_fn = v8::FunctionTemplate::New(isolate, V8JS_MN(require), base_path)->GetFunction();
464+
465+
if (require_fn.IsEmpty()) {
466+
efree(normalised_path);
467+
efree(normalised_module_id);
468+
info.GetReturnValue().Set(isolate->ThrowException(V8JS_SYM("Failed to create require method")));
469+
return;
470+
}
471+
472+
462473
// Add this module and path to the stack
463474
c->modules_stack.push_back(normalised_module_id);
464-
c->modules_base.push_back(normalised_path);
465475

466476
// Run script to evaluate closure
467477
v8::Local<v8::Value> module_function = script->Run();
@@ -474,20 +484,22 @@ V8JS_METHOD(require)
474484
module->Set(V8JS_SYM("exports"), exports);
475485

476486
if (module_function->IsFunction()) {
477-
v8::Local<v8::Value> *jsArgv = static_cast<v8::Local<v8::Value> *>(alloca(2 * sizeof(v8::Local<v8::Value>)));
487+
v8::Local<v8::Value> *jsArgv = static_cast<v8::Local<v8::Value> *>(alloca(3 * sizeof(v8::Local<v8::Value>)));
478488
new(&jsArgv[0]) v8::Local<v8::Value>;
479489
jsArgv[0] = exports;
480490

481491
new(&jsArgv[1]) v8::Local<v8::Value>;
482492
jsArgv[1] = module;
483493

494+
new(&jsArgv[2]) v8::Local<v8::Value>;
495+
jsArgv[2] = require_fn.ToLocalChecked();
496+
484497
// actually call the module
485-
v8::Local<v8::Function>::Cast(module_function)->Call(exports, 2, jsArgv);
498+
v8::Local<v8::Function>::Cast(module_function)->Call(exports, 3, jsArgv);
486499
}
487500

488501
// Remove this module and path from the stack
489502
c->modules_stack.pop_back();
490-
c->modules_base.pop_back();
491503

492504
efree(normalised_path);
493505

@@ -532,8 +544,8 @@ void v8js_register_methods(v8::Local<v8::ObjectTemplate> global, v8js_ctx *c) /*
532544
global->Set(V8JS_SYM("print"), v8::FunctionTemplate::New(isolate, V8JS_MN(print)), v8::ReadOnly);
533545
global->Set(V8JS_SYM("var_dump"), v8::FunctionTemplate::New(isolate, V8JS_MN(var_dump)), v8::ReadOnly);
534546

535-
c->modules_base.push_back("");
536-
global->Set(V8JS_SYM("require"), v8::FunctionTemplate::New(isolate, V8JS_MN(require), v8::External::New(isolate, c)), v8::ReadOnly);
547+
v8::Local<v8::String> base_path = V8JS_STRL("", 0);
548+
global->Set(V8JS_SYM("require"), v8::FunctionTemplate::New(isolate, V8JS_MN(require), base_path), v8::ReadOnly);
537549
}
538550
/* }}} */
539551

0 commit comments

Comments
 (0)