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

src,tools: speed up startup by 2.5% #5458

Merged
merged 1 commit into from
Oct 25, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
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
49 changes: 31 additions & 18 deletions src/node_javascript.cc
Original file line number Diff line number Diff line change
Expand Up @@ -6,33 +6,46 @@

namespace node {

using v8::HandleScope;
using v8::Local;
using v8::NewStringType;
using v8::Object;
using v8::String;

// id##_data is defined in node_natives.h.
#define V(id) \
static struct : public String::ExternalOneByteStringResource { \
const char* data() const override { \
return reinterpret_cast<const char*>(id##_data); \
} \
size_t length() const override { return sizeof(id##_data); } \
void Dispose() override { /* Default calls `delete this`. */ } \
} id##_external_data;
NODE_NATIVES_MAP(V)
#undef V

Local<String> MainSource(Environment* env) {
return String::NewFromUtf8(
env->isolate(),
reinterpret_cast<const char*>(internal_bootstrap_node_native),
NewStringType::kNormal,
sizeof(internal_bootstrap_node_native)).ToLocalChecked();
auto maybe_string =
String::NewExternalOneByte(
env->isolate(),
&internal_bootstrap_node_external_data);
return maybe_string.ToLocalChecked();
}

void DefineJavaScript(Environment* env, Local<Object> target) {
HandleScope scope(env->isolate());

for (auto native : natives) {
if (native.source != internal_bootstrap_node_native) {
Local<String> name = String::NewFromUtf8(env->isolate(), native.name);
Local<String> source =
String::NewFromUtf8(
env->isolate(), reinterpret_cast<const char*>(native.source),
NewStringType::kNormal, native.source_len).ToLocalChecked();
target->Set(name, source);
}
}
auto context = env->context();
#define V(id) \
do { \
auto key = \
String::NewFromOneByte( \
env->isolate(), id##_name, NewStringType::kNormal, \
sizeof(id##_name)).ToLocalChecked(); \
auto value = \
String::NewExternalOneByte( \
env->isolate(), &id##_external_data).ToLocalChecked(); \
CHECK(target->Set(context, key, value).FromJust()); \
} while (0);
NODE_NATIVES_MAP(V)
#undef V
}

} // namespace node
164 changes: 31 additions & 133 deletions tools/js2c.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,11 @@
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):
Expand All @@ -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))
Expand Down Expand Up @@ -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 = []
Expand All @@ -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.
Expand All @@ -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:]
Expand Down