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: 98 104 94.2 %
Date: 2021-01-16 04:10:54 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::Integer;
11
using v8::Isolate;
12
using v8::Local;
13
using v8::MaybeLocal;
14
using v8::Object;
15
using v8::ScriptCompiler;
16
using v8::ScriptOrigin;
17
using v8::String;
18
19
4665
NativeModuleLoader NativeModuleLoader::instance_;
20
21
4665
NativeModuleLoader::NativeModuleLoader() : config_(GetConfig()) {
22
4665
  LoadJavaScriptSource();
23
4665
}
24
25
305938
NativeModuleLoader* NativeModuleLoader::GetInstance() {
26
305938
  return &instance_;
27
}
28
29
15
bool NativeModuleLoader::Exists(const char* id) {
30
15
  return source_.find(id) != source_.end();
31
}
32
33
15
bool NativeModuleLoader::Add(const char* id, const UnionBytes& source) {
34
15
  if (Exists(id)) {
35
    return false;
36
  }
37
15
  source_.emplace(id, source);
38
15
  return true;
39
}
40
41
6
Local<Object> NativeModuleLoader::GetSourceObject(Local<Context> context) {
42
6
  Isolate* isolate = context->GetIsolate();
43
6
  Local<Object> out = Object::New(isolate);
44
1512
  for (auto const& x : source_) {
45
1506
    Local<String> key = OneByteString(isolate, x.first.c_str(), x.first.size());
46
4518
    out->Set(context, key, x.second.ToStringChecked(isolate)).FromJust();
47
  }
48
6
  return out;
49
}
50
51
445
Local<String> NativeModuleLoader::GetConfigString(Isolate* isolate) {
52
445
  return config_.ToStringChecked(isolate);
53
}
54
55
447
std::vector<std::string> NativeModuleLoader::GetModuleIds() {
56
447
  std::vector<std::string> ids;
57
447
  ids.reserve(source_.size());
58
112612
  for (auto const& x : source_) {
59
112115
    ids.emplace_back(x.first);
60
  }
61
447
  return ids;
62
}
63
64
2010
void NativeModuleLoader::InitializeModuleCategories() {
65
2010
  if (module_categories_.is_initialized) {
66
    DCHECK(!module_categories_.can_be_required.empty());
67
2001
    return;
68
  }
69
70
  std::vector<std::string> prefixes = {
71
#if !HAVE_OPENSSL
72
    "internal/crypto/",
73
#endif  // !HAVE_OPENSSL
74
75
    "internal/bootstrap/",
76
    "internal/per_context/",
77
    "internal/deps/",
78
    "internal/main/"
79
18
  };
80
81
  module_categories_.can_be_required.emplace(
82
9
      "internal/deps/cjs-module-lexer/lexer");
83
84
81
  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
      "crypto/promises",
97
      "https",
98
      "http2",
99
      "tls",
100
      "_tls_common",
101
      "_tls_wrap",
102
      "internal/http2/core",
103
      "internal/http2/compat",
104
      "internal/policy/manifest",
105
      "internal/process/policy",
106
      "internal/streams/lazy_transform",
107
#endif  // !HAVE_OPENSSL
108
#if !NODE_EXPERIMENTAL_QUIC
109
      "internal/quic/core",
110
      "internal/quic/util",
111
#endif
112
      "sys",  // Deprecated.
113
      "wasi",  // Experimental.
114
      "internal/test/binding",
115
      "internal/v8_prof_polyfill",
116
      "internal/v8_prof_processor",
117
72
  };
118
119
2268
  for (auto const& x : source_) {
120
2259
    const std::string& id = x.first;
121
11295
    for (auto const& prefix : prefixes) {
122
9036
      if (prefix.length() > id.length()) {
123
3042
        continue;
124
      }
125

6372
      if (id.find(prefix) == 0 &&
126
378
          module_categories_.can_be_required.count(id) == 0) {
127
369
        module_categories_.cannot_be_required.emplace(id);
128
      }
129
    }
130
  }
131
132
2268
  for (auto const& x : source_) {
133
2259
    const std::string& id = x.first;
134
2259
    if (0 == module_categories_.cannot_be_required.count(id)) {
135
1827
      module_categories_.can_be_required.emplace(id);
136
    }
137
  }
138
139
9
  module_categories_.is_initialized = true;
