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: 96 102 94.1 %
Date: 2021-04-09 04:13:47 Branches: 42 50 84.0 %

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::Isolate;
11
using v8::Local;
12
using v8::MaybeLocal;
13
using v8::Object;
14
using v8::ScriptCompiler;
15
using v8::ScriptOrigin;
16
using v8::String;
17
18
4757
NativeModuleLoader NativeModuleLoader::instance_;
19
20
4757
NativeModuleLoader::NativeModuleLoader() : config_(GetConfig()) {
21
4757
  LoadJavaScriptSource();
22
4757
}
23
24
394160
NativeModuleLoader* NativeModuleLoader::GetInstance() {
25
394160
  return &instance_;
26
}
27
28
15
bool NativeModuleLoader::Exists(const char* id) {
29
15
  return source_.find(id) != source_.end();
30
}
31
32
15
bool NativeModuleLoader::Add(const char* id, const UnionBytes& source) {
33
15
  if (Exists(id)) {
34
    return false;
35
  }
36
15
  source_.emplace(id, source);
37
15
  return true;
38
}
39
40
6
Local<Object> NativeModuleLoader::GetSourceObject(Local<Context> context) {
41
6
  Isolate* isolate = context->GetIsolate();
42
6
  Local<Object> out = Object::New(isolate);
43
1566
  for (auto const& x : source_) {
44
1560
    Local<String> key = OneByteString(isolate, x.first.c_str(), x.first.size());
45
4680
    out->Set(context, key, x.second.ToStringChecked(isolate)).FromJust();
46
  }
47
6
  return out;
48
}
49
50
461
Local<String> NativeModuleLoader::GetConfigString(Isolate* isolate) {
51
461
  return config_.ToStringChecked(isolate);
52
}
53
54
462
std::vector<std::string> NativeModuleLoader::GetModuleIds() {
55
462
  std::vector<std::string> ids;
56
462
  ids.reserve(source_.size());
57
120748
  for (auto const& x : source_) {
58
120187
    ids.emplace_back(x.first);
59
  }
60
463
  return ids;
61
}
62
63
2082
void NativeModuleLoader::InitializeModuleCategories() {
64
2082
  if (module_categories_.is_initialized) {
65
    DCHECK(!module_categories_.can_be_required.empty());
66
2073
    return;
67
  }
68
69
  std::vector<std::string> prefixes = {
70
#if !HAVE_OPENSSL
71
    "internal/crypto/",
72
#endif  // !HAVE_OPENSSL
73
74
    "internal/bootstrap/",
75
    "internal/per_context/",
76
    "internal/deps/",
77
    "internal/main/"
78
18
  };
79
80
  module_categories_.can_be_required.emplace(
81
9
      "internal/deps/cjs-module-lexer/lexer");
82
83
63
  module_categories_.cannot_be_required = std::set<std::string> {
84
#if !HAVE_INSPECTOR
85
      "inspector",
86
      "internal/util/inspector",
87
#endif  // !HAVE_INSPECTOR
88
89
#if !NODE_USE_V8_PLATFORM || !defined(NODE_HAVE_I18N_SUPPORT)
90
      "trace_events",
91
#endif  // !NODE_USE_V8_PLATFORM
92
93
#if !HAVE_OPENSSL
94
      "crypto",
95
      "crypto/promises",
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
      "sys",  // Deprecated.
108
      "wasi",  // Experimental.
109
      "internal/test/binding",
110
      "internal/v8_prof_polyfill",
111
      "internal/v8_prof_processor",
112
54
  };
113
114
2349
  for (auto const& x : source_) {
115
2340
    const std::string& id = x.first;
116
11700
    for (auto const& prefix : prefixes) {
117
9360
      if (prefix.length() > id.length()) {
118
3060
        continue;
119
      }
120

6678
      if (id.find(prefix) == 0 &&
121
378
          module_categories_.can_be_required.count(id) == 0) {
122
369
        module_categories_.cannot_be_required.emplace(id);
123
      }
124
    }
125
  }
126
127
2349
  for (auto const& x : source_) {
128
2340
    const std::string& id = x.first;
129
2340
    if (0 == module_categories_.cannot_be_required.count(id)) {
130
1926
      module_categories_.can_be_required.emplace(id);
131
    }
132
  }
133
134
9
  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
2081
const std::set<std::string>& NativeModuleLoader::GetCanBeRequired() {
143
2081
  InitializeModuleCategories();
144
2081
  return module_categories_.can_be_required;
145
}
146
147
2080
bool NativeModuleLoader::CanBeRequired(const char* id) {
148
2080
  return GetCanBeRequired().count(id) == 1;
149
}
150
151
bool NativeModuleLoader::CannotBeRequired(const char* id) {
152
  return GetCannotBeRequired().count(id) == 1;
153
}
154
155
4688
NativeModuleCacheMap* NativeModuleLoader::code_cache() {
156
4688
  return &code_cache_;
157
}
158
159
1712
ScriptCompiler::CachedData* NativeModuleLoader::GetCodeCache(
160
    const char* id) const {
161
3424
  Mutex::ScopedLock lock(code_cache_mutex_);
162
1712
  const auto it = code_cache_.find(id);
163
1712
  if (it == code_cache_.end()) {
164
    // The module has not been compiled before.
165
    return nullptr;
166
  }
167
1712
  return it->second.get();
168
}
169
170
380515
MaybeLocal<Function> NativeModuleLoader::CompileAsModule(
171
    Local<Context> context,
172
    const char* id,
173
    NativeModuleLoader::Result* result) {
174
380515
  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
761051
      FIXED_ONE_BYTE_STRING(isolate, "primordials")};
182
761042
  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
390240
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
390240
  const auto source_it = source_.find(id);
238
390255
  CHECK_NE(source_it, source_.end());
239
780492
  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
390220
MaybeLocal<Function> NativeModuleLoader::LookupAndCompile(
247
    Local<Context> context,
248
    const char* id,
249
    std::vector<Local<String>>* parameters,
250
    NativeModuleLoader::Result* result) {
251
390220
  Isolate* isolate = context->GetIsolate();
252
390224
  EscapableHandleScope scope(isolate);
253
254
  Local<String> source;
255
780486
  if (!LoadBuiltinModuleSource(isolate, id).ToLocal(&source)) {
256
    return {};
257
  }
258
259
780502
  std::string filename_s = std::string("node:") + id;
260
  Local<String> filename =
261
390234
      OneByteString(isolate, filename_s.c_str(), filename_s.size());
262
390237
  ScriptOrigin origin(isolate, filename, 0, 0, true);
263
264
390237
  ScriptCompiler::CachedData* cached_data = nullptr;
265
  {
266
    // Note: The lock here should not extend into the
267
    // `CompileFunctionInContext()` call below, because this function may
268
    // recurse if there is a syntax error during bootstrap (because the fatal
269
    // exception handler is invoked, which may load built-in modules).
270
780497
    Mutex::ScopedLock lock(code_cache_mutex_);
271
390260
    auto cache_it = code_cache_.find(id);
272
390260
    if (cache_it != code_cache_.end()) {
273
      // Transfer ownership to ScriptCompiler::Source later.
274
375302
      cached_data = cache_it->second.release();
275
375302
      code_cache_.erase(cache_it);
276
    }
277
  }
278
279
390260
  const bool has_cache = cached_data != nullptr;
280
  ScriptCompiler::CompileOptions options =
281
390260
      has_cache ? ScriptCompiler::kConsumeCodeCache
282
390260
                : ScriptCompiler::kEagerCompile;
283
  ScriptCompiler::Source script_source(source, origin, cached_data);
284
285
  MaybeLocal<Function> maybe_fun =
286
      ScriptCompiler::CompileFunctionInContext(context,
287
                                               &script_source,
288
                                               parameters->size(),
289
                                               parameters->data(),
290
                                               0,
291
                                               nullptr,
292
390260
                                               options);
293
294
  // This could fail when there are early errors in the native modules,
295
  // e.g. the syntax errors
296
  Local<Function> fun;
297
390252
  if (!maybe_fun.ToLocal(&fun)) {
298
    // In the case of early errors, v8 is already capable of
299
    // decorating the stack for us - note that we use CompileFunctionInContext
300
    // so there is no need to worry about wrappers.
301
    return MaybeLocal<Function>();
302
  }
303
304
  // XXX(joyeecheung): this bookkeeping is not exactly accurate because
305
  // it only starts after the Environment is created, so the per_context.js
306
  // will never be in any of these two sets, but the two sets are only for
307
  // testing anyway.
308
309
765546
  *result = (has_cache && !script_source.GetCachedData()->rejected)
310
756365
                ? Result::kWithCache
311
                : Result::kWithoutCache;
312
  // Generate new cache for next compilation
313
  std::unique_ptr<ScriptCompiler::CachedData> new_cached_data(
314
780512
      ScriptCompiler::CreateCodeCacheForFunction(fun));
315
390246
  CHECK_NOT_NULL(new_cached_data);
316
317
  {
318
780500
    Mutex::ScopedLock lock(code_cache_mutex_);
319
    // The old entry should've been erased by now so we can just emplace.
320
    // If another thread did the same thing in the meantime, that should not
321
    // be an issue.
322
390260
    code_cache_.emplace(id, std::move(new_cached_data));
323
  }
324
325
390260
  return scope.Escape(fun);
326
}
327
328
}  // namespace native_module
329

14271
}  // namespace node