GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: node_builtins.cc Lines: 285 320 89.1 %
Date: 2022-09-18 04:22:26 Branches: 95 124 76.6 %

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
5598
BuiltinLoader::BuiltinLoader() : config_(GetConfig()), has_code_cache_(false) {
35
5598
  LoadJavaScriptSource();
36
5598
}
37
38
863924
BuiltinLoader* BuiltinLoader::GetInstance() {
39
863924
  return &instance_;
40
}
41
42
bool BuiltinLoader::Exists(const char* id) {
43
  auto& source = GetInstance()->source_;
44
  return source.find(id) != source.end();
45
}
46
47
19
bool BuiltinLoader::Add(const char* id, const UnionBytes& source) {
48
19
  auto result = GetInstance()->source_.emplace(id, source);
49
19
  return result.second;
50
}
51
52
42
Local<Object> BuiltinLoader::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
12894
  for (auto const& x : source) {
57
12852
    Local<String> key = OneByteString(isolate, x.first.c_str(), x.first.size());
58
38556
    out->Set(context, key, x.second.ToStringChecked(isolate)).FromJust();
59
  }
60
42
  return out;
61
}
62
63
822
Local<String> BuiltinLoader::GetConfigString(Isolate* isolate) {
64
822
  return GetInstance()->config_.ToStringChecked(isolate);
65
}
66
67
825
std::vector<std::string> BuiltinLoader::GetBuiltinIds() {
68
825
  std::vector<std::string> ids;
69
825
  ids.reserve(source_.size());
70
253458
  for (auto const& x : source_) {
71
252633
    ids.emplace_back(x.first);
72
  }
73
825
  return ids;
74
}
75
76
2
void BuiltinLoader::InitializeBuiltinCategories() {
77
2
  if (builtin_categories_.is_initialized) {
78
    DCHECK(!builtin_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
  builtin_categories_.can_be_required.emplace(
95
1
      "internal/deps/cjs-module-lexer/lexer");
96
97
7
  builtin_categories_.cannot_be_required = std::set<std::string> {
98
#if !HAVE_INSPECTOR
99
    "inspector", "internal/util/inspector",
100
#endif  // !HAVE_INSPECTOR
101
102
#if !NODE_USE_V8_PLATFORM || !defined(NODE_HAVE_I18N_SUPPORT)
103
        "trace_events",
104
#endif  // !NODE_USE_V8_PLATFORM || !defined(NODE_HAVE_I18N_SUPPORT)
105
106
#if !HAVE_OPENSSL
107
        "crypto", "crypto/promises", "https", "http2", "tls", "_tls_common",
108
        "_tls_wrap", "internal/tls/secure-pair",
109
        "internal/tls/parse-cert-string", "internal/tls/secure-context",
110
        "internal/http2/core", "internal/http2/compat",
111
        "internal/policy/manifest", "internal/process/policy",
112
        "internal/streams/lazy_transform",
113
#endif           // !HAVE_OPENSSL
114
        "sys",   // Deprecated.
115
        "wasi",  // Experimental.
116
        "internal/test/binding", "internal/v8_prof_polyfill",
117
        "internal/v8_prof_processor",
118
6
  };
119
120
307
  for (auto const& x : source_) {
121
306
    const std::string& id = x.first;
122
1530
    for (auto const& prefix : prefixes) {
123
1224
      if (prefix.length() > id.length()) {
124
348
        continue;
125
      }
126

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