Skip to content

Commit 95ac576

Browse files
committed
Revert "Move MakeCallback to JS"
This reverts commit 0109a9f. Also included: Port all the changes to process._makeCallback into the C++ version. Immediate nextTick, etc. This yields a slight boost in several benchmarks. V8 is optimizing and deoptimizing process._makeCallback repeatedly.
1 parent 401cef7 commit 95ac576

File tree

4 files changed

+51
-77
lines changed

4 files changed

+51
-77
lines changed

src/node.cc

Lines changed: 51 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,7 @@ Persistent<String> process_symbol;
100100
Persistent<String> domain_symbol;
101101

102102
static Persistent<Object> process;
103+
static Persistent<Function> process_tickCallback;
103104

104105
static Persistent<String> exports_symbol;
105106

@@ -114,7 +115,9 @@ static Persistent<String> heap_used_symbol;
114115

115116
static Persistent<String> fatal_exception_symbol;
116117

117-
static Persistent<Function> process_makeCallback;
118+
static Persistent<String> enter_symbol;
119+
static Persistent<String> exit_symbol;
120+
static Persistent<String> disposed_symbol;
118121

119122

120123
static bool print_eval = false;
@@ -926,11 +929,6 @@ MakeCallback(const Handle<Object> object,
926929
Handle<Value> argv[]) {
927930
HandleScope scope;
928931

929-
if (argc > 6) {
930-
fprintf(stderr, "node::MakeCallback - Too many args (%d)\n", argc);
931-
abort();
932-
}
933-
934932
Local<Value> callback_v = object->Get(symbol);
935933
if (!callback_v->IsFunction()) {
936934
String::Utf8Value method(symbol);
@@ -945,27 +943,60 @@ MakeCallback(const Handle<Object> object,
945943

946944
TryCatch try_catch;
947945

948-
if (process_makeCallback.IsEmpty()) {
949-
Local<Value> cb_v = process->Get(String::New("_makeCallback"));
950-
if (!cb_v->IsFunction()) {
951-
fprintf(stderr, "process._makeCallback assigned to non-function\n");
952-
abort();
946+
if (enter_symbol.IsEmpty()) {
947+
enter_symbol = NODE_PSYMBOL("enter");
948+
exit_symbol = NODE_PSYMBOL("exit");
949+
disposed_symbol = NODE_PSYMBOL("_disposed");
950+
}
951+
952+
Local<Value> domain_v = object->Get(domain_symbol);
953+
Local<Object> domain;
954+
Local<Function> enter;
955+
Local<Function> exit;
956+
if (!domain_v->IsUndefined()) {
957+
domain = domain_v->ToObject();
958+
if (domain->Get(disposed_symbol)->BooleanValue()) {
959+
// domain has been disposed of.
960+
return Undefined(node_isolate);
953961
}
954-
Local<Function> cb = cb_v.As<Function>();
955-
process_makeCallback = Persistent<Function>::New(cb);
962+
enter = Local<Function>::Cast(domain->Get(enter_symbol));
963+
enter->Call(domain, 0, NULL);
956964
}
957965

958-
Local<Array> argArray = Array::New(argc);
959-
for (int i = 0; i < argc; i++) {
960-
argArray->Set(Integer::New(i, node_isolate), argv[i]);
966+
if (try_catch.HasCaught()) {
967+
FatalException(try_catch);
968+
return Undefined(node_isolate);
961969
}
962970

963-
Local<Value> object_l = Local<Value>::New(node_isolate, object);
964-
Local<Value> symbol_l = Local<Value>::New(node_isolate, symbol);
971+
Local<Function> callback = Local<Function>::Cast(callback_v);
972+
Local<Value> ret = callback->Call(object, argc, argv);
965973

966-
Local<Value> args[3] = { object_l, symbol_l, argArray };
974+
if (try_catch.HasCaught()) {
975+
FatalException(try_catch);
976+
return Undefined(node_isolate);
977+
}
967978

968-
Local<Value> ret = process_makeCallback->Call(process, ARRAY_SIZE(args), args);
979+
if (!domain_v->IsUndefined()) {
980+
exit = Local<Function>::Cast(domain->Get(exit_symbol));
981+
exit->Call(domain, 0, NULL);
982+
}
983+
984+
if (try_catch.HasCaught()) {
985+
FatalException(try_catch);
986+
return Undefined(node_isolate);
987+
}
988+
989+
// process nextTicks after every time we get called.
990+
if (process_tickCallback.IsEmpty()) {
991+
Local<Value> cb_v = process->Get(String::New("_tickCallback"));
992+
if (!cb_v->IsFunction()) {
993+
fprintf(stderr, "process._tickCallback assigned to non-function\n");
994+
abort();
995+
}
996+
Local<Function> cb = cb_v.As<Function>();
997+
process_tickCallback = Persistent<Function>::New(cb);
998+
}
999+
process_tickCallback->Call(process, NULL, 0);
9691000

9701001
if (try_catch.HasCaught()) {
9711002
FatalException(try_catch);

src/node.js

Lines changed: 0 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,6 @@
4848
startup.processAssert();
4949
startup.processConfig();
5050
startup.processNextTick();
51-
startup.processMakeCallback();
5251
startup.processStdio();
5352
startup.processKillAndExit();
5453
startup.processSignalHandlers();
@@ -297,57 +296,6 @@
297296
});
298297
};
299298

300-
startup.processMakeCallback = function() {
301-
// Along with EventEmitter.emit, this is the hottest code in node.
302-
// Everything that comes from C++ into JS passes through here.
303-
process._makeCallback = function(obj, fn, args) {
304-
var domain = obj.domain;
305-
if (domain) {
306-
if (domain._disposed) return;
307-
domain.enter();
308-
}
309-
310-
// I know what you're thinking, why not just use fn.apply
311-
// Because we hit this function a lot, and really want to make sure
312-
// that V8 can optimize it as well as possible.
313-
var ret;
314-
switch (args.length) {
315-
case 0:
316-
ret = obj[fn]();
317-
break;
318-
case 1:
319-
ret = obj[fn](args[0]);
320-
break;
321-
case 2:
322-
ret = obj[fn](args[0], args[1]);
323-
break;
324-
case 3:
325-
ret = obj[fn](args[0], args[1], args[2]);
326-
break;
327-
case 4:
328-
ret = obj[fn](args[0], args[1], args[2], args[3]);
329-
break;
330-
case 5:
331-
ret = obj[fn](args[0], args[1], args[2], args[3], args[4]);
332-
break;
333-
case 6:
334-
ret = obj[fn](args[0], args[1], args[2], args[3], args[4], args[5]);
335-
break;
336-
337-
default:
338-
// How did we even get here? This should abort() in C++ land!
339-
throw new Error('too many args to makeCallback');
340-
break;
341-
}
342-
343-
if (domain) domain.exit();
344-
345-
// process the nextTicks after each time we get called.
346-
process._tickCallback();
347-
return ret;
348-
};
349-
};
350-
351299
startup.processNextTick = function() {
352300
var nextTickQueue = [];
353301
var nextTickIndex = 0;

test/message/stdin_messages.out

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ SyntaxError: Strict mode code may not include a with statement
1111
at Socket.EventEmitter.emit (events.js:*:*)
1212
at _stream_readable.js:*:*
1313
at process._tickCallback (node.js:*:*)
14-
at process._makeCallback (node.js:*:*)
1514
42
1615
42
1716

@@ -27,7 +26,6 @@ Error: hello
2726
at Socket.EventEmitter.emit (events.js:*:*)
2827
at _stream_readable.js:*:*
2928
at process._tickCallback (node.js:*:*)
30-
at process._makeCallback (node.js:*:*)
3129

3230
[stdin]:1
3331
throw new Error("hello")
@@ -41,7 +39,6 @@ Error: hello
4139
at Socket.EventEmitter.emit (events.js:*:*)
4240
at _stream_readable.js:*:*
4341
at process._tickCallback (node.js:*:*)
44-
at process._makeCallback (node.js:*:*)
4542
100
4643

4744
[stdin]:1
@@ -56,7 +53,6 @@ ReferenceError: y is not defined
5653
at Socket.EventEmitter.emit (events.js:*:*)
5754
at _stream_readable.js:*:*
5855
at process._tickCallback (node.js:*:*)
59-
at process._makeCallback (node.js:*:*)
6056

6157
[stdin]:1
6258
var ______________________________________________; throw 10

test/message/timeout_throw.out

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,3 @@
44
ReferenceError: undefined_reference_error_maker is not defined
55
at null._onTimeout (*test*message*timeout_throw.js:*:*)
66
at Timer.listOnTimeout [as ontimeout] (timers.js:*:*)
7-
at process._makeCallback (node.js:*:*)

0 commit comments

Comments
 (0)