Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Source map support #429

Merged
merged 2 commits into from
Aug 2, 2018
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
Source map support.
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
commit 6a440dc4674e5546452dbb653e2f754e3d7bb575
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;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

string | RawSourcemap?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually fixing this caused some unknown error. I'm backing out of that and landing as originally approved. Will fix in follow up.

}

// 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;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems duplicative with the Window interface above. Do we really need both?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we don't need either - but I'm not sure the right solution now. I will fix it later.

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;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You might want to reflect this in lib.deno.d.ts when that has landed.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks - done. (Although it's global right now. Will fix later)


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
13 changes: 10 additions & 3 deletions js/v8_source_maps.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
// Copyright 2018 the Deno authors. All rights reserved. MIT license.
// Originated from source-map-support but has been heavily modified for deno.
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 +25,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 +191,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 +213,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());
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

May want to reflect this in lib.deno.d.ts when it lands into master.


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.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I still find _fn a confusing abbreviation for filename.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just following the convention here. I'll avoid it in the future.


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();