GCC Code Coverage Report | |||||||||||||||||||||
|
|||||||||||||||||||||
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 |
6301 |
Realm::Realm(Environment* env, |
|
24 |
v8::Local<v8::Context> context, |
||
25 |
6301 |
const RealmSerializeInfo* realm_info) |
|
26 |
6301 |
: env_(env), isolate_(context->GetIsolate()) { |
|
27 |
6301 |
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 |
✓✓ | 6301 |
if (realm_info == nullptr) { |
33 |
780 |
CreateProperties(); |
|
34 |
} |
||
35 |
6301 |
} |
|
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 |
780 |
void Realm::CreateProperties() { |
|
47 |
1560 |
HandleScope handle_scope(isolate_); |
|
48 |
780 |
Local<Context> ctx = context(); |
|
49 |
|||
50 |
// Store primordials setup by the per-context script in the environment. |
||
51 |
Local<Object> per_context_bindings = |
||
52 |
1560 |
GetPerContextExports(ctx).ToLocalChecked(); |
|
53 |
Local<Value> primordials = |
||
54 |
1560 |
per_context_bindings->Get(ctx, env_->primordials_string()) |
|
55 |
780 |
.ToLocalChecked(); |
|
56 |
✗✓ | 780 |
CHECK(primordials->IsObject()); |
57 |
780 |
set_primordials(primordials.As<Object>()); |
|
58 |
|||
59 |
Local<String> prototype_string = |
||
60 |
780 |
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 |
✗✓✗✓ |
4680 |
V(primordials_safe_map_prototype_object, "SafeMap"); |
77 |
✗✓✗✓ |
4680 |
V(primordials_safe_set_prototype_object, "SafeSet"); |
78 |
✗✓✗✓ |
4680 |
V(primordials_safe_weak_map_prototype_object, "SafeWeakMap"); |
79 |
✗✓✗✓ |
4680 |
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 |
780 |
node::CreateProcessObject(this).FromMaybe(Local<Object>()); |
|
87 |
780 |
set_process_object(process_object); |
|
88 |
780 |
} |
|
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 |
5521 |
void Realm::DeserializeProperties(const RealmSerializeInfo* info) { |
|
112 |
5521 |
Local<Context> ctx = context(); |
|
113 |
|||
114 |
5521 |
const std::vector<PropInfo>& values = info->persistent_values; |
|
115 |
5521 |
size_t i = 0; // index to the array |
|
116 |
5521 |
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 |
✓✗✓✗ ✓✗✗✓ ✓✗✓✗ ✓✗✗✓ ✓✗✗✓ ✗✓✗✗ ✓✗✓✗ ✓✗✗✓ ✓✗✓✗ ✓✗✗✓ ✓✗✓✗ ✓✗✗✓ ✓✗✓✗ ✓✗✗✓ ✓✗✓✗ ✓✗✗✓ ✓✗✗✓ ✗✓✗✗ ✓✗✓✗ ✓✗✗✓ ✓✗✓✗ ✓✗✗✓ ✓✗✓✗ ✓✗✗✓ ✓✗✓✗ ✓✗✗✓ ✓✗✗✓ ✗✓✗✗ ✓✗✓✗ ✓✗✗✓ ✓✗✓✗ ✓✗✗✓ ✓✗✓✗ ✓✗✗✓ ✓✗✗✓ ✗✓✗✗ ✓✗✗✓ ✗✓✗✗ ✓✗✗✓ ✗✓✗✗ ✓✗✗✓ ✗✓✗✗ ✓✗✗✓ ✗✓✗✗ ✓✗✗✓ ✗✓✗✗ ✓✗✗✓ ✗✓✗✗ ✓✗✗✓ ✗✓✗✗ ✓✗✗✓ ✗✓✗✗ ✓✗✗✓ ✗✓✗✗ ✓✗✗✓ ✗✓✗✗ ✓✗✗✓ ✗✓✗✗ ✓✗✗✓ ✗✓✗✗ ✓✗✗✓ ✗✓✗✗ ✓✗✓✗ ✓✗✗✓ ✓✗✓✗ ✓✗✗✓ ✓✗✓✗ ✓✗✗✓ ✓✗✗✓ ✗✓✗✗ ✓✗✗✓ ✗✓✗✗ ✓✗✗✓ ✗✓✗✗ ✓✗✓✗ ✓✗✗✓ ✓✗✗✓ ✗✓✗✗ ✓✗✓✗ ✓✗✗✓ ✓✗✓✗ ✓✗✗✓ ✓✗✓✗ ✓✗✗✓ ✓✗✓✗ ✓✗✗✓ ✓✗✓✗ ✓✗✗✓ ✓✗✓✗ ✓✗✗✓ ✓✗✓✗ ✓✗✗✓ ✓✗✓✗ ✓✗✗✓ ✓✗✓✗ ✓✗✗✓ ✓✗✓✗ ✓✗✗✓ ✓✗✗✓ ✗✓✗✗ ✓✗✓✗ ✓✗✗✓ ✓✗✗✓ ✗✓✗✗ ✓✗✗✓ ✗✓✗✗ ✓✗✗✓ ✗✓✗✗ ✓✗✗✓ ✗✓✗✗ ✓✗✓✗ ✓✗✗✓ ✓✗✓✗ ✓✗✗✓ ✓✗✗✓ ✗✓✗✗ ✓✗✓✗ ✓✗✗✓ ✓✗✗✓ ✗✓✗✗ ✓✗✓✗ ✓✗✗✓ ✗✓✗✗ ✗✓✗✗ ✗✓✗✗ ✗✓✗✗ |
552100 |
PER_REALM_STRONG_PERSISTENT_VALUES(V); |
136 |
#undef V |
||
137 |
|||
138 |
MaybeLocal<Context> maybe_ctx_from_snapshot = |
||
139 |
11042 |
ctx->GetDataFromSnapshotOnce<Context>(info->context); |
|
140 |
Local<Context> ctx_from_snapshot; |
||
141 |
✗✓ | 5521 |
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 |
✗✓ | 5521 |
CHECK_EQ(ctx_from_snapshot, ctx); |
146 |
|||
147 |
5521 |
DoneBootstrapping(); |
|
148 |
5521 |
} |
|
149 |
|||
150 |
10186 |
MaybeLocal<Value> Realm::ExecuteBootstrapper(const char* id) { |
|
151 |
10186 |
EscapableHandleScope scope(isolate()); |
|
152 |
10186 |
Local<Context> ctx = context(); |
|
153 |
10186 |
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 |
✓✓ | 9917 |
if (result.IsEmpty()) { |
162 |
31 |
env()->async_hooks()->clear_async_id_stack(); |
|
163 |
} |
||
164 |
|||
165 |
9917 |
return scope.EscapeMaybe(result); |
|
166 |
} |
||
167 |
|||
168 |
780 |
MaybeLocal<Value> Realm::BootstrapInternalLoaders() { |
|
169 |
780 |
EscapableHandleScope scope(isolate_); |
|
170 |
|||
171 |
// Bootstrap internal loaders |
||
172 |
Local<Value> loader_exports; |
||
173 |
780 |
if (!ExecuteBootstrapper("internal/bootstrap/loaders") |
|
174 |
✗✓ | 780 |
.ToLocal(&loader_exports)) { |
175 |
return MaybeLocal<Value>(); |
||
176 |
} |
||
177 |
✗✓ | 780 |
CHECK(loader_exports->IsObject()); |
178 |
1560 |
Local<Object> loader_exports_obj = loader_exports.As<Object>(); |
|
179 |
Local<Value> internal_binding_loader = |
||
180 |
1560 |
loader_exports_obj->Get(context(), env_->internal_binding_string()) |
|
181 |
780 |
.ToLocalChecked(); |
|
182 |
✗✓ | 780 |
CHECK(internal_binding_loader->IsFunction()); |
183 |
780 |
set_internal_binding_loader(internal_binding_loader.As<Function>()); |
|
184 |
Local<Value> require = |
||
185 |
1560 |
loader_exports_obj->Get(context(), env_->require_string()) |
|
186 |
780 |
.ToLocalChecked(); |
|
187 |
✗✓ | 780 |
CHECK(require->IsFunction()); |
188 |
780 |
set_builtin_module_require(require.As<Function>()); |
|
189 |
|||
190 |
780 |
return scope.Escape(loader_exports); |
|
191 |
} |
||
192 |
|||
193 |
780 |
MaybeLocal<Value> Realm::BootstrapNode() { |
|
194 |
780 |
EscapableHandleScope scope(isolate_); |
|
195 |
|||
196 |
780 |
MaybeLocal<Value> result = ExecuteBootstrapper("internal/bootstrap/node"); |
|
197 |
|||
198 |
✗✓ | 780 |
if (result.IsEmpty()) { |
199 |
return MaybeLocal<Value>(); |
||
200 |
} |
||
201 |
|||
202 |
✓✗ | 780 |
if (!env_->no_browser_globals()) { |
203 |
780 |
result = ExecuteBootstrapper("internal/bootstrap/browser"); |
|
204 |
|||
205 |
✗✓ | 780 |
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 |
✓✓ | 780 |
env_->is_main_thread() ? "internal/bootstrap/switches/is_main_thread" |
213 |
780 |
: "internal/bootstrap/switches/is_not_main_thread"; |
|
214 |
780 |
result = ExecuteBootstrapper(thread_switch_id); |
|
215 |
|||
216 |
✗✓ | 780 |
if (result.IsEmpty()) { |
217 |
return MaybeLocal<Value>(); |
||
218 |
} |
||
219 |
|||
220 |
auto process_state_switch_id = |
||
221 |
780 |
env_->owns_process_state() |
|
222 |
✓✓ | 780 |
? "internal/bootstrap/switches/does_own_process_state" |
223 |
780 |
: "internal/bootstrap/switches/does_not_own_process_state"; |
|
224 |
780 |
result = ExecuteBootstrapper(process_state_switch_id); |
|
225 |
|||
226 |
✗✓ | 780 |
if (result.IsEmpty()) { |
227 |
return MaybeLocal<Value>(); |
||
228 |
} |
||
229 |
|||
230 |
780 |
Local<String> env_string = FIXED_ONE_BYTE_STRING(isolate_, "env"); |
|
231 |
Local<Object> env_var_proxy; |
||
232 |
✓✗ | 2340 |
if (!CreateEnvVarProxy(context(), isolate_).ToLocal(&env_var_proxy) || |
233 |
✗✓✗✓ |
3120 |
process_object()->Set(context(), env_string, env_var_proxy).IsNothing()) { |
234 |
return MaybeLocal<Value>(); |
||
235 |
} |
||
236 |
|||
237 |
780 |
return scope.EscapeMaybe(result); |
|
238 |
} |
||
239 |
|||
240 |
780 |
MaybeLocal<Value> Realm::RunBootstrapping() { |
|
241 |
780 |
EscapableHandleScope scope(isolate_); |
|
242 |
|||
243 |
✗✓ | 780 |
CHECK(!has_run_bootstrapping_code()); |
244 |
|||
245 |
✗✓ | 1560 |
if (BootstrapInternalLoaders().IsEmpty()) { |
246 |
return MaybeLocal<Value>(); |
||
247 |
} |
||
248 |
|||
249 |
Local<Value> result; |
||
250 |
✗✓ | 1560 |
if (!BootstrapNode().ToLocal(&result)) { |
251 |
return MaybeLocal<Value>(); |
||
252 |
} |
||
253 |
|||
254 |
780 |
DoneBootstrapping(); |
|
255 |
|||
256 |
780 |
return scope.Escape(result); |
|
257 |
} |
||
258 |
|||
259 |
6301 |
void Realm::DoneBootstrapping() { |
|
260 |
6301 |
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 |
✗✓ | 6301 |
CHECK(env_->req_wrap_queue()->IsEmpty()); |
270 |
✗✓ | 6301 |
CHECK(env_->handle_wrap_queue()->IsEmpty()); |
271 |
|||
272 |
// TODO(legendecas): track base object count by realms. |
||
273 |
6301 |
env_->set_base_object_created_by_bootstrap(env_->base_object_count()); |
|
274 |
6301 |
} |
|
275 |
|||
276 |
} // namespace node |
Generated by: GCOVR (Version 4.2) |