GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: node_builtins.cc Lines: 285 332 85.8 %
Date: 2022-12-07 04:23:16 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::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::Undefined;
30
using v8::Value;
31
32
BuiltinLoader BuiltinLoader::instance_;
33
34
5710
BuiltinLoader::BuiltinLoader() : config_(GetConfig()), has_code_cache_(false) {
35
5710
  LoadJavaScriptSource();
36
#if defined(NODE_HAVE_I18N_SUPPORT)
37
#ifdef NODE_SHARED_BUILTIN_CJS_MODULE_LEXER_LEXER_PATH
38
  AddExternalizedBuiltin(
39
      "internal/deps/cjs-module-lexer/lexer",
40
      STRINGIFY(NODE_SHARED_BUILTIN_CJS_MODULE_LEXER_LEXER_PATH));
41
#endif  // NODE_SHARED_BUILTIN_CJS_MODULE_LEXER_LEXER_PATH
42
43
#ifdef NODE_SHARED_BUILTIN_CJS_MODULE_LEXER_DIST_LEXER_PATH
44
  AddExternalizedBuiltin(
45
      "internal/deps/cjs-module-lexer/dist/lexer",
46
      STRINGIFY(NODE_SHARED_BUILTIN_CJS_MODULE_LEXER_DIST_LEXER_PATH));
47
#endif  // NODE_SHARED_BUILTIN_CJS_MODULE_LEXER_DIST_LEXER_PATH
48
49
#ifdef NODE_SHARED_BUILTIN_UNDICI_UNDICI_PATH
50
  AddExternalizedBuiltin("internal/deps/undici/undici",
51
                         STRINGIFY(NODE_SHARED_BUILTIN_UNDICI_UNDICI_PATH));
52
#endif  // NODE_SHARED_BUILTIN_UNDICI_UNDICI_PATH
53
#endif  // NODE_HAVE_I18N_SUPPORT
54
5710
}
55
56
928524
BuiltinLoader* BuiltinLoader::GetInstance() {
57
928524
  return &instance_;
58
}
59
60
bool BuiltinLoader::Exists(const char* id) {
61
  auto& source = GetInstance()->source_;
62
  return source.find(id) != source.end();
63
}
64
65
19
bool BuiltinLoader::Add(const char* id, const UnionBytes& source) {
66
19
  auto result = GetInstance()->source_.emplace(id, source);
67
19
  return result.second;
68
}
69
70
42
Local<Object> BuiltinLoader::GetSourceObject(Local<Context> context) {
71
42
  Isolate* isolate = context->GetIsolate();
72
42
  Local<Object> out = Object::New(isolate);
73
42
  auto& source = GetInstance()->source_;
74
13356
  for (auto const& x : source) {
75
13314
    Local<String> key = OneByteString(isolate, x.first.c_str(), x.first.size());
76
39942
    out->Set(context, key, x.second.ToStringChecked(isolate)).FromJust();
77
  }
78
42
  return out;
79
}
80
81
842
Local<String> BuiltinLoader::GetConfigString(Isolate* isolate) {
82
842
  return GetInstance()->config_.ToStringChecked(isolate);
83
}
84
85
846
std::vector<std::string> BuiltinLoader::GetBuiltinIds() {
86
846
  std::vector<std::string> ids;
87
846
  ids.reserve(source_.size());
88
269211
  for (auto const& x : source_) {
89
268365
    ids.emplace_back(x.first);
90
  }
91
846
  return ids;
92
}
93
94
2
void BuiltinLoader::InitializeBuiltinCategories() {
95
2
  if (builtin_categories_.is_initialized) {
96
    DCHECK(!builtin_categories_.can_be_required.empty());
97
1
    return;
98
  }
99
100
  std::vector<std::string> prefixes = {
101
#if !HAVE_OPENSSL
102
    "internal/crypto/",
103
    "internal/debugger/",
104
#endif  // !HAVE_OPENSSL
105
106
    "internal/bootstrap/",
107
    "internal/per_context/",
108
    "internal/deps/",
109
    "internal/main/"
110
7
  };
111
112
  builtin_categories_.can_be_required.emplace(
113
1
      "internal/deps/cjs-module-lexer/lexer");
114
115
7
  builtin_categories_.cannot_be_required = std::set<std::string> {
116
#if !HAVE_INSPECTOR
117
    "inspector", "inspector/promises", "internal/util/inspector",
118
#endif  // !HAVE_INSPECTOR
119
120
#if !NODE_USE_V8_PLATFORM || !defined(NODE_HAVE_I18N_SUPPORT)
121
        "trace_events",
122
#endif  // !NODE_USE_V8_PLATFORM || !defined(NODE_HAVE_I18N_SUPPORT)
123
124
#if !HAVE_OPENSSL
125
        "crypto", "crypto/promises", "https", "http2", "tls", "_tls_common",
126
        "_tls_wrap", "internal/tls/secure-pair",
127
        "internal/tls/parse-cert-string", "internal/tls/secure-context",
128
        "internal/http2/core", "internal/http2/compat",
129
        "internal/policy/manifest", "internal/process/policy",
130
        "internal/streams/lazy_transform",
131
#endif           // !HAVE_OPENSSL
132
        "sys",   // Deprecated.
133
        "wasi",  // Experimental.
134
        "internal/test/binding", "internal/v8_prof_polyfill",
135
        "internal/v8_prof_processor",
136
6
  };
137
138
318
  for (auto const& x : source_) {
139
317
    const std::string& id = x.first;
140
1585
    for (auto const& prefix : prefixes) {
141
1268
      if (prefix.length() > id.length()) {
142
364
        continue;
143
      }
144

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