prepack/scripts/test262-runner.js

1575 lines
50 KiB
JavaScript
Raw Permalink Normal View History

2015-10-15 02:59:41 +03:00
/**
* Copyright (c) 2017-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*/
/* @flow */
/* eslint-disable no-extend-native */
2015-10-15 02:59:41 +03:00
import { AbruptCompletion, ThrowCompletion } from "../lib/completions.js";
import { ObjectValue, StringValue } from "../lib/values/index.js";
import { Realm, ExecutionContext } from "../lib/realm.js";
import construct_realm from "../lib/construct_realm.js";
Refactor global intrinsics initialization (#477) We used initialize all possible environments in a single intrinsics entry point. That doesn't quite scale to many and complex environments. So the goal of this refactor is to invert the initialization of globals. Now a Realm is created with only the standard ECMA262 intrinsics. This is also important because we should be able to create new realms from within user code to model things like iframes, node.js contextify and the new standard Realm API that is used to create new realms. All of these basically starts out with a standard realm that can then be expanded. Then the actual initialization of the global happens outside of the serializer so that the serializer dependency isn't coupled to any particular set of environments. To do this I created a "global.js" file for each environment inside of intrinsics. It's interesting to note that "console" and timers isn't part of the standard realm. Another interesting one is that "global" isn't actually part of the DOM environment yet. It might be if this proposal gets through: https://github.com/tc39/proposal-global However, since so many tests depend on global, including in test262, I model it as already part of ECMA262 globals. I also had move the initialization of the realm out of the serializer API so that it is possible to initialize the realm with arbitrary intrinsics before that happens. However, when I did that I had to move the attaching of of the generator into the serializer because otherwise mutations to intrinsics during initialization gets tracked as something to serialize. This might help avoid the cycle problem that construct_realm was meant to fix so that we can just go back to using a simple constructor for Realm.
2017-04-28 04:11:37 +03:00
import initializeGlobals from "../lib/globals.js";
import { DetachArrayBuffer } from "../lib/methods/arraybuffer.js";
import { To } from "../lib/singletons.js";
import { Get } from "../lib/methods/get.js";
import invariant from "../lib/invariant.js";
Add serializer mode for test262 execution (#2290) Summary: I want to better understand the bugs we have in abstract evaluation. One of my ideas to do this is to replace all the literals in test262 tests with abstract values and see what our test coverage is. The first step to do this is to serialize the test262 sources after running them in Prepack and checking if their generated JavaScript runs correctly. This PR does that by adding a `--serializer` flag. With my methodology, all test262 harnesses are serialized every time since they are in the global scope. This unfortunately seems to be unavoidable since doing otherwise would change program semantics and break the tests. Running `time yarn test-test262` takes about 2 minutes and has a 98% pass rate. Running `time yarn test-test262 --serializer` takes about 5 minutes and has a 95% pass rate. [Here’s a diff of the two results.](https://gist.github.com/calebmer/1c9fe396b63ba055458c599c2be18a58) [Here is a selection of some of the bugs](https://gist.github.com/calebmer/1ac381096a4aa7be1fc7dc2163276ab4) in the serializer caught by running test262 with the Prepack serializer. I might open issues for these, but they can be a bit pedantic. I might fix some of them depending on how important they are to the React code we want to compile. Notably we have: - Lots of invariants being triggered. I particularly saw [a lot of this invariant](https://github.com/facebook/prepack/blob/7d355ef4c5f4d939742814714a78ef9b1279f9b4/src/serializer/ResidualHeapVisitor.js#L531). (An example of this is [`07.md`](https://gist.github.com/calebmer/1ac381096a4aa7be1fc7dc2163276ab4#file-07-md).) - Lots of values that are visited, but not serialized. (An example of this is [`01.md`](https://gist.github.com/calebmer/1ac381096a4aa7be1fc7dc2163276ab4#file-01-md).) - Some incorrect outputs only caught by executing code. Could not be caught by static analysis. Particularly around class serialization. I’ll build off this PR to get coverage for the abstract evaluator next, but I found these results interesting on their own so decided to do this in two PRs. Pull Request resolved: https://github.com/facebook/prepack/pull/2290 Differential Revision: D8908479 Pulled By: calebmer fbshipit-source-id: aa57d47611fbd92af33e4647fed7bf7990fb6de1
2018-07-19 04:48:13 +03:00
import { prepackSources } from "../lib/prepack-node.js";
2015-10-15 02:59:41 +03:00
import yaml from "js-yaml";
import chalk from "chalk";
import path from "path";
// need to use graceful-fs for single-process code because it opens too many
// files
import fs from "graceful-fs";
import cluster from "cluster";
import os from "os";
import tty from "tty";
import minimist from "minimist";
import process from "process";
Add serializer mode for test262 execution (#2290) Summary: I want to better understand the bugs we have in abstract evaluation. One of my ideas to do this is to replace all the literals in test262 tests with abstract values and see what our test coverage is. The first step to do this is to serialize the test262 sources after running them in Prepack and checking if their generated JavaScript runs correctly. This PR does that by adding a `--serializer` flag. With my methodology, all test262 harnesses are serialized every time since they are in the global scope. This unfortunately seems to be unavoidable since doing otherwise would change program semantics and break the tests. Running `time yarn test-test262` takes about 2 minutes and has a 98% pass rate. Running `time yarn test-test262 --serializer` takes about 5 minutes and has a 95% pass rate. [Here’s a diff of the two results.](https://gist.github.com/calebmer/1c9fe396b63ba055458c599c2be18a58) [Here is a selection of some of the bugs](https://gist.github.com/calebmer/1ac381096a4aa7be1fc7dc2163276ab4) in the serializer caught by running test262 with the Prepack serializer. I might open issues for these, but they can be a bit pedantic. I might fix some of them depending on how important they are to the React code we want to compile. Notably we have: - Lots of invariants being triggered. I particularly saw [a lot of this invariant](https://github.com/facebook/prepack/blob/7d355ef4c5f4d939742814714a78ef9b1279f9b4/src/serializer/ResidualHeapVisitor.js#L531). (An example of this is [`07.md`](https://gist.github.com/calebmer/1ac381096a4aa7be1fc7dc2163276ab4#file-07-md).) - Lots of values that are visited, but not serialized. (An example of this is [`01.md`](https://gist.github.com/calebmer/1ac381096a4aa7be1fc7dc2163276ab4#file-01-md).) - Some incorrect outputs only caught by executing code. Could not be caught by static analysis. Particularly around class serialization. I’ll build off this PR to get coverage for the abstract evaluator next, but I found these results interesting on their own so decided to do this in two PRs. Pull Request resolved: https://github.com/facebook/prepack/pull/2290 Differential Revision: D8908479 Pulled By: calebmer fbshipit-source-id: aa57d47611fbd92af33e4647fed7bf7990fb6de1
2018-07-19 04:48:13 +03:00
import vm from "vm";
Add abstract serializer mode for test262 execution (#2297) Summary: I extended the `--serializer` command line argument I added in #2290 to now support `--serializer abstract-scalar`. What this mode does is it converts all boolean, string, number, and symbol literals into abstract values. I did not choose to extend this logic to object and array literals just yet since scalars alone showed some interesting results. What I really want here is a review of the results. Full suite execution results are real bad. **18%** pass rate. I dug a bit into why. ``` === RESULTS === Passes: 3356 / 17780 (18%) ES5 passes: 2276 / 12045 (18%) ES6 passes: 1080 / 5735 (18%) Skipped: 13375 Timeouts: 28 ``` I was mostly interested in the runtime failures we see since that means Prepack is serializing invalid code. However, I found ~14k failures in the Prepack stage (more on this in a bit) and ~3k failures in the runtime stage. This means ~80% of tests _fail to compile_ with this abstract transformation applied. Why are these tests failing? I took the first 4 items of the stack traces from errors thrown in the Prepack stage, sorted, and ranked them. [Here’s the result.](https://gist.github.com/calebmer/29e27613325fd99fa04be7ab4a9641c0) The top 5 with thousands of hits are: ``` 7538 of: at AbstractValue.throwIfNotConcrete (/Users/calebmer/prepack/src/values/AbstractValue.js:536:11) at ToImplementation.ToStringPartial (/Users/calebmer/prepack/src/methods/to.js:717:69) at NativeFunctionValue._index.NativeFunctionValue [as callback] (/Users/calebmer/prepack/src/intrinsics/ecma262/String.js:34:37) at NativeFunctionValue.callCallback (/Users/calebmer/prepack/src/values/NativeFunctionValue.js:121:12) 4595 of: at AbstractValue.throwIfNotConcrete (/Users/calebmer/prepack/src/values/AbstractValue.js:536:11) at NativeFunctionValue.func.defineNativeMethod [as callback] (/Users/calebmer/prepack/src/intrinsics/ecma262/Object.js:328:41) at NativeFunctionValue.callCallback (/Users/calebmer/prepack/src/values/NativeFunctionValue.js:121:12) at functionCall (/Users/calebmer/prepack/src/methods/call.js:308:26) 1454 of: at AbstractValue.throwIfNotConcrete (/Users/calebmer/prepack/src/values/AbstractValue.js:536:11) at NativeFunctionValue.func.defineNativeMethod [as callback] (/Users/calebmer/prepack/src/intrinsics/ecma262/Object.js:364:41) at NativeFunctionValue.callCallback (/Users/calebmer/prepack/src/values/NativeFunctionValue.js:121:12) at functionCall (/Users/calebmer/prepack/src/methods/call.js:308:26) 1351 of: at invariant (/Users/calebmer/prepack/src/invariant.js:18:15) at EvalPropertyNamePartial (/Users/calebmer/prepack/src/evaluators/ObjectExpression.js:59:7) at _default (/Users/calebmer/prepack/src/evaluators/ObjectExpression.js:80:21) at LexicalEnvironment.evaluateAbstract (/Users/calebmer/prepack/src/environment.js:1368:20) 1053 of: at AbstractValue.throwIfNotConcrete (/Users/calebmer/prepack/src/values/AbstractValue.js:536:11) at NativeFunctionValue.obj.defineNativeMethod [as callback] (/Users/calebmer/prepack/src/intrinsics/ecma262/ObjectPrototype.js:35:39) at NativeFunctionValue.callCallback (/Users/calebmer/prepack/src/values/NativeFunctionValue.js:121:12) at functionCall (/Users/calebmer/prepack/src/methods/call.js:308:26) ``` This means there may be some low hanging fruit. Here are my questions for you. - Did you expect results like this? - What is our ideal test262 pass rate with this transformation applied? - What happens to React Compiler or other projects when these errors are thrown? (As I understand it, we bail out and don’t optimize the code, but do optimize the code around it.) - Do you think my methodology is flawed? It’s also possible that something in my methodology is wrong, but I didn’t spend much time investigating these failures as I spent investigating the failures I found in #2290. My goal with this test suite is to build an understanding of what “correctness” for the React Compiler against all JavaScript code looks like. (Not just the few bundles we’ve selected to look at.) I don’t think these results suggest that we only safely compile 18% of the language, but it’s a data point. I’ll be looking into fixing a selection of these issues to better understand their nature or if I need to change methodologies. Pull Request resolved: https://github.com/facebook/prepack/pull/2297 Differential Revision: D9120572 Pulled By: calebmer fbshipit-source-id: b394f1e8da034c9985366010e3e63fd55fd94168
2018-08-01 20:28:28 +03:00
import * as babelTypes from "@babel/types";
import traverse from "@babel/traverse";
import generate from "@babel/generator";
2015-10-15 02:59:41 +03:00
const EOL = os.EOL;
const cpus = os.cpus();
const numCPUs = cpus ? cpus.length : 1;
require("source-map-support").install();
2015-10-15 02:59:41 +03:00
type HarnessMap = { [key: string]: string };
2015-10-15 02:59:41 +03:00
type TestRecord = { test: TestFileInfo, result: TestResult[] };
type GroupsMap = { [key: string]: TestRecord[] };
Add serializer mode for test262 execution (#2290) Summary: I want to better understand the bugs we have in abstract evaluation. One of my ideas to do this is to replace all the literals in test262 tests with abstract values and see what our test coverage is. The first step to do this is to serialize the test262 sources after running them in Prepack and checking if their generated JavaScript runs correctly. This PR does that by adding a `--serializer` flag. With my methodology, all test262 harnesses are serialized every time since they are in the global scope. This unfortunately seems to be unavoidable since doing otherwise would change program semantics and break the tests. Running `time yarn test-test262` takes about 2 minutes and has a 98% pass rate. Running `time yarn test-test262 --serializer` takes about 5 minutes and has a 95% pass rate. [Here’s a diff of the two results.](https://gist.github.com/calebmer/1c9fe396b63ba055458c599c2be18a58) [Here is a selection of some of the bugs](https://gist.github.com/calebmer/1ac381096a4aa7be1fc7dc2163276ab4) in the serializer caught by running test262 with the Prepack serializer. I might open issues for these, but they can be a bit pedantic. I might fix some of them depending on how important they are to the React code we want to compile. Notably we have: - Lots of invariants being triggered. I particularly saw [a lot of this invariant](https://github.com/facebook/prepack/blob/7d355ef4c5f4d939742814714a78ef9b1279f9b4/src/serializer/ResidualHeapVisitor.js#L531). (An example of this is [`07.md`](https://gist.github.com/calebmer/1ac381096a4aa7be1fc7dc2163276ab4#file-07-md).) - Lots of values that are visited, but not serialized. (An example of this is [`01.md`](https://gist.github.com/calebmer/1ac381096a4aa7be1fc7dc2163276ab4#file-01-md).) - Some incorrect outputs only caught by executing code. Could not be caught by static analysis. Particularly around class serialization. I’ll build off this PR to get coverage for the abstract evaluator next, but I found these results interesting on their own so decided to do this in two PRs. Pull Request resolved: https://github.com/facebook/prepack/pull/2290 Differential Revision: D8908479 Pulled By: calebmer fbshipit-source-id: aa57d47611fbd92af33e4647fed7bf7990fb6de1
2018-07-19 04:48:13 +03:00
type TestRunOptions = {|
+timeout: number,
Add abstract serializer mode for test262 execution (#2297) Summary: I extended the `--serializer` command line argument I added in #2290 to now support `--serializer abstract-scalar`. What this mode does is it converts all boolean, string, number, and symbol literals into abstract values. I did not choose to extend this logic to object and array literals just yet since scalars alone showed some interesting results. What I really want here is a review of the results. Full suite execution results are real bad. **18%** pass rate. I dug a bit into why. ``` === RESULTS === Passes: 3356 / 17780 (18%) ES5 passes: 2276 / 12045 (18%) ES6 passes: 1080 / 5735 (18%) Skipped: 13375 Timeouts: 28 ``` I was mostly interested in the runtime failures we see since that means Prepack is serializing invalid code. However, I found ~14k failures in the Prepack stage (more on this in a bit) and ~3k failures in the runtime stage. This means ~80% of tests _fail to compile_ with this abstract transformation applied. Why are these tests failing? I took the first 4 items of the stack traces from errors thrown in the Prepack stage, sorted, and ranked them. [Here’s the result.](https://gist.github.com/calebmer/29e27613325fd99fa04be7ab4a9641c0) The top 5 with thousands of hits are: ``` 7538 of: at AbstractValue.throwIfNotConcrete (/Users/calebmer/prepack/src/values/AbstractValue.js:536:11) at ToImplementation.ToStringPartial (/Users/calebmer/prepack/src/methods/to.js:717:69) at NativeFunctionValue._index.NativeFunctionValue [as callback] (/Users/calebmer/prepack/src/intrinsics/ecma262/String.js:34:37) at NativeFunctionValue.callCallback (/Users/calebmer/prepack/src/values/NativeFunctionValue.js:121:12) 4595 of: at AbstractValue.throwIfNotConcrete (/Users/calebmer/prepack/src/values/AbstractValue.js:536:11) at NativeFunctionValue.func.defineNativeMethod [as callback] (/Users/calebmer/prepack/src/intrinsics/ecma262/Object.js:328:41) at NativeFunctionValue.callCallback (/Users/calebmer/prepack/src/values/NativeFunctionValue.js:121:12) at functionCall (/Users/calebmer/prepack/src/methods/call.js:308:26) 1454 of: at AbstractValue.throwIfNotConcrete (/Users/calebmer/prepack/src/values/AbstractValue.js:536:11) at NativeFunctionValue.func.defineNativeMethod [as callback] (/Users/calebmer/prepack/src/intrinsics/ecma262/Object.js:364:41) at NativeFunctionValue.callCallback (/Users/calebmer/prepack/src/values/NativeFunctionValue.js:121:12) at functionCall (/Users/calebmer/prepack/src/methods/call.js:308:26) 1351 of: at invariant (/Users/calebmer/prepack/src/invariant.js:18:15) at EvalPropertyNamePartial (/Users/calebmer/prepack/src/evaluators/ObjectExpression.js:59:7) at _default (/Users/calebmer/prepack/src/evaluators/ObjectExpression.js:80:21) at LexicalEnvironment.evaluateAbstract (/Users/calebmer/prepack/src/environment.js:1368:20) 1053 of: at AbstractValue.throwIfNotConcrete (/Users/calebmer/prepack/src/values/AbstractValue.js:536:11) at NativeFunctionValue.obj.defineNativeMethod [as callback] (/Users/calebmer/prepack/src/intrinsics/ecma262/ObjectPrototype.js:35:39) at NativeFunctionValue.callCallback (/Users/calebmer/prepack/src/values/NativeFunctionValue.js:121:12) at functionCall (/Users/calebmer/prepack/src/methods/call.js:308:26) ``` This means there may be some low hanging fruit. Here are my questions for you. - Did you expect results like this? - What is our ideal test262 pass rate with this transformation applied? - What happens to React Compiler or other projects when these errors are thrown? (As I understand it, we bail out and don’t optimize the code, but do optimize the code around it.) - Do you think my methodology is flawed? It’s also possible that something in my methodology is wrong, but I didn’t spend much time investigating these failures as I spent investigating the failures I found in #2290. My goal with this test suite is to build an understanding of what “correctness” for the React Compiler against all JavaScript code looks like. (Not just the few bundles we’ve selected to look at.) I don’t think these results suggest that we only safely compile 18% of the language, but it’s a data point. I’ll be looking into fixing a selection of these issues to better understand their nature or if I need to change methodologies. Pull Request resolved: https://github.com/facebook/prepack/pull/2297 Differential Revision: D9120572 Pulled By: calebmer fbshipit-source-id: b394f1e8da034c9985366010e3e63fd55fd94168
2018-08-01 20:28:28 +03:00
+serializer: boolean | "abstract-scalar",
Add serializer mode for test262 execution (#2290) Summary: I want to better understand the bugs we have in abstract evaluation. One of my ideas to do this is to replace all the literals in test262 tests with abstract values and see what our test coverage is. The first step to do this is to serialize the test262 sources after running them in Prepack and checking if their generated JavaScript runs correctly. This PR does that by adding a `--serializer` flag. With my methodology, all test262 harnesses are serialized every time since they are in the global scope. This unfortunately seems to be unavoidable since doing otherwise would change program semantics and break the tests. Running `time yarn test-test262` takes about 2 minutes and has a 98% pass rate. Running `time yarn test-test262 --serializer` takes about 5 minutes and has a 95% pass rate. [Here’s a diff of the two results.](https://gist.github.com/calebmer/1c9fe396b63ba055458c599c2be18a58) [Here is a selection of some of the bugs](https://gist.github.com/calebmer/1ac381096a4aa7be1fc7dc2163276ab4) in the serializer caught by running test262 with the Prepack serializer. I might open issues for these, but they can be a bit pedantic. I might fix some of them depending on how important they are to the React code we want to compile. Notably we have: - Lots of invariants being triggered. I particularly saw [a lot of this invariant](https://github.com/facebook/prepack/blob/7d355ef4c5f4d939742814714a78ef9b1279f9b4/src/serializer/ResidualHeapVisitor.js#L531). (An example of this is [`07.md`](https://gist.github.com/calebmer/1ac381096a4aa7be1fc7dc2163276ab4#file-07-md).) - Lots of values that are visited, but not serialized. (An example of this is [`01.md`](https://gist.github.com/calebmer/1ac381096a4aa7be1fc7dc2163276ab4#file-01-md).) - Some incorrect outputs only caught by executing code. Could not be caught by static analysis. Particularly around class serialization. I’ll build off this PR to get coverage for the abstract evaluator next, but I found these results interesting on their own so decided to do this in two PRs. Pull Request resolved: https://github.com/facebook/prepack/pull/2290 Differential Revision: D8908479 Pulled By: calebmer fbshipit-source-id: aa57d47611fbd92af33e4647fed7bf7990fb6de1
2018-07-19 04:48:13 +03:00
|};
2015-10-15 02:59:41 +03:00
// A TestTask is a task for a worker process to execute, which contains a
// single test to run
class TestTask {
static sentinel: string = "TestTask";
type: string;
file: TestFileInfo;
constructor(file: TestFileInfo) {
this.type = TestTask.sentinel;
this.file = file;
}
// eslint-disable-next-line flowtype/no-weak-types
static fromObject(obj: Object): TestTask {
// attempt to coerce the object into a test task
if ("file" in obj && typeof obj.file === "object") {
return new TestTask(TestFileInfo.fromObject(obj.file));
} else {
throw new Error(`Cannot be converted to a TestTask: ${JSON.stringify(obj)}`);
2015-10-15 02:59:41 +03:00
}
}
}
/**
* Information about a test file to be run.
*
*/
class TestFileInfo {
// Location of the test on the filesystem, call fs.readFile on this
location: string;
isES6: boolean;
groupName: string;
constructor(location: string, isES6: boolean) {
this.location = location;
this.isES6 = isES6;
this.groupName = path.dirname(location);
}
// eslint-disable-next-line flowtype/no-weak-types
static fromObject(obj: Object): TestFileInfo {
// attempt to coerce the object into a TestFileInfo
if ("location" in obj && typeof obj.location === "string" && "isES6" in obj && typeof obj.isES6 === "boolean") {
2015-10-15 02:59:41 +03:00
return new TestFileInfo(obj.location, obj.isES6);
} else {
throw new Error(`Cannot be converted to a TestFileInfo: ${JSON.stringify(obj)}`);
2015-10-15 02:59:41 +03:00
}
}
}
// A Message sent by a worker to the master to say that it has finished its
// current task successfully
class DoneMessage {
static sentinel: string = "DoneMessage";
type: string;
test: TestFileInfo;
testResults: TestResult[];
constructor(test: TestFileInfo, testResult: TestResult[] = []) {
this.type = DoneMessage.sentinel;
this.test = test;
this.testResults = testResult;
}
// eslint-disable-next-line flowtype/no-weak-types
static fromObject(obj: Object): DoneMessage {
if (!("type" in obj && typeof obj.type === "string" && obj.type === DoneMessage.sentinel)) {
throw new Error(`Cannot be converted to a DoneMessage: ${JSON.stringify(obj)}`);
2015-10-15 02:59:41 +03:00
}
if (!("test" in obj && typeof obj.test === "object")) {
throw new Error("A DoneMessage must have a test");
}
let msg = new DoneMessage(obj.test);
if ("testResults" in obj && typeof obj.testResults === "object" && Array.isArray(obj.testResults)) {
2015-10-15 02:59:41 +03:00
msg.testResults = obj.testResults;
}
return msg;
}
}
class ErrorMessage {
static sentinel: string = "ErrorMessage";
type: string;
err: Error;
constructor(err: Error) {
this.type = ErrorMessage.sentinel;
this.err = err;
}
// eslint-disable-next-line flowtype/no-weak-types
static fromObject(obj: Object): ErrorMessage {
if (!("type" in obj && typeof obj.type === "string" && obj.type === ErrorMessage.sentinel)) {
throw new Error(`Cannot be converted to an ErrorMessage: ${JSON.stringify(obj)}`);
2015-10-15 02:59:41 +03:00
}
if (!("err" in obj && typeof obj.err === "object")) {
throw new Error(`Cannot be converted to an ErrorMessage: ${JSON.stringify(obj)}`);
2015-10-15 02:59:41 +03:00
}
return new ErrorMessage(obj.err);
}
}
/**
* TestResult contains information about a test that ran.
*/
class TestResult {
passed: boolean;
strict: boolean;
err: ?Error;
constructor(passed: boolean, strict: boolean, err: ?Error = null) {
2015-10-15 02:59:41 +03:00
this.passed = passed;
this.strict = strict;
this.err = err;
}
}
// A Message sent by the master to workers to say that there is nothing more
// to do
class QuitMessage {
static sentinel: string = "QuitMessage";
type: string;
constructor() {
this.type = QuitMessage.sentinel;
}
static fromObject(obj): QuitMessage {
return new QuitMessage();
}
}
class BannerData {
info: string;
es5id: string;
es6id: string;
2015-10-15 02:59:41 +03:00
description: string;
flags: string[];
features: string[];
includes: string[];
// eslint-disable-next-line flowtype/no-weak-types
negative: Object;
constructor() {
this.info = "";
this.es5id = "";
this.es6id = "";
2015-10-15 02:59:41 +03:00
this.description = "";
this.flags = [];
this.features = [];
this.includes = [];
this.negative = {};
}
// eslint-disable-next-line flowtype/no-weak-types
static fromObject(obj: Object): BannerData {
let bd = new BannerData();
if ("info" in obj && typeof obj.info === "string") {
bd.info = obj.info;
}
if ("es5id" in obj && typeof obj.es5id === "string") {
bd.es5id = obj.es5id;
}
if ("es6id" in obj && typeof obj.es6id === "string") {
bd.es6id = obj.es6id;
}
2015-10-15 02:59:41 +03:00
if ("description" in obj && typeof obj.description === "string") {
bd.description = obj.description;
}
if ("flags" in obj && typeof obj.flags === "object" && Array.isArray(obj.flags)) {
bd.flags = obj.flags;
}
if ("features" in obj && typeof obj.features === "object" && Array.isArray(obj.features)) {
bd.features = obj.features;
}
if ("includes" in obj && typeof obj.includes === "object" && Array.isArray(obj.includes)) {
bd.includes = obj.includes;
}
if ("negative" in obj && typeof obj.negative === "object") {
bd.negative = obj.negative;
}
return bd;
}
}
class MasterProgramArgs {
verbose: boolean;
timeout: number;
bailAfter: number;
cpuScale: number;
statusFile: string;
filterString: string;
singleThreaded: boolean;
relativeTestPath: string;
Add abstract serializer mode for test262 execution (#2297) Summary: I extended the `--serializer` command line argument I added in #2290 to now support `--serializer abstract-scalar`. What this mode does is it converts all boolean, string, number, and symbol literals into abstract values. I did not choose to extend this logic to object and array literals just yet since scalars alone showed some interesting results. What I really want here is a review of the results. Full suite execution results are real bad. **18%** pass rate. I dug a bit into why. ``` === RESULTS === Passes: 3356 / 17780 (18%) ES5 passes: 2276 / 12045 (18%) ES6 passes: 1080 / 5735 (18%) Skipped: 13375 Timeouts: 28 ``` I was mostly interested in the runtime failures we see since that means Prepack is serializing invalid code. However, I found ~14k failures in the Prepack stage (more on this in a bit) and ~3k failures in the runtime stage. This means ~80% of tests _fail to compile_ with this abstract transformation applied. Why are these tests failing? I took the first 4 items of the stack traces from errors thrown in the Prepack stage, sorted, and ranked them. [Here’s the result.](https://gist.github.com/calebmer/29e27613325fd99fa04be7ab4a9641c0) The top 5 with thousands of hits are: ``` 7538 of: at AbstractValue.throwIfNotConcrete (/Users/calebmer/prepack/src/values/AbstractValue.js:536:11) at ToImplementation.ToStringPartial (/Users/calebmer/prepack/src/methods/to.js:717:69) at NativeFunctionValue._index.NativeFunctionValue [as callback] (/Users/calebmer/prepack/src/intrinsics/ecma262/String.js:34:37) at NativeFunctionValue.callCallback (/Users/calebmer/prepack/src/values/NativeFunctionValue.js:121:12) 4595 of: at AbstractValue.throwIfNotConcrete (/Users/calebmer/prepack/src/values/AbstractValue.js:536:11) at NativeFunctionValue.func.defineNativeMethod [as callback] (/Users/calebmer/prepack/src/intrinsics/ecma262/Object.js:328:41) at NativeFunctionValue.callCallback (/Users/calebmer/prepack/src/values/NativeFunctionValue.js:121:12) at functionCall (/Users/calebmer/prepack/src/methods/call.js:308:26) 1454 of: at AbstractValue.throwIfNotConcrete (/Users/calebmer/prepack/src/values/AbstractValue.js:536:11) at NativeFunctionValue.func.defineNativeMethod [as callback] (/Users/calebmer/prepack/src/intrinsics/ecma262/Object.js:364:41) at NativeFunctionValue.callCallback (/Users/calebmer/prepack/src/values/NativeFunctionValue.js:121:12) at functionCall (/Users/calebmer/prepack/src/methods/call.js:308:26) 1351 of: at invariant (/Users/calebmer/prepack/src/invariant.js:18:15) at EvalPropertyNamePartial (/Users/calebmer/prepack/src/evaluators/ObjectExpression.js:59:7) at _default (/Users/calebmer/prepack/src/evaluators/ObjectExpression.js:80:21) at LexicalEnvironment.evaluateAbstract (/Users/calebmer/prepack/src/environment.js:1368:20) 1053 of: at AbstractValue.throwIfNotConcrete (/Users/calebmer/prepack/src/values/AbstractValue.js:536:11) at NativeFunctionValue.obj.defineNativeMethod [as callback] (/Users/calebmer/prepack/src/intrinsics/ecma262/ObjectPrototype.js:35:39) at NativeFunctionValue.callCallback (/Users/calebmer/prepack/src/values/NativeFunctionValue.js:121:12) at functionCall (/Users/calebmer/prepack/src/methods/call.js:308:26) ``` This means there may be some low hanging fruit. Here are my questions for you. - Did you expect results like this? - What is our ideal test262 pass rate with this transformation applied? - What happens to React Compiler or other projects when these errors are thrown? (As I understand it, we bail out and don’t optimize the code, but do optimize the code around it.) - Do you think my methodology is flawed? It’s also possible that something in my methodology is wrong, but I didn’t spend much time investigating these failures as I spent investigating the failures I found in #2290. My goal with this test suite is to build an understanding of what “correctness” for the React Compiler against all JavaScript code looks like. (Not just the few bundles we’ve selected to look at.) I don’t think these results suggest that we only safely compile 18% of the language, but it’s a data point. I’ll be looking into fixing a selection of these issues to better understand their nature or if I need to change methodologies. Pull Request resolved: https://github.com/facebook/prepack/pull/2297 Differential Revision: D9120572 Pulled By: calebmer fbshipit-source-id: b394f1e8da034c9985366010e3e63fd55fd94168
2018-08-01 20:28:28 +03:00
serializer: boolean | "abstract-scalar";
expectedES5: number;
expectedES6: number;
expectedTimeouts: number;
2015-10-15 02:59:41 +03:00
constructor(
verbose: boolean,
timeout: number,
bailAfter: number,
cpuScale: number,
statusFile: string,
filterString: string,
singleThreaded: boolean,
relativeTestPath: string,
Add abstract serializer mode for test262 execution (#2297) Summary: I extended the `--serializer` command line argument I added in #2290 to now support `--serializer abstract-scalar`. What this mode does is it converts all boolean, string, number, and symbol literals into abstract values. I did not choose to extend this logic to object and array literals just yet since scalars alone showed some interesting results. What I really want here is a review of the results. Full suite execution results are real bad. **18%** pass rate. I dug a bit into why. ``` === RESULTS === Passes: 3356 / 17780 (18%) ES5 passes: 2276 / 12045 (18%) ES6 passes: 1080 / 5735 (18%) Skipped: 13375 Timeouts: 28 ``` I was mostly interested in the runtime failures we see since that means Prepack is serializing invalid code. However, I found ~14k failures in the Prepack stage (more on this in a bit) and ~3k failures in the runtime stage. This means ~80% of tests _fail to compile_ with this abstract transformation applied. Why are these tests failing? I took the first 4 items of the stack traces from errors thrown in the Prepack stage, sorted, and ranked them. [Here’s the result.](https://gist.github.com/calebmer/29e27613325fd99fa04be7ab4a9641c0) The top 5 with thousands of hits are: ``` 7538 of: at AbstractValue.throwIfNotConcrete (/Users/calebmer/prepack/src/values/AbstractValue.js:536:11) at ToImplementation.ToStringPartial (/Users/calebmer/prepack/src/methods/to.js:717:69) at NativeFunctionValue._index.NativeFunctionValue [as callback] (/Users/calebmer/prepack/src/intrinsics/ecma262/String.js:34:37) at NativeFunctionValue.callCallback (/Users/calebmer/prepack/src/values/NativeFunctionValue.js:121:12) 4595 of: at AbstractValue.throwIfNotConcrete (/Users/calebmer/prepack/src/values/AbstractValue.js:536:11) at NativeFunctionValue.func.defineNativeMethod [as callback] (/Users/calebmer/prepack/src/intrinsics/ecma262/Object.js:328:41) at NativeFunctionValue.callCallback (/Users/calebmer/prepack/src/values/NativeFunctionValue.js:121:12) at functionCall (/Users/calebmer/prepack/src/methods/call.js:308:26) 1454 of: at AbstractValue.throwIfNotConcrete (/Users/calebmer/prepack/src/values/AbstractValue.js:536:11) at NativeFunctionValue.func.defineNativeMethod [as callback] (/Users/calebmer/prepack/src/intrinsics/ecma262/Object.js:364:41) at NativeFunctionValue.callCallback (/Users/calebmer/prepack/src/values/NativeFunctionValue.js:121:12) at functionCall (/Users/calebmer/prepack/src/methods/call.js:308:26) 1351 of: at invariant (/Users/calebmer/prepack/src/invariant.js:18:15) at EvalPropertyNamePartial (/Users/calebmer/prepack/src/evaluators/ObjectExpression.js:59:7) at _default (/Users/calebmer/prepack/src/evaluators/ObjectExpression.js:80:21) at LexicalEnvironment.evaluateAbstract (/Users/calebmer/prepack/src/environment.js:1368:20) 1053 of: at AbstractValue.throwIfNotConcrete (/Users/calebmer/prepack/src/values/AbstractValue.js:536:11) at NativeFunctionValue.obj.defineNativeMethod [as callback] (/Users/calebmer/prepack/src/intrinsics/ecma262/ObjectPrototype.js:35:39) at NativeFunctionValue.callCallback (/Users/calebmer/prepack/src/values/NativeFunctionValue.js:121:12) at functionCall (/Users/calebmer/prepack/src/methods/call.js:308:26) ``` This means there may be some low hanging fruit. Here are my questions for you. - Did you expect results like this? - What is our ideal test262 pass rate with this transformation applied? - What happens to React Compiler or other projects when these errors are thrown? (As I understand it, we bail out and don’t optimize the code, but do optimize the code around it.) - Do you think my methodology is flawed? It’s also possible that something in my methodology is wrong, but I didn’t spend much time investigating these failures as I spent investigating the failures I found in #2290. My goal with this test suite is to build an understanding of what “correctness” for the React Compiler against all JavaScript code looks like. (Not just the few bundles we’ve selected to look at.) I don’t think these results suggest that we only safely compile 18% of the language, but it’s a data point. I’ll be looking into fixing a selection of these issues to better understand their nature or if I need to change methodologies. Pull Request resolved: https://github.com/facebook/prepack/pull/2297 Differential Revision: D9120572 Pulled By: calebmer fbshipit-source-id: b394f1e8da034c9985366010e3e63fd55fd94168
2018-08-01 20:28:28 +03:00
serializer: boolean | "abstract-scalar",
expectedES5: number,
expectedES6: number,
expectedTimeouts: number
2015-10-15 02:59:41 +03:00
) {
this.verbose = verbose;
this.timeout = timeout;
this.bailAfter = bailAfter;
this.cpuScale = cpuScale;
this.statusFile = statusFile;
this.filterString = filterString;
this.singleThreaded = singleThreaded;
this.relativeTestPath = relativeTestPath;
Add serializer mode for test262 execution (#2290) Summary: I want to better understand the bugs we have in abstract evaluation. One of my ideas to do this is to replace all the literals in test262 tests with abstract values and see what our test coverage is. The first step to do this is to serialize the test262 sources after running them in Prepack and checking if their generated JavaScript runs correctly. This PR does that by adding a `--serializer` flag. With my methodology, all test262 harnesses are serialized every time since they are in the global scope. This unfortunately seems to be unavoidable since doing otherwise would change program semantics and break the tests. Running `time yarn test-test262` takes about 2 minutes and has a 98% pass rate. Running `time yarn test-test262 --serializer` takes about 5 minutes and has a 95% pass rate. [Here’s a diff of the two results.](https://gist.github.com/calebmer/1c9fe396b63ba055458c599c2be18a58) [Here is a selection of some of the bugs](https://gist.github.com/calebmer/1ac381096a4aa7be1fc7dc2163276ab4) in the serializer caught by running test262 with the Prepack serializer. I might open issues for these, but they can be a bit pedantic. I might fix some of them depending on how important they are to the React code we want to compile. Notably we have: - Lots of invariants being triggered. I particularly saw [a lot of this invariant](https://github.com/facebook/prepack/blob/7d355ef4c5f4d939742814714a78ef9b1279f9b4/src/serializer/ResidualHeapVisitor.js#L531). (An example of this is [`07.md`](https://gist.github.com/calebmer/1ac381096a4aa7be1fc7dc2163276ab4#file-07-md).) - Lots of values that are visited, but not serialized. (An example of this is [`01.md`](https://gist.github.com/calebmer/1ac381096a4aa7be1fc7dc2163276ab4#file-01-md).) - Some incorrect outputs only caught by executing code. Could not be caught by static analysis. Particularly around class serialization. I’ll build off this PR to get coverage for the abstract evaluator next, but I found these results interesting on their own so decided to do this in two PRs. Pull Request resolved: https://github.com/facebook/prepack/pull/2290 Differential Revision: D8908479 Pulled By: calebmer fbshipit-source-id: aa57d47611fbd92af33e4647fed7bf7990fb6de1
2018-07-19 04:48:13 +03:00
this.serializer = serializer;
this.expectedES5 = expectedES5;
this.expectedES6 = expectedES6;
this.expectedTimeouts = expectedTimeouts;
2015-10-15 02:59:41 +03:00
}
}
class WorkerProgramArgs {
relativeTestPath: string;
Add serializer mode for test262 execution (#2290) Summary: I want to better understand the bugs we have in abstract evaluation. One of my ideas to do this is to replace all the literals in test262 tests with abstract values and see what our test coverage is. The first step to do this is to serialize the test262 sources after running them in Prepack and checking if their generated JavaScript runs correctly. This PR does that by adding a `--serializer` flag. With my methodology, all test262 harnesses are serialized every time since they are in the global scope. This unfortunately seems to be unavoidable since doing otherwise would change program semantics and break the tests. Running `time yarn test-test262` takes about 2 minutes and has a 98% pass rate. Running `time yarn test-test262 --serializer` takes about 5 minutes and has a 95% pass rate. [Here’s a diff of the two results.](https://gist.github.com/calebmer/1c9fe396b63ba055458c599c2be18a58) [Here is a selection of some of the bugs](https://gist.github.com/calebmer/1ac381096a4aa7be1fc7dc2163276ab4) in the serializer caught by running test262 with the Prepack serializer. I might open issues for these, but they can be a bit pedantic. I might fix some of them depending on how important they are to the React code we want to compile. Notably we have: - Lots of invariants being triggered. I particularly saw [a lot of this invariant](https://github.com/facebook/prepack/blob/7d355ef4c5f4d939742814714a78ef9b1279f9b4/src/serializer/ResidualHeapVisitor.js#L531). (An example of this is [`07.md`](https://gist.github.com/calebmer/1ac381096a4aa7be1fc7dc2163276ab4#file-07-md).) - Lots of values that are visited, but not serialized. (An example of this is [`01.md`](https://gist.github.com/calebmer/1ac381096a4aa7be1fc7dc2163276ab4#file-01-md).) - Some incorrect outputs only caught by executing code. Could not be caught by static analysis. Particularly around class serialization. I’ll build off this PR to get coverage for the abstract evaluator next, but I found these results interesting on their own so decided to do this in two PRs. Pull Request resolved: https://github.com/facebook/prepack/pull/2290 Differential Revision: D8908479 Pulled By: calebmer fbshipit-source-id: aa57d47611fbd92af33e4647fed7bf7990fb6de1
2018-07-19 04:48:13 +03:00
timeout: number;
Add abstract serializer mode for test262 execution (#2297) Summary: I extended the `--serializer` command line argument I added in #2290 to now support `--serializer abstract-scalar`. What this mode does is it converts all boolean, string, number, and symbol literals into abstract values. I did not choose to extend this logic to object and array literals just yet since scalars alone showed some interesting results. What I really want here is a review of the results. Full suite execution results are real bad. **18%** pass rate. I dug a bit into why. ``` === RESULTS === Passes: 3356 / 17780 (18%) ES5 passes: 2276 / 12045 (18%) ES6 passes: 1080 / 5735 (18%) Skipped: 13375 Timeouts: 28 ``` I was mostly interested in the runtime failures we see since that means Prepack is serializing invalid code. However, I found ~14k failures in the Prepack stage (more on this in a bit) and ~3k failures in the runtime stage. This means ~80% of tests _fail to compile_ with this abstract transformation applied. Why are these tests failing? I took the first 4 items of the stack traces from errors thrown in the Prepack stage, sorted, and ranked them. [Here’s the result.](https://gist.github.com/calebmer/29e27613325fd99fa04be7ab4a9641c0) The top 5 with thousands of hits are: ``` 7538 of: at AbstractValue.throwIfNotConcrete (/Users/calebmer/prepack/src/values/AbstractValue.js:536:11) at ToImplementation.ToStringPartial (/Users/calebmer/prepack/src/methods/to.js:717:69) at NativeFunctionValue._index.NativeFunctionValue [as callback] (/Users/calebmer/prepack/src/intrinsics/ecma262/String.js:34:37) at NativeFunctionValue.callCallback (/Users/calebmer/prepack/src/values/NativeFunctionValue.js:121:12) 4595 of: at AbstractValue.throwIfNotConcrete (/Users/calebmer/prepack/src/values/AbstractValue.js:536:11) at NativeFunctionValue.func.defineNativeMethod [as callback] (/Users/calebmer/prepack/src/intrinsics/ecma262/Object.js:328:41) at NativeFunctionValue.callCallback (/Users/calebmer/prepack/src/values/NativeFunctionValue.js:121:12) at functionCall (/Users/calebmer/prepack/src/methods/call.js:308:26) 1454 of: at AbstractValue.throwIfNotConcrete (/Users/calebmer/prepack/src/values/AbstractValue.js:536:11) at NativeFunctionValue.func.defineNativeMethod [as callback] (/Users/calebmer/prepack/src/intrinsics/ecma262/Object.js:364:41) at NativeFunctionValue.callCallback (/Users/calebmer/prepack/src/values/NativeFunctionValue.js:121:12) at functionCall (/Users/calebmer/prepack/src/methods/call.js:308:26) 1351 of: at invariant (/Users/calebmer/prepack/src/invariant.js:18:15) at EvalPropertyNamePartial (/Users/calebmer/prepack/src/evaluators/ObjectExpression.js:59:7) at _default (/Users/calebmer/prepack/src/evaluators/ObjectExpression.js:80:21) at LexicalEnvironment.evaluateAbstract (/Users/calebmer/prepack/src/environment.js:1368:20) 1053 of: at AbstractValue.throwIfNotConcrete (/Users/calebmer/prepack/src/values/AbstractValue.js:536:11) at NativeFunctionValue.obj.defineNativeMethod [as callback] (/Users/calebmer/prepack/src/intrinsics/ecma262/ObjectPrototype.js:35:39) at NativeFunctionValue.callCallback (/Users/calebmer/prepack/src/values/NativeFunctionValue.js:121:12) at functionCall (/Users/calebmer/prepack/src/methods/call.js:308:26) ``` This means there may be some low hanging fruit. Here are my questions for you. - Did you expect results like this? - What is our ideal test262 pass rate with this transformation applied? - What happens to React Compiler or other projects when these errors are thrown? (As I understand it, we bail out and don’t optimize the code, but do optimize the code around it.) - Do you think my methodology is flawed? It’s also possible that something in my methodology is wrong, but I didn’t spend much time investigating these failures as I spent investigating the failures I found in #2290. My goal with this test suite is to build an understanding of what “correctness” for the React Compiler against all JavaScript code looks like. (Not just the few bundles we’ve selected to look at.) I don’t think these results suggest that we only safely compile 18% of the language, but it’s a data point. I’ll be looking into fixing a selection of these issues to better understand their nature or if I need to change methodologies. Pull Request resolved: https://github.com/facebook/prepack/pull/2297 Differential Revision: D9120572 Pulled By: calebmer fbshipit-source-id: b394f1e8da034c9985366010e3e63fd55fd94168
2018-08-01 20:28:28 +03:00
serializer: boolean | "abstract-scalar";
2015-10-15 02:59:41 +03:00
Add abstract serializer mode for test262 execution (#2297) Summary: I extended the `--serializer` command line argument I added in #2290 to now support `--serializer abstract-scalar`. What this mode does is it converts all boolean, string, number, and symbol literals into abstract values. I did not choose to extend this logic to object and array literals just yet since scalars alone showed some interesting results. What I really want here is a review of the results. Full suite execution results are real bad. **18%** pass rate. I dug a bit into why. ``` === RESULTS === Passes: 3356 / 17780 (18%) ES5 passes: 2276 / 12045 (18%) ES6 passes: 1080 / 5735 (18%) Skipped: 13375 Timeouts: 28 ``` I was mostly interested in the runtime failures we see since that means Prepack is serializing invalid code. However, I found ~14k failures in the Prepack stage (more on this in a bit) and ~3k failures in the runtime stage. This means ~80% of tests _fail to compile_ with this abstract transformation applied. Why are these tests failing? I took the first 4 items of the stack traces from errors thrown in the Prepack stage, sorted, and ranked them. [Here’s the result.](https://gist.github.com/calebmer/29e27613325fd99fa04be7ab4a9641c0) The top 5 with thousands of hits are: ``` 7538 of: at AbstractValue.throwIfNotConcrete (/Users/calebmer/prepack/src/values/AbstractValue.js:536:11) at ToImplementation.ToStringPartial (/Users/calebmer/prepack/src/methods/to.js:717:69) at NativeFunctionValue._index.NativeFunctionValue [as callback] (/Users/calebmer/prepack/src/intrinsics/ecma262/String.js:34:37) at NativeFunctionValue.callCallback (/Users/calebmer/prepack/src/values/NativeFunctionValue.js:121:12) 4595 of: at AbstractValue.throwIfNotConcrete (/Users/calebmer/prepack/src/values/AbstractValue.js:536:11) at NativeFunctionValue.func.defineNativeMethod [as callback] (/Users/calebmer/prepack/src/intrinsics/ecma262/Object.js:328:41) at NativeFunctionValue.callCallback (/Users/calebmer/prepack/src/values/NativeFunctionValue.js:121:12) at functionCall (/Users/calebmer/prepack/src/methods/call.js:308:26) 1454 of: at AbstractValue.throwIfNotConcrete (/Users/calebmer/prepack/src/values/AbstractValue.js:536:11) at NativeFunctionValue.func.defineNativeMethod [as callback] (/Users/calebmer/prepack/src/intrinsics/ecma262/Object.js:364:41) at NativeFunctionValue.callCallback (/Users/calebmer/prepack/src/values/NativeFunctionValue.js:121:12) at functionCall (/Users/calebmer/prepack/src/methods/call.js:308:26) 1351 of: at invariant (/Users/calebmer/prepack/src/invariant.js:18:15) at EvalPropertyNamePartial (/Users/calebmer/prepack/src/evaluators/ObjectExpression.js:59:7) at _default (/Users/calebmer/prepack/src/evaluators/ObjectExpression.js:80:21) at LexicalEnvironment.evaluateAbstract (/Users/calebmer/prepack/src/environment.js:1368:20) 1053 of: at AbstractValue.throwIfNotConcrete (/Users/calebmer/prepack/src/values/AbstractValue.js:536:11) at NativeFunctionValue.obj.defineNativeMethod [as callback] (/Users/calebmer/prepack/src/intrinsics/ecma262/ObjectPrototype.js:35:39) at NativeFunctionValue.callCallback (/Users/calebmer/prepack/src/values/NativeFunctionValue.js:121:12) at functionCall (/Users/calebmer/prepack/src/methods/call.js:308:26) ``` This means there may be some low hanging fruit. Here are my questions for you. - Did you expect results like this? - What is our ideal test262 pass rate with this transformation applied? - What happens to React Compiler or other projects when these errors are thrown? (As I understand it, we bail out and don’t optimize the code, but do optimize the code around it.) - Do you think my methodology is flawed? It’s also possible that something in my methodology is wrong, but I didn’t spend much time investigating these failures as I spent investigating the failures I found in #2290. My goal with this test suite is to build an understanding of what “correctness” for the React Compiler against all JavaScript code looks like. (Not just the few bundles we’ve selected to look at.) I don’t think these results suggest that we only safely compile 18% of the language, but it’s a data point. I’ll be looking into fixing a selection of these issues to better understand their nature or if I need to change methodologies. Pull Request resolved: https://github.com/facebook/prepack/pull/2297 Differential Revision: D9120572 Pulled By: calebmer fbshipit-source-id: b394f1e8da034c9985366010e3e63fd55fd94168
2018-08-01 20:28:28 +03:00
constructor(relativeTestPath: string, timeout: number, serializer: boolean | "abstract-scalar") {
2015-10-15 02:59:41 +03:00
this.timeout = timeout;
Add serializer mode for test262 execution (#2290) Summary: I want to better understand the bugs we have in abstract evaluation. One of my ideas to do this is to replace all the literals in test262 tests with abstract values and see what our test coverage is. The first step to do this is to serialize the test262 sources after running them in Prepack and checking if their generated JavaScript runs correctly. This PR does that by adding a `--serializer` flag. With my methodology, all test262 harnesses are serialized every time since they are in the global scope. This unfortunately seems to be unavoidable since doing otherwise would change program semantics and break the tests. Running `time yarn test-test262` takes about 2 minutes and has a 98% pass rate. Running `time yarn test-test262 --serializer` takes about 5 minutes and has a 95% pass rate. [Here’s a diff of the two results.](https://gist.github.com/calebmer/1c9fe396b63ba055458c599c2be18a58) [Here is a selection of some of the bugs](https://gist.github.com/calebmer/1ac381096a4aa7be1fc7dc2163276ab4) in the serializer caught by running test262 with the Prepack serializer. I might open issues for these, but they can be a bit pedantic. I might fix some of them depending on how important they are to the React code we want to compile. Notably we have: - Lots of invariants being triggered. I particularly saw [a lot of this invariant](https://github.com/facebook/prepack/blob/7d355ef4c5f4d939742814714a78ef9b1279f9b4/src/serializer/ResidualHeapVisitor.js#L531). (An example of this is [`07.md`](https://gist.github.com/calebmer/1ac381096a4aa7be1fc7dc2163276ab4#file-07-md).) - Lots of values that are visited, but not serialized. (An example of this is [`01.md`](https://gist.github.com/calebmer/1ac381096a4aa7be1fc7dc2163276ab4#file-01-md).) - Some incorrect outputs only caught by executing code. Could not be caught by static analysis. Particularly around class serialization. I’ll build off this PR to get coverage for the abstract evaluator next, but I found these results interesting on their own so decided to do this in two PRs. Pull Request resolved: https://github.com/facebook/prepack/pull/2290 Differential Revision: D8908479 Pulled By: calebmer fbshipit-source-id: aa57d47611fbd92af33e4647fed7bf7990fb6de1
2018-07-19 04:48:13 +03:00
this.serializer = serializer;
this.relativeTestPath = relativeTestPath;
2015-10-15 02:59:41 +03:00
}
}
// NOTE: inheriting from Error does not seem to pass through an instanceof
// check
class ArgsParseError {
message: string;
constructor(message: string) {
this.message = message;
}
}
if (!("toJSON" in Error.prototype)) {
2015-10-15 02:59:41 +03:00
// $FlowFixMe this needs to become defined for Error to be serialized
Object.defineProperty(Error.prototype, "toJSON", {
// eslint-disable-line
value: function() {
2015-10-15 02:59:41 +03:00
let alt = {};
Object.getOwnPropertyNames(this).forEach(function(key) {
2015-10-15 02:59:41 +03:00
alt[key] = this[key];
}, this);
return alt;
},
configurable: true,
writable: true,
2015-10-15 02:59:41 +03:00
});
}
main();
2015-10-15 02:59:41 +03:00
function main(): number {
try {
if (cluster.isMaster) {
let args = masterArgsParse();
masterRun(args);
2015-10-15 02:59:41 +03:00
} else if (cluster.isWorker) {
let args = workerArgsParse();
workerRun(args);
} else {
throw new Error("Not a master or a worker");
}
} catch (e) {
if (e instanceof ArgsParseError) {
console.error("Illegal argument: %s.\n%s", e.message, usage());
2015-10-15 02:59:41 +03:00
} else {
console.error(e);
2015-10-15 02:59:41 +03:00
}
process.exit(1);
2015-10-15 02:59:41 +03:00
}
return 0;
}
function usage(): string {
return (
`Usage: ${process.argv[0]} ${process.argv[1]} ` +
EOL +
`[--verbose] [--timeout <number>] [--bailAfter <number>] ` +
EOL +
`[--cpuScale <number>] [--statusFile <string>] [--singleThreaded] [--relativeTestPath <string>]` +
EOL +
`[--expectedCounts <es5pass,es6pass,timeouts>]`
);
2015-10-15 02:59:41 +03:00
}
function masterArgsParse(): MasterProgramArgs {
let parsedArgs = minimist(process.argv.slice(2), {
string: ["statusFile", "relativeTestPath"],
Add abstract serializer mode for test262 execution (#2297) Summary: I extended the `--serializer` command line argument I added in #2290 to now support `--serializer abstract-scalar`. What this mode does is it converts all boolean, string, number, and symbol literals into abstract values. I did not choose to extend this logic to object and array literals just yet since scalars alone showed some interesting results. What I really want here is a review of the results. Full suite execution results are real bad. **18%** pass rate. I dug a bit into why. ``` === RESULTS === Passes: 3356 / 17780 (18%) ES5 passes: 2276 / 12045 (18%) ES6 passes: 1080 / 5735 (18%) Skipped: 13375 Timeouts: 28 ``` I was mostly interested in the runtime failures we see since that means Prepack is serializing invalid code. However, I found ~14k failures in the Prepack stage (more on this in a bit) and ~3k failures in the runtime stage. This means ~80% of tests _fail to compile_ with this abstract transformation applied. Why are these tests failing? I took the first 4 items of the stack traces from errors thrown in the Prepack stage, sorted, and ranked them. [Here’s the result.](https://gist.github.com/calebmer/29e27613325fd99fa04be7ab4a9641c0) The top 5 with thousands of hits are: ``` 7538 of: at AbstractValue.throwIfNotConcrete (/Users/calebmer/prepack/src/values/AbstractValue.js:536:11) at ToImplementation.ToStringPartial (/Users/calebmer/prepack/src/methods/to.js:717:69) at NativeFunctionValue._index.NativeFunctionValue [as callback] (/Users/calebmer/prepack/src/intrinsics/ecma262/String.js:34:37) at NativeFunctionValue.callCallback (/Users/calebmer/prepack/src/values/NativeFunctionValue.js:121:12) 4595 of: at AbstractValue.throwIfNotConcrete (/Users/calebmer/prepack/src/values/AbstractValue.js:536:11) at NativeFunctionValue.func.defineNativeMethod [as callback] (/Users/calebmer/prepack/src/intrinsics/ecma262/Object.js:328:41) at NativeFunctionValue.callCallback (/Users/calebmer/prepack/src/values/NativeFunctionValue.js:121:12) at functionCall (/Users/calebmer/prepack/src/methods/call.js:308:26) 1454 of: at AbstractValue.throwIfNotConcrete (/Users/calebmer/prepack/src/values/AbstractValue.js:536:11) at NativeFunctionValue.func.defineNativeMethod [as callback] (/Users/calebmer/prepack/src/intrinsics/ecma262/Object.js:364:41) at NativeFunctionValue.callCallback (/Users/calebmer/prepack/src/values/NativeFunctionValue.js:121:12) at functionCall (/Users/calebmer/prepack/src/methods/call.js:308:26) 1351 of: at invariant (/Users/calebmer/prepack/src/invariant.js:18:15) at EvalPropertyNamePartial (/Users/calebmer/prepack/src/evaluators/ObjectExpression.js:59:7) at _default (/Users/calebmer/prepack/src/evaluators/ObjectExpression.js:80:21) at LexicalEnvironment.evaluateAbstract (/Users/calebmer/prepack/src/environment.js:1368:20) 1053 of: at AbstractValue.throwIfNotConcrete (/Users/calebmer/prepack/src/values/AbstractValue.js:536:11) at NativeFunctionValue.obj.defineNativeMethod [as callback] (/Users/calebmer/prepack/src/intrinsics/ecma262/ObjectPrototype.js:35:39) at NativeFunctionValue.callCallback (/Users/calebmer/prepack/src/values/NativeFunctionValue.js:121:12) at functionCall (/Users/calebmer/prepack/src/methods/call.js:308:26) ``` This means there may be some low hanging fruit. Here are my questions for you. - Did you expect results like this? - What is our ideal test262 pass rate with this transformation applied? - What happens to React Compiler or other projects when these errors are thrown? (As I understand it, we bail out and don’t optimize the code, but do optimize the code around it.) - Do you think my methodology is flawed? It’s also possible that something in my methodology is wrong, but I didn’t spend much time investigating these failures as I spent investigating the failures I found in #2290. My goal with this test suite is to build an understanding of what “correctness” for the React Compiler against all JavaScript code looks like. (Not just the few bundles we’ve selected to look at.) I don’t think these results suggest that we only safely compile 18% of the language, but it’s a data point. I’ll be looking into fixing a selection of these issues to better understand their nature or if I need to change methodologies. Pull Request resolved: https://github.com/facebook/prepack/pull/2297 Differential Revision: D9120572 Pulled By: calebmer fbshipit-source-id: b394f1e8da034c9985366010e3e63fd55fd94168
2018-08-01 20:28:28 +03:00
boolean: ["verbose", "singleThreaded"],
2015-10-15 02:59:41 +03:00
default: {
verbose: process.stdout instanceof tty.WriteStream ? false : true,
2015-10-15 02:59:41 +03:00
statusFile: "",
timeout: 10,
cpuScale: 1,
bailAfter: Infinity,
singleThreaded: false,
relativeTestPath: "/../test/test262",
Add serializer mode for test262 execution (#2290) Summary: I want to better understand the bugs we have in abstract evaluation. One of my ideas to do this is to replace all the literals in test262 tests with abstract values and see what our test coverage is. The first step to do this is to serialize the test262 sources after running them in Prepack and checking if their generated JavaScript runs correctly. This PR does that by adding a `--serializer` flag. With my methodology, all test262 harnesses are serialized every time since they are in the global scope. This unfortunately seems to be unavoidable since doing otherwise would change program semantics and break the tests. Running `time yarn test-test262` takes about 2 minutes and has a 98% pass rate. Running `time yarn test-test262 --serializer` takes about 5 minutes and has a 95% pass rate. [Here’s a diff of the two results.](https://gist.github.com/calebmer/1c9fe396b63ba055458c599c2be18a58) [Here is a selection of some of the bugs](https://gist.github.com/calebmer/1ac381096a4aa7be1fc7dc2163276ab4) in the serializer caught by running test262 with the Prepack serializer. I might open issues for these, but they can be a bit pedantic. I might fix some of them depending on how important they are to the React code we want to compile. Notably we have: - Lots of invariants being triggered. I particularly saw [a lot of this invariant](https://github.com/facebook/prepack/blob/7d355ef4c5f4d939742814714a78ef9b1279f9b4/src/serializer/ResidualHeapVisitor.js#L531). (An example of this is [`07.md`](https://gist.github.com/calebmer/1ac381096a4aa7be1fc7dc2163276ab4#file-07-md).) - Lots of values that are visited, but not serialized. (An example of this is [`01.md`](https://gist.github.com/calebmer/1ac381096a4aa7be1fc7dc2163276ab4#file-01-md).) - Some incorrect outputs only caught by executing code. Could not be caught by static analysis. Particularly around class serialization. I’ll build off this PR to get coverage for the abstract evaluator next, but I found these results interesting on their own so decided to do this in two PRs. Pull Request resolved: https://github.com/facebook/prepack/pull/2290 Differential Revision: D8908479 Pulled By: calebmer fbshipit-source-id: aa57d47611fbd92af33e4647fed7bf7990fb6de1
2018-07-19 04:48:13 +03:00
serializer: false,
expectedCounts: "11943,5641,2",
},
2015-10-15 02:59:41 +03:00
});
let filterString = parsedArgs._[0];
if (typeof parsedArgs.verbose !== "boolean") {
throw new ArgsParseError("verbose must be a boolean (either --verbose or not)");
}
let verbose = parsedArgs.verbose;
2015-10-15 02:59:41 +03:00
if (typeof parsedArgs.timeout !== "number") {
throw new ArgsParseError("timeout must be a number (in seconds) (--timeout 10)");
}
let timeout = parsedArgs.timeout;
2015-10-15 02:59:41 +03:00
if (typeof parsedArgs.bailAfter !== "number") {
throw new ArgsParseError("bailAfter must be a number (--bailAfter 10)");
}
let bailAfter = parsedArgs.bailAfter;
2015-10-15 02:59:41 +03:00
if (typeof parsedArgs.cpuScale !== "number") {
throw new ArgsParseError("cpuScale must be a number (--cpuScale 0.5)");
}
let cpuScale = parsedArgs.cpuScale;
2015-10-15 02:59:41 +03:00
if (typeof parsedArgs.statusFile !== "string") {
throw new ArgsParseError("statusFile must be a string (--statusFile file.txt)");
}
let statusFile = parsedArgs.statusFile;
2015-10-15 02:59:41 +03:00
if (typeof parsedArgs.singleThreaded !== "boolean") {
throw new ArgsParseError("singleThreaded must be a boolean (either --singleThreaded or not)");
}
let singleThreaded = parsedArgs.singleThreaded;
if (typeof parsedArgs.relativeTestPath !== "string") {
throw new ArgsParseError("relativeTestPath must be a string (--relativeTestPath /../test/test262)");
}
let relativeTestPath = parsedArgs.relativeTestPath;
Add abstract serializer mode for test262 execution (#2297) Summary: I extended the `--serializer` command line argument I added in #2290 to now support `--serializer abstract-scalar`. What this mode does is it converts all boolean, string, number, and symbol literals into abstract values. I did not choose to extend this logic to object and array literals just yet since scalars alone showed some interesting results. What I really want here is a review of the results. Full suite execution results are real bad. **18%** pass rate. I dug a bit into why. ``` === RESULTS === Passes: 3356 / 17780 (18%) ES5 passes: 2276 / 12045 (18%) ES6 passes: 1080 / 5735 (18%) Skipped: 13375 Timeouts: 28 ``` I was mostly interested in the runtime failures we see since that means Prepack is serializing invalid code. However, I found ~14k failures in the Prepack stage (more on this in a bit) and ~3k failures in the runtime stage. This means ~80% of tests _fail to compile_ with this abstract transformation applied. Why are these tests failing? I took the first 4 items of the stack traces from errors thrown in the Prepack stage, sorted, and ranked them. [Here’s the result.](https://gist.github.com/calebmer/29e27613325fd99fa04be7ab4a9641c0) The top 5 with thousands of hits are: ``` 7538 of: at AbstractValue.throwIfNotConcrete (/Users/calebmer/prepack/src/values/AbstractValue.js:536:11) at ToImplementation.ToStringPartial (/Users/calebmer/prepack/src/methods/to.js:717:69) at NativeFunctionValue._index.NativeFunctionValue [as callback] (/Users/calebmer/prepack/src/intrinsics/ecma262/String.js:34:37) at NativeFunctionValue.callCallback (/Users/calebmer/prepack/src/values/NativeFunctionValue.js:121:12) 4595 of: at AbstractValue.throwIfNotConcrete (/Users/calebmer/prepack/src/values/AbstractValue.js:536:11) at NativeFunctionValue.func.defineNativeMethod [as callback] (/Users/calebmer/prepack/src/intrinsics/ecma262/Object.js:328:41) at NativeFunctionValue.callCallback (/Users/calebmer/prepack/src/values/NativeFunctionValue.js:121:12) at functionCall (/Users/calebmer/prepack/src/methods/call.js:308:26) 1454 of: at AbstractValue.throwIfNotConcrete (/Users/calebmer/prepack/src/values/AbstractValue.js:536:11) at NativeFunctionValue.func.defineNativeMethod [as callback] (/Users/calebmer/prepack/src/intrinsics/ecma262/Object.js:364:41) at NativeFunctionValue.callCallback (/Users/calebmer/prepack/src/values/NativeFunctionValue.js:121:12) at functionCall (/Users/calebmer/prepack/src/methods/call.js:308:26) 1351 of: at invariant (/Users/calebmer/prepack/src/invariant.js:18:15) at EvalPropertyNamePartial (/Users/calebmer/prepack/src/evaluators/ObjectExpression.js:59:7) at _default (/Users/calebmer/prepack/src/evaluators/ObjectExpression.js:80:21) at LexicalEnvironment.evaluateAbstract (/Users/calebmer/prepack/src/environment.js:1368:20) 1053 of: at AbstractValue.throwIfNotConcrete (/Users/calebmer/prepack/src/values/AbstractValue.js:536:11) at NativeFunctionValue.obj.defineNativeMethod [as callback] (/Users/calebmer/prepack/src/intrinsics/ecma262/ObjectPrototype.js:35:39) at NativeFunctionValue.callCallback (/Users/calebmer/prepack/src/values/NativeFunctionValue.js:121:12) at functionCall (/Users/calebmer/prepack/src/methods/call.js:308:26) ``` This means there may be some low hanging fruit. Here are my questions for you. - Did you expect results like this? - What is our ideal test262 pass rate with this transformation applied? - What happens to React Compiler or other projects when these errors are thrown? (As I understand it, we bail out and don’t optimize the code, but do optimize the code around it.) - Do you think my methodology is flawed? It’s also possible that something in my methodology is wrong, but I didn’t spend much time investigating these failures as I spent investigating the failures I found in #2290. My goal with this test suite is to build an understanding of what “correctness” for the React Compiler against all JavaScript code looks like. (Not just the few bundles we’ve selected to look at.) I don’t think these results suggest that we only safely compile 18% of the language, but it’s a data point. I’ll be looking into fixing a selection of these issues to better understand their nature or if I need to change methodologies. Pull Request resolved: https://github.com/facebook/prepack/pull/2297 Differential Revision: D9120572 Pulled By: calebmer fbshipit-source-id: b394f1e8da034c9985366010e3e63fd55fd94168
2018-08-01 20:28:28 +03:00
if (!(typeof parsedArgs.serializer === "boolean" || parsedArgs.serializer === "abstract-scalar")) {
throw new ArgsParseError(
"serializer must be a boolean or must be the string 'abstract-scalar' (--serializer or --serializer abstract-scalar)"
);
Add serializer mode for test262 execution (#2290) Summary: I want to better understand the bugs we have in abstract evaluation. One of my ideas to do this is to replace all the literals in test262 tests with abstract values and see what our test coverage is. The first step to do this is to serialize the test262 sources after running them in Prepack and checking if their generated JavaScript runs correctly. This PR does that by adding a `--serializer` flag. With my methodology, all test262 harnesses are serialized every time since they are in the global scope. This unfortunately seems to be unavoidable since doing otherwise would change program semantics and break the tests. Running `time yarn test-test262` takes about 2 minutes and has a 98% pass rate. Running `time yarn test-test262 --serializer` takes about 5 minutes and has a 95% pass rate. [Here’s a diff of the two results.](https://gist.github.com/calebmer/1c9fe396b63ba055458c599c2be18a58) [Here is a selection of some of the bugs](https://gist.github.com/calebmer/1ac381096a4aa7be1fc7dc2163276ab4) in the serializer caught by running test262 with the Prepack serializer. I might open issues for these, but they can be a bit pedantic. I might fix some of them depending on how important they are to the React code we want to compile. Notably we have: - Lots of invariants being triggered. I particularly saw [a lot of this invariant](https://github.com/facebook/prepack/blob/7d355ef4c5f4d939742814714a78ef9b1279f9b4/src/serializer/ResidualHeapVisitor.js#L531). (An example of this is [`07.md`](https://gist.github.com/calebmer/1ac381096a4aa7be1fc7dc2163276ab4#file-07-md).) - Lots of values that are visited, but not serialized. (An example of this is [`01.md`](https://gist.github.com/calebmer/1ac381096a4aa7be1fc7dc2163276ab4#file-01-md).) - Some incorrect outputs only caught by executing code. Could not be caught by static analysis. Particularly around class serialization. I’ll build off this PR to get coverage for the abstract evaluator next, but I found these results interesting on their own so decided to do this in two PRs. Pull Request resolved: https://github.com/facebook/prepack/pull/2290 Differential Revision: D8908479 Pulled By: calebmer fbshipit-source-id: aa57d47611fbd92af33e4647fed7bf7990fb6de1
2018-07-19 04:48:13 +03:00
}
let serializer = parsedArgs.serializer;
if (typeof parsedArgs.expectedCounts !== "string") {
throw new ArgsParseError("expectedCounts must be a string (--expectedCounts 11944,5566,2");
}
let expectedCounts = parsedArgs.expectedCounts.split(",").map(x => Number(x));
2015-10-15 02:59:41 +03:00
let programArgs = new MasterProgramArgs(
verbose,
timeout,
bailAfter,
cpuScale,
statusFile,
2015-10-15 02:59:41 +03:00
filterString,
singleThreaded,
relativeTestPath,
Add serializer mode for test262 execution (#2290) Summary: I want to better understand the bugs we have in abstract evaluation. One of my ideas to do this is to replace all the literals in test262 tests with abstract values and see what our test coverage is. The first step to do this is to serialize the test262 sources after running them in Prepack and checking if their generated JavaScript runs correctly. This PR does that by adding a `--serializer` flag. With my methodology, all test262 harnesses are serialized every time since they are in the global scope. This unfortunately seems to be unavoidable since doing otherwise would change program semantics and break the tests. Running `time yarn test-test262` takes about 2 minutes and has a 98% pass rate. Running `time yarn test-test262 --serializer` takes about 5 minutes and has a 95% pass rate. [Here’s a diff of the two results.](https://gist.github.com/calebmer/1c9fe396b63ba055458c599c2be18a58) [Here is a selection of some of the bugs](https://gist.github.com/calebmer/1ac381096a4aa7be1fc7dc2163276ab4) in the serializer caught by running test262 with the Prepack serializer. I might open issues for these, but they can be a bit pedantic. I might fix some of them depending on how important they are to the React code we want to compile. Notably we have: - Lots of invariants being triggered. I particularly saw [a lot of this invariant](https://github.com/facebook/prepack/blob/7d355ef4c5f4d939742814714a78ef9b1279f9b4/src/serializer/ResidualHeapVisitor.js#L531). (An example of this is [`07.md`](https://gist.github.com/calebmer/1ac381096a4aa7be1fc7dc2163276ab4#file-07-md).) - Lots of values that are visited, but not serialized. (An example of this is [`01.md`](https://gist.github.com/calebmer/1ac381096a4aa7be1fc7dc2163276ab4#file-01-md).) - Some incorrect outputs only caught by executing code. Could not be caught by static analysis. Particularly around class serialization. I’ll build off this PR to get coverage for the abstract evaluator next, but I found these results interesting on their own so decided to do this in two PRs. Pull Request resolved: https://github.com/facebook/prepack/pull/2290 Differential Revision: D8908479 Pulled By: calebmer fbshipit-source-id: aa57d47611fbd92af33e4647fed7bf7990fb6de1
2018-07-19 04:48:13 +03:00
serializer,
expectedCounts[0],
expectedCounts[1],
expectedCounts[2]
2015-10-15 02:59:41 +03:00
);
if (programArgs.filterString) {
// if filterstring is provided, assume that verbosity is desired
programArgs.verbose = true;
}
return programArgs;
}
function workerArgsParse(): WorkerProgramArgs {
let parsedArgs = minimist(process.argv.slice(2), {
default: {
relativeTestPath: "/../test/test262",
Add serializer mode for test262 execution (#2290) Summary: I want to better understand the bugs we have in abstract evaluation. One of my ideas to do this is to replace all the literals in test262 tests with abstract values and see what our test coverage is. The first step to do this is to serialize the test262 sources after running them in Prepack and checking if their generated JavaScript runs correctly. This PR does that by adding a `--serializer` flag. With my methodology, all test262 harnesses are serialized every time since they are in the global scope. This unfortunately seems to be unavoidable since doing otherwise would change program semantics and break the tests. Running `time yarn test-test262` takes about 2 minutes and has a 98% pass rate. Running `time yarn test-test262 --serializer` takes about 5 minutes and has a 95% pass rate. [Here’s a diff of the two results.](https://gist.github.com/calebmer/1c9fe396b63ba055458c599c2be18a58) [Here is a selection of some of the bugs](https://gist.github.com/calebmer/1ac381096a4aa7be1fc7dc2163276ab4) in the serializer caught by running test262 with the Prepack serializer. I might open issues for these, but they can be a bit pedantic. I might fix some of them depending on how important they are to the React code we want to compile. Notably we have: - Lots of invariants being triggered. I particularly saw [a lot of this invariant](https://github.com/facebook/prepack/blob/7d355ef4c5f4d939742814714a78ef9b1279f9b4/src/serializer/ResidualHeapVisitor.js#L531). (An example of this is [`07.md`](https://gist.github.com/calebmer/1ac381096a4aa7be1fc7dc2163276ab4#file-07-md).) - Lots of values that are visited, but not serialized. (An example of this is [`01.md`](https://gist.github.com/calebmer/1ac381096a4aa7be1fc7dc2163276ab4#file-01-md).) - Some incorrect outputs only caught by executing code. Could not be caught by static analysis. Particularly around class serialization. I’ll build off this PR to get coverage for the abstract evaluator next, but I found these results interesting on their own so decided to do this in two PRs. Pull Request resolved: https://github.com/facebook/prepack/pull/2290 Differential Revision: D8908479 Pulled By: calebmer fbshipit-source-id: aa57d47611fbd92af33e4647fed7bf7990fb6de1
2018-07-19 04:48:13 +03:00
timeout: 10,
serializer: false,
},
2015-10-15 02:59:41 +03:00
});
Add serializer mode for test262 execution (#2290) Summary: I want to better understand the bugs we have in abstract evaluation. One of my ideas to do this is to replace all the literals in test262 tests with abstract values and see what our test coverage is. The first step to do this is to serialize the test262 sources after running them in Prepack and checking if their generated JavaScript runs correctly. This PR does that by adding a `--serializer` flag. With my methodology, all test262 harnesses are serialized every time since they are in the global scope. This unfortunately seems to be unavoidable since doing otherwise would change program semantics and break the tests. Running `time yarn test-test262` takes about 2 minutes and has a 98% pass rate. Running `time yarn test-test262 --serializer` takes about 5 minutes and has a 95% pass rate. [Here’s a diff of the two results.](https://gist.github.com/calebmer/1c9fe396b63ba055458c599c2be18a58) [Here is a selection of some of the bugs](https://gist.github.com/calebmer/1ac381096a4aa7be1fc7dc2163276ab4) in the serializer caught by running test262 with the Prepack serializer. I might open issues for these, but they can be a bit pedantic. I might fix some of them depending on how important they are to the React code we want to compile. Notably we have: - Lots of invariants being triggered. I particularly saw [a lot of this invariant](https://github.com/facebook/prepack/blob/7d355ef4c5f4d939742814714a78ef9b1279f9b4/src/serializer/ResidualHeapVisitor.js#L531). (An example of this is [`07.md`](https://gist.github.com/calebmer/1ac381096a4aa7be1fc7dc2163276ab4#file-07-md).) - Lots of values that are visited, but not serialized. (An example of this is [`01.md`](https://gist.github.com/calebmer/1ac381096a4aa7be1fc7dc2163276ab4#file-01-md).) - Some incorrect outputs only caught by executing code. Could not be caught by static analysis. Particularly around class serialization. I’ll build off this PR to get coverage for the abstract evaluator next, but I found these results interesting on their own so decided to do this in two PRs. Pull Request resolved: https://github.com/facebook/prepack/pull/2290 Differential Revision: D8908479 Pulled By: calebmer fbshipit-source-id: aa57d47611fbd92af33e4647fed7bf7990fb6de1
2018-07-19 04:48:13 +03:00
if (typeof parsedArgs.relativeTestPath !== "string") {
throw new ArgsParseError("relativeTestPath must be a string (--relativeTestPath /../test/test262)");
}
2015-10-15 02:59:41 +03:00
if (typeof parsedArgs.timeout !== "number") {
throw new ArgsParseError("timeout must be a number (in seconds) (--timeout 10)");
}
Add abstract serializer mode for test262 execution (#2297) Summary: I extended the `--serializer` command line argument I added in #2290 to now support `--serializer abstract-scalar`. What this mode does is it converts all boolean, string, number, and symbol literals into abstract values. I did not choose to extend this logic to object and array literals just yet since scalars alone showed some interesting results. What I really want here is a review of the results. Full suite execution results are real bad. **18%** pass rate. I dug a bit into why. ``` === RESULTS === Passes: 3356 / 17780 (18%) ES5 passes: 2276 / 12045 (18%) ES6 passes: 1080 / 5735 (18%) Skipped: 13375 Timeouts: 28 ``` I was mostly interested in the runtime failures we see since that means Prepack is serializing invalid code. However, I found ~14k failures in the Prepack stage (more on this in a bit) and ~3k failures in the runtime stage. This means ~80% of tests _fail to compile_ with this abstract transformation applied. Why are these tests failing? I took the first 4 items of the stack traces from errors thrown in the Prepack stage, sorted, and ranked them. [Here’s the result.](https://gist.github.com/calebmer/29e27613325fd99fa04be7ab4a9641c0) The top 5 with thousands of hits are: ``` 7538 of: at AbstractValue.throwIfNotConcrete (/Users/calebmer/prepack/src/values/AbstractValue.js:536:11) at ToImplementation.ToStringPartial (/Users/calebmer/prepack/src/methods/to.js:717:69) at NativeFunctionValue._index.NativeFunctionValue [as callback] (/Users/calebmer/prepack/src/intrinsics/ecma262/String.js:34:37) at NativeFunctionValue.callCallback (/Users/calebmer/prepack/src/values/NativeFunctionValue.js:121:12) 4595 of: at AbstractValue.throwIfNotConcrete (/Users/calebmer/prepack/src/values/AbstractValue.js:536:11) at NativeFunctionValue.func.defineNativeMethod [as callback] (/Users/calebmer/prepack/src/intrinsics/ecma262/Object.js:328:41) at NativeFunctionValue.callCallback (/Users/calebmer/prepack/src/values/NativeFunctionValue.js:121:12) at functionCall (/Users/calebmer/prepack/src/methods/call.js:308:26) 1454 of: at AbstractValue.throwIfNotConcrete (/Users/calebmer/prepack/src/values/AbstractValue.js:536:11) at NativeFunctionValue.func.defineNativeMethod [as callback] (/Users/calebmer/prepack/src/intrinsics/ecma262/Object.js:364:41) at NativeFunctionValue.callCallback (/Users/calebmer/prepack/src/values/NativeFunctionValue.js:121:12) at functionCall (/Users/calebmer/prepack/src/methods/call.js:308:26) 1351 of: at invariant (/Users/calebmer/prepack/src/invariant.js:18:15) at EvalPropertyNamePartial (/Users/calebmer/prepack/src/evaluators/ObjectExpression.js:59:7) at _default (/Users/calebmer/prepack/src/evaluators/ObjectExpression.js:80:21) at LexicalEnvironment.evaluateAbstract (/Users/calebmer/prepack/src/environment.js:1368:20) 1053 of: at AbstractValue.throwIfNotConcrete (/Users/calebmer/prepack/src/values/AbstractValue.js:536:11) at NativeFunctionValue.obj.defineNativeMethod [as callback] (/Users/calebmer/prepack/src/intrinsics/ecma262/ObjectPrototype.js:35:39) at NativeFunctionValue.callCallback (/Users/calebmer/prepack/src/values/NativeFunctionValue.js:121:12) at functionCall (/Users/calebmer/prepack/src/methods/call.js:308:26) ``` This means there may be some low hanging fruit. Here are my questions for you. - Did you expect results like this? - What is our ideal test262 pass rate with this transformation applied? - What happens to React Compiler or other projects when these errors are thrown? (As I understand it, we bail out and don’t optimize the code, but do optimize the code around it.) - Do you think my methodology is flawed? It’s also possible that something in my methodology is wrong, but I didn’t spend much time investigating these failures as I spent investigating the failures I found in #2290. My goal with this test suite is to build an understanding of what “correctness” for the React Compiler against all JavaScript code looks like. (Not just the few bundles we’ve selected to look at.) I don’t think these results suggest that we only safely compile 18% of the language, but it’s a data point. I’ll be looking into fixing a selection of these issues to better understand their nature or if I need to change methodologies. Pull Request resolved: https://github.com/facebook/prepack/pull/2297 Differential Revision: D9120572 Pulled By: calebmer fbshipit-source-id: b394f1e8da034c9985366010e3e63fd55fd94168
2018-08-01 20:28:28 +03:00
if (!(typeof parsedArgs.serializer === "boolean" || parsedArgs.serializer === "abstract-scalar")) {
throw new ArgsParseError(
"serializer must be a boolean or must be the string 'abstract-scalar' (--serializer or --serializer abstract-scalar)"
);
}
Add serializer mode for test262 execution (#2290) Summary: I want to better understand the bugs we have in abstract evaluation. One of my ideas to do this is to replace all the literals in test262 tests with abstract values and see what our test coverage is. The first step to do this is to serialize the test262 sources after running them in Prepack and checking if their generated JavaScript runs correctly. This PR does that by adding a `--serializer` flag. With my methodology, all test262 harnesses are serialized every time since they are in the global scope. This unfortunately seems to be unavoidable since doing otherwise would change program semantics and break the tests. Running `time yarn test-test262` takes about 2 minutes and has a 98% pass rate. Running `time yarn test-test262 --serializer` takes about 5 minutes and has a 95% pass rate. [Here’s a diff of the two results.](https://gist.github.com/calebmer/1c9fe396b63ba055458c599c2be18a58) [Here is a selection of some of the bugs](https://gist.github.com/calebmer/1ac381096a4aa7be1fc7dc2163276ab4) in the serializer caught by running test262 with the Prepack serializer. I might open issues for these, but they can be a bit pedantic. I might fix some of them depending on how important they are to the React code we want to compile. Notably we have: - Lots of invariants being triggered. I particularly saw [a lot of this invariant](https://github.com/facebook/prepack/blob/7d355ef4c5f4d939742814714a78ef9b1279f9b4/src/serializer/ResidualHeapVisitor.js#L531). (An example of this is [`07.md`](https://gist.github.com/calebmer/1ac381096a4aa7be1fc7dc2163276ab4#file-07-md).) - Lots of values that are visited, but not serialized. (An example of this is [`01.md`](https://gist.github.com/calebmer/1ac381096a4aa7be1fc7dc2163276ab4#file-01-md).) - Some incorrect outputs only caught by executing code. Could not be caught by static analysis. Particularly around class serialization. I’ll build off this PR to get coverage for the abstract evaluator next, but I found these results interesting on their own so decided to do this in two PRs. Pull Request resolved: https://github.com/facebook/prepack/pull/2290 Differential Revision: D8908479 Pulled By: calebmer fbshipit-source-id: aa57d47611fbd92af33e4647fed7bf7990fb6de1
2018-07-19 04:48:13 +03:00
return new WorkerProgramArgs(parsedArgs.relativeTestPath, parsedArgs.timeout, parsedArgs.serializer);
2015-10-15 02:59:41 +03:00
}
function masterRun(args: MasterProgramArgs) {
let testPath = `${__dirname}` + args.relativeTestPath + "/test";
let tests = getFilesSync(testPath);
// remove tests that don't need to be run
if (args.filterString) tests = tests.filter(test => test.location.includes(args.filterString));
2015-10-15 02:59:41 +03:00
const originalTestLength = tests.length;
tests = tests.filter(test => testFilterByMetadata(test));
2015-10-15 02:59:41 +03:00
let groups: GroupsMap = {};
// Now that all the tasks are ready, start up workers to begin processing
// if single threaded, use that route instead
if (args.singleThreaded) {
masterRunSingleProcess(args, groups, tests, originalTestLength - tests.length);
} else {
masterRunMultiProcess(args, groups, tests, originalTestLength - tests.length);
}
}
function masterRunSingleProcess(
args: MasterProgramArgs,
groups: GroupsMap,
tests: TestFileInfo[],
numFiltered: number
2015-10-15 02:59:41 +03:00
): void {
console.log(`Running ${tests.length} tests as a single process`);
2015-10-15 02:59:41 +03:00
// print out every 5 percent (more granularity than multi-process because multi-process
// runs a lot faster)
const granularity = Math.floor(tests.length / 20);
let harnesses = getHarnesses(args.relativeTestPath);
2015-10-15 02:59:41 +03:00
let numLeft = tests.length;
for (let t of tests) {
Add serializer mode for test262 execution (#2290) Summary: I want to better understand the bugs we have in abstract evaluation. One of my ideas to do this is to replace all the literals in test262 tests with abstract values and see what our test coverage is. The first step to do this is to serialize the test262 sources after running them in Prepack and checking if their generated JavaScript runs correctly. This PR does that by adding a `--serializer` flag. With my methodology, all test262 harnesses are serialized every time since they are in the global scope. This unfortunately seems to be unavoidable since doing otherwise would change program semantics and break the tests. Running `time yarn test-test262` takes about 2 minutes and has a 98% pass rate. Running `time yarn test-test262 --serializer` takes about 5 minutes and has a 95% pass rate. [Here’s a diff of the two results.](https://gist.github.com/calebmer/1c9fe396b63ba055458c599c2be18a58) [Here is a selection of some of the bugs](https://gist.github.com/calebmer/1ac381096a4aa7be1fc7dc2163276ab4) in the serializer caught by running test262 with the Prepack serializer. I might open issues for these, but they can be a bit pedantic. I might fix some of them depending on how important they are to the React code we want to compile. Notably we have: - Lots of invariants being triggered. I particularly saw [a lot of this invariant](https://github.com/facebook/prepack/blob/7d355ef4c5f4d939742814714a78ef9b1279f9b4/src/serializer/ResidualHeapVisitor.js#L531). (An example of this is [`07.md`](https://gist.github.com/calebmer/1ac381096a4aa7be1fc7dc2163276ab4#file-07-md).) - Lots of values that are visited, but not serialized. (An example of this is [`01.md`](https://gist.github.com/calebmer/1ac381096a4aa7be1fc7dc2163276ab4#file-01-md).) - Some incorrect outputs only caught by executing code. Could not be caught by static analysis. Particularly around class serialization. I’ll build off this PR to get coverage for the abstract evaluator next, but I found these results interesting on their own so decided to do this in two PRs. Pull Request resolved: https://github.com/facebook/prepack/pull/2290 Differential Revision: D8908479 Pulled By: calebmer fbshipit-source-id: aa57d47611fbd92af33e4647fed7bf7990fb6de1
2018-07-19 04:48:13 +03:00
let options: TestRunOptions = {
timeout: args.timeout,
serializer: args.serializer,
};
handleTest(t, harnesses, options, (err, results) => {
2015-10-15 02:59:41 +03:00
if (err) {
if (args.verbose) {
console.error(err);
2015-10-15 02:59:41 +03:00
}
} else {
let ok = handleTestResults(groups, t, results);
if (!ok) {
// handleTestResults returns false if a failure threshold was exceeded
2015-10-15 02:59:41 +03:00
throw new Error("Too many test failures");
}
let progress = getProgressBar(numLeft, tests.length, granularity);
if (progress) {
console.log(progress);
}
}
numLeft--;
if (numLeft === 0) {
// all done
process.exit(handleFinished(args, groups, numFiltered));
}
2015-10-15 02:59:41 +03:00
});
}
}
function masterRunMultiProcess(
args: MasterProgramArgs,
groups: GroupsMap,
tests: TestFileInfo[],
numFiltered: number
2015-10-15 02:59:41 +03:00
): void {
if (!cluster.on) {
// stop flow errors on "cluster.on"
throw new Error("cluster is malformed");
}
const granularity = Math.floor(tests.length / 10);
const originalTestLength = tests.length;
// Fork workers.
const numWorkers = Math.max(1, Math.floor(numCPUs * args.cpuScale));
2015-10-15 02:59:41 +03:00
console.log(`Master starting up, forking ${numWorkers} workers`);
for (let i = 0; i < numWorkers; i++) {
cluster.fork();
}
let exitCount = 0;
cluster.on("exit", (worker, code, signal) => {
Add serializer mode for test262 execution (#2290) Summary: I want to better understand the bugs we have in abstract evaluation. One of my ideas to do this is to replace all the literals in test262 tests with abstract values and see what our test coverage is. The first step to do this is to serialize the test262 sources after running them in Prepack and checking if their generated JavaScript runs correctly. This PR does that by adding a `--serializer` flag. With my methodology, all test262 harnesses are serialized every time since they are in the global scope. This unfortunately seems to be unavoidable since doing otherwise would change program semantics and break the tests. Running `time yarn test-test262` takes about 2 minutes and has a 98% pass rate. Running `time yarn test-test262 --serializer` takes about 5 minutes and has a 95% pass rate. [Here’s a diff of the two results.](https://gist.github.com/calebmer/1c9fe396b63ba055458c599c2be18a58) [Here is a selection of some of the bugs](https://gist.github.com/calebmer/1ac381096a4aa7be1fc7dc2163276ab4) in the serializer caught by running test262 with the Prepack serializer. I might open issues for these, but they can be a bit pedantic. I might fix some of them depending on how important they are to the React code we want to compile. Notably we have: - Lots of invariants being triggered. I particularly saw [a lot of this invariant](https://github.com/facebook/prepack/blob/7d355ef4c5f4d939742814714a78ef9b1279f9b4/src/serializer/ResidualHeapVisitor.js#L531). (An example of this is [`07.md`](https://gist.github.com/calebmer/1ac381096a4aa7be1fc7dc2163276ab4#file-07-md).) - Lots of values that are visited, but not serialized. (An example of this is [`01.md`](https://gist.github.com/calebmer/1ac381096a4aa7be1fc7dc2163276ab4#file-01-md).) - Some incorrect outputs only caught by executing code. Could not be caught by static analysis. Particularly around class serialization. I’ll build off this PR to get coverage for the abstract evaluator next, but I found these results interesting on their own so decided to do this in two PRs. Pull Request resolved: https://github.com/facebook/prepack/pull/2290 Differential Revision: D8908479 Pulled By: calebmer fbshipit-source-id: aa57d47611fbd92af33e4647fed7bf7990fb6de1
2018-07-19 04:48:13 +03:00
if (code !== 0) {
console.log(`Worker ${worker.process.pid} died with ${signal || code}. Restarting...`);
cluster.fork();
} else {
exitCount++;
if (exitCount === numWorkers) {
process.exit(handleFinished(args, groups, numFiltered));
}
2015-10-15 02:59:41 +03:00
}
});
const giveTask = worker => {
2015-10-15 02:59:41 +03:00
// grab another test to run and give it to the child process
if (tests.length === 0) {
worker.send(new QuitMessage());
} else {
worker.send(new TestTask(tests.pop()));
}
};
cluster.on("message", (worker, message, handle) => {
2015-10-15 02:59:41 +03:00
switch (message.type) {
case ErrorMessage.sentinel:
let errMsg = ErrorMessage.fromObject(message);
// just skip the error, thus skipping that test
if (args.verbose) {
console.error(`An error occurred in worker #${worker.process.pid}:`);
console.error(errMsg.err);
2015-10-15 02:59:41 +03:00
}
giveTask(worker);
break;
case DoneMessage.sentinel:
let done = DoneMessage.fromObject(message);
let ok = handleTestResults(groups, done.test, done.testResults);
if (!ok) {
// bail
killWorkers(cluster.workers);
handleFinished(args, groups, numFiltered);
process.exit(1);
}
giveTask(worker);
let progress = getProgressBar(tests.length, originalTestLength, granularity);
if (progress) {
console.log(progress);
}
break;
default:
throw new Error(`Master got an unexpected message: ${JSON.stringify(message)}`);
2015-10-15 02:59:41 +03:00
}
});
cluster.on("online", worker => {
2015-10-15 02:59:41 +03:00
giveTask(worker);
});
}
function handleFinished(args: MasterProgramArgs, groups: GroupsMap, earlierNumSkipped: number): number {
let numPassed = 0;
2015-10-15 02:59:41 +03:00
let numPassedES5 = 0;
let numPassedES6 = 0;
let numFailed = 0;
2015-10-15 02:59:41 +03:00
let numFailedES5 = 0;
let numFailedES6 = 0;
let numSkipped = earlierNumSkipped;
2017-04-22 01:57:04 +03:00
let numTimeouts = 0;
2015-10-15 02:59:41 +03:00
let failed_groups = [];
for (let group in groups) {
// count some totals
let group_passed = 0;
let group_failed = 0;
2015-10-15 02:59:41 +03:00
let group_es5_passed = 0;
let group_es5_failed = 0;
let group_es6_passed = 0;
let group_es6_failed = 0;
let groupName = path.relative(path.join(__dirname, "..", "..", "test"), group);
let msg = "";
let errmsg = "";
msg += `${groupName}: `;
for (let t of groups[group]) {
let testName = path.relative(group, t.test.location);
let all_passed = true;
let was_skipped = true;
2015-10-15 02:59:41 +03:00
for (let testResult of t.result) {
was_skipped = false;
if (!testResult.passed) {
all_passed = false;
2015-10-15 02:59:41 +03:00
if (args.verbose) {
errmsg +=
create_test_message(testName, testResult.passed, testResult.err, t.test.isES6, testResult.strict) + EOL;
2015-10-15 02:59:41 +03:00
}
2017-04-22 01:57:04 +03:00
if (testResult.err && testResult.err.message === "Timed out") {
numTimeouts++;
2015-10-15 02:59:41 +03:00
}
}
}
if (was_skipped) {
numSkipped++;
} else if (all_passed) {
group_passed++;
if (t.test.isES6) {
group_es6_passed++;
} else {
group_es5_passed++;
}
} else {
group_failed++;
if (t.test.isES6) {
group_es6_failed++;
} else {
group_es5_failed++;
}
}
2015-10-15 02:59:41 +03:00
}
msg +=
`Passed: ${group_passed} / ${group_passed + group_failed} ` +
`(${toPercentage(group_passed, group_passed + group_failed)}%) ` +
chalk.yellow("(es5)") +
`: ${group_es5_passed} / ` +
`${group_es5_passed + group_es5_failed} ` +
2015-10-15 02:59:41 +03:00
`(${toPercentage(group_es5_passed, group_es5_passed + group_es5_failed)}%) ` +
chalk.yellow("(es6)") +
`: ${group_es6_passed} / ` +
2015-10-15 02:59:41 +03:00
`${group_es6_passed + group_es6_failed} ` +
`(${toPercentage(group_es6_passed, group_es6_passed + group_es6_failed)}%)`;
if (args.verbose) {
console.log(msg);
if (errmsg) {
console.error(errmsg);
2015-10-15 02:59:41 +03:00
}
}
if (group_es5_failed + group_es6_failed > 0) {
2015-10-15 02:59:41 +03:00
failed_groups.push(msg);
}
numPassed += group_passed;
2015-10-15 02:59:41 +03:00
numPassedES5 += group_es5_passed;
numPassedES6 += group_es6_passed;
numFailed += group_failed;
2015-10-15 02:59:41 +03:00
numFailedES5 += group_es5_failed;
numFailedES6 += group_es6_failed;
}
let status =
`=== RESULTS ===` +
EOL +
`Passes: ${numPassed} / ${numPassed + numFailed} ` +
`(${toPercentage(numPassed, numPassed + numFailed)}%)` +
EOL +
`ES5 passes: ${numPassedES5} / ${numPassedES5 + numFailedES5} ` +
`(${toPercentage(numPassedES5, numPassedES5 + numFailedES5)}%) ` +
EOL +
2015-10-15 02:59:41 +03:00
`ES6 passes: ${numPassedES6} / ${numPassedES6 + numFailedES6} ` +
`(${toPercentage(numPassedES6, numPassedES6 + numFailedES6)}%)` +
EOL +
`Skipped: ${numSkipped}` +
EOL +
`Timeouts: ${numTimeouts}` +
EOL;
2015-10-15 02:59:41 +03:00
console.log(status);
if (failed_groups.length !== 0) {
console.log("Groups with failures:");
for (let groupMessage of failed_groups) {
console.log(groupMessage);
}
}
if (args.statusFile) {
fs.writeFileSync(args.statusFile, status);
}
// exit status
if (
!args.filterString &&
(numPassedES5 < args.expectedES5 || numPassedES6 < args.expectedES6 || numTimeouts > args.expectedTimeouts)
) {
console.error(chalk.red("Overall failure. Expected more tests to pass!"));
process.exit(1);
invariant(false);
2015-10-15 02:59:41 +03:00
} else {
// use 0 to avoid the npm error messages
return 0;
}
}
function getProgressBar(currentTestLength: number, originalTestLength: number, granularity: number): string {
2015-10-15 02:59:41 +03:00
if (currentTestLength % granularity === 0 && currentTestLength !== 0) {
// print out a percent of tests completed to keep the user informed
return `Running... ${toPercentage(originalTestLength - currentTestLength, originalTestLength)}%`;
} else {
return "";
}
}
// Returns false if test processing should stop.
function handleTestResults(groups: GroupsMap, test: TestFileInfo, testResults: TestResult[]): boolean {
// test results are in, add it to its corresponding group
if (!(test.groupName in groups)) {
groups[test.groupName] = [];
2015-10-15 02:59:41 +03:00
}
groups[test.groupName].push({ test: test, result: testResults });
2015-10-15 02:59:41 +03:00
return true;
}
// $FlowFixMe cluster.Worker is marked as not exported by the node API by flow.
function killWorkers(workers: { [index: string]: cluster.Worker }): void {
for (let workerID in workers) {
workers[workerID].kill();
}
}
function toPercentage(x: number, total: number): number {
if (total === 0) {
return 100;
}
return Math.floor((x / total) * 100);
2015-10-15 02:59:41 +03:00
}
function create_test_message(name: string, success: boolean, err: ?Error, isES6: boolean, isStrict: boolean): string {
2015-10-15 02:59:41 +03:00
const checkmark = chalk.green("\u2713");
const xmark = chalk.red("\u2717");
let msg = "\t";
msg += (success ? checkmark : xmark) + " ";
msg += `${isES6 ? chalk.yellow("(es6) ") : ""}${isStrict ? "(strict)" : "(nostrict)"}: ${name}`;
if (!success) {
invariant(err, "Error must be non null if success is false");
if (err.message) {
// split the message by newline, add tabs, and join
let parts = err.message.split(EOL);
for (let line of parts) {
msg += EOL + `\t\t${line}`;
}
msg += EOL;
} else if (err.stack) {
msg += JSON.stringify(err.stack);
}
}
return msg;
}
function getHarnesses(relativeTestPath: string): HarnessMap {
let harnessPath = `${__dirname}` + relativeTestPath + "/harness";
let harnessesList = getFilesSync(harnessPath);
2015-10-15 02:59:41 +03:00
// convert to a mapping from harness name to file contents
let harnesses: HarnessMap = {};
for (let harness of harnessesList) {
// sync is fine, it's an initialization stage and there's not that many
// harnesses
harnesses[path.basename(harness.location)] = fs.readFileSync(harness.location).toString();
2015-10-15 02:59:41 +03:00
}
return harnesses;
}
function workerRun(args: WorkerProgramArgs) {
// NOTE: all harnesses (including contents of harness files) need to be
// used on workers. It needs to either be read from the fs once and
// distributed via IPC or once from each process. This is the
// "once from each process" approach.
// get all the harnesses
let harnesses = getHarnesses(args.relativeTestPath);
2015-10-15 02:59:41 +03:00
// we're a worker, run a portion of the tests
process.on("message", message => {
2015-10-15 02:59:41 +03:00
switch (message.type) {
case TestTask.sentinel:
// begin executing this TestTask
let task = TestTask.fromObject(message);
Add serializer mode for test262 execution (#2290) Summary: I want to better understand the bugs we have in abstract evaluation. One of my ideas to do this is to replace all the literals in test262 tests with abstract values and see what our test coverage is. The first step to do this is to serialize the test262 sources after running them in Prepack and checking if their generated JavaScript runs correctly. This PR does that by adding a `--serializer` flag. With my methodology, all test262 harnesses are serialized every time since they are in the global scope. This unfortunately seems to be unavoidable since doing otherwise would change program semantics and break the tests. Running `time yarn test-test262` takes about 2 minutes and has a 98% pass rate. Running `time yarn test-test262 --serializer` takes about 5 minutes and has a 95% pass rate. [Here’s a diff of the two results.](https://gist.github.com/calebmer/1c9fe396b63ba055458c599c2be18a58) [Here is a selection of some of the bugs](https://gist.github.com/calebmer/1ac381096a4aa7be1fc7dc2163276ab4) in the serializer caught by running test262 with the Prepack serializer. I might open issues for these, but they can be a bit pedantic. I might fix some of them depending on how important they are to the React code we want to compile. Notably we have: - Lots of invariants being triggered. I particularly saw [a lot of this invariant](https://github.com/facebook/prepack/blob/7d355ef4c5f4d939742814714a78ef9b1279f9b4/src/serializer/ResidualHeapVisitor.js#L531). (An example of this is [`07.md`](https://gist.github.com/calebmer/1ac381096a4aa7be1fc7dc2163276ab4#file-07-md).) - Lots of values that are visited, but not serialized. (An example of this is [`01.md`](https://gist.github.com/calebmer/1ac381096a4aa7be1fc7dc2163276ab4#file-01-md).) - Some incorrect outputs only caught by executing code. Could not be caught by static analysis. Particularly around class serialization. I’ll build off this PR to get coverage for the abstract evaluator next, but I found these results interesting on their own so decided to do this in two PRs. Pull Request resolved: https://github.com/facebook/prepack/pull/2290 Differential Revision: D8908479 Pulled By: calebmer fbshipit-source-id: aa57d47611fbd92af33e4647fed7bf7990fb6de1
2018-07-19 04:48:13 +03:00
let options: TestRunOptions = {
timeout: args.timeout,
serializer: args.serializer,
};
handleTest(task.file, harnesses, options, (err, results) => {
2015-10-15 02:59:41 +03:00
handleTestResultsMultiProcess(err, task.file, results);
});
break;
case QuitMessage.sentinel:
process.exit(0);
break;
default:
throw new Error(
`Worker #${process.pid} got an unexpected message:
${JSON.stringify(message)}`
);
}
});
}
function handleTestResultsMultiProcess(err: ?Error, test: TestFileInfo, testResults: TestResult[]): void {
2015-10-15 02:59:41 +03:00
if (err) {
process.send(new ErrorMessage(err));
} else {
let msg = new DoneMessage(test);
for (let t of testResults) {
msg.testResults.push(t);
}
try {
process.send(msg);
} catch (jsonCircularSerializationErr) {
// JSON circular serialization, ThrowCompletion is too deep to be
// serialized!
// Solution, truncate the "err" field if this happens
for (let t of msg.testResults) {
if (t.err) {
t.err = new Error(t.err.message);
}
}
// now try again
process.send(msg);
}
}
}
function handleTest(
test: TestFileInfo,
harnesses: HarnessMap,
Add serializer mode for test262 execution (#2290) Summary: I want to better understand the bugs we have in abstract evaluation. One of my ideas to do this is to replace all the literals in test262 tests with abstract values and see what our test coverage is. The first step to do this is to serialize the test262 sources after running them in Prepack and checking if their generated JavaScript runs correctly. This PR does that by adding a `--serializer` flag. With my methodology, all test262 harnesses are serialized every time since they are in the global scope. This unfortunately seems to be unavoidable since doing otherwise would change program semantics and break the tests. Running `time yarn test-test262` takes about 2 minutes and has a 98% pass rate. Running `time yarn test-test262 --serializer` takes about 5 minutes and has a 95% pass rate. [Here’s a diff of the two results.](https://gist.github.com/calebmer/1c9fe396b63ba055458c599c2be18a58) [Here is a selection of some of the bugs](https://gist.github.com/calebmer/1ac381096a4aa7be1fc7dc2163276ab4) in the serializer caught by running test262 with the Prepack serializer. I might open issues for these, but they can be a bit pedantic. I might fix some of them depending on how important they are to the React code we want to compile. Notably we have: - Lots of invariants being triggered. I particularly saw [a lot of this invariant](https://github.com/facebook/prepack/blob/7d355ef4c5f4d939742814714a78ef9b1279f9b4/src/serializer/ResidualHeapVisitor.js#L531). (An example of this is [`07.md`](https://gist.github.com/calebmer/1ac381096a4aa7be1fc7dc2163276ab4#file-07-md).) - Lots of values that are visited, but not serialized. (An example of this is [`01.md`](https://gist.github.com/calebmer/1ac381096a4aa7be1fc7dc2163276ab4#file-01-md).) - Some incorrect outputs only caught by executing code. Could not be caught by static analysis. Particularly around class serialization. I’ll build off this PR to get coverage for the abstract evaluator next, but I found these results interesting on their own so decided to do this in two PRs. Pull Request resolved: https://github.com/facebook/prepack/pull/2290 Differential Revision: D8908479 Pulled By: calebmer fbshipit-source-id: aa57d47611fbd92af33e4647fed7bf7990fb6de1
2018-07-19 04:48:13 +03:00
options: TestRunOptions,
2015-10-15 02:59:41 +03:00
cb: (err: ?Error, testResults: TestResult[]) => void
): void {
prepareTest(test, testFilterByContents, (err, banners, testFileContents) => {
if (err != null) {
cb(err, []);
return;
}
if (!banners) {
// skip this test
cb(null, []);
} else {
invariant(testFileContents, "testFileContents should not be null if banners are not None");
// filter out by flags, features, and includes
let keepThisTest =
filterFeatures(banners) &&
filterNegative(banners) &&
filterFlags(banners) &&
filterIncludes(banners) &&
filterDescription(banners) &&
filterCircleCI(banners) &&
Add serializer mode for test262 execution (#2290) Summary: I want to better understand the bugs we have in abstract evaluation. One of my ideas to do this is to replace all the literals in test262 tests with abstract values and see what our test coverage is. The first step to do this is to serialize the test262 sources after running them in Prepack and checking if their generated JavaScript runs correctly. This PR does that by adding a `--serializer` flag. With my methodology, all test262 harnesses are serialized every time since they are in the global scope. This unfortunately seems to be unavoidable since doing otherwise would change program semantics and break the tests. Running `time yarn test-test262` takes about 2 minutes and has a 98% pass rate. Running `time yarn test-test262 --serializer` takes about 5 minutes and has a 95% pass rate. [Here’s a diff of the two results.](https://gist.github.com/calebmer/1c9fe396b63ba055458c599c2be18a58) [Here is a selection of some of the bugs](https://gist.github.com/calebmer/1ac381096a4aa7be1fc7dc2163276ab4) in the serializer caught by running test262 with the Prepack serializer. I might open issues for these, but they can be a bit pedantic. I might fix some of them depending on how important they are to the React code we want to compile. Notably we have: - Lots of invariants being triggered. I particularly saw [a lot of this invariant](https://github.com/facebook/prepack/blob/7d355ef4c5f4d939742814714a78ef9b1279f9b4/src/serializer/ResidualHeapVisitor.js#L531). (An example of this is [`07.md`](https://gist.github.com/calebmer/1ac381096a4aa7be1fc7dc2163276ab4#file-07-md).) - Lots of values that are visited, but not serialized. (An example of this is [`01.md`](https://gist.github.com/calebmer/1ac381096a4aa7be1fc7dc2163276ab4#file-01-md).) - Some incorrect outputs only caught by executing code. Could not be caught by static analysis. Particularly around class serialization. I’ll build off this PR to get coverage for the abstract evaluator next, but I found these results interesting on their own so decided to do this in two PRs. Pull Request resolved: https://github.com/facebook/prepack/pull/2290 Differential Revision: D8908479 Pulled By: calebmer fbshipit-source-id: aa57d47611fbd92af33e4647fed7bf7990fb6de1
2018-07-19 04:48:13 +03:00
filterSneakyGenerators(banners, testFileContents) &&
(!options.serializer || filterReallyBigArrays(test, testFileContents));
2015-10-15 02:59:41 +03:00
let testResults = [];
if (keepThisTest) {
// now run the test
Add serializer mode for test262 execution (#2290) Summary: I want to better understand the bugs we have in abstract evaluation. One of my ideas to do this is to replace all the literals in test262 tests with abstract values and see what our test coverage is. The first step to do this is to serialize the test262 sources after running them in Prepack and checking if their generated JavaScript runs correctly. This PR does that by adding a `--serializer` flag. With my methodology, all test262 harnesses are serialized every time since they are in the global scope. This unfortunately seems to be unavoidable since doing otherwise would change program semantics and break the tests. Running `time yarn test-test262` takes about 2 minutes and has a 98% pass rate. Running `time yarn test-test262 --serializer` takes about 5 minutes and has a 95% pass rate. [Here’s a diff of the two results.](https://gist.github.com/calebmer/1c9fe396b63ba055458c599c2be18a58) [Here is a selection of some of the bugs](https://gist.github.com/calebmer/1ac381096a4aa7be1fc7dc2163276ab4) in the serializer caught by running test262 with the Prepack serializer. I might open issues for these, but they can be a bit pedantic. I might fix some of them depending on how important they are to the React code we want to compile. Notably we have: - Lots of invariants being triggered. I particularly saw [a lot of this invariant](https://github.com/facebook/prepack/blob/7d355ef4c5f4d939742814714a78ef9b1279f9b4/src/serializer/ResidualHeapVisitor.js#L531). (An example of this is [`07.md`](https://gist.github.com/calebmer/1ac381096a4aa7be1fc7dc2163276ab4#file-07-md).) - Lots of values that are visited, but not serialized. (An example of this is [`01.md`](https://gist.github.com/calebmer/1ac381096a4aa7be1fc7dc2163276ab4#file-01-md).) - Some incorrect outputs only caught by executing code. Could not be caught by static analysis. Particularly around class serialization. I’ll build off this PR to get coverage for the abstract evaluator next, but I found these results interesting on their own so decided to do this in two PRs. Pull Request resolved: https://github.com/facebook/prepack/pull/2290 Differential Revision: D8908479 Pulled By: calebmer fbshipit-source-id: aa57d47611fbd92af33e4647fed7bf7990fb6de1
2018-07-19 04:48:13 +03:00
testResults = runTestWithStrictness(test, testFileContents, banners, harnesses, options);
2015-10-15 02:59:41 +03:00
}
cb(null, testResults);
}
});
}
/**
* FIXME: this code is unsound in the presence of ENOENT (file not found)
* This function returns nested arrays of all the file names. It can be
* flattened at the call site, but the type hint is incorrect.
* DON'T USE THIS FUNCTION until it is fixed to behave exactly like getFilesSync
*/
/*
function getFiles(
filepath: string,
): Promise<TestFileInfo[]> {
return new Promise((resolve, reject) => {
fs.stat(filepath, (err, stat) => {
if (err !== null) {
reject(err);
} else {
if (stat.isFile()) {
// return an array of size 1
resolve([new TestFileInfo(filepath)]);
} else if (stat.isDirectory()) {
// recurse on its children
fs.readdir(filepath, (err, files) => {
if (err !== null) {
reject(err);
} else {
// FIXME flattening bug
// tmp is Promise<TestFileInfo[]>[] (array of promises of arrays)
// want to flatten that into Promise<TestFileInfo[]> where each
// promise is added to a single array
let tmp = files.map(f => getFiles(path.join(filepath, f)));
resolve(Promise.all(tmp));
}
});
}
}
});
});
}
*/
/**
* getFilesSync returns a TestFileInfo for each file that is underneath the
* directory ${filepath}. If ${filepath} is just a file, then it returns an
* array of size 1.
* This function synchronously fetches from the filesystem, as such it should
* only be used in initialization code that only runs once.
*/
function getFilesSync(filepath: string): TestFileInfo[] {
2015-10-15 02:59:41 +03:00
let stat = fs.statSync(filepath);
if (stat.isFile()) {
return [new TestFileInfo(filepath, false)];
} else if (stat.isDirectory()) {
let subFiles = fs.readdirSync(filepath);
return flatten(
subFiles.map(f => {
return getFilesSync(path.join(filepath, f));
})
);
2015-10-15 02:59:41 +03:00
} else {
throw new Error("That type of file is not supported");
}
}
function flatten<T>(arr: Array<Array<T>>): Array<T> {
return arr.reduce((a, b) => {
return a.concat(b);
}, []);
}
/**
* prepareTest opens the file corresponding to ${test} and calls ${cb} on the
* results, expect the ones for which ${filterFn} returns false.
* The value passed to ${cb} will be an error if the file could not be read,
* or the banner data for the test if successful.
* NOTE: if the test file contents match the filter function given, ${cb} will
* not be called for that test.
*/
function prepareTest(
test: TestFileInfo,
filterFn: (test: TestFileInfo, fileContents: string) => boolean,
cb: (err: ?Error, res: ?BannerData, testFileContents: ?string) => void
): void {
fs.readFile(test.location, (err, contents) => {
if (err != null) {
cb(err, null, null);
} else {
let contentsStr = contents.toString();
// check if this test should be filtered
if (!filterFn(test, contentsStr)) {
// skip this test
cb(null, null, null);
} else {
try {
let banners = getBanners(test, contentsStr);
cb(null, banners, contentsStr);
} catch (bannerParseErr) {
cb(bannerParseErr, null, null);
}
}
}
});
}
function createRealm(timeout: number): { realm: Realm, $: ObjectValue } {
// Create a new realm.
let realm = construct_realm({
strictlyMonotonicDateNow: true,
errorHandler: () => "Fail",
timeout: timeout * 1000,
});
Refactor global intrinsics initialization (#477) We used initialize all possible environments in a single intrinsics entry point. That doesn't quite scale to many and complex environments. So the goal of this refactor is to invert the initialization of globals. Now a Realm is created with only the standard ECMA262 intrinsics. This is also important because we should be able to create new realms from within user code to model things like iframes, node.js contextify and the new standard Realm API that is used to create new realms. All of these basically starts out with a standard realm that can then be expanded. Then the actual initialization of the global happens outside of the serializer so that the serializer dependency isn't coupled to any particular set of environments. To do this I created a "global.js" file for each environment inside of intrinsics. It's interesting to note that "console" and timers isn't part of the standard realm. Another interesting one is that "global" isn't actually part of the DOM environment yet. It might be if this proposal gets through: https://github.com/tc39/proposal-global However, since so many tests depend on global, including in test262, I model it as already part of ECMA262 globals. I also had move the initialization of the realm out of the serializer API so that it is possible to initialize the realm with arbitrary intrinsics before that happens. However, when I did that I had to move the attaching of of the generator into the serializer because otherwise mutations to intrinsics during initialization gets tracked as something to serialize. This might help avoid the cycle problem that construct_realm was meant to fix so that we can just go back to using a simple constructor for Realm.
2017-04-28 04:11:37 +03:00
initializeGlobals(realm);
2015-10-15 02:59:41 +03:00
let executionContext = new ExecutionContext();
executionContext.realm = realm;
realm.pushContext(executionContext);
2015-10-15 02:59:41 +03:00
// Create the Host-Defined functions.
let $ = new ObjectValue(realm);
$.defineNativeMethod("createRealm", 0, context => {
2015-10-15 02:59:41 +03:00
return createRealm(timeout).$;
});
$.defineNativeMethod("detachArrayBuffer", 1, (context, [buffer]) => {
return DetachArrayBuffer(realm, buffer);
});
$.defineNativeMethod("evalScript", 1, (context, [sourceText]) => {
// TODO: eval
return realm.intrinsics.undefined;
});
$.defineNativeProperty("global", realm.$GlobalObject);
let glob = ((realm.$GlobalObject: any): ObjectValue);
glob.defineNativeProperty("$262", $);
glob.defineNativeMethod("print", 1, (context, [arg]) => {
return realm.intrinsics.undefined;
});
2015-10-15 02:59:41 +03:00
return { realm, $ };
}
/**
* runTest executes the test given by ${test} whose contents are
* ${testFileContents}.
* It returns None if the test should is skipped, otherwise it returns a
* TestResult.
*/
function runTest(
test: TestFileInfo,
testFileContents: string,
data: BannerData,
// eslint-disable-next-line flowtype/no-weak-types
harnesses: Object,
strict: boolean,
Add abstract serializer mode for test262 execution (#2297) Summary: I extended the `--serializer` command line argument I added in #2290 to now support `--serializer abstract-scalar`. What this mode does is it converts all boolean, string, number, and symbol literals into abstract values. I did not choose to extend this logic to object and array literals just yet since scalars alone showed some interesting results. What I really want here is a review of the results. Full suite execution results are real bad. **18%** pass rate. I dug a bit into why. ``` === RESULTS === Passes: 3356 / 17780 (18%) ES5 passes: 2276 / 12045 (18%) ES6 passes: 1080 / 5735 (18%) Skipped: 13375 Timeouts: 28 ``` I was mostly interested in the runtime failures we see since that means Prepack is serializing invalid code. However, I found ~14k failures in the Prepack stage (more on this in a bit) and ~3k failures in the runtime stage. This means ~80% of tests _fail to compile_ with this abstract transformation applied. Why are these tests failing? I took the first 4 items of the stack traces from errors thrown in the Prepack stage, sorted, and ranked them. [Here’s the result.](https://gist.github.com/calebmer/29e27613325fd99fa04be7ab4a9641c0) The top 5 with thousands of hits are: ``` 7538 of: at AbstractValue.throwIfNotConcrete (/Users/calebmer/prepack/src/values/AbstractValue.js:536:11) at ToImplementation.ToStringPartial (/Users/calebmer/prepack/src/methods/to.js:717:69) at NativeFunctionValue._index.NativeFunctionValue [as callback] (/Users/calebmer/prepack/src/intrinsics/ecma262/String.js:34:37) at NativeFunctionValue.callCallback (/Users/calebmer/prepack/src/values/NativeFunctionValue.js:121:12) 4595 of: at AbstractValue.throwIfNotConcrete (/Users/calebmer/prepack/src/values/AbstractValue.js:536:11) at NativeFunctionValue.func.defineNativeMethod [as callback] (/Users/calebmer/prepack/src/intrinsics/ecma262/Object.js:328:41) at NativeFunctionValue.callCallback (/Users/calebmer/prepack/src/values/NativeFunctionValue.js:121:12) at functionCall (/Users/calebmer/prepack/src/methods/call.js:308:26) 1454 of: at AbstractValue.throwIfNotConcrete (/Users/calebmer/prepack/src/values/AbstractValue.js:536:11) at NativeFunctionValue.func.defineNativeMethod [as callback] (/Users/calebmer/prepack/src/intrinsics/ecma262/Object.js:364:41) at NativeFunctionValue.callCallback (/Users/calebmer/prepack/src/values/NativeFunctionValue.js:121:12) at functionCall (/Users/calebmer/prepack/src/methods/call.js:308:26) 1351 of: at invariant (/Users/calebmer/prepack/src/invariant.js:18:15) at EvalPropertyNamePartial (/Users/calebmer/prepack/src/evaluators/ObjectExpression.js:59:7) at _default (/Users/calebmer/prepack/src/evaluators/ObjectExpression.js:80:21) at LexicalEnvironment.evaluateAbstract (/Users/calebmer/prepack/src/environment.js:1368:20) 1053 of: at AbstractValue.throwIfNotConcrete (/Users/calebmer/prepack/src/values/AbstractValue.js:536:11) at NativeFunctionValue.obj.defineNativeMethod [as callback] (/Users/calebmer/prepack/src/intrinsics/ecma262/ObjectPrototype.js:35:39) at NativeFunctionValue.callCallback (/Users/calebmer/prepack/src/values/NativeFunctionValue.js:121:12) at functionCall (/Users/calebmer/prepack/src/methods/call.js:308:26) ``` This means there may be some low hanging fruit. Here are my questions for you. - Did you expect results like this? - What is our ideal test262 pass rate with this transformation applied? - What happens to React Compiler or other projects when these errors are thrown? (As I understand it, we bail out and don’t optimize the code, but do optimize the code around it.) - Do you think my methodology is flawed? It’s also possible that something in my methodology is wrong, but I didn’t spend much time investigating these failures as I spent investigating the failures I found in #2290. My goal with this test suite is to build an understanding of what “correctness” for the React Compiler against all JavaScript code looks like. (Not just the few bundles we’ve selected to look at.) I don’t think these results suggest that we only safely compile 18% of the language, but it’s a data point. I’ll be looking into fixing a selection of these issues to better understand their nature or if I need to change methodologies. Pull Request resolved: https://github.com/facebook/prepack/pull/2297 Differential Revision: D9120572 Pulled By: calebmer fbshipit-source-id: b394f1e8da034c9985366010e3e63fd55fd94168
2018-08-01 20:28:28 +03:00
options: TestRunOptions
2015-10-15 02:59:41 +03:00
): ?TestResult {
Add abstract serializer mode for test262 execution (#2297) Summary: I extended the `--serializer` command line argument I added in #2290 to now support `--serializer abstract-scalar`. What this mode does is it converts all boolean, string, number, and symbol literals into abstract values. I did not choose to extend this logic to object and array literals just yet since scalars alone showed some interesting results. What I really want here is a review of the results. Full suite execution results are real bad. **18%** pass rate. I dug a bit into why. ``` === RESULTS === Passes: 3356 / 17780 (18%) ES5 passes: 2276 / 12045 (18%) ES6 passes: 1080 / 5735 (18%) Skipped: 13375 Timeouts: 28 ``` I was mostly interested in the runtime failures we see since that means Prepack is serializing invalid code. However, I found ~14k failures in the Prepack stage (more on this in a bit) and ~3k failures in the runtime stage. This means ~80% of tests _fail to compile_ with this abstract transformation applied. Why are these tests failing? I took the first 4 items of the stack traces from errors thrown in the Prepack stage, sorted, and ranked them. [Here’s the result.](https://gist.github.com/calebmer/29e27613325fd99fa04be7ab4a9641c0) The top 5 with thousands of hits are: ``` 7538 of: at AbstractValue.throwIfNotConcrete (/Users/calebmer/prepack/src/values/AbstractValue.js:536:11) at ToImplementation.ToStringPartial (/Users/calebmer/prepack/src/methods/to.js:717:69) at NativeFunctionValue._index.NativeFunctionValue [as callback] (/Users/calebmer/prepack/src/intrinsics/ecma262/String.js:34:37) at NativeFunctionValue.callCallback (/Users/calebmer/prepack/src/values/NativeFunctionValue.js:121:12) 4595 of: at AbstractValue.throwIfNotConcrete (/Users/calebmer/prepack/src/values/AbstractValue.js:536:11) at NativeFunctionValue.func.defineNativeMethod [as callback] (/Users/calebmer/prepack/src/intrinsics/ecma262/Object.js:328:41) at NativeFunctionValue.callCallback (/Users/calebmer/prepack/src/values/NativeFunctionValue.js:121:12) at functionCall (/Users/calebmer/prepack/src/methods/call.js:308:26) 1454 of: at AbstractValue.throwIfNotConcrete (/Users/calebmer/prepack/src/values/AbstractValue.js:536:11) at NativeFunctionValue.func.defineNativeMethod [as callback] (/Users/calebmer/prepack/src/intrinsics/ecma262/Object.js:364:41) at NativeFunctionValue.callCallback (/Users/calebmer/prepack/src/values/NativeFunctionValue.js:121:12) at functionCall (/Users/calebmer/prepack/src/methods/call.js:308:26) 1351 of: at invariant (/Users/calebmer/prepack/src/invariant.js:18:15) at EvalPropertyNamePartial (/Users/calebmer/prepack/src/evaluators/ObjectExpression.js:59:7) at _default (/Users/calebmer/prepack/src/evaluators/ObjectExpression.js:80:21) at LexicalEnvironment.evaluateAbstract (/Users/calebmer/prepack/src/environment.js:1368:20) 1053 of: at AbstractValue.throwIfNotConcrete (/Users/calebmer/prepack/src/values/AbstractValue.js:536:11) at NativeFunctionValue.obj.defineNativeMethod [as callback] (/Users/calebmer/prepack/src/intrinsics/ecma262/ObjectPrototype.js:35:39) at NativeFunctionValue.callCallback (/Users/calebmer/prepack/src/values/NativeFunctionValue.js:121:12) at functionCall (/Users/calebmer/prepack/src/methods/call.js:308:26) ``` This means there may be some low hanging fruit. Here are my questions for you. - Did you expect results like this? - What is our ideal test262 pass rate with this transformation applied? - What happens to React Compiler or other projects when these errors are thrown? (As I understand it, we bail out and don’t optimize the code, but do optimize the code around it.) - Do you think my methodology is flawed? It’s also possible that something in my methodology is wrong, but I didn’t spend much time investigating these failures as I spent investigating the failures I found in #2290. My goal with this test suite is to build an understanding of what “correctness” for the React Compiler against all JavaScript code looks like. (Not just the few bundles we’ve selected to look at.) I don’t think these results suggest that we only safely compile 18% of the language, but it’s a data point. I’ll be looking into fixing a selection of these issues to better understand their nature or if I need to change methodologies. Pull Request resolved: https://github.com/facebook/prepack/pull/2297 Differential Revision: D9120572 Pulled By: calebmer fbshipit-source-id: b394f1e8da034c9985366010e3e63fd55fd94168
2018-08-01 20:28:28 +03:00
if (options.serializer) {
return executeTestUsingSerializer(test, testFileContents, data, harnesses, strict, options);
Add serializer mode for test262 execution (#2290) Summary: I want to better understand the bugs we have in abstract evaluation. One of my ideas to do this is to replace all the literals in test262 tests with abstract values and see what our test coverage is. The first step to do this is to serialize the test262 sources after running them in Prepack and checking if their generated JavaScript runs correctly. This PR does that by adding a `--serializer` flag. With my methodology, all test262 harnesses are serialized every time since they are in the global scope. This unfortunately seems to be unavoidable since doing otherwise would change program semantics and break the tests. Running `time yarn test-test262` takes about 2 minutes and has a 98% pass rate. Running `time yarn test-test262 --serializer` takes about 5 minutes and has a 95% pass rate. [Here’s a diff of the two results.](https://gist.github.com/calebmer/1c9fe396b63ba055458c599c2be18a58) [Here is a selection of some of the bugs](https://gist.github.com/calebmer/1ac381096a4aa7be1fc7dc2163276ab4) in the serializer caught by running test262 with the Prepack serializer. I might open issues for these, but they can be a bit pedantic. I might fix some of them depending on how important they are to the React code we want to compile. Notably we have: - Lots of invariants being triggered. I particularly saw [a lot of this invariant](https://github.com/facebook/prepack/blob/7d355ef4c5f4d939742814714a78ef9b1279f9b4/src/serializer/ResidualHeapVisitor.js#L531). (An example of this is [`07.md`](https://gist.github.com/calebmer/1ac381096a4aa7be1fc7dc2163276ab4#file-07-md).) - Lots of values that are visited, but not serialized. (An example of this is [`01.md`](https://gist.github.com/calebmer/1ac381096a4aa7be1fc7dc2163276ab4#file-01-md).) - Some incorrect outputs only caught by executing code. Could not be caught by static analysis. Particularly around class serialization. I’ll build off this PR to get coverage for the abstract evaluator next, but I found these results interesting on their own so decided to do this in two PRs. Pull Request resolved: https://github.com/facebook/prepack/pull/2290 Differential Revision: D8908479 Pulled By: calebmer fbshipit-source-id: aa57d47611fbd92af33e4647fed7bf7990fb6de1
2018-07-19 04:48:13 +03:00
}
Add abstract serializer mode for test262 execution (#2297) Summary: I extended the `--serializer` command line argument I added in #2290 to now support `--serializer abstract-scalar`. What this mode does is it converts all boolean, string, number, and symbol literals into abstract values. I did not choose to extend this logic to object and array literals just yet since scalars alone showed some interesting results. What I really want here is a review of the results. Full suite execution results are real bad. **18%** pass rate. I dug a bit into why. ``` === RESULTS === Passes: 3356 / 17780 (18%) ES5 passes: 2276 / 12045 (18%) ES6 passes: 1080 / 5735 (18%) Skipped: 13375 Timeouts: 28 ``` I was mostly interested in the runtime failures we see since that means Prepack is serializing invalid code. However, I found ~14k failures in the Prepack stage (more on this in a bit) and ~3k failures in the runtime stage. This means ~80% of tests _fail to compile_ with this abstract transformation applied. Why are these tests failing? I took the first 4 items of the stack traces from errors thrown in the Prepack stage, sorted, and ranked them. [Here’s the result.](https://gist.github.com/calebmer/29e27613325fd99fa04be7ab4a9641c0) The top 5 with thousands of hits are: ``` 7538 of: at AbstractValue.throwIfNotConcrete (/Users/calebmer/prepack/src/values/AbstractValue.js:536:11) at ToImplementation.ToStringPartial (/Users/calebmer/prepack/src/methods/to.js:717:69) at NativeFunctionValue._index.NativeFunctionValue [as callback] (/Users/calebmer/prepack/src/intrinsics/ecma262/String.js:34:37) at NativeFunctionValue.callCallback (/Users/calebmer/prepack/src/values/NativeFunctionValue.js:121:12) 4595 of: at AbstractValue.throwIfNotConcrete (/Users/calebmer/prepack/src/values/AbstractValue.js:536:11) at NativeFunctionValue.func.defineNativeMethod [as callback] (/Users/calebmer/prepack/src/intrinsics/ecma262/Object.js:328:41) at NativeFunctionValue.callCallback (/Users/calebmer/prepack/src/values/NativeFunctionValue.js:121:12) at functionCall (/Users/calebmer/prepack/src/methods/call.js:308:26) 1454 of: at AbstractValue.throwIfNotConcrete (/Users/calebmer/prepack/src/values/AbstractValue.js:536:11) at NativeFunctionValue.func.defineNativeMethod [as callback] (/Users/calebmer/prepack/src/intrinsics/ecma262/Object.js:364:41) at NativeFunctionValue.callCallback (/Users/calebmer/prepack/src/values/NativeFunctionValue.js:121:12) at functionCall (/Users/calebmer/prepack/src/methods/call.js:308:26) 1351 of: at invariant (/Users/calebmer/prepack/src/invariant.js:18:15) at EvalPropertyNamePartial (/Users/calebmer/prepack/src/evaluators/ObjectExpression.js:59:7) at _default (/Users/calebmer/prepack/src/evaluators/ObjectExpression.js:80:21) at LexicalEnvironment.evaluateAbstract (/Users/calebmer/prepack/src/environment.js:1368:20) 1053 of: at AbstractValue.throwIfNotConcrete (/Users/calebmer/prepack/src/values/AbstractValue.js:536:11) at NativeFunctionValue.obj.defineNativeMethod [as callback] (/Users/calebmer/prepack/src/intrinsics/ecma262/ObjectPrototype.js:35:39) at NativeFunctionValue.callCallback (/Users/calebmer/prepack/src/values/NativeFunctionValue.js:121:12) at functionCall (/Users/calebmer/prepack/src/methods/call.js:308:26) ``` This means there may be some low hanging fruit. Here are my questions for you. - Did you expect results like this? - What is our ideal test262 pass rate with this transformation applied? - What happens to React Compiler or other projects when these errors are thrown? (As I understand it, we bail out and don’t optimize the code, but do optimize the code around it.) - Do you think my methodology is flawed? It’s also possible that something in my methodology is wrong, but I didn’t spend much time investigating these failures as I spent investigating the failures I found in #2290. My goal with this test suite is to build an understanding of what “correctness” for the React Compiler against all JavaScript code looks like. (Not just the few bundles we’ve selected to look at.) I don’t think these results suggest that we only safely compile 18% of the language, but it’s a data point. I’ll be looking into fixing a selection of these issues to better understand their nature or if I need to change methodologies. Pull Request resolved: https://github.com/facebook/prepack/pull/2297 Differential Revision: D9120572 Pulled By: calebmer fbshipit-source-id: b394f1e8da034c9985366010e3e63fd55fd94168
2018-08-01 20:28:28 +03:00
let { realm } = createRealm(options.timeout);
2015-10-15 02:59:41 +03:00
// Run the test.
try {
try {
// execute the harnesss first
for (let name of ["sta.js", "assert.js"].concat(data.includes || [])) {
let harness = harnesses[name];
let completion = realm.$GlobalEnv.execute(harness, name);
if (completion instanceof ThrowCompletion) throw completion;
}
let completion = realm.$GlobalEnv.execute(
(strict ? '"use strict";' + EOL : "") + testFileContents,
2015-10-15 02:59:41 +03:00
test.location
);
if (completion instanceof ThrowCompletion) throw completion;
if (completion instanceof AbruptCompletion)
return new TestResult(false, strict, new Error("Unexpected abrupt completion"));
2015-10-15 02:59:41 +03:00
} catch (err) {
if (err.message === "Timed out") return new TestResult(false, strict, err);
2015-10-15 02:59:41 +03:00
if (!data.negative || data.negative !== err.name) {
throw err;
}
}
if (data.negative.type) {
throw new Error("Was supposed to error with type " + data.negative.type + " but passed");
2015-10-15 02:59:41 +03:00
}
// succeeded
return new TestResult(true, strict);
} catch (err) {
Add serializer mode for test262 execution (#2290) Summary: I want to better understand the bugs we have in abstract evaluation. One of my ideas to do this is to replace all the literals in test262 tests with abstract values and see what our test coverage is. The first step to do this is to serialize the test262 sources after running them in Prepack and checking if their generated JavaScript runs correctly. This PR does that by adding a `--serializer` flag. With my methodology, all test262 harnesses are serialized every time since they are in the global scope. This unfortunately seems to be unavoidable since doing otherwise would change program semantics and break the tests. Running `time yarn test-test262` takes about 2 minutes and has a 98% pass rate. Running `time yarn test-test262 --serializer` takes about 5 minutes and has a 95% pass rate. [Here’s a diff of the two results.](https://gist.github.com/calebmer/1c9fe396b63ba055458c599c2be18a58) [Here is a selection of some of the bugs](https://gist.github.com/calebmer/1ac381096a4aa7be1fc7dc2163276ab4) in the serializer caught by running test262 with the Prepack serializer. I might open issues for these, but they can be a bit pedantic. I might fix some of them depending on how important they are to the React code we want to compile. Notably we have: - Lots of invariants being triggered. I particularly saw [a lot of this invariant](https://github.com/facebook/prepack/blob/7d355ef4c5f4d939742814714a78ef9b1279f9b4/src/serializer/ResidualHeapVisitor.js#L531). (An example of this is [`07.md`](https://gist.github.com/calebmer/1ac381096a4aa7be1fc7dc2163276ab4#file-07-md).) - Lots of values that are visited, but not serialized. (An example of this is [`01.md`](https://gist.github.com/calebmer/1ac381096a4aa7be1fc7dc2163276ab4#file-01-md).) - Some incorrect outputs only caught by executing code. Could not be caught by static analysis. Particularly around class serialization. I’ll build off this PR to get coverage for the abstract evaluator next, but I found these results interesting on their own so decided to do this in two PRs. Pull Request resolved: https://github.com/facebook/prepack/pull/2290 Differential Revision: D8908479 Pulled By: calebmer fbshipit-source-id: aa57d47611fbd92af33e4647fed7bf7990fb6de1
2018-07-19 04:48:13 +03:00
// Skip syntax errors.
if (err.value && err.value.$Prototype && err.value.$Prototype.intrinsicName === "SyntaxError.prototype") {
return null;
2015-10-15 02:59:41 +03:00
}
let stack = err.stack;
if (data.negative.type) {
let type = data.negative.type;
if (
err &&
err instanceof ThrowCompletion &&
err.value instanceof ObjectValue &&
(Get(realm, err.value, "name"): any).value === type
) {
2015-10-15 02:59:41 +03:00
// Expected an error and got one.
return new TestResult(true, strict);
} else {
// Expected an error, but got something else.
if (err && err instanceof ThrowCompletion) {
return new TestResult(false, strict, err);
} else {
return new TestResult(false, strict, new Error(`Expected an error, but got something else: ${err.message}`));
2015-10-15 02:59:41 +03:00
}
}
} else {
// Not expecting an error, but got one.
try {
if (err && err instanceof ThrowCompletion) {
let interpreterStack: void | string;
2015-10-15 02:59:41 +03:00
if (err.value instanceof ObjectValue) {
if (err.value.$HasProperty("stack")) {
interpreterStack = To.ToStringPartial(realm, Get(realm, err.value, "stack"));
2015-10-15 02:59:41 +03:00
} else {
interpreterStack = To.ToStringPartial(realm, Get(realm, err.value, "message"));
2015-10-15 02:59:41 +03:00
}
// filter out if the error stack is due to async
if (interpreterStack.includes("async ")) {
return null;
}
} else if (err.value instanceof StringValue) {
interpreterStack = err.value.value;
if (interpreterStack === "only plain identifiers are supported in parameter lists") {
return null;
}
}
// Many strict-only tests involving eval check if certain SyntaxErrors are thrown.
// Some of those would require changes to Babel to support properly, and some we should handle ourselves in Prepack some day.
// But for now, ignore.
if (testFileContents.includes("eval(") && strict) {
return null;
}
2015-10-15 02:59:41 +03:00
if (interpreterStack) {
stack = `Interpreter: ${interpreterStack}${EOL}Native: ${err.nativeStack}`;
}
}
} catch (_err) {
stack = _err.stack;
}
return new TestResult(false, strict, new Error(`Got an error, but was not expecting one:${EOL}${stack}`));
2015-10-15 02:59:41 +03:00
}
}
}
Add serializer mode for test262 execution (#2290) Summary: I want to better understand the bugs we have in abstract evaluation. One of my ideas to do this is to replace all the literals in test262 tests with abstract values and see what our test coverage is. The first step to do this is to serialize the test262 sources after running them in Prepack and checking if their generated JavaScript runs correctly. This PR does that by adding a `--serializer` flag. With my methodology, all test262 harnesses are serialized every time since they are in the global scope. This unfortunately seems to be unavoidable since doing otherwise would change program semantics and break the tests. Running `time yarn test-test262` takes about 2 minutes and has a 98% pass rate. Running `time yarn test-test262 --serializer` takes about 5 minutes and has a 95% pass rate. [Here’s a diff of the two results.](https://gist.github.com/calebmer/1c9fe396b63ba055458c599c2be18a58) [Here is a selection of some of the bugs](https://gist.github.com/calebmer/1ac381096a4aa7be1fc7dc2163276ab4) in the serializer caught by running test262 with the Prepack serializer. I might open issues for these, but they can be a bit pedantic. I might fix some of them depending on how important they are to the React code we want to compile. Notably we have: - Lots of invariants being triggered. I particularly saw [a lot of this invariant](https://github.com/facebook/prepack/blob/7d355ef4c5f4d939742814714a78ef9b1279f9b4/src/serializer/ResidualHeapVisitor.js#L531). (An example of this is [`07.md`](https://gist.github.com/calebmer/1ac381096a4aa7be1fc7dc2163276ab4#file-07-md).) - Lots of values that are visited, but not serialized. (An example of this is [`01.md`](https://gist.github.com/calebmer/1ac381096a4aa7be1fc7dc2163276ab4#file-01-md).) - Some incorrect outputs only caught by executing code. Could not be caught by static analysis. Particularly around class serialization. I’ll build off this PR to get coverage for the abstract evaluator next, but I found these results interesting on their own so decided to do this in two PRs. Pull Request resolved: https://github.com/facebook/prepack/pull/2290 Differential Revision: D8908479 Pulled By: calebmer fbshipit-source-id: aa57d47611fbd92af33e4647fed7bf7990fb6de1
2018-07-19 04:48:13 +03:00
function executeTestUsingSerializer(
test: TestFileInfo,
testFileContents: string,
data: BannerData,
// eslint-disable-next-line flowtype/no-weak-types
harnesses: Object,
strict: boolean,
Add abstract serializer mode for test262 execution (#2297) Summary: I extended the `--serializer` command line argument I added in #2290 to now support `--serializer abstract-scalar`. What this mode does is it converts all boolean, string, number, and symbol literals into abstract values. I did not choose to extend this logic to object and array literals just yet since scalars alone showed some interesting results. What I really want here is a review of the results. Full suite execution results are real bad. **18%** pass rate. I dug a bit into why. ``` === RESULTS === Passes: 3356 / 17780 (18%) ES5 passes: 2276 / 12045 (18%) ES6 passes: 1080 / 5735 (18%) Skipped: 13375 Timeouts: 28 ``` I was mostly interested in the runtime failures we see since that means Prepack is serializing invalid code. However, I found ~14k failures in the Prepack stage (more on this in a bit) and ~3k failures in the runtime stage. This means ~80% of tests _fail to compile_ with this abstract transformation applied. Why are these tests failing? I took the first 4 items of the stack traces from errors thrown in the Prepack stage, sorted, and ranked them. [Here’s the result.](https://gist.github.com/calebmer/29e27613325fd99fa04be7ab4a9641c0) The top 5 with thousands of hits are: ``` 7538 of: at AbstractValue.throwIfNotConcrete (/Users/calebmer/prepack/src/values/AbstractValue.js:536:11) at ToImplementation.ToStringPartial (/Users/calebmer/prepack/src/methods/to.js:717:69) at NativeFunctionValue._index.NativeFunctionValue [as callback] (/Users/calebmer/prepack/src/intrinsics/ecma262/String.js:34:37) at NativeFunctionValue.callCallback (/Users/calebmer/prepack/src/values/NativeFunctionValue.js:121:12) 4595 of: at AbstractValue.throwIfNotConcrete (/Users/calebmer/prepack/src/values/AbstractValue.js:536:11) at NativeFunctionValue.func.defineNativeMethod [as callback] (/Users/calebmer/prepack/src/intrinsics/ecma262/Object.js:328:41) at NativeFunctionValue.callCallback (/Users/calebmer/prepack/src/values/NativeFunctionValue.js:121:12) at functionCall (/Users/calebmer/prepack/src/methods/call.js:308:26) 1454 of: at AbstractValue.throwIfNotConcrete (/Users/calebmer/prepack/src/values/AbstractValue.js:536:11) at NativeFunctionValue.func.defineNativeMethod [as callback] (/Users/calebmer/prepack/src/intrinsics/ecma262/Object.js:364:41) at NativeFunctionValue.callCallback (/Users/calebmer/prepack/src/values/NativeFunctionValue.js:121:12) at functionCall (/Users/calebmer/prepack/src/methods/call.js:308:26) 1351 of: at invariant (/Users/calebmer/prepack/src/invariant.js:18:15) at EvalPropertyNamePartial (/Users/calebmer/prepack/src/evaluators/ObjectExpression.js:59:7) at _default (/Users/calebmer/prepack/src/evaluators/ObjectExpression.js:80:21) at LexicalEnvironment.evaluateAbstract (/Users/calebmer/prepack/src/environment.js:1368:20) 1053 of: at AbstractValue.throwIfNotConcrete (/Users/calebmer/prepack/src/values/AbstractValue.js:536:11) at NativeFunctionValue.obj.defineNativeMethod [as callback] (/Users/calebmer/prepack/src/intrinsics/ecma262/ObjectPrototype.js:35:39) at NativeFunctionValue.callCallback (/Users/calebmer/prepack/src/values/NativeFunctionValue.js:121:12) at functionCall (/Users/calebmer/prepack/src/methods/call.js:308:26) ``` This means there may be some low hanging fruit. Here are my questions for you. - Did you expect results like this? - What is our ideal test262 pass rate with this transformation applied? - What happens to React Compiler or other projects when these errors are thrown? (As I understand it, we bail out and don’t optimize the code, but do optimize the code around it.) - Do you think my methodology is flawed? It’s also possible that something in my methodology is wrong, but I didn’t spend much time investigating these failures as I spent investigating the failures I found in #2290. My goal with this test suite is to build an understanding of what “correctness” for the React Compiler against all JavaScript code looks like. (Not just the few bundles we’ve selected to look at.) I don’t think these results suggest that we only safely compile 18% of the language, but it’s a data point. I’ll be looking into fixing a selection of these issues to better understand their nature or if I need to change methodologies. Pull Request resolved: https://github.com/facebook/prepack/pull/2297 Differential Revision: D9120572 Pulled By: calebmer fbshipit-source-id: b394f1e8da034c9985366010e3e63fd55fd94168
2018-08-01 20:28:28 +03:00
options: TestRunOptions
Add serializer mode for test262 execution (#2290) Summary: I want to better understand the bugs we have in abstract evaluation. One of my ideas to do this is to replace all the literals in test262 tests with abstract values and see what our test coverage is. The first step to do this is to serialize the test262 sources after running them in Prepack and checking if their generated JavaScript runs correctly. This PR does that by adding a `--serializer` flag. With my methodology, all test262 harnesses are serialized every time since they are in the global scope. This unfortunately seems to be unavoidable since doing otherwise would change program semantics and break the tests. Running `time yarn test-test262` takes about 2 minutes and has a 98% pass rate. Running `time yarn test-test262 --serializer` takes about 5 minutes and has a 95% pass rate. [Here’s a diff of the two results.](https://gist.github.com/calebmer/1c9fe396b63ba055458c599c2be18a58) [Here is a selection of some of the bugs](https://gist.github.com/calebmer/1ac381096a4aa7be1fc7dc2163276ab4) in the serializer caught by running test262 with the Prepack serializer. I might open issues for these, but they can be a bit pedantic. I might fix some of them depending on how important they are to the React code we want to compile. Notably we have: - Lots of invariants being triggered. I particularly saw [a lot of this invariant](https://github.com/facebook/prepack/blob/7d355ef4c5f4d939742814714a78ef9b1279f9b4/src/serializer/ResidualHeapVisitor.js#L531). (An example of this is [`07.md`](https://gist.github.com/calebmer/1ac381096a4aa7be1fc7dc2163276ab4#file-07-md).) - Lots of values that are visited, but not serialized. (An example of this is [`01.md`](https://gist.github.com/calebmer/1ac381096a4aa7be1fc7dc2163276ab4#file-01-md).) - Some incorrect outputs only caught by executing code. Could not be caught by static analysis. Particularly around class serialization. I’ll build off this PR to get coverage for the abstract evaluator next, but I found these results interesting on their own so decided to do this in two PRs. Pull Request resolved: https://github.com/facebook/prepack/pull/2290 Differential Revision: D8908479 Pulled By: calebmer fbshipit-source-id: aa57d47611fbd92af33e4647fed7bf7990fb6de1
2018-07-19 04:48:13 +03:00
) {
Add abstract serializer mode for test262 execution (#2297) Summary: I extended the `--serializer` command line argument I added in #2290 to now support `--serializer abstract-scalar`. What this mode does is it converts all boolean, string, number, and symbol literals into abstract values. I did not choose to extend this logic to object and array literals just yet since scalars alone showed some interesting results. What I really want here is a review of the results. Full suite execution results are real bad. **18%** pass rate. I dug a bit into why. ``` === RESULTS === Passes: 3356 / 17780 (18%) ES5 passes: 2276 / 12045 (18%) ES6 passes: 1080 / 5735 (18%) Skipped: 13375 Timeouts: 28 ``` I was mostly interested in the runtime failures we see since that means Prepack is serializing invalid code. However, I found ~14k failures in the Prepack stage (more on this in a bit) and ~3k failures in the runtime stage. This means ~80% of tests _fail to compile_ with this abstract transformation applied. Why are these tests failing? I took the first 4 items of the stack traces from errors thrown in the Prepack stage, sorted, and ranked them. [Here’s the result.](https://gist.github.com/calebmer/29e27613325fd99fa04be7ab4a9641c0) The top 5 with thousands of hits are: ``` 7538 of: at AbstractValue.throwIfNotConcrete (/Users/calebmer/prepack/src/values/AbstractValue.js:536:11) at ToImplementation.ToStringPartial (/Users/calebmer/prepack/src/methods/to.js:717:69) at NativeFunctionValue._index.NativeFunctionValue [as callback] (/Users/calebmer/prepack/src/intrinsics/ecma262/String.js:34:37) at NativeFunctionValue.callCallback (/Users/calebmer/prepack/src/values/NativeFunctionValue.js:121:12) 4595 of: at AbstractValue.throwIfNotConcrete (/Users/calebmer/prepack/src/values/AbstractValue.js:536:11) at NativeFunctionValue.func.defineNativeMethod [as callback] (/Users/calebmer/prepack/src/intrinsics/ecma262/Object.js:328:41) at NativeFunctionValue.callCallback (/Users/calebmer/prepack/src/values/NativeFunctionValue.js:121:12) at functionCall (/Users/calebmer/prepack/src/methods/call.js:308:26) 1454 of: at AbstractValue.throwIfNotConcrete (/Users/calebmer/prepack/src/values/AbstractValue.js:536:11) at NativeFunctionValue.func.defineNativeMethod [as callback] (/Users/calebmer/prepack/src/intrinsics/ecma262/Object.js:364:41) at NativeFunctionValue.callCallback (/Users/calebmer/prepack/src/values/NativeFunctionValue.js:121:12) at functionCall (/Users/calebmer/prepack/src/methods/call.js:308:26) 1351 of: at invariant (/Users/calebmer/prepack/src/invariant.js:18:15) at EvalPropertyNamePartial (/Users/calebmer/prepack/src/evaluators/ObjectExpression.js:59:7) at _default (/Users/calebmer/prepack/src/evaluators/ObjectExpression.js:80:21) at LexicalEnvironment.evaluateAbstract (/Users/calebmer/prepack/src/environment.js:1368:20) 1053 of: at AbstractValue.throwIfNotConcrete (/Users/calebmer/prepack/src/values/AbstractValue.js:536:11) at NativeFunctionValue.obj.defineNativeMethod [as callback] (/Users/calebmer/prepack/src/intrinsics/ecma262/ObjectPrototype.js:35:39) at NativeFunctionValue.callCallback (/Users/calebmer/prepack/src/values/NativeFunctionValue.js:121:12) at functionCall (/Users/calebmer/prepack/src/methods/call.js:308:26) ``` This means there may be some low hanging fruit. Here are my questions for you. - Did you expect results like this? - What is our ideal test262 pass rate with this transformation applied? - What happens to React Compiler or other projects when these errors are thrown? (As I understand it, we bail out and don’t optimize the code, but do optimize the code around it.) - Do you think my methodology is flawed? It’s also possible that something in my methodology is wrong, but I didn’t spend much time investigating these failures as I spent investigating the failures I found in #2290. My goal with this test suite is to build an understanding of what “correctness” for the React Compiler against all JavaScript code looks like. (Not just the few bundles we’ve selected to look at.) I don’t think these results suggest that we only safely compile 18% of the language, but it’s a data point. I’ll be looking into fixing a selection of these issues to better understand their nature or if I need to change methodologies. Pull Request resolved: https://github.com/facebook/prepack/pull/2297 Differential Revision: D9120572 Pulled By: calebmer fbshipit-source-id: b394f1e8da034c9985366010e3e63fd55fd94168
2018-08-01 20:28:28 +03:00
let { timeout } = options;
Add serializer mode for test262 execution (#2290) Summary: I want to better understand the bugs we have in abstract evaluation. One of my ideas to do this is to replace all the literals in test262 tests with abstract values and see what our test coverage is. The first step to do this is to serialize the test262 sources after running them in Prepack and checking if their generated JavaScript runs correctly. This PR does that by adding a `--serializer` flag. With my methodology, all test262 harnesses are serialized every time since they are in the global scope. This unfortunately seems to be unavoidable since doing otherwise would change program semantics and break the tests. Running `time yarn test-test262` takes about 2 minutes and has a 98% pass rate. Running `time yarn test-test262 --serializer` takes about 5 minutes and has a 95% pass rate. [Here’s a diff of the two results.](https://gist.github.com/calebmer/1c9fe396b63ba055458c599c2be18a58) [Here is a selection of some of the bugs](https://gist.github.com/calebmer/1ac381096a4aa7be1fc7dc2163276ab4) in the serializer caught by running test262 with the Prepack serializer. I might open issues for these, but they can be a bit pedantic. I might fix some of them depending on how important they are to the React code we want to compile. Notably we have: - Lots of invariants being triggered. I particularly saw [a lot of this invariant](https://github.com/facebook/prepack/blob/7d355ef4c5f4d939742814714a78ef9b1279f9b4/src/serializer/ResidualHeapVisitor.js#L531). (An example of this is [`07.md`](https://gist.github.com/calebmer/1ac381096a4aa7be1fc7dc2163276ab4#file-07-md).) - Lots of values that are visited, but not serialized. (An example of this is [`01.md`](https://gist.github.com/calebmer/1ac381096a4aa7be1fc7dc2163276ab4#file-01-md).) - Some incorrect outputs only caught by executing code. Could not be caught by static analysis. Particularly around class serialization. I’ll build off this PR to get coverage for the abstract evaluator next, but I found these results interesting on their own so decided to do this in two PRs. Pull Request resolved: https://github.com/facebook/prepack/pull/2290 Differential Revision: D8908479 Pulled By: calebmer fbshipit-source-id: aa57d47611fbd92af33e4647fed7bf7990fb6de1
2018-07-19 04:48:13 +03:00
let sources = [];
// Add the test262 intrinsics.
sources.push({
filePath: "test262.js",
fileContents: `\
var $ = {
evalScript: () => {}, // noop for now
global,
};
var $262 = $;
var print = () => {}; // noop for now
`,
});
// Add the harness files.
for (let name of ["sta.js", "assert.js"].concat(data.includes || [])) {
let harness = harnesses[name];
sources.push({ filePath: name, fileContents: harness });
}
// Add the test file.
sources.push({ filePath: test.location, fileContents: (strict ? '"use strict";' + EOL : "") + testFileContents });
let result;
try {
result = prepackSources(sources, {
serialize: true,
timeout: timeout * 1000,
errorHandler: diag => {
if (diag.severity === "Information") return "Recover";
if (diag.severity !== "Warning") return "Fail";
return "Recover";
},
Add abstract serializer mode for test262 execution (#2297) Summary: I extended the `--serializer` command line argument I added in #2290 to now support `--serializer abstract-scalar`. What this mode does is it converts all boolean, string, number, and symbol literals into abstract values. I did not choose to extend this logic to object and array literals just yet since scalars alone showed some interesting results. What I really want here is a review of the results. Full suite execution results are real bad. **18%** pass rate. I dug a bit into why. ``` === RESULTS === Passes: 3356 / 17780 (18%) ES5 passes: 2276 / 12045 (18%) ES6 passes: 1080 / 5735 (18%) Skipped: 13375 Timeouts: 28 ``` I was mostly interested in the runtime failures we see since that means Prepack is serializing invalid code. However, I found ~14k failures in the Prepack stage (more on this in a bit) and ~3k failures in the runtime stage. This means ~80% of tests _fail to compile_ with this abstract transformation applied. Why are these tests failing? I took the first 4 items of the stack traces from errors thrown in the Prepack stage, sorted, and ranked them. [Here’s the result.](https://gist.github.com/calebmer/29e27613325fd99fa04be7ab4a9641c0) The top 5 with thousands of hits are: ``` 7538 of: at AbstractValue.throwIfNotConcrete (/Users/calebmer/prepack/src/values/AbstractValue.js:536:11) at ToImplementation.ToStringPartial (/Users/calebmer/prepack/src/methods/to.js:717:69) at NativeFunctionValue._index.NativeFunctionValue [as callback] (/Users/calebmer/prepack/src/intrinsics/ecma262/String.js:34:37) at NativeFunctionValue.callCallback (/Users/calebmer/prepack/src/values/NativeFunctionValue.js:121:12) 4595 of: at AbstractValue.throwIfNotConcrete (/Users/calebmer/prepack/src/values/AbstractValue.js:536:11) at NativeFunctionValue.func.defineNativeMethod [as callback] (/Users/calebmer/prepack/src/intrinsics/ecma262/Object.js:328:41) at NativeFunctionValue.callCallback (/Users/calebmer/prepack/src/values/NativeFunctionValue.js:121:12) at functionCall (/Users/calebmer/prepack/src/methods/call.js:308:26) 1454 of: at AbstractValue.throwIfNotConcrete (/Users/calebmer/prepack/src/values/AbstractValue.js:536:11) at NativeFunctionValue.func.defineNativeMethod [as callback] (/Users/calebmer/prepack/src/intrinsics/ecma262/Object.js:364:41) at NativeFunctionValue.callCallback (/Users/calebmer/prepack/src/values/NativeFunctionValue.js:121:12) at functionCall (/Users/calebmer/prepack/src/methods/call.js:308:26) 1351 of: at invariant (/Users/calebmer/prepack/src/invariant.js:18:15) at EvalPropertyNamePartial (/Users/calebmer/prepack/src/evaluators/ObjectExpression.js:59:7) at _default (/Users/calebmer/prepack/src/evaluators/ObjectExpression.js:80:21) at LexicalEnvironment.evaluateAbstract (/Users/calebmer/prepack/src/environment.js:1368:20) 1053 of: at AbstractValue.throwIfNotConcrete (/Users/calebmer/prepack/src/values/AbstractValue.js:536:11) at NativeFunctionValue.obj.defineNativeMethod [as callback] (/Users/calebmer/prepack/src/intrinsics/ecma262/ObjectPrototype.js:35:39) at NativeFunctionValue.callCallback (/Users/calebmer/prepack/src/values/NativeFunctionValue.js:121:12) at functionCall (/Users/calebmer/prepack/src/methods/call.js:308:26) ``` This means there may be some low hanging fruit. Here are my questions for you. - Did you expect results like this? - What is our ideal test262 pass rate with this transformation applied? - What happens to React Compiler or other projects when these errors are thrown? (As I understand it, we bail out and don’t optimize the code, but do optimize the code around it.) - Do you think my methodology is flawed? It’s also possible that something in my methodology is wrong, but I didn’t spend much time investigating these failures as I spent investigating the failures I found in #2290. My goal with this test suite is to build an understanding of what “correctness” for the React Compiler against all JavaScript code looks like. (Not just the few bundles we’ve selected to look at.) I don’t think these results suggest that we only safely compile 18% of the language, but it’s a data point. I’ll be looking into fixing a selection of these issues to better understand their nature or if I need to change methodologies. Pull Request resolved: https://github.com/facebook/prepack/pull/2297 Differential Revision: D9120572 Pulled By: calebmer fbshipit-source-id: b394f1e8da034c9985366010e3e63fd55fd94168
2018-08-01 20:28:28 +03:00
onParse: ast => {
// Transform all statements which come from our test source file. Do not transform statements from our
// harness files.
if (options.serializer === "abstract-scalar") {
ast.program.body.forEach(node => {
if ((node.loc: any).filename === test.location) {
transformScalarsToAbstractValues(node);
}
});
}
Add serializer mode for test262 execution (#2290) Summary: I want to better understand the bugs we have in abstract evaluation. One of my ideas to do this is to replace all the literals in test262 tests with abstract values and see what our test coverage is. The first step to do this is to serialize the test262 sources after running them in Prepack and checking if their generated JavaScript runs correctly. This PR does that by adding a `--serializer` flag. With my methodology, all test262 harnesses are serialized every time since they are in the global scope. This unfortunately seems to be unavoidable since doing otherwise would change program semantics and break the tests. Running `time yarn test-test262` takes about 2 minutes and has a 98% pass rate. Running `time yarn test-test262 --serializer` takes about 5 minutes and has a 95% pass rate. [Here’s a diff of the two results.](https://gist.github.com/calebmer/1c9fe396b63ba055458c599c2be18a58) [Here is a selection of some of the bugs](https://gist.github.com/calebmer/1ac381096a4aa7be1fc7dc2163276ab4) in the serializer caught by running test262 with the Prepack serializer. I might open issues for these, but they can be a bit pedantic. I might fix some of them depending on how important they are to the React code we want to compile. Notably we have: - Lots of invariants being triggered. I particularly saw [a lot of this invariant](https://github.com/facebook/prepack/blob/7d355ef4c5f4d939742814714a78ef9b1279f9b4/src/serializer/ResidualHeapVisitor.js#L531). (An example of this is [`07.md`](https://gist.github.com/calebmer/1ac381096a4aa7be1fc7dc2163276ab4#file-07-md).) - Lots of values that are visited, but not serialized. (An example of this is [`01.md`](https://gist.github.com/calebmer/1ac381096a4aa7be1fc7dc2163276ab4#file-01-md).) - Some incorrect outputs only caught by executing code. Could not be caught by static analysis. Particularly around class serialization. I’ll build off this PR to get coverage for the abstract evaluator next, but I found these results interesting on their own so decided to do this in two PRs. Pull Request resolved: https://github.com/facebook/prepack/pull/2290 Differential Revision: D8908479 Pulled By: calebmer fbshipit-source-id: aa57d47611fbd92af33e4647fed7bf7990fb6de1
2018-07-19 04:48:13 +03:00
},
});
} catch (error) {
if (error.message === "Timed out") return new TestResult(false, strict, error);
if (error.message.includes("Syntax error")) return null;
Add abstract serializer mode for test262 execution (#2297) Summary: I extended the `--serializer` command line argument I added in #2290 to now support `--serializer abstract-scalar`. What this mode does is it converts all boolean, string, number, and symbol literals into abstract values. I did not choose to extend this logic to object and array literals just yet since scalars alone showed some interesting results. What I really want here is a review of the results. Full suite execution results are real bad. **18%** pass rate. I dug a bit into why. ``` === RESULTS === Passes: 3356 / 17780 (18%) ES5 passes: 2276 / 12045 (18%) ES6 passes: 1080 / 5735 (18%) Skipped: 13375 Timeouts: 28 ``` I was mostly interested in the runtime failures we see since that means Prepack is serializing invalid code. However, I found ~14k failures in the Prepack stage (more on this in a bit) and ~3k failures in the runtime stage. This means ~80% of tests _fail to compile_ with this abstract transformation applied. Why are these tests failing? I took the first 4 items of the stack traces from errors thrown in the Prepack stage, sorted, and ranked them. [Here’s the result.](https://gist.github.com/calebmer/29e27613325fd99fa04be7ab4a9641c0) The top 5 with thousands of hits are: ``` 7538 of: at AbstractValue.throwIfNotConcrete (/Users/calebmer/prepack/src/values/AbstractValue.js:536:11) at ToImplementation.ToStringPartial (/Users/calebmer/prepack/src/methods/to.js:717:69) at NativeFunctionValue._index.NativeFunctionValue [as callback] (/Users/calebmer/prepack/src/intrinsics/ecma262/String.js:34:37) at NativeFunctionValue.callCallback (/Users/calebmer/prepack/src/values/NativeFunctionValue.js:121:12) 4595 of: at AbstractValue.throwIfNotConcrete (/Users/calebmer/prepack/src/values/AbstractValue.js:536:11) at NativeFunctionValue.func.defineNativeMethod [as callback] (/Users/calebmer/prepack/src/intrinsics/ecma262/Object.js:328:41) at NativeFunctionValue.callCallback (/Users/calebmer/prepack/src/values/NativeFunctionValue.js:121:12) at functionCall (/Users/calebmer/prepack/src/methods/call.js:308:26) 1454 of: at AbstractValue.throwIfNotConcrete (/Users/calebmer/prepack/src/values/AbstractValue.js:536:11) at NativeFunctionValue.func.defineNativeMethod [as callback] (/Users/calebmer/prepack/src/intrinsics/ecma262/Object.js:364:41) at NativeFunctionValue.callCallback (/Users/calebmer/prepack/src/values/NativeFunctionValue.js:121:12) at functionCall (/Users/calebmer/prepack/src/methods/call.js:308:26) 1351 of: at invariant (/Users/calebmer/prepack/src/invariant.js:18:15) at EvalPropertyNamePartial (/Users/calebmer/prepack/src/evaluators/ObjectExpression.js:59:7) at _default (/Users/calebmer/prepack/src/evaluators/ObjectExpression.js:80:21) at LexicalEnvironment.evaluateAbstract (/Users/calebmer/prepack/src/environment.js:1368:20) 1053 of: at AbstractValue.throwIfNotConcrete (/Users/calebmer/prepack/src/values/AbstractValue.js:536:11) at NativeFunctionValue.obj.defineNativeMethod [as callback] (/Users/calebmer/prepack/src/intrinsics/ecma262/ObjectPrototype.js:35:39) at NativeFunctionValue.callCallback (/Users/calebmer/prepack/src/values/NativeFunctionValue.js:121:12) at functionCall (/Users/calebmer/prepack/src/methods/call.js:308:26) ``` This means there may be some low hanging fruit. Here are my questions for you. - Did you expect results like this? - What is our ideal test262 pass rate with this transformation applied? - What happens to React Compiler or other projects when these errors are thrown? (As I understand it, we bail out and don’t optimize the code, but do optimize the code around it.) - Do you think my methodology is flawed? It’s also possible that something in my methodology is wrong, but I didn’t spend much time investigating these failures as I spent investigating the failures I found in #2290. My goal with this test suite is to build an understanding of what “correctness” for the React Compiler against all JavaScript code looks like. (Not just the few bundles we’ve selected to look at.) I don’t think these results suggest that we only safely compile 18% of the language, but it’s a data point. I’ll be looking into fixing a selection of these issues to better understand their nature or if I need to change methodologies. Pull Request resolved: https://github.com/facebook/prepack/pull/2297 Differential Revision: D9120572 Pulled By: calebmer fbshipit-source-id: b394f1e8da034c9985366010e3e63fd55fd94168
2018-08-01 20:28:28 +03:00
// Uncomment the following JS code to do analysis on what kinds of Prepack errors we get.
//
// ```js
// console.error(
// `${error.name.replace(/\n/g, "\\n")}: ${error.message.replace(/\n/g, "\\n")} (${error.stack
// .match(/at .+$/gm)
// .slice(0, 3)
// .join(", ")})`
// );
// ```
//
// Analysis bash command:
//
// ```bash
// yarn test-test262 --serializer 2> result.err
// cat result.err | sort | uniq -c | sort -nr
// ```
Add serializer mode for test262 execution (#2290) Summary: I want to better understand the bugs we have in abstract evaluation. One of my ideas to do this is to replace all the literals in test262 tests with abstract values and see what our test coverage is. The first step to do this is to serialize the test262 sources after running them in Prepack and checking if their generated JavaScript runs correctly. This PR does that by adding a `--serializer` flag. With my methodology, all test262 harnesses are serialized every time since they are in the global scope. This unfortunately seems to be unavoidable since doing otherwise would change program semantics and break the tests. Running `time yarn test-test262` takes about 2 minutes and has a 98% pass rate. Running `time yarn test-test262 --serializer` takes about 5 minutes and has a 95% pass rate. [Here’s a diff of the two results.](https://gist.github.com/calebmer/1c9fe396b63ba055458c599c2be18a58) [Here is a selection of some of the bugs](https://gist.github.com/calebmer/1ac381096a4aa7be1fc7dc2163276ab4) in the serializer caught by running test262 with the Prepack serializer. I might open issues for these, but they can be a bit pedantic. I might fix some of them depending on how important they are to the React code we want to compile. Notably we have: - Lots of invariants being triggered. I particularly saw [a lot of this invariant](https://github.com/facebook/prepack/blob/7d355ef4c5f4d939742814714a78ef9b1279f9b4/src/serializer/ResidualHeapVisitor.js#L531). (An example of this is [`07.md`](https://gist.github.com/calebmer/1ac381096a4aa7be1fc7dc2163276ab4#file-07-md).) - Lots of values that are visited, but not serialized. (An example of this is [`01.md`](https://gist.github.com/calebmer/1ac381096a4aa7be1fc7dc2163276ab4#file-01-md).) - Some incorrect outputs only caught by executing code. Could not be caught by static analysis. Particularly around class serialization. I’ll build off this PR to get coverage for the abstract evaluator next, but I found these results interesting on their own so decided to do this in two PRs. Pull Request resolved: https://github.com/facebook/prepack/pull/2290 Differential Revision: D8908479 Pulled By: calebmer fbshipit-source-id: aa57d47611fbd92af33e4647fed7bf7990fb6de1
2018-07-19 04:48:13 +03:00
return new TestResult(false, strict, new Error(`Prepack error:\n${error.stack}`));
}
const context = vm.createContext({
// TODO(#2292): Workaround since Prepack serializes code that expects a global `TypedArray` class which does not
// exist per the ECMAScript specification.
TypedArray: Object.getPrototypeOf(Int8Array),
});
try {
vm.runInContext(result.code, context, { timeout: timeout * 1000 });
} catch (error) {
if (error.message === "Timed out") return new TestResult(false, strict, error);
if (data.negative && data.negative.type === error.name) {
return new TestResult(true, strict);
} else {
return new TestResult(false, strict, new Error(`Runtime error:\n${error.stack}`));
}
}
if (data.negative.type) {
return new TestResult(false, strict, new Error(`Expected \`${data.negative.type}\` error.`));
} else {
return new TestResult(true, strict);
}
}
Add abstract serializer mode for test262 execution (#2297) Summary: I extended the `--serializer` command line argument I added in #2290 to now support `--serializer abstract-scalar`. What this mode does is it converts all boolean, string, number, and symbol literals into abstract values. I did not choose to extend this logic to object and array literals just yet since scalars alone showed some interesting results. What I really want here is a review of the results. Full suite execution results are real bad. **18%** pass rate. I dug a bit into why. ``` === RESULTS === Passes: 3356 / 17780 (18%) ES5 passes: 2276 / 12045 (18%) ES6 passes: 1080 / 5735 (18%) Skipped: 13375 Timeouts: 28 ``` I was mostly interested in the runtime failures we see since that means Prepack is serializing invalid code. However, I found ~14k failures in the Prepack stage (more on this in a bit) and ~3k failures in the runtime stage. This means ~80% of tests _fail to compile_ with this abstract transformation applied. Why are these tests failing? I took the first 4 items of the stack traces from errors thrown in the Prepack stage, sorted, and ranked them. [Here’s the result.](https://gist.github.com/calebmer/29e27613325fd99fa04be7ab4a9641c0) The top 5 with thousands of hits are: ``` 7538 of: at AbstractValue.throwIfNotConcrete (/Users/calebmer/prepack/src/values/AbstractValue.js:536:11) at ToImplementation.ToStringPartial (/Users/calebmer/prepack/src/methods/to.js:717:69) at NativeFunctionValue._index.NativeFunctionValue [as callback] (/Users/calebmer/prepack/src/intrinsics/ecma262/String.js:34:37) at NativeFunctionValue.callCallback (/Users/calebmer/prepack/src/values/NativeFunctionValue.js:121:12) 4595 of: at AbstractValue.throwIfNotConcrete (/Users/calebmer/prepack/src/values/AbstractValue.js:536:11) at NativeFunctionValue.func.defineNativeMethod [as callback] (/Users/calebmer/prepack/src/intrinsics/ecma262/Object.js:328:41) at NativeFunctionValue.callCallback (/Users/calebmer/prepack/src/values/NativeFunctionValue.js:121:12) at functionCall (/Users/calebmer/prepack/src/methods/call.js:308:26) 1454 of: at AbstractValue.throwIfNotConcrete (/Users/calebmer/prepack/src/values/AbstractValue.js:536:11) at NativeFunctionValue.func.defineNativeMethod [as callback] (/Users/calebmer/prepack/src/intrinsics/ecma262/Object.js:364:41) at NativeFunctionValue.callCallback (/Users/calebmer/prepack/src/values/NativeFunctionValue.js:121:12) at functionCall (/Users/calebmer/prepack/src/methods/call.js:308:26) 1351 of: at invariant (/Users/calebmer/prepack/src/invariant.js:18:15) at EvalPropertyNamePartial (/Users/calebmer/prepack/src/evaluators/ObjectExpression.js:59:7) at _default (/Users/calebmer/prepack/src/evaluators/ObjectExpression.js:80:21) at LexicalEnvironment.evaluateAbstract (/Users/calebmer/prepack/src/environment.js:1368:20) 1053 of: at AbstractValue.throwIfNotConcrete (/Users/calebmer/prepack/src/values/AbstractValue.js:536:11) at NativeFunctionValue.obj.defineNativeMethod [as callback] (/Users/calebmer/prepack/src/intrinsics/ecma262/ObjectPrototype.js:35:39) at NativeFunctionValue.callCallback (/Users/calebmer/prepack/src/values/NativeFunctionValue.js:121:12) at functionCall (/Users/calebmer/prepack/src/methods/call.js:308:26) ``` This means there may be some low hanging fruit. Here are my questions for you. - Did you expect results like this? - What is our ideal test262 pass rate with this transformation applied? - What happens to React Compiler or other projects when these errors are thrown? (As I understand it, we bail out and don’t optimize the code, but do optimize the code around it.) - Do you think my methodology is flawed? It’s also possible that something in my methodology is wrong, but I didn’t spend much time investigating these failures as I spent investigating the failures I found in #2290. My goal with this test suite is to build an understanding of what “correctness” for the React Compiler against all JavaScript code looks like. (Not just the few bundles we’ve selected to look at.) I don’t think these results suggest that we only safely compile 18% of the language, but it’s a data point. I’ll be looking into fixing a selection of these issues to better understand their nature or if I need to change methodologies. Pull Request resolved: https://github.com/facebook/prepack/pull/2297 Differential Revision: D9120572 Pulled By: calebmer fbshipit-source-id: b394f1e8da034c9985366010e3e63fd55fd94168
2018-08-01 20:28:28 +03:00
const TransformScalarsToAbstractValuesVisitor = (() => {
const t = babelTypes;
function createAbstractCall(type, actual, { allowDuplicateNames, disablePlaceholders } = {}) {
const args = [type, actual];
if (allowDuplicateNames) {
args.push(
t.objectExpression([
t.objectProperty(t.identifier("allowDuplicateNames"), t.booleanLiteral(!!allowDuplicateNames)),
t.objectProperty(t.identifier("disablePlaceholders"), t.booleanLiteral(!!disablePlaceholders)),
])
);
}
return t.callExpression(t.identifier("__abstract"), args);
}
const defaultOptions = {
allowDuplicateNames: true,
disablePlaceholders: true,
};
const symbolOptions = {
// Intentionally false since two symbol calls will be referentially not equal, but Prepack will share
// a variable.
allowDuplicateNames: false,
disablePlaceholders: true,
};
return {
noScope: true,
BooleanLiteral(p) {
p.node = p.container[p.key] = createAbstractCall(
t.stringLiteral("boolean"),
t.stringLiteral(p.node.value.toString()),
defaultOptions
);
},
StringLiteral(p) {
// `eval()` does not support abstract arguments and we don't care to fix that.
if (
p.parent.type === "CallExpression" &&
p.parent.callee.type === "Identifier" &&
p.parent.callee.name === "eval"
) {
return;
}
p.node = p.container[p.key] = createAbstractCall(
t.stringLiteral("string"),
t.stringLiteral(JSON.stringify(p.node.value)),
defaultOptions
);
},
CallExpression(p) {
if (p.node.callee.type === "Identifier" && p.node.callee.name === "Symbol") {
p.node = p.container[p.key] = createAbstractCall(
t.stringLiteral("symbol"),
t.stringLiteral(generate(p.node).code),
symbolOptions
);
}
},
NumericLiteral(p) {
p.node = p.container[p.key] = createAbstractCall(
t.stringLiteral(Number.isInteger(p.node.value) ? "integral" : "number"),
t.stringLiteral(p.node.extra.raw),
defaultOptions
);
},
};
})();
function transformScalarsToAbstractValues(ast) {
traverse(ast, TransformScalarsToAbstractValuesVisitor);
traverse.cache.clear();
}
2015-10-15 02:59:41 +03:00
/**
* Returns true if ${test} should be run, false otherwise
*/
function testFilterByMetadata(test: TestFileInfo): boolean {
2015-10-15 02:59:41 +03:00
// filter hidden files
if (path.basename(test.location)[0] === ".") return false;
// emacs!
if (test.location.includes("~")) return false;
// SIMD isn't in JS yet
if (test.location.includes("Simd")) return false;
// temporarily disable intl402 tests (ES5)
if (test.location.includes("intl402") && !test.location.includes("/Date/prototype/to")) {
return false;
}
2015-10-15 02:59:41 +03:00
// temporarily disable tests which use realm.
if (test.location.includes("realm")) return false;
// temporarily disable tests which use with. (??)
if (test.location.includes("/with/")) return false;
// disable tests which use Atomics
if (test.location.includes("/Atomics/")) return false;
// disable tests which use generators
if (test.location.includes("/generators/")) return false;
if (test.location.includes("/yield/")) return false;
2015-10-15 02:59:41 +03:00
// disable tests which use modules
if (test.location.includes("/module-code/")) return false;
// disable browser specific tests
if (test.location.includes("/annexB/")) return false;
// disable tail-call optimization tests
if (test.location.includes("tco")) return false;
// disable nasty unicode tests.
if (test.location.includes("U180") || test.location.includes("u180") || test.location.includes("mongolian"))
return false;
2015-10-15 02:59:41 +03:00
// disable function toString tests.
if (test.location.includes("Function/prototype/toString")) return false;
// disable tests that check for detached-buffer-after-toindex
if (test.location.includes("detached-buffer-after-toindex")) return false;
// disable tests to check for detatched-buffer during iteration
if (test.location.includes("detach-typedarray-in-progress.js")) return false;
// disable broken RegExp tests
if (test.location.includes("RegExp/S15.10.2.12_A1_T1.js")) return false;
if (test.location.includes("RegExp/S15.10.2.12_A2_T1.js")) return false;
if (test.location.includes("RegExp/prototype/Symbol.search/lastindex-no-restore")) return false;
if (test.location.includes("RegExp/prototype/exec/failure-lastindex-no-access.js")) return false;
if (test.location.includes("RegExp/prototype/exec/success-lastindex-no-access.js")) return false;
// disable RegExp tests that use extended unicode
if (test.location.includes("Symbol.match/builtin-success-u-return-val-groups")) return false;
// disable SharedArrayBuffer tests
if (test.location.includes("sharedarraybuffer") || test.location.includes("SharedArrayBuffer")) return false;
return true;
}
function testFilterByContents(test: TestFileInfo, testFileContents: string): boolean {
2015-10-15 02:59:41 +03:00
// ES6 tests (can only be verified by contents, not by metadata)
let is_es6 = testFileContents.includes(EOL + "es6id: ");
test.isES6 = is_es6;
// Ignore phase: early tests because those are errors that babel should catch
// not issues related to Prepack
let phase_early = testFileContents.indexOf(" phase: early");
let end_of_comment = testFileContents.indexOf("---*/");
2015-10-15 02:59:41 +03:00
if (phase_early > 0 && phase_early < end_of_comment) return false;
let esid_pending = testFileContents.indexOf("esid: pending");
if (esid_pending > 0 && esid_pending < end_of_comment) return false;
// disable tests that require parser to throw SyntaxError in strict Mode
if (test.location.includes("/directive-prologue/") && testFileContents.includes("assert.throws(SyntaxError,"))
return false;
2015-10-15 02:59:41 +03:00
// disable SharedArrayBuffer tests
if (testFileContents.includes("SharedArrayBuffer")) return false;
return true;
}
function filterFlags(data: BannerData): boolean {
return !data.flags.includes("async");
}
function filterFeatures(data: BannerData): boolean {
let features = data.features;
if (features.includes("default-parameters")) return false;
if (features.includes("generators")) return false;
2017-06-01 03:46:04 +03:00
if (features.includes("generator")) return false;
if (features.includes("BigInt")) return false;
if (features.includes("class-fields")) return false;
if (features.includes("async-iteration")) return false;
if (features.includes("Function.prototype.toString")) return false;
if (features.includes("SharedArrayBuffer")) return false;
if (features.includes("cross-realm")) return false;
if (features.includes("atomics")) return false;
if (features.includes("u180e")) return false;
if (features.includes("Symbol.isConcatSpreadable")) return false;
if (features.includes("IsHTMLDDA")) return false;
if (features.includes("regexp-unicode-property-escapes")) return false;
if (features.includes("character-class-escape-non-whitespace")) return false;
if (features.includes("regexp-named-groups")) return false;
if (features.includes("regexp-lookbehind")) return false;
if (features.includes("regexp-dotall")) return false;
if (features.includes("optional-catch-binding")) return false;
if (features.includes("Symbol.asyncIterator")) return false;
if (features.includes("Promise.prototype.finally")) return false;
2015-10-15 02:59:41 +03:00
return true;
}
function filterNegative(data: BannerData): boolean {
let negative = data.negative;
if (negative.phase === "parse") return false;
return true;
}
2015-10-15 02:59:41 +03:00
function filterIncludes(data: BannerData): boolean {
// disable tail call optimization tests.
return !data.includes.includes("tco-helper.js");
}
function filterDescription(data: BannerData): boolean {
// For now, "Complex tests" is used in the description of some
// encode/decodeURI tests to indicate that they are long running.
// Filter these
return (
!data.description.includes("Complex tests") &&
!data.description.includes("iterating") &&
!data.description.includes("iterable")
);
2015-10-15 02:59:41 +03:00
}
function filterCircleCI(data: BannerData): boolean {
let skipTests = [
"7.8.5_A1.4_T2",
"7.8.5_A2.4_T2",
"7.8.5_A2.1_T2",
"7.8.5_A1.1_T2",
"15.1.2.2_A8",
"15.1.2.3_A6",
"7.4_A5",
"7.4_A6",
"15.10.2.12_A3_T1",
"15.10.2.12_A4_T1",
"15.10.2.12_A5_T1",
"15.10.2.12_A6_T1",
];
let skipTests6 = ["22.1.3.1_3"];
return !!process.env.NIGHTLY_BUILD || (skipTests.indexOf(data.es5id) < 0 && skipTests6.indexOf(data.es6id) < 0);
}
2017-06-02 02:48:28 +03:00
function filterSneakyGenerators(data: BannerData, testFileContents: string) {
2017-06-02 02:58:08 +03:00
// There are some sneaky tests that use generators but are not labeled with
// the "generators" or "generator" feature tag. Here we use a simple heuristic
// to filter out tests with sneaky generators.
if (data.features.includes("destructuring-binding")) {
2017-06-02 02:58:08 +03:00
return !testFileContents.includes("function*") && !testFileContents.includes("*method");
2017-06-02 02:48:28 +03:00
}
return true;
}
Add serializer mode for test262 execution (#2290) Summary: I want to better understand the bugs we have in abstract evaluation. One of my ideas to do this is to replace all the literals in test262 tests with abstract values and see what our test coverage is. The first step to do this is to serialize the test262 sources after running them in Prepack and checking if their generated JavaScript runs correctly. This PR does that by adding a `--serializer` flag. With my methodology, all test262 harnesses are serialized every time since they are in the global scope. This unfortunately seems to be unavoidable since doing otherwise would change program semantics and break the tests. Running `time yarn test-test262` takes about 2 minutes and has a 98% pass rate. Running `time yarn test-test262 --serializer` takes about 5 minutes and has a 95% pass rate. [Here’s a diff of the two results.](https://gist.github.com/calebmer/1c9fe396b63ba055458c599c2be18a58) [Here is a selection of some of the bugs](https://gist.github.com/calebmer/1ac381096a4aa7be1fc7dc2163276ab4) in the serializer caught by running test262 with the Prepack serializer. I might open issues for these, but they can be a bit pedantic. I might fix some of them depending on how important they are to the React code we want to compile. Notably we have: - Lots of invariants being triggered. I particularly saw [a lot of this invariant](https://github.com/facebook/prepack/blob/7d355ef4c5f4d939742814714a78ef9b1279f9b4/src/serializer/ResidualHeapVisitor.js#L531). (An example of this is [`07.md`](https://gist.github.com/calebmer/1ac381096a4aa7be1fc7dc2163276ab4#file-07-md).) - Lots of values that are visited, but not serialized. (An example of this is [`01.md`](https://gist.github.com/calebmer/1ac381096a4aa7be1fc7dc2163276ab4#file-01-md).) - Some incorrect outputs only caught by executing code. Could not be caught by static analysis. Particularly around class serialization. I’ll build off this PR to get coverage for the abstract evaluator next, but I found these results interesting on their own so decided to do this in two PRs. Pull Request resolved: https://github.com/facebook/prepack/pull/2290 Differential Revision: D8908479 Pulled By: calebmer fbshipit-source-id: aa57d47611fbd92af33e4647fed7bf7990fb6de1
2018-07-19 04:48:13 +03:00
function filterReallyBigArrays(test: TestFileInfo, testFileContents: string) {
// In tests where we serialize our values disable large array serialization. Serializing arrays with gaps
// is inefficient. Consider: https://prepack.io/repl#G4QwTgBCELwQ2gXQNwCgTwAyNhAjGhnptrgakA
return !(
((test.location.includes("Array") || test.location.includes("Object")) &&
testFileContents.includes("4294967294")) ||
(test.location.includes("Array") && testFileContents.includes("Math.pow(2, 32)")) ||
// Sneaky...
test.location.includes("Array/S15.4_A1.1_T10.js")
);
}
2015-10-15 02:59:41 +03:00
/**
* Run a given ${test} whose file contents are ${testFileContents} and return
* a list of results, one for each strictness level (strict or not).
* If the list's length is less than 2, than the missing tests were skipped.
*/
function runTestWithStrictness(
test: TestFileInfo,
testFileContents: string,
data: BannerData,
// eslint-disable-next-line flowtype/no-weak-types
harnesses: Object,
Add serializer mode for test262 execution (#2290) Summary: I want to better understand the bugs we have in abstract evaluation. One of my ideas to do this is to replace all the literals in test262 tests with abstract values and see what our test coverage is. The first step to do this is to serialize the test262 sources after running them in Prepack and checking if their generated JavaScript runs correctly. This PR does that by adding a `--serializer` flag. With my methodology, all test262 harnesses are serialized every time since they are in the global scope. This unfortunately seems to be unavoidable since doing otherwise would change program semantics and break the tests. Running `time yarn test-test262` takes about 2 minutes and has a 98% pass rate. Running `time yarn test-test262 --serializer` takes about 5 minutes and has a 95% pass rate. [Here’s a diff of the two results.](https://gist.github.com/calebmer/1c9fe396b63ba055458c599c2be18a58) [Here is a selection of some of the bugs](https://gist.github.com/calebmer/1ac381096a4aa7be1fc7dc2163276ab4) in the serializer caught by running test262 with the Prepack serializer. I might open issues for these, but they can be a bit pedantic. I might fix some of them depending on how important they are to the React code we want to compile. Notably we have: - Lots of invariants being triggered. I particularly saw [a lot of this invariant](https://github.com/facebook/prepack/blob/7d355ef4c5f4d939742814714a78ef9b1279f9b4/src/serializer/ResidualHeapVisitor.js#L531). (An example of this is [`07.md`](https://gist.github.com/calebmer/1ac381096a4aa7be1fc7dc2163276ab4#file-07-md).) - Lots of values that are visited, but not serialized. (An example of this is [`01.md`](https://gist.github.com/calebmer/1ac381096a4aa7be1fc7dc2163276ab4#file-01-md).) - Some incorrect outputs only caught by executing code. Could not be caught by static analysis. Particularly around class serialization. I’ll build off this PR to get coverage for the abstract evaluator next, but I found these results interesting on their own so decided to do this in two PRs. Pull Request resolved: https://github.com/facebook/prepack/pull/2290 Differential Revision: D8908479 Pulled By: calebmer fbshipit-source-id: aa57d47611fbd92af33e4647fed7bf7990fb6de1
2018-07-19 04:48:13 +03:00
options: TestRunOptions
2015-10-15 02:59:41 +03:00
): Array<TestResult> {
let fn = (strict: boolean) => {
Add serializer mode for test262 execution (#2290) Summary: I want to better understand the bugs we have in abstract evaluation. One of my ideas to do this is to replace all the literals in test262 tests with abstract values and see what our test coverage is. The first step to do this is to serialize the test262 sources after running them in Prepack and checking if their generated JavaScript runs correctly. This PR does that by adding a `--serializer` flag. With my methodology, all test262 harnesses are serialized every time since they are in the global scope. This unfortunately seems to be unavoidable since doing otherwise would change program semantics and break the tests. Running `time yarn test-test262` takes about 2 minutes and has a 98% pass rate. Running `time yarn test-test262 --serializer` takes about 5 minutes and has a 95% pass rate. [Here’s a diff of the two results.](https://gist.github.com/calebmer/1c9fe396b63ba055458c599c2be18a58) [Here is a selection of some of the bugs](https://gist.github.com/calebmer/1ac381096a4aa7be1fc7dc2163276ab4) in the serializer caught by running test262 with the Prepack serializer. I might open issues for these, but they can be a bit pedantic. I might fix some of them depending on how important they are to the React code we want to compile. Notably we have: - Lots of invariants being triggered. I particularly saw [a lot of this invariant](https://github.com/facebook/prepack/blob/7d355ef4c5f4d939742814714a78ef9b1279f9b4/src/serializer/ResidualHeapVisitor.js#L531). (An example of this is [`07.md`](https://gist.github.com/calebmer/1ac381096a4aa7be1fc7dc2163276ab4#file-07-md).) - Lots of values that are visited, but not serialized. (An example of this is [`01.md`](https://gist.github.com/calebmer/1ac381096a4aa7be1fc7dc2163276ab4#file-01-md).) - Some incorrect outputs only caught by executing code. Could not be caught by static analysis. Particularly around class serialization. I’ll build off this PR to get coverage for the abstract evaluator next, but I found these results interesting on their own so decided to do this in two PRs. Pull Request resolved: https://github.com/facebook/prepack/pull/2290 Differential Revision: D8908479 Pulled By: calebmer fbshipit-source-id: aa57d47611fbd92af33e4647fed7bf7990fb6de1
2018-07-19 04:48:13 +03:00
return runTest(test, testFileContents, data, harnesses, strict, options);
2015-10-15 02:59:41 +03:00
};
if (data.flags.includes("onlyStrict")) {
if (testFileContents.includes("assert.throws(SyntaxError")) return [];
2015-10-15 02:59:41 +03:00
let result = fn(true);
return result ? [result] : [];
} else if (data.flags.includes("noStrict") || test.location.includes("global/global-object.js")) {
if (testFileContents.includes('"use strict";') && testFileContents.includes("assert.throws(SyntaxError")) return [];
2015-10-15 02:59:41 +03:00
let result = fn(false);
return result ? [result] : [];
} else {
// run both strict and non-strict
let strictResult = fn(true);
let unStrictResult = fn(false);
let finalResult = [];
if (strictResult) {
finalResult.push(strictResult);
}
if (unStrictResult) {
finalResult.push(unStrictResult);
}
return finalResult;
2015-10-15 02:59:41 +03:00
}
}
/**
* Parses the banners, and returns the banners as arbitrary object data if they
* were found, or returns an error if the banner it couldn't be parsed.
*/
function getBanners(test: TestFileInfo, fileContents: string): ?BannerData {
2015-10-15 02:59:41 +03:00
let banners = fileContents.match(/---[\s\S]+---/);
let data = {};
if (banners) {
let bannerText = banners[0] || "";
if (bannerText.includes("StrictMode")) {
if (bannerText.includes("'arguments'")) return null;
if (bannerText.includes("'caller'")) return null;
} else if (bannerText.includes('properties "caller" or "arguments"')) {
2015-10-15 02:59:41 +03:00
return null;
} else if (bannerText.includes("function caller")) {
return null;
} else if (bannerText.includes("attribute of 'caller' property")) {
return null;
} else if (bannerText.includes("attribute of 'arguments'")) {
return null;
} else if (bannerText.includes("poisoned")) return null;
try {
data = yaml.safeLoad(banners[0].slice(3, -3));
} catch (e) {
// Some versions of test262 have comments inside of yaml banners.
// parsing these will usually fail.
return null;
}
2015-10-15 02:59:41 +03:00
}
return BannerData.fromObject(data);
}