diff options
author | Ben Noordhuis <info@bnoordhuis.nl> | 2016-05-13 23:08:43 +0200 |
---|---|---|
committer | Ben Noordhuis <info@bnoordhuis.nl> | 2016-10-25 13:16:16 +0200 |
commit | e4290dec2df252cbaaf79098784730924153b182 (patch) | |
tree | 59af9bb9844049aea0c7322d6567e570c47dc213 /tools | |
parent | 2a456162b67e914eec77849623dcdb87011a482f (diff) | |
download | node-new-e4290dec2df252cbaaf79098784730924153b182.tar.gz |
src,tools: speed up startup by 2.5%
Use zero-copy external string resources for storing the built-in JS
source code. Saves a few hundred kilobyte of memory and consistently
speeds up `benchmark/misc/startup.js` by 2.5%.
Everything old is new again! Commit 74954ce ("Add string class that
uses ExternalAsciiStringResource.") from 2011 did the same thing but
I removed that in 2013 in commit 34b0a36 ("src: don't use NewExternal()
with unaligned strings") because of a limitation in the V8 API.
V8 no longer requires that strings are aligned if they are one-byte
strings so it should be safe to re-enable external strings again.
PR-URL: https://github.com/nodejs/node/pull/5458
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Robert Jefe Lindstaedt <robert.lindstaedt@gmail.com>
Diffstat (limited to 'tools')
-rwxr-xr-x | tools/js2c.py | 164 |
1 files changed, 31 insertions, 133 deletions
diff --git a/tools/js2c.py b/tools/js2c.py index 40c30cc032..4808c56813 100755 --- a/tools/js2c.py +++ b/tools/js2c.py @@ -37,8 +37,11 @@ import sys import string -def ToCArray(filename, lines): - return ','.join(str(ord(c)) for c in lines) +def ToCString(contents): + step = 20 + slices = (contents[i:i+step] for i in xrange(0, len(contents), step)) + slices = map(lambda s: ','.join(str(ord(c)) for c in s), slices) + return ',\n'.join(slices) def ReadFile(filename): @@ -61,21 +64,6 @@ def ReadLines(filename): return result -def LoadConfigFrom(name): - import ConfigParser - config = ConfigParser.ConfigParser() - config.read(name) - return config - - -def ParseValue(string): - string = string.strip() - if string.startswith('[') and string.endswith(']'): - return string.lstrip('[').rstrip(']').split() - else: - return string - - def ExpandConstants(lines, constants): for key, value in constants.items(): lines = lines.replace(key, str(value)) @@ -174,53 +162,37 @@ def ReadMacros(lines): HEADER_TEMPLATE = """\ -#ifndef node_natives_h -#define node_natives_h -namespace node { - -%(source_lines)s\ +#ifndef NODE_NATIVES_H_ +#define NODE_NATIVES_H_ -struct _native { - const char* name; - const unsigned char* source; - size_t source_len; -}; +#include <stdint.h> -static const struct _native natives[] = { %(native_lines)s }; +#define NODE_NATIVES_MAP(V) \\ +{node_natives_map} -} -#endif -""" - - -NATIVE_DECLARATION = """\ - { "%(id)s", %(escaped_id)s_native, sizeof(%(escaped_id)s_native) }, -""" +namespace node {{ +{sources} +}} // namespace node -SOURCE_DECLARATION = """\ - const unsigned char %(escaped_id)s_native[] = { %(data)s }; +#endif // NODE_NATIVES_H_ """ -GET_DELAY_INDEX_CASE = """\ - if (strcmp(name, "%(id)s") == 0) return %(i)i; +NODE_NATIVES_MAP = """\ + V({escaped_id}) \\ """ -GET_DELAY_SCRIPT_SOURCE_CASE = """\ - if (index == %(i)i) return Vector<const char>(%(id)s, %(length)i); +SOURCES = """\ +static const uint8_t {escaped_id}_name[] = {{ +{name}}}; +static const uint8_t {escaped_id}_data[] = {{ +{data}}}; """ -GET_DELAY_SCRIPT_NAME_CASE = """\ - if (index == %(i)i) return Vector<const char>("%(name)s", %(length)i); -""" - def JS2C(source, target): - ids = [] - delay_ids = [] modules = [] - # Locate the macros file name. consts = {} macros = {} macro_lines = [] @@ -235,18 +207,14 @@ def JS2C(source, target): (consts, macros) = ReadMacros(macro_lines) # Build source code lines - source_lines = [ ] - source_lines_empty = [] - - native_lines = [] + node_natives_map = [] + sources = [] for s in modules: - delay = str(s).endswith('-delay.js') lines = ReadFile(str(s)) - lines = ExpandConstants(lines, consts) lines = ExpandMacros(lines, macros) - data = ToCArray(s, lines) + data = ToCString(lines) # On Windows, "./foo.bar" in the .gyp file is passed as "foo.bar" # so don't assume there is always a slash in the file path. @@ -258,89 +226,19 @@ def JS2C(source, target): if '.' in id: id = id.split('.', 1)[0] - if delay: id = id[:-6] - if delay: - delay_ids.append((id, len(lines))) - else: - ids.append((id, len(lines))) - + name = ToCString(id) escaped_id = id.replace('-', '_').replace('/', '_') - source_lines.append(SOURCE_DECLARATION % { - 'id': id, - 'escaped_id': escaped_id, - 'data': data - }) - source_lines_empty.append(SOURCE_DECLARATION % { - 'id': id, - 'escaped_id': escaped_id, - 'data': 0 - }) - native_lines.append(NATIVE_DECLARATION % { - 'id': id, - 'escaped_id': escaped_id - }) - - # Build delay support functions - get_index_cases = [ ] - get_script_source_cases = [ ] - get_script_name_cases = [ ] - - i = 0 - for (id, length) in delay_ids: - native_name = "native %s.js" % id - get_index_cases.append(GET_DELAY_INDEX_CASE % { 'id': id, 'i': i }) - get_script_source_cases.append(GET_DELAY_SCRIPT_SOURCE_CASE % { - 'id': id, - 'length': length, - 'i': i - }) - get_script_name_cases.append(GET_DELAY_SCRIPT_NAME_CASE % { - 'name': native_name, - 'length': len(native_name), - 'i': i - }); - i = i + 1 - - for (id, length) in ids: - native_name = "native %s.js" % id - get_index_cases.append(GET_DELAY_INDEX_CASE % { 'id': id, 'i': i }) - get_script_source_cases.append(GET_DELAY_SCRIPT_SOURCE_CASE % { - 'id': id, - 'length': length, - 'i': i - }) - get_script_name_cases.append(GET_DELAY_SCRIPT_NAME_CASE % { - 'name': native_name, - 'length': len(native_name), - 'i': i - }); - i = i + 1 + node_natives_map.append(NODE_NATIVES_MAP.format(**locals())) + sources.append(SOURCES.format(**locals())) + + node_natives_map = ''.join(node_natives_map) + sources = ''.join(sources) # Emit result output = open(str(target[0]), "w") - output.write(HEADER_TEMPLATE % { - 'builtin_count': len(ids) + len(delay_ids), - 'delay_count': len(delay_ids), - 'source_lines': "\n".join(source_lines), - 'native_lines': "\n".join(native_lines), - 'get_index_cases': "".join(get_index_cases), - 'get_script_source_cases': "".join(get_script_source_cases), - 'get_script_name_cases': "".join(get_script_name_cases) - }) + output.write(HEADER_TEMPLATE.format(**locals())) output.close() - if len(target) > 1: - output = open(str(target[1]), "w") - output.write(HEADER_TEMPLATE % { - 'builtin_count': len(ids) + len(delay_ids), - 'delay_count': len(delay_ids), - 'source_lines': "\n".join(source_lines_empty), - 'get_index_cases': "".join(get_index_cases), - 'get_script_source_cases': "".join(get_script_source_cases), - 'get_script_name_cases': "".join(get_script_name_cases) - }) - output.close() - def main(): natives = sys.argv[1] source_files = sys.argv[2:] |