From 4ac67cf3435b3e15f95fadc20c98e37abf706ea4 Mon Sep 17 00:00:00 2001 From: Ryan Dahl Date: Wed, 13 Jun 2018 19:38:22 +0200 Subject: [PATCH] Demo protobufs in deno2. Adds deno_set_response() to allow stack allocated responses. --- deno2/BUILD.gn | 9 ++++++--- deno2/deno.cc | 22 +++++++++++++--------- deno2/deno_internal.h | 1 + deno2/from_snapshot.cc | 1 + deno2/include/deno.h | 8 ++++++-- deno2/js/main.ts | 31 ++++++++++++++++++++++++++----- deno2/main.cc | 22 +++++++++++++++++++++- deno2/mock_runtime_test.cc | 23 +++++++++++------------ deno2/snapshot_creator.cc | 4 ++-- deno2/tools/lint.sh | 2 +- 10 files changed, 88 insertions(+), 35 deletions(-) diff --git a/deno2/BUILD.gn b/deno2/BUILD.gn index 7b358e7c68..564d8f8fb6 100644 --- a/deno2/BUILD.gn +++ b/deno2/BUILD.gn @@ -8,6 +8,8 @@ executable("deno") { ] deps = [ ":libdeno", + ":msg_proto", + "//third_party/protobuf:protoc_lib", ] } @@ -45,7 +47,6 @@ source_set("deno_nosnapshot") { ] include_dirs = [ "include/" ] deps = [ - ":msg_proto", "v8:v8", "v8:v8_libbase", "v8:v8_libplatform", @@ -66,6 +67,7 @@ proto_library("msg_proto") { sources = [ "msg.proto", ] + generate_python = false } template("run_node") { @@ -78,13 +80,15 @@ template("run_node") { run_node("bundle") { out_dir = "$target_gen_dir/bundle/" sources = [ - "$target_gen_dir/tsc_dist/main.js", # Not real input. See run_tsc comment. "js/main.ts", + "js/msg.pb.d.ts", + "js/msg.pb.js", ] outputs = [ out_dir + "main.js", ] deps = [ + ":protobufjs", ":run_tsc", ] args = [ @@ -111,7 +115,6 @@ run_node("run_tsc") { ] outputs = [ out_dir + "/main.js", - out_dir + "/main.map", ] deps = [ ":protobufjs", diff --git a/deno2/deno.cc b/deno2/deno.cc index 27dfefb8e7..d59f490655 100644 --- a/deno2/deno.cc +++ b/deno2/deno.cc @@ -154,15 +154,12 @@ void Pub(const v8::FunctionCallbackInfo& args) { const_cast(reinterpret_cast(contents.Data())); deno_buf buf{data, contents.ByteLength()}; - auto retbuf = d->cb(d, channel, buf); - if (retbuf.data) { - // TODO(ry) Support zero-copy. - auto ab = v8::ArrayBuffer::New(d->isolate, retbuf.len); - memcpy(ab->GetContents().Data(), retbuf.data, retbuf.len); - args.GetReturnValue().Set(handle_scope.Escape(ab)); - } else { - args.GetReturnValue().Set(v8::Null(d->isolate)); - } + assert(d->currentArgs == nullptr); + d->currentArgs = &args; + + d->cb(d, channel, buf); + + d->currentArgs = nullptr; } bool Execute(v8::Local context, const char* js_filename, @@ -334,6 +331,13 @@ bool deno_pub(Deno* d, const char* channel, deno_buf buf) { return true; } +void deno_set_response(Deno* d, deno_buf buf) { + // TODO(ry) Support zero-copy. + auto ab = v8::ArrayBuffer::New(d->isolate, buf.len); + memcpy(ab->GetContents().Data(), buf.data, buf.len); + d->currentArgs->GetReturnValue().Set(ab); +} + void deno_delete(Deno* d) { d->isolate->Dispose(); delete d; diff --git a/deno2/deno_internal.h b/deno2/deno_internal.h index 2ecd5d1f47..0c3d4fd779 100644 --- a/deno2/deno_internal.h +++ b/deno2/deno_internal.h @@ -11,6 +11,7 @@ extern "C" { // deno_s = Wrapped Isolate. struct deno_s { v8::Isolate* isolate; + const v8::FunctionCallbackInfo* currentArgs; std::string last_exception; v8::Persistent sub; v8::Persistent context; diff --git a/deno2/from_snapshot.cc b/deno2/from_snapshot.cc index 68185ce6da..5f954dc096 100644 --- a/deno2/from_snapshot.cc +++ b/deno2/from_snapshot.cc @@ -45,6 +45,7 @@ Deno* NewFromSnapshot(void* data, deno_sub_cb cb) { v8::DeserializeInternalFieldsCallback(DeserializeInternalFields, nullptr); Deno* d = new Deno; + d->currentArgs = nullptr; d->cb = cb; d->data = data; v8::Isolate::CreateParams params; diff --git a/deno2/include/deno.h b/deno2/include/deno.h index 3c42abd72f..72318677af 100644 --- a/deno2/include/deno.h +++ b/deno2/include/deno.h @@ -19,8 +19,7 @@ typedef struct deno_s Deno; // A callback to receive a message from deno_pub javascript call. // buf is valid only for the lifetime of the call. -// The returned deno_buf is returned from deno_pub in javascript. -typedef deno_buf (*deno_sub_cb)(Deno* d, const char* channel, deno_buf buf); +typedef void (*deno_sub_cb)(Deno* d, const char* channel, deno_buf buf); void deno_init(); const char* deno_v8_version(); @@ -37,6 +36,11 @@ bool deno_execute(Deno* d, const char* js_filename, const char* js_source); // value indicates error. Check deno_last_exception() for exception text. bool deno_pub(Deno* d, const char* channel, deno_buf buf); +// Call this inside a deno_sub_cb to respond synchronously to messages. +// If this is not called during the life time of a deno_sub_cb callback +// the denoPub() call in javascript will return null. +void deno_set_response(Deno* d, deno_buf buf); + const char* deno_last_exception(Deno* d); void deno_terminate_execution(Deno* d); diff --git a/deno2/js/main.ts b/deno2/js/main.ts index c5d490b0b8..7508132937 100644 --- a/deno2/js/main.ts +++ b/deno2/js/main.ts @@ -4,11 +4,32 @@ import * as ts from "typescript"; const globalEval = eval; const window = globalEval("this"); + window["denoMain"] = () => { - denoPrint("Hello world"); - const msg = pb.Msg.fromObject({}); - denoPrint(`msg.command: ${msg.command}`); denoPrint(`ts.version: ${ts.version}`); - denoPrint("Hello world from foo"); - return "foo"; + const res = denoPub("startDeno2", emptyArrayBuffer()); + //denoPrint(`after`); + const resUi8 = new Uint8Array(res); + denoPrint(`before`); + const msg = pb.Msg.decode(resUi8); + denoPrint(`after`); + const { + startCwd: cwd, + startArgv: argv, + startDebugFlag: debugFlag, + startMainJs: mainJs, + startMainMap: mainMap + } = msg; + denoPrint(`cwd: ${cwd}`); }; + +function typedArrayToArrayBuffer(ta: Uint8Array): ArrayBuffer { + return ta.buffer.slice( + ta.byteOffset, + ta.byteOffset + ta.byteLength + ) as ArrayBuffer; +} + +function emptyArrayBuffer(): ArrayBuffer { + return typedArrayToArrayBuffer(new Uint8Array([])); +} diff --git a/deno2/main.cc b/deno2/main.cc index 2c0b1b2983..506469dfa1 100644 --- a/deno2/main.cc +++ b/deno2/main.cc @@ -3,13 +3,33 @@ #include #include #include +#include +#include +#include "./msg.pb.h" #include "include/deno.h" +void MessagesFromJS(Deno* d, const char* channel, deno_buf buf) { + printf("MessagesFromJS %s\n", channel); + + char cwdbuf[1024]; + std::string cwd(getcwd(cwdbuf, sizeof(cwdbuf))); + + deno::Msg response; + response.set_command(deno::Msg_Command_START); + response.set_start_cwd(cwd); + + std::string output; + assert(response.SerializeToString(&output) == true); + + auto bufout = deno_buf{output.c_str(), output.length()}; + deno_set_response(d, bufout); +} + int main(int argc, char** argv) { deno_init(); - Deno* d = deno_new(NULL, NULL); + Deno* d = deno_new(NULL, MessagesFromJS); bool r = deno_execute(d, "deno_main.js", "denoMain();"); if (!r) { printf("Error! %s\n", deno_last_exception(d)); diff --git a/deno2/mock_runtime_test.cc b/deno2/mock_runtime_test.cc index bdaf30416a..908e2a7e69 100644 --- a/deno2/mock_runtime_test.cc +++ b/deno2/mock_runtime_test.cc @@ -5,20 +5,20 @@ #include "include/deno.h" TEST(MockRuntimeTest, InitializesCorrectly) { - Deno* d = deno_new(NULL, NULL); + Deno* d = deno_new(nullptr, nullptr); EXPECT_TRUE(deno_execute(d, "a.js", "1 + 2")); deno_delete(d); } TEST(MockRuntimeTest, CanCallFunction) { - Deno* d = deno_new(NULL, NULL); + Deno* d = deno_new(nullptr, nullptr); EXPECT_TRUE(deno_execute(d, "a.js", "if (CanCallFunction() != 'foo') throw Error();")); deno_delete(d); } TEST(MockRuntimeTest, ErrorsCorrectly) { - Deno* d = deno_new(NULL, NULL); + Deno* d = deno_new(nullptr, nullptr); EXPECT_FALSE(deno_execute(d, "a.js", "throw Error()")); deno_delete(d); } @@ -26,14 +26,14 @@ TEST(MockRuntimeTest, ErrorsCorrectly) { deno_buf strbuf(const char* str) { return deno_buf{str, strlen(str)}; } TEST(MockRuntimeTest, PubSuccess) { - Deno* d = deno_new(NULL, NULL); + Deno* d = deno_new(nullptr, nullptr); EXPECT_TRUE(deno_execute(d, "a.js", "PubSuccess()")); EXPECT_TRUE(deno_pub(d, "PubSuccess", strbuf("abc"))); deno_delete(d); } TEST(MockRuntimeTest, PubByteLength) { - Deno* d = deno_new(NULL, NULL); + Deno* d = deno_new(nullptr, nullptr); EXPECT_TRUE(deno_execute(d, "a.js", "PubByteLength()")); // We pub the wrong sized message, it should throw. EXPECT_FALSE(deno_pub(d, "PubByteLength", strbuf("abcd"))); @@ -41,7 +41,7 @@ TEST(MockRuntimeTest, PubByteLength) { } TEST(MockRuntimeTest, PubNoCallback) { - Deno* d = deno_new(NULL, NULL); + Deno* d = deno_new(nullptr, nullptr); // We didn't call deno_sub(), pubing should fail. EXPECT_FALSE(deno_pub(d, "PubNoCallback", strbuf("abc"))); deno_delete(d); @@ -49,14 +49,13 @@ TEST(MockRuntimeTest, PubNoCallback) { TEST(MockRuntimeTest, SubReturnEmpty) { static int count = 0; - Deno* d = deno_new(NULL, [](auto _, auto channel, auto buf) { + Deno* d = deno_new(nullptr, [](auto _, auto channel, auto buf) { count++; EXPECT_STREQ(channel, "SubReturnEmpty"); EXPECT_EQ(static_cast(3), buf.len); EXPECT_EQ(buf.data[0], 'a'); EXPECT_EQ(buf.data[1], 'b'); EXPECT_EQ(buf.data[2], 'c'); - return deno_buf{nullptr, 0}; }); EXPECT_TRUE(deno_execute(d, "a.js", "SubReturnEmpty()")); EXPECT_EQ(count, 2); @@ -65,14 +64,14 @@ TEST(MockRuntimeTest, SubReturnEmpty) { TEST(MockRuntimeTest, SubReturnBar) { static int count = 0; - Deno* d = deno_new(NULL, [](auto _, auto channel, auto buf) { + Deno* d = deno_new(nullptr, [](auto deno, auto channel, auto buf) { count++; EXPECT_STREQ(channel, "SubReturnBar"); EXPECT_EQ(static_cast(3), buf.len); EXPECT_EQ(buf.data[0], 'a'); EXPECT_EQ(buf.data[1], 'b'); EXPECT_EQ(buf.data[2], 'c'); - return strbuf("bar"); + deno_set_response(deno, strbuf("bar")); }); EXPECT_TRUE(deno_execute(d, "a.js", "SubReturnBar()")); EXPECT_EQ(count, 1); @@ -80,13 +79,13 @@ TEST(MockRuntimeTest, SubReturnBar) { } TEST(MockRuntimeTest, DoubleSubFails) { - Deno* d = deno_new(NULL, NULL); + Deno* d = deno_new(nullptr, nullptr); EXPECT_FALSE(deno_execute(d, "a.js", "DoubleSubFails()")); deno_delete(d); } TEST(MockRuntimeTest, TypedArraySnapshots) { - Deno* d = deno_new(NULL, NULL); + Deno* d = deno_new(nullptr, nullptr); EXPECT_TRUE(deno_execute(d, "a.js", "TypedArraySnapshots()")); deno_delete(d); } diff --git a/deno2/snapshot_creator.cc b/deno2/snapshot_creator.cc index 1cd39cce54..10ddc15002 100644 --- a/deno2/snapshot_creator.cc +++ b/deno2/snapshot_creator.cc @@ -136,8 +136,8 @@ int main(int argc, char** argv) { auto snapshot_in_blob = ReadFile(snapshot_in_bin); deno_init(); - auto snapshot_blob = - deno::MakeSnapshot(&natives_blob, &snapshot_in_blob, js_fn, js_source.c_str()); + auto snapshot_blob = deno::MakeSnapshot(&natives_blob, &snapshot_in_blob, + js_fn, js_source.c_str()); StartupDataCppWriter nativesWriter("natives", natives_out_cc, natives_blob); nativesWriter.Write(); diff --git a/deno2/tools/lint.sh b/deno2/tools/lint.sh index ed7831e297..64a452f0aa 100755 --- a/deno2/tools/lint.sh +++ b/deno2/tools/lint.sh @@ -1,4 +1,4 @@ #!/bin/sh cd `dirname "$0"`/.. set -e -v -cpplint --repository=. *.cc *.h include/*.h +cpplint --filter=-build/include_subdir --repository=. *.cc *.h include/*.h