576 lines
13 KiB
JavaScript
576 lines
13 KiB
JavaScript
|
// Copyright 2024 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: --allow-natives-syntax
|
||
|
|
||
|
function optimize(f, a) {
|
||
|
%PrepareFunctionForOptimization(f);
|
||
|
f(...a);
|
||
|
f(...a);
|
||
|
%OptimizeFunctionOnNextCall(f);
|
||
|
return f(...a);
|
||
|
}
|
||
|
%NeverOptimizeFunction(optimize);
|
||
|
|
||
|
// Top level versions
|
||
|
|
||
|
// Sloppy arguments with no mapped count.
|
||
|
(function() {
|
||
|
function bar(x, y) { return y; }
|
||
|
function foo() {
|
||
|
return bar.apply(this, arguments);
|
||
|
}
|
||
|
assertEquals(optimize(foo, [1, 2, 3]), 2);
|
||
|
})();
|
||
|
|
||
|
// Sloppy arguments with mapped count.
|
||
|
(function() {
|
||
|
function bar(x, y) { return y; }
|
||
|
function foo(x, y) {
|
||
|
return bar.apply(this, arguments);
|
||
|
}
|
||
|
assertEquals(optimize(foo, [1, 2, 3]), 2);
|
||
|
})();
|
||
|
|
||
|
// Strict arguments.
|
||
|
(function() {
|
||
|
"use strict";
|
||
|
function bar(x, y) { return y; }
|
||
|
function foo(x, y) {
|
||
|
return bar.apply(this, arguments);
|
||
|
}
|
||
|
assertEquals(optimize(foo, [1, 2, 3]), 2);
|
||
|
})();
|
||
|
|
||
|
// Sloppy arguments with no mapped count with update before call.
|
||
|
(function() {
|
||
|
function bar(x, y) { return y; }
|
||
|
function foo() {
|
||
|
arguments[1] = 42;
|
||
|
return bar.apply(this, arguments);
|
||
|
}
|
||
|
assertEquals(optimize(foo, [1, 2, 3]), 42);
|
||
|
})();
|
||
|
|
||
|
// Sloppy arguments with mapped count with update before call.
|
||
|
(function() {
|
||
|
function bar(x, y) { return y; }
|
||
|
function foo(x, y) {
|
||
|
arguments[1] = 42;
|
||
|
return bar.apply(this, arguments);
|
||
|
}
|
||
|
assertEquals(optimize(foo, [1, 2, 3]), 42);
|
||
|
})();
|
||
|
|
||
|
// Sloppy arguments with mapped count with mapped update before call.
|
||
|
(function() {
|
||
|
function bar(x, y) { return y; }
|
||
|
function foo(x, y) {
|
||
|
y = 42;
|
||
|
return bar.apply(this, arguments);
|
||
|
}
|
||
|
assertEquals(optimize(foo, [1, 2, 3]), 42);
|
||
|
})();
|
||
|
|
||
|
// Strict arguments with updates before call.
|
||
|
(function() {
|
||
|
"use strict";
|
||
|
function bar(x, y) { return y; }
|
||
|
function foo(x, y) {
|
||
|
arguments[1] = 42;
|
||
|
return bar.apply(this, arguments);
|
||
|
}
|
||
|
assertEquals(optimize(foo, [1, 2, 3]), 42);
|
||
|
})();
|
||
|
|
||
|
// Sloppy arguments with no mapped count with update after call.
|
||
|
(function() {
|
||
|
function bar(x, y) { return y; }
|
||
|
function foo() {
|
||
|
let r = bar.apply(this, arguments);
|
||
|
arguments[1] = 42;
|
||
|
return r;
|
||
|
}
|
||
|
assertEquals(optimize(foo, [1, 2, 3]), 2);
|
||
|
})();
|
||
|
|
||
|
// Sloppy arguments with mapped count with update after call.
|
||
|
(function() {
|
||
|
function bar(x, y) { return y; }
|
||
|
function foo(x, y) {
|
||
|
let r = bar.apply(this, arguments);
|
||
|
arguments[1] = 42;
|
||
|
return r;
|
||
|
}
|
||
|
assertEquals(optimize(foo, [1, 2, 3]), 2);
|
||
|
})();
|
||
|
|
||
|
// Strict arguments with updates after call.
|
||
|
(function() {
|
||
|
"use strict";
|
||
|
function bar(x, y) { return y; }
|
||
|
function foo(x, y) {
|
||
|
let r = bar.apply(this, arguments);
|
||
|
arguments[1] = 42;
|
||
|
return r;
|
||
|
}
|
||
|
assertEquals(optimize(foo, [1, 2, 3]), 2);
|
||
|
})();
|
||
|
|
||
|
// Sloppy arguments with no mapped count with update after call in a loop.
|
||
|
(function() {
|
||
|
function bar(x, y) { return y; }
|
||
|
function foo() {
|
||
|
let r = 0;
|
||
|
for (let i = 0; i < 2; i++) {
|
||
|
r += bar.apply(this, arguments);
|
||
|
arguments[1] = 42;
|
||
|
}
|
||
|
return r;
|
||
|
}
|
||
|
assertEquals(optimize(foo, [1, 2, 3]), 44);
|
||
|
})();
|
||
|
|
||
|
// Sloppy arguments with mapped count with update after call in a loop.
|
||
|
(function() {
|
||
|
function bar(x, y) { return y; }
|
||
|
function foo(x, y) {
|
||
|
let r = 0;
|
||
|
for (let i = 0; i < 2; i++) {
|
||
|
r += bar.apply(this, arguments);
|
||
|
arguments[1] = 42;
|
||
|
}
|
||
|
return r;
|
||
|
}
|
||
|
assertEquals(optimize(foo, [1, 2, 3]), 44);
|
||
|
})();
|
||
|
|
||
|
// Strict arguments with updates after call in a loop.
|
||
|
(function() {
|
||
|
"use strict";
|
||
|
function bar(x, y) { return y; }
|
||
|
function foo(x, y) {
|
||
|
let r = 0;
|
||
|
for (let i = 0; i < 2; i++) {
|
||
|
r += bar.apply(this, arguments);
|
||
|
arguments[1] = 42;
|
||
|
}
|
||
|
return r;
|
||
|
}
|
||
|
assertEquals(optimize(foo, [1, 2, 3]), 44);
|
||
|
})();
|
||
|
|
||
|
|
||
|
// Inlined versions
|
||
|
|
||
|
// Sloppy arguments with no mapped count.
|
||
|
(function() {
|
||
|
function bar(x, y) { return y; }
|
||
|
function foo() {
|
||
|
return bar.apply(this, arguments);
|
||
|
}
|
||
|
function top() {
|
||
|
return foo(1, 2, 3);
|
||
|
}
|
||
|
%PrepareFunctionForOptimization(foo);
|
||
|
assertEquals(optimize(top, []), 2);
|
||
|
})();
|
||
|
|
||
|
// Sloppy arguments with mapped count.
|
||
|
(function() {
|
||
|
function bar(x, y) { return y; }
|
||
|
function foo(x, y) {
|
||
|
return bar.apply(this, arguments);
|
||
|
}
|
||
|
function top() {
|
||
|
return foo(1, 2, 3);
|
||
|
}
|
||
|
%PrepareFunctionForOptimization(foo);
|
||
|
assertEquals(optimize(top, []), 2);
|
||
|
})();
|
||
|
|
||
|
// Strict arguments.
|
||
|
(function() {
|
||
|
"use strict";
|
||
|
function bar(x, y) { return y; }
|
||
|
function foo(x, y) {
|
||
|
return bar.apply(this, arguments);
|
||
|
}
|
||
|
function top() {
|
||
|
return foo(1, 2, 3);
|
||
|
}
|
||
|
%PrepareFunctionForOptimization(foo);
|
||
|
assertEquals(optimize(top, []), 2);
|
||
|
})();
|
||
|
|
||
|
// Sloppy arguments with no mapped count with update before call.
|
||
|
(function() {
|
||
|
function bar(x, y) { return y; }
|
||
|
function foo() {
|
||
|
arguments[1] = 42;
|
||
|
return bar.apply(this, arguments);
|
||
|
}
|
||
|
function top() {
|
||
|
return foo(1, 2, 3);
|
||
|
}
|
||
|
%PrepareFunctionForOptimization(foo);
|
||
|
assertEquals(optimize(top, []), 42);
|
||
|
})();
|
||
|
|
||
|
// Sloppy arguments with mapped count with update before call.
|
||
|
(function() {
|
||
|
function bar(x, y) { return y; }
|
||
|
function foo(x, y) {
|
||
|
arguments[1] = 42;
|
||
|
return bar.apply(this, arguments);
|
||
|
}
|
||
|
function top() {
|
||
|
return foo(1, 2, 3);
|
||
|
}
|
||
|
%PrepareFunctionForOptimization(foo);
|
||
|
assertEquals(optimize(top, []), 42);
|
||
|
})();
|
||
|
|
||
|
// Sloppy arguments with mapped count with mapped update before call.
|
||
|
(function() {
|
||
|
function bar(x, y) { return y; }
|
||
|
function foo(x, y) {
|
||
|
y = 42;
|
||
|
return bar.apply(this, arguments);
|
||
|
}
|
||
|
function top() {
|
||
|
return foo(1, 2, 3);
|
||
|
}
|
||
|
%PrepareFunctionForOptimization(foo);
|
||
|
assertEquals(optimize(top, []), 42);
|
||
|
})();
|
||
|
|
||
|
// Strict arguments with updates before call.
|
||
|
(function() {
|
||
|
"use strict";
|
||
|
function bar(x, y) { return y; }
|
||
|
function foo(x, y) {
|
||
|
arguments[1] = 42;
|
||
|
return bar.apply(this, arguments);
|
||
|
}
|
||
|
function top() {
|
||
|
return foo(1, 2, 3);
|
||
|
}
|
||
|
%PrepareFunctionForOptimization(foo);
|
||
|
assertEquals(optimize(top, []), 42);
|
||
|
})();
|
||
|
|
||
|
// Sloppy arguments with no mapped count with update after call.
|
||
|
(function() {
|
||
|
function bar(x, y) { return y; }
|
||
|
function foo() {
|
||
|
let r = bar.apply(this, arguments);
|
||
|
arguments[1] = 42;
|
||
|
return r;
|
||
|
}
|
||
|
function top() {
|
||
|
return foo(1, 2, 3);
|
||
|
}
|
||
|
%PrepareFunctionForOptimization(foo);
|
||
|
assertEquals(optimize(top, []), 2);
|
||
|
})();
|
||
|
|
||
|
// Sloppy arguments with mapped count with update after call.
|
||
|
(function() {
|
||
|
function bar(x, y) { return y; }
|
||
|
function foo(x, y) {
|
||
|
let r = bar.apply(this, arguments);
|
||
|
arguments[1] = 42;
|
||
|
return r;
|
||
|
}
|
||
|
function top() {
|
||
|
return foo(1, 2, 3);
|
||
|
}
|
||
|
%PrepareFunctionForOptimization(foo);
|
||
|
assertEquals(optimize(top, []), 2);
|
||
|
})();
|
||
|
|
||
|
// Strict arguments with updates after call.
|
||
|
(function() {
|
||
|
"use strict";
|
||
|
function bar(x, y) { return y; }
|
||
|
function foo(x, y) {
|
||
|
let r = bar.apply(this, arguments);
|
||
|
arguments[1] = 42;
|
||
|
return r;
|
||
|
}
|
||
|
function top() {
|
||
|
return foo(1, 2, 3);
|
||
|
}
|
||
|
%PrepareFunctionForOptimization(foo);
|
||
|
assertEquals(optimize(top, []), 2);
|
||
|
})();
|
||
|
|
||
|
// Sloppy arguments with no mapped count with update after call in a loop.
|
||
|
(function() {
|
||
|
function bar(x, y) { return y; }
|
||
|
function foo() {
|
||
|
let r = 0;
|
||
|
for (let i = 0; i < 2; i++) {
|
||
|
r += bar.apply(this, arguments);
|
||
|
arguments[1] = 42;
|
||
|
}
|
||
|
return r;
|
||
|
}
|
||
|
function top() {
|
||
|
return foo(1, 2, 3);
|
||
|
}
|
||
|
%PrepareFunctionForOptimization(foo);
|
||
|
assertEquals(optimize(top, []), 44);
|
||
|
})();
|
||
|
|
||
|
// Sloppy arguments with mapped count with update after call in a loop.
|
||
|
(function() {
|
||
|
function bar(x, y) { return y; }
|
||
|
function foo(x, y) {
|
||
|
let r = 0;
|
||
|
for (let i = 0; i < 2; i++) {
|
||
|
r += bar.apply(this, arguments);
|
||
|
arguments[1] = 42;
|
||
|
}
|
||
|
return r;
|
||
|
}
|
||
|
function top() {
|
||
|
return foo(1, 2, 3);
|
||
|
}
|
||
|
%PrepareFunctionForOptimization(foo);
|
||
|
assertEquals(optimize(top, []), 44);
|
||
|
})();
|
||
|
|
||
|
// Strict arguments with updates after call in a loop.
|
||
|
(function() {
|
||
|
"use strict";
|
||
|
function bar(x, y) { return y; }
|
||
|
function foo(x, y) {
|
||
|
let r = 0;
|
||
|
for (let i = 0; i < 2; i++) {
|
||
|
r += bar.apply(this, arguments);
|
||
|
arguments[1] = 42;
|
||
|
}
|
||
|
return r;
|
||
|
}
|
||
|
function top() {
|
||
|
return foo(1, 2, 3);
|
||
|
}
|
||
|
%PrepareFunctionForOptimization(foo);
|
||
|
assertEquals(optimize(top, []), 44);
|
||
|
})();
|
||
|
|
||
|
// Inline function propagating inlined arguments.
|
||
|
|
||
|
// Sloppy arguments with no mapped count.
|
||
|
(function() {
|
||
|
function bar(x, y) { return y; }
|
||
|
function foo() {
|
||
|
return bar.apply(this, arguments);
|
||
|
}
|
||
|
function top() {
|
||
|
return foo(1, 2, 3);
|
||
|
}
|
||
|
%PrepareFunctionForOptimization(bar);
|
||
|
%PrepareFunctionForOptimization(foo);
|
||
|
assertEquals(optimize(top, []), 2);
|
||
|
})();
|
||
|
|
||
|
// Sloppy arguments with mapped count.
|
||
|
(function() {
|
||
|
function bar(x, y) { return y; }
|
||
|
function foo(x, y) {
|
||
|
return bar.apply(this, arguments);
|
||
|
}
|
||
|
function top() {
|
||
|
return foo(1, 2, 3);
|
||
|
}
|
||
|
%PrepareFunctionForOptimization(foo);
|
||
|
assertEquals(optimize(top, []), 2);
|
||
|
})();
|
||
|
|
||
|
// Strict arguments.
|
||
|
(function() {
|
||
|
"use strict";
|
||
|
function bar(x, y) { return y; }
|
||
|
function foo(x, y) {
|
||
|
return bar.apply(this, arguments);
|
||
|
}
|
||
|
function top() {
|
||
|
return foo(1, 2, 3);
|
||
|
}
|
||
|
%PrepareFunctionForOptimization(bar);
|
||
|
%PrepareFunctionForOptimization(foo);
|
||
|
assertEquals(optimize(top, []), 2);
|
||
|
})();
|
||
|
|
||
|
// Sloppy arguments with no mapped count with update before call.
|
||
|
(function() {
|
||
|
function bar(x, y) { return y; }
|
||
|
function foo() {
|
||
|
arguments[1] = 42;
|
||
|
return bar.apply(this, arguments);
|
||
|
}
|
||
|
function top() {
|
||
|
return foo(1, 2, 3);
|
||
|
}
|
||
|
%PrepareFunctionForOptimization(bar);
|
||
|
%PrepareFunctionForOptimization(foo);
|
||
|
assertEquals(optimize(top, []), 42);
|
||
|
})();
|
||
|
|
||
|
// Sloppy arguments with mapped count with update before call.
|
||
|
(function() {
|
||
|
function bar(x, y) { return y; }
|
||
|
function foo(x, y) {
|
||
|
arguments[1] = 42;
|
||
|
return bar.apply(this, arguments);
|
||
|
}
|
||
|
function top() {
|
||
|
return foo(1, 2, 3);
|
||
|
}
|
||
|
%PrepareFunctionForOptimization(bar);
|
||
|
%PrepareFunctionForOptimization(foo);
|
||
|
assertEquals(optimize(top, []), 42);
|
||
|
})();
|
||
|
|
||
|
// Sloppy arguments with mapped count with mapped update before call.
|
||
|
(function() {
|
||
|
function bar(x, y) { return y; }
|
||
|
function foo(x, y) {
|
||
|
y = 42;
|
||
|
return bar.apply(this, arguments);
|
||
|
}
|
||
|
function top() {
|
||
|
return foo(1, 2, 3);
|
||
|
}
|
||
|
%PrepareFunctionForOptimization(bar);
|
||
|
%PrepareFunctionForOptimization(foo);
|
||
|
assertEquals(optimize(top, []), 42);
|
||
|
})();
|
||
|
|
||
|
// Strict arguments with updates before call.
|
||
|
(function() {
|
||
|
"use strict";
|
||
|
function bar(x, y) { return y; }
|
||
|
function foo(x, y) {
|
||
|
arguments[1] = 42;
|
||
|
return bar.apply(this, arguments);
|
||
|
}
|
||
|
function top() {
|
||
|
return foo(1, 2, 3);
|
||
|
}
|
||
|
%PrepareFunctionForOptimization(bar);
|
||
|
%PrepareFunctionForOptimization(foo);
|
||
|
assertEquals(optimize(top, []), 42);
|
||
|
})();
|
||
|
|
||
|
// Sloppy arguments with no mapped count with update after call.
|
||
|
(function() {
|
||
|
function bar(x, y) { return y; }
|
||
|
function foo() {
|
||
|
let r = bar.apply(this, arguments);
|
||
|
arguments[1] = 42;
|
||
|
return r;
|
||
|
}
|
||
|
function top() {
|
||
|
return foo(1, 2, 3);
|
||
|
}
|
||
|
%PrepareFunctionForOptimization(bar);
|
||
|
%PrepareFunctionForOptimization(foo);
|
||
|
assertEquals(optimize(top, []), 2);
|
||
|
})();
|
||
|
|
||
|
// Sloppy arguments with mapped count with update after call.
|
||
|
(function() {
|
||
|
function bar(x, y) { return y; }
|
||
|
function foo(x, y) {
|
||
|
let r = bar.apply(this, arguments);
|
||
|
arguments[1] = 42;
|
||
|
return r;
|
||
|
}
|
||
|
function top() {
|
||
|
return foo(1, 2, 3);
|
||
|
}
|
||
|
%PrepareFunctionForOptimization(bar);
|
||
|
%PrepareFunctionForOptimization(foo);
|
||
|
assertEquals(optimize(top, []), 2);
|
||
|
})();
|
||
|
|
||
|
// Strict arguments with updates after call.
|
||
|
(function() {
|
||
|
"use strict";
|
||
|
function bar(x, y) { return y; }
|
||
|
function foo(x, y) {
|
||
|
let r = bar.apply(this, arguments);
|
||
|
arguments[1] = 42;
|
||
|
return r;
|
||
|
}
|
||
|
function top() {
|
||
|
return foo(1, 2, 3);
|
||
|
}
|
||
|
%PrepareFunctionForOptimization(bar);
|
||
|
%PrepareFunctionForOptimization(foo);
|
||
|
assertEquals(optimize(top, []), 2);
|
||
|
})();
|
||
|
|
||
|
// Sloppy arguments with no mapped count with update after call in a loop.
|
||
|
(function() {
|
||
|
function bar(x, y) { return y; }
|
||
|
function foo() {
|
||
|
let r = 0;
|
||
|
for (let i = 0; i < 2; i++) {
|
||
|
r += bar.apply(this, arguments);
|
||
|
arguments[1] = 42;
|
||
|
}
|
||
|
return r;
|
||
|
}
|
||
|
function top() {
|
||
|
return foo(1, 2, 3);
|
||
|
}
|
||
|
%PrepareFunctionForOptimization(bar);
|
||
|
%PrepareFunctionForOptimization(foo);
|
||
|
assertEquals(optimize(top, []), 44);
|
||
|
})();
|
||
|
|
||
|
// Sloppy arguments with mapped count with update after call in a loop.
|
||
|
(function() {
|
||
|
function bar(x, y) { return y; }
|
||
|
function foo(x, y) {
|
||
|
let r = 0;
|
||
|
for (let i = 0; i < 2; i++) {
|
||
|
r += bar.apply(this, arguments);
|
||
|
arguments[1] = 42;
|
||
|
}
|
||
|
return r;
|
||
|
}
|
||
|
function top() {
|
||
|
return foo(1, 2, 3);
|
||
|
}
|
||
|
%PrepareFunctionForOptimization(bar);
|
||
|
%PrepareFunctionForOptimization(foo);
|
||
|
assertEquals(optimize(top, []), 44);
|
||
|
})();
|
||
|
|
||
|
// Strict arguments with updates after call in a loop.
|
||
|
(function() {
|
||
|
"use strict";
|
||
|
function bar(x, y) { return y; }
|
||
|
function foo(x, y) {
|
||
|
let r = 0;
|
||
|
for (let i = 0; i < 2; i++) {
|
||
|
r += bar.apply(this, arguments);
|
||
|
arguments[1] = 42;
|
||
|
}
|
||
|
return r;
|
||
|
}
|
||
|
function top() {
|
||
|
return foo(1, 2, 3);
|
||
|
}
|
||
|
%PrepareFunctionForOptimization(bar);
|
||
|
%PrepareFunctionForOptimization(foo);
|
||
|
assertEquals(optimize(top, []), 44);
|
||
|
})();
|