UNCONFIRMED 103727
Unset NodeMustGenerate flag for Call nodes of few String.prototype.* pure functions
https://bugs.webkit.org/show_bug.cgi?id=103727
Summary Unset NodeMustGenerate flag for Call nodes of few String.prototype.* pure fun...
Dmitry Melnik
Reported 2012-11-30 02:47:39 PST
Function calls have NodeMustGenerate flag set, but this is redundant in case the function has no side effects. This patch aims to remove NodeMustGenerate flag for Call nodes of String.replace, String.split, and String.indexOf, if their argument types imply no side effects. This would allow to eliminate such calls, if their result is unused. Example: function foo() { var str = "split it up"; var i; for (i = 0; i < 10000; i++) { var x = str.split(" "); } } var i; for (i = 0; i < 1000; i++) foo(); Run time w/o patch: 1.756s With the patch: 0.032s Is it, in general, the right way to eliminate redundant calls? I admit that using strcmp is not the best way to check for function names -- probably it would be better to create a hashtable with mapping of function names to argument checking routines, but for now I just would like to get some feedback to know whether this optimization is correct and if the WebKit community is interested in it.
Attachments
patch (6.14 KB, patch)
2012-11-30 02:49 PST, Dmitry Melnik
fpizlo: review-
fpizlo: commit-queue-
updated patch (7.34 KB, patch)
2012-12-03 08:13 PST, Dmitry Melnik
fpizlo: review-
eflews.bot: commit-queue-
patch for discussion (68.40 KB, patch)
2013-11-27 05:00 PST, Valery Ignatyev
no flags
Dmitry Melnik
Comment 1 2012-11-30 02:49:56 PST
Filip Pizlo
Comment 2 2012-11-30 12:11:25 PST
Comment on attachment 176931 [details] patch View in context: https://bugs.webkit.org/attachment.cgi?id=176931&action=review > Source/JavaScriptCore/dfg/DFGAbstractState.cpp:2045 > + node.clearFlags(NodeMustGenerate); It's not correct to do this inside AbstractState - since you have no way of knowing , yet, if the CFA has converged and if the function value you're relying upon is accurate. Instead, you should just move this whole method to the constant folding phase. (I know, really bad name for a phase since it does more than constant folding.). That phase runs after CFA converges so you can be sure that the function is accurate.
Filip Pizlo
Comment 3 2012-11-30 12:14:19 PST
(In reply to comment #0) > Function calls have NodeMustGenerate flag set, but this is redundant in case the function has no side effects. This patch aims to remove NodeMustGenerate flag for Call nodes of String.replace, String.split, and String.indexOf, if their argument types imply no side effects. This would allow to eliminate such calls, if their result is unused. > > Example: > > function foo() { > var str = "split it up"; > var i; > for (i = 0; i < 10000; i++) { > var x = str.split(" "); > } > } > > var i; > for (i = 0; i < 1000; i++) > foo(); > > Run time w/o patch: 1.756s > With the patch: 0.032s > > Is it, in general, the right way to eliminate redundant calls? > I admit that using strcmp is not the best way to check for function names -- probably it would be better to create a hashtable with mapping of function names to argument checking routines, but for now I just would like to get some feedback to know whether this optimization is correct and if the WebKit community is interested in it. I believe that what you are doing is broadly correct. You should just fix the bug regarding not making graph changes from AbstractState. I'm also wondering if maye we should clear the NodeClobbersWorld flag... Final thought: we would have previously used intrinsically to accomplish what you're doing. But I don't think that makes your approach wrong; particularly since your approach doesn't require new node types or any other special treatment of the fictions in question.
Dmitry Melnik
Comment 4 2012-12-03 08:13:22 PST
Created attachment 177258 [details] updated patch I moved the code to Constant Folding phase, and also added clearing of NodeClobbersWorld flag.
Darin Adler
Comment 5 2012-12-03 12:22:30 PST
Comment on attachment 177258 [details] updated patch View in context: https://bugs.webkit.org/attachment.cgi?id=177258&action=review > Source/JavaScriptCore/dfg/DFGConstantFoldingPhase.cpp:41 > +extern const HashTable stringTable; This is an anti-pattern. If we want to use an external symbol, we should include the header it’s declared in, not re-declare it inside a file that’s using it.
EFL EWS Bot
Comment 6 2013-04-23 15:56:24 PDT
Comment on attachment 177258 [details] updated patch Attachment 177258 [details] did not pass efl-wk2-ews (efl-wk2): Output: http://webkit-queues.appspot.com/results/50311
Filip Pizlo
Comment 7 2013-04-23 17:04:19 PDT
Comment on attachment 177258 [details] updated patch View in context: https://bugs.webkit.org/attachment.cgi?id=177258&action=review I think this will be unsound if we exit prior to where the call used to be, and the baseline JIT uses callee and this in the call. It'll probably crap out with an exception like that 'undefined' isn't callable. You should figure out what you want to do about that. One option is to convert the Call to a Phantom. A potentially better solution is to just make those functions intrinsic. That would save you from a lot of the trouble. > Source/JavaScriptCore/dfg/DFGConstantFoldingPhase.cpp:89 > + const HashTableValue& fEntry = JSC::stringTable.values[i]; I don't think we want this to become a pattern. It would be much better to make split and friends into intrinsics and detect this in the parser. It will conserve compile times, among other things.
Valery Ignatyev
Comment 8 2013-11-27 05:00:54 PST
Created attachment 217942 [details] patch for discussion This is the preliminary patch posted to discuss the suggested approach. Regarding your proposal to use intrinsics, we would like to implement more general approach. Please let us know any feedback. Also, we have successfully used m_graph.deref(nodeIndex) to remove instructions from DFG in the older webkit, but at the moment this approach doesn't work. Could you please suggest the correct way for removing instructions? In function bool performRedundantCallElimination(Node *callNode) we've tried different combinations of callNode->clearFlags(NodeMustGenerate | NodeClobbersWorld); callNode->children.reset(); callNode->convertToPhantomUnchecked(); callNode->setRefCount(0) without success.
Note You need to log in before you can comment on or make changes to this bug.