140
}
141
142
1
const std::set<std::string>& NativeModuleLoader::GetCannotBeRequired() {
143
1
  InitializeModuleCategories();
144
1
  return module_categories_.cannot_be_required;
145
}
146
147
2009
const std::set<std::string>& NativeModuleLoader::GetCanBeRequired() {
148
2009
  InitializeModuleCategories();
149
2009
  return module_categories_.can_be_required;
150
}
151
152
2008
bool NativeModuleLoader::CanBeRequired(const char* id) {
153
2008
  return GetCanBeRequired().count(id) == 1;
154
}
155
156
bool NativeModuleLoader::CannotBeRequired(const char* id) {
157
  return GetCannotBeRequired().count(id) == 1;
158
}
159
160
4589
NativeModuleCacheMap* NativeModuleLoader::code_cache() {
161
4589
  return &code_cache_;
162
}
163
164
1624
ScriptCompiler::CachedData* NativeModuleLoader::GetCodeCache(
165
    const char* id) const {
166
3248
  Mutex::ScopedLock lock(code_cache_mutex_);
167
1624
  const auto it = code_cache_.find(id);
168
1624
  if (it == code_cache_.end()) {
169
    // The module has not been compiled before.
170
    return nullptr;
171
  }
172
1624
  return it->second.get();
173
}
174
175
292634
MaybeLocal<Function> NativeModuleLoader::CompileAsModule(
176
    Local<Context> context,
177
    const char* id,
178
    NativeModuleLoader::Result* result) {
179
292634
  Isolate* isolate = context->GetIsolate();
180
  std::vector<Local<String>> parameters = {
181
      FIXED_ONE_BYTE_STRING(isolate, "exports"),
182
      FIXED_ONE_BYTE_STRING(isolate, "require"),
183
      FIXED_ONE_BYTE_STRING(isolate, "module"),
184
      FIXED_ONE_BYTE_STRING(isolate, "process"),
185
      FIXED_ONE_BYTE_STRING(isolate, "internalBinding"),
186
585286
      FIXED_ONE_BYTE_STRING(isolate, "primordials")};
187
585286
  return LookupAndCompile(context, id, &parameters, result);
188
}
189
190
#ifdef NODE_BUILTIN_MODULES_PATH
191
static std::string OnDiskFileName(const char* id) {
192
  std::string filename = NODE_BUILTIN_MODULES_PATH;
193
  filename += "/";
194
195
  if (strncmp(id, "internal/deps", strlen("internal/deps")) == 0) {
196
    id += strlen("internal/");
197
  } else {
198
    filename += "lib/";
199
  }
200
  filename += id;
201
  filename += ".js";
202
203
  return filename;
204
}
205
#endif  // NODE_BUILTIN_MODULES_PATH
206
207
302058
MaybeLocal<String> NativeModuleLoader::LoadBuiltinModuleSource(Isolate* isolate,
208
                                                               const char* id) {
209
#ifdef NODE_BUILTIN_MODULES_PATH
210
  std::string filename = OnDiskFileName(id);
211
212
  uv_fs_t req;
213
  uv_file file =
214
      uv_fs_open(nullptr, &req, filename.c_str(), O_RDONLY, 0, nullptr);
215
  CHECK_GE(req.result, 0);
216
  uv_fs_req_cleanup(&req);
217
218
  auto defer_close = OnScopeLeave([file]() {
219
    uv_fs_t close_req;
220
    CHECK_EQ(0, uv_fs_close(nullptr, &close_req, file, nullptr));
221
    uv_fs_req_cleanup(&close_req);
222
  });
223
224
  std::string contents;
225
  char buffer[4096];
226
  uv_buf_t buf = uv_buf_init(buffer, sizeof(buffer));
227
228
  while (true) {
229
    const int r =
230
        uv_fs_read(nullptr, &req, file, &buf, 1, contents.length(), nullptr);
231
    CHECK_GE(req.result, 0);
232
    uv_fs_req_cleanup(&req);
233
    if (r <= 0) {
234
      break;
235
    }
236
    contents.append(buf.base, r);
237
  }
238
239
  return String::NewFromUtf8(
240
      isolate, contents.c_str(), v8::NewStringType::kNormal, contents.length());
241
#else
242
302058
  const auto source_it = source_.find(id);
243
302064
  CHECK_NE(source_it, source_.end());
244
604119
  return source_it->second.ToStringChecked(isolate);
245
#endif  // NODE_BUILTIN_MODULES_PATH
246
}
247
248
// Returns Local<Function> of the compiled module if return_code_cache
249
// is false (we are only compiling the function).
250
// Otherwise return a Local<Object> containing the cache.
251
302053
MaybeLocal<Function> NativeModuleLoader::LookupAndCompile(
252
    Local<Context> context,
253
    const char* id,
254
    std::vector<Local<String>>* parameters,
255
    NativeModuleLoader::Result* result) {
256
302053
  Isolate* isolate = context->GetIsolate();
257
302056
  EscapableHandleScope scope(isolate);
258
259
  Local<String> source;
260
604125
  if (!LoadBuiltinModuleSource(isolate, id).ToLocal(&source)) {
261
    return {};
262
  }
263
264
604128
  std::string filename_s = std::string("node:") + id;
265
  Local<String> filename =
266
302060
      OneByteString(isolate, filename_s.c_str(), filename_s.size());
267
302054
  Local<Integer> line_offset = Integer::New(isolate, 0);
268
302051
  Local<Integer> column_offset = Integer::New(isolate, 0);
269
302066
  ScriptOrigin origin(filename, line_offset, column_offset, True(isolate));
270
271
302066
  ScriptCompiler::CachedData* cached_data = nullptr;
272
  {
273
    // Note: The lock here should not extend into the
274
    // `CompileFunctionInContext()` call below, because this function may
275
    // recurse if there is a syntax error during bootstrap (because the fatal
276
    // exception handler is invoked, which may load built-in modules).
277
604139
    Mutex::ScopedLock lock(code_cache_mutex_);
278
302073
    auto cache_it = code_cache_.find(id);
279
302073
    if (cache_it != code_cache_.end()) {
280
      // Transfer ownership to ScriptCompiler::Source later.
281
287681
      cached_data = cache_it->second.release();
282
287681
      code_cache_.erase(cache_it);
283
    }
284
  }
285
286
302069
  const bool has_cache = cached_data != nullptr;
287
  ScriptCompiler::CompileOptions options =
288
302069
      has_cache ? ScriptCompiler::kConsumeCodeCache
289
302069
                : ScriptCompiler::kEagerCompile;
290
  ScriptCompiler::Source script_source(source, origin, cached_data);
291
292
  MaybeLocal<Function> maybe_fun =
293
      ScriptCompiler::CompileFunctionInContext(context,
294
                                               &script_source,
295
                                               parameters->size(),
296
                                               parameters->data(),
297
                                               0,
298
                                               nullptr,
299
302069
                                               options);
300
301
  // This could fail when there are early errors in the native modules,
302
  // e.g. the syntax errors
303
  Local<Function> fun;
304
302065
  if (!maybe_fun.ToLocal(&fun)) {
305
    // In the case of early errors, v8 is already capable of
306
    // decorating the stack for us - note that we use CompileFunctionInContext
307
    // so there is no need to worry about wrappers.
308
    return MaybeLocal<Function>();
309
  }
310
311
  // XXX(joyeecheung): this bookkeeping is not exactly accurate because
312
  // it only starts after the Environment is created, so the per_context.js
313
  // will never be in any of these two sets, but the two sets are only for
314
  // testing anyway.
315
316
589736
  *result = (has_cache && !script_source.GetCachedData()->rejected)
317
582897
                ? Result::kWithCache
318
                : Result::kWithoutCache;
319
  // Generate new cache for next compilation
320
  std::unique_ptr<ScriptCompiler::CachedData> new_cached_data(
321
604138
      ScriptCompiler::CreateCodeCacheForFunction(fun));
322
302068
  CHECK_NOT_NULL(new_cached_data);
323
324
  {
325
604141
    Mutex::ScopedLock lock(code_cache_mutex_);
326
    // The old entry should've been erased by now so we can just emplace.
327
    // If another thread did the same thing in the meantime, that should not
328
    // be an issue.
329
302073
    code_cache_.emplace(id, std::move(new_cached_data));
330
  }
331
332
302073
  return scope.Escape(fun);
333
}
334
335
}  // namespace native_module
336

13995
}  // namespace node