tools: implement mkcodecache as an executable · nodejs/node@4fd7193 (original) (raw)
``
1
`+
#include "cache_builder.h"
`
``
2
`+
#include
`
``
3
`+
#include
`
``
4
`+
#include
`
``
5
`+
#include
`
``
6
`+
#include
`
``
7
`+
#include "util.h"
`
``
8
+
``
9
`+
#include "node_native_module.h"
`
``
10
+
``
11
`+
namespace node {
`
``
12
`+
namespace native_module {
`
``
13
+
``
14
`+
using v8::Context;
`
``
15
`+
using v8::Function;
`
``
16
`+
using v8::Isolate;
`
``
17
`+
using v8::Local;
`
``
18
`+
using v8::MaybeLocal;
`
``
19
`+
using v8::ScriptCompiler;
`
``
20
+
``
21
`+
static std::string GetDefName(const std::string& id) {
`
``
22
`+
char buf[64] = {0};
`
``
23
`+
size_t size = id.size();
`
``
24
`+
CHECK_LT(size, sizeof(buf));
`
``
25
`+
for (size_t i = 0; i < size; ++i) {
`
``
26
`+
char ch = id[i];
`
``
27
`+
buf[i] = (ch == '-' || ch == '/') ? '_' : ch;
`
``
28
`+
}
`
``
29
`+
return buf;
`
``
30
`+
}
`
``
31
+
``
32
`+
static std::string FormatSize(size_t size) {
`
``
33
`+
char buf[64] = {0};
`
``
34
`+
if (size < 1024) {
`
``
35
`+
snprintf(buf, sizeof(buf), "%.2fB", static_cast(size));
`
``
36
`+
} else if (size < 1024 * 1024) {
`
``
37
`+
snprintf(buf, sizeof(buf), "%.2fKB", static_cast(size / 1024));
`
``
38
`+
} else {
`
``
39
`+
snprintf(
`
``
40
`+
buf, sizeof(buf), "%.2fMB", static_cast(size / 1024 / 1024));
`
``
41
`+
}
`
``
42
`+
return buf;
`
``
43
`+
}
`
``
44
+
``
45
`+
static std::string GetDefinition(const std::string& id,
`
``
46
`+
size_t size,
`
``
47
`+
const uint8_t* data) {
`
``
48
`+
std::stringstream ss;
`
``
49
`+
ss << "static const uint8_t " << GetDefName(id) << "[] = {\n";
`
``
50
`+
for (size_t i = 0; i < size; ++i) {
`
``
51
`+
uint8_t ch = data[i];
`
``
52
`+
ss << std::to_string(ch) << (i == size - 1 ? '\n' : ',');
`
``
53
`+
}
`
``
54
`+
ss << "};";
`
``
55
`+
return ss.str();
`
``
56
`+
}
`
``
57
+
``
58
`+
static std::string GetInitializer(const std::string& id) {
`
``
59
`+
std::string def_name = GetDefName(id);
`
``
60
`+
char buf[256] = {0};
`
``
61
`+
snprintf(buf,
`
``
62
`+
sizeof(buf),
`
``
63
`+
"code_cache->emplace(\n"
`
``
64
`+
" "%s",\n"
`
``
65
`+
" std::make_uniquev8::ScriptCompiler::CachedData"
`
``
66
`+
"(%s, static_cast(arraysize(%s)), policy)\n"
`
``
67
`+
");",
`
``
68
`+
id.c_str(),
`
``
69
`+
def_name.c_str(),
`
``
70
`+
def_name.c_str());
`
``
71
`+
return buf;
`
``
72
`+
}
`
``
73
+
``
74
`+
static std::string GenerateCodeCache(
`
``
75
`+
std::map<std::string, ScriptCompiler::CachedData*> data,
`
``
76
`+
std::vectorstd::string ids,
`
``
77
`+
bool log_progress) {
`
``
78
`+
std::stringstream ss;
`
``
79
`+
ss << R"(#include
`
``
80
`+
#include "node_native_module_env.h"
`
``
81
+
``
82
`+
// This file is generated by tools/mkcodecache
`
``
83
`` +
// and is used when configure is run with `--code-cache-path`
``
``
84
+
``
85
`+
namespace node {
`
``
86
`+
namespace native_module {
`
``
87
`+
)";
`
``
88
+
``
89
`+
size_t total = 0;
`
``
90
`+
for (const auto& x : data) {
`
``
91
`+
const std::string& id = x.first;
`
``
92
`+
ScriptCompiler::CachedData* cached_data = x.second;
`
``
93
`+
total += cached_data->length;
`
``
94
`+
std::string def = GetDefinition(id, cached_data->length, cached_data->data);
`
``
95
`+
ss << def << "\n\n";
`
``
96
`+
if (log_progress) {
`
``
97
`+
std::cout << "Generated cache for " << id
`
``
98
`+
<< ", size = " << FormatSize(cached_data->length)
`
``
99
`+
<< ", total = " << FormatSize(total) << "\n";
`
``
100
`+
}
`
``
101
`+
}
`
``
102
+
``
103
`+
ss << R"(void NativeModuleEnv::InitializeCodeCache() {
`
``
104
`+
NativeModuleCacheMap* code_cache =
`
``
105
`+
NativeModuleLoader::GetInstance()->code_cache();
`
``
106
`+
if (!code_cache->empty()) {
`
``
107
`+
return;
`
``
108
`+
}
`
``
109
`+
auto policy = v8::ScriptCompiler::CachedData::BufferPolicy::BufferNotOwned;
`
``
110
`+
)";
`
``
111
+
``
112
`+
for (const auto& x : data) {
`
``
113
`+
const std::string& id = x.first;
`
``
114
`+
ss << GetInitializer(id) << "\n\n";
`
``
115
`+
}
`
``
116
+
``
117
`+
ss << R"(}
`
``
118
+
``
119
`+
} // namespace native_module
`
``
120
`+
} // namespace node
`
``
121
`+
)";
`
``
122
`+
return ss.str();
`
``
123
`+
}
`
``
124
+
``
125
`+
std::string CodeCacheBuilder::Generate(Local context) {
`
``
126
`+
NativeModuleLoader* loader = NativeModuleLoader::GetInstance();
`
``
127
`+
std::vectorstd::string ids = loader->GetModuleIds();
`
``
128
+
``
129
`+
std::vectorstd::string modules;
`
``
130
`+
modules.reserve(ids.size());
`
``
131
+
``
132
`+
std::map<std::string, ScriptCompiler::CachedData*> data;
`
``
133
+
``
134
`+
NativeModuleLoader::Result result;
`
``
135
`+
for (const auto& id : ids) {
`
``
136
`+
// TODO(joyeecheung): we can only compile the modules that can be
`
``
137
`+
// required here because the parameters for other types of builtins
`
``
138
`+
// are still very flexible. We should look into auto-generating
`
``
139
`+
// the paramters from the source somehow.
`
``
140
`+
if (loader->CanBeRequired(id.c_str())) {
`
``
141
`+
modules.push_back(id);
`
``
142
`+
USE(loader->CompileAsModule(context, id.c_str(), &result));
`
``
143
`+
ScriptCompiler::CachedData* cached_data =
`
``
144
`+
loader->GetCodeCache(id.c_str());
`
``
145
`+
if (cached_data == nullptr) {
`
``
146
`+
// TODO(joyeecheung): display syntax errors
`
``
147
`+
std::cerr << "Failed to complile " << id << "\n";
`
``
148
`+
} else {
`
``
149
`+
data.emplace(id, cached_data);
`
``
150
`+
}
`
``
151
`+
}
`
``
152
`+
}
`
``
153
+
``
154
`+
char env_buf[32];
`
``
155
`+
size_t env_size = sizeof(env_buf);
`
``
156
`+
int ret = uv_os_getenv("NODE_DEBUG", env_buf, &env_size);
`
``
157
`+
bool log_progress = false;
`
``
158
`+
if (ret == 0 && strcmp(env_buf, "mkcodecache") == 0) {
`
``
159
`+
log_progress = true;
`
``
160
`+
}
`
``
161
`+
return GenerateCodeCache(data, modules, log_progress);
`
``
162
`+
}
`
``
163
+
``
164
`+
} // namespace native_module
`
``
165
`+
} // namespace node
`