[modules] Do path resolution relative to each module file in d8
BUG=v8:1569 Review-Url: https://codereview.chromium.org/2361593002 Cr-Commit-Position: refs/heads/master@{#39646}
This commit is contained in:
parent
c0485c18a3
commit
3bbd11c233
@ -1089,6 +1089,9 @@ class V8_EXPORT Module {
|
||||
*/
|
||||
Local<String> GetModuleRequest(int i) const;
|
||||
|
||||
void SetEmbedderData(Local<Value> data);
|
||||
Local<Value> GetEmbedderData() const;
|
||||
|
||||
typedef MaybeLocal<Module> (*ResolveCallback)(Local<Context> context,
|
||||
Local<String> specifier,
|
||||
Local<Module> referrer,
|
||||
|
10
src/api.cc
10
src/api.cc
@ -1915,6 +1915,16 @@ Local<String> Module::GetModuleRequest(int i) const {
|
||||
return ToApiHandle<String>(i::handle(module_requests->get(i), isolate));
|
||||
}
|
||||
|
||||
void Module::SetEmbedderData(Local<Value> data) {
|
||||
Utils::OpenHandle(this)->set_embedder_data(*Utils::OpenHandle(*data));
|
||||
}
|
||||
|
||||
Local<Value> Module::GetEmbedderData() const {
|
||||
auto self = Utils::OpenHandle(this);
|
||||
return ToApiHandle<Value>(
|
||||
i::handle(self->embedder_data(), self->GetIsolate()));
|
||||
}
|
||||
|
||||
bool Module::Instantiate(Local<Context> v8_context,
|
||||
Module::ResolveCallback callback,
|
||||
Local<Value> callback_data) {
|
||||
|
107
src/d8.cc
107
src/d8.cc
@ -511,9 +511,64 @@ bool Shell::ExecuteString(Isolate* isolate, Local<String> source,
|
||||
return true;
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
bool IsAbsolutePath(const char* path) {
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
// TODO(adamk): This is an incorrect approximation, but should
|
||||
// work for all our test-running cases.
|
||||
return strchr(path, ':') != nullptr;
|
||||
#else
|
||||
return path[0] == '/';
|
||||
#endif
|
||||
}
|
||||
|
||||
std::string GetWorkingDirectory() {
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
char system_buffer[MAX_PATH];
|
||||
// TODO(adamk): Support Unicode paths.
|
||||
DWORD len = GetCurrentDirectoryA(MAX_PATH, system_buffer);
|
||||
CHECK(len > 0);
|
||||
return system_buffer;
|
||||
#else
|
||||
char curdir[PATH_MAX];
|
||||
CHECK_NOT_NULL(getcwd(curdir, PATH_MAX));
|
||||
return curdir;
|
||||
#endif
|
||||
}
|
||||
|
||||
std::string DirName(const std::string& path) {
|
||||
DCHECK(IsAbsolutePath(path.c_str()));
|
||||
size_t last_slash = path.find_last_of("/\\");
|
||||
DCHECK(last_slash != std::string::npos);
|
||||
return path.substr(0, last_slash + 1);
|
||||
}
|
||||
|
||||
MaybeLocal<Module> ResolveModuleCallback(Local<Context> context,
|
||||
Local<String> specifier,
|
||||
Local<Module> referrer,
|
||||
Local<Value> data) {
|
||||
Isolate* isolate = context->GetIsolate();
|
||||
auto module_map = static_cast<std::map<std::string, Global<Module>>*>(
|
||||
External::Cast(*data)->Value());
|
||||
String::Utf8Value specifier_utf8(specifier);
|
||||
CHECK(!IsAbsolutePath(*specifier_utf8));
|
||||
Local<String> dir_name = Local<String>::Cast(referrer->GetEmbedderData());
|
||||
std::string absolute_path = *String::Utf8Value(dir_name);
|
||||
absolute_path.append(*specifier_utf8);
|
||||
auto it = module_map->find(absolute_path);
|
||||
if (it != module_map->end()) {
|
||||
return it->second.Get(isolate);
|
||||
}
|
||||
return MaybeLocal<Module>();
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
MaybeLocal<Module> Shell::FetchModuleTree(
|
||||
Isolate* isolate, const std::string& file_name,
|
||||
std::map<std::string, Global<Module>>* module_map) {
|
||||
DCHECK(IsAbsolutePath(file_name.c_str()));
|
||||
TryCatch try_catch(isolate);
|
||||
try_catch.SetVerbose(true);
|
||||
Local<String> source_text = ReadFile(isolate, file_name.c_str());
|
||||
@ -532,12 +587,24 @@ MaybeLocal<Module> Shell::FetchModuleTree(
|
||||
}
|
||||
module_map->insert(
|
||||
std::make_pair(file_name, Global<Module>(isolate, module)));
|
||||
|
||||
std::string dir_name = DirName(file_name);
|
||||
module->SetEmbedderData(
|
||||
String::NewFromUtf8(isolate, dir_name.c_str(), NewStringType::kNormal)
|
||||
.ToLocalChecked());
|
||||
|
||||
for (int i = 0, length = module->GetModuleRequestsLength(); i < length; ++i) {
|
||||
Local<String> name = module->GetModuleRequest(i);
|
||||
// TODO(adamk): Resolve the imported module to a full path.
|
||||
std::string str = *String::Utf8Value(name);
|
||||
if (!module_map->count(str)) {
|
||||
if (FetchModuleTree(isolate, str, module_map).IsEmpty()) {
|
||||
String::Utf8Value utf8_value(name);
|
||||
std::string absolute_path;
|
||||
if (IsAbsolutePath(*utf8_value)) {
|
||||
absolute_path = *utf8_value;
|
||||
} else {
|
||||
absolute_path = dir_name;
|
||||
absolute_path.append(*utf8_value);
|
||||
}
|
||||
if (!module_map->count(absolute_path)) {
|
||||
if (FetchModuleTree(isolate, absolute_path, module_map).IsEmpty()) {
|
||||
return MaybeLocal<Module>();
|
||||
}
|
||||
}
|
||||
@ -546,32 +613,22 @@ MaybeLocal<Module> Shell::FetchModuleTree(
|
||||
return module;
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
MaybeLocal<Module> ResolveModuleCallback(Local<Context> context,
|
||||
Local<String> specifier,
|
||||
Local<Module> referrer,
|
||||
Local<Value> data) {
|
||||
Isolate* isolate = context->GetIsolate();
|
||||
auto module_map = static_cast<std::map<std::string, Global<Module>>*>(
|
||||
External::Cast(*data)->Value());
|
||||
std::string str_specifier = *String::Utf8Value(specifier);
|
||||
// TODO(adamk): Resolve the specifier using the referrer
|
||||
auto it = module_map->find(str_specifier);
|
||||
if (it != module_map->end()) {
|
||||
return it->second.Get(isolate);
|
||||
}
|
||||
return MaybeLocal<Module>();
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
bool Shell::ExecuteModule(Isolate* isolate, const char* file_name) {
|
||||
HandleScope handle_scope(isolate);
|
||||
|
||||
std::string absolute_path;
|
||||
if (IsAbsolutePath(file_name)) {
|
||||
absolute_path = file_name;
|
||||
} else {
|
||||
absolute_path = GetWorkingDirectory();
|
||||
absolute_path.push_back('/');
|
||||
absolute_path.append(file_name);
|
||||
}
|
||||
|
||||
Local<Module> root_module;
|
||||
std::map<std::string, Global<Module>> module_map;
|
||||
if (!FetchModuleTree(isolate, file_name, &module_map).ToLocal(&root_module)) {
|
||||
if (!FetchModuleTree(isolate, absolute_path, &module_map)
|
||||
.ToLocal(&root_module)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -1764,6 +1764,7 @@ Handle<Module> Factory::NewModule(Handle<SharedFunctionInfo> code) {
|
||||
module->set_exports(*exports);
|
||||
module->set_requested_modules(*requested_modules);
|
||||
module->set_flags(0);
|
||||
module->set_embedder_data(isolate()->heap()->undefined_value());
|
||||
return module;
|
||||
}
|
||||
|
||||
|
@ -927,6 +927,7 @@ void Module::ModuleVerify() {
|
||||
exports()->ObjectVerify();
|
||||
requested_modules()->ObjectVerify();
|
||||
VerifySmiField(kFlagsOffset);
|
||||
embedder_data()->ObjectVerify();
|
||||
// TODO(neis): Check more.
|
||||
}
|
||||
|
||||
|
@ -5717,6 +5717,7 @@ ACCESSORS(Module, exports, ObjectHashTable, kExportsOffset)
|
||||
ACCESSORS(Module, requested_modules, FixedArray, kRequestedModulesOffset)
|
||||
SMI_ACCESSORS(Module, flags, kFlagsOffset)
|
||||
BOOL_ACCESSORS(Module, flags, evaluated, kEvaluatedBit)
|
||||
ACCESSORS(Module, embedder_data, Object, kEmbedderDataOffset)
|
||||
|
||||
ACCESSORS(AccessorPair, getter, Object, kGetterOffset)
|
||||
ACCESSORS(AccessorPair, setter, Object, kSetterOffset)
|
||||
|
@ -1172,6 +1172,7 @@ void Module::ModulePrint(std::ostream& os) { // NOLINT
|
||||
os << "\n - exports: " << Brief(exports());
|
||||
os << "\n - requested_modules: " << Brief(requested_modules());
|
||||
os << "\n - evaluated: " << evaluated();
|
||||
os << "\n - embedder_data: " << Brief(embedder_data());
|
||||
os << "\n";
|
||||
}
|
||||
|
||||
|
@ -7945,6 +7945,9 @@ class Module : public Struct {
|
||||
// Storage for [[Evaluated]]
|
||||
DECL_INT_ACCESSORS(flags)
|
||||
|
||||
// Embedder-specified data
|
||||
DECL_ACCESSORS(embedder_data, Object)
|
||||
|
||||
static void CreateExport(Handle<Module> module, Handle<FixedArray> names);
|
||||
static Handle<Object> LoadExport(Handle<Module> module, Handle<String> name);
|
||||
static void StoreExport(Handle<Module> module, Handle<String> name,
|
||||
@ -7957,7 +7960,8 @@ class Module : public Struct {
|
||||
static const int kExportsOffset = kCodeOffset + kPointerSize;
|
||||
static const int kRequestedModulesOffset = kExportsOffset + kPointerSize;
|
||||
static const int kFlagsOffset = kRequestedModulesOffset + kPointerSize;
|
||||
static const int kSize = kFlagsOffset + kPointerSize;
|
||||
static const int kEmbedderDataOffset = kFlagsOffset + kPointerSize;
|
||||
static const int kSize = kEmbedderDataOffset + kPointerSize;
|
||||
|
||||
private:
|
||||
enum { kEvaluatedBit };
|
||||
|
@ -6,6 +6,8 @@
|
||||
|
||||
#include "test/cctest/cctest.h"
|
||||
|
||||
namespace {
|
||||
|
||||
using v8::Context;
|
||||
using v8::HandleScope;
|
||||
using v8::Isolate;
|
||||
@ -17,17 +19,18 @@ using v8::ScriptOrigin;
|
||||
using v8::String;
|
||||
using v8::Value;
|
||||
|
||||
static MaybeLocal<Module> AlwaysEmptyResolveCallback(Local<Context> context,
|
||||
Local<String> specifier,
|
||||
Local<Module> referrer,
|
||||
Local<Value> data) {
|
||||
MaybeLocal<Module> AlwaysEmptyResolveCallback(Local<Context> context,
|
||||
Local<String> specifier,
|
||||
Local<Module> referrer,
|
||||
Local<Value> data) {
|
||||
return MaybeLocal<Module>();
|
||||
}
|
||||
|
||||
static int g_count = 0;
|
||||
static MaybeLocal<Module> FailOnSecondCallResolveCallback(
|
||||
Local<Context> context, Local<String> specifier, Local<Module> referrer,
|
||||
Local<Value> data) {
|
||||
MaybeLocal<Module> FailOnSecondCallResolveCallback(Local<Context> context,
|
||||
Local<String> specifier,
|
||||
Local<Module> referrer,
|
||||
Local<Value> data) {
|
||||
if (g_count++ > 0) return MaybeLocal<Module>();
|
||||
Local<String> source_text = v8_str("");
|
||||
ScriptOrigin origin(v8_str("module.js"));
|
||||
@ -89,3 +92,20 @@ TEST(ModuleEvaluation) {
|
||||
CHECK(!module->Evaluate(env.local()).IsEmpty());
|
||||
ExpectInt32("Object.expando", 10);
|
||||
}
|
||||
|
||||
TEST(EmbedderData) {
|
||||
Isolate* isolate = CcTest::isolate();
|
||||
HandleScope scope(isolate);
|
||||
LocalContext env;
|
||||
|
||||
Local<String> source_text = v8_str("");
|
||||
ScriptOrigin origin(v8_str("file.js"));
|
||||
ScriptCompiler::Source source(source_text, origin);
|
||||
Local<Module> module =
|
||||
ScriptCompiler::CompileModule(isolate, &source).ToLocalChecked();
|
||||
CHECK(module->GetEmbedderData()->IsUndefined());
|
||||
module->SetEmbedderData(v8_num(42));
|
||||
CHECK_EQ(42, Local<v8::Int32>::Cast(module->GetEmbedderData())->Value());
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
|
Loading…
Reference in New Issue
Block a user