GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: node_realm.cc Lines: 100 109 91.7 %
Date: 2022-09-25 04:23:55 Branches: 319 694 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::Value;
22
23
6307
Realm::Realm(Environment* env,
24
             v8::Local<v8::Context> context,
25
6307
             const RealmSerializeInfo* realm_info)
26
6307
    : env_(env), isolate_(context->GetIsolate()) {
27
6307
  context_.Reset(isolate_, context);
28
29
  // Create properties if not deserializing from snapshot.
30
  // Or the properties are deserialized with DeserializeProperties() when the
31
  // env drained the deserialize requests.
32
6307
  if (realm_info == nullptr) {
33
787
    CreateProperties();
34
  }
35
6307
}
36
37
25
void Realm::MemoryInfo(MemoryTracker* tracker) const {
38
#define V(PropertyName, TypeName)                                              \
39
  tracker->TrackField(#PropertyName, PropertyName());
40
25
  PER_REALM_STRONG_PERSISTENT_VALUES(V)
41
#undef V
42
43
25
  tracker->TrackField("env", env_);
44
25
}
45
46
787
void Realm::CreateProperties() {
47
1574
  HandleScope handle_scope(isolate_);
48
787
  Local<Context> ctx = context();
49
50
  // Store primordials setup by the per-context script in the environment.
51
  Local<Object> per_context_bindings =
52
1574
      GetPerContextExports(ctx).ToLocalChecked();
53
  Local<Value> primordials =
54
1574
      per_context_bindings->Get(ctx, env_->primordials_string())
55
787
          .ToLocalChecked();
56
787
  CHECK(primordials->IsObject());
57
787
  set_primordials(primordials.As<Object>());
58
59
  Local<String> prototype_string =
60
787
      FIXED_ONE_BYTE_STRING(isolate(), "prototype");
61
62
#define V(EnvPropertyName, PrimordialsPropertyName)                            \
63
  {                                                                            \
64
    Local<Value> ctor =                                                        \
65
        primordials.As<Object>()                                               \
66
            ->Get(ctx,                                                         \
67
                  FIXED_ONE_BYTE_STRING(isolate(), PrimordialsPropertyName))   \
68
            .ToLocalChecked();                                                 \
69
    CHECK(ctor->IsObject());                                                   \
70
    Local<Value> prototype =                                                   \
71
        ctor.As<Object>()->Get(ctx, prototype_string).ToLocalChecked();        \
72
    CHECK(prototype->IsObject());                                              \
73
    set_##EnvPropertyName(prototype.As<Object>());                             \
74
  }
75
76

4722
  V(primordials_safe_map_prototype_object, "SafeMap");
77

4722
  V(primordials_safe_set_prototype_object, "SafeSet");
78

4722
  V(primordials_safe_weak_map_prototype_object, "SafeWeakMap");
79

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































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






























































































































552000
  PER_REALM_STRONG_PERSISTENT_VALUES(V);
136
#undef V
137
138
  MaybeLocal<Context> maybe_ctx_from_snapshot =
139
11040
      ctx->GetDataFromSnapshotOnce<Context>(info->context);
140
  Local<Context> ctx_from_snapshot;
141
5520
  if (!maybe_ctx_from_snapshot.ToLocal(&ctx_from_snapshot)) {
142
    fprintf(stderr,
143
            "Failed to deserialize context back reference from the snapshot\n");
144
  }
145
5520
  CHECK_EQ(ctx_from_snapshot, ctx);
146
147
5520
  DoneBootstrapping();
148
5520
}
149
150
10223
MaybeLocal<Value> Realm::ExecuteBootstrapper(const char* id) {
151
10223
  EscapableHandleScope scope(isolate());
152
10223
  Local<Context> ctx = context();
153
10223
  MaybeLocal<Value> result = BuiltinLoader::CompileAndCall(ctx, id, this);
154
155
  // If there was an error during bootstrap, it must be unrecoverable
156
  // (e.g. max call stack exceeded). Clear the stack so that the
157
  // AsyncCallbackScope destructor doesn't fail on the id check.
158
  // There are only two ways to have a stack size > 1: 1) the user manually
159
  // called MakeCallback or 2) user awaited during bootstrap, which triggered
160
  // _tickCallback().
161
9954
  if (result.IsEmpty()) {
162
31
    env()->async_hooks()->clear_async_id_stack();
163
  }
164
165
9954
  return scope.EscapeMaybe(result);
166
}
167
168
787
MaybeLocal<Value> Realm::BootstrapInternalLoaders() {
169
787
  EscapableHandleScope scope(isolate_);
170
171
  // Bootstrap internal loaders
172
  Local<Value> loader_exports;
173
787
  if (!ExecuteBootstrapper("internal/bootstrap/loaders")
174
787
           .ToLocal(&loader_exports)) {
175
    return MaybeLocal<Value>();
176
  }
177
787
  CHECK(loader_exports->IsObject());
178
1574
  Local<Object> loader_exports_obj = loader_exports.As<Object>();
179
  Local<Value> internal_binding_loader =
180
1574
      loader_exports_obj->Get(context(), env_->internal_binding_string())
181
787
          .ToLocalChecked();
182
787
  CHECK(internal_binding_loader->IsFunction());
183
787
  set_internal_binding_loader(internal_binding_loader.As<Function>());
184
  Local<Value> require =
185
1574
      loader_exports_obj->Get(context(), env_->require_string())
186
787
          .ToLocalChecked();
187
787
  CHECK(require->IsFunction());
188
787
  set_builtin_module_require(require.As<Function>());
189
190
787
  return scope.Escape(loader_exports);
191
}
192
193
787
MaybeLocal<Value> Realm::BootstrapNode() {
194
787
  EscapableHandleScope scope(isolate_);
195
196
787
  MaybeLocal<Value> result = ExecuteBootstrapper("internal/bootstrap/node");
197
198
787
  if (result.IsEmpty()) {
199
    return MaybeLocal<Value>();
200
  }
201
202
787
  if (!env_->no_browser_globals()) {
203
787
    result = ExecuteBootstrapper("internal/bootstrap/browser");
204
205
787
    if (result.IsEmpty()) {
206
      return MaybeLocal<Value>();
207
    }
208
  }
209
210
  // TODO(joyeecheung): skip these in the snapshot building for workers.
211
  auto thread_switch_id =
212
787
      env_->is_main_thread() ? "internal/bootstrap/switches/is_main_thread"
213
787
                             : "internal/bootstrap/switches/is_not_main_thread";
214
787
  result = ExecuteBootstrapper(thread_switch_id);
215
216
787
  if (result.IsEmpty()) {
217
    return MaybeLocal<Value>();
218
  }
219
220
  auto process_state_switch_id =
221
787
      env_->owns_process_state()
222
787
          ? "internal/bootstrap/switches/does_own_process_state"
223
787
          : "internal/bootstrap/switches/does_not_own_process_state";
224
787
  result = ExecuteBootstrapper(process_state_switch_id);
225
226
787
  if (result.IsEmpty()) {
227
    return MaybeLocal<Value>();
228
  }
229
230
787
  Local<String> env_string = FIXED_ONE_BYTE_STRING(isolate_, "env");
231
  Local<Object> env_var_proxy;
232
2361
  if (!CreateEnvVarProxy(context(), isolate_).ToLocal(&env_var_proxy) ||
233

3148
      process_object()->Set(context(), env_string, env_var_proxy).IsNothing()) {
234
    return MaybeLocal<Value>();
235
  }
236
237
787
  return scope.EscapeMaybe(result);
238
}
239
240
787
MaybeLocal<Value> Realm::RunBootstrapping() {
241
787
  EscapableHandleScope scope(isolate_);
242
243
787
  CHECK(!has_run_bootstrapping_code());
244
245
1574
  if (BootstrapInternalLoaders().IsEmpty()) {
246
    return MaybeLocal<Value>();
247
  }
248
249
  Local<Value> result;
250
1574
  if (!BootstrapNode().ToLocal(&result)) {
251
    return MaybeLocal<Value>();
252
  }
253
254
787
  DoneBootstrapping();
255
256
787
  return scope.Escape(result);
257
}
258
259
6307
void Realm::DoneBootstrapping() {
260
6307
  has_run_bootstrapping_code_ = true;
261
262
  // Make sure that no request or handle is created during bootstrap -
263
  // if necessary those should be done in pre-execution.
264
  // Usually, doing so would trigger the checks present in the ReqWrap and
265
  // HandleWrap classes, so this is only a consistency check.
266
267
  // TODO(legendecas): track req_wrap and handle_wrap by realms instead of
268
  // environments.
269
6307
  CHECK(env_->req_wrap_queue()->IsEmpty());
270
6307
  CHECK(env_->handle_wrap_queue()->IsEmpty());
271
272
  // TODO(legendecas): track base object count by realms.
273
6307
  env_->set_base_object_created_by_bootstrap(env_->base_object_count());
274
6307
}
275
276
}  // namespace node