Browse Source

Revert "Move MakeCallback to JS"

This reverts commit 0109a9f90a.

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.
v0.9.10-release
isaacs 12 years ago
parent
commit
95ac576bf9
  1. 71
      src/node.cc
  2. 52
      src/node.js
  3. 4
      test/message/stdin_messages.out
  4. 1
      test/message/timeout_throw.out

71
src/node.cc

@ -100,6 +100,7 @@ Persistent<String> process_symbol;
Persistent<String> domain_symbol; Persistent<String> domain_symbol;
static Persistent<Object> process; static Persistent<Object> process;
static Persistent<Function> process_tickCallback;
static Persistent<String> exports_symbol; static Persistent<String> exports_symbol;
@ -114,7 +115,9 @@ static Persistent<String> heap_used_symbol;
static Persistent<String> fatal_exception_symbol; static Persistent<String> fatal_exception_symbol;
static Persistent<Function> process_makeCallback; static Persistent<String> enter_symbol;
static Persistent<String> exit_symbol;
static Persistent<String> disposed_symbol;
static bool print_eval = false; static bool print_eval = false;
@ -926,11 +929,6 @@ MakeCallback(const Handle<Object> object,
Handle<Value> argv[]) { Handle<Value> argv[]) {
HandleScope scope; HandleScope scope;
if (argc > 6) {
fprintf(stderr, "node::MakeCallback - Too many args (%d)\n", argc);
abort();
}
Local<Value> callback_v = object->Get(symbol); Local<Value> callback_v = object->Get(symbol);
if (!callback_v->IsFunction()) { if (!callback_v->IsFunction()) {
String::Utf8Value method(symbol); String::Utf8Value method(symbol);
@ -945,27 +943,60 @@ MakeCallback(const Handle<Object> object,
TryCatch try_catch; TryCatch try_catch;
if (process_makeCallback.IsEmpty()) { if (enter_symbol.IsEmpty()) {
Local<Value> cb_v = process->Get(String::New("_makeCallback")); enter_symbol = NODE_PSYMBOL("enter");
if (!cb_v->IsFunction()) { exit_symbol = NODE_PSYMBOL("exit");
fprintf(stderr, "process._makeCallback assigned to non-function\n"); disposed_symbol = NODE_PSYMBOL("_disposed");
abort(); }
Local<Value> domain_v = object->Get(domain_symbol);
Local<Object> domain;
Local<Function> enter;
Local<Function> exit;
if (!domain_v->IsUndefined()) {
domain = domain_v->ToObject();
if (domain->Get(disposed_symbol)->BooleanValue()) {
// domain has been disposed of.
return Undefined(node_isolate);
} }
Local<Function> cb = cb_v.As<Function>(); enter = Local<Function>::Cast(domain->Get(enter_symbol));
process_makeCallback = Persistent<Function>::New(cb); enter->Call(domain, 0, NULL);
} }
Local<Array> argArray = Array::New(argc); if (try_catch.HasCaught()) {
for (int i = 0; i < argc; i++) { FatalException(try_catch);
argArray->Set(Integer::New(i, node_isolate), argv[i]); return Undefined(node_isolate);
} }
Local<Value> object_l = Local<Value>::New(node_isolate, object); Local<Function> callback = Local<Function>::Cast(callback_v);
Local<Value> symbol_l = Local<Value>::New(node_isolate, symbol); Local<Value> ret = callback->Call(object, argc, argv);
Local<Value> args[3] = { object_l, symbol_l, argArray }; if (try_catch.HasCaught()) {
FatalException(try_catch);
return Undefined(node_isolate);
}
Local<Value> ret = process_makeCallback->Call(process, ARRAY_SIZE(args), args); if (!domain_v->IsUndefined()) {
exit = Local<Function>::Cast(domain->Get(exit_symbol));
exit->Call(domain, 0, NULL);
}
if (try_catch.HasCaught()) {
FatalException(try_catch);
return Undefined(node_isolate);
}
// process nextTicks after every time we get called.
if (process_tickCallback.IsEmpty()) {
Local<Value> cb_v = process->Get(String::New("_tickCallback"));
if (!cb_v->IsFunction()) {
fprintf(stderr, "process._tickCallback assigned to non-function\n");
abort();
}
Local<Function> cb = cb_v.As<Function>();
process_tickCallback = Persistent<Function>::New(cb);
}
process_tickCallback->Call(process, NULL, 0);
if (try_catch.HasCaught()) { if (try_catch.HasCaught()) {
FatalException(try_catch); FatalException(try_catch);

52
src/node.js

@ -48,7 +48,6 @@
startup.processAssert(); startup.processAssert();
startup.processConfig(); startup.processConfig();
startup.processNextTick(); startup.processNextTick();
startup.processMakeCallback();
startup.processStdio(); startup.processStdio();
startup.processKillAndExit(); startup.processKillAndExit();
startup.processSignalHandlers(); startup.processSignalHandlers();
@ -297,57 +296,6 @@
}); });
}; };
startup.processMakeCallback = function() {
// Along with EventEmitter.emit, this is the hottest code in node.
// Everything that comes from C++ into JS passes through here.
process._makeCallback = function(obj, fn, args) {
var domain = obj.domain;
if (domain) {
if (domain._disposed) return;
domain.enter();
}
// I know what you're thinking, why not just use fn.apply
// Because we hit this function a lot, and really want to make sure
// that V8 can optimize it as well as possible.
var ret;
switch (args.length) {
case 0:
ret = obj[fn]();
break;
case 1:
ret = obj[fn](args[0]);
break;
case 2:
ret = obj[fn](args[0], args[1]);
break;
case 3:
ret = obj[fn](args[0], args[1], args[2]);
break;
case 4:
ret = obj[fn](args[0], args[1], args[2], args[3]);
break;
case 5:
ret = obj[fn](args[0], args[1], args[2], args[3], args[4]);
break;
case 6:
ret = obj[fn](args[0], args[1], args[2], args[3], args[4], args[5]);
break;
default:
// How did we even get here? This should abort() in C++ land!
throw new Error('too many args to makeCallback');
break;
}
if (domain) domain.exit();
// process the nextTicks after each time we get called.
process._tickCallback();
return ret;
};
};
startup.processNextTick = function() { startup.processNextTick = function() {
var nextTickQueue = []; var nextTickQueue = [];
var nextTickIndex = 0; var nextTickIndex = 0;

4
test/message/stdin_messages.out

@ -11,7 +11,6 @@ SyntaxError: Strict mode code may not include a with statement
at Socket.EventEmitter.emit (events.js:*:*) at Socket.EventEmitter.emit (events.js:*:*)
at _stream_readable.js:*:* at _stream_readable.js:*:*
at process._tickCallback (node.js:*:*) at process._tickCallback (node.js:*:*)
at process._makeCallback (node.js:*:*)
42 42
42 42
@ -27,7 +26,6 @@ Error: hello
at Socket.EventEmitter.emit (events.js:*:*) at Socket.EventEmitter.emit (events.js:*:*)
at _stream_readable.js:*:* at _stream_readable.js:*:*
at process._tickCallback (node.js:*:*) at process._tickCallback (node.js:*:*)
at process._makeCallback (node.js:*:*)
[stdin]:1 [stdin]:1
throw new Error("hello") throw new Error("hello")
@ -41,7 +39,6 @@ Error: hello
at Socket.EventEmitter.emit (events.js:*:*) at Socket.EventEmitter.emit (events.js:*:*)
at _stream_readable.js:*:* at _stream_readable.js:*:*
at process._tickCallback (node.js:*:*) at process._tickCallback (node.js:*:*)
at process._makeCallback (node.js:*:*)
100 100
[stdin]:1 [stdin]:1
@ -56,7 +53,6 @@ ReferenceError: y is not defined
at Socket.EventEmitter.emit (events.js:*:*) at Socket.EventEmitter.emit (events.js:*:*)
at _stream_readable.js:*:* at _stream_readable.js:*:*
at process._tickCallback (node.js:*:*) at process._tickCallback (node.js:*:*)
at process._makeCallback (node.js:*:*)
[stdin]:1 [stdin]:1
var ______________________________________________; throw 10 var ______________________________________________; throw 10

1
test/message/timeout_throw.out

@ -4,4 +4,3 @@
ReferenceError: undefined_reference_error_maker is not defined ReferenceError: undefined_reference_error_maker is not defined
at null._onTimeout (*test*message*timeout_throw.js:*:*) at null._onTimeout (*test*message*timeout_throw.js:*:*)
at Timer.listOnTimeout [as ontimeout] (timers.js:*:*) at Timer.listOnTimeout [as ontimeout] (timers.js:*:*)
at process._makeCallback (node.js:*:*)

Loading…
Cancel
Save