Add deno2 prototype from external repo.

This commit is contained in:
Ryan Dahl 2018-06-10 00:32:04 +02:00
parent fe9ea6dcf8
commit 110ddab670
24 changed files with 4668 additions and 0 deletions

38
deno2/.gclient Normal file
View file

@ -0,0 +1,38 @@
solutions = [{
'url': 'https://chromium.googlesource.com/v8/v8.git',
'custom_vars': {
'build_for_node': True
},
'name': 'v8',
'deps_file': 'DEPS',
'custom_deps': {
'v8/third_party/catapult': None,
'v8/third_party/colorama/src': None,
'v8/testing/gmock': None,
'v8/tools/swarming_client': None,
'v8/third_party/instrumented_libraries': None,
'v8/tools/gyp': None,
'v8/third_party/android_tools': None,
'v8/test/wasm-js': None,
'v8/test/benchmarks/data': None,
'v8/test/mozilla/data': None,
'v8/third_party/icu': None,
'v8/test/test262/data': None,
'v8/test/test262/harness': None,
'v8/tools/luci-go': None
}
}, {
'url': 'https://github.com/ry/protobuf_chromium.git',
'name': 'third_party/protobuf',
'deps_file': 'DEPS'
}, {
'url':
'https://chromium.googlesource.com/chromium/src/tools/protoc_wrapper',
'name':
'tools/protoc_wrapper'
}, {
'url':
'https://chromium.googlesource.com/chromium/src/third_party/zlib',
'name':
'third_party/zlib'
}]

8
deno2/.gitignore vendored Normal file
View file

@ -0,0 +1,8 @@
out/
js/.cache/
js/node_modules/
v8/
tools/protoc_wrapper/
third_party/protobuf/
third_party/zlib/
.gclient_entries

61
deno2/.gn Normal file
View file

@ -0,0 +1,61 @@
# This file is used by the GN meta build system to find the root of the source
# tree and to set startup options. For documentation on the values set in this
# file, run "gn help dotfile" at the command line.
import("//v8/build/dotfile_settings.gni")
# The location of the build configuration file.
buildconfig = "//v8/build/config/BUILDCONFIG.gn"
# The secondary source root is a parallel directory tree where
# GN build files are placed when they can not be placed directly
# in the source tree, e.g. for third party source trees.
secondary_source = "//v8/"
# These are the targets to check headers for by default. The files in targets
# matching these patterns (see "gn help label_pattern" for format) will have
# their includes checked for proper dependencies when you run either
# "gn check" or "gn gen --check".
check_targets = []
# These are the list of GN files that run exec_script. This whitelist exists
# to force additional review for new uses of exec_script, which is strongly
# discouraged except for gypi_to_gn calls.
exec_script_whitelist = build_dotfile_settings.exec_script_whitelist + []
default_args = {
# Default to release builds for this project.
is_component_build = false
is_debug = false
libcpp_is_static = false
symbol_level = 1
treat_warnings_as_errors = false
use_custom_libcxx = false
use_sysroot = false
v8_deprecation_warnings = false
#v8_embedder_string = ""
v8_enable_gdbjit = false
v8_enable_i18n_support = false
v8_enable_test_features = false
v8_experimental_extra_library_files = []
v8_extra_library_files = []
v8_imminent_deprecation_warnings = false
v8_monolithic = false
v8_static_library = false
v8_target_cpu = "x64"
v8_untrusted_code_mitigations = false
# This tells V8 to write out/Default/gen/v8/snapshot.bin
# Which we can use to build our own snapshot.
v8_use_external_startup_data = true
v8_use_snapshot = true
# Snapshot the dist/main.js bundle into V8.
# Is ".gn" really the most appropriate place to specify this important
# value? This is how they do it in Chrome.
# https://cs.chromium.org/chromium/src/.gn?l=37&rcl=f1c8c3cf8bd4a63da6433ee67e2ff5ecbbdb4316
# "$target_gen_dir/main.js"
#]
}

134
deno2/BUILD.gn Normal file
View file

