summaryrefslogtreecommitdiff
path: root/core/libdeno
diff options
context:
space:
mode:
Diffstat (limited to 'core/libdeno')
-rw-r--r--core/libdeno/api.cc10
-rw-r--r--core/libdeno/binding.cc17
-rw-r--r--core/libdeno/deno.h30
-rw-r--r--core/libdeno/libdeno.d.ts3
-rw-r--r--core/libdeno/libdeno_test.cc51
-rw-r--r--core/libdeno/libdeno_test.js39
-rw-r--r--core/libdeno/modules_test.cc20
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);