tor-browser

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

stencil-scope.js (4544B)


      1 const optionsFull = {
      2    fileName: "compileToStencil-DATA.js",
      3    lineNumber: 1,
      4    eagerDelazificationStrategy: "ParseEverythingEagerly",
      5 };
      6 
      7 const optionsLazy = {
      8    fileName: "compileToStencil-DATA.js",
      9    lineNumber: 1,
     10    eagerDelazificationStrategy: "OnDemandOnly",
     11 };
     12 
     13 const optionsLazyCache = {
     14    fileName: "compileToStencil-DATA.js",
     15    lineNumber: 1,
     16    eagerDelazificationStrategy: "ConcurrentDepthFirst",
     17 };
     18 
     19 const optionsLazyCache2 = {
     20    fileName: "compileToStencil-DATA.js",
     21    lineNumber: 1,
     22    eagerDelazificationStrategy: "ConcurrentLargeFirst",
     23 };
     24 
     25 let result = 0;
     26 
     27 function testMainThread(script_str) {
     28    const stencil = compileToStencil(script_str, optionsFull);
     29    result = evalStencil(stencil, optionsFull);
     30    assertEq(result, 1);
     31 }
     32 
     33 function testMainThreadDelazifyAll(script_str) {
     34    if (isLcovEnabled()) {
     35      // Code-coverage implies forceFullParse = true, and as such it cannot be
     36      // used while testing to incrementally delazify.
     37      return;
     38    }
     39    const stencil = compileToStencil(script_str, optionsLazy);
     40    result = evalStencil(stencil, optionsLazy);
     41    assertEq(result, 1);
     42 }
     43 
     44 function testMainThreadCacheAll(script_str) {
     45  if (isLcovEnabled() || helperThreadCount() === 0) {
     46    // Code-coverage implies forceFullParse = true, and as such it cannot be
     47    // used while testing to incrementally delazify.
     48    // Similarly, concurrent delazification requires off-threads processing.
     49    return;
     50  }
     51  const stencil = compileToStencil(script_str, optionsLazyCache);
     52  result = evalStencil(stencil, optionsLazyCache);
     53  assertEq(result, 1);
     54 }
     55 
     56 function testMainThreadCacheAll2(script_str) {
     57  if (isLcovEnabled() || helperThreadCount() === 0) {
     58    // Code-coverage implies forceFullParse = true, and as such it cannot be
     59    // used while testing to incrementally delazify.
     60    // Similarly, concurrent delazification requires off-threads processing.
     61    return;
     62  }
     63  const stencil = compileToStencil(script_str, optionsLazyCache2);
     64  result = evalStencil(stencil, optionsLazyCache2);
     65  assertEq(result, 1);
     66 }
     67 
     68 function testOffThread(script_str) {
     69    const job = offThreadCompileToStencil(script_str, optionsFull);
     70    const stencil = finishOffThreadStencil(job);
     71    result = evalStencil(stencil, optionsFull);
     72    assertEq(result, 1);
     73 }
     74 
     75 // These patches are meant to wrap the inner code given as argument into one
     76 // kind of scope. The freeVars specify one way to retrieve the variable name
     77 // added in this process if any.
     78 const scopeCases = [
     79    { code: inner => `{ ${inner} }`, freeVars: [] },
     80    { code: inner => `{ var v = 1; ${inner} }`, freeVars: ["v"] },
     81    { code: inner => `{ let l = 1; ${inner} }`, freeVars: ["l"] },
     82    { code: inner => `{ const c = 1; ${inner} }`, freeVars: ["c"] },
     83    { code: inner => `with ({ p: 1 }) { ${inner} }`, freeVars: ["p"],
     84      inClass: false },
     85    { code: inner => `(a => { ${inner} })(1)`, freeVars: ["a"] },
     86    { code: inner => `function fun(a) { ${inner} }; fun(1)`, freeVars: ["a"],
     87      inClass: false},
     88    { code: inner => `try { ${inner} } catch(unused) { }`, freeVars: [] },
     89    { code: inner => `try { throw 1; } catch(t) { ${inner} }`, freeVars: ["t"] },
     90    { code: inner => `{ class C { #m = 1; constructor() { ${inner} }}; new C() }`,
     91      freeVars: ["this.#m"], isClass: true },
     92 ];
     93 
     94 // This function is used to generate code which mostly exercise the various kind
     95 // of scopes to cover ScopeContext class in CompilationStencil.h
     96 function generateCode(seed) {
     97    let start = inner => `
     98      ${inner};
     99      result
    100    `;
    101 
    102    let prog = [start];
    103    let freeVars = ["1"];
    104    let inClass = false;
    105 
    106    while (seed >= freeVars.length) {
    107        let index = seed % scopeCases.length;
    108        seed = (seed / scopeCases.length) | 0;
    109        let scope = scopeCases[index];
    110        if (inClass && !(scope.inClass ?? false)) {
    111            // Skip illegal code (non-strict) or code which might not accept
    112            // this to work.
    113            continue;
    114        }
    115        inClass ||= scope.isClass ?? false;
    116        prog.push(scope.code);
    117        freeVars = freeVars.concat(scope.freeVars);
    118    }
    119 
    120    let name = freeVars[seed];
    121    return prog.reduceRight((inner, f) => f(inner), `result = ${name}`);
    122 }
    123 
    124 for (let s = 0; s < 3000; s++) {
    125    let code = generateCode(s);
    126    // console.log(s, ":", code);
    127    testMainThread(code);
    128    testMainThreadDelazifyAll(code);
    129    testMainThreadCacheAll(code);
    130    testMainThreadCacheAll2(code);
    131    if (helperThreadCount() > 0) {
    132        testOffThread(code);
    133    }
    134 }