Skip to content

Commit

Permalink
fix: Use per process native module loader for compiled JS source
Browse files Browse the repository at this point in the history
  • Loading branch information
deepak1556 committed Jan 8, 2019
1 parent 136c5dc commit 65a1776
Show file tree
Hide file tree
Showing 9 changed files with 89 additions and 157 deletions.
64 changes: 24 additions & 40 deletions BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -54,55 +54,40 @@ config("branding") {
}

npm_action("atom_browserify_sandbox") {
deps = [
":atom_js2c_copy",
]
script = "browserify"

sandbox_args = [
"lib/sandboxed_renderer/init.js",
"-r",
"./lib/sandboxed_renderer/api/exports/electron.js:electron",
"-t",
"aliasify",
outputs = [
"$target_gen_dir/js2c/preload_bundle.js",
]

inputs = [
args = [
# FIXME(zcbenz): The dependencies of these files are not listed here, so
# the generated file will be out-dated when dependencies are modified.
# Use a script to generate all dependencies and put them here.
"lib/sandboxed_renderer/init.js",
"lib/sandboxed_renderer/api/exports/electron.js",
]
outputs = [
"$target_gen_dir/js2c/preload_bundle.js",
"-r",
"./lib/sandboxed_renderer/api/exports/electron.js:electron",
"-t",
"aliasify",
"-o",
rebase_path(outputs[0]),
]

script = "browserify"
args = sandbox_args + [
"-o",
rebase_path(outputs[0]),
]
}

npm_action("atom_browserify_isolated") {
deps = [
":atom_js2c_copy",
]
script = "browserify"

inputs = [
"lib/isolated_renderer/init.js",
]
outputs = [
"$target_gen_dir/js2c/isolated_bundle.js",
]

script = "browserify"
args = inputs + [
"-t",
"aliasify",
"-o",
rebase_path(outputs[0]),
]
args = [
"lib/isolated_renderer/init.js",
"-t",
"aliasify",
"-o",
rebase_path(outputs[0]),
]
}

copy("atom_js2c_copy") {
Expand All @@ -122,23 +107,24 @@ action("atom_js2c") {
":atom_js2c_copy",
]

js2c_sources = filenames.js2c_sources

browserify_sources = [
"$target_gen_dir/js2c/isolated_bundle.js",
"$target_gen_dir/js2c/preload_bundle.js",
]

inputs = js2c_sources + browserify_sources
sources = browserify_sources + [
"$target_gen_dir/js2c/asar.js",
"$target_gen_dir/js2c/asar_init.js",
]

outputs = [
"$target_gen_dir/atom_natives.h",
"$root_gen_dir/atom_natives.cc",
]

script = "tools/js2c.py"
args = [ rebase_path("//third_party/electron_node") ] +
rebase_path(outputs, root_build_dir) +
[ rebase_path("$target_gen_dir/js2c", root_build_dir) ]
rebase_path(sources, root_build_dir)
}

asar("js2asar") {
Expand Down Expand Up @@ -337,8 +323,6 @@ static_library("electron_lib") {
sources = filenames.lib_sources
set_sources_assignment_filter(sources_assignment_filter)

sources += [ "$target_gen_dir/atom_natives.h" ]

if (is_component_build) {
defines += [ "NODE_SHARED_MODE" ]
}
Expand Down
28 changes: 10 additions & 18 deletions atom/common/api/atom_api_asar.cc
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
#include "native_mate/wrappable.h"

#include "atom/common/node_includes.h"
#include "atom_natives.h" // NOLINT: This file is generated with js2c.
#include "third_party/electron_node/src/node_native_module.h"

namespace {

Expand Down Expand Up @@ -122,23 +122,15 @@ void InitAsarSupport(v8::Isolate* isolate,
v8::Local<v8::Value> source,
v8::Local<v8::Value> require) {
// Evaluate asar_init.js.
v8::Local<v8::Context> context(isolate->GetCurrentContext());
auto maybe_asar_init = v8::Script::Compile(
context, node::asar_init_value.ToStringChecked(isolate));
v8::Local<v8::Script> asar_init;
v8::Local<v8::Value> result;
if (maybe_asar_init.ToLocal(&asar_init))
result = asar_init->Run(context).ToLocalChecked();

// Initialize asar support.
DCHECK(result->IsFunction());

v8::Local<v8::Value> args[] = {
source,
require,
node::asar_value.ToStringChecked(isolate),
};
result.As<v8::Function>()->Call(result, 3, args);
std::vector<v8::Local<v8::String>> asar_init_params = {
node::FIXED_ONE_BYTE_STRING(isolate, "source"),
node::FIXED_ONE_BYTE_STRING(isolate, "require")};

std::vector<v8::Local<v8::Value>> asar_init_args = {source, require};

node::per_process::native_module_loader.CompileAndCall(
isolate->GetCurrentContext(), "electron/js2c/asar_init",
&asar_init_params, &asar_init_args, nullptr);
}

void Initialize(v8::Local<v8::Object> exports,
Expand Down
4 changes: 2 additions & 2 deletions atom/common/node_includes.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,11 +30,11 @@
#undef NO_RETURN
#undef LIKELY
#undef arraysize
#undef debug_string // This is defined in macOS SDK in AssertMacros.h.
#undef debug_string // This is defined in macOS SDK in AssertMacros.h.
#undef require_string // This is defined in macOS SDK in AssertMacros.h.
#include "env-inl.h"
#include "env.h"
#include "node.h"
#include "node_binding.h"
#include "node_buffer.h"
#include "node_internals.h"
#include "node_options.h"
Expand Down
33 changes: 12 additions & 21 deletions atom/renderer/atom_renderer_client.cc
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,7 @@
#include "third_party/blink/public/web/web_local_frame.h"

#include "atom/common/node_includes.h"
#include "atom_natives.h" // NOLINT: This file is generated with js2c
#include "tracing/trace_event.h"
#include "third_party/electron_node/src/node_native_module.h"

namespace atom {

Expand Down Expand Up @@ -189,28 +188,20 @@ void AtomRendererClient::SetupMainWorldOverrides(
v8::Handle<v8::Context> context,
content::RenderFrame* render_frame) {
// Setup window overrides in the main world context
v8::Isolate* isolate = context->GetIsolate();
v8::HandleScope handle_scope(isolate);
v8::Context::Scope context_scope(context);

// Wrap the bundle into a function that receives the isolatedWorld as
// an argument.
std::string left = "(function (nodeProcess, isolatedWorld) {\n";
std::string right = "\n})";
auto source = v8::String::Concat(
isolate, mate::ConvertToV8(isolate, left)->ToString(isolate),
v8::String::Concat(isolate,
node::isolated_bundle_value.ToStringChecked(isolate),
mate::ConvertToV8(isolate, right)->ToString(isolate)));
auto result = RunScript(context, source);
DCHECK(result->IsFunction());

v8::Local<v8::Value> args[] = {
auto* isolate = context->GetIsolate();
std::vector<v8::Local<v8::String>> isolated_bundle_params = {
node::FIXED_ONE_BYTE_STRING(isolate, "nodeProcess"),
node::FIXED_ONE_BYTE_STRING(isolate, "isolatedWorld")};

std::vector<v8::Local<v8::Value>> isolated_bundle_args = {
GetEnvironment(render_frame)->process_object(),
GetContext(render_frame->GetWebFrame(), isolate)->Global(),
};
ignore_result(result.As<v8::Function>()->Call(context, v8::Null(isolate),
node::arraysize(args), args));
GetContext(render_frame->GetWebFrame(), isolate)->Global()};

node::per_process::native_module_loader.CompileAndCall(
context, "electron/js2c/isolated_bundle", &isolated_bundle_params,
&isolated_bundle_args, nullptr);
}

node::Environment* AtomRendererClient::GetEnvironment(
Expand Down
2 changes: 1 addition & 1 deletion atom/renderer/atom_renderer_client.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@

namespace node {
class Environment;
}
} // namespace node

namespace atom {

Expand Down
34 changes: 13 additions & 21 deletions atom/renderer/atom_sandboxed_renderer_client.cc
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,8 @@
#include "third_party/blink/public/web/web_document.h"

#include "atom/common/node_includes.h"
#include "atom_natives.h" // NOLINT: This file is generated with js2c
#include "third_party/electron_node/src/node_binding.h"
#include "third_party/electron_node/src/node_native_module.h"

namespace atom {

Expand Down Expand Up @@ -182,30 +183,21 @@ void AtomSandboxedRendererClient::DidCreateScriptContext(
!IsDevToolsExtension(render_frame))
return;

// Wrap the bundle into a function that receives the binding object as
// argument.
auto* isolate = context->GetIsolate();
v8::HandleScope handle_scope(isolate);
v8::Context::Scope context_scope(context);
// Wrap the bundle into a function that receives the binding object and the
// preload script path as arguments.
std::string left = "(function(binding, require) {\n";
std::string right = "\n})";
// Compile the wrapper and run it to get the function object
auto source = v8::String::Concat(
isolate, mate::ConvertToV8(isolate, left)->ToString(isolate),
v8::String::Concat(isolate,
node::preload_bundle_value.ToStringChecked(isolate),
mate::ConvertToV8(isolate, right)->ToString(isolate)));
auto result = RunScript(context, source);

DCHECK(result->IsFunction());
// Create and initialize the binding object
auto binding = v8::Object::New(isolate);
InitializeBindings(binding, context);
AddRenderBindings(isolate, binding);
v8::Local<v8::Value> args[] = {binding};
// Execute the function with proper arguments
ignore_result(result.As<v8::Function>()->Call(context, v8::Null(isolate),
node::arraysize(args), args));

std::vector<v8::Local<v8::String>> preload_bundle_params = {
node::FIXED_ONE_BYTE_STRING(isolate, "binding")};

std::vector<v8::Local<v8::Value>> preload_bundle_args = {binding};

node::per_process::native_module_loader.CompileAndCall(
isolate->GetCurrentContext(), "electron/js2c/preload_bundle",
&preload_bundle_params, &preload_bundle_args, nullptr);
}

void AtomSandboxedRendererClient::WillReleaseScriptContext(
Expand Down
5 changes: 0 additions & 5 deletions filenames.gni
Original file line number Diff line number Diff line change
@@ -1,9 +1,4 @@
filenames = {
js2c_sources = [
"lib/common/asar.js",
"lib/common/asar_init.js",
]

js_sources = [
"lib/browser/api/app.js",
"lib/browser/api/auto-updater.js",
Expand Down
30 changes: 12 additions & 18 deletions lib/common/asar_init.js
Original file line number Diff line number Diff line change
@@ -1,20 +1,14 @@
'use strict'

;(function () { // eslint-disable-line
return function (source, require, asarSource) {
// Expose fs module without asar support.

// NB: Node's 'fs' and 'internal/fs/streams' have a lazy-loaded circular
// dependency. So to expose the unmodified Node 'fs' functionality here,
// we have to copy both 'fs' *and* 'internal/fs/streams' and modify the
// copies to depend on each other instead of on our asarified 'fs' code.
source['original-fs'] = source.fs.replace("require('internal/fs/streams')", "require('original-fs/streams')")
source['original-fs/streams'] = source['internal/fs/streams'].replace("require('fs')", "require('original-fs')")

// Make asar.js accessible via "require".
source.ELECTRON_ASAR = asarSource

// Monkey-patch the fs module.
require('ELECTRON_ASAR').wrapFsWithAsar(require('fs'))
}
})()
/* global source, require */

// Expose fs module without asar support.
// NB: Node's 'fs' and 'internal/fs/streams' have a lazy-loaded circular
// dependency. So to expose the unmodified Node 'fs' functionality here,
// we have to copy both 'fs' *and* 'internal/fs/streams' and modify the
// copies to depend on each other instead of on our asarified 'fs' code.
source['original-fs'].replace("require('internal/fs/streams')", "require('original-fs/streams')")
source['original-fs/streams'].replace("require('fs')", "require('original-fs')")

// Monkey-patch the fs module.
require('electron/js2c/asar').wrapFsWithAsar(require('fs'))
46 changes: 15 additions & 31 deletions tools/js2c.py
Original file line number Diff line number Diff line change
@@ -1,54 +1,38 @@
#!/usr/bin/env python

import contextlib
import glob
import os
import subprocess
import sys


SOURCE_ROOT = os.path.abspath(os.path.dirname(os.path.dirname(__file__)))

TEMPLATE = """
#ifndef ATOM_NATIVES_H_
#define ATOM_NATIVES_H_
#include "node_native_module.h"
#include "node_internals.h"
namespace node {{
namespace native_module {{
{definitions}
}} // namespace node
void NativeModuleLoader::LoadEmbedderJavaScriptSource() {{
{initializers}
}}
#endif // ATOM_NATIVES_H_
"""
}} // namespace native_module
}} // namespace node
"""

def main():
node_path = os.path.abspath(sys.argv[1])
natives = os.path.abspath(sys.argv[2])
js_source_files = glob.glob('{0}/*.js'.format(sys.argv[3]))

call_js2c(node_path, natives, js_source_files)

js_source_files = sys.argv[3:]

def call_js2c(node_path, natives, js_source_files):
js2c = os.path.join(node_path, 'tools', 'js2c.py')
src_dir = os.path.dirname(js_source_files[0])
with scoped_cwd(src_dir):
subprocess.check_call(
[sys.executable, js2c, natives] +
[os.path.basename(source) for source in js_source_files] +
['-t', TEMPLATE])


@contextlib.contextmanager
def scoped_cwd(path):
cwd = os.getcwd()
os.chdir(path)
try:
yield
finally:
os.chdir(cwd)
subprocess.check_call(
[sys.executable, js2c, natives] +
js_source_files +
['-t', TEMPLATE])


if __name__ == '__main__':
Expand Down

0 comments on commit 65a1776

Please sign in to comment.