GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: node_native_module.cc Lines: 268 300 89.3 %
Date: 2022-08-05 04:16:08 Branches: 84 108 77.8 %

Line Branch Exec Source
1
#include "node_native_module.h"
2
#include "debug_utils-inl.h"
3
#include "env-inl.h"
4
#include "node_external_reference.h"
5
#include "node_internals.h"
6
#include "util-inl.h"
7
8
namespace node {
9
namespace native_module {
10
11
using v8::Context;
12
using v8::DEFAULT;
13
using v8::EscapableHandleScope;
14
using v8::Function;
15
using v8::FunctionCallbackInfo;
16
using v8::IntegrityLevel;
17
using v8::Isolate;
18
using v8::Local;
19
using v8::MaybeLocal;
20
using v8::Name;
21
using v8::None;
22
using v8::Object;
23
using v8::PropertyCallbackInfo;
24
using v8::ScriptCompiler;
25
using v8::ScriptOrigin;
26
using v8::Set;
27
using v8::SideEffectType;
28
using v8::String;
29
using v8::Value;
30
31
NativeModuleLoader NativeModuleLoader::instance_;
32
33
5386
NativeModuleLoader::NativeModuleLoader()
34
5386
    : config_(GetConfig()), has_code_cache_(false) {
35
5386
  LoadJavaScriptSource();
36
5386
}
37
38
977419
NativeModuleLoader* NativeModuleLoader::GetInstance() {
39
977419
  return &instance_;
40
}
41
42
bool NativeModuleLoader::Exists(const char* id) {
43
  auto& source = GetInstance()->source_;
44
  return source.find(id) != source.end();
45
}
46
47
17
bool NativeModuleLoader::Add(const char* id, const UnionBytes& source) {
48
17
  auto result = GetInstance()->source_.emplace(id, source);
49
17
  return result.second;
50
}
51
52
42
Local<Object> NativeModuleLoader::GetSourceObject(Local<Context> context) {
53
42
  Isolate* isolate = context->GetIsolate();
54
42
  Local<Object> out = Object::New(isolate);
55
42
  auto& source = GetInstance()->source_;
56
12642
  for (auto const& x : source) {
57
12600
    Local<String> key = OneByteString(isolate, x.first.c_str(), x.first.size());
58
37800
    out->Set(context, key, x.second.ToStringChecked(isolate)).FromJust();
59
  }
60
42
  return out;
61
}
62
63
1347
Local<String> NativeModuleLoader::GetConfigString(Isolate* isolate) {
64
1347
  return GetInstance()->config_.ToStringChecked(isolate);
65
}
66
67
1350
std::vector<std::string> NativeModuleLoader::GetModuleIds() {
68
1350
  std::vector<std::string> ids;
69
1350
  ids.reserve(source_.size());
70
406505
  for (auto const& x : source_) {
71
405155
    ids.emplace_back(x.first);
72
  }
73
1350
  return ids;
74
}
75
76
2
void NativeModuleLoader::InitializeModuleCategories() {
77
2
  if (module_categories_.is_initialized) {
78
    DCHECK(!module_categories_.can_be_required.empty());
79
1
    return;
80
  }
81
82
  std::vector<std::string> prefixes = {
83
#if !HAVE_OPENSSL
84
    "internal/crypto/",
85
    "internal/debugger/",
86
#endif  // !HAVE_OPENSSL
87
88
    "internal/bootstrap/",
89
    "internal/per_context/",
90
    "internal/deps/",
91
    "internal/main/"
92
7
  };
93
94
  module_categories_.can_be_required.emplace(
95
1
      "internal/deps/cjs-module-lexer/lexer");
96
97
7
  module_categories_.cannot_be_required = std::set<std::string> {
98
#if !HAVE_INSPECTOR
99
      "inspector",
100
      "internal/util/inspector",
101
#endif  // !HAVE_INSPECTOR
102
103
#if !NODE_USE_V8_PLATFORM || !defined(NODE_HAVE_I18N_SUPPORT)
104
      "trace_events",
105
#endif  // !NODE_USE_V8_PLATFORM || !defined(NODE_HAVE_I18N_SUPPORT)
106
107
#if !HAVE_OPENSSL
108
      "crypto",
109
      "crypto/promises",
110
      "https",
111
      "http2",
112
      "tls",
113
      "_tls_common",
114
      "_tls_wrap",
115
      "internal/tls/secure-pair",
116
      "internal/tls/parse-cert-string",
117
      "internal/tls/secure-context",
118
      "internal/http2/core",
119
      "internal/http2/compat",
120
      "internal/policy/manifest",
121
      "internal/process/policy",
122
      "internal/streams/lazy_transform",
123
#endif  // !HAVE_OPENSSL
124
      "sys",  // Deprecated.
125
      "wasi",  // Experimental.
126
      "internal/test/binding",
127
      "internal/v8_prof_polyfill",
128
      "internal/v8_prof_processor",
129
6
  };
130
131
301
  for (auto const& x : source_) {
132
300
    const std::string& id = x.first;
133
1500
    for (auto const& prefix : prefixes) {
134
1200
      if (prefix.length() > id.length()) {
135
347
        continue;
136
      }
137

891
      if (id.find(prefix) == 0 &&
138
38
          module_categories_.can_be_required.count(id) == 0) {
139
37
        module_categories_.cannot_be_required.emplace(id);
140
      }
141
    }
142
  }
143
144
301
  for (auto const& x : source_) {
145
300
    const std::string& id = x.first;
146
300
    if (0 == module_categories_.cannot_be_required.count(id)) {
147
258
      module_categories_.can_be_required.emplace(id);
148
    }
149
  }
150
151
1
  module_categories_.is_initialized = true;
152
}
153
154
1
const std::set<std::string>& NativeModuleLoader::GetCannotBeRequired() {
155
1
  InitializeModuleCategories();
156
1
  return module_categories_.cannot_be_required;
157
}
158
159
1
const std::set<std::string>& NativeModuleLoader::GetCanBeRequired() {
160
1
  InitializeModuleCategories();
161
1
  return module_categories_.can_be_required;
162
}
163
164
bool NativeModuleLoader::CanBeRequired(const char* id) {
165
  return GetCanBeRequired().count(id) == 1;
166
}
167
168
bool NativeModuleLoader::CannotBeRequired(const char* id) {
169
  return GetCannotBeRequired().count(id) == 1;
170
}
171
172
5313
NativeModuleCacheMap* NativeModuleLoader::code_cache() {
173
5313
  return &code_cache_;
174
}
175
176
ScriptCompiler::CachedData* NativeModuleLoader::GetCodeCache(
177
    const char* id) const {
178
  Mutex::ScopedLock lock(code_cache_mutex_);
179
  const auto it = code_cache_.find(id);
180
  if (it == code_cache_.end()) {
181
    // The module has not been compiled before.
182
    return nullptr;
183
  }
184
  return it->second.get();
185
}
186
187
#ifdef NODE_BUILTIN_MODULES_PATH
188
static std::string OnDiskFileName(const char* id) {
189
  std::string filename = NODE_BUILTIN_MODULES_PATH;
190
  filename += "/";
191
192
  if (strncmp(id, "internal/deps", strlen("internal/deps")) == 0) {
193
    id += strlen("internal/");
194
  } else {
195
    filename += "lib/";
196
  }
197
  filename += id;
198
  filename += ".js";
199
200
  return filename;
201
}
202
#endif  // NODE_BUILTIN_MODULES_PATH
203
204
492302
MaybeLocal<String> NativeModuleLoader::LoadBuiltinModuleSource(Isolate* isolate,
205
                                                               const char* id) {
206
#ifdef NODE_BUILTIN_MODULES_PATH
207
  if (strncmp(id, "embedder_main_", strlen("embedder_main_")) == 0) {
208
#endif  // NODE_BUILTIN_MODULES_PATH
209
492302
    const auto source_it = source_.find(id);
210
492302
    if (UNLIKELY(source_it == source_.end())) {
211
      fprintf(stderr, "Cannot find native builtin: \"%s\".\n", id);
212
      ABORT();
213
    }
214
984604
    return source_it->second.ToStringChecked(isolate);
215
#ifdef NODE_BUILTIN_MODULES_PATH
216
  }
217
  std::string filename = OnDiskFileName(id);
218
219
  std::string contents;
220
  int r = ReadFileSync(&contents, filename.c_str());
221
  if (r != 0) {
222
    const std::string buf = SPrintF("Cannot read local builtin. %s: %s \"%s\"",
223
                                    uv_err_name(r),
224
                                    uv_strerror(r),
225
                                    filename);
226
    Local<String> message = OneByteString(isolate, buf.c_str());
227
    isolate->ThrowException(v8::Exception::Error(message));
228
    return MaybeLocal<String>();
229
  }
230
  return String::NewFromUtf8(
231
      isolate, contents.c_str(), v8::NewStringType::kNormal, contents.length());
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
492302
MaybeLocal<Function> NativeModuleLoader::LookupAndCompileInternal(
239
    Local<Context> context,
240
    const char* id,
241
    std::vector<Local<String>>* parameters,
242
    NativeModuleLoader::Result* result) {
243
492302
  Isolate* isolate = context->GetIsolate();
244
492302
  EscapableHandleScope scope(isolate);
245
246
  Local<String> source;
247
984604
  if (!LoadBuiltinModuleSource(isolate, id).ToLocal(&source)) {
248
    return {};
249
  }
250
251
1476906
  std::string filename_s = std::string("node:") + id;
252
  Local<String> filename =
253
492302
      OneByteString(isolate, filename_s.c_str(), filename_s.size());
254
492302
  ScriptOrigin origin(isolate, filename, 0, 0, true);
255
256
492302
  ScriptCompiler::CachedData* cached_data = nullptr;
257
  {
258
    // Note: The lock here should not extend into the
259
    // `CompileFunctionInContext()` call below, because this function may
260
    // recurse if there is a syntax error during bootstrap (because the fatal
261
    // exception handler is invoked, which may load built-in modules).
262
984604
    Mutex::ScopedLock lock(code_cache_mutex_);
263
492302
    auto cache_it = code_cache_.find(id);
264
492302
    if (cache_it != code_cache_.end()) {
265
      // Transfer ownership to ScriptCompiler::Source later.
266
486983
      cached_data = cache_it->second.release();
267
486983
      code_cache_.erase(cache_it);
268
    }
269
  }
270
271
492302
  const bool has_cache = cached_data != nullptr;
272
492302
  ScriptCompiler::CompileOptions options =
273
492302
      has_cache ? ScriptCompiler::kConsumeCodeCache
274
                : ScriptCompiler::kEagerCompile;
275
492302
  ScriptCompiler::Source script_source(source, origin, cached_data);
276
277
  per_process::Debug(DebugCategory::CODE_CACHE,
278
                     "Compiling %s %s code cache\n",
279
                     id,
280
492302
                     has_cache ? "with" : "without");
281
282
  MaybeLocal<Function> maybe_fun =
283
      ScriptCompiler::CompileFunctionInContext(context,
284
                                               &script_source,
285
                                               parameters->size(),
286
                                               parameters->data(),
287
                                               0,
288
                                               nullptr,
289
492302
                                               options);
290
291
  // This could fail when there are early errors in the native modules,
292
  // e.g. the syntax errors
293
  Local<Function> fun;
294
492302
  if (!maybe_fun.ToLocal(&fun)) {
295
    // In the case of early errors, v8 is already capable of
296
    // decorating the stack for us - note that we use CompileFunctionInContext
297
    // so there is no need to worry about wrappers.
298
    return MaybeLocal<Function>();
299
  }
300
301
  // XXX(joyeecheung): this bookkeeping is not exactly accurate because
302
  // it only starts after the Environment is created, so the per_context.js
303
  // will never be in any of these two sets, but the two sets are only for
304
  // testing anyway.
305
306
486983
  *result = (has_cache && !script_source.GetCachedData()->rejected)
307
979285
                ? Result::kWithCache
308
                : Result::kWithoutCache;
309
310
492302
  if (has_cache) {
311
486983
    per_process::Debug(DebugCategory::CODE_CACHE,
312
                       "Code cache of %s (%s) %s\n",
313
                       id,
314
486983
                       script_source.GetCachedData()->buffer_policy ==
315
                               ScriptCompiler::CachedData::BufferNotOwned
316
973966
                           ? "BufferNotOwned"
317
                           : "BufferOwned",
318
486983
                       script_source.GetCachedData()->rejected ? "is rejected"
319
                                                               : "is accepted");
320
  }
321
322
  // Generate new cache for next compilation
323
  std::unique_ptr<ScriptCompiler::CachedData> new_cached_data(
324
492302
      ScriptCompiler::CreateCodeCacheForFunction(fun));
325
492302
  CHECK_NOT_NULL(new_cached_data);
326
327
  {
328
984604
    Mutex::ScopedLock lock(code_cache_mutex_);
329
492302
    const auto it = code_cache_.find(id);
330
    // TODO(joyeecheung): it's safer for each thread to have its own
331
    // copy of the code cache map.
332
492302
    if (it == code_cache_.end()) {
333
490455
      code_cache_.emplace(id, std::move(new_cached_data));
334
    } else {
335
1847
      it->second.reset(new_cached_data.release());
336
    }
337
  }
338
339
492302
  return scope.Escape(fun);
340
}
341
342
// Returns Local<Function> of the compiled module if return_code_cache
343
// is false (we are only compiling the function).
344
// Otherwise return a Local<Object> containing the cache.
345
492302
MaybeLocal<Function> NativeModuleLoader::LookupAndCompile(
346
    Local<Context> context,
347
    const char* id,
348
    Environment* optional_env) {
349
  Result result;
350
492302
  std::vector<Local<String>> parameters;
351
492302
  Isolate* isolate = context->GetIsolate();
352
  // Detects parameters of the scripts based on module ids.
353
  // internal/bootstrap/loaders: process, getLinkedBinding,
354
  //                             getInternalBinding, primordials
355
492302
  if (strcmp(id, "internal/bootstrap/loaders") == 0) {
356
1311
    parameters = {
357
1311
        FIXED_ONE_BYTE_STRING(isolate, "process"),
358
1311
        FIXED_ONE_BYTE_STRING(isolate, "getLinkedBinding"),
359
1311
        FIXED_ONE_BYTE_STRING(isolate, "getInternalBinding"),
360
1311
        FIXED_ONE_BYTE_STRING(isolate, "primordials"),
361
1311
    };
362
490991
  } else if (strncmp(id,
363
                     "internal/per_context/",
364
                     strlen("internal/per_context/")) == 0) {
365
    // internal/per_context/*: global, exports, primordials
366
423
    parameters = {
367
423
        FIXED_ONE_BYTE_STRING(isolate, "global"),
368
423
        FIXED_ONE_BYTE_STRING(isolate, "exports"),
369
423
        FIXED_ONE_BYTE_STRING(isolate, "primordials"),
370
423
    };
371
490568
  } else if (strncmp(id, "internal/main/", strlen("internal/main/")) == 0) {
372
    // internal/main/*: process, require, internalBinding, primordials
373
6651
    parameters = {
374
6651
        FIXED_ONE_BYTE_STRING(isolate, "process"),
375
6651
        FIXED_ONE_BYTE_STRING(isolate, "require"),
376
6651
        FIXED_ONE_BYTE_STRING(isolate, "internalBinding"),
377
6651
        FIXED_ONE_BYTE_STRING(isolate, "primordials"),
378
6651
    };
379
483917
  } else if (strncmp(id, "embedder_main_", strlen("embedder_main_")) == 0) {
380
    // Synthetic embedder main scripts from LoadEnvironment(): process, require
381
17
    parameters = {
382
17
        FIXED_ONE_BYTE_STRING(isolate, "process"),
383
17
        FIXED_ONE_BYTE_STRING(isolate, "require"),
384
17
    };
385
483900
  } else if (strncmp(id,
386
                     "internal/bootstrap/",
387
                     strlen("internal/bootstrap/")) == 0) {
388
    // internal/bootstrap/*: process, require, internalBinding, primordials
389
5256
    parameters = {
390
5256
        FIXED_ONE_BYTE_STRING(isolate, "process"),
391
5256
        FIXED_ONE_BYTE_STRING(isolate, "require"),
392
5256
        FIXED_ONE_BYTE_STRING(isolate, "internalBinding"),
393
5256
        FIXED_ONE_BYTE_STRING(isolate, "primordials"),
394
5256
    };
395
  } else {
396
    // others: exports, require, module, process, internalBinding, primordials
397
478644
    parameters = {
398
478644
        FIXED_ONE_BYTE_STRING(isolate, "exports"),
399
478644
        FIXED_ONE_BYTE_STRING(isolate, "require"),
400
478644
        FIXED_ONE_BYTE_STRING(isolate, "module"),
401
478644
        FIXED_ONE_BYTE_STRING(isolate, "process"),
402
478644
        FIXED_ONE_BYTE_STRING(isolate, "internalBinding"),
403
478644
        FIXED_ONE_BYTE_STRING(isolate, "primordials"),
404
478644
    };
405
  }
406
407
  MaybeLocal<Function> maybe = GetInstance()->LookupAndCompileInternal(
408
492302
      context, id, &parameters, &result);
409
492302
  if (optional_env != nullptr) {
410
490163
    RecordResult(id, result, optional_env);
411
  }
412
492302
  return maybe;
413
}
414
415
6
bool NativeModuleLoader::CompileAllBuiltins(Local<Context> context) {
416
6
  NativeModuleLoader* loader = GetInstance();
417
12
  std::vector<std::string> ids = loader->GetModuleIds();
418
6
  bool all_succeeded = true;
419
6
  std::string v8_tools_prefix = "internal/deps/v8/tools/";
420
1806
  for (const auto& id : ids) {
421
1800
    if (id.compare(0, v8_tools_prefix.size(), v8_tools_prefix) == 0) {
422
66
      continue;
423
    }
424
3468
    v8::TryCatch bootstrapCatch(context->GetIsolate());
425
1734
    USE(loader->LookupAndCompile(context, id.c_str(), nullptr));
426
1734
    if (bootstrapCatch.HasCaught()) {
427
      per_process::Debug(DebugCategory::CODE_CACHE,
428
                         "Failed to compile code cache for %s\n",
429
                         id.c_str());
430
      all_succeeded = false;
431
      PrintCaughtException(context->GetIsolate(), context, bootstrapCatch);
432
    }
433
  }
434
6
  return all_succeeded;
435
}
436
437
6
void NativeModuleLoader::CopyCodeCache(std::vector<CodeCacheInfo>* out) {
438
6
  NativeModuleLoader* loader = GetInstance();
439
12
  Mutex::ScopedLock lock(loader->code_cache_mutex());
440
6
  auto in = loader->code_cache();
441
1740
  for (auto const& item : *in) {
442
1734
    out->push_back(
443
1734
        {item.first,
444
1734
         {item.second->data, item.second->data + item.second->length}});
445
  }
446
6
}
447
448
5307
void NativeModuleLoader::RefreshCodeCache(
449
    const std::vector<CodeCacheInfo>& in) {
450
5307
  NativeModuleLoader* loader = GetInstance();
451
5307
  Mutex::ScopedLock lock(loader->code_cache_mutex());
452
5307
  auto out = loader->code_cache();
453
1539030
  for (auto const& item : in) {
454
1533723
    size_t length = item.data.size();
455
1533723
    uint8_t* buffer = new uint8_t[length];
456
1533723
    memcpy(buffer, item.data.data(), length);
457
    auto new_cache = std::make_unique<v8::ScriptCompiler::CachedData>(
458
3067446
        buffer, length, v8::ScriptCompiler::CachedData::BufferOwned);
459
1533723
    auto cache_it = out->find(item.id);
460
1533723
    if (cache_it != out->end()) {
461
      // Release the old cache and replace it with the new copy.
462
      cache_it->second.reset(new_cache.release());
463
    } else {
464
1533723
      out->emplace(item.id, new_cache.release());
465
    }
466
  }
467
5307
  loader->has_code_cache_ = true;
468
5307
}
469
470
1
void NativeModuleLoader::GetModuleCategories(
471
    Local<Name> property, const PropertyCallbackInfo<Value>& info) {
472
1
  Environment* env = Environment::GetCurrent(info);
473
1
  Isolate* isolate = env->isolate();
474
1
  Local<Context> context = env->context();
475
1
  Local<Object> result = Object::New(isolate);
476
477
  // Copy from the per-process categories
478
  std::set<std::string> cannot_be_required =
479
1
      GetInstance()->GetCannotBeRequired();
480
1
  std::set<std::string> can_be_required = GetInstance()->GetCanBeRequired();
481
482
1
  if (!env->owns_process_state()) {
483
    can_be_required.erase("trace_events");
484
    cannot_be_required.insert("trace_events");
485
  }
486
487
  Local<Value> cannot_be_required_js;
488
  Local<Value> can_be_required_js;
489
490
2
  if (!ToV8Value(context, cannot_be_required).ToLocal(&cannot_be_required_js))
491
    return;
492
1
  if (result
493
1
          ->Set(context,
494
                OneByteString(isolate, "cannotBeRequired"),
495
2
                cannot_be_required_js)
496
1
          .IsNothing())
497
    return;
498
2
  if (!ToV8Value(context, can_be_required).ToLocal(&can_be_required_js)) return;
499
1
  if (result
500
1
          ->Set(context,
501
                OneByteString(isolate, "canBeRequired"),
502
2
                can_be_required_js)
503
1
          .IsNothing()) {
504
    return;
505
  }
506
2
  info.GetReturnValue().Set(result);
507
}
508
509
1
void NativeModuleLoader::GetCacheUsage(
510
    const FunctionCallbackInfo<Value>& args) {
511
1
  Environment* env = Environment::GetCurrent(args);
512
1
  Isolate* isolate = env->isolate();
513
1
  Local<Context> context = env->context();
514
1
  Local<Object> result = Object::New(isolate);
515
516
  Local<Value> native_modules_with_cache_js;
517
  Local<Value> native_modules_without_cache_js;
518
  Local<Value> native_modules_in_snapshot_js;
519
1
  if (!ToV8Value(context, env->native_modules_with_cache)
520
1
           .ToLocal(&native_modules_with_cache_js)) {
521
    return;
522
  }
523
1
  if (result
524
1
          ->Set(env->context(),
525
                OneByteString(isolate, "compiledWithCache"),
526
2
                native_modules_with_cache_js)
527
1
          .IsNothing()) {
528
    return;
529
  }
530
531
1
  if (!ToV8Value(context, env->native_modules_without_cache)
532
1
           .ToLocal(&native_modules_without_cache_js)) {
533
    return;
534
  }
535
1
  if (result
536
1
          ->Set(env->context(),
537
                OneByteString(isolate, "compiledWithoutCache"),
538
2
                native_modules_without_cache_js)
539
1
          .IsNothing()) {
540
    return;
541
  }
542
543
1
  if (!ToV8Value(context, env->native_modules_in_snapshot)
544
1
           .ToLocal(&native_modules_without_cache_js)) {
545
    return;
546
  }
547
1
  if (result
548
1
          ->Set(env->context(),
549
                OneByteString(isolate, "compiledInSnapshot"),
550
2
                native_modules_without_cache_js)
551
1
          .IsNothing()) {
552
    return;
553
  }
554
555
2
  args.GetReturnValue().Set(result);
556
}
557
558
1344
void NativeModuleLoader::ModuleIdsGetter(
559
    Local<Name> property, const PropertyCallbackInfo<Value>& info) {
560
1344
  Isolate* isolate = info.GetIsolate();
561
562
1344
  std::vector<std::string> ids = GetInstance()->GetModuleIds();
563
4032
  info.GetReturnValue().Set(
564
2688
      ToV8Value(isolate->GetCurrentContext(), ids).ToLocalChecked());
565
1344
}
566
567
1305
void NativeModuleLoader::ConfigStringGetter(
568
    Local<Name> property, const PropertyCallbackInfo<Value>& info) {
569
1305
  info.GetReturnValue().Set(GetConfigString(info.GetIsolate()));
570
1305
}
571
572
490163
void NativeModuleLoader::RecordResult(const char* id,
573
                                      NativeModuleLoader::Result result,
574
                                      Environment* env) {
575
490163
  if (result == NativeModuleLoader::Result::kWithCache) {
576
478293
    env->native_modules_with_cache.insert(id);
577
  } else {
578
11870
    env->native_modules_without_cache.insert(id);
579
  }
580
490163
}
581
582
477042
void NativeModuleLoader::CompileFunction(
583
    const FunctionCallbackInfo<Value>& args) {
584
477042
  Environment* env = Environment::GetCurrent(args);
585
954084
  CHECK(args[0]->IsString());
586
1431126
  node::Utf8Value id_v(env->isolate(), args[0].As<String>());
587
477042
  const char* id = *id_v;
588
  MaybeLocal<Function> maybe =
589
477042
      GetInstance()->LookupAndCompile(env->context(), id, env);
590
  Local<Function> fn;
591
477042
  if (maybe.ToLocal(&fn)) {
592
954084
    args.GetReturnValue().Set(fn);
593
  }
594
477042
}
595
596
4
void NativeModuleLoader::HasCachedBuiltins(
597
    const FunctionCallbackInfo<Value>& args) {
598
4
  args.GetReturnValue().Set(
599
4
      v8::Boolean::New(args.GetIsolate(), GetInstance()->has_code_cache_));
600
4
}
601
602
// TODO(joyeecheung): It is somewhat confusing that Class::Initialize
603
// is used to initialize to the binding, but it is the current convention.
604
// Rename this across the code base to something that makes more sense.
605
1305
void NativeModuleLoader::Initialize(Local<Object> target,
606
                                    Local<Value> unused,
607
                                    Local<Context> context,
608
                                    void* priv) {
609
1305
  Environment* env = Environment::GetCurrent(context);
610
1305
  Isolate* isolate = env->isolate();
611
612
  target
613
1305
      ->SetAccessor(context,
614
                    env->config_string(),
615
                    ConfigStringGetter,
616
                    nullptr,
617
                    MaybeLocal<Value>(),
618
                    DEFAULT,
619
                    None,
620
5220
                    SideEffectType::kHasNoSideEffect)
621
      .Check();
622
  target
623
1305
      ->SetAccessor(context,
624
                    FIXED_ONE_BYTE_STRING(isolate, "moduleIds"),
625
                    ModuleIdsGetter,
626
                    nullptr,
627
                    MaybeLocal<Value>(),
628
                    DEFAULT,
629
                    None,
630
5220
                    SideEffectType::kHasNoSideEffect)
631
      .Check();
632
633
  target
634
1305
      ->SetAccessor(context,
635
                    FIXED_ONE_BYTE_STRING(isolate, "moduleCategories"),
636
                    GetModuleCategories,
637
                    nullptr,
638
                    Local<Value>(),
639
                    DEFAULT,
640
                    None,
641
2610
                    SideEffectType::kHasNoSideEffect)
642
      .Check();
643
644
1305
  SetMethod(
645
      context, target, "getCacheUsage", NativeModuleLoader::GetCacheUsage);
646
1305
  SetMethod(
647
      context, target, "compileFunction", NativeModuleLoader::CompileFunction);
648
1305
  SetMethod(context, target, "hasCachedBuiltins", HasCachedBuiltins);
649
  // internalBinding('native_module') should be frozen
650
1305
  target->SetIntegrityLevel(context, IntegrityLevel::kFrozen).FromJust();
651
1305
}
652
653
5314
void NativeModuleLoader::RegisterExternalReferences(
654
    ExternalReferenceRegistry* registry) {
655
5314
  registry->Register(ConfigStringGetter);
656
5314
  registry->Register(ModuleIdsGetter);
657
5314
  registry->Register(GetModuleCategories);
658
5314
  registry->Register(GetCacheUsage);
659
5314
  registry->Register(CompileFunction);
660
5314
  registry->Register(HasCachedBuiltins);
661
5314
}
662
663
}  // namespace native_module
664
}  // namespace node
665
666
5386
NODE_MODULE_CONTEXT_AWARE_INTERNAL(
667
    native_module, node::native_module::NativeModuleLoader::Initialize)
668
5314
NODE_MODULE_EXTERNAL_REFERENCE(
669
    native_module,
670
    node::native_module::NativeModuleLoader::RegisterExternalReferences)