7 Commits

Author SHA1 Message Date
Nicolò Ribaudo
464df13c69 Allow yielding an arrow function withour parens around the param (#6877) 2017-11-22 15:28:37 -06:00
Raja Sekar
63397d0aad Better error message for super when not using an object method (#6754) 2017-11-15 21:29:46 -06:00
Nicolò Ribaudo
9ae23639ad
Parse async arrows with flow type parameters (#6802)
Fixes #6712
2017-11-14 16:24:14 +01:00
Daniel Tschinder
cc66495a95
Unify eslint/prettier config (#6747)
* Unify eslint/prettier config

Use a prettier config file and correctly configure trailing commas

Enable curly in babylon as in all other packages.

* Add experimental and codemods
2017-11-06 14:19:59 +01:00
Benedikt Meurer
de72ce6ce7 Changed for..in loops to iterating through Object.keys, so only own properties gets processed (#6748)
* Properly guard for..in loops with Object#hasOwnProperty.

I noticed that babylon spends a lot of time in what we call *slow mode*
`for..in` when running in Node (on V8), and the reason for that is that
the version distributed on npm is build with *loose mode*, which turns
methods on the prototype into enumerable properties. Let's look at a
simplified example of the `State` class from `src/tokenizer/state.js`:

```js
class State {
  constructor() { this.x = 1; }

  clone() {
    var state = new State();
    for (var key in this) {
      var val = this[key];
      state[key] = val;
    }
    return state;
  }
}
```

According to the specification the `State.prototype.clone` method is
non-enumerable. However when transpiling this with loose mode, we get
the following output:

```js
var State = (function() {
  function State() { this.x = 1; }

  State.prototype.clone = function clone() {
    var state = new State();
    for (var key in this) {
      var val = this[key];
      state[key] = val;
    }
    return state;
  }

  return State;
})();
```

So all of a sudden the `State.prototype.clone` method is enumerable.
This means that the `for..in` loop inside of that method enumerates
`x` and `clone` for `key`, whereas originally it was supposed to only
enumerate `x`. This in turn means that the shape of the result of a
call to `clone` will be different than the shape of a state that is
created via the `State` constructor. You can check this in `d8` using
the `--allow-natives-syntax` flag and this simple test driver:

```js
const s = new State;
%DebugPrint(s);
%DebugPrint(s.clone());
```

Using either the class version or the transpiled version we see:

```
$ out/Release/d8 --allow-natives-syntax state-original.js
0x2a9d7970d329 <State map = 0x2a9d40b0c751>
0x2a9d7970d3c1 <State map = 0x2a9d40b0c751>
$ out/Release/d8 --allow-natives-syntax state-loose.js
0x3729ee30d1b9 <State map = 0x3729af90c701>
0x3729ee30d251 <State map = 0x3729af90c7a1>
```

So as you can see, the transpiled version (using *loose mode*) produces
a different shape for the result of `clone`, whereas the original
version is fine. This pollutes all sites which use either a state
created from the `State` constructor or returned from the `clone`
method. The original one has only the `x` property in either case,
whereas in the transpiled version the result of `clone` has properties
`x` and `clone` on the instance.

To mitigate this effect, it's best to guard the `for..in` loops with
`Object.prototype.hasOwnProperty` calls, such that the actual body of
the loop only deals with own properties and not with properties from the
prototype chain. This change does exactly that for the two affected
`clone` functions.

In addition to the performance hit because of the unnecessary
polymorphism, there's also the performance hit because of the *slow
mode* `for..in` itself, which has to collect the properties from the
instance plus the prototype. Ideally the prototype properties shouldn't
be enumerable to avoid this whole set of problems. I see a couple of
possible solutions:

1. Distribute the original ES2015 version via npm.
2. Don't use loose mode, so that `Object.defineProperty` is used
   instead, correctly passing `enumerable:false`.
3. Globally change loose mode in Babel to generate the correct and
   fast `Object.defineProperty` instead.

I'd personally prefer a combination of 1. and 3. here, but I'm aware
that distributing the ES2015 code might not be an option yet. So the
mitigation of properly guarding the `for..in` here should already help.
But it'd be nice to have a discussion on using `Object.defineProperty`
in general, as I imagine that this could easily bite other applications
as well and this performance cliff is completely unobvious to
developers.

* Switch to Object.keys and Array.prototype.forEach.
2017-11-06 13:23:20 +01:00
Henry Zhu
1196ec1e38
add loose/useBuiltIns option to stage presets, use it, opt babylon build (#6733)
* add loose, useBuiltIns options to presets + use loose class properties

* whitelist helpers for babylon

* use transform-for-of-as-array in babylon
2017-11-03 14:22:06 -04:00
Daniel Tschinder
2d378d076e
Move babylon into monorepo 2017-11-01 16:16:48 +01:00