Javascript  |  342行  |  9.7 KB

// Copyright 2015 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

// Flags: --strong-mode --harmony-reflect
// Flags: --allow-natives-syntax

'use strict';


function generateArguments(n, prefix) {
  let a = [];
  if (prefix) {
    a.push(prefix);
  }
  for (let i = 0; i < n; i++) {
    a.push(String(i));
  }

  return a.join(', ');
}


function generateParams(n, directive_in_body) {
  let a = [];
  for (let i = 0; i < n; i++) {
    a[i] = `p${i}`;
  }
  return a.join(', ');
}

function generateParamsWithRest(n, directive_in_body) {
  let a = [];
  let i = 0;
  for (; i < n; i++) {
    a[i] = `p${i}`;
  }
  if (!directive_in_body) {
    // If language mode directive occurs in body, rest parameters will trigger
    // an early error regardless of language mode.
    a.push(`...p${i}`);
  }
  return a.join(', ');
}


function generateSpread(n) {
  return `...[${generateArguments(n)}]`;
}


(function FunctionCall() {
  for (let parameterCount = 0; parameterCount < 3; parameterCount++) {
    let defs = [
      `'use strong'; function f(${generateParams(parameterCount)}) {}`,
      `'use strong'; function f(${generateParamsWithRest(parameterCount)}) {}`,
      `'use strong'; function* f(${generateParams(parameterCount)}) {}`,
      `'use strong'; function* f(${generateParamsWithRest(parameterCount)}) {}`,
      `'use strong'; let f = (${generateParams(parameterCount)}) => {}`,
      `function f(${generateParams(parameterCount)}) { 'use strong'; }`,
      `function* f(${generateParams(parameterCount)}) { 'use strong'; }`,
      `let f = (${generateParams(parameterCount)}) => { 'use strong'; }`,
    ];
    for (let def of defs) {
      for (let argumentCount = 0; argumentCount < 3; argumentCount++) {
        let calls = [
          `f(${generateArguments(argumentCount)})`,
          `f(${generateSpread(argumentCount)})`,
          `f.call(${generateArguments(argumentCount, 'undefined')})`,
          `f.call(undefined, ${generateSpread(argumentCount)})`,
          `f.apply(undefined, [${generateArguments(argumentCount)}])`,
          `f.bind(undefined)(${generateArguments(argumentCount)})`,
          `%_Call(f, ${generateArguments(argumentCount, 'undefined')})`,
          `%Call(f, ${generateArguments(argumentCount, 'undefined')})`,
          `%Apply(f, undefined, [${generateArguments(argumentCount)}], 0,
                  ${argumentCount})`,
        ];

        for (let call of calls) {
          let code = `'use strict'; ${def}; ${call};`;
          if (argumentCount < parameterCount) {
            print(code);
            assertThrows(code, TypeError);
          } else {
            assertDoesNotThrow(code);
          }
        }
      }

      let calls = [
        `f.call()`,
        `f.apply()`,
        `f.apply(undefined)`,
      ];
      for (let call of calls) {
        let code = `'use strict'; ${def}; ${call};`;
        if (parameterCount > 0) {
          assertThrows(code, TypeError);
        } else {
          assertDoesNotThrow(code);
        }
      }
    }
  }
})();


(function MethodCall() {
  for (let genParams of [generateParams, generateParamsWithRest]) {
    for (let parameterCount = 0; parameterCount < 3; parameterCount++) {
      let defs = [
        `let o = new class {
          m(${genParams(parameterCount, true)}) { 'use strong'; }
        }`,
        `let o = new class {
          *m(${genParams(parameterCount, true)}) { 'use strong'; }
        }`,
        `let o = { m(${genParams(parameterCount, true)}) { 'use strong'; } }`,
        `let o = { *m(${genParams(parameterCount, true)}) { 'use strong'; } }`,
        `'use strong';
        let o = new class { m(${genParams(parameterCount)}) {} }`,
        `'use strong';
        let o = new class { *m(${genParams(parameterCount)}) {} }`,
        `'use strong'; let o = { m(${genParams(parameterCount)}) {} }`,
        `'use strong'; let o = { *m(${genParams(parameterCount)}) {} }`,
      ];
      for (let def of defs) {
        for (let argumentCount = 0; argumentCount < 3; argumentCount++) {
          let calls = [
            `o.m(${generateArguments(argumentCount)})`,
            `o.m(${generateSpread(argumentCount)})`,
            `o.m.call(${generateArguments(argumentCount, 'o')})`,
            `o.m.call(o, ${generateSpread(argumentCount)})`,
            `o.m.apply(o, [${generateArguments(argumentCount)}])`,
            `o.m.bind(o)(${generateArguments(argumentCount)})`,
            `%_Call(o.m, ${generateArguments(argumentCount, 'o')})`,
            `%Call(o.m, ${generateArguments(argumentCount, 'o')})`,
            `%Apply(o.m, o, [${generateArguments(argumentCount)}], 0,
                    ${argumentCount})`,
          ];

          for (let call of calls) {
            let code = `'use strict'; ${def}; ${call};`;
            if (argumentCount < parameterCount) {
              assertThrows(code, TypeError);
            } else {
              assertDoesNotThrow(code);
            }
          }
        }

        let calls = [
          `o.m.call()`,
          `o.m.apply()`,
          `o.m.apply(o)`,
        ];
        for (let call of calls) {
          let code = `'use strict'; ${def}; ${call};`;
          if (parameterCount > 0) {
            assertThrows(code, TypeError);
          } else {
            assertDoesNotThrow(code);
          }
        }
      }
    }
  }
})();


