Commit Graph

586 Commits

Author SHA1 Message Date
Sebastian Markbage
d16750f5c8 Set on havoced object should target the receiver, not the own object (#2338)
Summary:
In case the havoced object has a setter on it.

This is fixes this particular bug but it's also useful to be able to pass the correct receiver to properties.js rather than unwrapping it like we do now. This will be evident in a follow up PR.

This also lets emitPropertyAssignment deal with abstract values which is a common pattern and will become more common with widened objects.
Pull Request resolved: https://github.com/facebook/prepack/pull/2338

Differential Revision: D9035746

Pulled By: sebmarkbage

fbshipit-source-id: 2abb1a3eb047de1739dec94259a803c4c45e416d
2018-07-27 15:09:10 -07:00
Sebastian Markbage
b03e018910 Symbol Coercion Should Always Throw (#2300)
Summary:
Coercing a symbol to a number or primitive implicitly always throws an error. We generated fatal compiler errors. Instead, this should just be treated as a throw.

This is neat because that means other serializers doesn't have to deal with the expressions involving symbols.
Pull Request resolved: https://github.com/facebook/prepack/pull/2300

Differential Revision: D9035734

Pulled By: sebmarkbage

fbshipit-source-id: 60c0d089e63b7b36b6757dab0c9928c19514c5d6
2018-07-27 15:09:10 -07:00
Sebastian Markbage
2334d329d1 Special case conditionals for $DefineOwnProperty, $SetPartial, $GetPartial and $Delete (#2329)
Summary:
Follow up to #2219

This also includes two relevant bonus fixes: 2aa1ad35a4 and e96ac8c0c1
Pull Request resolved: https://github.com/facebook/prepack/pull/2329

Differential Revision: D9033950

Pulled By: sebmarkbage

fbshipit-source-id: b28b608b7449f0bbd7781c7d6aab5717d638d904
2018-07-27 13:56:01 -07:00
Sebastian Markbage
042a71259a Try conditional branches separately if binary expression fails (#2332)
Summary:
This solves the remaining issues in #2300.

If a binary expression can't be resolved as pure (such as when applied to values of two different types), we can instead try conditions separately and join the effects.

If the left value is conditional, we try each possible value separately until we hit a non-conditional value. Then we try any conditional right values.
Pull Request resolved: https://github.com/facebook/prepack/pull/2332

Differential Revision: D9032487

Pulled By: sebmarkbage

fbshipit-source-id: 0f89a680ad0b710e90c1dd7a4c127c2247527c99
2018-07-27 13:18:09 -07:00
Sapan Bhatia
3bcd3fb4ee Deduplicate object creation code in a non-branched setting (#2302)
Summary:
This pull request breaks out the first part of #2185, which deduplicates object creation when leaking is unconditional to begin with. No changes are made to how leaking works. Only to how leak information is used by the serializer and visitor.
Pull Request resolved: https://github.com/facebook/prepack/pull/2302

Differential Revision: D8997109

Pulled By: sb98052

fbshipit-source-id: e0ea2e7ea574a9f2be71b70be289831c7f797d9d
2018-07-25 11:40:50 -07:00
Dominic Gannaway
b0fe89e863 Add shape model functionality to React components (#2320)
Summary:
Release notes: React components can have their props modelled via `__optimizeReactComponentTree`

This extends the current shape modelling functionality added for InstantRender (great work by hotsnr ) and provides the same powers to the React compiler. An example of usage:

```js
var React = require("React");

function App(props) {
  return <div>
    <h1>{props.header.toString()}</h1>
    <ul>
      {
        props.items && props.items.map(item =>
          <li key={item.id}>{item.title.toString()}</li>
        )
      }
    </ul>
  </div>;
}

App.getTrials = function(renderer, Root) {
  var items = [{ id: 0, title: "Item 1" }, { id: 1, title: "Item 2" }, { id: 2, title: "Item 3" }];
  renderer.update(<Root items={items} header={"Hello world!"} />);
  return [["render simple with props model", renderer.toJSON()]];
};

if (this.__optimizeReactComponentTree) {

  let universe = {
    Item: {
      kind: "object",
      jsType: "object",
      properties: {
        id: {
          shape: {
            kind: "scalar",
            jsType: "integral",
          },
          optional: false,
        },
        title: {
          shape: {
            kind: "scalar",
            jsType: "string",
          },
          optional: false,
        },
      },
    },
    Props: {
      kind: "object",
      jsType: "object",
      properties: {
        header: {
          shape: {
            kind: "scalar",
            jsType: "string",
          },
          optional: false,
        },
        items: {
          shape: {
            kind: "array",
            jsType: "array",
            elementShape: {
              shape: {
                kind: "link",
                shapeName: "Item",
              },
              optional: false,
            },
          },
          optional: true,
        },
      },
    },
  };

  let appModel = {
    component: {
      props: "Props",
    },
    universe,
  };

  __optimizeReactComponentTree(App, {
    model: JSON.stringify(appModel),
  });
}

module.exports = App;
```
Pull Request resolved: https://github.com/facebook/prepack/pull/2320

Differential Revision: D8996429

Pulled By: trueadm

fbshipit-source-id: 31eb4b42fcfab4aec785492ed0baecfb5533a0e2
2018-07-25 11:27:47 -07:00
Caleb Meredith
2810294260 Fix React branch serialization issues (#2318)
Summary:
After adding classes to my fuzzer (which does not use first render mode) I found #2316. This PR fixes #2316 and a related issue I found while working on that. (Each fix is in a separate commit.) The second issue I found is scarier since the compiler passes but we get invalid output.

In the following example I observed an invariant violation:

```js
const React = require("react");

__evaluatePureFunction(() => {
  function Tau(props) {
    return React.createElement(
      "div",
      null,
      React.createElement(Epsilon, {
        a: props.z,
      }),
      React.createElement(Zeta, {
        p: props.h,
      })
    );
  }

  class Epsilon extends React.Component {
    constructor(props) {
      super(props);
      this.state = {};
    }

    render() {
      return React.createElement(Zeta, { p: this.props.a });
    }
  }

  function Zeta(props) {
    return props.p ? null : React.createElement("foobar", null);
  }

  __optimizeReactComponentTree(Tau);

  module.exports = Tau;
});
```

```
=== serialized but not visited values
=== visited but not serialized values
undefined, hash: 792057514635681
  referenced by 1 scopes
      =>_resolveAbstractConditionalValue alternate(#75)=>ReactAdditionalFunctionEffects(#80)

Invariant Violation: serialized 26 of 27
This is likely a bug in Prepack, not your code. Feel free to open an issue on GitHub.
    at invariant (/Users/calebmer/prepack/src/invariant.js:18:15)
    at ResidualHeapSerializer.serialize (/Users/calebmer/prepack/src/serializer/ResidualHeapSerializer.js:2465:17)
    at statistics.referenceCounts.measure (/Users/calebmer/prepack/src/serializer/serializer.js:259:15)
    at PerformanceTracker.measure (/Users/calebmer/prepack/src/statistics.js💯14)
    at ast (/Users/calebmer/prepack/src/serializer/serializer.js:238:38)
    at statistics.total.measure (/Users/calebmer/prepack/src/serializer/serializer.js:169:17)
    at PerformanceTracker.measure (/Users/calebmer/prepack/src/statistics.js💯14)
    at Serializer.init (/Users/calebmer/prepack/src/serializer/serializer.js:136:35)
    at prepackSources (/Users/calebmer/prepack/src/prepack-standalone.js:66:33)
    at compileSource (/Users/calebmer/prepack/scripts/debug-fb-www.js:92:18)
```

Somehow we were visiting `undefined`, but clearly we weren’t serializing it given the source code. Here’s what was happening:

- We’d visit an additional function calling `withCleanEquivalenceSet`.
- The additional function would enqueue an action which visited `<foobar>`.
- Later, we’d execute the `<foobar>` visiting action outside our `withCleanEquivalenceSet` with our default equivalence set.
- The same thing happens with our new root from our `Epsilon` class.
- Except now some effects have been applied that set the `type` for our `<foobar>` React element in our React equivalence set to `undefined`. Since when we created `<foobar>` we modified its `type` property. (Recorded in `modifiedProperties`.)
- Now our `<Zeta>` in `<Tau>` and our `<Zeta>` in `<Epsilon>` share the _exact same_ `<foobar>` thanks to our equivalence set.
- But `<foobar>` has a `type` of `undefined` thanks to the effects we applied. We should be creating a new `<foobar>` since we are in a new optimized function.
- ***Boom!*** We visit `undefined`, but don’t serialize it since the same effects aren’t applied when we serialize.

This test case caught an important flaw in our visiting logic, but it only manifested as an invariant under these very specific conditions. Which is a little scary. In a large example, like our internal bundle, we would of course serialize some `undefined` value but we would have still visited `undefined` instead of the proper type, _and_ we may consider two elements to be equivalent when we shouldn’t since their components may render independently. This issue (I presume) can also affect we bail out on since they create new trees inside the root tree.

While debugging and fixing this issue, I found another with incorrect/suboptimal output that passes Prepack and passes eslint. Given the following input:

```js
require("react");

__evaluatePureFunction(() => {
  const React = require("react");

  function Tau(props) {
    return React.createElement(
      "a",
      null,
      React.createElement("b", null),
      React.createElement(Epsilon, null),
      React.createElement("c", null)
    );
  }

  class Epsilon extends React.Component {
    constructor(props) {
      super(props);
      this.state = {};
    }

    render() {
      return React.createElement("d", null);
    }
  }

  __optimizeReactComponentTree(Tau);

  module.exports = { Tau, Epsilon };
});
```

We get this output:

```js
(function () {
  var _$0 = require("react").Component;

  var _3 = function (props, context) {
    _6 === void 0 && $f_0();
    _9 === void 0 && $f_1();

    var _8 = <_B />;

    var _4 = <a>{_6}{_8}{_9}</a>;

    return _4;
  };

  var _B = class extends _$0 {
    constructor(props) {
      super(props);
      this.state = {};
    }

    render() {
      return _E; // <--------------------------- Incorrect. `_B` may be rendered outside of `_3`.
    }
  };

  var $f_0 = function () {
    _6 = <b />;
    _E = <d />;
  };

  var _6;

  var _E;

  var $f_1 = function () {
    _9 = <c />;
  };

  var _9;

  var _0 = {
    Tau: _3,
    Epsilon: _B
  };
  module.exports = _0;
})();
```

This happened because the React serializer’s `_lazilyHoistedNodes` logic was implemented in a way that doesn’t play well with the interleaving almost random order of the serializer invocation of React lazily hoisted nodes logic.
Pull Request resolved: https://github.com/facebook/prepack/pull/2318

Differential Revision: D8992253

Pulled By: calebmer

fbshipit-source-id: 4a75e5768ffb7887c3a8afa2a0f3f59e7eac266d
2018-07-25 09:55:21 -07:00
Caleb Meredith
d3e62037aa Support string with abstract argument (#2310)
Summary:
I was seeing `throwIfNotConcrete` a lot for `String()` calls on abstract values in #2297. The fix is relatively quick.
Pull Request resolved: https://github.com/facebook/prepack/pull/2310

Differential Revision: D8960761

Pulled By: calebmer

fbshipit-source-id: f378092cb3e36ac4026404a9e185abe9a768f577
2018-07-23 17:25:02 -07:00
Chris Blappert
f80b4af956 ForkedAbruptCompletion created with generator containing joinCondition (#2272)
Summary:
Release Notes: None

PR solved by hermanventer's recent PR, just adding another test case closer to the one in the issue.

Resolves #2248
Pull Request resolved: https://github.com/facebook/prepack/pull/2272

Differential Revision: D8938294

Pulled By: cblappert

fbshipit-source-id: 18e4fd3b8913400b98242eff06f011ed0140459b
2018-07-20 12:09:39 -07:00
Nikolai Tillmann
eeb081a545 Don't emit modified bindings unless they are alive (#2287)
Summary:
Release notes: Enhanced dead code elimination for optimized functions

This resolves #2276: Visiting+emitting modified bindings now participates
in the fixed point computation, checking for whether the modified binding
is actually getting visited for other reasons.

The previously existing code that did CSE by mutating the generator entry
got removed, as it wouldn't work exactly like that anymore (can't return value
because actual analysis gets postponed for fixed point computation). Filed #2286
to keep track of that and more needed changes around CSE for values stored in locations
participating in effects tracking. --- Turns out that we didn't have a test anyway
that would detect whether binding CSE happens or not.

Added regression test.
Pull Request resolved: https://github.com/facebook/prepack/pull/2287

Differential Revision: D8902345

Pulled By: NTillmann

fbshipit-source-id: 6ba3fb9755312956829050f0278dee2d85d6a261
2018-07-18 14:40:05 -07:00
Nikolai Tillmann
7d355ef4c5 Ignore modifications of Prepack-specific intrinsic properties (#2269)
Summary:
Release notes: None

Fixes #2266 and adds regression test.
Fixes #2262 and adds regression test.
Pull Request resolved: https://github.com/facebook/prepack/pull/2269

Differential Revision: D8896059

Pulled By: NTillmann

fbshipit-source-id: aee93083c6da6d703d7788a6458e2506638debc3
2018-07-18 10:54:59 -07:00
Dan Abramov
3bf79dd693 Add a regression test for #2090 (#2281)
Summary:
https://github.com/facebook/prepack/issues/2090 doesn't reproduce for me anymore so I'm adding a test.
Pull Request resolved: https://github.com/facebook/prepack/pull/2281

Differential Revision: D8893196

Pulled By: gaearon

fbshipit-source-id: c0d9748e5898ab8cffa0c6c23dd5db9dadfbf6cc
2018-07-18 07:24:17 -07:00
Roman Khotsyn
6e60644e12 Function argument modeling (#2215)
Summary:
This change allows modeling of optimized function arguments in different way than regular environment modeling. The main point of this modeling is being able to determine what getter should be used at this particular GraphQL property access at compile time. To achieve this Prepack should know the shape of arguments used for optimizing functions and should be able to infer the shape of value when it is needed.
Shape information is attached to AbstractValue (to pass it around) and on every property access a new AbstractValue is returned with shape information specific to this property.
As an output of this process, every member access to modeled values is replaced by function call like prop_string(obj, "key").
Structure of the model can be found in `ShapeInformation.js`.
Pull Request resolved: https://github.com/facebook/prepack/pull/2215

Reviewed By: NTillmann

Differential Revision: D8874743

Pulled By: hotsnr

fbshipit-source-id: 9e1b2254ef54986229be7d1195c1586b95d9a4be
2018-07-18 04:09:03 -07:00
Nikolai Tillmann
7ec32cf3aa For abstract objects, look into values domain for IsCall (#2268)
Summary:
Release notes: None

IsCall used to fail on abstract values even if they have a set of values in their domain.
This in turn would make `typeof` not work on abstract values.
This makes it work, and adds a regression test.
Pull Request resolved: https://github.com/facebook/prepack/pull/2268

Differential Revision: D8878641

Pulled By: NTillmann

fbshipit-source-id: f6dda513786eaf3f02bd13d5c6474c2f20fb0082
2018-07-18 01:54:08 -07:00
Herman Venter
cd67ae0e8c Move generators from PNC normal branches to joined normal effects (#2274)
Summary:
Release note: none

Generators that end up in joined effects, need to disappear from the generators in the forked completions from which they have been extracted. Also, they need to be applied to the generator containing the timeline in which the fork occurs, before the fork occurs.

With some luck, this may fix a lot of issues.
Pull Request resolved: https://github.com/facebook/prepack/pull/2274

Differential Revision: D8878320

Pulled By: hermanventer

fbshipit-source-id: a6cd41bf9e82bc4e362bda32a1e32c5fc90298cf
2018-07-17 19:09:35 -07:00
Caleb Meredith
b0516b49ea Nested abstract conditional fixes (#2255)
Summary:
Fixes #1867 and fixes #2058 which are issues blocking the React compiler.

Test case from #1867 copied below:

```js
(function() {
  function fn(arg) {
    if (arg.foo) {
      if (arg.bar) {
        return 42;
      }
    }
  }

  if (global.__optimize) {
    __optimize(fn);
  }

  global.inspect = function() {
    return JSON.stringify([
        fn(null),
        fn({}),
        fn({foo: true}),
    ]);
  };
})();
```

The fix is almost entirely in `joinOrForkResults` where I remove the call to `updatePossiblyNormalCompletionWithConditionalSimpleNormalCompletion` and replace it with a new `PossiblyNormalCompletion`. Here’s my understanding of the issue and the previous strategy. Hopefully hermanventer can correct me if I’m wrong or explain why it needs to be the way it was.

In our program above when we are joining the `arg.foo` consequent with its alternate we have the following completion for the `arg.foo` consequent:

- `PossiblyNormalCompletion` (join condition is `arg.bar`)
  - `ReturnCompletion(42)` (value of `42`)
  - `SimpleNormalCompletion(empty)` (there is no `else`)

We are joining this with an alternate of `SimpleNormalCompletion` since there is no `else` on the `arg.foo` if-statement. Before we would try and “sneak into” the two branches and add an abstract conditional to the result. However, the implementation was limited so we we only updated `SimpleNormalCompletion`. This meant we ended up changing our above completion to:

- `PossiblyNormalCompletion` (join condition is `arg.bar`)
  - `ReturnCompletion(42)`
  - `SimpleNormalCompletion(arg.foo ? empty : empty)`

The only change being the second `SimpleNormalCompletion` is now `arg.foo ? empty : empty`. This would serialize into roughly:

```js
function f() {
  return _$1 ? 42 : undefined;
}
```

Where `_$1` is not declared! Since we were serializing a `PossiblyNormalCompletion` with a join condition of `arg.bar` and the `arg.foo ? empty : empty` abstract conditional simplified to just `empty` which means we never emit `arg.foo` so never emit `arg.bar` which has a dependency on `arg.foo`.

My strategy was to nest the `PossiblyNormalCompletion` in another `PossiblyNormalCompletion`. So the final completion for the code sample at the top of this PR is:

- `PossiblyNormalCompletion` (join condition is `arg.foo`)
  - consequent: `PossiblyNormalCompletion` (join condition is `arg.bar`)
    - consequent: `ReturnCompletion(42)`
    - alternate: `SimpleNormalCompletion(empty)`
  - alternate: `SimpleNormalCompletion(empty)`

I’m confused as to why this was not done in the first place and instead an update strategy was used.

I then wrote a test (now in `test/serializer/optimized-functions/NestedConditions.js`) to enumerate a bunch of nested conditional cases. The rest of the fixes come from there. Notably the refactor of `replacePossiblyNormalCompletionWithForkedAbruptCompletion` which did not produce the same output when `consequent` and `alternate` were flipped.
Pull Request resolved: https://github.com/facebook/prepack/pull/2255

Differential Revision: D8865130

Pulled By: calebmer

fbshipit-source-id: 4964acc11b6403b9956cf29decefb1971340516d
2018-07-17 15:18:34 -07:00
Dominic Gannaway
5f626ebdbf Ensure Object.assign merge optimization properly accounts for prefix args (#2261)
Summary:
Release notes: none

When we check to do the temporal `Object.assign` merge optimization, we should properly account for any "prefix" args that occur before "to" and the "suffix" args. Test case added that came up in testing.
Pull Request resolved: https://github.com/facebook/prepack/pull/2261

Differential Revision: D8874714

Pulled By: trueadm

fbshipit-source-id: 59869f556c1300424c5a1b59d3df1fdd139b41fe
2018-07-17 06:24:02 -07:00
Herman Venter
2dc8607269 Compose subsequent effects with currently applied affects (#2271)
Summary:
Release note: none

This fixes a problem reported as a comment in PR #2258.

The underlying problem was that Realm.evaluateForEffects would just append the normal effects, captured since the last non complete join, into the saved partially normal completion that becomes the result of the returned Effects. This is not quite right because applying the resulting Effects should restore the complete set of normal effects that were in force when evaluateForEffects completed.
Pull Request resolved: https://github.com/facebook/prepack/pull/2271

Differential Revision: D8870763

Pulled By: hermanventer

fbshipit-source-id: 027924f2b250174393c60d90c2feefdb5a55eec3
2018-07-16 18:25:24 -07:00
Herman Venter
bad3985f54 Clone completions when they complete composed effects (#2258)
Summary:
Release note: none

The main part of this PR is to ensure that completions and the effects they complete are always 1-1.

Along the way some bugs got fixed #2241.

This also includes a little side project: limiting the console spew when doing "yarn test-serializer --fast", which is something I do all the time and I'm much happier this way.
Pull Request resolved: https://github.com/facebook/prepack/pull/2258

Differential Revision: D8864448

Pulled By: hermanventer

fbshipit-source-id: a7f257a7e07211ecd6069b84330aa3305609c5d2
2018-07-16 13:56:10 -07:00
Sebastian Markbage
81bc21fad8 Delete node-cli Option and all the Node.js intrinsics (#2267)
Summary:
Since I'm adding a new experiment I figured I'd delete an equivalent sized one.

Last year I added an option that runs the Prepack program by invoking Node.js JS runtime which lets us prepack the whole module system and initialization. It's essentially a packager with perfect Node.js module resolution semantics. It did this by modeling Node's native environment as Prepack bindings.

This PR removes that whole option.

There's a few reasons why I don't think that worked out as a good idea.

- It's not solving a real need. It is hard to keep different module systems in tact. There is always something in the ecosystem that breaks down and using the canonical one solves that. However, in practice, if there is a need for bundling the ecosystem itself adapts to the toolchain. So it's not actually that hard to bundle up a CLI even with Webpack, even if it's strictly not 100% compatible, by tweaking a few downstream depenencies.

- Running the resulting bundle is tricky. The resulting bundle includes the JS parts of Node. This overlaps with what Node.js adds at runtime so it runs it twice. The ideal is actually to build a custom distribution of Node.js but this is generally overkill for what people want.

- Bindings change a lot. While Node.js's API notoriously doesn't change much. The internals do change a lot. By picking the API boundary in the middle of the internals of Node.js, it risks changing with any version. While technically observable changes, nobody else relies on these details. If this option was worth its weight, someone could probably maintain it but so far that has not been the case so we had to disable this option in CI to upgrade Node.

However, going forward I think there are alternative approaches we can explore.

- First class module system. This is something we really need at some point. A first class module system would be able to load Node.js module files from disk and package them up while excluding others. It doesn't have to be literally Node.js's module system. Close enough is ok. Especially as standards compliant ECMAScript modules get more popular. This lets us target compiling output that runs after Node's initialization.

- By introducing havocing and membranes in the boundaries, it becomes possible to initialize Node.js modules without actually knowing the internal of the boundaries.

- We've started optimizing residual functions which is much more interesting. However, this requires that code puts some constraints on how it works with its environment. It's not designed to be fully backwards compatible. That's probably a good thing but that also means that we can put constraints on the modules being Prepacked.

This removes the ability to prepack Prepack itself which is unfortunate but already wasn't being tested. To speed up Prepack itself, the [LLVM backend](https://github.com/facebook/prepack/pull/2264) seems much more useful if it can ever work on Prepack itself.
Pull Request resolved: https://github.com/facebook/prepack/pull/2267

Differential Revision: D8863788

Pulled By: sebmarkbage

fbshipit-source-id: d777ec9a95c8523b3386cfad553d9f691ec59074
2018-07-16 13:09:59 -07:00
Sebastian Markbage
51e495a4e2 Impure abstract getters on prototype chain (#2257)
Summary:
This fixes an issue where get on abstract top val didn't consider Receiver.

This also illustrates two common patterns of getters that are not pure. One is reading a mutable property known by Prepack and one is lazily initializing a shared mutable property.

I believe we'll want to continue supporting these patterns since they almost always work anyway. Note that supporting these don't add much negative consequence. We can still eliminate unused getters. Most of the time these patterns doesn't happen where the prototype is unknown or havoced.

Usually the getter is abstract because the Receiver itself is unknown or havoced (not its prototype). So havocing even more doesn't have any further negative downside.
Pull Request resolved: https://github.com/facebook/prepack/pull/2257

Differential Revision: D8862827

Pulled By: sebmarkbage

fbshipit-source-id: 7e6e98f8b85b6fceaa5131136cc6163d94f5d289
2018-07-16 12:58:27 -07:00
Dominic Gannaway
e170c37aaa Upgrade Prepack to Babel 7 (#2256)
Summary:
Release notes: upgrades Prepack to use Babel 7.0.0-beta.53

This is a big PR that updates all of Prepack to Babel 7. Babylon is now `babel/parser` and pretty much all of the the previous Babel packages are now located in scoped packages. I had to make a bunch of changes around Jest/Flow/Webpack to get this all working. The build times of building Prepack itself seem considerably faster (easily twice as fast locally). I followed most of the Babel 6 -> 7 upgrade guide from the Babel site in terms of changing nodes and type definitions to match the new ones.
Pull Request resolved: https://github.com/facebook/prepack/pull/2256

Differential Revision: D8850583

Pulled By: trueadm

fbshipit-source-id: 2d2aaec25c6a1ccd1ec0c08c5e7e2a71f78ac2d8
2018-07-14 09:55:18 -07:00
Caleb Meredith
37d692480b Optimize ReactEquivalenceSet (#2243)
Summary:
I generated the following program (now added to test cases) and while I would expect its evaluation in Prepack to terminate reasonably quickly, I did not see the program terminate after five minutes of execution:

https://gist.github.com/calebmer/2bf1d84a5b7849fa732bce69811df10b

After this change that same program’s Prepack evaluation terminates in about two seconds. This change also saves about 2.8s on the evaluation of our internal bundle which is about 3% of the total time.

What was happening? Why did my program fail to terminate execution in five minutes? Why was the internal bundle relatively ok compared to my extreme case?

In my program, I would [expect the component `Mu`](https://gist.github.com/calebmer/2bf1d84a5b7849fa732bce69811df10b#file-program-js-L289-L291) to be inlined about 60 times. Which means there should only be about 60 calls to `ReactElementSet#add` for each of `Mu`’s `div`s. However, after some basic instrumentation I observed way over ten thousand visits to these React elements.

This pair of method calls happens a couple times in `ReactEquivalenceSet` and friends.

5f7256f17e/src/react/ReactEquivalenceSet.js (L233-L234)

Both `getEquivalentPropertyValue`…

5f7256f17e/src/react/ReactEquivalenceSet.js (L255)

…and `getValue`…

5f7256f17e/src/react/ReactEquivalenceSet.js (L104)

…end up calling `ReactElementSet#add` with the same React element. Then `ReactElementSet#add` ends up recursing into children. So the root element is added 2 times, so the root’s children are added 4 times each, so each child of those elements are added 8 times each, and so on. So if a leaf element is `n` deep in the tree it will be added `2^n` times. The most nested `Mu` child was 9 elements deep. `Mu` appeared 60 times at many levels of nesting.

I’m not entirely sure why my generated case was so much worse then our internal bundle. My two best guesses are: lots of repeated components or deeper nesting?

My fix was to move the `getValue` call into `getEquivalentPropertyValue`. This way if `getEquivalentPropertyValue` already finds an equivalent value we can short-circuit and not run `getValue` which will perform the same operation.
Pull Request resolved: https://github.com/facebook/prepack/pull/2243

Reviewed By: trueadm

Differential Revision: D8811463

Pulled By: calebmer

fbshipit-source-id: 4f30a75e96c6592456f5b21ee9c2ee3e40b56d81
2018-07-13 13:40:00 -07:00
Herman Venter
cd1b752e92 Fix join of SimpleNormal with PossiblyNormal completions. (#2250)
Summary:
Release note: none

When joining a SimpleNormalCompletion with a PossiblyNormalCompletion, do not move the join condition to a leaf position.
Pull Request resolved: https://github.com/facebook/prepack/pull/2250

Differential Revision: D8838821

Pulled By: hermanventer

fbshipit-source-id: 6e102307af31e2ff2f3fbc7ec7f5ad516df5f7a5
2018-07-13 11:24:21 -07:00
Dominic Gannaway
a94f15e6f3 Fix bug with unknown arrays during React reconciliation (#2251)
Summary:
Release notes: none

Fixes a bug with `valueIsFactoryClassComponent` not taking into account unknown arrays.
Pull Request resolved: https://github.com/facebook/prepack/pull/2251

Differential Revision: D8834128

Pulled By: trueadm

fbshipit-source-id: 01b337b3036fa3831f8d46bf1a25e2cd06971667
2018-07-13 07:55:29 -07:00
Dominic Gannaway
8b75241959 Prevent loops from getting stuck in infinite loops (#2247)
Summary:
Release notes: stop abstract loops from getting stuck in infinite loops when body contains a return, throw or break completion

Fixes https://github.com/facebook/prepack/issues/2053. This PR adds logic to "for loops" where they might get stuck in an infinite loop when there is no incrementor but there is a return, throw or break completion in the loop body. We check this via a new function `andfailIfContainsBreakOrReturnOrThrowCompletion` and only do this after `100` iterations of evaluating the loop body. I was thinking of making the iteration count configurable but wanted feedback on the approach first. I tried `1000` iterations, but it actually ended up taking about 2 minutes to evaluate the test case :/
Pull Request resolved: https://github.com/facebook/prepack/pull/2247

Differential Revision: D8827425

Pulled By: trueadm

fbshipit-source-id: d05f539e2c8a6dce15b7f23c1b76e89087437738
2018-07-12 23:40:53 -07:00
Dominic Gannaway
1412ffa1ed Further optimize Object.assign (#2246)
Summary:
Release notes: Object.assign should no longer lose values when snapshotting in certain cases

Fixes https://github.com/facebook/prepack/issues/2240. This PR does a few things:

- Improves the value of Object.assign when snapshots are involved. Previously, the `removeProperties` property passed to `getSnapshot` was being called in all cases, now it only does it when it makes sense – i.e. the next "source" is partial. I've explained this in comments and broken this logic out into its own function.
- Removed the duplicate Object.assign logic for `react/utils`, we no longer need this as the fallback route never gets triggered anymore and it's just dead code.
- Updated the dead code tests with assertions to ensure we check the $ variable matches the Object.assign and also updated a few tests that were affected by this PR (as the Object.assign variable changed).
Pull Request resolved: https://github.com/facebook/prepack/pull/2246

Differential Revision: D8827443

Pulled By: trueadm

fbshipit-source-id: ec600baf7d08916b6c62f0aeaa09d739fba4415b
2018-07-12 16:08:50 -07:00
Herman Venter
ca8a08b47f Remove the now dead vestiges of ErasedAbruptCompletion (#2237)
Summary:
Release note: none

This just removes code that became redundant because of earlier PRs. To put it another way: ErasedAbruptCompletion is now gone!!!
Pull Request resolved: https://github.com/facebook/prepack/pull/2237

Differential Revision: D8811164

Pulled By: hermanventer

fbshipit-source-id: c7ca973f5ab6f3f7b5d4d78f70e2a3590cbe52e6
2018-07-11 15:10:22 -07:00
Sebastian Markbage
5f7256f17e Special case conditionals for $Set operations on abstract object (#2219)
Summary:
This lets the simplifier do it work and allows intermediate objects to be dead code eliminated.

If this looks good, I'll do $SetPartial and $Delete too.
Pull Request resolved: https://github.com/facebook/prepack/pull/2219

Differential Revision: D8809146

Pulled By: sebmarkbage

fbshipit-source-id: 9fbfa87f5079b60f234ce4c1b2c745ac72a6b2af
2018-07-11 12:54:13 -07:00
Herman Venter
afc77da9a0 Allow PossiblyNormalCompletion to have both forks be normal (#2230)
Summary:
Release note: none

I'd like to get rid of ErasedAbruptCompletion and restore the invariant that any subclass of AbruptCompletion is strictly abrupt. To do that, I need to relax some invariants in PossiblyNormalCompletion.

This is also a first step towards fixing the code for composing possibly normal completions correctly.

I've pulled this out into a relatively small PR to make reviewing easier. Hence, the remaining TODO in the code.

Even this smallish change results in some regression because previously different code paths were followed that allowed simplification to succeed that will now fail. Fixing that is too ambitious for this PR and will have to wait.
Pull Request resolved: https://github.com/facebook/prepack/pull/2230

Differential Revision: D8808922

Pulled By: hermanventer

fbshipit-source-id: 4afce5e27bc30290b2b237b40c1e92f8c22bd100
2018-07-11 12:13:37 -07:00
Dan Abramov
ec37b77b6e Run Prettier for serializer tests too (#2234)
Summary:
Follow-up to https://github.com/facebook/prepack/pull/2212.
Pull Request resolved: https://github.com/facebook/prepack/pull/2234

Differential Revision: D8788834

Pulled By: gaearon

fbshipit-source-id: 08937736bed3df0ea13d5e7a3925fb2f58633d5c
2018-07-11 03:55:11 -07:00
Herman Venter
8f3ce551f8 Small tweak to solve a pressing instance of a more general problem (#2239)
Summary:
Release note: none

Resolves #2238

This is a quick fix for the above issue. The underlying cause is that we do not construct completions with effects, but rely on incremental updates in special situations, such as the constructor for ForkedAbruptCompletions.

I'll try to fix the underlying cause in a subsequent PR.
Pull Request resolved: https://github.com/facebook/prepack/pull/2239

Differential Revision: D8795886

Pulled By: hermanventer

fbshipit-source-id: 677f2481ae3d6463a73f36a7e7106afbd92b068e
2018-07-10 17:40:29 -07:00
Chris Blappert
91847ea6ba Make optimized functions produce compiler diagnostic on mutating non-… (#2175)
Summary:
…local state

The logic was already there for the React Compiler's invocations of evaluatePure, this PR just generalizes it a little to be used for optmized functions as well.

Additionally, adds the ability to check for compiler info/warning logs in test-runner + updates test-error-handler.

See #1589
Pull Request resolved: https://github.com/facebook/prepack/pull/2175

Differential Revision: D8786744

Pulled By: cblappert

fbshipit-source-id: 110a4732dd6bd129b4d91047c3c9a24f5249a5e9
2018-07-10 12:10:41 -07:00
Chris Blappert
c943ced74e Allow __optimize to work in conditional contexts (#2214)
Summary:
Release Notes: None

Before `__optimize` wouldn't work when called in a conditional context, now if `__optimize` is called in some conditional context, we extract the FunctionValue from the AbstractValue in the `__optimizedFunctions` map.

Also fixes a bug where __optimize would silently noop when given something other than an `ECMAScriptSourceFunctionValue` causing two tests to fail with `TypeError`. Issue #2213 is setup to track this.
Pull Request resolved: https://github.com/facebook/prepack/pull/2214

Differential Revision: D8785643

Pulled By: cblappert

fbshipit-source-id: 3db992d693dd431aa8a2c5e6eb7ad0a1ecb6b79e
2018-07-10 10:34:20 -07:00
Dan Abramov
66351887d3 Run Prettier checks on CI (#2212)
Summary:
This will fail CI if we forgot to run `yarn prettier` before committing.
We do the same in React repo. It prevents committing stale files that later cause unexpected changes.
Pull Request resolved: https://github.com/facebook/prepack/pull/2212

Differential Revision: D8784406

Pulled By: gaearon

fbshipit-source-id: ca948b8e088be8886c8ba865f280ba8d72750f69
2018-07-10 09:55:23 -07:00
Nikolai Tillmann
d456e64116 Add ability to rewrite generated code via global.__output (#2218)
Summary:
Release notes: Add ability to rewrite generated code via global.__output

When a special global variable __output is set to an object,
then all global generator entries are forgotten
and replaced by a series of assignments to reflecting the key-value
pairs of the __output object.

This is needed for instant render to emit single render functions only.
Pull Request resolved: https://github.com/facebook/prepack/pull/2218

Differential Revision: D8778269

Pulled By: NTillmann

fbshipit-source-id: 1dbc5ddd68aa5fd7845da8a7f551c8c7ba2b8919
2018-07-09 19:09:51 -07:00
Dominic Gannaway
db5ed0c7d3 Optimize Object.assign calls by merging the temporal entries together where possible (#2206)
Summary:
Release notes: adds an optimization to Object.assign that attempts to merge calls together where possible

I frequently see `Objet.assign` calls litter our internal bundle. Many of them can actually be merged together to reduce bloat and runtime overhead (on that matter, `Object.assign` isn't a cheap call). We do this by adding a new `TemporalObjectAssignEntry` entry, that allows us to add some fine-tuning of Object.assign temporal entries we create.

The new `TemporalObjectAssignEntry` entry has an optimization that aims to merge entries by checking if linked nodes, specifically the `Object.assign` calls `to` field, to see if it can literally merge the arguments of many `Object.assign`s together. If a `to` is visited and can't be omitted, it doesn't try to apply this optimization. What we end up with, is a single `Object.assign` call and the others all get dead-code eliminated away because of the `mutatesOnly` logic from earlier.
Pull Request resolved: https://github.com/facebook/prepack/pull/2206

Reviewed By: NTillmann

Differential Revision: D8775391

Pulled By: trueadm

fbshipit-source-id: 41e5d6bb1d51fcfff66b2fe758bd51492ec472d9
2018-07-09 16:54:43 -07:00
Caleb Meredith
85b70951d9 Fix React library visiting logic (#2223)
Summary:
> I’m learning the Prepack/React Fusion codebase, so incorrect assumptions and limited a understanding of systems on my part are both very likely.

While I was experimenting with the React Compiler codebase I found the following invariant violation with the test case after that when using `create-element` as the `reactOutput`.

```
Invariant Violation: value must have been visited
```

```js
const React = require("react");

__evaluatePureFunction(() => {
  function Foo(props) {
    return <React.Fragment />;
  }

  __optimizeReactComponentTree(Foo);

  module.exports = Foo;
});
```

[[Prepack REPL]](https://prepack.io/repl.html#MYewdgzgLgBASgUwIbFgXhgJwQRwK4CW2AFAETYpSkCUA3AFD0D6TCAbkgDZ5JQIAKebADE8YVAXDFi1GGgB8MAN70YMAGZiJ4GMJAhiAB0whDEWSrVrsUIWBgAeRJQB0wzEgDmAWwRhYAPTyDGoAvoxqLKZQBN4EAF4IzqgAwiDehuB+UAAq2AjEeiB0ETDeIAAmeJwILggAHpmYUBByuvoMoSVAA)

After digging in more, I discovered that this was the same issue which required some clowniness in the React Compiler tests to workaround.

e3f4262c9d/test/react/setupReactTests.js (L116-L119)

The problem with my example is that the React library was not being visited when a `React.Fragment` appeared even though the serializer needed the library to be visited to output code.

This diff makes sure we visit the React library when we see a `React.Fragment` and makes sure we don’t over visit the React library in `jsx` mode.

I also refactored this area of the code and added comments. Let me know if my refactors or comments don’t make sense.
Pull Request resolved: https://github.com/facebook/prepack/pull/2223

Reviewed By: trueadm

Differential Revision: D8774047

Pulled By: calebmer

fbshipit-source-id: 775a626b8a6bd33a5366e6dae6727350835b060e
2018-07-09 16:04:03 -07:00
Herman Venter
e3f4262c9d Traverse all normal paths when pushing path conditions (#2201)
Summary:
Release note: none

Resolves: #2207

When a PossiblyNormalCompletion has more than one normal path, it is not correct to push only the path leading to the nominally normal completion. Surprisingly, this has not caused all sorts of havoc so far, but clearly this needs fixing.

Interestingly, these changes did uncover some latent bugs, hence the additional changes here.

Testing this more thoroughly will be much easier once PNC composition is fixed. That will take a while, but this PR will help facilitate that.
Pull Request resolved: https://github.com/facebook/prepack/pull/2201

Differential Revision: D8754966

Pulled By: hermanventer

fbshipit-source-id: 220ddc80eaff69b8ee93f75c1943ee1a16adcdee
2018-07-06 15:10:12 -07:00
Herman Venter
7aa5455148 Update test262 submodule hash
Summary: Update the test262 submodule to the latest version.

Reviewed By: cblappert

Differential Revision: D8753974

fbshipit-source-id: 6ba4904969dbe3c529dd73e1d20d227bf6e5c226
2018-07-06 14:25:54 -07:00
Dominic Gannaway
3cd3dd8431 Reduce React bloat on equivalent objects with similar temporal alias trees (#2193)
Summary:
Release notes: none

In an attempt to pull out some of the work from https://github.com/facebook/prepack/pull/2148 to make things easier to consume and review. This PR is one part, where we check the temporal alias values (if an object value has it) and see if we can dedupe the trees. Example below:
Closes https://github.com/facebook/prepack/pull/2193

Differential Revision: D8732542

Pulled By: trueadm

fbshipit-source-id: 352d0048acfef69b5a257c0fe280435fa7baaa7f
2018-07-05 05:09:30 -07:00
Dominic Gannaway
ef7e1873fa Support React keys in array branches, fixes #2139 (#2157)
Summary:
Release notes: none

Add logic to support adding keys when inlining arrays. Fixes https://github.com/facebook/prepack/issues/2139.
Closes https://github.com/facebook/prepack/pull/2157

Differential Revision: D8732339

Pulled By: trueadm

fbshipit-source-id: cfb1fe8725522e3eba5e1061832ddba8359484bb
2018-07-04 08:23:26 -07:00
Dominic Gannaway
2c79cb103d Ensure we handle numeric properties on $GetPartial path (#2205)
Summary:
Release notes: none

We were missing logic for handling abstract arrays with unknown numeric properties when we attempt to get a partial value on the array. I've added a regression test too.
Closes https://github.com/facebook/prepack/pull/2205

Differential Revision: D8732181

Pulled By: trueadm

fbshipit-source-id: 6002eac4b7d4d0b842407a3bb9ea9bcec19f486b
2018-07-04 07:39:05 -07:00
Dominic Gannaway
5f444abbda @allow-large-files [prepack][PR] Adds React native mocks (#2096)
Summary:
Release notes: adds React Native mocks to Prepack

This adds React Native mocks to Prepack and a few basic tests to demonstrate inlining of `View` and `Text`.
Closes https://github.com/facebook/prepack/pull/2096

Differential Revision: D8723932

Pulled By: NTillmann

fbshipit-source-id: 38bd265cd8935ebdf30266ec337378b4ea5b09d6
2018-07-03 14:44:41 -07:00
Sapan Bhatia
e9ef64da0e Support injection of residual statements. Support dynamic invariants. (#2195)
Summary:
Release notes: Support dynamic invariants via __assume

Resolves #2171. Implements an __assume primitive that injects dynamic invariants into the code.

Source:
```js
x = __abstract("number", "5");
__invariant(x==5, "x should be 5");
```

Generated:
```js
(function () {
  var _$0 = this;
  var _0 = 5;
  _$0.x = _0;

  var _1 = _0 == 5;
  if (!_1) {
    throw new Error("x should be 5");
  }
}).call(this);
```
Closes https://github.com/facebook/prepack/pull/2195

Reviewed By: hermanventer

Differential Revision: D8725726

Pulled By: sb98052

fbshipit-source-id: 28db3272199cdb9ae669062344eb82f0ef619bd4
2018-07-03 12:09:49 -07:00
Herman Venter
f12e0369f0 Do not always give up when running Array.map over an abstract array. (#2173)
Summary:
Release note: Enhanced handling of Array.map applied to abstract arrays

Fixes #2169.

If an abstract array is the join or a few concrete arrays, we apply the map over all of the concrete arrays and join the results. This is a bit of a hack, much like what we have for switch statements. The code from the latter has been factored out and reused for this.
Closes https://github.com/facebook/prepack/pull/2173

Differential Revision: D8721507

Pulled By: hermanventer

fbshipit-source-id: e08f2dc1d7e78c7b59f9ff7c76ad54b398b8afe9
2018-07-02 19:23:38 -07:00
Herman Venter
b6ce555f37 Ensure temporal assignments are not lost when the value does not change. (#2197)
Summary:
Release note: Fix temporal assignments to intrinsics that happen inside non deterministic loops

Tweak the property set logic to not short circuit when the target object is intrinsic and the RH value is the same as the current (tracked) property value.

Also fix the code generator for loop bodies to not get upset when the lh side is temporal, but rh side is not widened (because it is a constant).
Closes https://github.com/facebook/prepack/pull/2197

Differential Revision: D8721001

Pulled By: hermanventer

fbshipit-source-id: d38565a40fa7ab8b4e30596f0e1dcfc655a4fb5e
2018-07-02 17:55:04 -07:00
Herman Venter
466d19ddfd Special case "x === undefined || x === null" kind of expressions (#2188)
Summary:
Release note: special case expression simplification for Instant Render

When instant render is enabled turn x === undefined || x === null into __cannotBecomeObject(x) so that Instant Render can easily compile it down to a single byte code.
Closes https://github.com/facebook/prepack/pull/2188

Differential Revision: D8716594

Pulled By: hermanventer

fbshipit-source-id: bbcb25462f79852d8deac29bfed62e86745e5589
2018-07-02 13:39:35 -07:00
Dominic Gannaway
67a47fd48f Improve fb-www mocks objectWithoutProperties value by ensuring we store known values (#2194)
Summary:
Release notes: none

When the `objectWithoutProperties` mock was originally created, my knowledge of Prepack's internals wasn't as good as it was now. Now that I understand how AbstractObjectValues work, we can safely add the known values in `objectWithoutProperties` to the abstract backing object. The backing object was missing these values before and was an empty empty that was partial. This should give more data and value on our internal bundle, where before the values would be lost unnecessarily.
Closes https://github.com/facebook/prepack/pull/2194

Differential Revision: D8716289

Pulled By: trueadm

fbshipit-source-id: 451065473ea09943831f75c0bc15490e73c8d947
2018-07-02 13:11:28 -07:00
Dan Abramov
5159b0d832 Make React tests fast (#2187)
Summary:
Currently we have a single giant file with all tests, and a giant snapshot. This is both slow, and hard to work with and iterate on.

In this PR I will refactor our test setup.

- [x] Split it up into multiple files (gets the test running from 45s to 27s)
- [x] Run Prettier on test files
- [x] Split tests further for better performance
- [x] Make it possible to run one test file
- [x] Fix the issue with double test re-runs in watch mode on changes in the test file
- [x] Refactor error handling
- [x] Run Prettier on fixtures
- [x] Add a fast mode with `yarn test-react-fast <Filename>`
- [x] Fix double reruns on failure

Potential followups:
- [x] Figure out why test interruption broke (need https://github.com/facebook/jest/issues/6599 and https://github.com/facebook/jest/issues/6598 fixed)
- [x] Revisit weird things like `this['React']` assignment with a funny comment in every test
Closes https://github.com/facebook/prepack/pull/2187

Differential Revision: D8713639

Pulled By: gaearon

fbshipit-source-id: 5edbfa4e61610ecafff17c0e5e7f84d44cd51168
2018-07-02 11:25:58 -07:00