db2ba190db
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}
343 lines
9.8 KiB
JavaScript
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);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
})();
|