GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: node_native_module_env.cc Lines: 138 156 88.5 %
Date: 2022-06-06 04:15:48 Branches: 28 44 63.6 %

Line Branch Exec Source
1
#include <algorithm>
2
3
#include "debug_utils-inl.h"
4
#include "env-inl.h"
5
#include "node_external_reference.h"
6
#include "node_native_module_env.h"
7
8
namespace node {
9
namespace native_module {
10
11
using v8::Context;
12
using v8::DEFAULT;
13
using v8::Function;
14
using v8::FunctionCallbackInfo;
15
using v8::IntegrityLevel;
16
using v8::Isolate;
17
using v8::Local;
18
using v8::MaybeLocal;
19
using v8::Name;
20
using v8::None;
21
using v8::Object;
22
using v8::PropertyCallbackInfo;
23
using v8::Set;
24
using v8::SideEffectType;
25
using v8::String;
26
using v8::Value;
27
28
bool NativeModuleEnv::has_code_cache_ = false;
29
30
17
bool NativeModuleEnv::Add(const char* id, const UnionBytes& source) {
31
17
  return NativeModuleLoader::GetInstance()->Add(id, source);
32
}
33
34
bool NativeModuleEnv::Exists(const char* id) {
35
  return NativeModuleLoader::GetInstance()->Exists(id);
36
}
37
38
41
Local<Object> NativeModuleEnv::GetSourceObject(Local<Context> context) {
39
41
  return NativeModuleLoader::GetInstance()->GetSourceObject(context);
40
}
41
42
895
Local<String> NativeModuleEnv::GetConfigString(Isolate* isolate) {
43
895
  return NativeModuleLoader::GetInstance()->GetConfigString(isolate);
44
}
45
46
6
bool NativeModuleEnv::CompileAllModules(Local<Context> context) {
47
6
  NativeModuleLoader* loader = NativeModuleLoader::GetInstance();
48
6
  std::vector<std::string> ids = loader->GetModuleIds();
49
6
  bool all_succeeded = true;
50
1806
  for (const auto& id : ids) {
51
    // TODO(joyeecheung): compile non-module scripts here too.
52
1800
    if (!loader->CanBeRequired(id.c_str())) {
53
258
      continue;
54
    }
55
3084
    v8::TryCatch bootstrapCatch(context->GetIsolate());
56
    native_module::NativeModuleLoader::Result result;
57
1542
    USE(loader->CompileAsModule(context, id.c_str(), &result));
58
1542
    if (bootstrapCatch.HasCaught()) {
59
      per_process::Debug(DebugCategory::CODE_CACHE,
60
                         "Failed to compile code cache for %s\n",
61
                         id.c_str());
62
      all_succeeded = false;
63
      PrintCaughtException(context->GetIsolate(), context, bootstrapCatch);
64
    }
65
  }
66
6
  return all_succeeded;
67
}
68
69
6
void NativeModuleEnv::CopyCodeCache(std::vector<CodeCacheInfo>* out) {
70
6
  NativeModuleLoader* loader = NativeModuleLoader::GetInstance();
71
12
  Mutex::ScopedLock lock(loader->code_cache_mutex());
72
6
  auto in = loader->code_cache();
73
1596
  for (auto const& item : *in) {
74
1590
    out->push_back(
75
1590
        {item.first,
76
1590
         {item.second->data, item.second->data + item.second->length}});
77
  }
78
6
}
79
80
5200
void NativeModuleEnv::RefreshCodeCache(const std::vector<CodeCacheInfo>& in) {
81
5200
  NativeModuleLoader* loader = NativeModuleLoader::GetInstance();
82
5200
  Mutex::ScopedLock lock(loader->code_cache_mutex());
83
5200
  auto out = loader->code_cache();
84
1383200
  for (auto const& item : in) {
85
1378000
    size_t length = item.data.size();
86
1378000
    uint8_t* buffer = new uint8_t[length];
87
1378000
    memcpy(buffer, item.data.data(), length);
88
    auto new_cache = std::make_unique<v8::ScriptCompiler::CachedData>(
89
2756000
        buffer, length, v8::ScriptCompiler::CachedData::BufferOwned);
90
1378000
    auto cache_it = out->find(item.id);
91
1378000
    if (cache_it != out->end()) {
92
      // Release the old cache and replace it with the new copy.
93
      cache_it->second.reset(new_cache.release());
94
    } else {
95
1378000
      out->emplace(item.id, new_cache.release());
96
    }
97
  }
98
5200
  NativeModuleEnv::has_code_cache_ = true;
99
5200
}
100
101
1
void NativeModuleEnv::GetModuleCategories(
102
    Local<Name> property, const PropertyCallbackInfo<Value>& info) {
103
1
  Environment* env = Environment::GetCurrent(info);
104
1
  Isolate* isolate = env->isolate();
105
1
  Local<Context> context = env->context();
106
1
  Local<Object> result = Object::New(isolate);
107
108
  // Copy from the per-process categories
109
  std::set<std::string> cannot_be_required =
110
1
      NativeModuleLoader::GetInstance()->GetCannotBeRequired();
111
  std::set<std::string> can_be_required =
112
1
      NativeModuleLoader::GetInstance()->GetCanBeRequired();
113
114
1
  if (!env->owns_process_state()) {
115
    can_be_required.erase("trace_events");
116
    cannot_be_required.insert("trace_events");
117
  }
118
119
  Local<Value> cannot_be_required_js;
120
  Local<Value> can_be_required_js;
121
122
2
  if (!ToV8Value(context, cannot_be_required).ToLocal(&cannot_be_required_js))
123
    return;
124
1
  if (result
125
1
      ->Set(context,
126
            OneByteString(isolate, "cannotBeRequired"),
127
2
            cannot_be_required_js)
128
1
      .IsNothing())
129
    return;
130
2
  if (!ToV8Value(context, can_be_required).ToLocal(&can_be_required_js))
131
    return;
132
1
  if (result
133
1
      ->Set(context,
134
            OneByteString(isolate, "canBeRequired"),
135
2
            can_be_required_js)
136
1
      .IsNothing()) {
137
    return;
138
  }
139
2
  info.GetReturnValue().Set(result);
140
}
141
142
1
void NativeModuleEnv::GetCacheUsage(const FunctionCallbackInfo<Value>& args) {
143
1
  Environment* env = Environment::GetCurrent(args);
144
1
  Isolate* isolate = env->isolate();
145
1
  Local<Context> context = env->context();
146
1
  Local<Object> result = Object::New(isolate);
147
148
  Local<Value> native_modules_with_cache_js;
149
  Local<Value> native_modules_without_cache_js;
150
  Local<Value> native_modules_in_snapshot_js;
151
1
  if (!ToV8Value(context, env->native_modules_with_cache)
152
1
      .ToLocal(&native_modules_with_cache_js)) {
153
    return;
154
  }
155
1
  if (result
156
1
      ->Set(env->context(),
157
            OneByteString(isolate, "compiledWithCache"),
158
2
            native_modules_with_cache_js)
159
1
      .IsNothing()) {
160
    return;
161
  }
162
163
1
  if (!ToV8Value(context, env->native_modules_without_cache)
164
1
      .ToLocal(&native_modules_without_cache_js)) {
165
    return;
166
  }
167
1
  if (result
168
1
      ->Set(env->context(),
169
            OneByteString(isolate, "compiledWithoutCache"),
170
2
            native_modules_without_cache_js)
171
1
      .IsNothing()) {
172
    return;
173
  }
174
175
1
  if (!ToV8Value(context, env->native_modules_in_snapshot)
176
1
      .ToLocal(&native_modules_without_cache_js)) {
177
    return;
178
  }
179
1
  if (result
180
1
      ->Set(env->context(),
181
            OneByteString(isolate, "compiledInSnapshot"),
182
2
            native_modules_without_cache_js)
183
1
      .IsNothing()) {
184
    return;
185
  }
186
187
2
  args.GetReturnValue().Set(result);
188
}
189
190
892
void NativeModuleEnv::ModuleIdsGetter(Local<Name> property,
191
                                      const PropertyCallbackInfo<Value>& info) {
192
892
  Isolate* isolate = info.GetIsolate();
193
194
  std::vector<std::string> ids =
195
892
      NativeModuleLoader::GetInstance()->GetModuleIds();
196
2676
  info.GetReturnValue().Set(
197
1784
      ToV8Value(isolate->GetCurrentContext(), ids).ToLocalChecked());
198
892
}
199
200
854
void NativeModuleEnv::ConfigStringGetter(
201
    Local<Name> property, const PropertyCallbackInfo<Value>& info) {
202
854
  info.GetReturnValue().Set(GetConfigString(info.GetIsolate()));
203
854
}
204
205
405808
void NativeModuleEnv::RecordResult(const char* id,
206
                                   NativeModuleLoader::Result result,
207
                                   Environment* env) {
208
405808
  if (result == NativeModuleLoader::Result::kWithCache) {
209
383048
    env->native_modules_with_cache.insert(id);
210
  } else {
211
22760
    env->native_modules_without_cache.insert(id);
212
  }
213
405808
}
214
395500
void NativeModuleEnv::CompileFunction(const FunctionCallbackInfo<Value>& args) {
215
395500
  Environment* env = Environment::GetCurrent(args);
216
791000
  CHECK(args[0]->IsString());
217
1186500
  node::Utf8Value id_v(env->isolate(), args[0].As<String>());
218
395500
  const char* id = *id_v;
219
  NativeModuleLoader::Result result;
220
  MaybeLocal<Function> maybe =
221
      NativeModuleLoader::GetInstance()->CompileAsModule(
222
395500
          env->context(), id, &result);
223
395500
  RecordResult(id, result, env);
224
  Local<Function> fn;
225
395500
  if (maybe.ToLocal(&fn)) {
226
791000
    args.GetReturnValue().Set(fn);
227
  }
228
395500
}
229
230
// Returns Local<Function> of the compiled module if return_code_cache
231
// is false (we are only compiling the function).
232
// Otherwise return a Local<Object> containing the cache.
233
10701
MaybeLocal<Function> NativeModuleEnv::LookupAndCompile(
234
    Local<Context> context,
235
    const char* id,
236
    std::vector<Local<String>>* parameters,
237
    Environment* optional_env) {
238
  NativeModuleLoader::Result result;
239
  MaybeLocal<Function> maybe =
240
      NativeModuleLoader::GetInstance()->LookupAndCompile(
241
10701
          context, id, parameters, &result);
242
10701
  if (optional_env != nullptr) {
243
10308
    RecordResult(id, result, optional_env);
244
  }
245
10701
  return maybe;
246
}
247
248
4
void NativeModuleEnv::HasCachedBuiltins(
249
    const FunctionCallbackInfo<Value>& args) {
250
4
  args.GetReturnValue().Set(
251
      v8::Boolean::New(args.GetIsolate(), NativeModuleEnv::has_code_cache_));
252
4
}
253
254
// TODO(joyeecheung): It is somewhat confusing that Class::Initialize
255
// is used to initialize to the binding, but it is the current convention.
256
// Rename this across the code base to something that makes more sense.
257
854
void NativeModuleEnv::Initialize(Local<Object> target,
258
                                 Local<Value> unused,
259
                                 Local<Context> context,
260
                                 void* priv) {
261
854
  Environment* env = Environment::GetCurrent(context);
262
263
  target
264
854
      ->SetAccessor(env->context(),
265
                    env->config_string(),
266
                    ConfigStringGetter,
267
                    nullptr,
268
                    MaybeLocal<Value>(),
269
                    DEFAULT,
270
                    None,
271
3416
                    SideEffectType::kHasNoSideEffect)
272
      .Check();
273
  target
274
854
      ->SetAccessor(env->context(),
275
                    FIXED_ONE_BYTE_STRING(env->isolate(), "moduleIds"),
276
                    ModuleIdsGetter,
277
                    nullptr,
278
                    MaybeLocal<Value>(),
279
                    DEFAULT,
280
                    None,
281
3416
                    SideEffectType::kHasNoSideEffect)
282
      .Check();
283
284
  target
285
854
      ->SetAccessor(env->context(),
286
                    FIXED_ONE_BYTE_STRING(env->isolate(), "moduleCategories"),
287
                    GetModuleCategories,
288
                    nullptr,
289
                    Local<Value>(),
290
                    DEFAULT,
291
                    None,
292
1708
                    SideEffectType::kHasNoSideEffect)
293
      .Check();
294
295
854
  env->SetMethod(target, "getCacheUsage", NativeModuleEnv::GetCacheUsage);
296
854
  env->SetMethod(target, "compileFunction", NativeModuleEnv::CompileFunction);
297
854
  env->SetMethod(target, "hasCachedBuiltins", HasCachedBuiltins);
298
  // internalBinding('native_module') should be frozen
299
854
  target->SetIntegrityLevel(context, IntegrityLevel::kFrozen).FromJust();
300
854
}
301
302
5206
void NativeModuleEnv::RegisterExternalReferences(
303
    ExternalReferenceRegistry* registry) {
304
5206
  registry->Register(ConfigStringGetter);
305
5206
  registry->Register(ModuleIdsGetter);
306
5206
  registry->Register(GetModuleCategories);
307
5206
  registry->Register(GetCacheUsage);
308
5206
  registry->Register(CompileFunction);
309
5206
  registry->Register(HasCachedBuiltins);
310
5206
}
311
312
}  // namespace native_module
313
}  // namespace node
314
315
5274
NODE_MODULE_CONTEXT_AWARE_INTERNAL(
316
    native_module, node::native_module::NativeModuleEnv::Initialize)
317
5206
NODE_MODULE_EXTERNAL_REFERENCE(
318
    native_module,
319
    node::native_module::NativeModuleEnv::RegisterExternalReferences)