Skip to content

Commit

Permalink
tmp
Browse files Browse the repository at this point in the history
  • Loading branch information
vkurchatkin committed Jan 8, 2015
1 parent 6e9d1c8 commit 980fb8f
Show file tree
Hide file tree
Showing 9 changed files with 199 additions and 0 deletions.
1 change: 1 addition & 0 deletions src/env.h
Original file line number Diff line number Diff line change
Expand Up @@ -261,6 +261,7 @@ namespace node {
V(module_load_list_array, v8::Array) \
V(pipe_constructor_template, v8::FunctionTemplate) \
V(process_object, v8::Object) \
V(promise_reject_function, v8::Function) \
V(script_context_constructor_template, v8::FunctionTemplate) \
V(script_data_constructor_function, v8::Function) \
V(secure_context_constructor_template, v8::FunctionTemplate) \
Expand Down
39 changes: 39 additions & 0 deletions src/node.cc
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,8 @@ using v8::Message;
using v8::Number;
using v8::Object;
using v8::ObjectTemplate;
using v8::Promise;
using v8::PromiseRejectMessage;
using v8::PropertyCallbackInfo;
using v8::String;
using v8::TryCatch;
Expand Down Expand Up @@ -985,6 +987,42 @@ void SetupNextTick(const FunctionCallbackInfo<Value>& args) {
FIXED_ONE_BYTE_STRING(args.GetIsolate(), "_setupNextTick"));
}

void PromiseRejectCallback(PromiseRejectMessage message) {
Isolate* isolate = Isolate::GetCurrent();

CHECK(isolate);

Environment* env = Environment::GetCurrent(isolate);
Local<Function> callback = env->promise_reject_function();

Local<Promise> promise = message.GetPromise();
Local<Value> value = message.GetValue();
Local<Integer> event = Integer::New(isolate, message.GetEvent());

if (value.IsEmpty()) {
value = Undefined(isolate);
}

Local<Value> args[] = { event, promise, value };
Local<Object> process = env->process_object();


callback->Call(process, 3, args);
}

void SetupPromises(const FunctionCallbackInfo<Value>& args) {
Environment* env = Environment::GetCurrent(args);
Isolate* isolate = env->isolate();

CHECK(args[0]->IsFunction());

isolate->SetPromiseRejectCallback(PromiseRejectCallback);
env->set_promise_reject_function(args[0].As<Function>());

env->process_object()->Delete(
FIXED_ONE_BYTE_STRING(args.GetIsolate(), "_setupPromises"));
}


Handle<Value> MakeCallback(Environment* env,
Handle<Value> recv,
Expand Down Expand Up @@ -2755,6 +2793,7 @@ void SetupProcessObject(Environment* env,
env->SetMethod(process, "_linkedBinding", LinkedBinding);

env->SetMethod(process, "_setupNextTick", SetupNextTick);
env->SetMethod(process, "_setupPromises", SetupPromises);
env->SetMethod(process, "_setupDomainUse", SetupDomainUse);

// pre-set _events object for faster emit checks
Expand Down
46 changes: 46 additions & 0 deletions src/node.js
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@
startup.processAssert();
startup.processConfig();
startup.processNextTick();
startup.processPromises();
startup.processStdio();
startup.processKillAndExit();
startup.processSignalHandlers();
Expand Down Expand Up @@ -411,6 +412,51 @@
}
};

