JavaScriptCore nested "call" performance issue

JavascriptJavascriptcore

Javascript Problem Overview


If I define a function

inc = function(x) { return x + 1 }

and make a nested invocation of it

inc(inc(inc(inc(inc(inc(inc(inc(inc(inc(inc(inc(inc(inc(inc(inc(inc(inc(inc(inc(inc(1)))))))))))))))))))))

this will result in the value 22. If I revise the nested expression to instead make use of call, passing in null for this, as

inc.call(null, inc.call(null, inc.call(null, inc.call(null, inc.call(null, inc.call(null, inc.call(null, inc.call(null, inc.call(null, inc.call(null, inc.call(null, inc.call(null, inc.call(null, inc.call(null, inc.call(null, inc.call(null, inc.call(null, inc.call(null, inc.call(null, inc.call(null, inc.call(null, 1)))))))))))))))))))))

this will also produce the value 22.

But, on JavaScriptCore this second form appears to consume O(2^n) memory, where n is the number of nested calls. This is not the case if I try this JavaScript in Firefox or Chrome so it seems to be isolated to JavaScriptCore.

I have very little JavaScript experience (almost none). I don't have a feel for the tradeoffs that various JavaScript implementations might make, nor whether it is reasonable for the example code to be expensive in some implementations (providing generic support for closures or some such), while efficient in others.

My question is: Is this code inherently problematic? Should it be rewritten to be structured in a different way? Or is the code fine—does JavaScriptCore simply have a bug?

I've done some experimentation where refactoring a few of the inner calls to temporaries will "truncate" the memory doubling behavior

var temp1 = inc.call(null, inc.call(null, inc.call(null, inc.call(null, inc.call(null, inc.call(null, inc.call(null, 1)))))));
                                                                                              
var temp2 = inc.call(null, inc.call(null, inc.call(null, inc.call(null, inc.call(null, inc.call(null, inc.call(null, temp1)))))));
    
inc.call(null, inc.call(null, inc.call(null, inc.call(null, inc.call(null, inc.call(null, inc.call(null, temp2)))))));

Javascript Solutions


Solution 1 - Javascript

Based on comments on this question, the consensus is that there is no fundamental problem with the code as written, but that instead this is a bug in JavaScriptCore.

For the ticket filed, it has been confirmed as reproducible and has been imported into Apple's Radar system.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionMike FikesView Question on Stackoverflow
Solution 1 - JavascriptMike FikesView Answer on Stackoverflow