summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRyan Dahl <ry@tinyclouds.org>2019-01-06 16:32:21 -0500
committerGitHub <noreply@github.com>2019-01-06 16:32:21 -0500
commit1b7938e3aa0ba1fb7ad7d6699f01cbf3c8a4196c (patch)
tree25b63f93af0d5e9e571a1fd3c8c4b02191706dcf
parentf37d67e80933bc437fbd29092108eaf2deeee383 (diff)
Add libdeno.builtinModules (#1463)
This is needed to support builtin modules like import { open } from "deno"
-rw-r--r--js/libdeno.ts2
-rw-r--r--libdeno/binding.cc62
-rw-r--r--libdeno/internal.h14
-rw-r--r--libdeno/libdeno_test.cc25
4 files changed, 100 insertions, 3 deletions
diff --git a/js/libdeno.ts b/js/libdeno.ts
index e67a021c7..cbd9a60f0 100644
--- a/js/libdeno.ts
+++ b/js/libdeno.ts
@@ -18,6 +18,8 @@ interface Libdeno {
shared: ArrayBuffer;
+ builtinModules: { [s: string]: object };
+
setGlobalErrorHandler: (
handler: (
message: string,
diff --git a/libdeno/binding.cc b/libdeno/binding.cc
index f05d20757..da3ce198d 100644
--- a/libdeno/binding.cc
+++ b/libdeno/binding.cc
@@ -323,6 +323,23 @@ void Send(const v8::FunctionCallbackInfo<v8::Value>& args) {
}
}
+v8::Local<v8::Object> DenoIsolate::GetBuiltinModules() {
+ v8::EscapableHandleScope handle_scope(isolate_);
+ if (builtin_modules_.IsEmpty()) {
+ builtin_modules_.Reset(isolate_, v8::Object::New(isolate_));
+ }
+ return handle_scope.Escape(builtin_modules_.Get(isolate_));
+}
+
+void BuiltinModules(v8::Local<v8::Name> property,
+ const v8::PropertyCallbackInfo<v8::Value>& info) {
+ v8::Isolate* isolate = info.GetIsolate();
+ DenoIsolate* d = FromIsolate(isolate);
+ DCHECK_EQ(d->isolate_, isolate);
+ v8::Locker locker(d->isolate_);
+ info.GetReturnValue().Set(d->GetBuiltinModules());
+}
+
void Shared(v8::Local<v8::Name> property,
const v8::PropertyCallbackInfo<v8::Value>& info) {
v8::Isolate* isolate = info.GetIsolate();
@@ -408,6 +425,44 @@ v8::MaybeLocal<v8::Module> ResolveCallback(v8::Local<v8::Context> context,
v8::EscapableHandleScope handle_scope(isolate);
v8::Context::Scope context_scope(context);
+ v8::String::Utf8Value specifier_utf8val(isolate, specifier);
+ const char* specifier_cstr = ToCString(specifier_utf8val);
+
+ auto builtin_modules = d->GetBuiltinModules();
+ bool has_builtin = builtin_modules->Has(context, specifier).ToChecked();
+ if (has_builtin) {
+ auto val = builtin_modules->Get(context, specifier).ToLocalChecked();
+ CHECK(val->IsObject());
+ auto obj = val->ToObject(isolate);
+
+ // In order to export obj as a module, we must iterate over its properties
+ // and export them each individually.
+ // TODO Find a better way to do this.
+ std::string src = "let globalEval = eval\nlet g = globalEval('this');\n";
+ auto names = obj->GetOwnPropertyNames(context).ToLocalChecked();
+ for (uint32_t i = 0; i < names->Length(); i++) {
+ auto name = names->Get(context, i).ToLocalChecked();
+ v8::String::Utf8Value name_utf8val(isolate, name);
+ const char* name_cstr = ToCString(name_utf8val);
+ // TODO use format string.
+ src.append("export const ");
+ src.append(name_cstr);
+ src.append(" = g.libdeno.builtinModules.");
+ src.append(specifier_cstr);
+ src.append(".");
+ src.append(name_cstr);
+ src.append(";\n");
+ }
+ auto export_str = v8_str(src.c_str(), true);
+
+ auto module =
+ CompileModule(context, specifier_cstr, export_str).ToLocalChecked();
+ auto maybe_ok = module->InstantiateModule(context, ResolveCallback);
+ CHECK(!maybe_ok.IsNothing());
+
+ return handle_scope.Escape(module);
+ }
+
int ref_id = referrer->GetIdentityHash();
std::string referrer_filename = d->module_filename_map_[ref_id];
@@ -439,7 +494,7 @@ void DenoIsolate::ResolveOk(const char* filename, const char* source) {
v8::HandleScope handle_scope(isolate_);
auto context = context_.Get(isolate_);
v8::TryCatch try_catch(isolate_);
- auto maybe_module = CompileModule(context, filename, v8_str(source));
+ auto maybe_module = CompileModule(context, filename, v8_str(source, true));
if (maybe_module.IsEmpty()) {
DCHECK(try_catch.HasCaught());
HandleException(context, try_catch.Exception());
@@ -545,6 +600,11 @@ void InitializeContext(v8::Isolate* isolate, v8::Local<v8::Context> context) {
CHECK(deno_val->SetAccessor(context, deno::v8_str("shared"), Shared)
.FromJust());
+
+ CHECK(
+ deno_val
+ ->SetAccessor(context, deno::v8_str("builtinModules"), BuiltinModules)
+ .FromJust());
}
void DenoIsolate::AddIsolate(v8::Isolate* isolate) {
diff --git a/libdeno/internal.h b/libdeno/internal.h
index d8316ce6b..454b3e2e4 100644
--- a/libdeno/internal.h
+++ b/libdeno/internal.h
@@ -45,6 +45,8 @@ class DenoIsolate {
void ResolveOk(const char* filename, const char* source);
void ClearModules();
+ v8::Local<v8::Object> GetBuiltinModules();
+
v8::Isolate* isolate_;
v8::ArrayBuffer::Allocator* array_buffer_allocator_;
deno_buf shared_;
@@ -63,6 +65,8 @@ class DenoIsolate {
// Set by deno_resolve_ok
v8::Persistent<v8::Module> resolve_module_;
+ v8::Persistent<v8::Object> builtin_modules_;
+
v8::Persistent<v8::Context> context_;
std::map<int32_t, v8::Persistent<v8::Value>> async_data_map_;
std::map<int, v8::Persistent<v8::Value>> pending_promise_map_;
@@ -108,9 +112,15 @@ void Recv(const v8::FunctionCallbackInfo<v8::Value>& args);
void Send(const v8::FunctionCallbackInfo<v8::Value>& args);
void Shared(v8::Local<v8::Name> property,
const v8::PropertyCallbackInfo<v8::Value>& info);
+void BuiltinModules(v8::Local<v8::Name> property,
+ const v8::PropertyCallbackInfo<v8::Value>& info);
static intptr_t external_references[] = {
- reinterpret_cast<intptr_t>(Print), reinterpret_cast<intptr_t>(Recv),
- reinterpret_cast<intptr_t>(Send), reinterpret_cast<intptr_t>(Shared), 0};
+ reinterpret_cast<intptr_t>(Print),
+ reinterpret_cast<intptr_t>(Recv),
+ reinterpret_cast<intptr_t>(Send),
+ reinterpret_cast<intptr_t>(Shared),
+ reinterpret_cast<intptr_t>(BuiltinModules),
+ 0};
static const deno_buf empty_buf = {nullptr, 0, nullptr, 0};
diff --git a/libdeno/libdeno_test.cc b/libdeno/libdeno_test.cc
index 8b95c1831..6ee8979ee 100644
--- a/libdeno/libdeno_test.cc
+++ b/libdeno/libdeno_test.cc
@@ -306,3 +306,28 @@ TEST(LibDenoTest, ModuleSnapshot) {
delete[] test_snapshot.data_ptr;
}
+
+TEST(LibDenoTest, BuiltinModules) {
+ static int count = 0;
+ auto resolve_cb = [](void* user_data, const char* specifier,
+ const char* referrer) {
+ EXPECT_STREQ(specifier, "b.js");
+ EXPECT_STREQ(referrer, "c.js");
+ count++;
+ auto d = reinterpret_cast<Deno*>(user_data);
+ deno_resolve_ok(d, "b.js", mod_b);
+ };
+ Deno* d = deno_new(deno_config{0, empty, empty, nullptr, resolve_cb});
+ EXPECT_TRUE(deno_execute(
+ d, d, "setup.js", "libdeno.builtinModules['deno'] = { foo: 'bar' }; \n"));
+ EXPECT_EQ(count, 0);
+ EXPECT_TRUE(
+ deno_execute_mod(d, d, "c.js",
+ "import { retb } from 'b.js'\n"
+ "import * as deno from 'deno'\n"
+ "if (retb() != 'b') throw Error('retb');\n"
+ // " libdeno.print('deno ' + JSON.stringify(deno));\n"
+ "if (deno.foo != 'bar') throw Error('foo');\n"));
+ EXPECT_EQ(count, 1);
+ deno_delete(d);
+}