diff --git a/deno2/deno.cc b/deno2/deno.cc index e158a0e9a37c96..c21dc43c027dbf 100644 --- a/deno2/deno.cc +++ b/deno2/deno.cc @@ -144,17 +144,12 @@ void Pub(const v8::FunctionCallbackInfo& args) { auto retbuf = d->cb(d, deno_buf{buf, buflen}); if (retbuf.data) { - auto ab = v8::ArrayBuffer::New(d->isolate, retbuf.data, retbuf.len, - v8::ArrayBufferCreationMode::kInternalized); - /* - // I'm slightly worried the above v8::ArrayBuffer construction leaks memory - // the following might be a safer way to do it. + // TODO(ry) Support zero-copy. auto ab = v8::ArrayBuffer::New(d->isolate, retbuf.len); - auto contents = ab->GetContents(); - memcpy(contents.Data(), retbuf.data, retbuf.len); - free(retbuf.data); - */ + memcpy(ab->GetContents().Data(), retbuf.data, retbuf.len); args.GetReturnValue().Set(handle_scope.Escape(ab)); + } else { + args.GetReturnValue().Set(v8::Null(d->isolate)); } } @@ -207,7 +202,8 @@ v8::StartupData MakeSnapshot(v8::StartupData* prev_natives_blob, v8::Context::Scope context_scope(context); auto global = context->Global(); - + // TODO(ry) Add a global namespace object "deno" and move print, sub, and + // pub inside that object. auto print_tmpl = v8::FunctionTemplate::New(isolate, Print); auto print_val = print_tmpl->GetFunction(context).ToLocalChecked(); CHECK( diff --git a/deno2/js/mock_runtime.js b/deno2/js/mock_runtime.js index b3ec7f03487206..97688a08d9dd0c 100644 --- a/deno2/js/mock_runtime.js +++ b/deno2/js/mock_runtime.js @@ -1,18 +1,42 @@ // A simple runtime that doesn't involve typescript or protobufs to test // libdeno. const window = eval("this"); -window['foo'] = () => { +window["foo"] = () => { deno_print("Hello world from foo"); return "foo"; -} +}; function assert(cond) { if (!cond) throw Error("mock_runtime.js assert failed"); } function subabc() { - deno_sub((msg) => { + deno_sub(msg => { assert(msg instanceof ArrayBuffer); assert(msg.byteLength === 3); }); } + +function typedArrayToArrayBuffer(ta) { + return ta.buffer.slice(ta.byteOffset, ta.byteOffset + ta.byteLength); +} + +function pubReturnEmpty() { + const ui8 = new Uint8Array("abc".split("").map(c => c.charCodeAt(0))); + const ab = typedArrayToArrayBuffer(ui8); + let r = deno_pub(ab); + assert(r == null); + r = deno_pub(ab); + assert(r == null); +} + +function pubReturnBar() { + const ui8 = new Uint8Array("abc".split("").map(c => c.charCodeAt(0))); + const ab = typedArrayToArrayBuffer(ui8); + const r = deno_pub(ab); + assert(r instanceof ArrayBuffer); + assert(r.byteLength === 3); + const rui8 = new Uint8Array(r); + const rstr = String.fromCharCode(...rui8); + assert(rstr === "bar"); +} diff --git a/deno2/mock_runtime_test.cc b/deno2/mock_runtime_test.cc index 1d8a6545747af0..6f6688f48e96ab 100644 --- a/deno2/mock_runtime_test.cc +++ b/deno2/mock_runtime_test.cc @@ -49,6 +49,40 @@ TEST(MockRuntimeTest, PubNoCallback) { deno_dispose(d); } +TEST(MockRuntimeTest, SubReturnEmpty) { + static int count = 0; + Deno* d = deno_new(NULL, [](Deno* _, deno_buf buf) { + count++; + EXPECT_EQ(static_cast(3), buf.len); + // TODO(ry) buf.data should just be a char*. + char* data = reinterpret_cast(buf.data); + EXPECT_EQ(data[0], 'a'); + EXPECT_EQ(data[1], 'b'); + EXPECT_EQ(data[2], 'c'); + return deno_buf{nullptr, 0}; + }); + EXPECT_TRUE(deno_load(d, "a.js", "pubReturnEmpty()")); + EXPECT_EQ(count, 2); + deno_dispose(d); +} + +TEST(MockRuntimeTest, SubReturnBar) { + static int count = 0; + Deno* d = deno_new(NULL, [](Deno* _, deno_buf buf) { + count++; + EXPECT_EQ(static_cast(3), buf.len); + // TODO(ry) buf.data should just be a char*. + char* data = reinterpret_cast(buf.data); + EXPECT_EQ(data[0], 'a'); + EXPECT_EQ(data[1], 'b'); + EXPECT_EQ(data[2], 'c'); + return strbuf("bar"); + }); + EXPECT_TRUE(deno_load(d, "a.js", "pubReturnBar()")); + EXPECT_EQ(count, 1); + deno_dispose(d); +} + int main(int argc, char** argv) { testing::InitGoogleTest(&argc, argv); deno_init();