@ -0,0 +1,134 @@
import("//third_party/protobuf/proto_library.gni")
import("//v8/gni/v8.gni")
import("//v8/snapshot_toolchain.gni")
proto_library("msg_proto") {
sources = [
"msg.proto",
]
}
action("run_parcel") {
sources = [
"js/main.ts",
]
outputs = [
"$target_gen_dir/main.js",
"$target_gen_dir/main.map",
]
# Our script imports this Python file so we want to rebuild if it changes.
# inputs = [ "helper_library.py" ]
# Note that we have to manually pass the sources to our script if the
# script needs them as inputs.
script = "js/run_node.py"
root = root_build_dir + "/../../js"
args = [
"./node_modules/.bin/parcel",
"build",
"--log-level=1",
"--no-minify",
"--out-dir=" + rebase_path(target_gen_dir, root),
] + rebase_path(sources, root)
}
# Template to generate different V8 snapshots based on different runtime flags.
# Can be invoked with run_mksnapshot(<name>). The target will resolve to
# run_mksnapshot_<name>. If <name> is "default", no file suffixes will be used.
# Otherwise files are suffixed, e.g. embedded_<name>.cc and
# snapshot_blob_<name>.bin.
#
# The template exposes the variables:
# args: additional flags for mksnapshots
# embedded_suffix: a camel case suffix for method names in the embedded
# snapshot.
template("create_snapshot") {
name = target_name
suffix = "_$name"
action("create_snapshot_" + name) {
visibility = [ ":*" ] # Only targets in this file can depend on this.
deps = [ ":snapshot_creator" ] + invoker.deps
script = "v8/tools/run.py"
data = []
exe = rebase_path(get_label_info(":snapshot_creator", "root_out_dir") +
"/snapshot_creator")
natives_in_bin = "$root_out_dir/natives_blob.bin"
snapshot_in_bin = "$root_out_dir/snapshot_blob.bin"
natives_out_cc = "$target_gen_dir/natives${suffix}.cc"
snapshot_out_cc = "$target_gen_dir/snapshot${suffix}.cc"
sources = [
invoker.js,
]
outputs = [
natives_out_cc,
snapshot_out_cc,
]
args = [
exe,
rebase_path(invoker.js, root_build_dir),
rebase_path(natives_in_bin, root_build_dir),
rebase_path(snapshot_in_bin, root_build_dir),
rebase_path(natives_out_cc, root_build_dir),
rebase_path(snapshot_out_cc, root_build_dir),
]
data = [
invoker.js,
]
}
}
# Generates $target_gen_dir/snapshot_bundle.cc
create_snapshot("deno") {
js = "$target_gen_dir/main.js"
deps = [
":run_parcel",
]
}
v8_executable("snapshot_creator") {
sources = [
"deno.cc",
"deno.h",
"snapshot_creator.cc",
]
configs = [ "v8:libplatform_config" ]
deps = [
"v8:v8",
"v8:v8_libbase",
"v8:v8_libplatform",
"v8:v8_libsampler",
"//build/config:exe_and_shlib_deps",
"//build/win:default_exe_manifest",
]
}
v8_executable("deno") {
sources = [
"deno.cc",
"deno.h",
"main.cc",
]
include_dirs = [ target_gen_dir ]
configs = [ "v8:libplatform_config" ]
deps = [
":create_snapshot_deno",
":msg_proto",
"v8:v8",
"v8:v8_libbase",
"v8:v8_libplatform",
"v8:v8_libsampler",
"//build/config:exe_and_shlib_deps",
"//build/win:default_exe_manifest",
]
}
executable("deno_test") {
testonly = true
sources = [
"deno_test.cc",
]
deps = [
"//testing/gtest:gtest",
]
}

68
deno2/README.md Normal file
View file

@ -0,0 +1,68 @@
# Deno Prototype 2
## Status
This code is a rewrite of the unprivileged parts of Deno. It will soon become
the root of the project.
There are several goals:
* Use the gn build system for fast builds, sane configuration, and easy
linking into Chrome.
* Use V8 snapshots to improve startup time.
* Remove Golang. Although it has been working nicely, I am concerned the
double GC will become a problem sometime down the road.
* Distribute a C++ library called libdeno, containing the snapshotted
typescript runtime.
* Test the message passing and other functionality at that layer before
involving higher level languages.
The contenders for building the unprivileged part of Deno are Rust and C++.
Thanks to Chrome and gn, using C++ to link into high level libraries is not
untenable. However, there's a lot of interest in Rust in the JS community and
it seems like a reasonable choice. TBD.
There are many people exploring the project, so care will be taken to keep the
original code functional while this is developed. However, once it's ready this
the code in this deno2/ directory will be moved to the root.
## Prerequisites
Get Depot Tools and make sure it's in your path.
http://commondatastorage.googleapis.com/chrome-infra-docs/flat/depot_tools/docs/html/depot_tools_tutorial.html#_setting_up
For linux you need these prereqs:
sudo apt-get install libgtk-3-dev pkg-config ccache
## Build
First install the javascript deps.
cd js; yarn install
TODO(ry) Remove the above step by a deps submodule.
Wrapper around the gclient/gn/ninja for end users. Try this first:
./tools/build.py --use_ccache --debug
If that doesn't work, or you need more control, try calling gn manually:
gn gen out/Debug --args='cc_wrapper="ccache" is_debug=true '
Then build with ninja:
ninja -C out/Debug/ deno
Other useful commands:
gn args out/Debug/ --list # List build args
gn args out/Debug/ # Modify args in $EDITOR

