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::Undefined; |
||
22 |
using v8::Value; |
||
23 |
|||
24 |
6246 |
Realm::Realm(Environment* env, |
|
25 |
v8::Local<v8::Context> context, |
||
26 |
6246 |
const RealmSerializeInfo* realm_info) |
|
27 |
6246 |
: env_(env), isolate_(context->GetIsolate()) { |
|
28 |
6246 |
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 |
✓✓ | 6246 |
if (realm_info == nullptr) { |
34 |
780 |
CreateProperties(); |
|
35 |
} |
||
36 |
6246 |
} |
|
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 |
780 |
void Realm::CreateProperties() { |
|
48 |
1560 |
HandleScope handle_scope(isolate_); |
|
49 |
780 |
Local<Context> ctx = context(); |
|
50 |
|||
51 |
// Store primordials setup by the per-context script in the environment. |
||
52 |
Local<Object> per_context_bindings = |
||
53 |
1560 |
GetPerContextExports(ctx).ToLocalChecked(); |
|
54 |
Local<Value> primordials = |
||
55 |
1560 |
per_context_bindings->Get(ctx, env_->primordials_string()) |
|
56 |
780 |
.ToLocalChecked(); |
|
57 |
✗✓ | 780 |
CHECK(primordials->IsObject()); |
58 |
780 |
set_primordials(primordials.As<Object>()); |
|
59 |
|||
60 |
Local<String> prototype_string = |
||
61 |
780 |
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 |
✗✓✗✓ |
4680 |
V(primordials_safe_map_prototype_object, "SafeMap"); |
78 |
✗✓✗✓ |
4680 |
V(primordials_safe_set_prototype_object, "SafeSet"); |
79 |
✗✓✗✓ |
4680 |
V(primordials_safe_weak_map_prototype_object, "SafeWeakMap"); |
80 |
✗✓✗✓ |
4680 |
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 |
780 |
node::CreateProcessObject(this).FromMaybe(Local<Object>()); |
|
88 |
780 |
set_process_object(process_object); |
|
89 |
780 |
} |
|
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 |
5466 |
void Realm::DeserializeProperties(const RealmSerializeInfo* info) { |
|
113 |
5466 |
Local<Context> ctx = context(); |
|
114 |
|||
115 |
5466 |
const std::vector<PropInfo>& values = info->persistent_values; |
|
116 |
5466 |
size_t i = 0; // index to the array |
|
117 |
5466 |
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 |
✓✗✓✗ ✓✗✗✓ ✓✗✓✗ ✓✗✗✓ ✓✗✗✓ ✗✓✗✗ ✓✗✓✗ ✓✗✗✓ ✓✗✓✗ ✓✗✗✓ ✓✗✓✗ ✓✗✗✓ ✓✗✓✗ ✓✗✗✓ ✓✗✓✗ ✓✗✗✓ ✓✗✗✓ ✗✓✗✗ ✓✗✓✗ ✓✗✗✓ ✓✗✓✗ ✓✗✗✓ ✓✗✓✗ ✓✗✗✓ ✓✗✓✗ ✓✗✗✓ ✓✗✗✓ ✗✓✗✗ ✓✗✓✗ ✓✗✗✓ ✓✗✓✗ ✓✗✗✓ ✓✗✓✗ ✓✗✗✓ ✓✗✗✓ ✗✓✗✗ ✓✗✗✓ ✗✓✗✗ ✓✗✗✓ ✗✓✗✗ ✓✗✗✓ ✗✓✗✗ ✓✗✗✓ ✗✓✗✗ ✓✗✗✓ ✗✓✗✗ ✓✗✗✓ ✗✓✗✗ ✓✗✗✓ ✗✓✗✗ ✓✗✗✓ ✗✓✗✗ ✓✗✗✓ ✗✓✗✗ ✓✗✗✓ ✗✓✗✗ ✓✗✗✓ ✗✓✗✗ ✓✗✗✓ ✗✓✗✗ ✓✗✗✓ ✗✓✗✗ ✓✗✓✗ ✓✗✗✓ ✓✗✓✗ ✓✗✗✓ ✓✗✓✗ ✓✗✗✓ ✓✗✗✓ ✗✓✗✗ ✓✗✗✓ ✗✓✗✗ ✓✗✗✓ ✗✓✗✗ ✓✗✓✗ ✓✗✗✓ ✓✗✗✓ ✗✓✗✗ ✓✗✓✗ ✓✗✗✓ ✓✗✓✗ ✓✗✗✓ ✓✗✓✗ ✓✗✗✓ ✓✗✓✗ ✓✗✗✓ ✓✗✓✗ ✓✗✗✓ ✓✗✓✗ ✓✗✗✓ ✓✗✓✗ ✓✗✗✓ ✓✗✓✗ ✓✗✗✓ ✓✗✓✗ ✓✗✗✓ ✓✗✓✗ ✓✗✗✓ ✓✗✗✓ ✗✓✗✗ ✓✗✓✗ ✓✗✗✓ ✓✗✗✓ ✗✓✗✗ ✓✗✗✓ ✗✓✗✗ ✓✗✗✓ ✗✓✗✗ ✓✗✗✓ ✗✓✗✗ ✓✗✓✗ ✓✗✗✓ ✓✗✓✗ ✓✗✗✓ ✓✗✗✓ ✗✓✗✗ ✓✗✓✗ ✓✗✗✓ ✓✗✗✓ ✗✓✗✗ ✓✗✓✗ ✓✗✗✓ ✗✓✗✗ ✗✓✗✗ ✗✓✗✗ ✗✓✗✗ |
546600 |
PER_REALM_STRONG_PERSISTENT_VALUES(V); |
137 |
#undef V |
||
138 |
|||
139 |
MaybeLocal<Context> maybe_ctx_from_snapshot = |
||
140 |
10932 |
ctx->GetDataFromSnapshotOnce<Context>(info->context); |
|
141 |
Local<Context> ctx_from_snapshot; |
||
142 |
✗✓ | 5466 |
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 |
✗✓ | 5466 |
CHECK_EQ(ctx_from_snapshot, ctx); |
147 |
|||
148 |
5466 |
DoneBootstrapping(); |
|
149 |
5466 |
} |
|
150 |
|||
151 |
10131 |
MaybeLocal<Value> Realm::ExecuteBootstrapper( |
|
152 |
const char* id, std::vector<Local<Value>>* arguments) { |
||
153 |
10131 |
EscapableHandleScope scope(isolate()); |
|
154 |
10131 |
Local<Context> ctx = context(); |
|
155 |
MaybeLocal<Function> maybe_fn = |
||
156 |
10131 |
BuiltinLoader::LookupAndCompile(ctx, id, env()); |
|
157 |
|||
158 |
Local<Function> fn; |
||
159 |
✗✓ | 10131 |
if (!maybe_fn.ToLocal(&fn)) { |
160 |
return MaybeLocal<Value>(); |
||
161 |
} |
||
162 |
|||
163 |
MaybeLocal<Value> result = |
||
164 |
20262 |
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 |
✓✓ | 9865 |
if (result.IsEmpty()) { |
173 |
31 |
env()->async_hooks()->clear_async_id_stack(); |
|
174 |
} |
||
175 |
|||
176 |
9865 |
return scope.EscapeMaybe(result); |
|
177 |
} |
||
178 |
|||
179 |
780 |
MaybeLocal<Value> Realm::BootstrapInternalLoaders() { |
|
180 |
780 |
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 |
780 |
NewFunctionTemplate(isolate_, binding::GetLinkedBinding) |
|
187 |
780 |
->GetFunction(context()) |
|
188 |
.ToLocalChecked(), |
||
189 |
780 |
NewFunctionTemplate(isolate_, binding::GetInternalBinding) |
|
190 |
780 |
->GetFunction(context()) |
|
191 |
.ToLocalChecked(), |
||
192 |
5460 |
primordials()}; |
|
193 |
|||
194 |
// Bootstrap internal loaders |
||
195 |
Local<Value> loader_exports; |
||
196 |
780 |
if (!ExecuteBootstrapper("internal/bootstrap/loaders", &loaders_args) |
|
197 |
✗✓ | 780 |
.ToLocal(&loader_exports)) { |
198 |
return MaybeLocal<Value>(); |
||
199 |
} |
||
200 |
✗✓ | 780 |
CHECK(loader_exports->IsObject()); |
201 |
780 |
Local<Object> loader_exports_obj = loader_exports.As<Object>(); |
|
202 |
Local<Value> internal_binding_loader = |
||
203 |
1560 |
loader_exports_obj->Get(context(), env_->internal_binding_string()) |
|
204 |
780 |
.ToLocalChecked(); |
|
205 |
✗✓ | 780 |
CHECK(internal_binding_loader->IsFunction()); |
206 |
780 |
set_internal_binding_loader(internal_binding_loader.As<Function>()); |
|
207 |
Local<Value> require = |
||
208 |
1560 |
loader_exports_obj->Get(context(), env_->require_string()) |
|
209 |
780 |
.ToLocalChecked(); |
|
210 |
✗✓ | 780 |
CHECK(require->IsFunction()); |
211 |
780 |
set_builtin_module_require(require.As<Function>()); |
|
212 |
|||
213 |
780 |
return scope.Escape(loader_exports); |
|
214 |
} |
||
215 |
|||
216 |
780 |
MaybeLocal<Value> Realm::BootstrapNode() { |
|
217 |
780 |
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 |
4680 |
primordials()}; |
|
226 |
|||
227 |
MaybeLocal<Value> result = |
||
228 |
780 |
ExecuteBootstrapper("internal/bootstrap/node", &node_args); |
|
229 |
|||
230 |
✗✓ | 780 |
if (result.IsEmpty()) { |
231 |
return MaybeLocal<Value>(); |
||
232 |
} |
||
233 |
|||
234 |
✓✗ | 780 |
if (!env_->no_browser_globals()) { |
235 |
780 |
result = ExecuteBootstrapper("internal/bootstrap/browser", &node_args); |
|
236 |
|||
237 |
✗✓ | 780 |
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 |
✓✓ | 780 |
env_->is_main_thread() ? "internal/bootstrap/switches/is_main_thread" |
245 |
780 |
: "internal/bootstrap/switches/is_not_main_thread"; |
|
246 |
780 |
result = ExecuteBootstrapper(thread_switch_id, &node_args); |
|
247 |
|||
248 |
✗✓ | 780 |
if (result.IsEmpty()) { |
249 |
return MaybeLocal<Value>(); |
||
250 |
} |
||
251 |
|||
252 |
auto process_state_switch_id = |
||
253 |
780 |
env_->owns_process_state() |
|
254 |
✓✓ | 780 |
? "internal/bootstrap/switches/does_own_process_state" |
255 |
780 |
: "internal/bootstrap/switches/does_not_own_process_state"; |
|
256 |
780 |
result = ExecuteBootstrapper(process_state_switch_id, &node_args); |
|
257 |
|||
258 |
✗✓ | 780 |
if (result.IsEmpty()) { |
259 |
return MaybeLocal<Value>(); |
||
260 |
} |
||
261 |
|||
262 |
780 |
Local<String> env_string = FIXED_ONE_BYTE_STRING(isolate_, "env"); |
|
263 |
Local<Object> env_var_proxy; |
||
264 |
✓✗ | 2340 |
if (!CreateEnvVarProxy(context(), isolate_).ToLocal(&env_var_proxy) || |
265 |
✗✓✗✓ |
3120 |
process_object()->Set(context(), env_string, env_var_proxy).IsNothing()) { |
266 |
return MaybeLocal<Value>(); |
||
267 |
} |
||
268 |
|||
269 |
780 |
return scope.EscapeMaybe(result); |
|
270 |
} |
||
271 |
|||
272 |
780 |
MaybeLocal<Value> Realm::RunBootstrapping() { |
|
273 |
780 |
EscapableHandleScope scope(isolate_); |
|
274 |
|||
275 |
✗✓ | 780 |
CHECK(!has_run_bootstrapping_code()); |
276 |
|||
277 |
✗✓ | 1560 |
if (BootstrapInternalLoaders().IsEmpty()) { |
278 |
return MaybeLocal<Value>(); |
||
279 |
} |
||
280 |
|||
281 |
Local<Value> result; |
||
282 |
✗✓ | 1560 |
if (!BootstrapNode().ToLocal(&result)) { |
283 |
return MaybeLocal<Value>(); |
||
284 |
} |
||
285 |
|||
286 |
780 |
DoneBootstrapping(); |
|
287 |
|||
288 |
780 |
return scope.Escape(result); |
|
289 |
} |
||
290 |
|||
291 |
6246 |
void Realm::DoneBootstrapping() { |
|
292 |
6246 |
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 |
✗✓ | 6246 |
CHECK(env_->req_wrap_queue()->IsEmpty()); |
302 |
✗✓ | 6246 |
CHECK(env_->handle_wrap_queue()->IsEmpty()); |
303 |
|||
304 |
// TODO(legendecas): track base object count by realms. |
||
305 |
6246 |
env_->set_base_object_created_by_bootstrap(env_->base_object_count()); |
|
306 |
6246 |
} |
|
307 |
|||
308 |
} // namespace node |
Generated by: GCOVR (Version 4.2) |