Skip to content

Commit

Permalink
Source map support (denoland#429)
Browse files Browse the repository at this point in the history
This change increases size:
out/debug/obj/libdeno/from_snapshot.o  19M -> 34M
out/release/deno                       32M -> 47M
  • Loading branch information
ry committed Aug 2, 2018
1 parent e30bdb7 commit c7c6203
Show file tree
Hide file tree
Showing 11 changed files with 90 additions and 27 deletions.
1 change: 1 addition & 0 deletions BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -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",
]
Expand Down
9 changes: 5 additions & 4 deletions build_extra/deno.gni
Original file line number Diff line number Diff line change
Expand Up @@ -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"]
Expand Down
9 changes: 7 additions & 2 deletions js/lib.deno.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;
2 changes: 2 additions & 0 deletions js/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
33 changes: 23 additions & 10 deletions js/runtime.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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";

Expand All @@ -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.
Expand Down
20 changes: 17 additions & 3 deletions js/v8_source_maps.ts
Original file line number Diff line number Diff line change
@@ -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";

Expand All @@ -24,7 +32,7 @@ interface Position {
line: number;
}

type GetGeneratedContentsCallback = (fileName: string) => string;
type GetGeneratedContentsCallback = (fileName: string) => string | RawSourceMap;

let getGeneratedContents: GetGeneratedContentsCallback;

Expand Down Expand Up @@ -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);
Expand All @@ -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);
}
Expand Down
13 changes: 11 additions & 2 deletions src/binding.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand All @@ -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;
}
Expand Down
2 changes: 1 addition & 1 deletion src/from_filesystem.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}

Expand Down
4 changes: 3 additions & 1 deletion src/internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -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);

Expand Down
17 changes: 13 additions & 4 deletions src/snapshot_creator.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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));
}
Expand All @@ -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);
Expand Down
7 changes: 7 additions & 0 deletions tests/008_stack_trace.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { throwsError } from "./subdir/mod1.ts";

function foo() {
throwsError();
}

foo();

0 comments on commit c7c6203

Please sign in to comment.