summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRyan Dahl <ry@tinyclouds.org>2018-08-02 13:13:32 -0400
committerGitHub <noreply@github.com>2018-08-02 13:13:32 -0400
commitc7c6203e61cb6bb85051b96eabd6deae7995a787 (patch)
treeef463466f34fd72a4ac5a30eecd3cc94254f321f
parente30bdb71aa8b9902078e1ed8e7d014a68eb9eb2e (diff)
Source map support (#429)
This change increases size: out/debug/obj/libdeno/from_snapshot.o 19M -> 34M out/release/deno 32M -> 47M
-rw-r--r--BUILD.gn1
-rw-r--r--build_extra/deno.gni9
-rw-r--r--js/lib.deno.d.ts9
-rw-r--r--js/main.ts2
-rw-r--r--js/runtime.ts33
-rw-r--r--js/v8_source_maps.ts20
-rw-r--r--src/binding.cc13
-rw-r--r--src/from_filesystem.cc2
-rw-r--r--src/internal.h4
-rw-r--r--src/snapshot_creator.cc17
-rw-r--r--tests/008_stack_trace.ts7
11 files changed, 90 insertions, 27 deletions
diff --git a/BUILD.gn b/BUILD.gn
index bab200547..b200c2cfe 100644
--- a/BUILD.gn
+++ b/BUILD.gn
@@ -264,6 +264,7 @@ rust_flatbuffer("msg_rs") {
# Generates $target_gen_dir/snapshot_deno.cc
create_snapshot("deno") {
js = "$target_gen_dir/bundle/main.js"
+ source_map = "$target_gen_dir/bundle/main.js.map"
deps = [
":bundle",
]
diff --git a/build_extra/deno.gni b/build_extra/deno.gni
index 5f3f4aa48..08cccfdea 100644
--- a/build_extra/deno.gni
+++ b/build_extra/deno.gni
@@ -32,13 +32,14 @@ template("create_snapshot") {
inputs = [
invoker.js,
]
+ if (defined(invoker.source_map)) {
+ inputs += [ invoker.source_map ]
+ }
outputs = [
snapshot_out_bin,
]
- args = [
- rebase_path(snapshot_out_bin, root_build_dir),
- rebase_path(invoker.js, root_build_dir),
- ]
+ args = rebase_path(outputs, root_build_dir) +
+ rebase_path(inputs, root_build_dir)
# To debug snapshotting problems:
# args += ["--trace-serializer"]
diff --git a/js/lib.deno.d.ts b/js/lib.deno.d.ts
index 81e8daf4e..b11a08edf 100644
--- a/js/lib.deno.d.ts
+++ b/js/lib.deno.d.ts
@@ -27,10 +27,15 @@ declare class Console {
interface Window {
console: Console;
- mainSource: string; // TODO(ry) This shouldn't be global.
+ // TODO(ry) These shouldn't be global.
+ mainSource: string;
+ setMainSourceMap(sm: string): void;
}
// Globals in the runtime environment
declare let console: Console;
-declare let mainSource: string; // TODO(ry) This shouldn't be global.
declare const window: Window;
+
+// TODO(ry) These shouldn't be global.
+declare let mainSource: string;
+declare function setMainSourceMap(sm: string): void;
diff --git a/js/main.ts b/js/main.ts
index 50f73a4c6..81dabab33 100644
--- a/js/main.ts
+++ b/js/main.ts
@@ -20,6 +20,8 @@ function startMsg(cmdId: number): Uint8Array {
/* tslint:disable-next-line:no-default-export */
export default function denoMain() {
+ runtime.setup();
+
// First we send an empty "Start" message to let the privlaged side know we
// are ready. The response should be a "StartRes" message containing the CLI
// argv and other info.
diff --git a/js/runtime.ts b/js/runtime.ts
index 79f463759..4e9cb657d 100644
--- a/js/runtime.ts
+++ b/js/runtime.ts
@@ -12,7 +12,7 @@ import * as util from "./util";
import { log } from "./util";
import { assetSourceCode } from "./assets";
import * as os from "./os";
-//import * as sourceMaps from "./v8_source_maps";
+import * as sourceMaps from "./v8_source_maps";
import { window, globalEval } from "./globals";
//import * as deno from "./deno";
@@ -39,26 +39,39 @@ window.onerror = (
os.exit(1);
};
-/*
-export function setup(mainJs: string, mainMap: string): void {
+// This is called during snapshot creation with the contents of
+// out/debug/gen/bundle/main.js.map.
+import { RawSourceMap } from "source-map";
+let mainSourceMap: RawSourceMap = null;
+function setMainSourceMap(rawSourceMap: RawSourceMap) {
+ util.assert(Number(rawSourceMap.version) === 3);
+ mainSourceMap = rawSourceMap;
+}
+window["setMainSourceMap"] = setMainSourceMap;
+
+export function setup(): void {
sourceMaps.install({
installPrepareStackTrace: true,
- getGeneratedContents: (filename: string): string => {
- if (filename === "/main.js") {
- return mainJs;
- } else if (filename === "/main.map") {
- return mainMap;
+ getGeneratedContents: (filename: string): string | RawSourceMap => {
+ util.log("getGeneratedContents", filename);
+ if (filename === "gen/bundle/main.js") {
+ util.assert(window["mainSource"].length > 0);
+ return window["mainSource"];
+ } else if (filename === "main.js.map") {
+ return mainSourceMap;
+ } else if (filename === "deno_main.js") {
+ return "";
} else {
const mod = FileModule.load(filename);
if (!mod) {
- console.error("getGeneratedContents cannot find", filename);
+ util.log("getGeneratedContents cannot find", filename);
+ return null;
}
return mod.outputCode;
}
}
});
}
-*/
// This class represents a module. We call it FileModule to make it explicit
// that each module represents a single file.
diff --git a/js/v8_source_maps.ts b/js/v8_source_maps.ts
index 956ffbe82..d5feeb1c0 100644
--- a/js/v8_source_maps.ts
+++ b/js/v8_source_maps.ts
@@ -1,7 +1,15 @@
// Copyright 2014 Evan Wallace
// Copyright 2018 the Deno authors. All rights reserved. MIT license.
// Originated from source-map-support but has been heavily modified for deno.
+
+// Because NodeJS.CallSite and Error.prepareStackTrace are used we add a
+// dependency on the Node types.
+// TODO(ry) Ideally this triple slash directive should be removed as we only
+// need CallSite and Error.prepareStackTrace but nothing else.
+/// <reference types="node" />
+
import { SourceMapConsumer, MappedPosition } from "source-map";
+import { RawSourceMap } from "source-map";
import * as base64 from "base64-js";
import { arrayToStr } from "./util";
@@ -24,7 +32,7 @@ interface Position {
line: number;
}
-type GetGeneratedContentsCallback = (fileName: string) => string;
+type GetGeneratedContentsCallback = (fileName: string) => string | RawSourceMap;
let getGeneratedContents: GetGeneratedContentsCallback;
@@ -190,13 +198,16 @@ function loadConsumer(source: string): SourceMapConsumer {
if (!code) {
return null;
}
+ if (typeof code !== "string") {
+ throw new Error("expected string");
+ }
let sourceMappingURL = retrieveSourceMapURL(code);
if (!sourceMappingURL) {
throw Error("No source map?");
}
- let sourceMapData: string;
+ let sourceMapData: string | RawSourceMap;
if (reSourceMap.test(sourceMappingURL)) {
// Support source map URL as a data url
const rawData = sourceMappingURL.slice(sourceMappingURL.indexOf(",") + 1);
@@ -209,8 +220,11 @@ function loadConsumer(source: string): SourceMapConsumer {
sourceMapData = getGeneratedContents(sourceMappingURL);
}
+ const rawSourceMap =
+ typeof sourceMapData === "string"
+ ? JSON.parse(sourceMapData)
+ : sourceMapData;
//console.log("sourceMapData", sourceMapData);
- const rawSourceMap = JSON.parse(sourceMapData);
consumer = new SourceMapConsumer(rawSourceMap);
consumers.set(source, consumer);
}
diff --git a/src/binding.cc b/src/binding.cc
index 1c4deaa23..19448ca2a 100644
--- a/src/binding.cc
+++ b/src/binding.cc
@@ -270,7 +270,8 @@ bool Execute(v8::Local<v8::Context> context, const char* js_filename,
}
void InitializeContext(v8::Isolate* isolate, v8::Local<v8::Context> context,
- const char* js_filename, const char* js_source) {
+ const char* js_filename, const std::string& js_source,
+ const std::string* source_map) {
v8::HandleScope handle_scope(isolate);
v8::Context::Scope context_scope(context);
@@ -293,11 +294,19 @@ void InitializeContext(v8::Isolate* isolate, v8::Local<v8::Context> context,
skip_onerror = true;
{
- auto source = deno::v8_str(js_source);
+ auto source = deno::v8_str(js_source.c_str());
CHECK(global->Set(context, deno::v8_str("mainSource"), source).FromJust());
bool r = deno::ExecuteV8StringSource(context, js_filename, source);
CHECK(r);
+
+ if (source_map != nullptr) {
+ CHECK_GT(source_map->length(), 1u);
+ std::string set_source_map = "setMainSourceMap( " + *source_map + " )";
+ CHECK_GT(set_source_map.length(), source_map->length());
+ r = deno::Execute(context, "set_source_map.js", set_source_map.c_str());
+ CHECK(r);
+ }
}
skip_onerror = false;
}
diff --git a/src/from_filesystem.cc b/src/from_filesystem.cc
index a47808b82..797659de0 100644
--- a/src/from_filesystem.cc
+++ b/src/from_filesystem.cc
@@ -32,7 +32,7 @@ Deno* NewFromFileSystem(void* data, deno_recv_cb cb) {
{
v8::HandleScope handle_scope(isolate);
auto context = v8::Context::New(isolate);
- InitializeContext(isolate, context, BUNDLE_LOCATION, js_source.c_str());
+ InitializeContext(isolate, context, BUNDLE_LOCATION, js_source, nullptr);
d->context.Reset(d->isolate, context);
}
diff --git a/src/internal.h b/src/internal.h
index dc28112dc..0719bdc3e 100644
--- a/src/internal.h
+++ b/src/internal.h
@@ -20,6 +20,7 @@ struct deno_s {
// TODO(ry) Remove these when we call deno_reply_start from Rust.
char** deno_argv();
int deno_argc();
+struct deno_s* deno_from_isolate(v8::Isolate* isolate);
}
namespace deno {
@@ -38,7 +39,8 @@ static intptr_t external_references[] = {reinterpret_cast<intptr_t>(Print),
Deno* NewFromSnapshot(void* data, deno_recv_cb cb);
void InitializeContext(v8::Isolate* isolate, v8::Local<v8::Context> context,
- const char* js_filename, const char* js_source);
+ const char* js_filename, const std::string& js_source,
+ const std::string* source_map);
void AddIsolate(Deno* d, v8::Isolate* isolate);
diff --git a/src/snapshot_creator.cc b/src/snapshot_creator.cc
index f821565e5..8038c9b13 100644
--- a/src/snapshot_creator.cc
+++ b/src/snapshot_creator.cc
@@ -22,14 +22,16 @@ v8::StartupData SerializeInternalFields(v8::Local<v8::Object> holder, int index,
return {payload, size};
}
-v8::StartupData MakeSnapshot(const char* js_filename, const char* js_source) {
+v8::StartupData MakeSnapshot(const char* js_filename,
+ const std::string& js_source,
+ const std::string* source_map) {
auto* creator = new v8::SnapshotCreator(external_references);
auto* isolate = creator->GetIsolate();
v8::Isolate::Scope isolate_scope(isolate);
{
v8::HandleScope handle_scope(isolate);
auto context = v8::Context::New(isolate);
- InitializeContext(isolate, context, js_filename, js_source);
+ InitializeContext(isolate, context, js_filename, js_source, source_map);
creator->SetDefaultContext(context, v8::SerializeInternalFieldsCallback(
SerializeInternalFields, nullptr));
}
@@ -45,18 +47,25 @@ v8::StartupData MakeSnapshot(const char* js_filename, const char* js_source) {
int main(int argc, char** argv) {
const char* snapshot_out_bin = argv[1];
const char* js_fn = argv[2];
+ const char* source_map_fn = argv[3]; // Optional.
v8::V8::SetFlagsFromCommandLine(&argc, argv, true);
- CHECK_EQ(argc, 3);
CHECK_NE(js_fn, nullptr);
CHECK_NE(snapshot_out_bin, nullptr);
std::string js_source;
CHECK(deno::ReadFileToString(js_fn, &js_source));
+ std::string source_map;
+ if (source_map_fn != nullptr) {
+ CHECK_EQ(argc, 4);
+ CHECK(deno::ReadFileToString(source_map_fn, &source_map));
+ }
+
deno_init();
- auto snapshot_blob = deno::MakeSnapshot(js_fn, js_source.c_str());
+ auto snapshot_blob = deno::MakeSnapshot(
+ js_fn, js_source, source_map_fn != nullptr ? &source_map : nullptr);
std::string snapshot_str(snapshot_blob.data, snapshot_blob.raw_size);
std::ofstream file_(snapshot_out_bin, std::ios::binary);
diff --git a/tests/008_stack_trace.ts b/tests/008_stack_trace.ts
new file mode 100644
index 000000000..6aa0fcc3b
--- /dev/null
+++ b/tests/008_stack_trace.ts
@@ -0,0 +1,7 @@
+import { throwsError } from "./subdir/mod1.ts";
+
+function foo() {
+ throwsError();
+}
+
+foo();