Commit 3bbd11c2 authored by adamk's avatar adamk Committed by Commit bot

[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}
parent c0485c18
......@@ -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,
......
......@@ -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) {
......
......@@ -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
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment