Exposing a few things that are currently VM-internal


#1

Was talking with @jdalton tonight at the Seattle JS meetup about lodash (his presentation on it will hopefully be available soon), and how it unexpectedly creams the performance of the native versions of the functions it implements.

Some of lodash’s performance gains are due to optimizations made possible by some ugly hacks, and we were discussing how much more effectively these optimizations could be done if the underlying characteristics lodash detects heuristically were explicitly surfaced in JavaScript.

These APIs would pave the way for lodash to be more consistent across environments, and even make it easier to write more performant implementations for core functions in JavaScript (since context switches are, to my knowledge, one of the largest sources of perf losses, which is probably a big part of why stuff like lodash has better perf than native).

##Function#isBound

lodash has a (significant) performance boost where it checks whether a function uses this to determine if it can use f() instead of f.bind()/f.call(). Right now jdalton has this shimmed with /\bthis\b/.test(f.toString()), which is very hacky (with some environments not even supporting function stringification at all). If this were made available, lodash could just check f.isBound.

Function#isNative

The way lodash determines this right now is by comparing with something like Object.prototype.toString.toString(), which is only slightly less unreliable than the above hack for testing the existence of a reference.

I think there was also some mention of surfacing a flag for native objects (eg. DOM elements) as well.

Array#isSparse

lodash is currently designed to assume that an array is never sparse. Exposing this would let lodash implement a slow-path for sparse array compatibility, and subsequently / conversely open the door for performant shims of existing sparse-array-compatible core functions.

cloneObject

I’m not sure where this could go or what the interface / signature should be, but jdalton mentioned that his work would be significantly easier (as it would certainly be for many other developers, myself included) if VMs exposed the deep object clone method they use for places like postMessage.

(Edit: replaced Function#references with Function#isBound per @FremyCompany’s suggestion)


A Defense of Declarative Content
Putting APIs in ECMAScript
#2

To the exception of Function#references which I believe is too broad, I think the proposals make sense.

Regarding the Function#references section, I think we could get the job done with a simpler Function#isBound which would return true for functions which have been bound using Function#bind but also for functions which do not contain any reference to “this” nor any direct eval statement.

Would it be sufficient for the envisionned use cases?


#3

Another addition that would help recover the decision power of your “'references” proposal would be Function#hasArguments.

Function#hasArguments would return false if the considered function do not use its arguments (or all of them have been bound using Function#bind).

Functions which use a param array (…args) or the “arguments” object (as well as bound functions calling those) will never return false for “hasArguments” and will therefore always have to react to additionnal “bind” requests containing arguments to bind.


#4

Probably - when we were discussing this Thursday night, we were thinking it would be “Function#usesThis”, which is essentially a clumsier-worded version of the inverse. I only added “Function#references” when I was writing this up, out of a desire to generalize, but you’re right that isBound would be the more accurate generalization.

I’ve edited the OP accordingly to remove Function#references as I had it:

Function#references

This would be any outside names referenced in the function, as a Set (or Array).

lodash has a (significant) performance boost where it checks whether a function uses this to determine if it can skip the binding/calling step. Right now jdalton has this shimmed with /\bthis\b/.test(f.toString()), which is very hacky (with some environments not even supporting function stringification at all). If this were made available as a set, lodash could just do f.references.has('this').

This could also maybe be an Object/Map that includes parameters and variable names, as well as the outside names, with the values being “argument” or “var” if they’re one of those two (otherwise I guess they’d be “upvalue”?)


#5

The aforementioned talk has been uploaded:


#6

Any ES spec people who can speak to this? @domenic ?