GCC Code Coverage Report
Directory: ../ Exec Total Coverage
File: /home/iojs/build/workspace/node-test-commit-linux-coverage-daily/nodes/benchmark/out/../src/node_native_module.cc Lines: 125 128 97.7 %
Date: 2019-03-02 22:23:06 Branches: 30 44 68.2 %

Line Branch Exec Source
1
#include "node_native_module.h"
2
#include "node_errors.h"
3
4
namespace node {
5
6
namespace per_process {
7
4292
native_module::NativeModuleLoader native_module_loader;
8
}  // namespace per_process
9
10
namespace native_module {
11
12
using v8::Array;
13
using v8::ArrayBuffer;
14
using v8::Context;
15
using v8::DEFAULT;
16
using v8::EscapableHandleScope;
17
using v8::Function;
18
using v8::FunctionCallbackInfo;
19
using v8::HandleScope;
20
using v8::Integer;
21
using v8::IntegrityLevel;
22
using v8::Isolate;
23
using v8::Local;
24
using v8::Maybe;
25
using v8::MaybeLocal;
26
using v8::Name;
27
using v8::None;
28
using v8::Object;
29
using v8::PropertyCallbackInfo;
30
using v8::Script;
31
using v8::ScriptCompiler;
32
using v8::ScriptOrigin;
33
using v8::Set;
34
using v8::SideEffectType;
35
using v8::String;
36
using v8::Uint8Array;
37
using v8::Value;
38
39
// TODO(joyeecheung): make these more general and put them into util.h
40
19
Local<Object> MapToObject(Local<Context> context,
41
                          const NativeModuleRecordMap& in) {
42
19
  Isolate* isolate = context->GetIsolate();
43
19
  Local<Object> out = Object::New(isolate);
44
3762
  for (auto const& x : in) {
45
3743
    Local<String> key = OneByteString(isolate, x.first.c_str(), x.first.size());
46
11229
    out->Set(context, key, x.second.ToStringChecked(isolate)).FromJust();
47
  }
48
19
  return out;
49
}
50
51
2
Local<Set> ToJsSet(Local<Context> context,
52
                   const std::set<std::string>& in) {
53
2
  Isolate* isolate = context->GetIsolate();
54
2
  Local<Set> out = Set::New(isolate);
55
171
  for (auto const& x : in) {
56
507
    out->Add(context, OneByteString(isolate, x.c_str(), x.size()))
57
338
        .ToLocalChecked();
58
  }
59
2
  return out;
60
}
61
62
4243
bool NativeModuleLoader::Exists(const char* id) {
63
4243
  return source_.find(id) != source_.end();
64
}
65
66
1
void NativeModuleLoader::GetCacheUsage(
67
    const FunctionCallbackInfo<Value>& args) {
68
1
  Environment* env = Environment::GetCurrent(args);
69
1
  Isolate* isolate = env->isolate();
70
1
  Local<Context> context = env->context();
71
1
  Local<Object> result = Object::New(isolate);
72
  result
73
      ->Set(env->context(),
74
            OneByteString(isolate, "compiledWithCache"),
75
5
            ToJsSet(context, env->native_modules_with_cache))
76
2
      .FromJust();
77
  result
78
      ->Set(env->context(),
79
            OneByteString(isolate, "compiledWithoutCache"),
80
5
            ToJsSet(context, env->native_modules_without_cache))
81
2
      .FromJust();
82
2
  args.GetReturnValue().Set(result);
83
1
}
84
85
4414
void NativeModuleLoader::ModuleIdsGetter(
86
    Local<Name> property, const PropertyCallbackInfo<Value>& info) {
87
4414
  Isolate* isolate = info.GetIsolate();
88
89
  const NativeModuleRecordMap& source_ =
90
4414
      per_process::native_module_loader.source_;
91
4414
  std::vector<Local<Value>> ids;
92
4414
  ids.reserve(source_.size());
93
94
873972
  for (auto const& x : source_) {
95
1739116
    ids.push_back(OneByteString(isolate, x.first.c_str(), x.first.size()));
96
  }
97
98
13242
  info.GetReturnValue().Set(Array::New(isolate, ids.data(), ids.size()));
99
4414
}
100
101
4408
void NativeModuleLoader::ConfigStringGetter(
102
    Local<Name> property, const PropertyCallbackInfo<Value>& info) {
103
  info.GetReturnValue().Set(
104
13224
      per_process::native_module_loader.GetConfigString(info.GetIsolate()));
105
4408
}
106
107
19
Local<Object> NativeModuleLoader::GetSourceObject(
108
    Local<Context> context) const {
109
19
  return MapToObject(context, source_);
110
}
111
112
4427
Local<String> NativeModuleLoader::GetConfigString(Isolate* isolate) const {
113
4427
  return config_.ToStringChecked(isolate);
114
}
115
116
4292
NativeModuleLoader::NativeModuleLoader() : config_(GetConfig()) {
117
4292
  LoadJavaScriptSource();
118
4292
  LoadCodeCache();
119
4292
}
120
121
// This is supposed to be run only by the main thread in
122
// tools/generate_code_cache.js
123
162
void NativeModuleLoader::GetCodeCache(const FunctionCallbackInfo<Value>& args) {
124
162
  Environment* env = Environment::GetCurrent(args);
125
162
  Isolate* isolate = env->isolate();
126
162
  CHECK(env->is_main_thread());
127
128
486
  CHECK(args[0]->IsString());
129
324
  node::Utf8Value id_v(isolate, args[0].As<String>());
130
162
  const char* id = *id_v;
131
132
162
  const NativeModuleLoader& loader = per_process::native_module_loader;
133
162
  MaybeLocal<Uint8Array> ret = loader.GetCodeCache(isolate, id);
134
162
  if (!ret.IsEmpty()) {
135
324
    args.GetReturnValue().Set(ret.ToLocalChecked());
136
162
  }
137
162
}
138
139
// This is supposed to be run only by the main thread in
140
// tools/generate_code_cache.js
141
162
MaybeLocal<Uint8Array> NativeModuleLoader::GetCodeCache(Isolate* isolate,
142
                                                        const char* id) const {
143
162
  EscapableHandleScope scope(isolate);
144
324
  Mutex::ScopedLock lock(code_cache_mutex_);
145
146
162
  ScriptCompiler::CachedData* cached_data = nullptr;
147
162
  const auto it = code_cache_.find(id);
148
162
  if (it == code_cache_.end()) {
149
    // The module has not been compiled before.
150
    return MaybeLocal<Uint8Array>();
151
  }
152
153
162
  cached_data = it->second.get();
154
155
162
  Local<ArrayBuffer> buf = ArrayBuffer::New(isolate, cached_data->length);
156
324
  memcpy(buf->GetContents().Data(), cached_data->data, cached_data->length);
157
324
  return scope.Escape(Uint8Array::New(buf, 0, cached_data->length));
158
}
159
160
346888
void NativeModuleLoader::CompileFunction(
161
    const FunctionCallbackInfo<Value>& args) {
162
346888
  Environment* env = Environment::GetCurrent(args);
163
1040664
  CHECK(args[0]->IsString());
164
693776
  node::Utf8Value id(env->isolate(), args[0].As<String>());
165
166
346890
  MaybeLocal<Function> result = CompileAsModule(env, *id);
167
346890
  if (!result.IsEmpty()) {
168
693780
    args.GetReturnValue().Set(result.ToLocalChecked());
169
346890
  }
170
346890
}
171
172
346887
MaybeLocal<Function> NativeModuleLoader::CompileAsModule(Environment* env,
173
                                                         const char* id) {
174
  std::vector<Local<String>> parameters = {env->exports_string(),
175
                                           env->require_string(),
176
                                           env->module_string(),
177
                                           env->process_string(),
178
                                           env->internal_binding_string(),
179
346887
                                           env->primordials_string()};
180
  return per_process::native_module_loader.LookupAndCompile(
181
346890
      env->context(), id, &parameters, env);
182
}
183
184
// Returns Local<Function> of the compiled module if return_code_cache
185
// is false (we are only compiling the function).
186
// Otherwise return a Local<Object> containing the cache.
187
373525
MaybeLocal<Function> NativeModuleLoader::LookupAndCompile(
188
    Local<Context> context,
189
    const char* id,
190
    std::vector<Local<String>>* parameters,
191
    Environment* optional_env) {
192
373525
  Isolate* isolate = context->GetIsolate();
193
373526
  EscapableHandleScope scope(isolate);
194
  Local<Value> ret;  // Used to convert to MaybeLocal before return
195
196
373526
  const auto source_it = source_.find(id);
197
373525
  CHECK_NE(source_it, source_.end());
198
373522
  Local<String> source = source_it->second.ToStringChecked(isolate);
199
200
747052
  std::string filename_s = id + std::string(".js");
201
  Local<String> filename =
202
373525
      OneByteString(isolate, filename_s.c_str(), filename_s.size());
203
373524
  Local<Integer> line_offset = Integer::New(isolate, 0);
204
373518
  Local<Integer> column_offset = Integer::New(isolate, 0);
205
373525
  ScriptOrigin origin(filename, line_offset, column_offset, True(isolate));
206
207
747051
  Mutex::ScopedLock lock(code_cache_mutex_);
208
209
373526
  ScriptCompiler::CachedData* cached_data = nullptr;
210
  {
211
373526
    auto cache_it = code_cache_.find(id);
212
373526
    if (cache_it != code_cache_.end()) {
213
      // Transfer ownership to ScriptCompiler::Source later.
214
15881
      cached_data = cache_it->second.release();
215
15881
      code_cache_.erase(cache_it);
216
    }
217
  }
218
219
373526
  const bool use_cache = cached_data != nullptr;
220
  ScriptCompiler::CompileOptions options =
221
      use_cache ? ScriptCompiler::kConsumeCodeCache
222
373526
                : ScriptCompiler::kEagerCompile;
223
  ScriptCompiler::Source script_source(source, origin, cached_data);
224
225
  MaybeLocal<Function> maybe_fun =
226
      ScriptCompiler::CompileFunctionInContext(context,
227
                                               &script_source,
228
                                               parameters->size(),
229
                                               parameters->data(),
230
                                               0,
231
                                               nullptr,
232
373526
                                               options);
233
234
  // This could fail when there are early errors in the native modules,
235
  // e.g. the syntax errors
236
373526
  if (maybe_fun.IsEmpty()) {
237
    // In the case of early errors, v8 is already capable of
238
    // decorating the stack for us - note that we use CompileFunctionInContext
239
    // so there is no need to worry about wrappers.
240
    return MaybeLocal<Function>();
241
  }
242
243
373526
  Local<Function> fun = maybe_fun.ToLocalChecked();
244
  // XXX(joyeecheung): this bookkeeping is not exactly accurate because
245
  // it only starts after the Environment is created, so the per_context.js
246
  // will never be in any of these two sets, but the two sets are only for
247
  // testing anyway.
248
373526
  if (use_cache) {
249
15881
    if (optional_env != nullptr) {
250
      // This could happen when Node is run with any v8 flag, but
251
      // the cache is not generated with one
252
11139
      if (script_source.GetCachedData()->rejected) {
253
        optional_env->native_modules_without_cache.insert(id);
254
      } else {
255
11139
        optional_env->native_modules_with_cache.insert(id);
256
      }
257
    }
258
  } else {
259
357645
    if (optional_env != nullptr) {
260
353401
      optional_env->native_modules_without_cache.insert(id);
261
    }
262
  }
263
264
  // Generate new cache for next compilation
265
  std::unique_ptr<ScriptCompiler::CachedData> new_cached_data(
266
747052
      ScriptCompiler::CreateCodeCacheForFunction(fun));
267
373526
  CHECK_NOT_NULL(new_cached_data);
268
269
  // The old entry should've been erased by now so we can just emplace
270
373526
  code_cache_.emplace(id, std::move(new_cached_data));
271
272
373526
  return scope.Escape(fun);
273
}
274
275
4414
void NativeModuleLoader::Initialize(Local<Object> target,
276
                                    Local<Value> unused,
277
                                    Local<Context> context,
278
                                    void* priv) {
279
4414
  Environment* env = Environment::GetCurrent(context);
280
281
17656
  CHECK(target
282
            ->SetAccessor(env->context(),
283
                          env->config_string(),
284
                          ConfigStringGetter,
285
                          nullptr,
286
                          MaybeLocal<Value>(),
287
                          DEFAULT,
288
                          None,
289
                          SideEffectType::kHasNoSideEffect)
290
            .FromJust());
291
17656
  CHECK(target
292
            ->SetAccessor(env->context(),
293
                          FIXED_ONE_BYTE_STRING(env->isolate(), "moduleIds"),
294
                          ModuleIdsGetter,
295
                          nullptr,
296
                          MaybeLocal<Value>(),
297
                          DEFAULT,
298
                          None,
299
                          SideEffectType::kHasNoSideEffect)
300
            .FromJust());
301
302
  env->SetMethod(
303
4414
      target, "getCacheUsage", NativeModuleLoader::GetCacheUsage);
304
  env->SetMethod(
305
4414
      target, "compileFunction", NativeModuleLoader::CompileFunction);
306
4414
  env->SetMethod(target, "getCodeCache", NativeModuleLoader::GetCodeCache);
307
  // internalBinding('native_module') should be frozen
308
8828
  target->SetIntegrityLevel(context, IntegrityLevel::kFrozen).FromJust();
309
4414
}
310
311
}  // namespace native_module
312
}  // namespace node
313
314

17168
NODE_MODULE_CONTEXT_AWARE_INTERNAL(
315
    native_module, node::native_module::NativeModuleLoader::Initialize)