GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: node_builtins.cc Lines: 285 332 85.8 %
Date: 2022-12-31 04:22:30 Branches: 95 126 75.4 %

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::FunctionTemplate;
17
using v8::IntegrityLevel;
18
using v8::Isolate;
19
using v8::Local;
20
using v8::MaybeLocal;
21
using v8::Name;
22
using v8::None;
23
using v8::Object;
24
using v8::ObjectTemplate;
25
using v8::PropertyCallbackInfo;
26
using v8::ScriptCompiler;
27
using v8::ScriptOrigin;
28
using v8::Set;
29
using v8::SideEffectType;
30
using v8::String;
31
using v8::Undefined;
32
using v8::Value;
33
34
BuiltinLoader BuiltinLoader::instance_;
35
36
5788
BuiltinLoader::BuiltinLoader() : config_(GetConfig()), has_code_cache_(false) {
37
5788
  LoadJavaScriptSource();
38
#if defined(NODE_HAVE_I18N_SUPPORT)
39
#ifdef NODE_SHARED_BUILTIN_CJS_MODULE_LEXER_LEXER_PATH
40
  AddExternalizedBuiltin(
41
      "internal/deps/cjs-module-lexer/lexer",
42
      STRINGIFY(NODE_SHARED_BUILTIN_CJS_MODULE_LEXER_LEXER_PATH));
43
#endif  // NODE_SHARED_BUILTIN_CJS_MODULE_LEXER_LEXER_PATH
44
45
#ifdef NODE_SHARED_BUILTIN_CJS_MODULE_LEXER_DIST_LEXER_PATH
46
  AddExternalizedBuiltin(
47
      "internal/deps/cjs-module-lexer/dist/lexer",
48
      STRINGIFY(NODE_SHARED_BUILTIN_CJS_MODULE_LEXER_DIST_LEXER_PATH));
49
#endif  // NODE_SHARED_BUILTIN_CJS_MODULE_LEXER_DIST_LEXER_PATH
50
51
#ifdef NODE_SHARED_BUILTIN_UNDICI_UNDICI_PATH
52
  AddExternalizedBuiltin("internal/deps/undici/undici",
53
                         STRINGIFY(NODE_SHARED_BUILTIN_UNDICI_UNDICI_PATH));
54
#endif  // NODE_SHARED_BUILTIN_UNDICI_UNDICI_PATH
55
#endif  // NODE_HAVE_I18N_SUPPORT
56
5788
}
57
58
1286610
BuiltinLoader* BuiltinLoader::GetInstance() {
59
1286610
  return &instance_;
60
}
61
62
bool BuiltinLoader::Exists(const char* id) {
63
  auto& source = GetInstance()->source_;
64
  return source.find(id) != source.end();
65
}
66
67
20
bool BuiltinLoader::Add(const char* id, const UnionBytes& source) {
68
20
  auto result = GetInstance()->source_.emplace(id, source);
69
20
  return result.second;
70
}
71
72
42
Local<Object> BuiltinLoader::GetSourceObject(Local<Context> context) {
73
42
  Isolate* isolate = context->GetIsolate();
74
42
  Local<Object> out = Object::New(isolate);
75
42
  auto& source = GetInstance()->source_;
76
13608
  for (auto const& x : source) {
77
13566
    Local<String> key = OneByteString(isolate, x.first.c_str(), x.first.size());
78
40698
    out->Set(context, key, x.second.ToStringChecked(isolate)).FromJust();
79
  }
80
42
  return out;
81
}
82
83
869
Local<String> BuiltinLoader::GetConfigString(Isolate* isolate) {
84
869
  return GetInstance()->config_.ToStringChecked(isolate);
85
}
86
87
873
std::vector<std::string> BuiltinLoader::GetBuiltinIds() {
88
873
  std::vector<std::string> ids;
89
873
  ids.reserve(source_.size());
90
283017
  for (auto const& x : source_) {
91
282144
    ids.emplace_back(x.first);
92
  }
93
873
  return ids;
94
}
95
96
2
void BuiltinLoader::InitializeBuiltinCategories() {
97
2
  if (builtin_categories_.is_initialized) {
98
    DCHECK(!builtin_categories_.can_be_required.empty());
99
1
    return;
100
  }
101
102
  std::vector<std::string> prefixes = {
103
#if !HAVE_OPENSSL
104
    "internal/crypto/",
105
    "internal/debugger/",
106
#endif  // !HAVE_OPENSSL
107
108
    "internal/bootstrap/",
109
    "internal/per_context/",
110
    "internal/deps/",
111
    "internal/main/"
112
7
  };
113
114
  builtin_categories_.can_be_required.emplace(
115
1
      "internal/deps/cjs-module-lexer/lexer");
116
117
7
  builtin_categories_.cannot_be_required = std::set<std::string> {
118
#if !HAVE_INSPECTOR
119
    "inspector", "inspector/promises", "internal/util/inspector",
120
#endif  // !HAVE_INSPECTOR
121
122
#if !NODE_USE_V8_PLATFORM || !defined(NODE_HAVE_I18N_SUPPORT)
123
        "trace_events",
124
#endif  // !NODE_USE_V8_PLATFORM || !defined(NODE_HAVE_I18N_SUPPORT)
125
126
#if !HAVE_OPENSSL
127
        "crypto", "crypto/promises", "https", "http2", "tls", "_tls_common",
128
        "_tls_wrap", "internal/tls/secure-pair",
129
        "internal/tls/parse-cert-string", "internal/tls/secure-context",
130
        "internal/http2/core", "internal/http2/compat",
131
        "internal/policy/manifest", "internal/process/policy",
132
        "internal/streams/lazy_transform",
133
#endif           // !HAVE_OPENSSL
134
        "sys",   // Deprecated.
135
        "wasi",  // Experimental.
136
        "internal/test/binding", "internal/v8_prof_polyfill",
137
        "internal/v8_prof_processor",
138
6
  };
139
140
324
  for (auto const& x : source_) {
141
323
    const std::string& id = x.first;
142
1615
    for (auto const& prefix : prefixes) {
143
1292
      if (prefix.length() > id.length()) {
144
370
        continue;
145
      }
146

961
      if (id.find(prefix) == 0 &&
147
39
          builtin_categories_.can_be_required.count(id) == 0) {
148
38
        builtin_categories_.cannot_be_required.emplace(id);
149
      }
150
    }
151
  }
152
153
324
  for (auto const& x : source_) {
154
323
    const std::string& id = x.first;
155
323
    if (0 == builtin_categories_.cannot_be_required.count(id)) {
156
280
      builtin_categories_.can_be_required.emplace(id);
157
    }
158
  }
159
160
1
  builtin_categories_.is_initialized = true;
161
}
162
163
1
const std::set<std::string>& BuiltinLoader::GetCannotBeRequired() {
164
1
  InitializeBuiltinCategories();
165
1
  return builtin_categories_.cannot_be_required;
166
}
167
168
1
const std::set<std::string>& BuiltinLoader::GetCanBeRequired() {
169
1
  InitializeBuiltinCategories();
170
1
  return builtin_categories_.can_be_required;
171
}
172
173
bool BuiltinLoader::CanBeRequired(const char* id) {
174
  return GetCanBeRequired().count(id) == 1;
175
}
176
177
bool BuiltinLoader::CannotBeRequired(const char* id) {
178
  return GetCannotBeRequired().count(id) == 1;
179
}
180
181
5716
BuiltinCodeCacheMap* BuiltinLoader::code_cache() {
182
5716
  return &code_cache_;
183
}
184
185
ScriptCompiler::CachedData* BuiltinLoader::GetCodeCache(const char* id) const {
186
  Mutex::ScopedLock lock(code_cache_mutex_);
187
  const auto it = code_cache_.find(id);
188
  if (it == code_cache_.end()) {
189
    // The module has not been compiled before.
190
    return nullptr;
191
  }
192
  return it->second.get();
193
}
194
195
#ifdef NODE_BUILTIN_MODULES_PATH
196
static std::string OnDiskFileName(const char* id) {
197
  std::string filename = NODE_BUILTIN_MODULES_PATH;
198
  filename += "/";
199
200
  if (strncmp(id, "internal/deps", strlen("internal/deps")) == 0) {
201
    id += strlen("internal/");
202
  } else {
203
    filename += "lib/";
204
  }
205
  filename += id;
206
  filename += ".js";
207
208
  return filename;
209
}
210
#endif  // NODE_BUILTIN_MODULES_PATH
211
212
646184
MaybeLocal<String> BuiltinLoader::LoadBuiltinSource(Isolate* isolate,
213
                                                    const char* id) {
214
#ifdef NODE_BUILTIN_MODULES_PATH
215
  if (strncmp(id, "embedder_main_", strlen("embedder_main_")) == 0) {
216
#endif  // NODE_BUILTIN_MODULES_PATH
217
646184
    const auto source_it = source_.find(id);
218
646184
    if (UNLIKELY(source_it == source_.end())) {
219
      fprintf(stderr, "Cannot find native builtin: \"%s\".\n", id);
220
      ABORT();
221
    }
222
1292368
    return source_it->second.ToStringChecked(isolate);
223
#ifdef NODE_BUILTIN_MODULES_PATH
224
  }
225
  std::string filename = OnDiskFileName(id);
226
227
  std::string contents;
228
  int r = ReadFileSync(&contents, filename.c_str());
229
  if (r != 0) {
230
    const std::string buf = SPrintF("Cannot read local builtin. %s: %s \"%s\"",
231
                                    uv_err_name(r),
232
                                    uv_strerror(r),
233
                                    filename);
234
    Local<String> message = OneByteString(isolate, buf.c_str());
235
    isolate->ThrowException(v8::Exception::Error(message));
236
    return MaybeLocal<String>();
237
  }
238
  return String::NewFromUtf8(
239
      isolate, contents.c_str(), v8::NewStringType::kNormal, contents.length());
240
#endif  // NODE_BUILTIN_MODULES_PATH
241
}
242
243
#if defined(NODE_HAVE_I18N_SUPPORT)
244
void BuiltinLoader::AddExternalizedBuiltin(const char* id,
245
                                           const char* filename) {
246
  std::string source;
247
  int r = ReadFileSync(&source, filename);
248
  if (r != 0) {
249
    fprintf(
250
        stderr, "Cannot load externalized builtin: \"%s:%s\".\n", id, filename);
251
    ABORT();
252
    return;
253
  }
254
255
  icu::UnicodeString utf16 = icu::UnicodeString::fromUTF8(
256
      icu::StringPiece(source.data(), source.length()));
257
  auto source_utf16 = std::make_unique<icu::UnicodeString>(utf16);
258
  Add(id,
259
      UnionBytes(reinterpret_cast<const uint16_t*>((*source_utf16).getBuffer()),
260
                 utf16.length()));
261
  // keep source bytes for builtin alive while BuiltinLoader exists
262
  GetInstance()->externalized_source_bytes_.push_back(std::move(source_utf16));
263
}
264
#endif  // NODE_HAVE_I18N_SUPPORT
265
266
// Returns Local<Function> of the compiled module if return_code_cache
267
// is false (we are only compiling the function).
268
// Otherwise return a Local<Object> containing the cache.
269
646184
MaybeLocal<Function> BuiltinLoader::LookupAndCompileInternal(
270
    Local<Context> context,
271
    const char* id,
272
    std::vector<Local<String>>* parameters,
273
    BuiltinLoader::Result* result) {
274
646184
  Isolate* isolate = context->GetIsolate();
275
646184
  EscapableHandleScope scope(isolate);
276
277
  Local<String> source;
278
1292368
  if (!LoadBuiltinSource(isolate, id).ToLocal(&source)) {
279
    return {};
280
  }
281
282
1938552
  std::string filename_s = std::string("node:") + id;
283
  Local<String> filename =
284
646184
      OneByteString(isolate, filename_s.c_str(), filename_s.size());
285
646184
  ScriptOrigin origin(isolate, filename, 0, 0, true);
286
287
646184
  ScriptCompiler::CachedData* cached_data = nullptr;
288
  {
289
    // Note: The lock here should not extend into the
290
    // `CompileFunction()` call below, because this function may recurse if
291
    // there is a syntax error during bootstrap (because the fatal exception
292
    // handler is invoked, which may load built-in modules).
293
1292368
    Mutex::ScopedLock lock(code_cache_mutex_);
294
646184
    auto cache_it = code_cache_.find(id);
295
646184
    if (cache_it != code_cache_.end()) {
296
      // Transfer ownership to ScriptCompiler::Source later.
297
641939
      cached_data = cache_it->second.release();
298
641939
      code_cache_.erase(cache_it);
299
    }
300
  }
301
302
646184
  const bool has_cache = cached_data != nullptr;
303
646184
  ScriptCompiler::CompileOptions options =
304
646184
      has_cache ? ScriptCompiler::kConsumeCodeCache
305
                : ScriptCompiler::kEagerCompile;
306
646184
  ScriptCompiler::Source script_source(source, origin, cached_data);
307
308
  per_process::Debug(DebugCategory::CODE_CACHE,
309
                     "Compiling %s %s code cache\n",
310
                     id,
311
646184
                     has_cache ? "with" : "without");
312
313
  MaybeLocal<Function> maybe_fun =
314
      ScriptCompiler::CompileFunction(context,
315
                                      &script_source,
316
                                      parameters->size(),
317
                                      parameters->data(),
318
                                      0,
319
                                      nullptr,
320
646184
                                      options);
321
322
  // This could fail when there are early errors in the built-in modules,
323
  // e.g. the syntax errors
324
  Local<Function> fun;
325
646184
  if (!maybe_fun.ToLocal(&fun)) {
326
    // In the case of early errors, v8 is already capable of
327
    // decorating the stack for us - note that we use CompileFunction
328
    // so there is no need to worry about wrappers.
329
    return MaybeLocal<Function>();
330
  }
331
332
  // XXX(joyeecheung): this bookkeeping is not exactly accurate because
333
  // it only starts after the Environment is created, so the per_context.js
334
  // will never be in any of these two sets, but the two sets are only for
335
  // testing anyway.
336
337
641939
  *result = (has_cache && !script_source.GetCachedData()->rejected)
338
1288123
                ? Result::kWithCache
339
                : Result::kWithoutCache;
340
341
646184
  if (has_cache) {
342
641939
    per_process::Debug(DebugCategory::CODE_CACHE,
343
                       "Code cache of %s (%s) %s\n",
344
                       id,
345
641939
                       script_source.GetCachedData()->buffer_policy ==
346
                               ScriptCompiler::CachedData::BufferNotOwned
347
1283878
                           ? "BufferNotOwned"
348
                           : "BufferOwned",
349
641939
                       script_source.GetCachedData()->rejected ? "is rejected"
350
                                                               : "is accepted");
351
  }
352
353
  // Generate new cache for next compilation
354
  std::unique_ptr<ScriptCompiler::CachedData> new_cached_data(
355
646184
      ScriptCompiler::CreateCodeCacheForFunction(fun));
356
646184
  CHECK_NOT_NULL(new_cached_data);
357
358
  {
359
1292368
    Mutex::ScopedLock lock(code_cache_mutex_);
360
646184
    const auto it = code_cache_.find(id);
361
    // TODO(joyeecheung): it's safer for each thread to have its own
362
    // copy of the code cache map.
363
646184
    if (it == code_cache_.end()) {
364
645446
      code_cache_.emplace(id, std::move(new_cached_data));
365
    } else {
366
738
      it->second.reset(new_cached_data.release());
367
    }
368
  }
369
370
646184
  return scope.Escape(fun);
371
}
372
373
// Returns Local<Function> of the compiled module if return_code_cache
374
// is false (we are only compiling the function).
375
// Otherwise return a Local<Object> containing the cache.
376
646184
MaybeLocal<Function> BuiltinLoader::LookupAndCompile(Local<Context> context,
377
                                                     const char* id,
378
                                                     Realm* optional_realm) {
379
  Result result;
380
646184
  std::vector<Local<String>> parameters;
381
646184
  Isolate* isolate = context->GetIsolate();
382
  // Detects parameters of the scripts based on module ids.
383
  // internal/bootstrap/loaders: process, getLinkedBinding,
384
  //                             getInternalBinding, primordials
385
646184
  if (strcmp(id, "internal/bootstrap/loaders") == 0) {
386
834
    parameters = {
387
834
        FIXED_ONE_BYTE_STRING(isolate, "process"),
388
834
        FIXED_ONE_BYTE_STRING(isolate, "getLinkedBinding"),
389
834
        FIXED_ONE_BYTE_STRING(isolate, "getInternalBinding"),
390
834
        FIXED_ONE_BYTE_STRING(isolate, "primordials"),
391
834
    };
392
645350
  } else if (strncmp(id,
393
                     "internal/per_context/",
394
                     strlen("internal/per_context/")) == 0) {
395
    // internal/per_context/*: global, exports, primordials
396
471
    parameters = {
397
471
        FIXED_ONE_BYTE_STRING(isolate, "exports"),
398
471
        FIXED_ONE_BYTE_STRING(isolate, "primordials"),
399
471
    };
400
644879
  } else if (strncmp(id, "internal/main/", strlen("internal/main/")) == 0 ||
401
638293
             strncmp(id,
402
                     "internal/bootstrap/",
403
                     strlen("internal/bootstrap/")) == 0) {
404
    // internal/main/*, internal/bootstrap/*: process, require,
405
    //                                        internalBinding, primordials
406
9936
    parameters = {
407
9936
        FIXED_ONE_BYTE_STRING(isolate, "process"),
408
9936
        FIXED_ONE_BYTE_STRING(isolate, "require"),
409
9936
        FIXED_ONE_BYTE_STRING(isolate, "internalBinding"),
410
9936
        FIXED_ONE_BYTE_STRING(isolate, "primordials"),
411
9936
    };
412
634943
  } else if (strncmp(id, "embedder_main_", strlen("embedder_main_")) == 0) {
413
    // Synthetic embedder main scripts from LoadEnvironment(): process, require
414
20
    parameters = {
415
20
        FIXED_ONE_BYTE_STRING(isolate, "process"),
416
20
        FIXED_ONE_BYTE_STRING(isolate, "require"),
417
20
    };
418
  } else {
419
    // others: exports, require, module, process, internalBinding, primordials
420
634923
    parameters = {
421
634923
        FIXED_ONE_BYTE_STRING(isolate, "exports"),
422
634923
        FIXED_ONE_BYTE_STRING(isolate, "require"),
423
634923
        FIXED_ONE_BYTE_STRING(isolate, "module"),
424
634923
        FIXED_ONE_BYTE_STRING(isolate, "process"),
425
634923
        FIXED_ONE_BYTE_STRING(isolate, "internalBinding"),
426
634923
        FIXED_ONE_BYTE_STRING(isolate, "primordials"),
427
634923
    };
428
  }
429
430
  MaybeLocal<Function> maybe = GetInstance()->LookupAndCompileInternal(
431
646184
      context, id, &parameters, &result);
432
646184
  if (optional_realm != nullptr) {
433
643550
    RecordResult(id, result, optional_realm);
434
  }
435
646184
  return maybe;
436
}
437
438
10650
MaybeLocal<Value> BuiltinLoader::CompileAndCall(Local<Context> context,
439
                                                const char* id,
440
                                                Realm* realm) {
441
10650
  Isolate* isolate = context->GetIsolate();
442
  // Arguments must match the parameters specified in
443
  // BuiltinLoader::LookupAndCompile().
444
20999
  std::vector<Local<Value>> arguments;
445
  // Detects parameters of the scripts based on module ids.
446
  // internal/bootstrap/loaders: process, getLinkedBinding,
447
  //                             getInternalBinding, primordials
448
10650
  if (strcmp(id, "internal/bootstrap/loaders") == 0) {
449
    Local<Value> get_linked_binding;
450
    Local<Value> get_internal_binding;
451
827
    if (!NewFunctionTemplate(isolate, binding::GetLinkedBinding)
452
827
             ->GetFunction(context)
453
1654
             .ToLocal(&get_linked_binding) ||
454
827
        !NewFunctionTemplate(isolate, binding::GetInternalBinding)
455
1654
             ->GetFunction(context)
456
827
             .ToLocal(&get_internal_binding)) {
457
      return MaybeLocal<Value>();
458
    }
459
2481
    arguments = {realm->process_object(),
460
                 get_linked_binding,
461
                 get_internal_binding,
462
827
                 realm->primordials()};
463
9823
  } else if (strncmp(id, "internal/main/", strlen("internal/main/")) == 0 ||
464
3328
             strncmp(id,
465
                     "internal/bootstrap/",
466
                     strlen("internal/bootstrap/")) == 0) {
467
    // internal/main/*, internal/bootstrap/*: process, require,
468
    //                                        internalBinding, primordials
469
49015
    arguments = {realm->process_object(),
470
                 realm->builtin_module_require(),
471
                 realm->internal_binding_loader(),
472
9803
                 realm->primordials()};
473
20
  } else if (strncmp(id, "embedder_main_", strlen("embedder_main_")) == 0) {
474
    // Synthetic embedder main scripts from LoadEnvironment(): process, require
475
60
    arguments = {
476
        realm->process_object(),
477
        realm->builtin_module_require(),
478
20
    };
479
  } else {
480
    // This should be invoked with the other CompileAndCall() methods, as
481
    // we are unable to generate the arguments.
482
    // Currently there are two cases:
483
    // internal/per_context/*: the arguments are generated in
484
    //                         InitializePrimordials()
485
    // all the other cases: the arguments are generated in the JS-land loader.
486
    UNREACHABLE();
487
  }
488
10650
  return CompileAndCall(context, id, arguments.size(), arguments.data(), realm);
489
}
490
491
11100
MaybeLocal<Value> BuiltinLoader::CompileAndCall(Local<Context> context,
492
                                                const char* id,
493
                                                int argc,
494
                                                Local<Value> argv[],
495
                                                Realm* optional_realm) {
496
  // Arguments must match the parameters specified in
497
  // BuiltinLoader::LookupAndCompile().
498
11100
  MaybeLocal<Function> maybe_fn = LookupAndCompile(context, id, optional_realm);
499
  Local<Function> fn;
500
11100
  if (!maybe_fn.ToLocal(&fn)) {
501
    return MaybeLocal<Value>();
502
  }
503
22200
  Local<Value> undefined = Undefined(context->GetIsolate());
504
11100
  return fn->Call(context, undefined, argc, argv);
505
}
506
507
7
bool BuiltinLoader::CompileAllBuiltins(Local<Context> context) {
508
7
  BuiltinLoader* loader = GetInstance();
509
14
  std::vector<std::string> ids = loader->GetBuiltinIds();
510
7
  bool all_succeeded = true;
511
7
  std::string v8_tools_prefix = "internal/deps/v8/tools/";
512
2268
  for (const auto& id : ids) {
513
2261
    if (id.compare(0, v8_tools_prefix.size(), v8_tools_prefix) == 0) {
514
77
      continue;
515
    }
516
4368
    v8::TryCatch bootstrapCatch(context->GetIsolate());
517
2184
    USE(loader->LookupAndCompile(context, id.c_str(), nullptr));
518
2184
    if (bootstrapCatch.HasCaught()) {
519
      per_process::Debug(DebugCategory::CODE_CACHE,
520
                         "Failed to compile code cache for %s\n",
521
                         id.c_str());
522
      all_succeeded = false;
523
      PrintCaughtException(context->GetIsolate(), context, bootstrapCatch);
524
    }
525
  }
526
7
  return all_succeeded;
527
}
528
529
7
void BuiltinLoader::CopyCodeCache(std::vector<CodeCacheInfo>* out) {
530
7
  BuiltinLoader* loader = GetInstance();
531
14
  Mutex::ScopedLock lock(loader->code_cache_mutex());
532
7
  auto in = loader->code_cache();
533
2191
  for (auto const& item : *in) {
534
2184
    out->push_back(
535
2184
        {item.first,
536
2184
         {item.second->data, item.second->data + item.second->length}});
537
  }
538
7
}
539
540
5709
void BuiltinLoader::RefreshCodeCache(const std::vector<CodeCacheInfo>& in) {
541
5709
  BuiltinLoader* loader = GetInstance();
542
5709
  Mutex::ScopedLock lock(loader->code_cache_mutex());
543
5709
  auto out = loader->code_cache();
544
1786917
  for (auto const& item : in) {
545
1781208
    size_t length = item.data.size();
546
1781208
    uint8_t* buffer = new uint8_t[length];
547
1781208
    memcpy(buffer, item.data.data(), length);
548
    auto new_cache = std::make_unique<v8::ScriptCompiler::CachedData>(
549
3562416
        buffer, length, v8::ScriptCompiler::CachedData::BufferOwned);
550
1781208
    auto cache_it = out->find(item.id);
551
1781208
    if (cache_it != out->end()) {
552
      // Release the old cache and replace it with the new copy.
553
      cache_it->second.reset(new_cache.release());
554
    } else {
555
1781208
      out->emplace(item.id, new_cache.release());
556
    }
557
  }
558
5709
  loader->has_code_cache_ = true;
559
5709
}
560
561
1
void BuiltinLoader::GetBuiltinCategories(
562
    Local<Name> property, const PropertyCallbackInfo<Value>& info) {
563
1
  Environment* env = Environment::GetCurrent(info);
564
1
  Isolate* isolate = env->isolate();
565
1
  Local<Context> context = env->context();
566
1
  Local<Object> result = Object::New(isolate);
567
568
  // Copy from the per-process categories
569
  std::set<std::string> cannot_be_required =
570
1
      GetInstance()->GetCannotBeRequired();
571
1
  std::set<std::string> can_be_required = GetInstance()->GetCanBeRequired();
572
573
1
  if (!env->owns_process_state()) {
574
    can_be_required.erase("trace_events");
575
    cannot_be_required.insert("trace_events");
576
  }
577
578
  Local<Value> cannot_be_required_js;
579
  Local<Value> can_be_required_js;
580
581
2
  if (!ToV8Value(context, cannot_be_required).ToLocal(&cannot_be_required_js))
582
    return;
583
1
  if (result
584
1
          ->Set(context,
585
                OneByteString(isolate, "cannotBeRequired"),
586
2
                cannot_be_required_js)
587
1
          .IsNothing())
588
    return;
589
2
  if (!ToV8Value(context, can_be_required).ToLocal(&can_be_required_js)) return;
590
1
  if (result
591
1
          ->Set(context,
592
                OneByteString(isolate, "canBeRequired"),
593
2
                can_be_required_js)
594
1
          .IsNothing()) {
595
    return;
596
  }
597
2
  info.GetReturnValue().Set(result);
598
}
599
600
1
void BuiltinLoader::GetCacheUsage(const FunctionCallbackInfo<Value>& args) {
601
1
  Realm* realm = Realm::GetCurrent(args);
602
1
  Isolate* isolate = realm->isolate();
603
1
  Local<Context> context = realm->context();
604
1
  Local<Object> result = Object::New(isolate);
605
606
  Local<Value> builtins_with_cache_js;
607
  Local<Value> builtins_without_cache_js;
608
  Local<Value> builtins_in_snapshot_js;
609
1
  if (!ToV8Value(context, realm->builtins_with_cache)
610
1
           .ToLocal(&builtins_with_cache_js)) {
611
    return;
612
  }
613
1
  if (result
614
1
          ->Set(context,
615
                OneByteString(isolate, "compiledWithCache"),
616
2
                builtins_with_cache_js)
617
1
          .IsNothing()) {
618
    return;
619
  }
620
621
1
  if (!ToV8Value(context, realm->builtins_without_cache)
622
1
           .ToLocal(&builtins_without_cache_js)) {
623
    return;
624
  }
625
1
  if (result
626
1
          ->Set(context,
627
                OneByteString(isolate, "compiledWithoutCache"),
628
2
                builtins_without_cache_js)
629
1
          .IsNothing()) {
630
    return;
631
  }
632
633
1
  if (!ToV8Value(context, realm->builtins_in_snapshot)
634
1
           .ToLocal(&builtins_without_cache_js)) {
635
    return;
636
  }
637
1
  if (result
638
1
          ->Set(context,
639
                OneByteString(isolate, "compiledInSnapshot"),
640
2
                builtins_without_cache_js)
641
1
          .IsNothing()) {
642
    return;
643
  }
644
645
2
  args.GetReturnValue().Set(result);
646
}
647
648
866
void BuiltinLoader::BuiltinIdsGetter(Local<Name> property,
649
                                     const PropertyCallbackInfo<Value>& info) {
650
866
  Isolate* isolate = info.GetIsolate();
651
652
866
  std::vector<std::string> ids = GetInstance()->GetBuiltinIds();
653
2598
  info.GetReturnValue().Set(
654
1732
      ToV8Value(isolate->GetCurrentContext(), ids).ToLocalChecked());
655
866
}
656
657
827
void BuiltinLoader::ConfigStringGetter(
658
    Local<Name> property, const PropertyCallbackInfo<Value>& info) {
659
827
  info.GetReturnValue().Set(GetConfigString(info.GetIsolate()));
660
827
}
661
662
643550
void BuiltinLoader::RecordResult(const char* id,
663
                                 BuiltinLoader::Result result,
664
                                 Realm* realm) {
665
643550
  if (result == BuiltinLoader::Result::kWithCache) {
666
626381
    realm->builtins_with_cache.insert(id);
667
  } else {
668
17169
    realm->builtins_without_cache.insert(id);
669
  }
670
643550
}
671
672
632900
void BuiltinLoader::CompileFunction(const FunctionCallbackInfo<Value>& args) {
673
632900
  Realm* realm = Realm::GetCurrent(args);
674
1265800
  CHECK(args[0]->IsString());
675
1898700
  node::Utf8Value id_v(realm->isolate(), args[0].As<String>());
676
632900
  const char* id = *id_v;
677
  MaybeLocal<Function> maybe =
678
632900
      GetInstance()->LookupAndCompile(realm->context(), id, realm);
679
  Local<Function> fn;
680
632900
  if (maybe.ToLocal(&fn)) {
681
1265800
    args.GetReturnValue().Set(fn);
682
  }
683
632900
}
684
685
4
void BuiltinLoader::HasCachedBuiltins(const FunctionCallbackInfo<Value>& args) {
686
4
  args.GetReturnValue().Set(
687
4
      v8::Boolean::New(args.GetIsolate(), GetInstance()->has_code_cache_));
688
4
}
689
690
831
void BuiltinLoader::CreatePerIsolateProperties(IsolateData* isolate_data,
691
                                               Local<FunctionTemplate> target) {
692
831
  Isolate* isolate = isolate_data->isolate();
693
831
  Local<ObjectTemplate> proto = target->PrototypeTemplate();
694
695
2493
  proto->SetAccessor(isolate_data->config_string(),
696
                     ConfigStringGetter,
697
                     nullptr,
698
                     Local<Value>(),
699
                     DEFAULT,
700
                     None,
701
                     SideEffectType::kHasNoSideEffect);
702
703
2493
  proto->SetAccessor(FIXED_ONE_BYTE_STRING(isolate, "builtinIds"),
704
                     BuiltinIdsGetter,
705
                     nullptr,
706
                     Local<Value>(),
707
                     DEFAULT,
708
                     None,
709
                     SideEffectType::kHasNoSideEffect);
710
711
2493
  proto->SetAccessor(FIXED_ONE_BYTE_STRING(isolate, "builtinCategories"),
712
                     GetBuiltinCategories,
713
                     nullptr,
714
                     Local<Value>(),
715
                     DEFAULT,
716
                     None,
717
                     SideEffectType::kHasNoSideEffect);
718
719
831
  SetMethod(isolate, proto, "getCacheUsage", BuiltinLoader::GetCacheUsage);
720
831
  SetMethod(isolate, proto, "compileFunction", BuiltinLoader::CompileFunction);
721
831
  SetMethod(isolate, proto, "hasCachedBuiltins", HasCachedBuiltins);
722
831
}
723
724
827
void BuiltinLoader::CreatePerContextProperties(Local<Object> target,
725
                                               Local<Value> unused,
726
                                               Local<Context> context,
727
                                               void* priv) {
728
  // internalBinding('builtins') should be frozen
729
827
  target->SetIntegrityLevel(context, IntegrityLevel::kFrozen).FromJust();
730
827
}
731
732
5717
void BuiltinLoader::RegisterExternalReferences(
733
    ExternalReferenceRegistry* registry) {
734
5717
  registry->Register(ConfigStringGetter);
735
5717
  registry->Register(BuiltinIdsGetter);
736
5717
  registry->Register(GetBuiltinCategories);
737
5717
  registry->Register(GetCacheUsage);
738
5717
  registry->Register(CompileFunction);
739
5717
  registry->Register(HasCachedBuiltins);
740
5717
}
741
742
}  // namespace builtins
743
}  // namespace node
744
745
831
NODE_BINDING_PER_ISOLATE_INIT(
746
    builtins, node::builtins::BuiltinLoader::CreatePerIsolateProperties)
747
5788
NODE_BINDING_CONTEXT_AWARE_INTERNAL(
748
    builtins, node::builtins::BuiltinLoader::CreatePerContextProperties)
749
5717
NODE_BINDING_EXTERNAL_REFERENCE(
750
    builtins, node::builtins::BuiltinLoader::RegisterExternalReferences)