mirror of
https://github.com/denoland/deno.git
synced 2024-12-22 15:24:46 -05:00
Add libdeno.shared global shared ArrayBuffer.
This commit is contained in:
parent
61cda72881
commit
0501330607
10 changed files with 128 additions and 55 deletions
|
@ -17,6 +17,8 @@ interface Libdeno {
|
|||
|
||||
print(x: string, isErr?: boolean): void;
|
||||
|
||||
shared: ArrayBuffer;
|
||||
|
||||
setGlobalErrorHandler: (
|
||||
handler: (
|
||||
message: string,
|
||||
|
|
|
@ -13,8 +13,8 @@
|
|||
|
||||
extern "C" {
|
||||
|
||||
Deno* deno_new(deno_buf snapshot, deno_recv_cb cb) {
|
||||
deno::DenoIsolate* d = new deno::DenoIsolate(snapshot, cb);
|
||||
Deno* deno_new(deno_buf snapshot, deno_buf shared, deno_recv_cb cb) {
|
||||
deno::DenoIsolate* d = new deno::DenoIsolate(snapshot, cb, shared);
|
||||
v8::Isolate::CreateParams params;
|
||||
params.array_buffer_allocator =
|
||||
v8::ArrayBuffer::Allocator::NewDefaultAllocator();
|
||||
|
@ -42,11 +42,12 @@ Deno* deno_new(deno_buf snapshot, deno_recv_cb cb) {
|
|||
return reinterpret_cast<Deno*>(d);
|
||||
}
|
||||
|
||||
Deno* deno_new_snapshotter(deno_recv_cb cb, 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) {
|
||||
auto* creator = new v8::SnapshotCreator(deno::external_references);
|
||||
auto* isolate = creator->GetIsolate();
|
||||
auto* d = new deno::DenoIsolate(deno::empty_buf, cb);
|
||||
auto* d = new deno::DenoIsolate(deno::empty_buf, cb, shared);
|
||||
d->snapshot_creator_ = creator;
|
||||
d->AddIsolate(isolate);
|
||||
v8::Isolate::Scope isolate_scope(isolate);
|
||||
|
|
|
@ -339,6 +339,26 @@ void Send(const v8::FunctionCallbackInfo<v8::Value>& args) {
|
|||
}
|
||||
}
|
||||
|
||||
void Shared(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_);
|
||||
v8::EscapableHandleScope handle_scope(isolate);
|
||||
if (d->shared_.data_ptr == nullptr) {
|
||||
return;
|
||||
}
|
||||
v8::Local<v8::ArrayBuffer> ab;
|
||||
if (d->shared_ab_.IsEmpty()) {
|
||||
// Lazily initialize the persistent external ArrayBuffer.
|
||||
ab = v8::ArrayBuffer::New(isolate, d->shared_.data_ptr, d->shared_.data_len,
|
||||
v8::ArrayBufferCreationMode::kExternalized);
|
||||
d->shared_ab_.Reset(isolate, ab);
|
||||
}
|
||||
info.GetReturnValue().Set(ab);
|
||||
}
|
||||
|
||||
// Sets the global error handler.
|
||||
void SetGlobalErrorHandler(const v8::FunctionCallbackInfo<v8::Value>& args) {
|
||||
v8::Isolate* isolate = args.GetIsolate();
|
||||
|
@ -470,6 +490,9 @@ void InitializeContext(v8::Isolate* isolate, v8::Local<v8::Context> context,
|
|||
auto send_val = send_tmpl->GetFunction(context).ToLocalChecked();
|
||||
CHECK(deno_val->Set(context, deno::v8_str("send"), send_val).FromJust());
|
||||
|
||||
CHECK(deno_val->SetAccessor(context, deno::v8_str("shared"), Shared)
|
||||
.FromJust());
|
||||
|
||||
auto set_global_error_handler_tmpl =
|
||||
v8::FunctionTemplate::New(isolate, SetGlobalErrorHandler);
|
||||
auto set_global_error_handler_val =
|
||||
|
|
|
@ -29,10 +29,11 @@ void deno_init();
|
|||
const char* deno_v8_version();
|
||||
void deno_set_v8_flags(int* argc, char** argv);
|
||||
|
||||
Deno* deno_new(deno_buf snapshot, deno_recv_cb cb);
|
||||
Deno* deno_new(deno_buf snapshot, deno_buf shared, deno_recv_cb cb);
|
||||
|
||||
Deno* deno_new_snapshotter(deno_recv_cb cb, 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);
|
||||
deno_buf deno_get_snapshot(Deno* d);
|
||||
|
||||
void deno_delete(Deno* d);
|
||||
|
|
|
@ -13,8 +13,9 @@ namespace deno {
|
|||
// deno_s = Wrapped Isolate.
|
||||
class DenoIsolate {
|
||||
public:
|
||||
DenoIsolate(deno_buf snapshot, deno_recv_cb cb)
|
||||
DenoIsolate(deno_buf snapshot, deno_recv_cb cb, deno_buf shared)
|
||||
: isolate_(nullptr),
|
||||
shared_(shared),
|
||||
current_args_(nullptr),
|
||||
snapshot_creator_(nullptr),
|
||||
global_import_buf_ptr_(nullptr),
|
||||
|
@ -31,6 +32,7 @@ class DenoIsolate {
|
|||
void AddIsolate(v8::Isolate* isolate);
|
||||
|
||||
v8::Isolate* isolate_;
|
||||
deno_buf shared_;
|
||||
const v8::FunctionCallbackInfo<v8::Value>* current_args_;
|
||||
v8::SnapshotCreator* snapshot_creator_;
|
||||
void* global_import_buf_ptr_;
|
||||
|
@ -48,6 +50,7 @@ class DenoIsolate {
|
|||
v8::Persistent<v8::Function> promise_error_examiner_;
|
||||
v8::StartupData snapshot_;
|
||||
v8::Persistent<v8::ArrayBuffer> global_import_buf_;
|
||||
v8::Persistent<v8::ArrayBuffer> shared_ab_;
|
||||
};
|
||||
|
||||
class UserDataScope {
|
||||
|
@ -75,6 +78,8 @@ struct InternalFieldData {
|
|||
void Print(const v8::FunctionCallbackInfo<v8::Value>& args);
|
||||
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 SetGlobalErrorHandler(const v8::FunctionCallbackInfo<v8::Value>& args);
|
||||
void SetPromiseRejectHandler(const v8::FunctionCallbackInfo<v8::Value>& args);
|
||||
void SetPromiseErrorExaminer(const v8::FunctionCallbackInfo<v8::Value>& args);
|
||||
|
@ -82,6 +87,7 @@ 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),
|
||||
reinterpret_cast<intptr_t>(SetGlobalErrorHandler),
|
||||
reinterpret_cast<intptr_t>(SetPromiseRejectHandler),
|
||||
reinterpret_cast<intptr_t>(SetPromiseErrorExaminer),
|
||||
|
|
|
@ -2,40 +2,38 @@
|
|||
#include "test.h"
|
||||
|
||||
TEST(LibDenoTest, InitializesCorrectly) {
|
||||
printf("snapshot.data_ptr %p\n", snapshot.data_ptr);
|
||||
EXPECT_NE(snapshot.data_ptr, nullptr);
|
||||
Deno* d = deno_new(empty, nullptr);
|
||||
Deno* d = deno_new(snapshot, empty, nullptr);
|
||||
EXPECT_TRUE(deno_execute(d, nullptr, "a.js", "1 + 2"));
|
||||
deno_delete(d);
|
||||
}
|
||||
|
||||
TEST(LibDenoTest, InitializesCorrectlyWithoutSnapshot) {
|
||||
deno_buf empty = {nullptr, 0, nullptr, 0};
|
||||
Deno* d = deno_new(empty, nullptr);
|
||||
Deno* d = deno_new(empty, empty, nullptr);
|
||||
EXPECT_TRUE(deno_execute(d, nullptr, "a.js", "1 + 2"));
|
||||
deno_delete(d);
|
||||
}
|
||||
|
||||
TEST(LibDenoTest, Snapshotter) {
|
||||
Deno* d1 = deno_new_snapshotter(nullptr, "a.js", "a = 1 + 2", nullptr);
|
||||
Deno* d1 = deno_new_snapshotter(empty, nullptr, "a.js", "a = 1 + 2", nullptr);
|
||||
deno_buf test_snapshot = deno_get_snapshot(d1);
|
||||
// TODO(ry) deno_delete(d1);
|
||||
|
||||
Deno* d2 = deno_new(test_snapshot, nullptr);
|
||||
Deno* d2 = deno_new(test_snapshot, empty, nullptr);
|
||||
EXPECT_TRUE(
|
||||
deno_execute(d2, nullptr, "b.js", "if (a != 3) throw Error('x');"));
|
||||
deno_delete(d2);
|
||||
}
|
||||
|
||||
TEST(LibDenoTest, CanCallFunction) {
|
||||
Deno* d = deno_new(snapshot, nullptr);
|
||||
Deno* d = deno_new(snapshot, 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, nullptr);
|
||||
Deno* d = deno_new(snapshot, empty, nullptr);
|
||||
EXPECT_FALSE(deno_execute(d, nullptr, "a.js", "throw Error()"));
|
||||
deno_delete(d);
|
||||
}
|
||||
|
@ -72,14 +70,15 @@ void assert_null(deno_buf b) {
|
|||
|
||||
TEST(LibDenoTest, RecvReturnEmpty) {
|
||||
static int count = 0;
|
||||
Deno* d = deno_new(snapshot, [](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, 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');
|
||||
});
|
||||
EXPECT_TRUE(deno_execute(d, nullptr, "a.js", "RecvReturnEmpty()"));
|
||||
EXPECT_EQ(count, 2);
|
||||
deno_delete(d);
|
||||
|
@ -87,7 +86,7 @@ TEST(LibDenoTest, RecvReturnEmpty) {
|
|||
|
||||
TEST(LibDenoTest, RecvReturnBar) {
|
||||
static int count = 0;
|
||||
Deno* d = deno_new(snapshot,
|
||||
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);
|
||||
|
@ -104,7 +103,7 @@ TEST(LibDenoTest, RecvReturnBar) {
|
|||
}
|
||||
|
||||
TEST(LibDenoTest, DoubleRecvFails) {
|
||||
Deno* d = deno_new(snapshot, nullptr);
|
||||
Deno* d = deno_new(snapshot, empty, nullptr);
|
||||
EXPECT_FALSE(deno_execute(d, nullptr, "a.js", "DoubleRecvFails()"));
|
||||
deno_delete(d);
|
||||
}
|
||||
|
@ -112,7 +111,7 @@ TEST(LibDenoTest, DoubleRecvFails) {
|
|||
TEST(LibDenoTest, SendRecvSlice) {
|
||||
static int count = 0;
|
||||
Deno* d = deno_new(
|
||||
snapshot, [](auto user_data, int req_id, auto buf, auto data_buf) {
|
||||
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;
|
||||
|
@ -146,47 +145,49 @@ TEST(LibDenoTest, SendRecvSlice) {
|
|||
|
||||
TEST(LibDenoTest, JSSendArrayBufferViewTypes) {
|
||||
static int count = 0;
|
||||
Deno* d = deno_new(snapshot, [](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, 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);
|
||||
});
|
||||
EXPECT_TRUE(deno_execute(d, nullptr, "a.js", "JSSendArrayBufferViewTypes()"));
|
||||
EXPECT_EQ(count, 3);
|
||||
deno_delete(d);
|
||||
}
|
||||
|
||||
TEST(LibDenoTest, TypedArraySnapshots) {
|
||||
Deno* d = deno_new(snapshot, nullptr);
|
||||
Deno* d = deno_new(snapshot, empty, nullptr);
|
||||
EXPECT_TRUE(deno_execute(d, nullptr, "a.js", "TypedArraySnapshots()"));
|
||||
deno_delete(d);
|
||||
}
|
||||
|
||||
TEST(LibDenoTest, SnapshotBug) {
|
||||
Deno* d = deno_new(snapshot, nullptr);
|
||||
Deno* d = deno_new(snapshot, 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, [](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, 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);
|
||||
});
|
||||
EXPECT_FALSE(deno_execute(d, nullptr, "a.js", "GlobalErrorHandling()"));
|
||||
EXPECT_EQ(count, 1);
|
||||
deno_delete(d);
|
||||
}
|
||||
|
||||
TEST(LibDenoTest, DoubleGlobalErrorHandlingFails) {
|
||||
Deno* d = deno_new(snapshot, nullptr);
|
||||
Deno* d = deno_new(snapshot, empty, nullptr);
|
||||
EXPECT_FALSE(
|
||||
deno_execute(d, nullptr, "a.js", "DoubleGlobalErrorHandlingFails()"));
|
||||
deno_delete(d);
|
||||
|
@ -195,7 +196,7 @@ TEST(LibDenoTest, DoubleGlobalErrorHandlingFails) {
|
|||
TEST(LibDenoTest, DataBuf) {
|
||||
static int count = 0;
|
||||
static deno_buf data_buf_copy;
|
||||
Deno* d = deno_new(snapshot,
|
||||
Deno* d = deno_new(snapshot, empty,
|
||||
[](auto _, int req_id, deno_buf buf, deno_buf data_buf) {
|
||||
count++;
|
||||
data_buf.data_ptr[0] = 4;
|
||||
|
@ -217,12 +218,25 @@ TEST(LibDenoTest, DataBuf) {
|
|||
|
||||
TEST(LibDenoTest, PromiseRejectCatchHandling) {
|
||||
static int count = 0;
|
||||
Deno* d = deno_new(snapshot, [](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, empty,
|
||||
[](auto _, int req_id, auto buf, auto data_buf) {
|
||||
// If no error, nothing should be sent, and count should
|
||||
// not increment
|
||||
count++;
|
||||
});
|
||||
EXPECT_TRUE(deno_execute(d, nullptr, "a.js", "PromiseRejectCatchHandling()"));
|
||||
|
||||
EXPECT_EQ(count, 0);
|
||||
deno_delete(d);
|
||||
}
|
||||
|
||||
TEST(LibDenoTest, Shared) {
|
||||
uint8_t s[] = {0, 1, 2};
|
||||
deno_buf shared = {nullptr, 0, s, 3};
|
||||
Deno* d = deno_new(snapshot, shared, nullptr);
|
||||
EXPECT_TRUE(deno_execute(d, nullptr, "a.js", "Shared()"));
|
||||
EXPECT_EQ(s[0], 42);
|
||||
EXPECT_EQ(s[1], 43);
|
||||
EXPECT_EQ(s[2], 44);
|
||||
deno_delete(d);
|
||||
}
|
||||
|
|
|
@ -173,3 +173,16 @@ global.PromiseRejectCatchHandling = () => {
|
|||
}
|
||||
})();
|
||||
}
|
||||
|
||||
global.Shared = () => {
|
||||
const ab = libdeno.shared;
|
||||
assert(ab instanceof ArrayBuffer);
|
||||
assert(ab.byteLength === 3);
|
||||
const ui8 = new Uint8Array(ab);
|
||||
assert(ui8[0] === 0);
|
||||
assert(ui8[1] === 1);
|
||||
assert(ui8[2] === 2);
|
||||
ui8[0] = 42;
|
||||
ui8[1] = 43;
|
||||
ui8[2] = 44;
|
||||
}
|
||||
|
|
|
@ -30,7 +30,7 @@ int main(int argc, char** argv) {
|
|||
|
||||
deno_init();
|
||||
Deno* d = deno_new_snapshotter(
|
||||
nullptr, js_fn, js_source.c_str(),
|
||||
deno::empty_buf, nullptr, js_fn, js_source.c_str(),
|
||||
source_map_fn != nullptr ? source_map.c_str() : nullptr);
|
||||
|
||||
auto snapshot = deno_get_snapshot(d);
|
||||
|
|
|
@ -100,6 +100,15 @@ pub struct Metrics {
|
|||
|
||||
static DENO_INIT: std::sync::Once = std::sync::ONCE_INIT;
|
||||
|
||||
fn empty() -> libdeno::deno_buf {
|
||||
libdeno::deno_buf {
|
||||
alloc_ptr: std::ptr::null_mut(),
|
||||
alloc_len: 0,
|
||||
data_ptr: std::ptr::null_mut(),
|
||||
data_len: 0,
|
||||
}
|
||||
}
|
||||
|
||||
impl Isolate {
|
||||
pub fn new(
|
||||
flags: flags::DenoFlags,
|
||||
|
@ -109,9 +118,9 @@ impl Isolate {
|
|||
DENO_INIT.call_once(|| {
|
||||
unsafe { libdeno::deno_init() };
|
||||
});
|
||||
|
||||
let shared = empty(); // TODO Use shared for message passing.
|
||||
let libdeno_isolate = unsafe {
|
||||
libdeno::deno_new(snapshot::deno_snapshot.clone(), pre_dispatch)
|
||||
libdeno::deno_new(snapshot::deno_snapshot.clone(), shared, pre_dispatch)
|
||||
};
|
||||
// This channel handles sending async messages back to the runtime.
|
||||
let (tx, rx) = mpsc::channel::<(i32, Buf)>();
|
||||
|
|
|
@ -28,7 +28,11 @@ 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, cb: DenoRecvCb) -> *const isolate;
|
||||
pub fn deno_new(
|
||||
snapshot: deno_buf,
|
||||
shared: deno_buf,
|
||||
cb: DenoRecvCb,
|
||||
) -> *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);
|
||||
|
|
Loading…
Reference in a new issue