GCC Code Coverage Report
Directory: ../ Exec Total Coverage
File: /home/iojs/build/workspace/node-test-commit-linux-coverage-daily/nodes/benchmark/out/../src/api/environment.cc Lines: 107 187 57.2 %
Date: 2019-05-05 22:32:45 Branches: 52 113 46.0 %

Line Branch Exec Source
1
#include "env.h"
2
#include "node.h"
3
#include "node_context_data.h"
4
#include "node_errors.h"
5
#include "node_internals.h"
6
#include "node_native_module_env.h"
7
#include "node_platform.h"
8
#include "node_v8_platform-inl.h"
9
#include "uv.h"
10
11
#ifdef NODE_ENABLE_VTUNE_PROFILING
12
#include "../deps/v8/src/third_party/vtune/v8-vtune.h"
13
#endif
14
15
namespace node {
16
using v8::Context;
17
using v8::EscapableHandleScope;
18
using v8::Function;
19
using v8::HandleScope;
20
using v8::Isolate;
21
using v8::Local;
22
using v8::MaybeLocal;
23
using v8::Message;
24
using v8::MicrotasksPolicy;
25
using v8::Null;
26
using v8::Object;
27
using v8::ObjectTemplate;
28
using v8::Private;
29
using v8::String;
30
using v8::Value;
31
32
31
static bool AllowWasmCodeGenerationCallback(Local<Context> context,
33
                                            Local<String>) {
34
  Local<Value> wasm_code_gen =
35
62
      context->GetEmbedderData(ContextEmbedderIndex::kAllowWasmCodeGeneration);
36

93
  return wasm_code_gen->IsUndefined() || wasm_code_gen->IsTrue();
37
}
38
39
32
static bool ShouldAbortOnUncaughtException(Isolate* isolate) {
40
32
  DebugSealHandleScope scope(isolate);
41
32
  Environment* env = Environment::GetCurrent(isolate);
42
32
  return env != nullptr &&
43

95
         (env->is_main_thread() || !env->is_stopping()) &&
44

158
         env->should_abort_on_uncaught_toggle()[0] &&
45
66
         !env->inside_should_not_abort_on_uncaught_scope();
46
}
47
48
893541
void* NodeArrayBufferAllocator::Allocate(size_t size) {
49

893541
  if (zero_fill_field_ || per_process::cli_options->zero_fill_all_buffers)
50
52760
    return UncheckedCalloc(size);
51
  else
52
840781
    return UncheckedMalloc(size);
53
}
54
55
DebuggingArrayBufferAllocator::~DebuggingArrayBufferAllocator() {
56
  CHECK(allocations_.empty());
57
}
58
59
void* DebuggingArrayBufferAllocator::Allocate(size_t size) {
60
  Mutex::ScopedLock lock(mutex_);
61
  void* data = NodeArrayBufferAllocator::Allocate(size);
62
  RegisterPointerInternal(data, size);
63
  return data;
64
}
65
66
void* DebuggingArrayBufferAllocator::AllocateUninitialized(size_t size) {
67
  Mutex::ScopedLock lock(mutex_);
68
  void* data = NodeArrayBufferAllocator::AllocateUninitialized(size);
69
  RegisterPointerInternal(data, size);
70
  return data;
71
}
72
73
void DebuggingArrayBufferAllocator::Free(void* data, size_t size) {
74
  Mutex::ScopedLock lock(mutex_);
75
  UnregisterPointerInternal(data, size);
76
  NodeArrayBufferAllocator::Free(data, size);
77
}
78
79
void* DebuggingArrayBufferAllocator::Reallocate(void* data,
80
                                                size_t old_size,
81
                                                size_t size) {
82
  Mutex::ScopedLock lock(mutex_);
83
  void* ret = NodeArrayBufferAllocator::Reallocate(data, old_size, size);
84
  if (ret == nullptr) {
85
    if (size == 0)  // i.e. equivalent to free().
86
      UnregisterPointerInternal(data, old_size);
87
    return nullptr;
88
  }
89
90
  if (data != nullptr) {
91
    auto it = allocations_.find(data);
92
    CHECK_NE(it, allocations_.end());
93
    allocations_.erase(it);
94
  }
95
96
  RegisterPointerInternal(ret, size);
97
  return ret;
98
}
99
100
void DebuggingArrayBufferAllocator::RegisterPointer(void* data, size_t size) {
101
  Mutex::ScopedLock lock(mutex_);
102
  RegisterPointerInternal(data, size);
103
}
104
105
void DebuggingArrayBufferAllocator::UnregisterPointer(void* data, size_t size) {
106
  Mutex::ScopedLock lock(mutex_);
107
  UnregisterPointerInternal(data, size);
108
}
109
110
void DebuggingArrayBufferAllocator::UnregisterPointerInternal(void* data,
111
                                                              size_t size) {
112
  if (data == nullptr) return;
113
  auto it = allocations_.find(data);
114
  CHECK_NE(it, allocations_.end());
115
  if (size > 0) {
116
    // We allow allocations with size 1 for 0-length buffers to avoid having
117
    // to deal with nullptr values.
118
    CHECK_EQ(it->second, size);
119
  }
120
  allocations_.erase(it);
121
}
122
123
void DebuggingArrayBufferAllocator::RegisterPointerInternal(void* data,
124
                                                            size_t size) {
125
  if (data == nullptr) return;
126
  CHECK_EQ(allocations_.count(data), 0);
127
  allocations_[data] = size;
128
}
129
130
4654
std::unique_ptr<ArrayBufferAllocator> ArrayBufferAllocator::Create(bool debug) {
131

4654
  if (debug || per_process::cli_options->debug_arraybuffer_allocations)
132
    return std::make_unique<DebuggingArrayBufferAllocator>();
133
  else
134
4654
    return std::make_unique<NodeArrayBufferAllocator>();
135
}
136
137
ArrayBufferAllocator* CreateArrayBufferAllocator() {
138
  return ArrayBufferAllocator::Create().release();
139
}
140
141
void FreeArrayBufferAllocator(ArrayBufferAllocator* allocator) {
142
  delete allocator;
143
}
144
145
4654
void SetIsolateCreateParamsForNode(Isolate::CreateParams* params) {
146
4654
  const uint64_t total_memory = uv_get_total_memory();
147
4654
  if (total_memory > 0) {
148
    // V8 defaults to 700MB or 1.4GB on 32 and 64 bit platforms respectively.
149
    // This default is based on browser use-cases. Tell V8 to configure the
150
    // heap based on the actual physical memory.
151
4654
    params->constraints.ConfigureDefaults(total_memory, 0);
152
  }
153
154
#ifdef NODE_ENABLE_VTUNE_PROFILING
155
  params->code_event_handler = vTune::GetVtuneCodeEventHandler();
156
#endif
157
4654
}
158
159
9308
void SetIsolateUpForNode(v8::Isolate* isolate, IsolateSettingCategories cat) {
160
9308
  switch (cat) {
161
    case IsolateSettingCategories::kErrorHandlers:
162
      isolate->AddMessageListenerWithErrorLevel(
163
          errors::PerIsolateMessageListener,
164
          Isolate::MessageErrorLevel::kMessageError |
165
4654
              Isolate::MessageErrorLevel::kMessageWarning);
166
      isolate->SetAbortOnUncaughtExceptionCallback(
167
4654
          ShouldAbortOnUncaughtException);
168
4654
      isolate->SetFatalErrorHandler(OnFatalError);
169
4654
      break;
170
    case IsolateSettingCategories::kMisc:
171
4654
      isolate->SetMicrotasksPolicy(MicrotasksPolicy::kExplicit);
172
      isolate->SetAllowWasmCodeGenerationCallback(
173
4654
          AllowWasmCodeGenerationCallback);
174
4654
      isolate->SetPromiseRejectCallback(task_queue::PromiseRejectCallback);
175
4654
      v8::CpuProfiler::UseDetailedSourcePositionsForProfiling(isolate);
176
4654
      break;
177
    default:
178
      UNREACHABLE();
179
      break;
180
  }
181
9308
}
182
183
185
void SetIsolateUpForNode(v8::Isolate* isolate) {
184
185
  SetIsolateUpForNode(isolate, IsolateSettingCategories::kErrorHandlers);
185
185
  SetIsolateUpForNode(isolate, IsolateSettingCategories::kMisc);
186
185
}
187
188
185
Isolate* NewIsolate(ArrayBufferAllocator* allocator, uv_loop_t* event_loop) {
189
185
  return NewIsolate(allocator, event_loop, GetMainThreadMultiIsolatePlatform());
190
}
191
192
// TODO(joyeecheung): we may want to expose this, but then we need to be
193
// careful about what we override in the params.
194
185
Isolate* NewIsolate(Isolate::CreateParams* params,
195
                    uv_loop_t* event_loop,
196
                    MultiIsolatePlatform* platform) {
197
185
  Isolate* isolate = Isolate::Allocate();
198
185
  if (isolate == nullptr) return nullptr;
199
200
  // Register the isolate on the platform before the isolate gets initialized,
201
  // so that the isolate can access the platform during initialization.
202
185
  platform->RegisterIsolate(isolate, event_loop);
203
204
185
  SetIsolateCreateParamsForNode(params);
205
185
  Isolate::Initialize(isolate, *params);
206
185
  SetIsolateUpForNode(isolate);
207
208
185
  return isolate;
209
}
210
211
185
Isolate* NewIsolate(ArrayBufferAllocator* allocator,
212
                    uv_loop_t* event_loop,
213
                    MultiIsolatePlatform* platform) {
214
185
  Isolate::CreateParams params;
215
185
  if (allocator != nullptr) params.array_buffer_allocator = allocator;
216
185
  return NewIsolate(&params, event_loop, platform);
217
}
218
219
185
IsolateData* CreateIsolateData(Isolate* isolate,
220
                               uv_loop_t* loop,
221
                               MultiIsolatePlatform* platform,
222
                               ArrayBufferAllocator* allocator) {
223
185
  return new IsolateData(isolate, loop, platform, allocator);
224
}
225
226
185
void FreeIsolateData(IsolateData* isolate_data) {
227
185
  delete isolate_data;
228
185
}
229
230
Environment* CreateEnvironment(IsolateData* isolate_data,
231
                               Local<Context> context,
232
                               int argc,
233
                               const char* const* argv,
234
                               int exec_argc,
235
                               const char* const* exec_argv) {
236
  Isolate* isolate = context->GetIsolate();
237
  HandleScope handle_scope(isolate);
238
  Context::Scope context_scope(context);
239
  // TODO(addaleax): This is a much better place for parsing per-Environment
240
  // options than the global parse call.
241
  std::vector<std::string> args(argv, argv + argc);
242
  std::vector<std::string> exec_args(exec_argv, exec_argv + exec_argc);
243
  // TODO(addaleax): Provide more sensible flags, in an embedder-accessible way.
244
  Environment* env = new Environment(
245
      isolate_data,
246
      context,
247
      static_cast<Environment::Flags>(Environment::kIsMainThread |
248
                                      Environment::kOwnsProcessState |
249
                                      Environment::kOwnsInspector));
250
  env->InitializeLibuv(per_process::v8_is_profiling);
251
  env->ProcessCliArgs(args, exec_args);
252
  if (RunBootstrapping(env).IsEmpty()) {
253
    return nullptr;
254
  }
255
256
  std::vector<Local<String>> parameters = {
257
      env->require_string(),
258
      FIXED_ONE_BYTE_STRING(env->isolate(), "markBootstrapComplete")};
259
  std::vector<Local<Value>> arguments = {
260
      env->native_module_require(),
261
      env->NewFunctionTemplate(MarkBootstrapComplete)
262
          ->GetFunction(env->context())
263
          .ToLocalChecked()};
264
  if (ExecuteBootstrapper(
265
          env, "internal/bootstrap/environment", &parameters, &arguments)
266
          .IsEmpty()) {
267
    return nullptr;
268
  }
269
  return env;
270
}
271
272
182
void FreeEnvironment(Environment* env) {
273
182
  env->RunCleanup();
274
182
  delete env;
275
182
}
276
277
Environment* GetCurrentEnvironment(Local<Context> context) {
278
  return Environment::GetCurrent(context);
279
}
280
281
185
MultiIsolatePlatform* GetMainThreadMultiIsolatePlatform() {
282
185
  return per_process::v8_platform.Platform();
283
}
284
285
MultiIsolatePlatform* CreatePlatform(
286
    int thread_pool_size,
287
    node::tracing::TracingController* tracing_controller) {
288
  return new NodePlatform(thread_pool_size, tracing_controller);
289
}
290
291
4469
MultiIsolatePlatform* InitializeV8Platform(int thread_pool_size) {
292
4469
  per_process::v8_platform.Initialize(thread_pool_size);
293
4469
  return per_process::v8_platform.Platform();
294
}
295
296
void FreePlatform(MultiIsolatePlatform* platform) {
297
  delete platform;
298
}
299
300
9828
MaybeLocal<Object> GetPerContextExports(Local<Context> context) {
301
9828
  Isolate* isolate = context->GetIsolate();
302
9828
  EscapableHandleScope handle_scope(isolate);
303
304
9828
  Local<Object> global = context->Global();
305
  Local<Private> key = Private::ForApi(isolate,
306
9828
      FIXED_ONE_BYTE_STRING(isolate, "node:per_context_binding_exports"));
307
308
  Local<Value> existing_value;
309
19656
  if (!global->GetPrivate(context, key).ToLocal(&existing_value))
310
    return MaybeLocal<Object>();
311
9828
  if (existing_value->IsObject())
312
4663
    return handle_scope.Escape(existing_value.As<Object>());
313
314
5165
  Local<Object> exports = Object::New(isolate);
315
15495
  if (context->Global()->SetPrivate(context, key, exports).IsNothing())
316
    return MaybeLocal<Object>();
317
5165
  return handle_scope.Escape(exports);
318
}
319
320
5165
Local<Context> NewContext(Isolate* isolate,
321
                          Local<ObjectTemplate> object_template) {
322
10330
  auto context = Context::New(isolate, nullptr, object_template);
323
5165
  if (context.IsEmpty()) return context;
324
5165
  HandleScope handle_scope(isolate);
325
326
  context->SetEmbedderData(ContextEmbedderIndex::kAllowWasmCodeGeneration,
327
5165
                           True(isolate));
328
329
  {
330
    // Run per-context JS files.
331
    Context::Scope context_scope(context);
332
    Local<Object> exports;
333
334
    Local<String> primordials_string =
335
5165
        FIXED_ONE_BYTE_STRING(isolate, "primordials");
336
5165
    Local<String> global_string = FIXED_ONE_BYTE_STRING(isolate, "global");
337
5165
    Local<String> exports_string = FIXED_ONE_BYTE_STRING(isolate, "exports");
338
339
    // Create primordials first and make it available to per-context scripts.
340
5165
    Local<Object> primordials = Object::New(isolate);
341


36155
    if (!primordials->SetPrototype(context, Null(isolate)).FromJust() ||
342

36155
        !GetPerContextExports(context).ToLocal(&exports) ||
343

25825
        !exports->Set(context, primordials_string, primordials).FromJust()) {
344
      return Local<Context>();
345
    }
346
347
    static const char* context_files[] = {"internal/per_context/primordials",
348
                                          "internal/per_context/setup",
349
                                          "internal/per_context/domexception",
350
                                          nullptr};
351
352
20416
    for (const char** module = context_files; *module != nullptr; module++) {
353
      std::vector<Local<String>> parameters = {
354
15333
          global_string, exports_string, primordials_string};
355
76665
      Local<Value> arguments[] = {context->Global(), exports, primordials};
356
      MaybeLocal<Function> maybe_fn =
357
          native_module::NativeModuleEnv::LookupAndCompile(
358
15333
              context, *module, &parameters, nullptr);
359
15333
      if (maybe_fn.IsEmpty()) {
360
        return Local<Context>();
361
      }
362
15333
      Local<Function> fn = maybe_fn.ToLocalChecked();
363
      MaybeLocal<Value> result =
364
          fn->Call(context, Undefined(isolate),
365
30666
                   arraysize(arguments), arguments);
366
      // Execution failed during context creation.
367
      // TODO(joyeecheung): deprecate this signature and return a MaybeLocal.
368
15333
      if (result.IsEmpty()) {
369
82
        return Local<Context>();
370
      }
371
20334
    }
372
  }
373
374
5083
  return context;
375
}
376
377
8
uv_loop_t* GetCurrentEventLoop(Isolate* isolate) {
378
8
  HandleScope handle_scope(isolate);
379
8
  Local<Context> context = isolate->GetCurrentContext();
380
8
  if (context.IsEmpty()) return nullptr;
381
8
  Environment* env = Environment::GetCurrent(context);
382
8
  if (env == nullptr) return nullptr;
383
8
  return env->event_loop();
384
}
385
386
}  // namespace node