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: 2020-08-22 22:13:06 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::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
4465
NativeModuleLoader NativeModuleLoader::instance_;
20
21
4465
NativeModuleLoader::NativeModuleLoader() : config_(GetConfig()) {
22
4465
  LoadJavaScriptSource();
23
4465
}
24
25
339183
NativeModuleLoader* NativeModuleLoader::GetInstance() {
26
339183
  return &instance_;
27
}
28
29
13
bool NativeModuleLoader::Exists(const char* id) {
30
13
  return source_.find(id) != source_.end();
31
}
32
33
13
bool NativeModuleLoader::Add(const char* id, const UnionBytes& source) {
34
13
  if (Exists(id)) {
35
    return false;
36
  }
37
13
  source_.emplace(id, source);
38
13
  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
1392
  for (auto const& x : source_) {
45
1386
    Local<String> key = OneByteString(isolate, x.first.c_str(), x.first.size());
46
4158
    out->Set(context, key, x.second.ToStringChecked(isolate)).FromJust();
47
  }
48
6
  return out;
49
}
50
51
460
Local<String> NativeModuleLoader::GetConfigString(Isolate* isolate) {
52
460
  return config_.ToStringChecked(isolate);
53
}
54
55
455
std::vector<std::string> NativeModuleLoader::GetModuleIds() {
56
455
  std::vector<std::string> ids;
57
455
  ids.reserve(source_.size());
58
105645
  for (auto const& x : source_) {
59
105190
    ids.emplace_back(x.first);
60
  }
61
455
  return ids;
62
}
63
64
233
void NativeModuleLoader::InitializeModuleCategories() {
65
233
  if (module_categories_.is_initialized) {
66
    DCHECK(!module_categories_.can_be_required.empty());
67
231
    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
4
  };
80
81
18
  module_categories_.cannot_be_required = std::set<std::string> {
82
#if !HAVE_INSPECTOR
83
      "inspector",
84
      "internal/util/inspector",
85
#endif  // !HAVE_INSPECTOR
86
87
#if !NODE_USE_V8_PLATFORM || !defined(NODE_HAVE_I18N_SUPPORT)
88
      "trace_events",
89
#endif  // !NODE_USE_V8_PLATFORM
90
91
#if !HAVE_OPENSSL
92
      "crypto",
93
      "https",
94
      "http2",
95
      "tls",
96
      "_tls_common",
97
      "_tls_wrap",
98
      "internal/http2/core",
99
      "internal/http2/compat",
100
      "internal/policy/manifest",
101
      "internal/process/policy",
102
      "internal/streams/lazy_transform",
103
#endif  // !HAVE_OPENSSL
104
#if !NODE_EXPERIMENTAL_QUIC
105
      "internal/quic/core",
106
      "internal/quic/util",
107
#endif
108
      "sys",  // Deprecated.
109
      "wasi",  // Experimental.
110
      "internal/test/binding",
111
      "internal/v8_prof_polyfill",
112
      "internal/v8_prof_processor",
113
16
  };
114
115
464
  for (auto const& x : source_) {
116
462
    const std::string& id = x.first;
117
2310
    for (auto const& prefix : prefixes) {
118
1848
      if (prefix.length() > id.length()) {
119
634
        continue;
120
      }
121
1214
      if (id.find(prefix) == 0) {
122
82
        module_categories_.cannot_be_required.emplace(id);
123
      }
124
    }
125
  }
126
127
464
  for (auto const& x : source_) {
128
462
    const std::string& id = x.first;
129
462
    if (0 == module_categories_.cannot_be_required.count(id)) {
130
366
      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
232
const std::set<std::string>& NativeModuleLoader::GetCanBeRequired() {
143
232
  InitializeModuleCategories();
144
232
  return module_categories_.can_be_required;
145
}
146
147
231
bool NativeModuleLoader::CanBeRequired(const char* id) {
148
231
  return GetCanBeRequired().count(id) == 1;
149
}
150
151
bool NativeModuleLoader::CannotBeRequired(const char* id) {
152
  return GetCannotBeRequired().count(id) == 1;
153
}
154
155
4400
NativeModuleCacheMap* NativeModuleLoader::code_cache() {
156
4400
  return &code_cache_;
157
}
158
159
183
ScriptCompiler::CachedData* NativeModuleLoader::GetCodeCache(
160
    const char* id) const {
161
366
  Mutex::ScopedLock lock(code_cache_mutex_);
162
183
  const auto it = code_cache_.find(id);
163
183
  if (it == code_cache_.end()) {
164
    // The module has not been compiled before.
165
    return nullptr;
166
  }
167
183
  return it->second.get();
168
}
169
170
324621
MaybeLocal<Function> NativeModuleLoader::CompileAsModule(
171
    Local<Context> context,
172
    const char* id,
173
    NativeModuleLoader::Result* result) {
174
324621
  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
649259
      FIXED_ONE_BYTE_STRING(isolate, "primordials")};
182
649258
  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
334033
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
334033
  const auto source_it = source_.find(id);
238
334034
  CHECK_NE(source_it, source_.end());
239
668073
  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
334033
MaybeLocal<Function> NativeModuleLoader::LookupAndCompile(
247
    Local<Context> context,
248
    const char* id,
249
    std::vector<Local<String>>* parameters,
250
    NativeModuleLoader::Result* result) {
251
334033
  Isolate* isolate = context->GetIsolate();
252
334038
  EscapableHandleScope scope(isolate);
253
254
  Local<String> source;
255
668075
  if (!LoadBuiltinModuleSource(isolate, id).ToLocal(&source)) {
256
    return {};
257
  }
258
259
668076
  std::string filename_s = id + std::string(".js");
260
  Local<String> filename =
261
334038
      OneByteString(isolate, filename_s.c_str(), filename_s.size());
262
334035
  Local<Integer> line_offset = Integer::New(isolate, 0);
263
334033
  Local<Integer> column_offset = Integer::New(isolate, 0);
264
334033
  ScriptOrigin origin(filename, line_offset, column_offset, True(isolate));
265
266
334033
  ScriptCompiler::CachedData* cached_data = nullptr;
267
  {
268
    // Note: The lock here should not extend into the
269
    // `CompileFunctionInContext()` call below, because this function may
270
    // recurse if there is a syntax error during bootstrap (because the fatal
271
    // exception handler is invoked, which may load built-in modules).
272
668072
    Mutex::ScopedLock lock(code_cache_mutex_);
273
334039
    auto cache_it = code_cache_.find(id);
274
334039
    if (cache_it != code_cache_.end()) {
275
      // Transfer ownership to ScriptCompiler::Source later.
276
321830
      cached_data = cache_it->second.release();
277
321830
      code_cache_.erase(cache_it);
278
    }
279
  }
280
281
334039
  const bool has_cache = cached_data != nullptr;
282
  ScriptCompiler::CompileOptions options =
283
334039
      has_cache ? ScriptCompiler::kConsumeCodeCache
284
334039
                : ScriptCompiler::kEagerCompile;
285
  ScriptCompiler::Source script_source(source, origin, cached_data);
286
287
  MaybeLocal<Function> maybe_fun =
288
      ScriptCompiler::CompileFunctionInContext(context,
289
                                               &script_source,
290
                                               parameters->size(),
291
                                               parameters->data(),
292
                                               0,
293
                                               nullptr,
294
334039
                                               options);
295
296
  // This could fail when there are early errors in the native modules,
297
  // e.g. the syntax errors
298
  Local<Function> fun;
299
334037
  if (!maybe_fun.ToLocal(&fun)) {
300
    // In the case of early errors, v8 is already capable of
301
    // decorating the stack for us - note that we use CompileFunctionInContext
302
    // so there is no need to worry about wrappers.
303
    return MaybeLocal<Function>();
304
  }
305
306
  // XXX(joyeecheung): this bookkeeping is not exactly accurate because
307
  // it only starts after the Environment is created, so the per_context.js
308
  // will never be in any of these two sets, but the two sets are only for
309
  // testing anyway.
310
311
655863
  *result = (has_cache && !script_source.GetCachedData()->rejected)
312
646580
                ? Result::kWithCache
313
                : Result::kWithoutCache;
314
  // Generate new cache for next compilation
315
  std::unique_ptr<ScriptCompiler::CachedData> new_cached_data(
316
668076
      ScriptCompiler::CreateCodeCacheForFunction(fun));
317
334039
  CHECK_NOT_NULL(new_cached_data);
318
319
  {
320
668077
    Mutex::ScopedLock lock(code_cache_mutex_);
321
    // The old entry should've been erased by now so we can just emplace.
322
    // If another thread did the same thing in the meantime, that should not
323
    // be an issue.
324
334039
    code_cache_.emplace(id, std::move(new_cached_data));
325
  }
326
327
334039
  return scope.Escape(fun);
328
}
329
330
}  // namespace native_module
331

13395
}  // namespace node