Skip to content

Commit 6086ed7

Browse files
trevnorrisMike Kaufman
authored andcommitted
adding support to test nextTick() by reading int values from a javascript array, as opposed to returning a new v8::Integer each time
1 parent 7f2d1b3 commit 6086ed7

7 files changed

Lines changed: 156 additions & 24 deletions

File tree

lib/internal/async_wrap.js

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
'use strict';
2+
3+
const async_wrap = process.binding('async_wrap');
4+
5+
const nextIdArray = async_wrap.getNextAsyncId2();
6+
const currentIdArray = async_wrap.getCurrentAsyncId2();
7+
8+
function getLittleEndian(a) {
9+
if (a[0] === 0xffffffff) {
10+
a[0] = 0;
11+
a[1]++;
12+
}
13+
return a[0] + a[1] * 0x100000000;
14+
}
15+
16+
function getBigEndian(a) {
17+
if (a[1] === 0xffffffff) {
18+
a[1] = 0;
19+
a[0]++;
20+
}
21+
return a[1] + a[0] * 0x100000000;
22+
}
23+
24+
function getCurrentIdLittleEndian() {
25+
return getLittleEndian(currentIdArray);
26+
}
27+
28+
function getCurrentIdBigEndian() {
29+
return getBigEndian(currentIdArray);
30+
}
31+
32+
function getNextIdLittleEndian() {
33+
return getLittleEndian(nextIdArray);
34+
}
35+
36+
function getNextIdBigEndian() {
37+
return getBigEndian(nextIdArray);
38+
}
39+
40+
module.exports.getCurrentAsyncWrapId = async_wrap.getCurrentAsyncId;
41+
module.exports.getNextAsyncWrapId = async_wrap.getNextAsyncId;
42+
43+
module.exports.getCurrentAsyncWrapId2 =
44+
process.binding('os').isBigEndian ? getCurrentIdBigEndian : getCurrentIdLittleEndian;
45+
46+
module.exports.getNextAsyncWrapId2 =
47+
process.binding('os').isBigEndian ? getNextIdBigEndian : getNextIdLittleEndian;

lib/internal/process/next_tick.js

