diff options
Diffstat (limited to 'core/libdeno')
-rw-r--r-- | core/libdeno/api.cc | 10 | ||||
-rw-r--r-- | core/libdeno/binding.cc | 17 | ||||
-rw-r--r-- | core/libdeno/deno.h | 30 | ||||
-rw-r--r-- | core/libdeno/libdeno.d.ts | 3 | ||||
-rw-r--r-- | core/libdeno/libdeno_test.cc | 51 | ||||
-rw-r--r-- | core/libdeno/libdeno_test.js | 39 | ||||
-rw-r--r-- | core/libdeno/modules_test.cc | 20 |
7 files changed, 126 insertions, 44 deletions
diff --git a/core/libdeno/api.cc b/core/libdeno/api.cc index 61eeb43ca..1e6b5dfbf 100644 --- a/core/libdeno/api.cc +++ b/core/libdeno/api.cc @@ -159,10 +159,11 @@ void deno_pinned_buf_delete(deno_pinned_buf* buf) { auto _ = deno::PinnedBuf(buf); } -void deno_respond(Deno* d_, void* user_data, deno_buf buf) { +void deno_respond(Deno* d_, void* user_data, deno_op_id op_id, deno_buf buf) { auto* d = unwrap(d_); if (d->current_args_ != nullptr) { // Synchronous response. + // Note op_id is not passed back in the case of synchronous response. if (buf.data_ptr != nullptr) { auto ab = deno::ImportBuf(d, buf); d->current_args_->GetReturnValue().Set(ab); @@ -187,12 +188,13 @@ void deno_respond(Deno* d_, void* user_data, deno_buf buf) { return; } - v8::Local<v8::Value> args[1]; + v8::Local<v8::Value> args[2]; int argc = 0; if (buf.data_ptr != nullptr) { - args[0] = deno::ImportBuf(d, buf); - argc = 1; + args[0] = v8::Integer::New(d->isolate_, op_id); + args[1] = deno::ImportBuf(d, buf); + argc = 2; } auto v = recv_->Call(context, context->Global(), argc, args); diff --git a/core/libdeno/binding.cc b/core/libdeno/binding.cc index da582a3bf..291e62f01 100644 --- a/core/libdeno/binding.cc +++ b/core/libdeno/binding.cc @@ -223,22 +223,29 @@ void Send(const v8::FunctionCallbackInfo<v8::Value>& args) { v8::HandleScope handle_scope(isolate); deno_buf control = {nullptr, 0}; - if (args[0]->IsArrayBufferView()) { - auto view = v8::Local<v8::ArrayBufferView>::Cast(args[0]); + + int32_t op_id = 0; + if (args[0]->IsInt32()) { + auto context = d->context_.Get(isolate); + op_id = args[0]->Int32Value(context).FromJust(); + } + + if (args[1]->IsArrayBufferView()) { + auto view = v8::Local<v8::ArrayBufferView>::Cast(args[1]); auto data = reinterpret_cast<uint8_t*>(view->Buffer()->GetContents().Data()); control = {data + view->ByteOffset(), view->ByteLength()}; } PinnedBuf zero_copy = - args[1]->IsArrayBufferView() - ? PinnedBuf(v8::Local<v8::ArrayBufferView>::Cast(args[1])) + args[2]->IsArrayBufferView() + ? PinnedBuf(v8::Local<v8::ArrayBufferView>::Cast(args[2])) : PinnedBuf(); DCHECK_NULL(d->current_args_); d->current_args_ = &args; - d->recv_cb_(d->user_data_, control, zero_copy.IntoRaw()); + d->recv_cb_(d->user_data_, op_id, control, zero_copy.IntoRaw()); if (d->current_args_ == nullptr) { // This indicates that deno_repond() was called already. diff --git a/core/libdeno/deno.h b/core/libdeno/deno.h index fe5214848..2c248a87e 100644 --- a/core/libdeno/deno.h +++ b/core/libdeno/deno.h @@ -28,10 +28,22 @@ typedef struct { typedef struct deno_s Deno; -// A callback to receive a message from a libdeno.send() javascript call. +typedef uint32_t deno_op_id; + +// A callback to receive a message from a Deno.core.send() javascript call. // control_buf is valid for only for the lifetime of this callback. // data_buf is valid until deno_respond() is called. -typedef void (*deno_recv_cb)(void* user_data, deno_buf control_buf, +// +// op_id corresponds to the first argument of Deno.core.send(). +// op_id is an extra user-defined integer valued which is not interpreted by +// libdeno. +// +// control_buf corresponds to the second argument of Deno.core.send(). +// +// zero_copy_buf corresponds to the third argument of Deno.core.send(). +// The user must call deno_pinned_buf_delete on each zero_copy_buf received. +typedef void (*deno_recv_cb)(void* user_data, deno_op_id op_id, + deno_buf control_buf, deno_pinned_buf zero_copy_buf); typedef int deno_dyn_import_id; @@ -49,7 +61,7 @@ typedef struct { int will_snapshot; // Default 0. If calling deno_snapshot_new 1. deno_snapshot load_snapshot; // A startup snapshot to use. deno_buf shared; // Shared buffer to be mapped to libdeno.shared - deno_recv_cb recv_cb; // Maps to libdeno.send() calls. + deno_recv_cb recv_cb; // Maps to Deno.core.send() calls. deno_dyn_import_cb dyn_import_cb; } deno_config; @@ -78,21 +90,25 @@ void deno_unlock(Deno* d); void deno_execute(Deno* d, void* user_data, const char* js_filename, const char* js_source); -// deno_respond sends up to one message back for every deno_recv_cb made. +// deno_respond sends one message back for every deno_recv_cb made. // -// If this is called during deno_recv_cb, the issuing libdeno.send() in +// If this is called during deno_recv_cb, the issuing Deno.core.send() in // javascript will synchronously return the specified buf as an ArrayBuffer (or // null if buf is empty). // // If this is called after deno_recv_cb has returned, the deno_respond -// will call into the JS callback specified by libdeno.recv(). +// will call into the JS callback specified by Deno.core.recv(). // // (Ideally, but not currently: After calling deno_respond(), the caller no // longer owns `buf` and must not use it; deno_respond() is responsible for // releasing its memory.) // +// op_id is an extra user-defined integer valued which is not currently +// interpreted by libdeno. But it should probably correspond to the op_id in +// deno_recv_cb. +// // If a JS exception was encountered, deno_last_exception() will be non-NULL. -void deno_respond(Deno* d, void* user_data, deno_buf buf); +void deno_respond(Deno* d, void* user_data, deno_op_id op_id, deno_buf buf); // consumes zero_copy void deno_pinned_buf_delete(deno_pinned_buf* buf); diff --git a/core/libdeno/libdeno.d.ts b/core/libdeno/libdeno.d.ts index 1bc7367d9..8a26e49ca 100644 --- a/core/libdeno/libdeno.d.ts +++ b/core/libdeno/libdeno.d.ts @@ -13,13 +13,14 @@ interface EvalErrorInfo { } declare interface MessageCallback { - (msg: Uint8Array): void; + (opId: number, msg: Uint8Array): void; } declare interface DenoCore { recv(cb: MessageCallback): void; send( + opId: number, control: null | ArrayBufferView, data?: ArrayBufferView ): null | Uint8Array; diff --git a/core/libdeno/libdeno_test.cc b/core/libdeno/libdeno_test.cc index 16a4a11f6..a72793944 100644 --- a/core/libdeno/libdeno_test.cc +++ b/core/libdeno/libdeno_test.cc @@ -49,7 +49,8 @@ void assert_null(deno_pinned_buf b) { TEST(LibDenoTest, RecvReturnEmpty) { static int count = 0; - auto recv_cb = [](auto _, auto buf, auto zero_copy_buf) { + auto recv_cb = [](auto _, deno_op_id op_id, auto buf, auto zero_copy_buf) { + EXPECT_EQ(op_id, 42u); assert_null(zero_copy_buf); count++; EXPECT_EQ(static_cast<size_t>(3), buf.data_len); @@ -64,9 +65,43 @@ TEST(LibDenoTest, RecvReturnEmpty) { deno_delete(d); } +TEST(LibDenoTest, BasicRecv) { + static int count = 0; + auto recv_cb = [](auto user_data, deno_op_id op_id, auto buf, + auto zero_copy_buf) { + EXPECT_EQ(op_id, 42u); + // auto d = reinterpret_cast<Deno*>(user_data); + assert_null(zero_copy_buf); + count++; + EXPECT_EQ(static_cast<size_t>(3), buf.data_len); + EXPECT_EQ(buf.data_ptr[0], 1); + EXPECT_EQ(buf.data_ptr[1], 2); + EXPECT_EQ(buf.data_ptr[2], 3); + }; + Deno* d = deno_new(deno_config{0, snapshot, empty, recv_cb, nullptr}); + deno_execute(d, d, "a.js", "BasicRecv()"); + EXPECT_EQ(nullptr, deno_last_exception(d)); + EXPECT_EQ(count, 1); + deno_check_promise_errors(d); + EXPECT_EQ(deno_last_exception(d), nullptr); + { + deno_lock(d); + uint8_t response[] = {'b', 'a', 'r'}; + deno_respond(d, nullptr, 43, {response, sizeof response}); + deno_unlock(d); + } + EXPECT_EQ(count, 2); + EXPECT_EQ(nullptr, deno_last_exception(d)); + deno_check_promise_errors(d); + EXPECT_EQ(deno_last_exception(d), nullptr); + deno_delete(d); +} + TEST(LibDenoTest, RecvReturnBar) { static int count = 0; - auto recv_cb = [](auto user_data, auto buf, auto zero_copy_buf) { + auto recv_cb = [](auto user_data, deno_op_id op_id, auto buf, + auto zero_copy_buf) { + EXPECT_EQ(op_id, 42u); auto d = reinterpret_cast<Deno*>(user_data); assert_null(zero_copy_buf); count++; @@ -75,7 +110,7 @@ TEST(LibDenoTest, RecvReturnBar) { EXPECT_EQ(buf.data_ptr[1], 'b'); EXPECT_EQ(buf.data_ptr[2], 'c'); uint8_t response[] = {'b', 'a', 'r'}; - deno_respond(d, user_data, {response, sizeof response}); + deno_respond(d, user_data, op_id, {response, sizeof response}); }; Deno* d = deno_new(deno_config{0, snapshot, empty, recv_cb, nullptr}); deno_execute(d, d, "a.js", "RecvReturnBar()"); @@ -126,8 +161,9 @@ TEST(LibDenoTest, GlobalErrorHandling) { TEST(LibDenoTest, ZeroCopyBuf) { static int count = 0; static deno_pinned_buf zero_copy_buf2; - auto recv_cb = [](auto user_data, deno_buf buf, + auto recv_cb = [](auto user_data, deno_op_id op_id, deno_buf buf, deno_pinned_buf zero_copy_buf) { + EXPECT_EQ(op_id, 42u); count++; EXPECT_NE(zero_copy_buf.pin, nullptr); zero_copy_buf.data_ptr[0] = 4; @@ -155,7 +191,9 @@ TEST(LibDenoTest, ZeroCopyBuf) { TEST(LibDenoTest, CheckPromiseErrors) { static int count = 0; - auto recv_cb = [](auto _, auto buf, auto zero_copy_buf) { count++; }; + auto recv_cb = [](auto _, deno_op_id op_id, auto buf, auto zero_copy_buf) { + count++; + }; Deno* d = deno_new(deno_config{0, snapshot, empty, recv_cb, nullptr}); EXPECT_EQ(deno_last_exception(d), nullptr); deno_execute(d, nullptr, "a.js", "CheckPromiseErrors()"); @@ -264,7 +302,8 @@ TEST(LibDenoTest, SharedAtomics) { TEST(LibDenoTest, WasmInstantiate) { static int count = 0; - auto recv_cb = [](auto _, auto buf, auto zero_copy_buf) { + auto recv_cb = [](auto _, deno_op_id op_id, auto buf, auto zero_copy_buf) { + EXPECT_EQ(op_id, 42u); EXPECT_EQ(buf.data_len, 1u); EXPECT_EQ(buf.data_ptr[0], 42); count++; diff --git a/core/libdeno/libdeno_test.js b/core/libdeno/libdeno_test.js index 006c71666..1c7655391 100644 --- a/core/libdeno/libdeno_test.js +++ b/core/libdeno/libdeno_test.js @@ -28,15 +28,30 @@ global.TypedArraySnapshots = () => { global.RecvReturnEmpty = () => { const m1 = new Uint8Array("abc".split("").map(c => c.charCodeAt(0))); const m2 = m1.slice(); - const r1 = Deno.core.send(m1); + const r1 = Deno.core.send(42, m1); assert(r1 == null); - const r2 = Deno.core.send(m2); + const r2 = Deno.core.send(42, m2); assert(r2 == null); }; +global.BasicRecv = () => { + const m = new Uint8Array([1, 2, 3]); + Deno.core.recv((opId, buf) => { + assert(opId === 43); + assert(buf instanceof Uint8Array); + assert(buf.byteLength === 3); + const s = String.fromCharCode(...buf); + assert(s === "bar"); + const r = Deno.core.send(42, m); + assert(!r); // async + }); + const r = Deno.core.send(42, m); + assert(!r); // async +}; + global.RecvReturnBar = () => { const m = new Uint8Array("abc".split("").map(c => c.charCodeAt(0))); - const r = Deno.core.send(m); + const r = Deno.core.send(42, m); assert(r instanceof Uint8Array); assert(r.byteLength === 3); const rstr = String.fromCharCode(...r); @@ -58,7 +73,7 @@ global.SendRecvSlice = () => { buf[0] = 100 + i; buf[buf.length - 1] = 100 - i; // On the native side, the slice is shortened by 19 bytes. - buf = Deno.core.send(buf); + buf = Deno.core.send(42, buf); assert(buf.byteOffset === i * 11); assert(buf.byteLength === abLen - i * 30 - 19); assert(buf.buffer.byteLength == abLen); @@ -78,17 +93,17 @@ global.JSSendArrayBufferViewTypes = () => { const ab1 = new ArrayBuffer(4321); const u8 = new Uint8Array(ab1, 2468, 1000); u8[0] = 1; - Deno.core.send(u8); + Deno.core.send(42, u8); // Send Uint32Array. const ab2 = new ArrayBuffer(4321); const u32 = new Uint32Array(ab2, 2468, 1000 / Uint32Array.BYTES_PER_ELEMENT); u32[0] = 0x02020202; - Deno.core.send(u32); + Deno.core.send(42, u32); // Send DataView. const ab3 = new ArrayBuffer(4321); const dv = new DataView(ab3, 2468, 1000); dv.setUint8(0, 3); - Deno.core.send(dv); + Deno.core.send(42, dv); }; // The following join has caused SnapshotBug to segfault when using kKeep. @@ -110,7 +125,7 @@ global.ZeroCopyBuf = () => { const b = zeroCopyBuf; // The second parameter of send should modified by the // privileged side. - const r = Deno.core.send(a, b); + const r = Deno.core.send(42, a, b); assert(r == null); // b is different. assert(b[0] === 4); @@ -129,7 +144,7 @@ global.CheckPromiseErrors = () => { try { await fn(); } catch (e) { - Deno.core.send(new Uint8Array([42])); + Deno.core.send(42, new Uint8Array([42])); } })(); }; @@ -239,17 +254,17 @@ global.WasmInstantiate = () => { ]); (async () => { - Deno.core.send(new Uint8Array([42])); + Deno.core.send(42, new Uint8Array([42])); const wasm = await WebAssembly.instantiate(bytes); - Deno.core.send(new Uint8Array([42])); + Deno.core.send(42, new Uint8Array([42])); const result = wasm.instance.exports.add(1, 3); if (result != 4) { throw Error("bad"); } // To signal success, we send back a fixed buffer. - Deno.core.send(new Uint8Array([42])); + Deno.core.send(42, new Uint8Array([42])); })(); }; diff --git a/core/libdeno/modules_test.cc b/core/libdeno/modules_test.cc index 987e88791..e11231528 100644 --- a/core/libdeno/modules_test.cc +++ b/core/libdeno/modules_test.cc @@ -2,9 +2,11 @@ #include "test.h" static int exec_count = 0; -void recv_cb(void* user_data, deno_buf buf, deno_pinned_buf zero_copy_buf) { +void recv_cb(void* user_data, deno_op_id op_id, deno_buf buf, + deno_pinned_buf zero_copy_buf) { // We use this to check that scripts have executed. EXPECT_EQ(1u, buf.data_len); + EXPECT_EQ(42u, op_id); EXPECT_EQ(buf.data_ptr[0], 4); EXPECT_EQ(zero_copy_buf.data_ptr, nullptr); EXPECT_EQ(zero_copy_buf.data_len, 0u); @@ -20,7 +22,7 @@ TEST(ModulesTest, Resolution) { static deno_mod a = deno_mod_new(d, true, "a.js", "import { b } from 'b.js'\n" "if (b() != 'b') throw Error();\n" - "Deno.core.send(new Uint8Array([4]));"); + "Deno.core.send(42, new Uint8Array([4]));"); EXPECT_NE(a, 0); EXPECT_EQ(nullptr, deno_last_exception(d)); @@ -72,7 +74,7 @@ TEST(ModulesTest, ResolutionError) { static deno_mod a = deno_mod_new(d, true, "a.js", "import 'bad'\n" - "Deno.core.send(new Uint8Array([4]));"); + "Deno.core.send(42, new Uint8Array([4]));"); EXPECT_NE(a, 0); EXPECT_EQ(nullptr, deno_last_exception(d)); @@ -106,7 +108,7 @@ TEST(ModulesTest, ImportMetaUrl) { static deno_mod a = deno_mod_new(d, true, "a.js", "if ('a.js' != import.meta.url) throw 'hmm'\n" - "Deno.core.send(new Uint8Array([4]));"); + "Deno.core.send(42, new Uint8Array([4]));"); EXPECT_NE(a, 0); EXPECT_EQ(nullptr, deno_last_exception(d)); @@ -165,7 +167,7 @@ TEST(ModulesTest, DynamicImportSuccess) { " let mod = await import('foo'); \n" " assert(mod.b() === 'b'); \n" // Send a message to signify that we're done. - " Deno.core.send(new Uint8Array([4])); \n" + " Deno.core.send(42, new Uint8Array([4])); \n" "})(); \n"; Deno* d = deno_new(deno_config{0, snapshot, empty, recv_cb, dyn_import_cb}); static deno_mod a = deno_mod_new(d, true, "a.js", src); @@ -206,7 +208,7 @@ TEST(ModulesTest, DynamicImportError) { "(async () => { \n" " let mod = await import('foo'); \n" // The following should be unreachable. - " Deno.core.send(new Uint8Array([4])); \n" + " Deno.core.send(42, new Uint8Array([4])); \n" "})(); \n"; Deno* d = deno_new(deno_config{0, snapshot, empty, recv_cb, dyn_import_cb}); static deno_mod a = deno_mod_new(d, true, "a.js", src); @@ -249,7 +251,7 @@ TEST(ModulesTest, DynamicImportAsync) { " mod = await import('foo'); \n" " assert(mod.b() === 'b'); \n" // Send a message to signify that we're done. - " Deno.core.send(new Uint8Array([4])); \n" + " Deno.core.send(42, new Uint8Array([4])); \n" "})(); \n"; Deno* d = deno_new(deno_config{0, snapshot, empty, recv_cb, dyn_import_cb}); static deno_mod a = deno_mod_new(d, true, "a.js", src); @@ -327,7 +329,7 @@ TEST(ModulesTest, DynamicImportThrows) { "(async () => { \n" " let mod = await import('b.js'); \n" // unreachable - " Deno.core.send(new Uint8Array([4])); \n" + " Deno.core.send(42, new Uint8Array([4])); \n" "})(); \n"; static deno_mod a = deno_mod_new(d, true, "a.js", a_src); EXPECT_NE(a, 0); @@ -401,7 +403,7 @@ TEST(ModulesTest, DynamicImportSyntaxError) { "(async () => { \n" " let mod = await import('b.js'); \n" // unreachable - " Deno.core.send(new Uint8Array([4])); \n" + " Deno.core.send(42, new Uint8Array([4])); \n" "})(); \n"; static deno_mod a = deno_mod_new(d, true, "a.js", src); EXPECT_NE(a, 0); |