(function Constructor() {
  for (let genParams of [generateParams, generateParamsWithRest]) {
    for (let argumentCount = 0; argumentCount < 3; argumentCount++) {
      for (let parameterCount = 0; parameterCount < 3; parameterCount++) {
        let defs = [
          `'use strong';
          class C { constructor(${genParams(parameterCount)}) {} }`,
        ];
        for (let def of defs) {
          let calls = [
            `new C(${generateArguments(argumentCount)})`,
            `new C(${generateSpread(argumentCount)})`,
            `Reflect.construct(C, [${generateArguments(argumentCount)}])`,
          ];
          for (let call of calls) {
            let code = `${def}; ${call};`;
            if (argumentCount < parameterCount) {
              assertThrows(code, TypeError);
            } else {
              assertDoesNotThrow(code);
            }
          }
        }
      }
    }
  }
})();


(function DerivedConstructor() {
  for (let genParams of [generateParams, generateParamsWithRest]) {
    for (let genArgs of [generateArguments, generateSpread]) {
      for (let argumentCount = 0; argumentCount < 3; argumentCount++) {
        for (let parameterCount = 0; parameterCount < 3; parameterCount++) {
          let defs = [
            `'use strong';
            class B {
              constructor(${genParams(parameterCount)}) {}
            }
            class C extends B {
              constructor() {
                super(${genArgs(argumentCount)});
              }
            }`,
          ];
          for (let def of defs) {
            let code = `${def}; new C();`;
            if (argumentCount < parameterCount) {
              assertThrows(code, TypeError);
            } else {
              assertDoesNotThrow(code);
            }
          }
        }
      }
    }
  }
})();


(function DerivedConstructorDefaultConstructorInDerivedClass() {
  for (let genParams of [generateParams, generateParamsWithRest]) {
    for (let genArgs of [generateArguments, generateSpread]) {
      for (let argumentCount = 0; argumentCount < 3; argumentCount++) {
        for (let parameterCount = 0; parameterCount < 3; parameterCount++) {
          let defs = [
            `'use strong';
            class B {
              constructor(${genParams(parameterCount)}) {}
            }
            class C extends B {}`,
          ];
          for (let def of defs) {
            let code = `${def}; new C(${genArgs(argumentCount)})`;
            if (argumentCount < parameterCount) {
              assertThrows(code, TypeError);
            } else {
              assertDoesNotThrow(code);
            }
          }
        }
      }
    }
  }
})();


(function TestOptimized() {
  function f(x, y) { 'use strong'; }

  assertThrows(f, TypeError);
  %OptimizeFunctionOnNextCall(f);
  assertThrows(f, TypeError);

  function g() {
    f(1);
  }
  assertThrows(g, TypeError);
  %OptimizeFunctionOnNextCall(g);
  assertThrows(g, TypeError);

  f(1, 2);
  %OptimizeFunctionOnNextCall(f);
  f(1, 2);
})();


(function TestOptimized2() {
  'use strong';
  function f(x, y) {}

  assertThrows(f, TypeError);
  %OptimizeFunctionOnNextCall(f);
  assertThrows(f, TypeError);

  function g() {
    f(1);
  }
  assertThrows(g, TypeError);
  %OptimizeFunctionOnNextCall(g);
  assertThrows(g, TypeError);

  f(1, 2);
  %OptimizeFunctionOnNextCall(f);
  f(1, 2);
})();


(function TestOptimized3() {
  function f(x, y) {}
  function g() {
    'use strong';
    f(1);
  }

  g();
  %OptimizeFunctionOnNextCall(f);
  g();
})();


(function ParametersSuper() {
  for (let genArgs of [generateArguments, generateSpread]) {
    for (let argumentCount = 0; argumentCount < 3; argumentCount++) {
      for (let parameterCount = 0; parameterCount < 3; parameterCount++) {
        let defs = [
          `'use strict';
          class B {
            m(${generateParams(parameterCount)} ){ 'use strong' }
          }`,
          `'use strong'; class B { m(${generateParams(parameterCount)}) {} }`,
        ];
        for (let def of defs) {
          let code = `${def};
              class D extends B {
                m() {
                  super.m(${genArgs(argumentCount)});
                }
              }
              new D().m()`;
          print('\n\n' + code);
          if (argumentCount < parameterCount) {
            assertThrows(code, TypeError);
          } else {
            assertDoesNotThrow(code);
          }
        }
      }
    }
  }
})();