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: 92 97 94.8 %
Date: 2020-02-19 22:14:06 Branches: 37 44 84.1 %

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

12558
}  // namespace node