startup.processPromises = function() {
// this should be kept in sync with PromiseRejectEvent in v8.h
var kPromiseRejectWithNoHandler = 0;
var kPromiseHandlerAddedAfterReject = 1;

function promiseRejectCallback(event, promise, value) {

if (event === kPromiseRejectWithNoHandler)
promiseRejectWithNoHandlerCallback(promise, value);
else
promiseHandlerAddedAfterRejectCallback(promise);
}

function promiseRejectWithNoHandlerCallback(promise, value) {
var rejection = new PromiseRejection(promise, value);
process.emit('unhandledPromiseRejection', promise, rejection);

if (!rejection.isHandled()) {
process.nextTick(function() {
throw value;
});
}
}

function promiseHandlerAddedAfterRejectCallback(promise) {
process.emit('unhandledPromiseRejectionHandled', promise);
}

function PromiseRejection(promise, value) {
this.promise = promise;
this.value = value;
this._handled = false;
}

PromiseRejection.prototype.handle = function() {
this._handled = true;
};

PromiseRejection.prototype.isHandled = function() {
return this._handled;
};

process._setupPromises(promiseRejectCallback);
};

function evalScript(name) {
var Module = NativeModule.require('module');
var path = NativeModule.require('path');
Expand Down
3 changes: 3 additions & 0 deletions test/message/unhandled_rejection.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
var common = require('../common');

Promise.reject(new Error('error'));
12 changes: 12 additions & 0 deletions test/message/unhandled_rejection.out
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
node.js:*
throw value;
^
Error: error
at Object.<anonymous> (*test*message*unhandled_rejection.js:*)
at Module._compile (module.js:*)
at Object.Module._extensions..js (module.js:*)
at Module.load (module.js:*)
at Function.Module._load (module.js:*)
at Function.Module.runMain (module.js:*)
at startup (node.js:*)
at node.js:*
20 changes: 20 additions & 0 deletions test/parallel/test-unhandled-rejection1.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
var common = require('../common');
var assert = require('assert');

/**
* Unhandled rejections are thrown by default
* and should be available in `uncaughtException`.
*/

var caught = null;

process.once('uncaughtException', function(error) {
caught = error;
});

process.on('exit', function() {
assert(caught);
});

var error = new Error('error');
Promise.reject(error);
29 changes: 29 additions & 0 deletions test/parallel/test-unhandled-rejection2.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
var common = require('../common');
var assert = require('assert');

/**
* In `unhandledPromiseRejection` handler `rejection`
* object is available. If `rejection.handle()` is
* not called `rejection.value` is thrown.
*/

var caught = false;
var unhandledRejection = null;

process.once('uncaughtException', function() {
caught = true;
});

process.on('exit', function() {
assert(caught);
assert.equal(unhandledRejection.promise, promise);
assert.equal(unhandledRejection.value, error);
assert.equal(unhandledRejection.isHandled(), false);
});

process.on('unhandledPromiseRejection', function(promise, rejection) {
unhandledRejection = rejection;
});

var error = new Error('error');
var promise = Promise.reject(error);
22 changes: 22 additions & 0 deletions test/parallel/test-unhandled-rejection3.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
var common = require('../common');
var assert = require('assert');

/**
* If `rejection.handle()` is called rejection is not
* thrown.
*/

var unhandledRejection = null;

process.on('exit', function() {
assert.equal(unhandledRejection.promise, promise);
assert.equal(unhandledRejection.value, error);
});

process.on('unhandledPromiseRejection', function(promise, rejection) {
unhandledRejection = rejection;
rejection.handle();
});

var error = new Error('error');
var promise = Promise.reject(error);
27 changes: 27 additions & 0 deletions test/parallel/test-unhandled-rejection4.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
var common = require('../common');
var assert = require('assert');

/**
* `rejection.promise` should be last
* promise in chain, not original rejected
* promise.
*/

var unhandledRejection = null;

process.on('exit', function() {
assert.equal(unhandledRejection.promise, promise2);
assert.equal(unhandledRejection.value, error);
});

process.on('unhandledPromiseRejection', function(promise, rejection) {
unhandledRejection = rejection;
rejection.handle();
});

var error = new Error('error');
var promise = new Promise(function(resolve, reject) {
setImmediate(reject.bind(null, error));
});

var promise2 = promise.then(function() {});

0 comments on commit 980fb8f

Please sign in to comment.