tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

script-source-extent.js (14578B)


      1 // |jit-test|
      2 
      3 // Test that the sourceStart/sourceEnd values of scripts match the current
      4 // expectations. These values are internal details and slightly arbitrary so
      5 // these tests expectations can be updated as needed.
      6 //
      7 // We don't check lineno/column here since they are reasonably robustly
      8 // determined from source start offset.
      9 
     10 // We use the Debugger API to introspect locate (possibly hidden) scripts and
     11 // inspect their internal source coordinates. While we want new globals for each
     12 // test case, they can share the same debuggee compartment.
     13 let dbg = new Debugger();
     14 let debuggeeCompartment = newGlobal({newCompartment: true});
     15 
     16 // Some static class field initializer lambdas may be thrown away by GC.
     17 gczeal(0);
     18 
     19 function getScriptSourceExtent(source) {
     20    // NOTE: We will _evaluate_ the source below which may introduce dynamic
     21    //       scripts which are also reported. This is intended so that we may test
     22    //       those cases too.
     23 
     24    let g = newGlobal({sameCompartmentAs: debuggeeCompartment});
     25    dbg.addDebuggee(g);
     26 
     27    g.evaluate(source);
     28 
     29    // Use Debugger.findScripts to locate scripts, including hidden ones that
     30    // are implementation details.
     31    let scripts = dbg.findScripts();
     32 
     33    // Ignore the top-level script since it may or may not be GC'd and is
     34    // otherwise uninteresting to us here.
     35    scripts = scripts.filter(script => (script.sourceStart > 0) || script.isFunction);
     36 
     37    // Sanity-check that line/column are consistent with sourceStart. If we need
     38    // to test multi-line sources, this will need to be updated.
     39    for (let script of scripts) {
     40        assertEq(script.startLine, 1);
     41        assertEq(script.startColumn, script.sourceStart + 1);
     42    }
     43 
     44    // Map each found script to a source extent string.
     45    function getExtentString(script) {
     46        let start = script.sourceStart;
     47        let end = script.sourceStart + script.sourceLength;
     48        let length = script.sourceLength;
     49 
     50        let resultLength = source.length;
     51        assertEq(start <  resultLength, true);
     52        assertEq(end   <= resultLength, true);
     53 
     54        // The result string takes one of following forms:
     55        //  ` ^    `, when start == end.
     56        //  ` ^--^ `, typical case.
     57        //  ` ^----`, when end == resultLength.
     58        let result = " ".repeat(start) + "^";
     59        if (end > start) {
     60            result += "^".padStart(length, "-");
     61        }
     62        return result.padEnd(resultLength)
     63                     .substring(0, resultLength);
     64    }
     65    let results = scripts.map(getExtentString);
     66 
     67    // Sort results since `findScripts` does not have deterministic ordering.
     68    results.sort();
     69 
     70    dbg.removeDebuggee(g);
     71 
     72    return results;
     73 }
     74 
     75 function testSourceExtent(source, ...expectations) {
     76    let actual = getScriptSourceExtent(source);
     77 
     78    // Check that strings of each array match. These should have been presorted.
     79    assertEq(actual.length, expectations.length);
     80    for (let i = 0; i < expectations.length; ++i) {
     81        assertEq(actual[i], expectations[i]);
     82    }
     83 }
     84 
     85 ////////////////////
     86 
     87 // Function statements.
     88 testSourceExtent(`function foo () { }`,
     89                 `             ^-----`);
     90 testSourceExtent(`function foo (a) { }`,
     91                 `             ^------`);
     92 testSourceExtent(`function foo (a, b) { }`,
     93                 `             ^---------`);
     94 
     95 // Function expressions.
     96 testSourceExtent(`let foo = function () { }`,
     97                 `                   ^-----`);
     98 testSourceExtent(`let foo = function (a) { }`,
     99                 `                   ^------`);
    100 testSourceExtent(`let foo = function (a, b) { }`,
    101                 `                   ^---------`);
    102 
    103 // Named function expressions.
    104 testSourceExtent(`let foo = function bar () { }`,
    105                 `                       ^-----`);
    106 testSourceExtent(`let foo = function bar (a) { }`,
    107                 `                       ^------`);
    108 testSourceExtent(`let foo = function bar (a, b) { }`,
    109                 `                       ^---------`);
    110 
    111 // Arrow functions.
    112 testSourceExtent(`let foo = x => { }`,
    113                 `          ^-------`);
    114 testSourceExtent(`let foo = x => { };`,
    115                 `          ^-------^`);
    116 testSourceExtent(`let foo = () => { }`,
    117                 `          ^--------`);
    118 testSourceExtent(`let foo = (a, b) => { }`,
    119                 `          ^------------`);
    120 testSourceExtent(`let foo = x => x`,
    121                 `          ^-----`);
    122 testSourceExtent(`let foo = () => 0`,
    123                 `          ^------`);
    124 
    125 // Async / Generator functions.
    126 testSourceExtent(`function * foo () { }`,
    127                 `               ^-----`);
    128 testSourceExtent(`async function foo () { }`,
    129                 `                   ^-----`);
    130 testSourceExtent(`async function * foo () { }`,
    131                 `                     ^-----`);
    132 
    133 // Async arrow functions.
    134 testSourceExtent(`let foo = async x => { }`,
    135                 `                ^-------`);
    136 testSourceExtent(`let foo = async () => { }`,
    137                 `                ^--------`);
    138 
    139 // Basic inner functions.
    140 testSourceExtent(`function foo() { function bar () {} }`,
    141                 `                              ^----^ `,
    142                 `            ^------------------------`);
    143 
    144 // Default parameter expressions.
    145 // NOTE: Arrow function parser back-tracking may generate multiple scripts for
    146 //       the same source text. Delazification expects these copies to have correct
    147 //       range information for `skipInnerLazyFunction` to work. If syntax parsing is
    148 //       disabled (such as for coverage builds), these extra functions are not
    149 //       generated.
    150 if (!isLcovEnabled()) {
    151    testSourceExtent(`function foo(a = b => c) {}`,
    152                     `                 ^-----^   `,
    153                     `            ^--------------`);
    154    testSourceExtent(`let foo = (a = (b = c => 1) => 2) => 3;`,
    155                     `                    ^-----^            `,
    156                     `               ^----------------^      `,
    157                     `          ^---------------------------^`);
    158 }
    159 
    160 // Object methods, getters, setters.
    161 testSourceExtent(`let obj = { x () {} };`,
    162                 `              ^----^  `);
    163 testSourceExtent(`let obj = { * x () {} };`,
    164                 `                ^----^  `);
    165 testSourceExtent(`let obj = { async x () {} };`,
    166                 `                    ^----^  `);
    167 testSourceExtent(`let obj = { async * x () {} };`,
    168                 `                      ^----^  `);
    169 testSourceExtent(`let obj = { get x () {} };`,
    170                 `                  ^----^  `);
    171 testSourceExtent(`let obj = { set x (v) {} };`,
    172                 `                  ^-----^  `);
    173 testSourceExtent(`let obj = { x: function () {} };`,
    174                 `                        ^----^  `);
    175 testSourceExtent(`let obj = { x: y => z };`,
    176                 `               ^-----^  `);
    177 
    178 // Classes without user-defined constructors.
    179 testSourceExtent(` class C { } `,
    180                 ` ^----------^`);
    181 testSourceExtent(` let C = class { } `,
    182                 `         ^--------^`);
    183 testSourceExtent(` class C { }; class D extends C { } `,
    184                 `              ^--------------------^`,
    185                 ` ^----------^                       `);
    186 testSourceExtent(` class C { }; let D = class extends C { } `,
    187                 `                      ^------------------^`,
    188                 ` ^----------^                             `);
    189 testSourceExtent(`let C = class extends class { } { }`,
    190                 `                      ^--------^   `,
    191                 `        ^--------------------------`);
    192 
    193 // Classes with user-defined constructors.
    194 testSourceExtent(` class C { constructor() { } } `,
    195                 `                      ^-----^  `);
    196 testSourceExtent(` let C = class { constructor() { } } `,
    197                 `                            ^-----^  `);
    198 testSourceExtent(` class C { }; class D extends C { constructor() { } } `,
    199                 `                                             ^-----^  `,
    200                 ` ^----------^                                         `);
    201 testSourceExtent(` class C { }; let D = class extends C { constructor() { } } `,
    202                 `                                                   ^-----^  `,
    203                 ` ^----------^                                               `);
    204 testSourceExtent(`let C = class extends class { } { constructor() { } }`,
    205                 `                                             ^-----^ `,
    206                 `                      ^--------^                     `);
    207 
    208 // Class field initializers lambdas.
    209 // NOTE: These are an implementation detail and may be optimized away in future.
    210 testSourceExtent(`class C { field }`,
    211                 `          ^----^ `,
    212                 `^----------------`);
    213 testSourceExtent(`class C { field; }`,
    214                 `          ^----^  `,
    215                 `^-----------------`);
    216 testSourceExtent(`class C { "field" }`,
    217                 `          ^------^ `,
    218                 `^------------------`);
    219 testSourceExtent(`class C { 0 }`,
    220                 `          ^^ `,
    221                 `^------------`);
    222 testSourceExtent(`class C { [1n] }`,
    223                 `          ^---^ `,
    224                 `^---------------`);
    225 testSourceExtent(`class C { field = 1 }`,
    226                 `          ^--------^ `,
    227                 `^--------------------`);
    228 testSourceExtent(`class C { "field" = 1 }`,
    229                 `          ^----------^ `,
    230                 `^----------------------`);
    231 testSourceExtent(`class C { 0 = 1 }`,
    232                 `          ^----^ `,
    233                 `^----------------`);
    234 testSourceExtent(`class C { [1n] = 1}`,
    235                 `          ^-------^`,
    236                 `^------------------`);
    237 
    238 // Static class field initializer lambdas.
    239 // NOTE: These are an implementation detail and may be optimized away in future.
    240 testSourceExtent(`class C { static field }`,
    241                 `                 ^----^ `,
    242                 `^-----------------------`);
    243 testSourceExtent(`class C { static field; }`,
    244                 `                 ^----^  `,
    245                 `^------------------------`);
    246 testSourceExtent(`class C { static field = 1 }`,
    247                 `                 ^--------^ `,
    248                 `^---------------------------`);
    249 testSourceExtent(`class C { static [0] = 1 }`,
    250                 `                 ^------^ `,
    251                 `^-------------------------`);
    252 
    253 // Static class methods, getters, setters.
    254 testSourceExtent(`class C { static mtd() {} }`,
    255                 `                    ^----^ `,
    256                 `^--------------------------`);
    257 testSourceExtent(`class C { static * mtd() {} }`,
    258                 `                      ^----^ `,
    259                 `^----------------------------`);
    260 testSourceExtent(`class C { static async mtd() {} }`,
    261                 `                          ^----^ `,
    262                 `^--------------------------------`);
    263 testSourceExtent(`class C { static async * mtd() {} }`,
    264                 `                            ^----^ `,
    265                 `^----------------------------------`);
    266 testSourceExtent(`class C { static get prop() {} }`,
    267                 `                         ^----^ `,
    268                 `^-------------------------------`);
    269 testSourceExtent(`class C { static get [0]() {} }`,
    270                 `                        ^----^ `,
    271                 `^------------------------------`);
    272 testSourceExtent(`class C { static set prop(v) {} }`,
    273                 `                         ^-----^ `,
    274                 `^--------------------------------`);
    275 
    276 // Private class field initializer lambdas.
    277 // NOTE: These are an implementation detail and may be optimized away in future.
    278 testSourceExtent(`class C { #field }`,
    279                 `          ^-----^ `,
    280                 `^-----------------`);
    281 testSourceExtent(`class C { #field = 1 }`,
    282                 `          ^---------^ `,
    283                 `^---------------------`);
    284 testSourceExtent(`class C { static #field }`,
    285                 `                 ^-----^ `,
    286                 `^------------------------`);
    287 testSourceExtent(`class C { static #field = 1 }`,
    288                 `                 ^---------^ `,
    289                 `^----------------------------`);
    290 
    291 // Private class methods, getters, setters.
    292 // NOTE: These generate both a field initializer lambda and a method script.
    293 testSourceExtent(` class C { #field() { } }`,
    294                 `                 ^-----^ `,
    295                 ` ^-----------------------`);
    296 testSourceExtent(` class C { get #field() { } }`,
    297                 `                     ^-----^ `,
    298                 `           ^---------------^ `,
    299                 ` ^---------------------------`);
    300 testSourceExtent(` class C { set #field(v) { } }`,
    301                 `                     ^------^ `,
    302                 `           ^----------------^ `,
    303                 ` ^----------------------------`);
    304 testSourceExtent(` class C { * #field() { } }`,
    305                 `                   ^-----^ `,
    306                 ` ^-------------------------`);
    307 testSourceExtent(` class C { async #field() { } }`,
    308                 `                       ^-----^ `,
    309                 ` ^-----------------------------`);
    310 testSourceExtent(` class C { async * #field() { } }`,
    311                 `                         ^-----^ `,
    312                 ` ^-------------------------------`);
    313 
    314 // Private static class methods.
    315 testSourceExtent(` class C { static #mtd() { } }`,
    316                 `                      ^-----^ `,
    317                 ` ^----------------------------`);
    318 testSourceExtent(` class C { static * #mtd() { } }`,
    319                 `                        ^-----^ `,
    320                 ` ^------------------------------`);
    321 testSourceExtent(` class C { static async #mtd() { } }`,
    322                 `                            ^-----^ `,
    323                 ` ^----------------------------------`);
    324 testSourceExtent(` class C { static async * #mtd() { } }`,
    325                 `                              ^-----^ `,
    326                 ` ^------------------------------------`);
    327 testSourceExtent(` class C { static get #prop() { } }`,
    328                 `                           ^-----^ `,
    329                 ` ^---------------------------------`);
    330 testSourceExtent(` class C { static set #prop(v) { } }`,
    331                 `                           ^------^ `,
    332                 ` ^----------------------------------`);
    333 
    334 // Static Class Blocks
    335 testSourceExtent(` class C { static { 10; } }`,
    336                 `           ^-------------^ `,
    337                 ` ^-------------------------`);