Skip to content

JS-2-GIL and Test262

Coverage of JS-2-GIL

JS-2-GIL is a compiler from ECMAScript ES5 Strict to GIL, with broad coverage. It supports the entire core (chapters 8-14), with the exception of the RegExp literal, as well as all of the JavaScript built-in libraries except the following:

  • Date, RegExp, JSON
  • Number.prototype.toFixed
  • String.fromCharCode
  • In String.prototype: charCodeAt, localeCompare, match, replace, search, split, trim, toLocaleLowerCase, toLocaleUpperCase, toLowerCase, toUpperCase
  • In the global object: decodeURI, decodeURIComponent, encodeURI, encodeURIComponent, parseInt, parseFloat Additionally, indirect eval is not supported, as it is meant to be executed as non-strict code. Furthermore, all Function constructor code runs as strict-mode code.

Correctness of JS-2-GIL

The JS-2-GIL compiler can be split into two compilers: JS-2-JSIL, which compiles JavaScript to JSIL, the intermediate representation that we have used in JaVerT / Cosette / JaVerT 2.0; and JSIL-2-GIL, the compiler from JSIL to GIL, the intermediate representation of Gillian.

Previously, we have tested JS-2-JSIL against Test262, the JavaScript official test suite (specifically, this commit from 2016/05/30). As Test262 commit targets ES6, we had to identify the subset of tests that are appropriate for JS-2-JSIL, as explained in detail in JaVerT. We obtained 8797 applicable tests, of which JS-2-JSIL passes 100%.

We have initially tested JS-2-GIL successfully on the same 8797 tests and reported this in the submitted version of the paper. However, these tests were not systematically categorised and we were not able to automate the testing process to our satisfaction using the bulk testing mechanism of Gillian. For this reason, we have chosen to work with the latest version of Test262 at time of writing, forked here, where each test comes with a precise description of its intended outcome. For example, a test that is supposed to fail at parsing time with a JavaScript native syntax error will contain the following in its header:

negative:
  phase: parse
  type: SyntaxError

We re-filter Test262 to find the applicable tests and run them using JS-2-GIL and the concrete semantics of Gillian-JS. The summary results are presented in the table below and will be included in the final version of the paper. A more detailed, per-folder breakdown is available further below.

LanguageBuilt-insTotal
Total tests3202786011062
Non-strict tests583136719
Strict tests2619772410343
Non-strict features415091
For unimplemented features1711821199
Using unimplemented features231235
ES6+325
Applicable253567489013
Passing253067459005
Failing538

Table columns:

Table rows:

  • Total tests: all tests.
  • Non-strict tests (filtered out): tests that should be run only in non-strict mode. They contain the flags: [noStrict] directive and are filtered out automatically by our bulk testing mechanism.
  • Strict tests: tests that should be run in strict mode.
  • Non-strict features (filtered out): tests that combine strict and non-strict mode, using either indirect eval or the non-strict Function constructor (91 tests, list available in the non_strict_tests variable of test262_filtering.ml).
  • For unimplemented features (filtered out): tests that test unimplemented features, such as the JSON library (1205 tests, list available in the tests_for_unimplemented_features variable of test262_filtering.ml). Note that the structural tests for some of these features still pass, as we have the appropriate stubs in the initial heap.
  • Using unimplemented features (filtered out): tests that use unimplemented features to test behaviours of implemented features, with the most prominent examples being the Date constructor and RegExp literals (29 tests, list available in the tests_using_unimplemented_features variable of test262_filtering.ml).
  • ES6+ (filtered out): tests that use behaviours beyond ES5 (5 tests, list available in the es6_tests variable of test262_filtering.ml). For example, two language tests test for the ES6 completion of the if statement (returns undefined instead of the ES5 empty), one language test uses a function declaration in statement position (disallowed in ES5), and two built-in tests require a specific ordering of object keys (implementation-dependent in ES5).
  • Applicable: the number of tests applicable to JS-2-GIL.
  • Passing: the number of tests passing.
  • Failing: the number of tests failing.

Failing tests

The following eight tests fail due to a discrepancy between how Unicode characters are treated in JavaScript (either UCS-2 or UTF-16) and OCaml (sequences of bytes):

  • test262/test/language/line-terminators/7.3-6.js
  • test262/test/language/line-terminators/7.3-5.js
  • test262/test/language/line-terminators/7.3-15.js
  • test262/test/language/line-terminators/invalid-string-cr.js
  • test262/test/language/source-text/6.1.js
  • test262/test/built-ins/Number/S9.3.1_A3_T1.js
  • test262/test/built-ins/Number/S9.3.1_A3_T2.js
  • test262/test/built-ins/Number/S9.3.1_A2.js

One solution would be to move to strings provided by the Camomile library instead of the native OCaml strings.

Reproducing the results

Clone our forked Test262 repository to a folder on your machine. Inside that folder, you can find the Test262 tests in the test subfolder. In particular, test/language contains the core language tests, whereas test/built-ins contains the tests for the built-in libraries.

To run all of the tests, execute the following command inside your Gillian folder:

bash
dune exec -- gillian-js bulk-exec <path to Test262 folder>/test

For example, we normally clone Test262 in the same folder as the Gillian project and change its folder name from javert-test262 to test262. We then run all of the tests by executing the following commands from within the Gillian folder:

bash
cd ..
git clone https://github.com/GillianPlatform/javert-test262.git test262
cd Gillian
dune exec -- gillian-js bulk-exec ../test262/test

The testing should take approximately thirty minutes. The bulk tester will actively report progress, folder-by-folder, and signal any test failures encountered. In the end, a list of all failed tests (the eight given above) will be printed.

If you would like to test a specific subfolder of the test suite, simply add it to the test path. For example, to run only the tests for Array.prototype.reduce, execute:

bash
dune exec -- gillian-js bulk-exec ../test262/test/built-ins/Array/prototype/reduce/

If you would like to examine the filtered tests, you can find them in test262_filtering.ml our forked Test262 repository.

Detailed per-folder breakdown

Language

arguments-objectasicommentsdirective-prologueeval-codeexpressionsfunction-codefuture-reserved-wordsglobal-codeidentifier-resolutionidentifierskeywordsline-terminatorsliteralspunctuatorsreserved-wordssource-textstatementstypeswhite-spaceTotal
All tests4610118625814692125531149254114511131733109403202
Non-strict tests1200574153107725000000022790583
Strict tests34101185541316105481649254114511131506100402619
Non-strict features000025150000000000100041
For unimplemented features00000000000001700000017
Using unimplemented features00200340000001200020023
ES6+000000000000000003003
Applicable3410116529131296481649254111611131491100402535
Passing3410116529131296481649253711611130491100402530
Failing000000000000400010005

Built-ins

ArrayBooleanDatedecodeURIdecodeURIComponentencodeURIencodeURIComponentErrorevalFunctionglobalInfinityisFiniteisNanJSONMathNaNNumberObjectparseFloatparseIntRegExpStringundefinedTotal
All tests2171424305252282833739831722908171522892405750174987860
Non-strict tests27000000008842000020700033136
Strict tests2144424305252282833731027522908151522885405750174657724
Non-strict features000000000500000000000000050
For unimplemented0017454521210000000810055335045540401182
Using unimplemented features30000000030000000000006012
ES6+0000000000000000002000002
Applicable21414241377773372572752298151472878774633656748
Passing21414241377773372572752298151442878774633656745
Failing0000000000000000030000003