Uh oh!
There was an error while loading. Please reload this page.
- Notifications
You must be signed in to change notification settings - Fork 34.3k
domain: add arguments for the function in domain.run()#15
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Uh oh!
There was an error while loading. Please reload this page.
Conversation
lib/domain.js Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fyi this is unnecessary, just use arguments in the fn.apply()
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It looks correct to me. It needs to slice off the fn argument, doesn't it?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@rvagg, what @bnoordhuis says is correct, the function needs all the arguments but the first, which is the function itself.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry, didn't notice the 1
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Shouldn't it be the same as https://github.com/iojs/io.js/blob/v0.12/lib/events.js#L103 ?
bnoordhuis commented Nov 29, 2014
LGTM FWIW. |
bnoordhuis commented Dec 1, 2014
I suppose one question that needs answering is whether @micnic Can you make the commit log conform to the template as described in CONTRIBUTING.md? Thanks. |
vkurchatkin commented Dec 1, 2014
@bnoordhuis I agree. Also it's possible just to call |
micnic commented Dec 1, 2014
@bnoordhuis, I'll add a switch for different cases as @vkurchatkin proposes. related to the commit log, should I make a new pull request or just another commit with a more verbose description? (it's my first PR) |
bnoordhuis commented Dec 1, 2014
@micnic That's a good idea but can you then also add a small benchmark in benchmarks/ that shows that the switch statement actually speeds things up? Thanks. As to the commit log, you can just |
micnic commented Dec 2, 2014
@bnoordhuis, I added the benchmark and made some changes to the arguments slicing logic to: if(arguments.length>=2){args=Array.prototype.slice.call(arguments,1);ret=fn.apply(this,args);}else{ret=fn.call(this);}it's similar to what is used in Now, what I discovered is that we also should bind the arguments to the domain if they may emit any errors, take in count this use case: vardomain=require('domain');varevents=require('events');vardom=domain.create();varemitter=newevents.EventEmitter();dom.on('error',function(error){console.log(error.message+' is caught');});dom.run(function(ee){ee.emit('someEvent');},emitter);// This error is not caught by the domainemitter.emit('error',newError('Oh No!'));What do you think about explicitly binding the arguments to the domain? |
vkurchatkin commented Dec 2, 2014
sounds counterintuitive and probably will cause lots of confusion |
d7e65ff to 185d11cComparecaineio commented Dec 8, 2014
Hello! I am pleased to see your valuable contribution to this project. Would you Questions:
Please provide the answers in an ordered list like this:
Note that I am just a bot with a limited human-reply parsing abilities, In case of success I will say: In case of validation problem I will say: Truly yours, Responsibilities
|
micnic commented Dec 8, 2014
|
caineio commented Dec 8, 2014
...summoning the core team devs! |
bnoordhuis commented Dec 10, 2014
I think this conflicts with #66. I'll bring it up in the TC meeting today; if we are going to deprecate domains, it doesn't make sense to extend the API. |
lib/domain.js Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I did some quick research and calling Array.prototype.slice.call(arguments) always deopts the function. You can see it for yourself when you run with --trace_opt --trace_deopt; V8 always bails out with "Bad value context for arguments value". It's unavoidable and probably doesn't matter much in the grand scheme of things but it's still a pity.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I believe you can work around this by copying arguments to args using a loop. Not sure if it's worth it in this case.
Ref: https://github.com/petkaantonov/bluebird/wiki/Optimization-killers#32-leaking-arguments
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a bit of a fun one because slicing the arguments manually is not usually faster than calling Array::slice() - so whether this is worthwhile or not depends on how much work the rest of your function does. In this case that function isn't doing a lot of work itself but it means that V8 can't inline the function calls. This is a slightly obfuscated version that should be faster:
Domain.prototype.run=function(fn){if(this._disposed)return;if(arguments.length>=2){returnthis._runWithArgs(fn,Array.prototype.slice.call(arguments,1));}else{returnthis._runNaked(fn);}};Domain.prototype._runNaked=function(fn){this.enter();varret=fn.call(this);this.exit();returnret;};Domain.prototype._runWithArgs=function(fn,args){this.enter();varret=fn.apply(this,args);this.exit();returnret;};There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This section of code from lib/events.js is probably the correct approach to take - https://github.com/iojs/io.js/blob/v0.12/lib/events.js#L110-L127
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we should have a standard function to handle the arguments in the most optimal way, something like this:
util.getArgumentsAsArray=function(args,slice){varlength=args.length-slice;vararr=newArray(length);varindex=slice;while(index<length){arr[index-slice]=args[index];index++;}returnarr;};// or maybe ES6 Array.from() not sure about itArray.from(arguments).slice(1);This function may be used in setTimeout(), setInterval(), setImmediate(), EventEmitter.emit(), domain.run(), in some future implementation with custom arguments and in third-party modules.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@micnic how would you call this function without leaking the arguments from the caller?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My understanding is that arguments are just a pain to deal with and that passing them to a function, like your getArgumentsAsArray(), is enough to cause a deoptimization in most cases.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There's no way to slice or otherwise manipulate arguments without doing it manually if you want to avoid deopts. The only function that it is ok to pass a naked arguments to is Function.prototype.apply as it is special cased. Bluebird uses a macro to make this more convenient, also see https://github.com/petkaantonov/bluebird/wiki/Optimization-killers#3-managing-arguments for more info.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@phpnode, ah, you are right, there is no way no avoid deoptimization, thanks for clarifying, I hope V8 devs will improve this.
I'll just add the loop manipulation as it is in the EventEmitter.
Adds the feature to define arguments for the function called in domain.run(), this is supposed to be useful when a function is called from another context and some values from the current context are needed as arguments, it's similar to the callback from setTimeout or setInterval.
micnic commented Dec 11, 2014
This PR is ready for merge, I made the demanded changes |
bnoordhuis commented Dec 11, 2014
@micnic@chrisdickinson will take it from here, he graciously volunteered to shepherd this PR. |
PR for nodejs/node-v0.x-archive#7193