GCC Code Coverage Report
Directory: ../ Exec Total Coverage
File: /home/iojs/build/workspace/node-test-commit-linux-coverage-daily/nodes/benchmark/out/../src/node_native_module.cc Lines: 95 101 94.1 %
Date: 2020-05-27 22:15:15 Branches: 38 46 82.6 %

Line Branch Exec Source
1
#include "node_native_module.h"
2
#include "util-inl.h"
3
4
namespace node {
5
namespace native_module {
6
7
using v8::Context;
8
using v8::EscapableHandleScope;
9
using v8::Function;
10
using v8::HandleScope;
11
using v8::Integer;
12
using v8::Isolate;
13
using v8::Local;
14
using v8::Maybe;
15
using v8::MaybeLocal;
16
using v8::Object;
17
using v8::Script;
18
using v8::ScriptCompiler;
19
using v8::ScriptOrigin;
20
using v8::String;
21
22
4326
NativeModuleLoader NativeModuleLoader::instance_;
23
24
4326
NativeModuleLoader::NativeModuleLoader() : config_(GetConfig()) {
25
4326
  LoadJavaScriptSource();
26
4326
}
27
28
476958
NativeModuleLoader* NativeModuleLoader::GetInstance() {
29
476958
  return &instance_;
30
}
31
32
4567
bool NativeModuleLoader::Exists(const char* id) {
33
4567
  return source_.find(id) != source_.end();
34
}
35
36
9
bool NativeModuleLoader::Add(const char* id, const UnionBytes& source) {
37
9
  if (Exists(id)) {
38
    return false;
39
  }
40
9
  source_.emplace(id, source);
41
9
  return true;
42
}
43
44
7
Local<Object> NativeModuleLoader::GetSourceObject(Local<Context> context) {
45
7
  Isolate* isolate = context->GetIsolate();
46
7
  Local<Object> out = Object::New(isolate);
47
1568
  for (auto const& x : source_) {
48
1561
    Local<String> key = OneByteString(isolate, x.first.c_str(), x.first.size());
49
4683
    out->Set(context, key, x.second.ToStringChecked(isolate)).FromJust();
50
  }
51
7
  return out;
52
}
53
54
4601
Local<String> NativeModuleLoader::GetConfigString(Isolate* isolate) {
55
4601
  return config_.ToStringChecked(isolate);
56
}
57
58
4595
std::vector<std::string> NativeModuleLoader::GetModuleIds() {
59
4595
  std::vector<std::string> ids;
60
4595
  ids.reserve(source_.size());
61
1029312
  for (auto const& x : source_) {
62
1024717
    ids.emplace_back(x.first);
63
  }
64
4595
  return ids;
65
}
66
67
225
void NativeModuleLoader::InitializeModuleCategories() {
68
225
  if (module_categories_.is_initialized) {
69
    DCHECK(!module_categories_.can_be_required.empty());
70
223
    return;
71
  }
72
73
  std::vector<std::string> prefixes = {
74
#if !HAVE_OPENSSL
75
    "internal/crypto/",
76
#endif  // !HAVE_OPENSSL
77
78
    "internal/bootstrap/",
79
    "internal/per_context/",
80
    "internal/deps/",
81
    "internal/main/"
82
4
  };
83
84
14
  module_categories_.cannot_be_required = std::set<std::string> {
85
#if !HAVE_INSPECTOR
86
      "inspector",
87
      "internal/util/inspector",
88
#endif  // !HAVE_INSPECTOR
89
90
#if !NODE_USE_V8_PLATFORM || !defined(NODE_HAVE_I18N_SUPPORT)
91
      "trace_events",
92
#endif  // !NODE_USE_V8_PLATFORM
93
94
#if !HAVE_OPENSSL
95
      "crypto",
96
      "https",
97
      "http2",
98
      "tls",
99
      "_tls_common",
100
      "_tls_wrap",
101
      "internal/http2/core",
102
      "internal/http2/compat",
103
      "internal/policy/manifest",
104
      "internal/process/policy",
105
      "internal/streams/lazy_transform",
106
#endif  // !HAVE_OPENSSL
107
108
      "sys",  // Deprecated.
109
      "wasi",  // Experimental.
110
      "internal/test/binding",
111
      "internal/v8_prof_polyfill",
112
      "internal/v8_prof_processor",
113
12
  };
114
115
448
  for (auto const& x : source_) {
116
446
    const std::string& id = x.first;
117
2230
    for (auto const& prefix : prefixes) {
118
1784
      if (prefix.length() > id.length()) {
119
606
        continue;
120
      }
121
1178
      if (id.find(prefix) == 0) {
122
84
        module_categories_.cannot_be_required.emplace(id);
123
      }
124
    }
125
  }
126
127
448
  for (auto const& x : source_) {
128
446
    const std::string& id = x.first;
129
446
    if (0 == module_categories_.cannot_be_required.count(id)) {
130
352
      module_categories_.can_be_required.emplace(id);
131
    }
132
  }
133
134
2
  module_categories_.is_initialized = true;
135
}
136
137
1
const std::set<std::string>& NativeModuleLoader::GetCannotBeRequired() {
138
1
  InitializeModuleCategories();
139
1
  return module_categories_.cannot_be_required;
140
}
141
142
224
const std::set<std::string>& NativeModuleLoader::GetCanBeRequired() {
143
224
  InitializeModuleCategories();
144
224
  return module_categories_.can_be_required;
145
}
146
147
223
bool NativeModuleLoader::CanBeRequired(const char* id) {
148
223
  return GetCanBeRequired().count(id) == 1;
149
}
150
151
bool NativeModuleLoader::CannotBeRequired(const char* id) {
152
  return GetCannotBeRequired().count(id) == 1;
153
}
154
155
4263
NativeModuleCacheMap* NativeModuleLoader::code_cache() {
156
4263
  return &code_cache_;
157
}
158
159
176
ScriptCompiler::CachedData* NativeModuleLoader::GetCodeCache(
160
    const char* id) const {
161
352
  Mutex::ScopedLock lock(code_cache_mutex_);
162
176
  const auto it = code_cache_.find(id);
163
176
  if (it == code_cache_.end()) {
164
    // The module has not been compiled before.
165
    return nullptr;
166
  }
167
176
  return it->second.get();
168
}
169
170
434110
MaybeLocal<Function> NativeModuleLoader::CompileAsModule(
171
    Local<Context> context,
172
    const char* id,
173
    NativeModuleLoader::Result* result) {
174
434110
  Isolate* isolate = context->GetIsolate();
175
  std::vector<Local<String>> parameters = {
176
      FIXED_ONE_BYTE_STRING(isolate, "exports"),
177
      FIXED_ONE_BYTE_STRING(isolate, "require"),
178
      FIXED_ONE_BYTE_STRING(isolate, "module"),
179
      FIXED_ONE_BYTE_STRING(isolate, "process"),
180
      FIXED_ONE_BYTE_STRING(isolate, "internalBinding"),
181
868232
      FIXED_ONE_BYTE_STRING(isolate, "primordials")};
182
868232
  return LookupAndCompile(context, id, &parameters, result);
183
}
184
185
#ifdef NODE_BUILTIN_MODULES_PATH
186
static std::string OnDiskFileName(const char* id) {
187
  std::string filename = NODE_BUILTIN_MODULES_PATH;
188
  filename += "/";
189
190
  if (strncmp(id, "internal/deps", strlen("internal/deps")) == 0) {
191
    id += strlen("internal/");
192
  } else {
193
    filename += "lib/";
194
  }
195
  filename += id;
196
  filename += ".js";
197
198
  return filename;
199
}
200
#endif  // NODE_BUILTIN_MODULES_PATH
201
202
459095
MaybeLocal<String> NativeModuleLoader::LoadBuiltinModuleSource(Isolate* isolate,
203
                                                               const char* id) {
204
#ifdef NODE_BUILTIN_MODULES_PATH
205
  std::string filename = OnDiskFileName(id);
206
207
  uv_fs_t req;
208
  uv_file file =
209
      uv_fs_open(nullptr, &req, filename.c_str(), O_RDONLY, 0, nullptr);
210
  CHECK_GE(req.result, 0);
211
  uv_fs_req_cleanup(&req);
212
213
  auto defer_close = OnScopeLeave([file]() {
214
    uv_fs_t close_req;
215
    CHECK_EQ(0, uv_fs_close(nullptr, &close_req, file, nullptr));
216
    uv_fs_req_cleanup(&close_req);
217
  });
218
219
  std::string contents;
220
  char buffer[4096];
221
  uv_buf_t buf = uv_buf_init(buffer, sizeof(buffer));
222
223
  while (true) {
224
    const int r =
225
        uv_fs_read(nullptr, &req, file, &buf, 1, contents.length(), nullptr);
226
    CHECK_GE(req.result, 0);
227
    uv_fs_req_cleanup(&req);
228
    if (r <= 0) {
229
      break;
230
    }
231
    contents.append(buf.base, r);
232
  }
233
234
  return String::NewFromUtf8(
235
      isolate, contents.c_str(), v8::NewStringType::kNormal, contents.length());
236
#else
237
459095
  const auto source_it = source_.find(id);
238
459101
  CHECK_NE(source_it, source_.end());
239
918205
  return source_it->second.ToStringChecked(isolate);
240
#endif  // NODE_BUILTIN_MODULES_PATH
241
}
242
243
// Returns Local<Function> of the compiled module if return_code_cache
244
// is false (we are only compiling the function).
245
// Otherwise return a Local<Object> containing the cache.
246
459099
MaybeLocal<Function> NativeModuleLoader::LookupAndCompile(
247
    Local<Context> context,
248
    const char* id,
249
    std::vector<Local<String>>* parameters,
250
    NativeModuleLoader::Result* result) {
251
459099
  Isolate* isolate = context->GetIsolate();
252
459105
  EscapableHandleScope scope(isolate);
253
254
  Local<String> source;
255
918209
  if (!LoadBuiltinModuleSource(isolate, id).ToLocal(&source)) {
256
    return {};
257
  }
258
259
918210
  std::string filename_s = id + std::string(".js");
260
  Local<String> filename =
261
459105
      OneByteString(isolate, filename_s.c_str(), filename_s.size());
262
459101
  Local<Integer> line_offset = Integer::New(isolate, 0);
263
459103
  Local<Integer> column_offset = Integer::New(isolate, 0);
264
459100
  ScriptOrigin origin(filename, line_offset, column_offset, True(isolate));
265
266
918206
  Mutex::ScopedLock lock(code_cache_mutex_);
267
268
459106
  ScriptCompiler::CachedData* cached_data = nullptr;
269
  {
270
459106
    auto cache_it = code_cache_.find(id);
271
459106
    if (cache_it != code_cache_.end()) {
272
      // Transfer ownership to ScriptCompiler::Source later.
273
431565
      cached_data = cache_it->second.release();
274
431565
      code_cache_.erase(cache_it);
275
    }
276
  }
277
278
459106
  const bool has_cache = cached_data != nullptr;
279
  ScriptCompiler::CompileOptions options =
280
459106
      has_cache ? ScriptCompiler::kConsumeCodeCache
281
459106
                : ScriptCompiler::kEagerCompile;
282
  ScriptCompiler::Source script_source(source, origin, cached_data);
283
284
  MaybeLocal<Function> maybe_fun =
285
      ScriptCompiler::CompileFunctionInContext(context,
286
                                               &script_source,
287
                                               parameters->size(),
288
                                               parameters->data(),
289
                                               0,
290
                                               nullptr,
291
459106
                                               options);
292
293
  // This could fail when there are early errors in the native modules,
294
  // e.g. the syntax errors
295
  Local<Function> fun;
296
459106
  if (!maybe_fun.ToLocal(&fun)) {
297
    // In the case of early errors, v8 is already capable of
298
    // decorating the stack for us - note that we use CompileFunctionInContext
299
    // so there is no need to worry about wrappers.
300
    return MaybeLocal<Function>();
301
  }
302
303
  // XXX(joyeecheung): this bookkeeping is not exactly accurate because
304
  // it only starts after the Environment is created, so the per_context.js
305
  // will never be in any of these two sets, but the two sets are only for
306
  // testing anyway.
307
308
890671
  *result = (has_cache && !script_source.GetCachedData()->rejected)
309
877800
                ? Result::kWithCache
310
                : Result::kWithoutCache;
311
  // Generate new cache for next compilation
312
  std::unique_ptr<ScriptCompiler::CachedData> new_cached_data(
313
918212
      ScriptCompiler::CreateCodeCacheForFunction(fun));
314
459106
  CHECK_NOT_NULL(new_cached_data);
315
316
  // The old entry should've been erased by now so we can just emplace
317
459106
  code_cache_.emplace(id, std::move(new_cached_data));
318
319
459106
  return scope.Escape(fun);
320
}
321
322
}  // namespace native_module
323

12978
}  // namespace node