Skip to content

Commit 82f6624

Browse files
committed
tools: port js2c.py to C++
nodejs/node#46997
1 parent 9e3760e commit 82f6624

3 files changed

Lines changed: 196 additions & 142 deletions

File tree

BUILD.gn

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -249,7 +249,7 @@ action("electron_js2c") {
249249
"$target_gen_dir/js2c/worker_init.js",
250250
]
251251

252-
inputs = sources + [ "//third_party/electron_node/tools/js2c.py" ]
252+
inputs = sources + [ "//third_party/electron_node/tools/js2c.cc" ]
253253
outputs = [ "$root_gen_dir/electron_natives.cc" ]
254254

255255
script = "build/js2c.py"

build/js2c.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ def main():
2424
natives = os.path.abspath(sys.argv[2])
2525
js_source_files = sys.argv[3:]
2626

27-
js2c = os.path.join(node_path, 'tools', 'js2c.py')
27+
js2c = os.path.join(node_path, 'tools', 'js2c.cc')
2828
subprocess.check_call(
2929
[sys.executable, js2c] +
3030
js_source_files +

patches/node/build_modify_js2c_py_to_allow_injection_of_original-fs_and_custom_embedder_js.patch

Lines changed: 194 additions & 140 deletions
Original file line numberDiff line numberDiff line change
@@ -14,13 +14,14 @@ renderer/browser/worker/sandboxed bootstrap scripts). These are loaded
1414
through LoadEmbedderJavaScriptSource()
1515

1616
diff --git a/lib/internal/fs/watchers.js b/lib/internal/fs/watchers.js
17-
index ce885c154c81c5703365fa34957697698da9aff6..229b0d522aeee3632145c86715bea1394d496bc4 100644
17+
index 99212fa713bf3f767d4604906e41d9b279447239..4e32a274a63c8244ce3168d0c5cc56203cfe5473 100644
1818
--- a/lib/internal/fs/watchers.js
1919
+++ b/lib/internal/fs/watchers.js
20-
@@ -293,11 +293,13 @@ function emitCloseNT(self) {
20+
@@ -292,12 +292,13 @@ function emitCloseNT(self) {
21+
}
2122

2223
// Legacy alias on the C++ wrapper object. This is not public API, so we may
23-
// want to runtime-deprecate it at some point. There's no hurry, though.
24+
-// want to runtime-deprecate it at some point. There's no hurry, though.
2425
-ObjectDefineProperty(FSEvent.prototype, 'owner', {
2526
- __proto__: null,
2627
- get() { return this[owner_symbol]; },
@@ -34,159 +35,212 @@ index ce885c154c81c5703365fa34957697698da9aff6..229b0d522aeee3632145c86715bea139
3435
+ });
3536
+}
3637

