GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: node_builtins.cc Lines: 267 299 89.3 %
Date: 2022-08-14 04:19:53 Branches: 84 108 77.8 %

Line Branch Exec Source
1
#include "node_builtins.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 builtins {
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
BuiltinLoader BuiltinLoader::instance_;
32
33
5321
BuiltinLoader::BuiltinLoader() : config_(GetConfig()), has_code_cache_(false) {
34
5321
  LoadJavaScriptSource();
35
5321
}
36
37
800731
BuiltinLoader* BuiltinLoader::GetInstance() {
38
800731
  return &instance_;
39
}
40
41
bool BuiltinLoader::Exists(const char* id) {
42
  auto& source = GetInstance()->source_;
43
  return source.find(id) != source.end();
44
}
45
46
17
bool BuiltinLoader::Add(const char* id, const UnionBytes& source) {
47
17
  auto result = GetInstance()->source_.emplace(id, source);
48
17
  return result.second;
49
}
50
51
42
Local<Object> BuiltinLoader::GetSourceObject(Local<Context> context) {
52
42
  Isolate* isolate = context->GetIsolate();
53
42
  Local<Object> out = Object::New(isolate);
54
42
  auto& source = GetInstance()->source_;
55
12684
  for (auto const& x : source) {
56
12642
    Local<String> key = OneByteString(isolate, x.first.c_str(), x.first.size());
57
37926
    out->Set(context, key, x.second.ToStringChecked(isolate)).FromJust();
58
  }
59
42
  return out;
60
}
61
62
804
Local<String> BuiltinLoader::GetConfigString(Isolate* isolate) {
63
804
  return GetInstance()->config_.ToStringChecked(isolate);
64
}
65
66
807
std::vector<std::string> BuiltinLoader::GetBuiltinIds() {
67
807
  std::vector<std::string> ids;
68
807
  ids.reserve(source_.size());
69
243869
  for (auto const& x : source_) {
70
243062
    ids.emplace_back(x.first);
71
  }
72
807
  return ids;
73
}
74
75
2
void BuiltinLoader::InitializeBuiltinCategories() {
76
2
  if (builtin_categories_.is_initialized) {
77
    DCHECK(!builtin_categories_.can_be_required.empty());
78
1
    return;
79
  }
80
81
  std::vector<std::string> prefixes = {
82
#if !HAVE_OPENSSL
83
    "internal/crypto/",
84
    "internal/debugger/",
85
#endif  // !HAVE_OPENSSL
86
87
    "internal/bootstrap/",
88
    "internal/per_context/",
89
    "internal/deps/",
90
    "internal/main/"
91
7
  };
92
93
  builtin_categories_.can_be_required.emplace(
94
1
      "internal/deps/cjs-module-lexer/lexer");
95
96
7
  builtin_categories_.cannot_be_required = std::set<std::string> {
97
#if !HAVE_INSPECTOR
98
    "inspector", "internal/util/inspector",
99
#endif  // !HAVE_INSPECTOR
100
101
#if !NODE_USE_V8_PLATFORM || !defined(NODE_HAVE_I18N_SUPPORT)
102
        "trace_events",
103
#endif  // !NODE_USE_V8_PLATFORM || !defined(NODE_HAVE_I18N_SUPPORT)
104
105
#if !HAVE_OPENSSL
106
        "crypto", "crypto/promises", "https", "http2", "tls", "_tls_common",
107
        "_tls_wrap", "internal/tls/secure-pair",
108
        "internal/tls/parse-cert-string", "internal/tls/secure-context",
109
        "internal/http2/core", "internal/http2/compat",
110
        "internal/policy/manifest", "internal/process/policy",
111
        "internal/streams/lazy_transform",
112
#endif           // !HAVE_OPENSSL
113
        "sys",   // Deprecated.
114
        "wasi",  // Experimental.
115
        "internal/test/binding", "internal/v8_prof_polyfill",
116
        "internal/v8_prof_processor",
117
6
  };
118
119
302
  for (auto const& x : source_) {
120
301
    const std::string& id = x.first;
121
1505
    for (auto const& prefix : prefixes) {
122
1204
      if (prefix.length() > id.length()) {
123
347
        continue;
124
      }
125

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