@@ -105,8 +105,17 @@ inline AliasedFloat64Array& AsyncHooks::async_ids_stack() {
105
105
return async_ids_stack_;
106
106
}
107
107
108
- inline v8::Local<v8::Array> AsyncHooks::execution_async_resources () {
109
- return PersistentToLocal::Strong (execution_async_resources_);
108
+ v8::Local<v8::Array> AsyncHooks::js_execution_async_resources () {
109
+ if (UNLIKELY (js_execution_async_resources_.IsEmpty ())) {
110
+ js_execution_async_resources_.Reset (
111
+ env ()->isolate (), v8::Array::New (env ()->isolate ()));
112
+ }
113
+ return PersistentToLocal::Strong (js_execution_async_resources_);
114
+ }
115
+
116
+ v8::Local<v8::Object> AsyncHooks::native_execution_async_resource (size_t i) {
117
+ if (i >= native_execution_async_resources_.size ()) return {};
118
+ return PersistentToLocal::Strong (native_execution_async_resources_[i]);
110
119
}
111
120
112
121
inline v8::Local<v8::String> AsyncHooks::provider_string (int idx) {
@@ -124,9 +133,7 @@ inline Environment* AsyncHooks::env() {
124
133
// Remember to keep this code aligned with pushAsyncContext() in JS.
125
134
inline void AsyncHooks::push_async_context (double async_id,
126
135
double trigger_async_id,
127
- v8::Local<v8::Value> resource) {
128
- v8::HandleScope handle_scope (env ()->isolate ());
129
-
136
+ v8::Local<v8::Object> resource) {
130
137
// Since async_hooks is experimental, do only perform the check
131
138
// when async_hooks is enabled.
132
139
if (fields_[kCheck ] > 0 ) {
@@ -143,8 +150,19 @@ inline void AsyncHooks::push_async_context(double async_id,
143
150
async_id_fields_[kExecutionAsyncId ] = async_id;
144
151
async_id_fields_[kTriggerAsyncId ] = trigger_async_id;
145
152
146
- auto resources = execution_async_resources ();
147
- USE (resources->Set (env ()->context (), offset, resource));
153
+ #ifdef DEBUG
154
+ for (uint32_t i = offset; i < native_execution_async_resources_.size (); i++)
155
+ CHECK (native_execution_async_resources_[i].IsEmpty ());
156
+ #endif
157
+
158
+ // When this call comes from JS (as a way of increasing the stack size),
159
+ // `resource` will be empty, because JS caches these values anyway, and
160
+ // we should avoid creating strong global references that might keep
161
+ // these JS resource objects alive longer than necessary.
162
+ if (!resource.IsEmpty ()) {
163
+ native_execution_async_resources_.resize (offset + 1 );
164
+ native_execution_async_resources_[offset].Reset (env ()->isolate (), resource);
165
+ }
148
166
}
149
167
150
168
// Remember to keep this code aligned with popAsyncContext() in JS.
@@ -177,17 +195,45 @@ inline bool AsyncHooks::pop_async_context(double async_id) {
177
195
async_id_fields_[kTriggerAsyncId ] = async_ids_stack_[2 * offset + 1 ];
178
196
fields_[kStackLength ] = offset;
179
197
180
- auto resources = execution_async_resources ();
181
- USE (resources->Delete (env ()->context (), offset));
198
+ if (LIKELY (offset < native_execution_async_resources_.size () &&
199
+ !native_execution_async_resources_[offset].IsEmpty ())) {
200
+ #ifdef DEBUG
201
+ for (uint32_t i = offset + 1 ;
202
+ i < native_execution_async_resources_.size ();
203
+ i++) {
204
+ CHECK (native_execution_async_resources_[i].IsEmpty ());
205
+ }
206
+ #endif
207
+ native_execution_async_resources_.resize (offset);
208
+ if (native_execution_async_resources_.size () <
209
+ native_execution_async_resources_.capacity () / 2 &&
210
+ native_execution_async_resources_.size () > 16 ) {
211
+ native_execution_async_resources_.shrink_to_fit ();
212
+ }
213
+ }
214
+
215
+ if (UNLIKELY (js_execution_async_resources ()->Length () > offset)) {
216
+ v8::HandleScope handle_scope (env ()->isolate ());
217
+ USE (js_execution_async_resources ()->Set (
218
+ env ()->context (),
219
+ env ()->length_string (),
220
+ v8::Integer::NewFromUnsigned (env ()->isolate (), offset)));
221
+ }
182
222
183
223
return fields_[kStackLength ] > 0 ;
184
224
}
185
225
186
- // Keep in sync with clearAsyncIdStack in lib/internal/async_hooks.js.
187
- inline void AsyncHooks::clear_async_id_stack () {
188
- auto isolate = env ()->isolate ();
226
+ void AsyncHooks::clear_async_id_stack () {
227
+ v8::Isolate* isolate = env ()->isolate ();
189
228
v8::HandleScope handle_scope (isolate);
190
- execution_async_resources_.Reset (isolate, v8::Array::New (isolate));
229
+ if (!js_execution_async_resources_.IsEmpty ()) {
230
+ USE (PersistentToLocal::Strong (js_execution_async_resources_)->Set (
231
+ env ()->context (),
232
+ env ()->length_string (),
233
+ v8::Integer::NewFromUnsigned (isolate, 0 )));
234
+ }
235
+ native_execution_async_resources_.clear ();
236
+ native_execution_async_resources_.shrink_to_fit ();
191
237
192
238
async_id_fields_[kExecutionAsyncId ] = 0 ;
193
239
async_id_fields_[kTriggerAsyncId ] = 0 ;
0 commit comments