37-
async function* watch(filename, options = kEmptyObject) {
38-
const path = toNamespacedPath(getValidatedPath(filename));
38+
let kResistStopPropagation;
39+
3940
diff --git a/src/node_builtins.cc b/src/node_builtins.cc
40-
index 356ec3acd0bf3ac1e7518b32a5a58b042a03f598..4d4b59916bfdb203702c4e878ff2659b79de8c52 100644
41+
index 84815969b6d1faa7cc3ed177e04248d9cb074596..7e4a43a6f13845c8a81bae96ec073ccdfc655999 100644
4142
--- a/src/node_builtins.cc
4243
+++ b/src/node_builtins.cc
43-
@@ -33,6 +33,7 @@ BuiltinLoader BuiltinLoader::instance_;
44-
45-
BuiltinLoader::BuiltinLoader() : config_(GetConfig()), has_code_cache_(false) {
44+
@@ -35,6 +35,7 @@ using v8::Value;
45+
BuiltinLoader::BuiltinLoader()
46+
: config_(GetConfig()), code_cache_(std::make_shared<BuiltinCodeCache>()) {
4647
LoadJavaScriptSource();
4748
+ LoadEmbedderJavaScriptSource();
4849
#ifdef NODE_SHARED_BUILTIN_CJS_MODULE_LEXER_LEXER_PATH
4950
AddExternalizedBuiltin(
5051
"internal/deps/cjs-module-lexer/lexer",
5152
diff --git a/src/node_builtins.h b/src/node_builtins.h
52-
index 90b158b84bb2a66781cf92f5b4c1a64f9e2ee651..8d9f7c409659a30747e5feeac6cfec4208791370 100644
53+
index 9f2fbc1e53937448aa27c1f5fe110eabc7edc0df..ba0c926a7968ec6a4cf07a469f1fd9314287a937 100644
5354
--- a/src/node_builtins.h
5455
+++ b/src/node_builtins.h
55-
@@ -71,6 +71,7 @@ class NODE_EXTERN_PRIVATE BuiltinLoader {
56+
@@ -124,6 +124,7 @@ class NODE_EXTERN_PRIVATE BuiltinLoader {
5657

5758
// Generated by tools/js2c.py as node_javascript.cc
5859
void LoadJavaScriptSource(); // Loads data into source_
5960
+ void LoadEmbedderJavaScriptSource(); // Loads embedder data into source_
6061
UnionBytes GetConfig(); // Return data for config.gypi
6162

62-
std::vector<std::string> GetBuiltinIds();
63-
diff --git a/tools/js2c.py b/tools/js2c.py
64-
index 077bba1572f05f1aa16553894703b12abc19a985..bb9f26e3adc863757ad8ede5069d299c2d138369 100755
65-
--- a/tools/js2c.py
66-
+++ b/tools/js2c.py
67-
@@ -39,6 +39,8 @@ import codecs
68-
import utils
69-
70-
def ReadFile(filename):
71-
+ if filename.startswith("//v8"):
72-
+ filename = "../../" + filename[2:]
73-
if is_verbose:
74-
print(filename)
75-
with codecs.open(filename, "r", "utf-8") as f:
76-
@@ -57,13 +59,15 @@ namespace builtins {{
77-
78-
{0}
79-
80-
-void BuiltinLoader::LoadJavaScriptSource() {{
81-
+void BuiltinLoader::Load{4}JavaScriptSource() {{
82-
{1}
83-
}}
84-
85-
+#if {2}
86-
UnionBytes BuiltinLoader::GetConfig() {{
87-
- return UnionBytes(config_raw, {2}); // config.gypi
88-
+ return UnionBytes(config_raw, {3}); // config.gypi
89-
}}
90-
+#endif
91-
92-
}} // namespace builtins
93-
94-
@@ -113,8 +117,8 @@ def GetDefinition(var, source, step=30):
95-
return definition, len(code_points)
96-
97-
98-
-def AddModule(filename, definitions, initializers):
99-
- code = ReadFile(filename)
100-
+def AddModule(filename, definitions, initializers, ReadFileFn=ReadFile):
101-
+ code = ReadFileFn(filename)
102-
name = NormalizeFileName(filename)
103-
slug = SLUGGER_RE.sub('_', name)
104-
var = slug + '_raw'
105-
@@ -124,7 +128,9 @@ def AddModule(filename, definitions, initializers):
106-
initializers.append(initializer)
107-
108-
def NormalizeFileName(filename):
109-
- split = filename.split('/')
110-
+ if filename.startswith('//v8'):
111-
+ filename = "deps/" + filename[2:]
112-
+ split = os.path.normpath(filename).split(os.path.sep)
113-
if split[0] == 'deps':
114-
split = ['internal'] + split
115-
else: # `lib/**/*.js` so drop the 'lib' part
116-
@@ -142,23 +148,36 @@ def NormalizeFileName(filename):
117-
return os.path.splitext(filename)[0]
118-
119-
120-
-def JS2C(source_files, target):
121-
+def JS2C(source_files, target, only_js):
122-
# Build source code lines
123-
definitions = []
124-
initializers = []
125-
126-
- for filename in source_files['.js']:
127-
- AddModule(filename, definitions, initializers)
128-
- for filename in source_files['.mjs']:
129-
- AddModule(filename, definitions, initializers)
130-
-
131-
- config_def, config_size = handle_config_gypi(source_files['config.gypi'])
132-
- definitions.append(config_def)
133-
+ for extension in source_files.keys():
134-
+ if extension == '.js' or extension == '.mjs':
135-
+ for filename in source_files[extension]:
136-
+ AddModule(filename, definitions, initializers)
63+
std::vector<std::string_view> GetBuiltinIds() const;
64+
diff --git a/tools/js2c.cc b/tools/js2c.cc
65+
index 904fb6fa44d4f56fb67476e937edcbb797d78fe7..28dc4b59898fb5ac02dc55f930613f7a46a8a66e 100644
66+
--- a/tools/js2c.cc
67+
+++ b/tools/js2c.cc
68+
@@ -29,6 +29,7 @@ namespace js2c {
69+
int Main(int argc, char* argv[]);
70+
71+
static bool is_verbose = false;
72+
+static bool only_js = false;
73+
74+
void Debug(const char* format, ...) {
75+
va_list arguments;
76+
@@ -213,13 +214,17 @@ void BuiltinLoader::LoadJavaScriptSource() {
77+
source_ = global_source_map;
78+
}
79+
80+
+void BuiltinLoader::LoadEmbedderJavaScriptSource() {
81+
+ source_ = global_source_map;
82+
+}
83+
+
84+
void RegisterExternalReferencesForInternalizedBuiltinCode(
85+
ExternalReferenceRegistry* registry) {
86+
%.*s
87+
}
88+
89+
UnionBytes BuiltinLoader::GetConfig() {
90+
- return UnionBytes(&config_resource);
91+
+ return config_resource ? UnionBytes(&config_resource) : UnionBytes(nullptr);
92+
}
93+
94+
} // namespace builtins
95+
@@ -254,10 +259,14 @@ Fragment Format(const Fragments& definitions,
96+
}
97+
98+
std::vector<char> ReadFileSync(const char* path, size_t size, int* error) {
99+
+ std::string filepath(path);
100+
+ if (filepath.starts_with("//v8"))
101+
+ filepath = "../../" + filepath.substr(2);
102+
+
103+
uv_fs_t req;
104+
- Debug("ReadFileSync %s with size %zu\n", path, size);
105+
+ Debug("ReadFileSync %s with size %zu\n", filepath.c_str(), size);
106+
107+
- uv_file file = uv_fs_open(nullptr, &req, path, O_RDONLY, 0, nullptr);
108+
+ uv_file file = uv_fs_open(nullptr, &req, filepath.c_str(), O_RDONLY, 0, nullptr);
109+
if (req.result < 0) {
110+
uv_fs_req_cleanup(&req);
111+
*error = req.result;
112+
@@ -536,7 +545,8 @@ Fragment GetDefinition(const std::string& var, const std::vector<char>& code) {
113+
int AddModule(const std::string& filename,
114+
Fragments* definitions,
115+
Fragments* initializers,
116+
- Fragments* registrations) {
117+
+ Fragments* registrations,
118+
+ std::function<std::vector<char>(const std::vector<char>&)> read_file_fn = ReadFileSync) {
119+
Debug("AddModule %s start\n", filename.c_str());
120+
121+
int error = 0;
122+
@@ -544,7 +554,7 @@ int AddModule(const std::string& filename,
123+
if (error != 0) {
124+
return error;
125+
}
126+
- std::vector<char> code = ReadFileSync(filename.c_str(), file_size, &error);
127+
+ std::vector<char> code = read_file_fn(filename.c_str(), file_size, &error);
128+
if (error != 0) {
129+
return error;
130+
}
131+
@@ -703,6 +713,39 @@ int JS2C(const FileList& js_files,
132+
if (r != 0) {
133+
return r;
134+
}
137135
+
138-
+ # Electron: Expose fs module without asar support.
139-
+ if filename == 'lib/fs.js':
140-
+ # Node's 'fs' and 'internal/fs/<filename> have lazy-loaded circular
141-
+ # dependencies. So to expose the unmodified Node 'fs' functionality here,
142-
+ # we have to copy both 'fs' *and* 'internal/fs/<filename>' files and modify the
143-
+ # copies to depend on each other instead of on our asarified 'fs' code.
144-
+ AddModule('lib/original-fs.js', definitions, initializers, lambda _: ReadFile(filename).replace("require('internal/fs/", "require('internal/original-fs/"))
145-
+ elif filename.startswith('lib/internal/fs/'):
146-
+ original_fs_filename = filename.replace('internal/fs/', 'internal/original-fs/')
147-
+ AddModule(original_fs_filename, definitions, initializers, lambda _: ReadFile(filename).replace("require('fs')", "require('original-fs')"))
136+
+ // Electron: Expose fs module without asar support.
137+
+ if (filename == "lib/fs.js") {
138+
+ int error = 0;
139+
+ size_t size = GetFileSize(filename, &error);
140+
+ if (error != 0 && error != UV_ENOENT)
141+
+ return error;
148142
+
149-
+ config_size = 0
150-
+ if not only_js:
151-
+ config_def, config_size = handle_config_gypi(source_files['config.gypi'])
152-
+ definitions.append(config_def)
153-
154-
# Emit result
155-
definitions = ''.join(definitions)
156-
initializers = '\n '.join(initializers)
157-
- out = TEMPLATE.format(definitions, initializers, config_size)
158-
+ out = TEMPLATE.format(definitions, initializers, '0' if only_js else '1', config_size, 'Embedder' if only_js else '')
159-
write_if_chaged(out, target)
160-
161-
162-
@@ -222,6 +241,7 @@ def main():
163-
default=None,
164-
help='root directory containing the sources')
165-
parser.add_argument('--verbose', action='store_true', help='output file')
166-
+ parser.add_argument('--only-js', action='store_true', help='do not require or parse any config.gypi files')
167-
parser.add_argument('sources', nargs='*', help='input files')
168-
options = parser.parse_args()
169-
global is_verbose
170-
@@ -238,13 +258,15 @@ def main():
171-
172-
source_files = functools.reduce(SourceFileByExt, sources, {})
173-
174-
- # Should have exactly 3 types: `.js`, `.mjs` and `.gypi`
175-
- assert len(source_files) == 3
176-
- # Currently config.gypi is the only `.gypi` file allowed
177-
- assert len(source_files['.gypi']) == 1
178-
- assert os.path.basename(source_files['.gypi'][0]) == 'config.gypi'
179-
- source_files['config.gypi'] = source_files.pop('.gypi')[0]
180-
- JS2C(source_files, options.target)
181-
+ if options.only_js:
182-
+ assert len(source_files) == 1
183-
+ else:
184-
+ # Should have exactly 3 types: `.js`, `.mjs` and `.gypi`
185-
+ assert len(source_files) == 3
186-
+ # Currently config.gypi is the only `.gypi` file allowed
187-
+ assert source_files['.gypi'][0].endswith('config.gypi')
188-
+ source_files['config.gypi'] = source_files.pop('.gypi')[0]
189-
+ JS2C(source_files, options.target, options.only_js)
190-
191-
192-
if __name__ == "__main__":
143+
+ std::function<std::vector<char>(const std::vector<char>&)> ReadFileTransform = [](const char* path, size_t size, int* error) {
144+
+ std::vector<char> code = ReadFileSync(path, size, &error);
145+
+ std::replace(code.begin(), code.end(), "require('internal/fs/", "require('internal/original-fs/");
146+
+ return code;
147+
+ };
148+
+ int r = AddModule("lib/original-fs.js", definitions, initializers, ReadFileTransform)
149+
+ if (r != 0) {
150+
+ return r;
151+
+ }
152+
+ } else if (filename.rfind("lib/internal/fs/")) {
153+
+ // std::equal(prefix.begin(), prefix.end(), toCheck.begin())?
154+
+ std::string original_fs_filename = filename;
155+
+ std::replace(original_fs_filename.begin(), original_fs_filename.end(), "internal/fs/", "internal/original-fs/");
156+
+
157+
+ std::function<std::vector<char>(const std::vector<char>&)> ReadFileTransform = [](const char* path, size_t size, int* error) {
158+
+ std::vector<char> code = ReadFileSync(path, size, &error);
159+
+ std::replace(code.begin(), code.end(), "require('fs')", "require('original-fs')");
160+
+ return code;
161+
+ };
162+
+
163+
+ int r = AddModule(original_fs_filename, definitions, initializers, ReadFileTransform)
164+
+ if (r != 0) {
165+
+ return r;
166+
+ }
167+
+ }
168+
}
169+
for (const auto& filename : mjs_files) {
170+
int r = AddModule(filename, &definitions, &initializers, &registrations);
171+
@@ -711,12 +754,15 @@ int JS2C(const FileList& js_files,
172+
}
173+
}
174+
175+
- assert(FilenameIsConfigGypi(config));
176+
- // "config.gypi" -> config_raw.
177+
- int r = AddGypi("config", config, &definitions);
178+
- if (r != 0) {
179+
- return r;
180+
+ if (!only_js) {
181+
+ assert(FilenameIsConfigGypi(config));
182+
+ // "config.gypi" -> config_raw.
183+
+ int r = AddGypi("config", config, &definitions);
184+
+ if (r != 0) {
185+
+ return r;
186+
+ }
187+
}
188+
+
189+
Fragment out = Format(definitions, initializers, registrations);
190+
return WriteIfChanged(out, dest);
191+
}
192+
@@ -742,6 +788,8 @@ int Main(int argc, char* argv[]) {
193+
std::string arg(argv[i]);
194+
if (arg == "--verbose") {
195+
is_verbose = true;
196+
+ } else if (arg == "--only-js") {
197+
+ only_js = true;
198+
} else if (arg == "--root") {
199+
if (i == argc - 1) {
200+
fprintf(stderr, "--root must be followed by a path\n");
201+
@@ -790,23 +838,30 @@ int Main(int argc, char* argv[]) {
202+
}
203+
}
204+
205+
- // Should have exactly 3 types: `.js`, `.mjs` and `.gypi`.
206+
- assert(file_map.size() == 3);
207+
- auto gypi_it = file_map.find(".gypi");
208+
- // Currently config.gypi is the only `.gypi` file allowed
209+
- if (gypi_it == file_map.end() || gypi_it->second.size() != 1 ||
210+
- !FilenameIsConfigGypi(gypi_it->second[0])) {
211+
- fprintf(
212+
- stderr,
213+
- "Arguments should contain one and only one .gypi file: config.gypi\n");
214+
- return 1;
215+
- }
216+
auto js_it = file_map.find(".js");
217+
auto mjs_it = file_map.find(".mjs");
218+
- assert(js_it != file_map.end() && mjs_it != file_map.end());
219+
+ auto gypi_it = file_map.find(".gypi");
220+
221+
- std::sort(js_it->second.begin(), js_it->second.end());
222+
- std::sort(mjs_it->second.begin(), mjs_it->second.end());
223+
+ if (only_js) {
224+
+ assert(file_map.size() == 1);
225+
+ assert(js_it != file_map.end());
226+
+ } else {
227+
+ // Should have exactly 3 types: `.js`, `.mjs` and `.gypi`.
228+
+ assert(file_map.size() == 3);
229+
+ assert(js_it != file_map.end() && mjs_it != file_map.end());
230+
+
231+
+ std::sort(js_it->second.begin(), js_it->second.end());
232+
+ std::sort(mjs_it->second.begin(), mjs_it->second.end());
233+
+
234+
+ // Currently config.gypi is the only `.gypi` file allowed
235+
+ if (gypi_it == file_map.end() || gypi_it->second.size() != 1 ||
236+
+ !FilenameIsConfigGypi(gypi_it->second[0])) {
237+
+ fprintf(
238+
+ stderr,
239+
+ "Arguments should contain one and only one .gypi file: config.gypi\n");
240+
+ return 1;
241+
+ }
242+
+ }
243+
244+
return JS2C(js_it->second, mjs_it->second, gypi_it->second[0], output);
245+
}
246+

0 commit comments

Comments
 (0)