1
deno2/build Symbolic link
View file

@ -0,0 +1 @@
v8/build

364
deno2/deno.cc Normal file
View file

@ -0,0 +1,364 @@
/*
Copyright 2018 Ryan Dahl <ry@tinyclouds.org>. All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to
deal in the Software without restriction, including without limitation the
rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
sell copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
IN THE SOFTWARE.
*/
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <string>
#include "v8/include/libplatform/libplatform.h"
#include "v8/include/v8.h"
#include "./deno.h"
#define CHECK(x) assert(x) // TODO(ry) use V8's CHECK.
// Extracts a C string from a v8::V8 Utf8Value.
const char* ToCString(const v8::String::Utf8Value& value) {
return *value ? *value : "<string conversion failed>";
}
static inline v8::Local<v8::String> v8_str(const char* x) {
return v8::String::NewFromUtf8(v8::Isolate::GetCurrent(), x,
v8::NewStringType::kNormal)
.ToLocalChecked();
}
// Exits the process.
void HandleException(Deno* d, v8::Local<v8::Value> exception) {
v8::HandleScope handle_scope(d->isolate);
auto context = d->context.Get(d->isolate);
v8::Context::Scope context_scope(context);
auto message = v8::Exception::CreateMessage(d->isolate, exception);
auto onerrorStr = v8::String::NewFromUtf8(d->isolate, "onerror");
auto onerror = context->Global()->Get(onerrorStr);
if (onerror->IsFunction()) {
auto func = v8::Local<v8::Function>::Cast(onerror);
v8::Local<v8::Value> args[5];
auto origin = message->GetScriptOrigin();
args[0] = exception->ToString();
args[1] = message->GetScriptResourceName();
args[2] = origin.ResourceLineOffset();
args[3] = origin.ResourceColumnOffset();
args[4] = exception;
func->Call(context->Global(), 5, args);
/* message, source, lineno, colno, error */
} else {
v8::String::Utf8Value exceptionStr(d->isolate, exception);
printf("Unhandled Exception %s\n", ToCString(exceptionStr));
message->PrintCurrentStackTrace(d->isolate, stdout);
}
exit(1);
}
/*
bool AbortOnUncaughtExceptionCallback(v8::Isolate* isolate) {
return true;
}
void MessageCallback2(Local<Message> message, v8::Local<v8::Value> data) {
printf("MessageCallback2\n\n");
}
void FatalErrorCallback2(const char* location, const char* message) {
printf("FatalErrorCallback2\n");
}
*/
void ExitOnPromiseRejectCallback(
v8::PromiseRejectMessage promise_reject_message) {
auto* isolate = v8::Isolate::GetCurrent();
Deno* d = static_cast<Deno*>(isolate->GetData(0));
assert(d->isolate == isolate);
v8::HandleScope handle_scope(d->isolate);
auto exception = promise_reject_message.GetValue();
HandleException(d, exception);
}
void Print(const v8::FunctionCallbackInfo<v8::Value>& args) {
bool first = true;
auto* isolate = args.GetIsolate();
for (int i = 0; i < args.Length(); i++) {
v8::HandleScope handle_scope(isolate);
if (first) {
first = false;
} else {
printf(" ");
}
v8::String::Utf8Value str(isolate, args[i]);
const char* cstr = ToCString(str);
printf("%s", cstr);
}
printf("\n");
fflush(stdout);
}
// Sets the recv callback.
void Recv(const v8::FunctionCallbackInfo<v8::Value>& args) {
v8::Isolate* isolate = args.GetIsolate();
Deno* d = reinterpret_cast<Deno*>(isolate->GetData(0));
assert(d->isolate == isolate);
v8::HandleScope handle_scope(isolate);
v8::Local<v8::Value> v = args[0];
assert(v->IsFunction());
v8::Local<v8::Function> func = v8::Local<v8::Function>::Cast(v);
d->recv.Reset(isolate, func);
}
// Called from JavaScript, routes message to golang.
void Send(const v8::FunctionCallbackInfo<v8::Value>& args) {
v8::Isolate* isolate = args.GetIsolate();
Deno* d = static_cast<Deno*>(isolate->GetData(0));
assert(d->isolate == isolate);
v8::Locker locker(d->isolate);
v8::EscapableHandleScope handle_scope(isolate);
v8::Local<v8::Value> v = args[0];
assert(v->IsArrayBuffer());
auto ab = v8::Local<v8::ArrayBuffer>::Cast(v);
auto contents = ab->GetContents();
void* buf = contents.Data();
int buflen = static_cast<int>(contents.ByteLength());
auto retbuf = d->cb(d, DenoBuf{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.
auto ab = v8::ArrayBuffer::New(d->isolate, retbuf.len);
auto contents = ab->GetContents();
memcpy(contents.Data(), retbuf.data, retbuf.len);
free(retbuf.data);
*/
args.GetReturnValue().Set(handle_scope.Escape(ab));
}
}
intptr_t external_references[] = {reinterpret_cast<intptr_t>(Print),
reinterpret_cast<intptr_t>(Recv),
reinterpret_cast<intptr_t>(Send), 0};
const char* v8_version() { return v8::V8::GetVersion(); }
void v8_set_flags(int* argc, char** argv) {
v8::V8::SetFlagsFromCommandLine(argc, argv, true);
}
const char* deno_last_exception(Deno* d) { return d->last_exception.c_str(); }
int deno_load(Deno* d, const char* name_s, const char* source_s) {
v8::Locker locker(d->isolate);
v8::Isolate::Scope isolate_scope(d->isolate);
v8::HandleScope handle_scope(d->isolate);
auto context = d->context.Get(d->isolate);
v8::Context::Scope context_scope(context);
v8::TryCatch try_catch(d->isolate);
auto name = v8_str(name_s);
auto source = v8_str(source_s);
v8::ScriptOrigin origin(name);
auto script = v8::Script::Compile(context, source, &origin);
if (script.IsEmpty()) {
assert(try_catch.HasCaught());
HandleException(d, try_catch.Exception());
assert(false);
return 1;
}
auto result = script.ToLocalChecked()->Run(context);
if (result.IsEmpty()) {
assert(try_catch.HasCaught());
HandleException(d, try_catch.Exception());
assert(false);
return 2;
}
return 0;
}
// Called from golang. Must route message to javascript lang.
// non-zero return value indicates error. check deno_last_exception().
int deno_send(Deno* d, DenoBuf buf) {
v8::Locker locker(d->isolate);
v8::Isolate::Scope isolate_scope(d->isolate);
v8::HandleScope handle_scope(d->isolate);
auto context = d->context.Get(d->isolate);
v8::Context::Scope context_scope(context);
v8::TryCatch try_catch(d->isolate);
v8::Local<v8::Function> recv =
v8::Local<v8::Function>::New(d->isolate, d->recv);
if (recv.IsEmpty()) {
d->last_exception = "V8Deno2.recv has not been called.";
return 1;
}
v8::Local<v8::Value> args[1];
args[0] = v8::ArrayBuffer::New(d->isolate, buf.data, buf.len,
v8::ArrayBufferCreationMode::kInternalized);
assert(!args[0].IsEmpty());
assert(!try_catch.HasCaught());
recv->Call(context->Global(), 1, args);
if (try_catch.HasCaught()) {
HandleException(d, try_catch.Exception());
return 2;
}
return 0;
}
void v8_init() {
// v8::V8::InitializeICUDefaultLocation(argv[0]);
// v8::V8::InitializeExternalStartupData(argv[0]);
auto p = v8::platform::CreateDefaultPlatform();
v8::V8::InitializePlatform(p);
v8::V8::Initialize();
}
Deno* deno_new(void* data, RecvCallback cb) {
Deno* d = new Deno;
d->cb = cb;
d->data = data;
v8::Isolate::CreateParams params;
params.array_buffer_allocator =
v8::ArrayBuffer::Allocator::NewDefaultAllocator();
v8::Isolate* isolate = v8::Isolate::New(params);
deno_add_isolate(d, isolate);
return d;
}
Deno* deno_from_snapshot(v8::StartupData* blob, void* data, RecvCallback cb) {
Deno* d = new Deno;
d->cb = cb;
d->data = data;
v8::Isolate::CreateParams params;
params.snapshot_blob = blob;
params.array_buffer_allocator =
v8::ArrayBuffer::Allocator::NewDefaultAllocator();
params.external_references = external_references;
v8::Isolate* isolate = v8::Isolate::New(params);
deno_add_isolate(d, isolate);
v8::Isolate::Scope isolate_scope(isolate);
{
v8::HandleScope handle_scope(isolate);
auto context = v8::Context::New(isolate);
d->context.Reset(d->isolate, context);
}
return d;
}
void deno_add_isolate(Deno* d, v8::Isolate* isolate) {
d->isolate = isolate;
// Leaving this code here because it will probably be useful later on, but
// disabling it now as I haven't got tests for the desired behavior.
// d->isolate->SetCaptureStackTraceForUncaughtExceptions(true);
// d->isolate->SetAbortOnUncaughtExceptionCallback(AbortOnUncaughtExceptionCallback);
// d->isolate->AddMessageListener(MessageCallback2);
// d->isolate->SetFatalErrorHandler(FatalErrorCallback2);
d->isolate->SetPromiseRejectCallback(ExitOnPromiseRejectCallback);
d->isolate->SetData(0, d);
}
v8::StartupData SerializeInternalField(v8::Local<v8::Object> holder, int index,
void* data) {
printf("SerializeInternalField %d\n", index);
v8::StartupData sd;
sd.data = "a";
sd.raw_size = 1;
return sd;
}
v8::StartupData deno_make_snapshot(const char* js_filename,
const char* js_source) {
auto creator = new v8::SnapshotCreator(external_references);
auto* isolate = creator->GetIsolate();
Deno* d = new Deno;
deno_add_isolate(d, isolate);
v8::Isolate::Scope isolate_scope(isolate);
{
v8::HandleScope handle_scope(isolate);
v8::Local<v8::Context> context = v8::Context::New(d->isolate);
v8::Context::Scope context_scope(context);
d->context.Reset(d->isolate, context);
auto global = context->Global();
auto print_tmpl = v8::FunctionTemplate::New(isolate, Print);
auto print_val = print_tmpl->GetFunction(context).ToLocalChecked();
CHECK(global->Set(context, v8_str("deno_print"), print_val).FromJust());
auto recv_tmpl = v8::FunctionTemplate::New(isolate, Recv);
auto recv_val = recv_tmpl->GetFunction(context).ToLocalChecked();
CHECK(global->Set(context, v8_str("deno_recv"), recv_val).FromJust());
auto send_tmpl = v8::FunctionTemplate::New(isolate, Send);
auto send_val = send_tmpl->GetFunction(context).ToLocalChecked();
CHECK(global->Set(context, v8_str("deno_send"), send_val).FromJust());
creator->SetDefaultContext(context);
}
int r = deno_load(d, js_filename, js_source);
assert(r == 0);
d->context.Reset(); // Delete persistant handles.
d->recv.Reset(); // Delete persistant handles.
auto snapshot_blob =
creator->CreateBlob(v8::SnapshotCreator::FunctionCodeHandling::kKeep);
return snapshot_blob;
}
void deno_dispose(Deno* d) {
d->isolate->Dispose();
delete (d);
}
void deno_terminate_execution(Deno* d) { d->isolate->TerminateExecution(); }

55
deno2/deno.h Normal file
View file

@ -0,0 +1,55 @@
// Copyright 2018 Ryan Dahl <ry@tinyclouds.org>
// All rights reserved. MIT License.
#ifndef DENO_H_
#define DENO_H_
#include <string>
#include "v8/include/v8.h"
// Data that gets transmitted.
struct buf_s {
void* data;
size_t len;
};
typedef struct buf_s DenoBuf;
// Deno = Wrapped Isolate.
struct deno_s;
typedef struct deno_s Deno;
// The callback from V8 when data is sent.
typedef DenoBuf (*RecvCallback)(Deno* d, DenoBuf buf);
struct deno_s {
v8::Isolate* isolate;
std::string last_exception;
v8::Persistent<v8::Function> recv;
v8::Persistent<v8::Context> context;
RecvCallback cb;
void* data;
};
void v8_init();
const char* v8_version();
void v8_set_flags(int* argc, char** argv);
// Constructors:
Deno* deno_new(void* data, RecvCallback cb);
Deno* deno_from_snapshot(v8::StartupData* blob, void* data, RecvCallback cb);
v8::StartupData deno_make_snapshot(const char* js_filename,
const char* js_source);
void deno_add_isolate(Deno* d, v8::Isolate* isolate);
void* deno_get_data();
// Returns nonzero on error.
// Get error text with deno_last_exception().
int deno_load(Deno* d, const char* name_s, const char* source_s);
// Returns nonzero on error.
int deno_send(Deno* d, DenoBuf buf);
const char* deno_last_exception(Deno* d);
void deno_dispose(Deno* d);
void deno_terminate_execution(Deno* d);
#endif // DENO_H_

15
deno2/deno_test.cc Normal file
View file

@ -0,0 +1,15 @@
// Copyright 2018 Ryan Dahl <ry@tinyclouds.org>
// All rights reserved. MIT License.
#include "testing/gtest/include/gtest/gtest.h"
#include "./deno.h"
TEST(SnapshotTest, InitializesCorrectly) {
EXPECT_TRUE(true);
// TODO(ry) add actual tests
}
int main(int argc, char** argv) {
testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}

7
deno2/js/main.ts Normal file
View file

@ -0,0 +1,7 @@
const globalEval = eval;
const window = globalEval("this");
window['foo'] = () => {
deno_print("Hello world from foo");
return "foo";
}

6
deno2/js/package.json Normal file
View file

@ -0,0 +1,6 @@
{
"devDependencies": {
"parcel-bundler": "^1.8.1",
"typescript": "^2.9.1"
}
}

14
deno2/js/run_node.py Executable file
View file

@ -0,0 +1,14 @@
#!/usr/bin/env python
"""
gn can only run python scripts.
Also Node programs except to be run with cwd = $root_dir/js so it can resolve
node_modules.
"""
import subprocess
import sys
import os
js_path = os.path.dirname(os.path.realpath(__file__))
os.chdir(js_path)
args = ["node"] + sys.argv[1:]
sys.exit(subprocess.call(args))

3535
deno2/js/yarn.lock Normal file

File diff suppressed because it is too large Load diff

33
deno2/main.cc Normal file
View file

@ -0,0 +1,33 @@
// Copyright 2018 Ryan Dahl <ry@tinyclouds.org>
// All rights reserved. MIT License.
#include <assert.h>
#include <stdio.h>
#include "v8/include/v8.h"
#include "./deno.h"
#include "natives_deno.cc"
#include "snapshot_deno.cc"
int main(int argc, char** argv) {
v8_init();
auto natives_blob = *StartupBlob_natives();
printf("natives_blob %d bytes\n", natives_blob.raw_size);
auto snapshot_blob = *StartupBlob_snapshot();
printf("snapshot_blob %d bytes\n", snapshot_blob.raw_size);
v8::V8::SetNativesDataBlob(&natives_blob);
v8::V8::SetSnapshotDataBlob(&snapshot_blob);
Deno* d = deno_from_snapshot(&snapshot_blob, NULL, NULL);
int r = deno_load(d, "main2.js", "foo();");
if (r != 0) {
printf("Error! %s\n", deno_last_exception(d));
exit(1);
}
const char* v = v8::V8::GetVersion();
printf("Hello World. V8 version %s\n", v);
}

102
deno2/msg.proto Normal file
View file

@ -0,0 +1,102 @@
// Copyright 2018 Ryan Dahl <ry@tinyclouds.org>
// All rights reserved. MIT License.
syntax = "proto3";
package main;
option go_package = "deno";
message BaseMsg {
string channel = 1;
bytes payload = 2;
}
message Msg {
enum Command {
ERROR = 0;
START = 1;
CODE_FETCH = 2;
CODE_FETCH_RES = 3;
CODE_CACHE = 4;
EXIT = 5;
TIMER_START = 6;
TIMER_READY = 7;
TIMER_CLEAR = 8;
FETCH_REQ = 9;
FETCH_RES = 10;
READ_FILE_SYNC = 11;
READ_FILE_SYNC_RES = 12;
WRITE_FILE_SYNC = 13;
}
Command command = 1;
// We avoid creating a message for each command (and use oneof or any types)
// In order to reduce code in the size of the generated javascript
// "msg.pb.js". It seems that each new message adds 20k and we want to
// potentially add many hundreds of commands. Therefore we just prefix command
// arguments by their name.
// ERROR
string error = 2;
// START
string start_cwd = 10;
repeated string start_argv = 11;
bool start_debug_flag = 12;
string start_main_js = 13; // The contents of dist/main.js
string start_main_map = 14; // The contents of dist/main.map
// CODE_FETCH
string code_fetch_module_specifier = 20;
string code_fetch_containing_file = 21;
// CODE_FETCH_RES
// If it's a non-http module, moduleName and filename will be the same.
// For http modules, moduleName is its resolved http URL, and filename
// is the location of the locally downloaded source code.
string code_fetch_res_module_name = 30;
string code_fetch_res_filename = 31;
string code_fetch_res_source_code = 32;
string code_fetch_res_output_code = 33; // Non-empty only if cached.
// CODE_CACHE
string code_cache_filename = 41;
string code_cache_source_code = 42;
string code_cache_output_code = 43;
// EXIT
int32 exit_code = 50;
// TIMER_START
int32 timer_start_id = 60;
bool timer_start_interval = 61;
int32 timer_start_duration = 62; // In milliseconds.
// TIMER_READY
int32 timer_ready_id = 70;
bool timer_ready_done = 71;
// TIMER_CLEAR
int32 timer_clear_id = 80;
// FETCH_REQ
int32 fetch_req_id = 90;
string fetch_req_url = 91;
// repeated string fetch_req_header_line = 91
// FETCH_RES
int32 fetch_res_id = 100;
int32 fetch_res_status = 101;
repeated string fetch_res_header_line = 102;
bytes fetch_res_body = 103;
// READ_FILE_SYNC
string read_file_sync_filename = 110;
// READ_FILE_SYNC_RES
bytes read_file_sync_data = 120;
// WRITE_FILE_SYNC
string write_file_sync_filename = 130;
bytes write_file_sync_data = 131;
uint32 write_file_sync_perm = 132;
// write_file_sync_perm specified by https://godoc.org/os#FileMode
}

145
deno2/snapshot_creator.cc Normal file
View file

@ -0,0 +1,145 @@
// Copyright 2018 Ryan Dahl <ry@tinyclouds.org>
// All rights reserved. MIT License.
#include <assert.h>
#include <stdio.h>
#include <string.h>
#include <fstream>
#include <iterator>
#include <vector>
#include "v8/include/v8.h"
#include "./deno.h"
class StartupDataCppWriter {
public:
StartupDataCppWriter(const char* name, const char* filename,
v8::StartupData sd)
: name_(name),
filename_(filename),
sd_(sd),
file_(filename_, std::ios::binary) {}
void Write() {
WritePrefix();
WriteData();
WriteSuffix();
file_.close();
if (file_.bad()) {
printf("Unable to open file \"%s\" for writing.\n", filename_);
exit(1);
}
printf("Wrote %s %d %s \n", name_, sd_.raw_size, filename_);
}
private:
void WritePrefix() {
file_ << "// Autogenerated snapshot file. Do not edit.\n\n";
file_ << "#include \"v8/include/v8.h\"\n\n";
}
void WriteSuffix() {
char buffer[500];
snprintf(buffer, sizeof(buffer),
"const v8::StartupData* StartupBlob_%s() {\n", name_);
file_ << buffer;
snprintf(buffer, sizeof(buffer), " return &%s_blob;\n", name_);
file_ << buffer;
file_ << "}\n\n";
}
void WriteBinaryContentsAsCArray() {
char buffer[5];
for (int i = 0; i < sd_.raw_size; i++) {
if ((i & 0x1F) == 0x1F) file_ << "\n";
if (i > 0) file_ << ",";
snprintf(buffer, sizeof(buffer), "%u",
static_cast<unsigned char>(sd_.data[i]));
file_ << buffer;
}
file_ << "\n";
}
void WriteData() {
char buffer[500];
snprintf(buffer, sizeof(buffer), "static const char %s_blob_data[] = {\n",
name_);
file_ << buffer;
WriteBinaryContentsAsCArray();
file_ << "};\n";
snprintf(buffer, sizeof(buffer), "static const int %s_blob_size = %d;\n",
name_, sd_.raw_size);
file_ << buffer;
snprintf(buffer, sizeof(buffer), "static const v8::StartupData %s_blob =\n",
name_);
file_ << buffer;
snprintf(buffer, sizeof(buffer),
"{ (const char*) %s_blob_data, %s_blob_size };\n", name_, name_);
file_ << buffer;
}
const char* name_;
const char* filename_;
v8::StartupData sd_;
std::ofstream file_;
};
// Caller must free returned value.
static v8::StartupData ReadFile(const char* fn) {
std::ifstream input(fn, std::ios::binary);
if (input.bad()) {
printf("Error reading %s\n", fn);
exit(1);
}
// Note the allocated buffer is intentionally not freed in this program.
// It may show up as a memory leak some day, but other than that it's
// harmless.
auto* buffer = new std::vector<char>((std::istreambuf_iterator<char>(input)),
(std::istreambuf_iterator<char>()));
v8::StartupData sd;
sd.data = buffer->data();
sd.raw_size = static_cast<int>(buffer->size());
if (input.bad()) {
printf("Error reading %s\n", fn);
exit(1);
}
return sd;
}
void WriteFile(const char* fn, v8::StartupData startup_data) {
std::ofstream output(fn, std::ios::binary);
output.write(startup_data.data, startup_data.raw_size);
output.close();
if (output.bad()) {
printf("Error writing %s\n", fn);
exit(1);
}
}
int main(int argc, char** argv) {
// The only documentation for this programs arguments is right here.
const char* js_fn = argv[1];
const char* natives_in_bin = argv[2];
const char* snapshot_in_bin = argv[3];
const char* natives_out_cc = argv[4];
const char* snapshot_out_cc = argv[5];
v8_init();
auto js_data = ReadFile(js_fn);
auto natives_blob = ReadFile(natives_in_bin);
auto snapshot_in_blob = ReadFile(snapshot_in_bin);
v8::V8::SetNativesDataBlob(&natives_blob);
v8::V8::SetSnapshotDataBlob(&snapshot_in_blob);
auto snapshot_blob = deno_make_snapshot(js_fn, js_data.data);
StartupDataCppWriter nativesWriter("natives", natives_out_cc, natives_blob);
nativesWriter.Write();
StartupDataCppWriter snapshotWriter("snapshot", snapshot_out_cc,
snapshot_blob);
snapshotWriter.Write();
}

1
deno2/testing Symbolic link
View file

@ -0,0 +1 @@
v8/testing

1
deno2/third_party/googletest vendored Symbolic link
View file

@ -0,0 +1 @@
../v8/third_party/googletest/

1
deno2/third_party/jinja2 vendored Symbolic link
View file

@ -0,0 +1 @@
../v8/third_party/jinja2/

1
deno2/third_party/llvm-build vendored Symbolic link
View file

@ -0,0 +1 @@
../v8/third_party/llvm-build/

1
deno2/third_party/markupsafe vendored Symbolic link
View file

@ -0,0 +1 @@
../v8/third_party/markupsafe/

67
deno2/tools/build.py Executable file
View file

@ -0,0 +1,67 @@
#!/usr/bin/env python
# Get Depot Tools and make sure it's in your path.
# http://commondatastorage.googleapis.com/chrome-infra-docs/flat/depot_tools/docs/html/depot_tools_tutorial.html#_setting_up
# Use .gclient to modify the deps.
import os
import sys
import subprocess
import argparse
TARGET = "deno"
parser = argparse.ArgumentParser(description="build.py")
parser.add_argument('--debug', dest='debug', action='store_true')
parser.add_argument('--use_ccache', dest='use_ccache', action='store_true')
parser.add_argument('--sync', dest='sync', action='store_true')
parser.set_defaults(debug=False, use_ccache=False, sync=False)
args = parser.parse_args()
root_path = os.path.dirname(os.path.dirname(os.path.realpath(__file__)))
def main():
os.chdir(root_path)
buildName = "Debug" if args.debug else "Default"
buildDir = os.path.join(root_path, "out", buildName)
# Run sync if any of the dep dirs don't exist.
# Or the user supplied the --sync flag.
if args.sync or dirsMissing():
run(["gclient", "sync", "--no-history"])
# Run gn gen out/Default if out doesn't exist.
if not os.path.exists(buildDir):
gn_gen = ["gn", "gen", buildDir]
gn_args = []
if args.debug:
gn_args.append("is_debug=true")
if args.use_ccache:
gn_args.append("cc_wrapper=\"ccache\"")
if len(gn_args) > 0:
gn_gen += ["--args=%s" % " ".join(gn_args)]
run(gn_gen)
# Always run ninja.
run(["ninja", "-C", buildDir, TARGET])
def run(args):
print " ".join(args)
env = os.environ.copy()
subprocess.check_call(args, env=env)
def dirsMissing():
dirsToLoad = [
"v8",
"third_party/protobuf",
"tools/protoc_wrapper",
"third_party/zlib",
]
for d in dirsToLoad:
if not os.path.exists(d):
return True
return False
if '__main__' == __name__:
main()

6
deno2/tools/format.sh Executable file
View file

@ -0,0 +1,6 @@
#!/bin/sh
cd `dirname "$0"`/..
clang-format -i -style Google *.cc *.h
gn format BUILD.gn
gn format .gn
yapf -i tools/*.py

4
deno2/tools/lint.sh Executable file
View file

@ -0,0 +1,4 @@
#!/bin/sh
cd `dirname "$0"`/..
set -e
cpplint *.cc *.h