Lines changed: 35 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ exports.setup = setupNextTick;
55
function setupNextTick() {
66

77
var asyncWrap = process.binding('async_wrap');
8+
const async_wrap = require('internal/async_wrap');
9+
810
const promises = require('internal/process/promises');
911
const emitPendingUnhandledRejections = promises.setup(scheduleMicrotasks);
1012
var nextTickQueue = [];
@@ -18,6 +20,7 @@ function setupNextTick() {
1820
var kLength = 1;
1921

2022
process.nextTick = nextTick;
23+
process.nextTickTemp = nextTickTemp;
2124
// Needs to be accessible from beyond this scope.
2225
process._tickCallback = _tickCallback;
2326
process._tickDomainCallback = _tickDomainCallback;
@@ -152,14 +155,26 @@ function setupNextTick() {
152155
this.callback = c;
153156
this.domain = process.domain || null;
154157
this.args = args;
155-
this.parentAsyncId = asyncWrap.getCurrentAsyncId();
156-
this.asyncId = asyncWrap.getNextAsyncId();
158+
this.parentAsyncId = async_wrap.getCurrentAsyncWrapId();
159+
this.asyncId = async_wrap.getNextAsyncWrapId();
157160
this.asyncState = {};
158161
this.ranInitCallback = asyncWrap.notifyAsyncEnqueue(
159162
this.asyncId, this.asyncState, undefined, undefined,
160163
asyncWrap.Providers.NEXTTICK);
161164
}
162165

166+
function TickObjectTemp(c, args) {
167+
this.callback = c;
168+
this.domain = process.domain || null;
169+
this.args = args;
170+
this.parentAsyncId = async_wrap.getCurrentAsyncWrapId2();
171+
this.asyncId = async_wrap.getNextAsyncWrapId2();
172+
this.asyncState = {};
173+
this.ranInitCallback = asyncWrap.notifyAsyncEnqueue(
174+
this.asyncId, this.asyncState, undefined, undefined,
175+
asyncWrap.Providers.NEXTTICK);
176+
}
177+
163178
function nextTick(callback) {
164179
if (typeof callback !== 'function')
165180
throw new TypeError('callback is not a function');
@@ -177,4 +192,22 @@ function setupNextTick() {
177192
nextTickQueue.push(new TickObject(callback, args));
178193
tickInfo[kLength]++;
179194
}
195+
196+
function nextTickTemp(callback) {
197+
if (typeof callback !== 'function')
198+
throw new TypeError('callback is not a function');
199+
// on the way out, don't bother. it won't get fired anyway.
200+
if (process._exiting)
201+
return;
202+
203+
var args;
204+
if (arguments.length > 1) {
205+
args = new Array(arguments.length - 1);
206+
for (var i = 1; i < arguments.length; i++)
207+
args[i - 1] = arguments[i];
208+
}
209+
210+
nextTickQueue.push(new TickObjectTemp(callback, args));
211+
tickInfo[kLength]++;
212+
}
180213
}

node.gyp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@
7070
'lib/v8.js',
7171
'lib/vm.js',
7272
'lib/zlib.js',
73+
'lib/internal/async_wrap.js',
7374
'lib/internal/child_process.js',
7475
'lib/internal/cluster.js',
7576
'lib/internal/freelist.js',

src/async-wrap-inl.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ inline AsyncWrap::AsyncWrap(Environment* env,
1818
ProviderType provider,
1919
AsyncWrap* parent)
2020
: BaseObject(env, object), bits_(static_cast<uint32_t>(provider) << 1),
21-
uid_(env->get_next_async_wrap_uid()) {
21+
uid_(env->async_hooks()->get_next_async_wrap_uid()) {
2222
CHECK_NE(provider, PROVIDER_NONE);
2323
CHECK_GE(object->InternalFieldCount(), 1);
2424

src/async-wrap.cc

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -120,16 +120,26 @@ static void DisableHooksJS(const FunctionCallbackInfo<Value>& args) {
120120

121121
static void GetCurrentAsyncId(const FunctionCallbackInfo<Value>& args) {
122122
Environment* env = Environment::GetCurrent(args);
123-
v8::Local<v8::Value> uid = v8::Integer::New(env->isolate(), env->get_current_async_wrap_uid());
123+
v8::Local<v8::Value> uid = v8::Integer::New(env->isolate(), env->async_hooks()->get_current_async_wrap_uid());
124124
args.GetReturnValue().Set(uid);
125125
}
126126

127127
static void GetNextAsyncId(const FunctionCallbackInfo<Value>& args) {
128128
Environment* env = Environment::GetCurrent(args);
129-
v8::Local<v8::Integer> uid = v8::Integer::New(env->isolate(), env->get_next_async_wrap_uid());
129+
v8::Local<v8::Integer> uid = v8::Integer::New(env->isolate(), env->async_hooks()->get_next_async_wrap_uid());
130130
args.GetReturnValue().Set(uid);
131131
}
132132

133+
static void GetCurrentAsyncId2(const FunctionCallbackInfo<Value>& args) {
134+
Environment* env = Environment::GetCurrent(args);
135+
args.GetReturnValue().Set(env->async_hooks()->get_current_async_id_array());
136+
}
137+
138+
static void GetNextAsyncId2(const FunctionCallbackInfo<Value>& args) {
139+
Environment* env = Environment::GetCurrent(args);
140+
args.GetReturnValue().Set(env->async_hooks()->get_next_async_id_array());
141+
}
142+
133143
static bool FireAsyncInitCallbacksInternal(
134144
Environment* env,
135145
int64_t uid,
@@ -243,7 +253,7 @@ void AsyncWrap::FireAsyncPreCallbacks(
243253
v8::Local<v8::Number> uid,
244254
v8::Local<v8::Object> obj)
245255
{
246-
env->set_current_async_wrap_uid(uid->IntegerValue());
256+
env->async_hooks()->set_current_async_wrap_uid(uid->IntegerValue());
247257

248258
if (ranInitCallbacks) {
249259
Local<Function> pre_fn = env->async_hooks_pre_function();
@@ -283,7 +293,7 @@ void AsyncWrap::FireAsyncPostCallbacks(Environment* env, bool ranInitCallback, v
283293
}
284294
}
285295

286-
env->set_current_async_wrap_uid(0);
296+
env->async_hooks()->set_current_async_wrap_uid(0);
287297
}
288298

289299
static void NotifyAsyncEndFromJS(const FunctionCallbackInfo<Value>& args) {
@@ -351,10 +361,9 @@ static void SetupHooks(const FunctionCallbackInfo<Value>& args) {
351361
env->set_async_hooks_destroy_function(destroy_v.As<Function>());
352362
}
353363

354-
355364
static void Initialize(Local<Object> target,
356-
Local<Value> unused,
357-
Local<Context> context) {
365+
Local<Value> unused,
366+
Local<Context> context) {
358367
Environment* env = Environment::GetCurrent(context);
359368
Isolate* isolate = env->isolate();
360369
HandleScope scope(isolate);
@@ -364,6 +373,8 @@ static void Initialize(Local<Object> target,
364373
env->SetMethod(target, "enable", EnableHooksJS);
365374
env->SetMethod(target, "getCurrentAsyncId", GetCurrentAsyncId);
366375
env->SetMethod(target, "getNextAsyncId", GetNextAsyncId);
376+
env->SetMethod(target, "getCurrentAsyncId2", GetCurrentAsyncId2);
377+
env->SetMethod(target, "getNextAsyncId2", GetNextAsyncId2);
367378
env->SetMethod(target, "notifyAsyncEnqueue", NotifyAsyncEnqueueFromJS);
368379
env->SetMethod(target, "notifyAsyncStart", NotifyAsyncStartFromJS);
369380
env->SetMethod(target, "notifyAsyncEnd", NotifyAsyncEndFromJS);

src/env-inl.h

Lines changed: 41 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -81,8 +81,34 @@ inline v8::Isolate* Environment::IsolateData::isolate() const {
8181
return isolate_;
8282
}
8383

84-
inline Environment::AsyncHooks::AsyncHooks() {
85-
for (int i = 0; i < kFieldsCount; i++) fields_[i] = 0;
84+
inline Environment::AsyncHooks::AsyncHooks(Environment* env)
85+
: async_wrap_current_uid_(0),
86+
async_wrap_counter_uid_(0),
87+
env_(env) {
88+
89+
for (int i = 0; i < kFieldsCount; i++) {
90+
fields_[i] = 0;
91+
}
92+
93+
v8::HandleScope handle_scope(env_->isolate());
94+
95+
// set up int array for returing async_wrap_counter_uid_ value
96+
const size_t array_length = sizeof(async_wrap_counter_uid_) / sizeof(int32_t);
97+
static_assert(array_length == 2, "async_wrap_counter_uid_ unexpected size");
98+
v8::Local<v8::ArrayBuffer> ab =
99+
v8::ArrayBuffer::New(this->env_->isolate(), &async_wrap_counter_uid_, array_length);
100+
v8::Local<v8::Uint32Array> ua =
101+
v8::Uint32Array::New(ab, 0, array_length);
102+
this->async_wrap_next_id_array_.Reset(this->env_->isolate(), ua);
103+
104+
// set up int array for returing async_wrap_current_uid_ value
105+
const size_t array_length2 = sizeof(async_wrap_current_uid_) / sizeof(int32_t);
106+
v8::Local<v8::ArrayBuffer> ab2 =
107+
v8::ArrayBuffer::New(this->env_->isolate(), &async_wrap_current_uid_, array_length);
108+
v8::Local<v8::Uint32Array> ua2 =
109+
v8::Uint32Array::New(ab2, 0, array_length);
110+
this->async_wrap_current_id_array_.Reset(this->env_->isolate(), ua2);
111+
86112
}
87113

88114
inline uint32_t* Environment::AsyncHooks::fields() {
@@ -216,13 +242,12 @@ inline Environment::Environment(v8::Local<v8::Context> context,
216242
uv_loop_t* loop)
217243
: isolate_(context->GetIsolate()),
218244
isolate_data_(IsolateData::GetOrCreate(context->GetIsolate(), loop)),
245+
async_hooks_(this),
219246
timer_base_(uv_now(loop)),
220247
using_domains_(false),
221248
printed_error_(false),
222249
trace_sync_io_(false),
223250
makecallback_cntr_(0),
224-
async_wrap_counter_uid_(0),
225-
async_wrap_current_uid_(0),
226251
debugger_agent_(this),
227252
http_parser_buffer_(nullptr),
228253
context_(context->GetIsolate(), context) {
@@ -373,15 +398,24 @@ inline void Environment::set_trace_sync_io(bool value) {
373398
trace_sync_io_ = value;
374399
}
375400

376-
inline int64_t Environment::get_next_async_wrap_uid() {
401+
inline int64_t Environment::AsyncHooks::get_next_async_wrap_uid() {
377402
return ++async_wrap_counter_uid_;
378403
}
379404

380-
inline int64_t Environment::get_current_async_wrap_uid() {
405+
inline int64_t Environment::AsyncHooks::get_current_async_wrap_uid() {
381406
return this->async_wrap_current_uid_;
382407
}
383408

384-
inline void Environment::set_current_async_wrap_uid(int64_t value) {
409+
inline v8::Local<v8::Uint32Array> Environment::AsyncHooks::get_current_async_id_array() {
410+
return async_wrap_current_id_array_.Get(this->env_->isolate());
411+
}
412+
413+
inline v8::Local<v8::Uint32Array> Environment::AsyncHooks::get_next_async_id_array() {
414+
return async_wrap_next_id_array_.Get(this->env_->isolate());
415+
}
416+
417+
418+
inline void Environment::AsyncHooks::set_current_async_wrap_uid(int64_t value) {
385419
this->async_wrap_current_uid_ = value;
386420
}
387421

src/env.h

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -300,10 +300,20 @@ class Environment {
300300
inline int fields_count() const;
301301
inline bool callbacks_enabled();
302302
inline void set_enable_callbacks(uint32_t flag);
303+
inline int64_t get_next_async_wrap_uid();
304+
inline int64_t get_current_async_wrap_uid();
305+
inline void set_current_async_wrap_uid(int64_t value);
306+
inline v8::Local<v8::Uint32Array> get_current_async_id_array();
307+
inline v8::Local<v8::Uint32Array> get_next_async_id_array();
303308

304309
private:
305310
friend class Environment; // So we can call the constructor.
306-
inline AsyncHooks();
311+
inline AsyncHooks(Environment* env);
312+
313+
int64_t async_wrap_counter_uid_;
314+
int64_t async_wrap_current_uid_;
315+
v8::Persistent<v8::Uint32Array> async_wrap_current_id_array_;
316+
v8::Persistent<v8::Uint32Array> async_wrap_next_id_array_;
307317

308318
enum Fields {
309319
// Set this to not zero if the init hook should be called.
@@ -312,6 +322,7 @@ class Environment {
312322
};
313323

314324
uint32_t fields_[kFieldsCount];
325+
Environment* env_;
315326

316327
DISALLOW_COPY_AND_ASSIGN(AsyncHooks);
317328
};
@@ -473,10 +484,6 @@ class Environment {
473484
void PrintSyncTrace() const;
474485
inline void set_trace_sync_io(bool value);
475486

476-
inline int64_t get_next_async_wrap_uid();
477-
inline int64_t get_current_async_wrap_uid();
478-
inline void set_current_async_wrap_uid(int64_t value);
479-
480487
inline uint32_t* heap_statistics_buffer() const;
481488
inline void set_heap_statistics_buffer(uint32_t* pointer);
482489

@@ -579,8 +586,7 @@ class Environment {
579586
bool printed_error_;
580587
bool trace_sync_io_;
581588
size_t makecallback_cntr_;
582-
int64_t async_wrap_counter_uid_;
583-
int64_t async_wrap_current_uid_;
589+
584590
debugger::Agent debugger_agent_;
585591

586592
HandleWrapQueue handle_wrap_queue_;

0 commit comments

Comments
 (0)