Add deno_config struct for isolate creation. (#1277)

In preperation for adding other callbacks to libdeno.
This commit is contained in:
Ryan Dahl 2018-12-04 15:06:20 -08:00 committed by GitHub
parent 30420ad317
commit d70b04c6d7
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 140 additions and 129 deletions

View file

@ -13,8 +13,8 @@
extern "C" {
Deno* deno_new(deno_buf snapshot, deno_buf shared, deno_recv_cb cb) {
deno::DenoIsolate* d = new deno::DenoIsolate(snapshot, cb, shared);
Deno* deno_new(deno_buf snapshot, deno_config config) {
deno::DenoIsolate* d = new deno::DenoIsolate(snapshot, config);
v8::Isolate::CreateParams params;
params.array_buffer_allocator = d->array_buffer_allocator_;
params.external_references = deno::external_references;
@ -46,12 +46,11 @@ Deno* deno_new(deno_buf snapshot, deno_buf shared, deno_recv_cb cb) {
return reinterpret_cast<Deno*>(d);
}
Deno* deno_new_snapshotter(deno_buf shared, deno_recv_cb cb,
const char* js_filename, const char* js_source,
const char* source_map) {
Deno* deno_new_snapshotter(deno_config config, const char* js_filename,
const char* js_source, const char* source_map) {
auto* creator = new v8::SnapshotCreator(deno::external_references);
auto* isolate = creator->GetIsolate();
auto* d = new deno::DenoIsolate(deno::empty_buf, cb, shared);
auto* d = new deno::DenoIsolate(deno::empty_buf, config);
d->snapshot_creator_ = creator;
d->AddIsolate(isolate);
{
@ -100,10 +99,10 @@ const char* deno_last_exception(Deno* d_) {
return d->last_exception_.c_str();
}
int deno_execute(Deno* d_, void* user_data_, const char* js_filename,
int deno_execute(Deno* d_, void* user_data, const char* js_filename,
const char* js_source) {
auto* d = unwrap(d_);
deno::UserDataScope user_data_scope(d, user_data_);
deno::UserDataScope user_data_scope(d, user_data);
auto* isolate = d->isolate_;
v8::Locker locker(isolate);
v8::Isolate::Scope isolate_scope(isolate);
@ -112,7 +111,7 @@ int deno_execute(Deno* d_, void* user_data_, const char* js_filename,
return deno::Execute(context, js_filename, js_source) ? 1 : 0;
}
int deno_respond(Deno* d_, void* user_data_, int32_t req_id, deno_buf buf) {
int deno_respond(Deno* d_, void* user_data, int32_t req_id, deno_buf buf) {
auto* d = unwrap(d_);
if (d->current_args_ != nullptr) {
// Synchronous response.
@ -123,7 +122,7 @@ int deno_respond(Deno* d_, void* user_data_, int32_t req_id, deno_buf buf) {
}
// Asynchronous response.
deno::UserDataScope user_data_scope(d, user_data_);
deno::UserDataScope user_data_scope(d, user_data);
v8::Locker locker(d->isolate_);
v8::Isolate::Scope isolate_scope(d->isolate_);
v8::HandleScope handle_scope(d->isolate_);

View file

@ -324,7 +324,7 @@ void Send(const v8::FunctionCallbackInfo<v8::Value>& args) {
DCHECK_EQ(d->current_args_, nullptr);
d->current_args_ = &args;
d->cb_(d->user_data_, req_id, control, data);
d->recv_cb_(d->user_data_, req_id, control, data);
if (d->current_args_ == nullptr) {
// This indicates that deno_repond() was called already.

View file

@ -29,11 +29,16 @@ void deno_init();
const char* deno_v8_version();
void deno_set_v8_flags(int* argc, char** argv);
Deno* deno_new(deno_buf snapshot, deno_buf shared, deno_recv_cb cb);
typedef struct {
deno_buf shared; // Shared buffer to be mapped to libdeno.shared
deno_recv_cb recv_cb; // Maps to libdeno.send() calls.
} deno_config;
Deno* deno_new(deno_buf snapshot, deno_config config);
Deno* deno_new_snapshotter(deno_config config, const char* js_filename,
const char* js_source, const char* source_map);
Deno* deno_new_snapshotter(deno_buf shared, deno_recv_cb cb,
const char* js_filename, const char* js_source,
const char* source_map);
// Generate a snapshot. The resulting buf can be used with deno_new.
// The caller must free the returned data by calling delete[] buf.data_ptr.
deno_buf deno_get_snapshot(Deno* d);

View file

@ -13,14 +13,14 @@ namespace deno {
// deno_s = Wrapped Isolate.
class DenoIsolate {
public:
DenoIsolate(deno_buf snapshot, deno_recv_cb cb, deno_buf shared)
DenoIsolate(deno_buf snapshot, deno_config config)
: isolate_(nullptr),
shared_(shared),
shared_(config.shared),
current_args_(nullptr),
snapshot_creator_(nullptr),
global_import_buf_ptr_(nullptr),
pending_promise_events_(0),
cb_(cb),
recv_cb_(config.recv_cb),
next_req_id_(0),
user_data_(nullptr) {
array_buffer_allocator_ = v8::ArrayBuffer::Allocator::NewDefaultAllocator();
@ -48,7 +48,7 @@ class DenoIsolate {
v8::SnapshotCreator* snapshot_creator_;
void* global_import_buf_ptr_;
int32_t pending_promise_events_;
deno_recv_cb cb_;
deno_recv_cb recv_cb_;
int32_t next_req_id_;
void* user_data_;
@ -65,20 +65,20 @@ class DenoIsolate {
};
class UserDataScope {
DenoIsolate* deno;
void* prev_data;
void* data; // Not necessary; only for sanity checking.
DenoIsolate* deno_;
void* prev_data_;
void* data_; // Not necessary; only for sanity checking.
public:
UserDataScope(DenoIsolate* deno_, void* data_) : deno(deno_), data(data_) {
UserDataScope(DenoIsolate* deno, void* data) : deno_(deno), data_(data) {
CHECK(deno->user_data_ == nullptr || deno->user_data_ == data_);
prev_data = deno->user_data_;
prev_data_ = deno->user_data_;
deno->user_data_ = data;
}
~UserDataScope() {
CHECK(deno->user_data_ == data);
deno->user_data_ = prev_data;
CHECK(deno_->user_data_ == data_);
deno_->user_data_ = prev_data_;
}
};

View file

@ -3,28 +3,30 @@
TEST(LibDenoTest, InitializesCorrectly) {
EXPECT_NE(snapshot.data_ptr, nullptr);
Deno* d = deno_new(snapshot, empty, nullptr);
Deno* d = deno_new(snapshot, deno_config{empty, nullptr});
EXPECT_TRUE(deno_execute(d, nullptr, "a.js", "1 + 2"));
deno_delete(d);
}
TEST(LibDenoTest, InitializesCorrectlyWithoutSnapshot) {
Deno* d = deno_new(empty, empty, nullptr);
Deno* d = deno_new(empty, deno_config{empty, nullptr});
EXPECT_TRUE(deno_execute(d, nullptr, "a.js", "1 + 2"));
deno_delete(d);
}
TEST(LibDenoTest, SnapshotterInitializesCorrectly) {
Deno* d = deno_new_snapshotter(empty, nullptr, "a.js", "a = 1 + 2", nullptr);
Deno* d = deno_new_snapshotter(deno_config{empty, nullptr}, "a.js",
"a = 1 + 2", nullptr);
deno_delete(d);
}
TEST(LibDenoTest, Snapshotter) {
Deno* d1 = deno_new_snapshotter(empty, nullptr, "a.js", "a = 1 + 2", nullptr);
Deno* d1 = deno_new_snapshotter(deno_config{empty, nullptr}, "a.js",
"a = 1 + 2", nullptr);
deno_buf test_snapshot = deno_get_snapshot(d1);
deno_delete(d1);
Deno* d2 = deno_new(test_snapshot, empty, nullptr);
Deno* d2 = deno_new(test_snapshot, deno_config{empty, nullptr});
EXPECT_TRUE(
deno_execute(d2, nullptr, "b.js", "if (a != 3) throw Error('x');"));
deno_delete(d2);
@ -33,14 +35,14 @@ TEST(LibDenoTest, Snapshotter) {
}
TEST(LibDenoTest, CanCallFunction) {
Deno* d = deno_new(snapshot, empty, nullptr);
Deno* d = deno_new(snapshot, deno_config{empty, nullptr});
EXPECT_TRUE(deno_execute(d, nullptr, "a.js",
"if (CanCallFunction() != 'foo') throw Error();"));
deno_delete(d);
}
TEST(LibDenoTest, ErrorsCorrectly) {
Deno* d = deno_new(snapshot, empty, nullptr);
Deno* d = deno_new(snapshot, deno_config{empty, nullptr});
EXPECT_FALSE(deno_execute(d, nullptr, "a.js", "throw Error()"));
deno_delete(d);
}
@ -77,15 +79,15 @@ void assert_null(deno_buf b) {
TEST(LibDenoTest, RecvReturnEmpty) {
static int count = 0;
Deno* d = deno_new(snapshot, empty,
[](auto _, int req_id, auto buf, auto data_buf) {
assert_null(data_buf);
count++;
EXPECT_EQ(static_cast<size_t>(3), buf.data_len);
EXPECT_EQ(buf.data_ptr[0], 'a');
EXPECT_EQ(buf.data_ptr[1], 'b');
EXPECT_EQ(buf.data_ptr[2], 'c');
});
auto recv_cb = [](auto _, int req_id, auto buf, auto data_buf) {
assert_null(data_buf);
count++;
EXPECT_EQ(static_cast<size_t>(3), buf.data_len);
EXPECT_EQ(buf.data_ptr[0], 'a');
EXPECT_EQ(buf.data_ptr[1], 'b');
EXPECT_EQ(buf.data_ptr[2], 'c');
};
Deno* d = deno_new(snapshot, deno_config{empty, recv_cb});
EXPECT_TRUE(deno_execute(d, nullptr, "a.js", "RecvReturnEmpty()"));
EXPECT_EQ(count, 2);
deno_delete(d);
@ -93,58 +95,58 @@ TEST(LibDenoTest, RecvReturnEmpty) {
TEST(LibDenoTest, RecvReturnBar) {
static int count = 0;
Deno* d = deno_new(snapshot, empty,
[](auto user_data, int req_id, auto buf, auto data_buf) {
auto d = reinterpret_cast<Deno*>(user_data);
assert_null(data_buf);
count++;
EXPECT_EQ(static_cast<size_t>(3), buf.data_len);
EXPECT_EQ(buf.data_ptr[0], 'a');
EXPECT_EQ(buf.data_ptr[1], 'b');
EXPECT_EQ(buf.data_ptr[2], 'c');
deno_respond(d, user_data, req_id, strbuf("bar"));
});
auto recv_cb = [](auto user_data, int req_id, auto buf, auto data_buf) {
auto d = reinterpret_cast<Deno*>(user_data);
assert_null(data_buf);
count++;
EXPECT_EQ(static_cast<size_t>(3), buf.data_len);
EXPECT_EQ(buf.data_ptr[0], 'a');
EXPECT_EQ(buf.data_ptr[1], 'b');
EXPECT_EQ(buf.data_ptr[2], 'c');
deno_respond(d, user_data, req_id, strbuf("bar"));
};
Deno* d = deno_new(snapshot, deno_config{empty, recv_cb});
EXPECT_TRUE(deno_execute(d, d, "a.js", "RecvReturnBar()"));
EXPECT_EQ(count, 1);
deno_delete(d);
}
TEST(LibDenoTest, DoubleRecvFails) {
Deno* d = deno_new(snapshot, empty, nullptr);
Deno* d = deno_new(snapshot, deno_config{empty, nullptr});
EXPECT_FALSE(deno_execute(d, nullptr, "a.js", "DoubleRecvFails()"));
deno_delete(d);
}
TEST(LibDenoTest, SendRecvSlice) {
static int count = 0;
Deno* d = deno_new(
snapshot, empty, [](auto user_data, int req_id, auto buf, auto data_buf) {
auto d = reinterpret_cast<Deno*>(user_data);
assert_null(data_buf);
static const size_t alloc_len = 1024;
size_t i = count++;
// Check the size and offset of the slice.
size_t data_offset = buf.data_ptr - buf.alloc_ptr;
EXPECT_EQ(data_offset, i * 11);
EXPECT_EQ(buf.data_len, alloc_len - i * 30);
EXPECT_EQ(buf.alloc_len, alloc_len);
// Check values written by the JS side.
EXPECT_EQ(buf.data_ptr[0], 100 + i);
EXPECT_EQ(buf.data_ptr[buf.data_len - 1], 100 - i);
// Make copy of the backing buffer -- this is currently necessary
// because deno_respond() takes ownership over the buffer, but we are
// not given ownership of `buf` by our caller.
uint8_t* alloc_ptr = reinterpret_cast<uint8_t*>(malloc(alloc_len));
memcpy(alloc_ptr, buf.alloc_ptr, alloc_len);
// Make a slice that is a bit shorter than the original.
deno_buf buf2{alloc_ptr, alloc_len, alloc_ptr + data_offset,
buf.data_len - 19};
// Place some values into the buffer for the JS side to verify.
buf2.data_ptr[0] = 200 + i;
buf2.data_ptr[buf2.data_len - 1] = 200 - i;
// Send back.
deno_respond(d, user_data, req_id, buf2);
});
auto recv_cb = [](auto user_data, int req_id, auto buf, auto data_buf) {
auto d = reinterpret_cast<Deno*>(user_data);
assert_null(data_buf);
static const size_t alloc_len = 1024;
size_t i = count++;
// Check the size and offset of the slice.
size_t data_offset = buf.data_ptr - buf.alloc_ptr;
EXPECT_EQ(data_offset, i * 11);
EXPECT_EQ(buf.data_len, alloc_len - i * 30);
EXPECT_EQ(buf.alloc_len, alloc_len);
// Check values written by the JS side.
EXPECT_EQ(buf.data_ptr[0], 100 + i);
EXPECT_EQ(buf.data_ptr[buf.data_len - 1], 100 - i);
// Make copy of the backing buffer -- this is currently necessary
// because deno_respond() takes ownership over the buffer, but we are
// not given ownership of `buf` by our caller.
uint8_t* alloc_ptr = reinterpret_cast<uint8_t*>(malloc(alloc_len));
memcpy(alloc_ptr, buf.alloc_ptr, alloc_len);
// Make a slice that is a bit shorter than the original.
deno_buf buf2{alloc_ptr, alloc_len, alloc_ptr + data_offset,
buf.data_len - 19};
// Place some values into the buffer for the JS side to verify.
buf2.data_ptr[0] = 200 + i;
buf2.data_ptr[buf2.data_len - 1] = 200 - i;
// Send back.
deno_respond(d, user_data, req_id, buf2);
};
Deno* d = deno_new(snapshot, deno_config{empty, recv_cb});
EXPECT_TRUE(deno_execute(d, d, "a.js", "SendRecvSlice()"));
EXPECT_EQ(count, 5);
deno_delete(d);
@ -152,49 +154,49 @@ TEST(LibDenoTest, SendRecvSlice) {
TEST(LibDenoTest, JSSendArrayBufferViewTypes) {
static int count = 0;
Deno* d = deno_new(snapshot, empty,
[](auto _, int req_id, auto buf, auto data_buf) {
assert_null(data_buf);
count++;
size_t data_offset = buf.data_ptr - buf.alloc_ptr;
EXPECT_EQ(data_offset, 2468u);
EXPECT_EQ(buf.data_len, 1000u);
EXPECT_EQ(buf.alloc_len, 4321u);
EXPECT_EQ(buf.data_ptr[0], count);
});
auto recv_cb = [](auto _, int req_id, auto buf, auto data_buf) {
assert_null(data_buf);
count++;
size_t data_offset = buf.data_ptr - buf.alloc_ptr;
EXPECT_EQ(data_offset, 2468u);
EXPECT_EQ(buf.data_len, 1000u);
EXPECT_EQ(buf.alloc_len, 4321u);
EXPECT_EQ(buf.data_ptr[0], count);
};
Deno* d = deno_new(snapshot, deno_config{empty, recv_cb});
EXPECT_TRUE(deno_execute(d, nullptr, "a.js", "JSSendArrayBufferViewTypes()"));
EXPECT_EQ(count, 3);
deno_delete(d);
}
TEST(LibDenoTest, TypedArraySnapshots) {
Deno* d = deno_new(snapshot, empty, nullptr);
Deno* d = deno_new(snapshot, deno_config{empty, nullptr});
EXPECT_TRUE(deno_execute(d, nullptr, "a.js", "TypedArraySnapshots()"));
deno_delete(d);
}
TEST(LibDenoTest, SnapshotBug) {
Deno* d = deno_new(snapshot, empty, nullptr);
Deno* d = deno_new(snapshot, deno_config{empty, nullptr});
EXPECT_TRUE(deno_execute(d, nullptr, "a.js", "SnapshotBug()"));
deno_delete(d);
}
TEST(LibDenoTest, GlobalErrorHandling) {
static int count = 0;
Deno* d = deno_new(snapshot, empty,
[](auto _, int req_id, auto buf, auto data_buf) {
assert_null(data_buf);
count++;
EXPECT_EQ(static_cast<size_t>(1), buf.data_len);
EXPECT_EQ(buf.data_ptr[0], 42);
});
auto recv_cb = [](auto _, int req_id, auto buf, auto data_buf) {
assert_null(data_buf);
count++;
EXPECT_EQ(static_cast<size_t>(1), buf.data_len);
EXPECT_EQ(buf.data_ptr[0], 42);
};
Deno* d = deno_new(snapshot, deno_config{empty, recv_cb});
EXPECT_FALSE(deno_execute(d, nullptr, "a.js", "GlobalErrorHandling()"));
EXPECT_EQ(count, 1);
deno_delete(d);
}
TEST(LibDenoTest, DoubleGlobalErrorHandlingFails) {
Deno* d = deno_new(snapshot, empty, nullptr);
Deno* d = deno_new(snapshot, deno_config{empty, nullptr});
EXPECT_FALSE(
deno_execute(d, nullptr, "a.js", "DoubleGlobalErrorHandlingFails()"));
deno_delete(d);
@ -203,17 +205,17 @@ TEST(LibDenoTest, DoubleGlobalErrorHandlingFails) {
TEST(LibDenoTest, DataBuf) {
static int count = 0;
static deno_buf data_buf_copy;
Deno* d = deno_new(snapshot, empty,
[](auto _, int req_id, deno_buf buf, deno_buf data_buf) {
count++;
data_buf.data_ptr[0] = 4;
data_buf.data_ptr[1] = 2;
data_buf_copy = data_buf;
EXPECT_EQ(2u, buf.data_len);
EXPECT_EQ(2u, data_buf.data_len);
EXPECT_EQ(buf.data_ptr[0], 1);
EXPECT_EQ(buf.data_ptr[1], 2);
});
auto recv_cb = [](auto _, int req_id, deno_buf buf, deno_buf data_buf) {
count++;
data_buf.data_ptr[0] = 4;
data_buf.data_ptr[1] = 2;
data_buf_copy = data_buf;
EXPECT_EQ(2u, buf.data_len);
EXPECT_EQ(2u, data_buf.data_len);
EXPECT_EQ(buf.data_ptr[0], 1);
EXPECT_EQ(buf.data_ptr[1], 2);
};
Deno* d = deno_new(snapshot, deno_config{empty, recv_cb});
EXPECT_TRUE(deno_execute(d, nullptr, "a.js", "DataBuf()"));
EXPECT_EQ(count, 1);
// data_buf was subsequently changed in JS, let's check that our copy reflects
@ -225,12 +227,12 @@ TEST(LibDenoTest, DataBuf) {
TEST(LibDenoTest, PromiseRejectCatchHandling) {
static int count = 0;
Deno* d = deno_new(snapshot, empty,
[](auto _, int req_id, auto buf, auto data_buf) {
// If no error, nothing should be sent, and count should
// not increment
count++;
});
auto recv_cb = [](auto _, int req_id, auto buf, auto data_buf) {
// If no error, nothing should be sent, and count should
// not increment
count++;
};
Deno* d = deno_new(snapshot, deno_config{empty, recv_cb});
EXPECT_TRUE(deno_execute(d, nullptr, "a.js", "PromiseRejectCatchHandling()"));
EXPECT_EQ(count, 0);
@ -240,7 +242,7 @@ TEST(LibDenoTest, PromiseRejectCatchHandling) {
TEST(LibDenoTest, Shared) {
uint8_t s[] = {0, 1, 2};
deno_buf shared = {nullptr, 0, s, 3};
Deno* d = deno_new(snapshot, shared, nullptr);
Deno* d = deno_new(snapshot, deno_config{shared, nullptr});
EXPECT_TRUE(deno_execute(d, nullptr, "a.js", "Shared()"));
EXPECT_EQ(s[0], 42);
EXPECT_EQ(s[1], 43);

View file

@ -29,8 +29,9 @@ int main(int argc, char** argv) {
}
deno_init();
deno_config config = {deno::empty_buf, nullptr};
Deno* d = deno_new_snapshotter(
deno::empty_buf, nullptr, js_fn, js_source.c_str(),
config, js_fn, js_source.c_str(),
source_map_fn != nullptr ? source_map.c_str() : nullptr);
auto snapshot = deno_get_snapshot(d);

View file

@ -141,9 +141,11 @@ impl Isolate {
DENO_INIT.call_once(|| {
unsafe { libdeno::deno_init() };
});
let shared = libdeno::deno_buf::empty(); // TODO Use shared for message passing.
let libdeno_isolate =
unsafe { libdeno::deno_new(snapshot, shared, pre_dispatch) };
let config = libdeno::deno_config {
shared: libdeno::deno_buf::empty(), // TODO Use for message passing.
recv_cb: pre_dispatch,
};
let libdeno_isolate = unsafe { libdeno::deno_new(snapshot, config) };
// This channel handles sending async messages back to the runtime.
let (tx, rx) = mpsc::channel::<(i32, Buf)>();

View file

@ -96,15 +96,17 @@ type DenoRecvCb = unsafe extern "C" fn(
data_buf: deno_buf,
);
#[repr(C)]
pub struct deno_config {
pub shared: deno_buf,
pub recv_cb: DenoRecvCb,
}
extern "C" {
pub fn deno_init();
pub fn deno_v8_version() -> *const c_char;
pub fn deno_set_v8_flags(argc: *mut c_int, argv: *mut *mut c_char);
pub fn deno_new(
snapshot: deno_buf,
shared: deno_buf,
cb: DenoRecvCb,
) -> *const isolate;
pub fn deno_new(snapshot: deno_buf, config: deno_config) -> *const isolate;
pub fn deno_delete(i: *const isolate);
pub fn deno_last_exception(i: *const isolate) -> *const c_char;
pub fn deno_check_promise_errors(i: *const isolate);