v8/test/mjsunit/strong/function-arity.js
bmeurer db2ba190db [runtime] Replace many buggy uses of %_CallFunction with %_Call.
The semantics of the %_CallFunction intrinsic seem to be very unclear,
which resulted in a lot of bugs. Especially the combination with
%IsSloppyModeFunction is always a bug, because the receiver would be
wrapped in the wrong context. So the %IsSloppyModeFunction helper is
gone now, and many of the buggy uses of %_CallFunction are also
eliminated.

If you ever need to call something with a different receiver, then
%_Call is your friend now. It does what you want and implements the
call sequence fully (and correct).

BUG=v8:4413
LOG=n

Review URL: https://codereview.chromium.org/1325573004

Cr-Commit-Position: refs/heads/master@{#30634}
2015-09-08 13:35:32 +00:00

343 lines
9.8 KiB
JavaScript

// 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-arrow-functions --harmony-reflect
// Flags: --harmony-spreadcalls --harmony-rest-parameters --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)})`,
`%_CallFunction(${generateArguments(argumentCount, 'undefined')},
f)`,
`%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)})`,
`%_CallFunction(${generateArguments(argumentCount, 'o')}, o.m)`,
`%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);
}
}
}
}
}
})();