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