GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: node_realm.cc Lines: 108 118 91.5 %
Date: 2022-09-02 04:23:42 Branches: 320 696 46.0 %

Line Branch Exec Source
1
#include "node_realm.h"
2
#include "env-inl.h"
3
4
#include "memory_tracker-inl.h"
5
#include "node_builtins.h"
6
#include "node_process.h"
7
#include "util.h"
8
9
namespace node {
10
11
using builtins::BuiltinLoader;
12
using v8::Context;
13
using v8::EscapableHandleScope;
14
using v8::Function;
15
using v8::HandleScope;
16
using v8::Local;
17
using v8::MaybeLocal;
18
using v8::Object;
19
using v8::SnapshotCreator;
20
using v8::String;
21
using v8::Undefined;
22
using v8::Value;
23
24
6132
Realm::Realm(Environment* env,
25
             v8::Local<v8::Context> context,
26
6132
             const RealmSerializeInfo* realm_info)
27
6132
    : env_(env), isolate_(context->GetIsolate()) {
28
6132
  context_.Reset(isolate_, context);
29
30
  // Create properties if not deserializing from snapshot.
31
  // Or the properties are deserialized with DeserializeProperties() when the
32
  // env drained the deserialize requests.
33
6132
  if (realm_info == nullptr) {
34
774
    CreateProperties();
35
  }
36
6132
}
37
38
24
void Realm::MemoryInfo(MemoryTracker* tracker) const {
39
#define V(PropertyName, TypeName)                                              \
40
  tracker->TrackField(#PropertyName, PropertyName());
41
24
  PER_REALM_STRONG_PERSISTENT_VALUES(V)
42
#undef V
43
44
24
  tracker->TrackField("env", env_);
45
24
}
46
47
774
void Realm::CreateProperties() {
48
1548
  HandleScope handle_scope(isolate_);
49
774
  Local<Context> ctx = context();
50
51
  // Store primordials setup by the per-context script in the environment.
52
  Local<Object> per_context_bindings =
53
1548
      GetPerContextExports(ctx).ToLocalChecked();
54
  Local<Value> primordials =
55
1548
      per_context_bindings->Get(ctx, env_->primordials_string())
56
774
          .ToLocalChecked();
57
774
  CHECK(primordials->IsObject());
58
774
  set_primordials(primordials.As<Object>());
59
60
  Local<String> prototype_string =
61
774
      FIXED_ONE_BYTE_STRING(isolate(), "prototype");
62
63
#define V(EnvPropertyName, PrimordialsPropertyName)                            \
64
  {                                                                            \
65
    Local<Value> ctor =                                                        \
66
        primordials.As<Object>()                                               \
67
            ->Get(ctx,                                                         \
68
                  FIXED_ONE_BYTE_STRING(isolate(), PrimordialsPropertyName))   \
69
            .ToLocalChecked();                                                 \
70
    CHECK(ctor->IsObject());                                                   \
71
    Local<Value> prototype =                                                   \
72
        ctor.As<Object>()->Get(ctx, prototype_string).ToLocalChecked();        \
73
    CHECK(prototype->IsObject());                                              \
74
    set_##EnvPropertyName(prototype.As<Object>());                             \
75
  }
76
77

4644
  V(primordials_safe_map_prototype_object, "SafeMap");
78

4644
  V(primordials_safe_set_prototype_object, "SafeSet");
79

4644
  V(primordials_safe_weak_map_prototype_object, "SafeWeakMap");
80

4644
  V(primordials_safe_weak_set_prototype_object, "SafeWeakSet");
81
#undef V
82
83
  // TODO(legendecas): some methods probably doesn't need to be created with
84
  // process. Distinguish them and create process object only in the principal
85
  // realm.
86
  Local<Object> process_object =
87
774
      node::CreateProcessObject(this).FromMaybe(Local<Object>());
88
774
  set_process_object(process_object);
89
774
}
90
91
6
RealmSerializeInfo Realm::Serialize(SnapshotCreator* creator) {
92
6
  RealmSerializeInfo info;
93
6
  Local<Context> ctx = context();
94
95
6
  uint32_t id = 0;
96
#define V(PropertyName, TypeName)                                              \
97
  do {                                                                         \
98
    Local<TypeName> field = PropertyName();                                    \
99
    if (!field.IsEmpty()) {                                                    \
100
      size_t index = creator->AddData(ctx, field);                             \
101
      info.persistent_values.push_back({#PropertyName, id, index});            \
102
    }                                                                          \
103
    id++;                                                                      \
104
  } while (0);
105































582
  PER_REALM_STRONG_PERSISTENT_VALUES(V)
106
#undef V
107
108
6
  info.context = creator->AddData(ctx, ctx);
109
6
  return info;
110
}
111
112
5358
void Realm::DeserializeProperties(const RealmSerializeInfo* info) {
113
5358
  Local<Context> ctx = context();
114
115
5358
  const std::vector<PropInfo>& values = info->persistent_values;
116
5358
  size_t i = 0;  // index to the array
117
5358
  uint32_t id = 0;
118
#define V(PropertyName, TypeName)                                              \
119
  do {                                                                         \
120
    if (values.size() > i && id == values[i].id) {                             \
121
      const PropInfo& d = values[i];                                           \
122
      DCHECK_EQ(d.name, #PropertyName);                                        \
123
      MaybeLocal<TypeName> maybe_field =                                       \
124
          ctx->GetDataFromSnapshotOnce<TypeName>(d.index);                     \
125
      Local<TypeName> field;                                                   \
126
      if (!maybe_field.ToLocal(&field)) {                                      \
127
        fprintf(stderr,                                                        \
128
                "Failed to deserialize realm value " #PropertyName "\n");      \
129
      }                                                                        \
130
      set_##PropertyName(field);                                               \
131
      i++;                                                                     \
132
    }                                                                          \
133
    id++;                                                                      \
134
  } while (0);
135
136






























































































































535800
  PER_REALM_STRONG_PERSISTENT_VALUES(V);
137
#undef V
138
139
  MaybeLocal<Context> maybe_ctx_from_snapshot =
140
10716
      ctx->GetDataFromSnapshotOnce<Context>(info->context);
141
  Local<Context> ctx_from_snapshot;
142
5358
  if (!maybe_ctx_from_snapshot.ToLocal(&ctx_from_snapshot)) {
143
    fprintf(stderr,
144
            "Failed to deserialize context back reference from the snapshot\n");
145
  }
146
5358
  CHECK_EQ(ctx_from_snapshot, ctx);
147
148
5358
  DoneBootstrapping();
149
5358
}
150
151
9987
MaybeLocal<Value> Realm::ExecuteBootstrapper(
152
    const char* id, std::vector<Local<Value>>* arguments) {
153
9987
  EscapableHandleScope scope(isolate());
154
9987
  Local<Context> ctx = context();
155
  MaybeLocal<Function> maybe_fn =
156
9987
      BuiltinLoader::LookupAndCompile(ctx, id, env());
157
158
  Local<Function> fn;
159
9987
  if (!maybe_fn.ToLocal(&fn)) {
160
    return MaybeLocal<Value>();
161
  }
162
163
  MaybeLocal<Value> result =
164
19974
      fn->Call(ctx, Undefined(isolate()), arguments->size(), arguments->data());
165
166
  // If there was an error during bootstrap, it must be unrecoverable
167
  // (e.g. max call stack exceeded). Clear the stack so that the
168
  // AsyncCallbackScope destructor doesn't fail on the id check.
169
  // There are only two ways to have a stack size > 1: 1) the user manually
170
  // called MakeCallback or 2) user awaited during bootstrap, which triggered
171
  // _tickCallback().
172
9715
  if (result.IsEmpty()) {
173
31
    env()->async_hooks()->clear_async_id_stack();
174
  }
175
176
9715
  return scope.EscapeMaybe(result);
177
}
178
179
774
MaybeLocal<Value> Realm::BootstrapInternalLoaders() {
180
774
  EscapableHandleScope scope(isolate_);
181
182
  // Arguments must match the parameters specified in
183
  // BuiltinLoader::LookupAndCompile().
184
  std::vector<Local<Value>> loaders_args = {
185
      process_object(),
186
774
      NewFunctionTemplate(isolate_, binding::GetLinkedBinding)
187
774
          ->GetFunction(context())
188
          .ToLocalChecked(),
189
774
      NewFunctionTemplate(isolate_, binding::GetInternalBinding)
190
774
          ->GetFunction(context())
191
          .ToLocalChecked(),
192
5418
      primordials()};
193
194
  // Bootstrap internal loaders
195
  Local<Value> loader_exports;
196
774
  if (!ExecuteBootstrapper("internal/bootstrap/loaders", &loaders_args)
197
774
           .ToLocal(&loader_exports)) {
198
    return MaybeLocal<Value>();
199
  }
200
774
  CHECK(loader_exports->IsObject());
201
774
  Local<Object> loader_exports_obj = loader_exports.As<Object>();
202
  Local<Value> internal_binding_loader =
203
1548
      loader_exports_obj->Get(context(), env_->internal_binding_string())
204
774
          .ToLocalChecked();
205
774
  CHECK(internal_binding_loader->IsFunction());
206
774
  set_internal_binding_loader(internal_binding_loader.As<Function>());
207
  Local<Value> require =
208
1548
      loader_exports_obj->Get(context(), env_->require_string())
209
774
          .ToLocalChecked();
210
774
  CHECK(require->IsFunction());
211
774
  set_builtin_module_require(require.As<Function>());
212
213
774
  return scope.Escape(loader_exports);
214
}
215
216
774
MaybeLocal<Value> Realm::BootstrapNode() {
217
774
  EscapableHandleScope scope(isolate_);
218
219
  // Arguments must match the parameters specified in
220
  // BuiltinLoader::LookupAndCompile().
221
  // process, require, internalBinding, primordials
222
  std::vector<Local<Value>> node_args = {process_object(),
223
                                         builtin_module_require(),
224
                                         internal_binding_loader(),
225
4644
                                         primordials()};
226
227
  MaybeLocal<Value> result =
228
774
      ExecuteBootstrapper("internal/bootstrap/node", &node_args);
229
230
774
  if (result.IsEmpty()) {
231
    return MaybeLocal<Value>();
232
  }
233
234
774
  if (!env_->no_browser_globals()) {
235
774
    result = ExecuteBootstrapper("internal/bootstrap/browser", &node_args);
236
237
774
    if (result.IsEmpty()) {
238
      return MaybeLocal<Value>();
239
    }
240
  }
241
242
  // TODO(joyeecheung): skip these in the snapshot building for workers.
243
  auto thread_switch_id =
244
774
      env_->is_main_thread() ? "internal/bootstrap/switches/is_main_thread"
245
774
                             : "internal/bootstrap/switches/is_not_main_thread";
246
774
  result = ExecuteBootstrapper(thread_switch_id, &node_args);
247
248
774
  if (result.IsEmpty()) {
249
    return MaybeLocal<Value>();
250
  }
251
252
  auto process_state_switch_id =
253
774
      env_->owns_process_state()
254
774
          ? "internal/bootstrap/switches/does_own_process_state"
255
774
          : "internal/bootstrap/switches/does_not_own_process_state";
256
774
  result = ExecuteBootstrapper(process_state_switch_id, &node_args);
257
258
774
  if (result.IsEmpty()) {
259
    return MaybeLocal<Value>();
260
  }
261
262
774
  Local<String> env_string = FIXED_ONE_BYTE_STRING(isolate_, "env");
263
  Local<Object> env_var_proxy;
264
2322
  if (!CreateEnvVarProxy(context(), isolate_).ToLocal(&env_var_proxy) ||
265

3096
      process_object()->Set(context(), env_string, env_var_proxy).IsNothing()) {
266
    return MaybeLocal<Value>();
267
  }
268
269
774
  return scope.EscapeMaybe(result);
270
}
271
272
774
MaybeLocal<Value> Realm::RunBootstrapping() {
273
774
  EscapableHandleScope scope(isolate_);
274
275
774
  CHECK(!has_run_bootstrapping_code());
276
277
1548
  if (BootstrapInternalLoaders().IsEmpty()) {
278
    return MaybeLocal<Value>();
279
  }
280
281
  Local<Value> result;
282
1548
  if (!BootstrapNode().ToLocal(&result)) {
283
    return MaybeLocal<Value>();
284
  }
285
286
774
  DoneBootstrapping();
287
288
774
  return scope.Escape(result);
289
}
290
291
6132
void Realm::DoneBootstrapping() {
292
6132
  has_run_bootstrapping_code_ = true;
293
294
  // Make sure that no request or handle is created during bootstrap -
295
  // if necessary those should be done in pre-execution.
296
  // Usually, doing so would trigger the checks present in the ReqWrap and
297
  // HandleWrap classes, so this is only a consistency check.
298
299
  // TODO(legendecas): track req_wrap and handle_wrap by realms instead of
300
  // environments.
301
6132
  CHECK(env_->req_wrap_queue()->IsEmpty());
302
6132
  CHECK(env_->handle_wrap_queue()->IsEmpty());
303
304
  // TODO(legendecas): track base object count by realms.
305
6132
  env_->set_base_object_created_by_bootstrap(env_->base_object_count());
306
6132
}
307
308
}  // namespace node