Skip to content

Commit 5325be1

Browse files
joyeecheungtargos
authored andcommittedMay 30, 2023
tools: port js2c.py to C++
This makes it easier to use third-party dependencies in this tool (e.g. adding compression using algorithms not available in Python). It is also much faster - locally js2c.py takes ~1.5s to generate the output whereas this version takes ~0.1s - and consumes less memory (~110MB v.s. 66MB). This also modifies the js2c.py a bit to simplify the output, making it easier to compare with one generated by the C++ version. Locally the output from the two are identical. We'll remove js2c.py in a subsequent commit when the C++ version is used by default. PR-URL: #46997 Reviewed-By: Yagiz Nizipli <[email protected]>

File tree

5 files changed

+857
-18
lines changed

5 files changed

+857
-18
lines changed
 

‎Makefile

+1
Original file line numberDiff line numberDiff line change
@@ -1409,6 +1409,7 @@ LINT_CPP_FILES = $(filter-out $(LINT_CPP_EXCLUDE), $(wildcard \
14091409
test/fixtures/*.c \
14101410
test/js-native-api/*/*.cc \
14111411
test/node-api/*/*.cc \
1412+
tools/js2c.cc \
14121413
tools/icu/*.cc \
14131414
tools/icu/*.h \
14141415
tools/code_cache/*.cc \

‎node.gyp

+29
Original file line numberDiff line numberDiff line change
@@ -1176,6 +1176,35 @@
11761176
}],
11771177
]
11781178
}, # overlapped-checker
1179+
{
1180+
'target_name': 'node_js2c',
1181+
'type': 'executable',
1182+
'dependencies': [
1183+
'deps/simdutf/simdutf.gyp:simdutf',
1184+
],
1185+
'include_dirs': [
1186+
'tools'
1187+
],
1188+
'sources': [
1189+
'tools/js2c.cc',
1190+
'tools/executable_wrapper.h'
1191+
],
1192+
'conditions': [
1193+
[ 'node_shared_libuv=="false"', {
1194+
'dependencies': [ 'deps/uv/uv.gyp:libuv' ],
1195+
}],
1196+
[ 'debug_node=="true"', {
1197+
'cflags!': [ '-O3' ],
1198+
'cflags': [ '-g', '-O0' ],
1199+
'defines': [ 'DEBUG' ],
1200+
'xcode_settings': {
1201+
'OTHER_CFLAGS': [
1202+
'-g', '-O0'
1203+
],
1204+
},
1205+
}],
1206+
]
1207+
},
11791208
{
11801209
'target_name': 'node_mksnapshot',
11811210
'type': 'executable',

‎tools/executable_wrapper.h

+55
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
#ifndef TOOLS_EXECUTABLE_WRAPPER_H_
2+
#define TOOLS_EXECUTABLE_WRAPPER_H_
3+
4+
// TODO(joyeecheung): reuse this in mksnapshot.
5+
#include "uv.h"
6+
#ifdef _WIN32
7+
#include <windows.h>
8+
#endif
9+
10+
namespace node {
11+
#ifdef _WIN32
12+
using argv_type = wchar_t*;
13+
#define NODE_MAIN int wmain
14+
15+
void FixupMain(int argc, argv_type raw_argv[], char*** argv) {
16+
// Convert argv to UTF8.
17+
*argv = new char*[argc + 1];
18+
for (int i = 0; i < argc; i++) {
19+
// Compute the size of the required buffer
20+
DWORD size = WideCharToMultiByte(
21+
CP_UTF8, 0, raw_argv[i], -1, nullptr, 0, nullptr, nullptr);
22+
if (size == 0) {
23+
// This should never happen.
24+
fprintf(stderr, "Could not convert arguments to utf8.");
25+
exit(1);
26+
}
27+
// Do the actual conversion
28+
(*argv)[i] = new char[size];
29+
DWORD result = WideCharToMultiByte(
30+
CP_UTF8, 0, raw_argv[i], -1, (*argv)[i], size, nullptr, nullptr);
31+
if (result == 0) {
32+
// This should never happen.
33+
fprintf(stderr, "Could not convert arguments to utf8.");
34+
exit(1);
35+
}
36+
}
37+
(*argv)[argc] = nullptr;
38+
}
39+
#else
40+
41+
using argv_type = char*;
42+
#define NODE_MAIN int main
43+
44+
void FixupMain(int argc, argv_type raw_argv[], char*** argv) {
45+
*argv = uv_setup_args(argc, raw_argv);
46+
// Disable stdio buffering, it interacts poorly with printf()
47+
// calls elsewhere in the program (e.g., any logging from V8.)
48+
setvbuf(stdout, nullptr, _IONBF, 0);
49+
setvbuf(stderr, nullptr, _IONBF, 0);
50+
}
51+
#endif
52+
53+
} // namespace node
54+
55+
#endif // TOOLS_EXECUTABLE_WRAPPER_H_

‎tools/js2c.cc

+756
Large diffs are not rendered by default.

‎tools/js2c.py

+16-18
Original file line numberDiff line numberDiff line change
@@ -55,22 +55,22 @@ def ReadFile(filename):
5555
namespace node {{
5656
5757
namespace builtins {{
58-
5958
{0}
60-
6159
namespace {{
6260
const ThreadsafeCopyOnWrite<BuiltinSourceMap> global_source_map {{
63-
BuiltinSourceMap{{ {1} }}
64-
}};
65-
}}
61+
BuiltinSourceMap {{
62+
{1}
63+
}} // BuiltinSourceMap
64+
}}; // ThreadsafeCopyOnWrite
65+
}} // anonymous namespace
6666
6767
void BuiltinLoader::LoadJavaScriptSource() {{
6868
source_ = global_source_map;
6969
}}
7070
7171
void RegisterExternalReferencesForInternalizedBuiltinCode(
7272
ExternalReferenceRegistry* registry) {{
73-
{2}
73+
{2}
7474
}}
7575
7676
UnionBytes BuiltinLoader::GetConfig() {{
@@ -98,9 +98,9 @@ def ReadFile(filename):
9898
static StaticExternalTwoByteResource {2}({0}, {3}, nullptr);
9999
"""
100100

101-
INITIALIZER = '{{"{0}", UnionBytes(&{1}) }},'
101+
INITIALIZER = ' {{"{0}", UnionBytes(&{1}) }},'
102102

103-
REGISTRATION = 'registry->Register(&{0});'
103+
REGISTRATION = ' registry->Register(&{0});'
104104

105105
CONFIG_GYPI_ID = 'config_raw'
106106

@@ -110,7 +110,7 @@ def ReadFile(filename):
110110

111111
is_verbose = False
112112

113-
def GetDefinition(var, source, resource_var, step=30):
113+
def GetDefinition(var, source, resource_var):
114114
template = ONE_BYTE_STRING
115115
code_points = [ord(c) for c in source]
116116
if any(c > 127 for c in code_points):
@@ -122,12 +122,8 @@ def GetDefinition(var, source, resource_var, step=30):
122122
for i in range(0, len(encoded_source), 2)
123123
]
124124

125-
# For easier debugging, align to the common 3 char for code-points.
126-
elements_s = ['%3s' % x for x in code_points]
127-
# Put no more then `step` code-points in a line.
128-
slices = [elements_s[i:i + step] for i in range(0, len(elements_s), step)]
129-
lines = [','.join(s) for s in slices]
130-
array_content = ',\n'.join(lines)
125+
elements_s = ['%s' % x for x in code_points]
126+
array_content = ','.join(elements_s) + ','
131127
length = len(code_points)
132128
definition = template.format(var, array_content, resource_var, length)
133129

@@ -174,8 +170,8 @@ def JS2C(source_files, target):
174170

175171
# Emit result
176172
definitions = ''.join(definitions)
177-
initializers = '\n '.join(initializers)
178-
registrations = '\n '.join(registrations)
173+
initializers = '\n'.join(initializers)
174+
registrations = '\n'.join(registrations)
179175
out = TEMPLATE.format(definitions, initializers,
180176
registrations, CONFIG_GYPI_RESOURCE_ID)
181177
write_if_chaged(out, target)
@@ -263,8 +259,10 @@ def main():
263259
assert len(source_files['.gypi']) == 1
264260
assert os.path.basename(source_files['.gypi'][0]) == 'config.gypi'
265261
source_files['config.gypi'] = source_files.pop('.gypi')[0]
266-
JS2C(source_files, options.target)
262+
source_files['.js'] = sorted(source_files['.js'])
263+
source_files['.mjs'] = sorted(source_files['.mjs'])
267264

265+
JS2C(source_files, options.target)
268266

269267
if __name__ == "__main__":
270268
main()

0 commit comments

Comments
 (0)
Please sign in to comment.