Upload Kmake

This commit is contained in:
Gorochu
2026-05-26 23:36:42 -07:00
parent ba051b2f74
commit 555ec72358
41615 changed files with 13344630 additions and 1 deletions

18
deps/v8/test/mjsunit/maglev/00.js vendored Normal file
View File

@ -0,0 +1,18 @@
// Copyright 2022 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 --maglev
function f(x) {
if (x) return 1;
return 2;
}
%PrepareFunctionForOptimization(f);
assertEquals(1, f(true));
assertEquals(2, f(false));
%OptimizeMaglevOnNextCall(f);
assertEquals(1, f(true));
assertEquals(2, f(false));

20
deps/v8/test/mjsunit/maglev/01.js vendored Normal file
View File

@ -0,0 +1,20 @@
// Copyright 2022 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 --maglev
var xyz = 42;
function f(x) {
if (x) return 1;
return xyz;
}
%PrepareFunctionForOptimization(f);
assertEquals(1, f(true));
assertEquals(42, f(false));
%OptimizeMaglevOnNextCall(f);
assertEquals(1, f(true));
assertEquals(42, f(false));

20
deps/v8/test/mjsunit/maglev/02.js vendored Normal file
View File

@ -0,0 +1,20 @@
// Copyright 2022 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 --maglev
function f(x) {
if (x < 0) return -1;
return 1;
}
%PrepareFunctionForOptimization(f);
assertEquals(-1, f(-2));
assertEquals(1, f(0));
assertEquals(1, f(2));
%OptimizeMaglevOnNextCall(f);
assertEquals(-1, f(-2));
assertEquals(1, f(0));
assertEquals(1, f(2));

21
deps/v8/test/mjsunit/maglev/03.js vendored Normal file
View File

@ -0,0 +1,21 @@
// Copyright 2022 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 --maglev
function f(x) {
var y = 0;
for (var i = 0; i < x; i++) {
y = 1;
}
return y;
}
%PrepareFunctionForOptimization(f);
assertEquals(1, f(true));
assertEquals(0, f(false));
%OptimizeMaglevOnNextCall(f);
assertEquals(1, f(true));
assertEquals(0, f(false));

16
deps/v8/test/mjsunit/maglev/04.js vendored Normal file
View File

@ -0,0 +1,16 @@
// Copyright 2022 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 --maglev
function f(x) {
while (true) {
if (x) return 10;
}
}
%PrepareFunctionForOptimization(f);
assertEquals(10, f(true));
%OptimizeMaglevOnNextCall(f);
assertEquals(10, f(true));

21
deps/v8/test/mjsunit/maglev/05.js vendored Normal file
View File

@ -0,0 +1,21 @@
// Copyright 2022 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 --maglev
function f(i, end) {
do {
do {
i = end;
} while (end);
end = i;
} while (i);
return 10;
}
%PrepareFunctionForOptimization(f);
assertEquals(10, f(false, false));
%OptimizeMaglevOnNextCall(f);
assertEquals(10, f(false, false));

25
deps/v8/test/mjsunit/maglev/06.js vendored Normal file
View File

@ -0,0 +1,25 @@
// Copyright 2022 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 --maglev
function f(i, j) {
var x = 1;
var y = 2;
if (i) {
x = y;
if (j) {
x = 3
}
}
return x;
}
%PrepareFunctionForOptimization(f);
assertEquals(1, f(false, true));
%OptimizeMaglevOnNextCall(f);
assertEquals(1, f(false, false));
assertEquals(2, f(true, false));
assertEquals(3, f(true, true));

19
deps/v8/test/mjsunit/maglev/07.js vendored Normal file
View File

@ -0,0 +1,19 @@
// Copyright 2022 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 --maglev
function f(i) {
var x = 1;
if (i) { x = 2 }
return x;
}
%PrepareFunctionForOptimization(f);
assertEquals(2, f(true));
assertEquals(1, f(false));
%OptimizeMaglevOnNextCall(f);
assertEquals(2, f(true));
assertEquals(1, f(false));

19
deps/v8/test/mjsunit/maglev/08.js vendored Normal file
View File

@ -0,0 +1,19 @@
// Copyright 2022 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 --maglev
function f(i) {
var x = 1;
if (i) {} else { x = 2 }
return x;
}
%PrepareFunctionForOptimization(f);
assertEquals(1, f(true));
assertEquals(2, f(false));
%OptimizeMaglevOnNextCall(f);
assertEquals(1, f(true));
assertEquals(2, f(false));

21
deps/v8/test/mjsunit/maglev/09.js vendored Normal file
View File

@ -0,0 +1,21 @@
// Copyright 2022 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 --maglev
function f(i) {
var x = 1;
if (i) {
if (i) { x = 3 } else {}
} else { x = 2 }
return x;
}
%PrepareFunctionForOptimization(f);
assertEquals(3, f(true));
assertEquals(2, f(false));
%OptimizeMaglevOnNextCall(f);
assertEquals(3, f(true));
assertEquals(2, f(false));

26
deps/v8/test/mjsunit/maglev/10.js vendored Normal file
View File

@ -0,0 +1,26 @@
// Copyright 2022 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 --maglev
const ys = [0,1,2];
function g() {
%CollectGarbage(42);
return [0,1,2];
}
%NeverOptimizeFunction(g);
const o = { g: g };
function f(o) {
// Using CallProperty since plain calls are still unimplemented.
return o.g();
}
%PrepareFunctionForOptimization(f);
assertEquals(ys, f(o));
%OptimizeMaglevOnNextCall(f);
assertEquals(ys, f(o));

39
deps/v8/test/mjsunit/maglev/11.js vendored Normal file
View File

@ -0,0 +1,39 @@
// Copyright 2022 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 --maglev
function f(x) {
return x.a
}
function Foo(a) {
this.a = a
}
%PrepareFunctionForOptimization(f);
// Smi
var o1_1 = new Foo(1);
var o1_2 = new Foo(1);
// Transition map to double, o1 is deprecated, o1's map is a deprecation target.
var o2 = new Foo(1.2);
// Transition map to tagged, o1 is still deprecated.
var an_object = {};
var o3 = new Foo(an_object);
assertEquals(1, f(o1_1));
assertEquals(1.2, f(o2));
assertEquals(an_object, f(o3));
// o1_1 got migrated, but o1_2 hasn't yet.
assertTrue(%HaveSameMap(o1_1,o3));
assertFalse(%HaveSameMap(o1_2,o3));
%OptimizeMaglevOnNextCall(f);
// Deprecated map works
assertEquals(1, f(o1_2));
// Non-deprecated map works
assertEquals(an_object, f(o3));

27
deps/v8/test/mjsunit/maglev/12.js vendored Normal file
View File

@ -0,0 +1,27 @@
// Copyright 2022 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 --maglev
function g() {
%CollectGarbage(42);
return 43;
}
%NeverOptimizeFunction(g);
const o = { g: g };
function f(o, x) {
var y = 42;
if (x) y = 43;
// Using CallProperty since plain calls are still unimplemented.
o.g();
return y;
}
%PrepareFunctionForOptimization(f);
assertEquals(43, f(o, true));
%OptimizeMaglevOnNextCall(f);
assertEquals(43, f(o, true));

17
deps/v8/test/mjsunit/maglev/13.js vendored Normal file
View File

@ -0,0 +1,17 @@
// Copyright 2022 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 --maglev
function f(a) {
while(true) {
if(5 < ++a) return a;
}
}
%PrepareFunctionForOptimization(f);
assertEquals(f(0), 6);
%OptimizeMaglevOnNextCall(f);
assertEquals(f(0), 6);

31
deps/v8/test/mjsunit/maglev/14.js vendored Normal file
View File

@ -0,0 +1,31 @@
// Copyright 2022 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 --maglev
function f(i) {
a:{
b: {
c: {
if (i < 100) {
break c;
} else {
break b;
}
i = 3;
}
i = 4;
break a;
}
i = 5;
}
return i;
}
%PrepareFunctionForOptimization(f);
assertEquals(f(1), 4);
%OptimizeMaglevOnNextCall(f);
assertEquals(f(1), 4);

17
deps/v8/test/mjsunit/maglev/15.js vendored Normal file
View File

@ -0,0 +1,17 @@
// Copyright 2022 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 --maglev
var xyz = 42;
function f(x) {
return x < x;
}
%PrepareFunctionForOptimization(f);
assertEquals(f(1), false);
%OptimizeMaglevOnNextCall(f);
assertEquals(f(1), false);

30
deps/v8/test/mjsunit/maglev/16.js vendored Normal file
View File

@ -0,0 +1,30 @@
// Copyright 2022 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 --maglev
function f(x) {
return x.a;
}
function Foo(a) {
this.a = a;
}
function Goo(a) {
this.a = a;
}
%PrepareFunctionForOptimization(f);
var o1 = new Foo(42);
var o2 = new Goo(4.2);
assertEquals(f(o1), 42);
assertEquals(f(o2), 4.2);
%OptimizeMaglevOnNextCall(f);
assertEquals(f(o1), 42);
assertEquals(f(o2), 4.2);

27
deps/v8/test/mjsunit/maglev/17.js vendored Normal file
View File

@ -0,0 +1,27 @@
// Copyright 2022 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 setA(o, val) {
o.a = val;
}
function Foo() {
this.a = 0;
}
var foo = new Foo();
%PrepareFunctionForOptimization(setA);
setA(foo, 1);
assertEquals(foo.a, 1);
setA(foo, 2);
assertEquals(foo.a, 2);
%OptimizeMaglevOnNextCall(setA);
setA(foo, 42);
assertEquals(foo.a, 42);

26
deps/v8/test/mjsunit/maglev/18.js vendored Normal file
View File

@ -0,0 +1,26 @@
// Copyright 2022 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 --maglev
function f(x) {
var y = 0;
for (var i = 0; i < x; i++) {
y = 1;
}
return y;
}
function g() {
// Test that normal tiering (without OptimizeMaglevOnNextCall) works.
for (let i = 0; i < 1000; i++) {
if (%ActiveTierIsMaglev(f)) break;
f(10);
}
}
%NeverOptimizeFunction(g);
g();
assertTrue(%ActiveTierIsMaglev(f));

25
deps/v8/test/mjsunit/maglev/19.js vendored Normal file
View File

@ -0,0 +1,25 @@
// Copyright 2022 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 --maglev
function f(i) {
var j;
var o;
if (i) {
} else {
if (j) {
} else {
}
}
return o;
}
%PrepareFunctionForOptimization(f);
f(false, true);
%OptimizeMaglevOnNextCall(f);
f(false, true);
f(false, true);
f(false, true);

View File

@ -0,0 +1,23 @@
// 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
async function f1(x) {
for (let i = 0; i < 1; i++) {
try { i[i](23n, 12); } catch {}
}
try {
await "-4294967296";
} catch {}
try {
Object.defineProperty(this, 'x', {
set: function (value) {x;}
});
} catch {}
}
%PrepareFunctionForOptimization(f1);
try {f1()} catch {};
%OptimizeFunctionOnNextCall(f1);
try {f1()} catch {};

View File

@ -0,0 +1,88 @@
// Copyright 2022 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 --maglev
(function() {
function add(x, y) {
return x + y;
}
%PrepareFunctionForOptimization(add);
assertEquals(4.2, add(2.1, 2.1));
%OptimizeMaglevOnNextCall(add);
assertEquals(4.2, add(2.1, 2.1));
assertTrue(isMaglevved(add));
// We don't deopt if we use smis.
assertEquals(42, add(22, 20));
assertTrue(isMaglevved(add));
// We deopt if not a number.
assertEquals("42", add("4", "2"));
assertFalse(isMaglevved(add));
})();
// Deopt in the second Float64Unbox when the first argument is a Smi.
(function() {
function add(x, y) {
return x + y;
}
%PrepareFunctionForOptimization(add);
assertEquals(4.2, add(2.1, 2.1));
%OptimizeMaglevOnNextCall(add);
assertEquals(4.2, add(2.1, 2.1));
assertTrue(isMaglevved(add));
// We deopt if not a number.
assertEquals("42", add(4, "2"));
assertFalse(isMaglevved(add));
})();
// Deopt in the second Float64Unbox when the first argument is a double.
(function() {
function add(x, y) {
return x + y;
}
%PrepareFunctionForOptimization(add);
assertEquals(4.2, add(2.1, 2.1));
%OptimizeMaglevOnNextCall(add);
assertEquals(4.2, add(2.1, 2.1));
assertTrue(isMaglevved(add));
// We deopt if not a number.
assertEquals("4.2!", add(4.2, "!"));
assertFalse(isMaglevved(add));
})();
// Emit FloatAdd through SmiAdd bytecode.
(function() {
function inc(x) {
return x + 1
}
%PrepareFunctionForOptimization(inc);
assertEquals(4.2, inc(3.2));
%OptimizeMaglevOnNextCall(inc);
assertEquals(4.2, inc(3.2));
})();
// Force the input of FloatAdd to be int32.
(function() {
function add(x, y, z) {
return (x + y) + z;
}
%PrepareFunctionForOptimization(add);
assertEquals(4.2, add(1, 3, 0.2));
%OptimizeMaglevOnNextCall(add);
assertEquals(4.2, add(1, 3, 0.2));
})();

40
deps/v8/test/mjsunit/maglev/add-smi.js vendored Normal file
View File

@ -0,0 +1,40 @@
// Copyright 2022 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 --maglev
// Checks Smi add operation and deopt while untagging.
(function() {
function add(x, y) {
return x + y;
}
%PrepareFunctionForOptimization(add);
assertEquals(3, add(1, 2));
%OptimizeMaglevOnNextCall(add);
assertEquals(3, add(1, 2));
assertTrue(isMaglevved(add));
assertEquals(0x40000000, add(1, 0x3FFFFFFF));
assertTrue(isMaglevved(add));
})();
// Checks when we deopt due to tagging.
(function() {
function add(x, y) {
return x + y;
}
%PrepareFunctionForOptimization(add);
assertEquals(3, add(1, 2));
%OptimizeMaglevOnNextCall(add);
assertEquals(3, add(1, 2));
assertTrue(isMaglevved(add));
// We should deopt here in Int32Add.
assertEquals(3.2, add(1.2, 2));
assertFalse(isMaglevved(add));
})();

View File

@ -0,0 +1,25 @@
// 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 --maglev --no-always-turbofan
function bar() {}
function foo(i) {
let a = [1, 4.2, 3];
let b = a;
if (i == 1) {
bar(); // Force deoptimization.
return a == b;
}
}
%PrepareFunctionForOptimization(foo);
foo(0);
foo(0);
%OptimizeMaglevOnNextCall(foo);
foo(0);
assertTrue(isMaglevved(foo));
assertTrue(foo(1));
assertUnoptimized(foo);

View File

@ -0,0 +1,32 @@
// 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 --maglev --no-always-turbofan
function a() {
}
function b() {
}
Error.captureStackTrace(a);
Error.captureStackTrace(b);
function foo(f, s) {
// This calls an API setter.
f.stack = s;
}
%PrepareFunctionForOptimization(foo);
foo(a, 'stack1');
foo(b, 'stack2');
foo(a, 'stack3');
// Make the store polymorphic.
foo({}, 'unrelated');
%OptimizeMaglevOnNextCall(foo);
foo(a, 'stack4');
assertEquals('stack4', a.stack);

View File

@ -0,0 +1,29 @@
// 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 --maglev --no-always-turbofan
function a() {
}
function b() {
}
Error.captureStackTrace(a);
Error.captureStackTrace(b);
function foo(f, s) {
// This calls an API setter.
f.stack = s;
}
%PrepareFunctionForOptimization(foo);
foo(a, 'stack1');
foo(b, 'stack2');
foo(a, 'stack3');
%OptimizeMaglevOnNextCall(foo);
foo(a, 'stack4');
assertEquals('stack4', a.stack);

View File

@ -0,0 +1,21 @@
// Copyright 2022 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: --maglev --allow-natives-syntax
function f(x) {
return x;
}
%PrepareFunctionForOptimization(f);
// f(x) takes one argument but we are under-applying here
assertEquals(undefined, f());
// f(x) takes one argument but we are over-applying here
assertEquals(1, f(1, 2));
%OptimizeMaglevOnNextCall(f);
// f(x) takes one argument but we are under-applying here
assertEquals(undefined, f());
// f(x) takes one argument but we are over-applying here
assertEquals(1, f(1, 2));

View File

@ -0,0 +1,575 @@
// 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);
})();

View File

@ -0,0 +1,34 @@
// Copyright 2022 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 --maglev
let change_elements = false
function maybe_change_elements(a) {
if (change_elements) {
let old = a[1];
// Transition a to DOUBLE_ELEMENTS
a[1] = 0.5;
a[1] = old;
}
}
function foo(a, f) {
let sum = 0;
a.forEach(v=>{
sum += v;
maybe_change_elements(a);
})
return sum;
}
%NeverOptimizeFunction(maybe_change_elements);
%PrepareFunctionForOptimization(foo);
assertEquals(3, foo([0,1,2]));
assertEquals(3, foo([0,1,2]));
%OptimizeMaglevOnNextCall(foo);
assertEquals(3, foo([0,1,2]));
change_elements = true;
foo([0,1,2]);

View File

@ -0,0 +1,88 @@
// Copyright 2025 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 --maglev --no-always-turbofan
load('test/mjsunit/elements-kinds-helpers.js');
// Tests calling Array.prototype.map on a dictionary mode array invalidate the
// "array constructor" protector, so they must be in a separate file.
function plusOne(x) {
return x + 1;
}
%PrepareFunctionForOptimization(plusOne);
function plusOneInObject(x) {
return {a: x.a + 1};
}
%PrepareFunctionForOptimization(plusOneInObject);
(function testDictionaryElements1() {
function foo(a) {
return a.map(plusOne);
}
%PrepareFunctionForOptimization(foo);
const array = [1, 2, 3];
const array2 = [1, 2, 3];
MakeArrayDictionaryMode(array, () => { return 0; });
MakeArrayDictionaryMode(array2, () => { return 0; });
assertTrue(%HasDictionaryElements(array));
assertTrue(%HasDictionaryElements(array2));
const result = foo(array);
assertTrue(HasHoleySmiElements(result));
%OptimizeMaglevOnNextCall(foo);
const result2 = foo(array2);
assertTrue(HasHoleySmiElements(result2));
assertTrue(isMaglevved(foo));
})();
(function testDictionaryElements2() {
function foo(a) {
return a.map(plusOne);
}
%PrepareFunctionForOptimization(foo);
const array = [1, 2, 3];
const array2 = [1, 2, 3];
MakeArrayDictionaryMode(array, () => { return 0.1; });
MakeArrayDictionaryMode(array2, () => { return 0.1; });
assertTrue(%HasDictionaryElements(array));
assertTrue(%HasDictionaryElements(array2));
const result = foo(array);
assertTrue(HasHoleyDoubleElements(result));
%OptimizeMaglevOnNextCall(foo);
const result2 = foo(array2);
assertTrue(HasHoleyDoubleElements(result2));
assertTrue(isMaglevved(foo));
})();
(function testDictionaryElements3() {
function foo(a) {
return a.map(plusOneInObject);
}
%PrepareFunctionForOptimization(foo);
const array = [{a: 1}, {a: 2}, {a: 3}];
const array2 = [{a: 1}, {a: 2}, {a: 3}];
MakeArrayDictionaryMode(array, () => { return {a: 0}; });
MakeArrayDictionaryMode(array2, () => { return {a: 0}; });
assertTrue(%HasDictionaryElements(array));
const result = foo(array);
assertTrue(HasHoleyObjectElements(result));
%OptimizeMaglevOnNextCall(foo);
const result2 = foo(array2);
assertTrue(HasHoleyObjectElements(result2));
assertTrue(isMaglevved(foo));
})();

View File

@ -0,0 +1,504 @@
// Copyright 2025 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 --maglev --no-always-turbofan
// Flags: --no-optimize-maglev-optimizes-to-turbofan
load('test/mjsunit/elements-kinds-helpers.js');
function identity(x) {
return x;
}
%PrepareFunctionForOptimization(identity);
function plusOne(x) {
return x + 1;
}
%PrepareFunctionForOptimization(plusOne);
function plusOneAndMore(x) {
return x + 1.1;
}
%PrepareFunctionForOptimization(plusOneAndMore);
function plusOneInObject(x) {
return {a: x.a + 1};
}
%PrepareFunctionForOptimization(plusOneInObject);
function wrapInObject(x) {
return {a: x};
}
%PrepareFunctionForOptimization(wrapInObject);
function unwrapObject(x) {
return x.a;
}
%PrepareFunctionForOptimization(unwrapObject);
let ix = 0;
function transitionFromSmiToDouble(x) {
if (ix++ == 0) {
return 0;
}
return 1.1;
}
%PrepareFunctionForOptimization(transitionFromSmiToDouble);
function transitionFromSmiToObject(x) {
if (ix++ == 0) {
return 0;
}
return {a: 1};
}
%PrepareFunctionForOptimization(transitionFromSmiToObject);
function transitionFromDoubleToObject(x) {
if (ix++ == 0) {
return 1.1;
}
return {a: 1};
}
%PrepareFunctionForOptimization(transitionFromDoubleToObject);
function transitionFromObjectToDouble(x) {
if (ix++ == 0) {
return {a: 1};
}
return 1.1;
}
%PrepareFunctionForOptimization(transitionFromObjectToDouble);
function resetTransitionFunctions() {
ix = 0;
}
(function testPackedSmiElementsWithIdentity() {
function foo(a) {
return a.map(identity);
}
%PrepareFunctionForOptimization(foo);
const array = [1, 2, 3];
const result = foo(array);
assertTrue(HasPackedSmiElements(result));
%OptimizeMaglevOnNextCall(foo);
const array2 = [1, 2, 3];
const result2 = foo(array2);
assertTrue(HasPackedSmiElements(result2));
assertTrue(isMaglevved(foo));
})();
(function testPackedSmiElements() {
function foo(a) {
return a.map(plusOne);
}
%PrepareFunctionForOptimization(foo);
const array = [1, 2, 3];
const result = foo(array);
assertTrue(HasPackedSmiElements(result));
%OptimizeMaglevOnNextCall(foo);
const array2 = [1, 2, 3];
const result2 = foo(array2);
assertTrue(HasPackedSmiElements(result2));
assertTrue(isMaglevved(foo));
})();
(function testHoleySmiElements() {
function foo(a) {
return a.map(plusOne);
}
%PrepareFunctionForOptimization(foo);
const array = [1, 2, , 3];
const result = foo(array);
assertTrue(HasHoleySmiElements(result));
%OptimizeMaglevOnNextCall(foo);
const array2 = [1, 2, , 3];
const result2 = foo(array2);
assertTrue(HasHoleySmiElements(result2));
assertTrue(isMaglevved(foo));
})();
(function testPackedDoubleElements1() {
function foo(a) {
return a.map(plusOne);
}
%PrepareFunctionForOptimization(foo);
const array = [1, 2, 3.3];
const result = foo(array);
assertTrue(HasPackedDoubleElements(result));
%OptimizeMaglevOnNextCall(foo);
const array2 = [1, 2, 3.3];
const result2 = foo(array2);
assertTrue(HasPackedDoubleElements(result2));
assertTrue(isMaglevved(foo));
})();
(function testPackedDoubleElements2() {
function foo(a) {
return a.map(plusOneAndMore);
}
%PrepareFunctionForOptimization(foo);
const array = [1, 2, 3];
const result = foo(array);
assertTrue(HasPackedDoubleElements(result));
%OptimizeMaglevOnNextCall(foo);
const array2 = [1, 2, 3];
const result2 = foo(array2);
assertTrue(HasPackedDoubleElements(result2));
assertTrue(isMaglevved(foo));
})();
(function testHoleyDoubleElements1() {
function foo(a) {
return a.map(plusOne);
}
%PrepareFunctionForOptimization(foo);
const array = [1, 2, , 3.3];
const result = foo(array);
assertTrue(HasHoleyDoubleElements(result));
%OptimizeMaglevOnNextCall(foo);
const array2 = [1, 2, , 3.3];
const result2 = foo(array2);
assertTrue(HasHoleyDoubleElements(result2));
assertTrue(isMaglevved(foo));
})();
(function testHoleyDoubleElements2() {
function foo(a) {
return a.map(plusOneAndMore);
}
%PrepareFunctionForOptimization(foo);
const array = [1, 2, , 3];
const result = foo(array);
assertTrue(HasHoleyDoubleElements(result));
%OptimizeMaglevOnNextCall(foo);
const array2 = [1, 2, , 3];
const result2 = foo(array2);
assertTrue(HasHoleyDoubleElements(result2));
assertTrue(isMaglevved(foo));
})();
(function testPackedElements1() {
function foo(a) {
return a.map(plusOneInObject);
}
%PrepareFunctionForOptimization(foo);
const array = [{a: 1}, {a: 2}, {a: 3}];
const result = foo(array);
assertTrue(HasPackedObjectElements(result));
%OptimizeMaglevOnNextCall(foo);
const array2 = [{a: 1}, {a: 2}, {a: 3}];
const result2 = foo(array2);
assertTrue(HasPackedObjectElements(result2));
assertTrue(isMaglevved(foo));
})();
(function testPackedElements2() {
function foo(a) {
return a.map(wrapInObject);
}
%PrepareFunctionForOptimization(foo);
const array = [1, 2, 3];
const result = foo(array);
assertTrue(HasPackedObjectElements(result));
%OptimizeMaglevOnNextCall(foo);
const array2 = [1, 2, 3];
const result2 = foo(array2);
assertTrue(HasPackedObjectElements(result2));
assertTrue(isMaglevved(foo));
})();
(function testHoleyObjectElements1() {
function foo(a) {
return a.map(plusOneInObject);
}
%PrepareFunctionForOptimization(foo);
const array = [{a: 1}, {a: 2}, , {a: 3}];
const result = foo(array);
assertTrue(HasHoleyObjectElements(result));
%OptimizeMaglevOnNextCall(foo);
const array2 = [{a: 1}, {a: 2}, , {a: 3}];
const result2 = foo(array2);
assertTrue(HasHoleyObjectElements(result2));
assertTrue(isMaglevved(foo));
})();
(function testHoleyObjectElements2() {
function foo(a) {
return a.map(wrapInObject);
}
%PrepareFunctionForOptimization(foo);
const array = [1, 2, , 3];
const result = foo(array);
assertTrue(HasHoleyObjectElements(result));
%OptimizeMaglevOnNextCall(foo);
const array2 = [1, 2, , 3];
const result2 = foo(array2);
assertTrue(HasHoleyObjectElements(result2));
assertTrue(isMaglevved(foo));
})();
(function testFromObjectToPackedSmi() {
function foo(a) {
return a.map(unwrapObject);
}
%PrepareFunctionForOptimization(foo);
const array = [{a: 1}, {a: 2}, {a: 3}];
const array2 = [{a: 1}, {a: 2}, {a: 3}];
const result = foo(array);
assertTrue(HasPackedSmiElements(result));
%OptimizeMaglevOnNextCall(foo);
const result2 = foo(array2);
assertTrue(HasPackedSmiElements(result2));
assertTrue(isMaglevved(foo));
})();
(function testFromObjectToHoleySmi() {
function foo(a) {
return a.map(unwrapObject);
}
%PrepareFunctionForOptimization(foo);
const array = [{a: 1}, {a: 2}, , {a: 3}];
const array2 = [{a: 1}, {a: 2}, , {a: 3}];
const result = foo(array);
assertTrue(HasHoleySmiElements(result));
%OptimizeMaglevOnNextCall(foo);
const result2 = foo(array2);
assertTrue(HasHoleySmiElements(result2));
assertTrue(isMaglevved(foo));
})();
(function testTransitionFromPackedSmiToDoubleWhileMapping() {
resetTransitionFunctions();
function foo(a) {
return a.map(transitionFromSmiToDouble);
}
%PrepareFunctionForOptimization(foo);
const array = [0, 0, 0];
const array2 = [0, 0, 0];
const result = foo(array);
assertTrue(HasPackedDoubleElements(result));
%OptimizeMaglevOnNextCall(foo);
resetTransitionFunctions();
const result2 = foo(array2);
assertTrue(HasPackedDoubleElements(result2));
assertTrue(isMaglevved(foo));
})();
(function testTransitionFromHoleySmiToDoubleWhileMapping() {
resetTransitionFunctions();
function foo(a) {
return a.map(transitionFromSmiToDouble);
}
%PrepareFunctionForOptimization(foo);
const array = [0, 0, , 0];
const array2 = [0, 0, , 0];
const result = foo(array);
assertTrue(HasHoleyDoubleElements(result));
%OptimizeMaglevOnNextCall(foo);
resetTransitionFunctions();
const result2 = foo(array2);
assertTrue(HasHoleyDoubleElements(result2));
assertTrue(isMaglevved(foo));
})();
(function testTransitionFromPackedSmiToObjectWhileMapping() {
resetTransitionFunctions();
function foo(a) {
return a.map(transitionFromSmiToObject);
}
%PrepareFunctionForOptimization(foo);
const array = [0, 0, 0];
const array2 = [0, 0, 0];
const result = foo(array);
assertTrue(HasPackedObjectElements(result));
%OptimizeMaglevOnNextCall(foo);
resetTransitionFunctions();
const result2 = foo(array2);
assertTrue(HasPackedObjectElements(result2));
assertTrue(isMaglevved(foo));
})();
(function testTransitionFromHoleySmiToObjectWhileMapping() {
resetTransitionFunctions();
function foo(a) {
return a.map(transitionFromSmiToObject);
}
%PrepareFunctionForOptimization(foo);
const array = [0, 0, , 0];
const array2 = [0, 0, , 0];
const result = foo(array);
assertTrue(HasHoleyObjectElements(result));
%OptimizeMaglevOnNextCall(foo);
resetTransitionFunctions();
const result2 = foo(array2);
assertTrue(HasHoleyObjectElements(result2));
assertTrue(isMaglevved(foo));
})();
(function testTransitionFromPackedSmiToDoubleToObjectWhileMapping() {
resetTransitionFunctions();
function foo(a) {
return a.map(transitionFromDoubleToObject);
}
%PrepareFunctionForOptimization(foo);
const array = [0, 0, 0];
const array2 = [0, 0, 0];
const result = foo(array);
assertTrue(HasPackedObjectElements(result));
%OptimizeMaglevOnNextCall(foo);
resetTransitionFunctions();
const result2 = foo(array2);
assertTrue(HasPackedObjectElements(result2));
assertTrue(isMaglevved(foo));
})();
(function testTransitionFromHoleySmiToDoubleToObjectWhileMapping() {
resetTransitionFunctions();
function foo(a) {
return a.map(transitionFromDoubleToObject);
}
%PrepareFunctionForOptimization(foo);
const array = [0, 0, , 0];
const array2 = [0, 0, , 0];
const result = foo(array);
assertTrue(HasHoleyObjectElements(result));
%OptimizeMaglevOnNextCall(foo);
resetTransitionFunctions();
const result2 = foo(array2);
assertTrue(HasHoleyObjectElements(result2));
assertTrue(isMaglevved(foo));
})();
(function testTransitionFromPackedSmiToObjectToDoubleWhileMapping() {
resetTransitionFunctions();
function foo(a) {
return a.map(transitionFromObjectToDouble);
}
%PrepareFunctionForOptimization(foo);
const array = [0, 0, 0];
const array2 = [0, 0, 0];
const result = foo(array);
assertTrue(HasPackedObjectElements(result));
%OptimizeMaglevOnNextCall(foo);
resetTransitionFunctions();
const result2 = foo(array2);
assertTrue(HasPackedObjectElements(result2));
assertTrue(isMaglevved(foo));
})();
(function testTransitionFromHoleySmiToObjectToDoubleWhileMapping() {
resetTransitionFunctions();
function foo(a) {
return a.map(transitionFromObjectToDouble);
}
%PrepareFunctionForOptimization(foo);
const array = [0, 0, , 0];
const array2 = [0, 0, , 0];
const result = foo(array);
assertTrue(HasHoleyObjectElements(result));
%OptimizeMaglevOnNextCall(foo);
resetTransitionFunctions();
const result2 = foo(array2);
assertTrue(HasHoleyObjectElements(result2));
assertTrue(isMaglevved(foo));
})();
(function testMapperReducesLength() {
let array = [0, 1, 2];
function evil(x) {
if (x == 1) {
array.length = 1;
}
return x;
}
%PrepareFunctionForOptimization(evil);
function foo(a) {
return a.map(evil);
}
%PrepareFunctionForOptimization(foo);
const result = foo(array);
assertTrue(HasHoleySmiElements(result));
assertEquals(undefined, result[2]);
array = [0, 1, 2];
%OptimizeMaglevOnNextCall(foo);
const result2 = foo(array);
assertTrue(HasHoleySmiElements(result2));
assertEquals(undefined, result2[2]);
assertTrue(isMaglevved(foo));
})();

View File

@ -0,0 +1,26 @@
// 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 --maglev --no-always-turbofan
function f(a) {
a.push(4.5);
a.push({}); // Trying to push a non-double into a double array
}
%PrepareFunctionForOptimization(f);
const a1 = [1.2];
f(a1);
assertEquals(3, a1.length);
assertTrue(%HasPackedElements(a1));
%OptimizeMaglevOnNextCall(f);
const a2 = [1.2];
f(a2);
// Immediate deopt.
assertFalse(isMaglevved(f));
assertEquals(3, a2.length);
assertTrue(%HasPackedElements(a2));

View File

@ -0,0 +1,174 @@
// Copyright 2023 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: --maglev --allow-natives-syntax
///////////////////////////////////////////////////////////////
// Without Phis
function basic_int32(a) {
let c = a + 2;
if (c) {
return 42;
} else {
return 19;
}
}
%PrepareFunctionForOptimization(basic_int32);
assertEquals(19, basic_int32(-2));
assertEquals(42, basic_int32(3));
%OptimizeMaglevOnNextCall(basic_int32);
assertEquals(19, basic_int32(-2));
assertEquals(42, basic_int32(3));
function basic_float64(a) {
let c = a + 2.5;
if (c) {
return 1.6;
} else {
if (c == c) {
return 2.42;
} else {
return 3.11;
}
}
}
%PrepareFunctionForOptimization(basic_float64);
assertEquals(2.42, basic_float64(-2.5));
assertEquals(1.6, basic_float64(3.5));
assertEquals(3.11, basic_float64(NaN));
%OptimizeMaglevOnNextCall(basic_float64);
assertEquals(2.42, basic_float64(-2.5));
assertEquals(1.6, basic_float64(3.5));
assertEquals(3.11, basic_float64(NaN));
function basic_holey_float64(a) {
let c = a + 2.5;
if (c) {
return 1.6;
} else {
if (a == a) {
return 3.6 + a;
} else {
return 3.11;
}
}
}
%PrepareFunctionForOptimization(basic_holey_float64);
assertEquals(1.1, basic_holey_float64(-2.5));
assertEquals(1.6, basic_holey_float64(3.5));
assertEquals(3.11, basic_holey_float64(NaN));
assertEquals(NaN, basic_holey_float64([1.1, , 2.2][1]));
%OptimizeMaglevOnNextCall(basic_holey_float64);
assertEquals(1.1, basic_holey_float64(-2.5));
assertEquals(1.6, basic_holey_float64(3.5));
assertEquals(3.11, basic_holey_float64(NaN));
assertEquals(NaN, basic_holey_float64([1.1, , 2.2][1]));
///////////////////////////////////////////////////////////////
// With Phis as condition.
//
// When Phi untagging is enabled, the condition should start as
// BranchIfToBooleanTrue, and later be updated to BranchIfInt32ToBooleanTrue or
// BranchIfFloat64ToBooleanTrue.
function phi_int32(a) {
let phi = a ? 4 : 0;
if (phi) {
return phi + 5;
} else {
return phi + 3;
}
}
%PrepareFunctionForOptimization(phi_int32);
assertEquals(3, phi_int32(0));
assertEquals(9, phi_int32(1));
%OptimizeMaglevOnNextCall(phi_int32);
assertEquals(3, phi_int32(0));
assertEquals(9, phi_int32(1));
function phi_float64_no_nan(a) {
let phi = a ? 3.5 : 0;
if (phi) {
return phi + 1.6;
} else {
return phi + 2.5;
}
}
%PrepareFunctionForOptimization(phi_float64_no_nan);
assertEquals(2.5, phi_float64_no_nan(0));
assertEquals(5.1, phi_float64_no_nan(1));
%OptimizeMaglevOnNextCall(phi_float64_no_nan);
assertEquals(2.5, phi_float64_no_nan(0));
assertEquals(5.1, phi_float64_no_nan(1));
function phi_float64_nan(a, b) {
let nan = 0 / a;
let f64 = b + 0.5;
let phi = a ? f64 : nan;
if (phi) {
return phi + 4.5;
} else {
if (phi == phi) {
return phi + 2.1;
} else {
return 4.25;
}
}
}
%PrepareFunctionForOptimization(phi_float64_nan);
assertEquals(4.25, phi_float64_nan(0, 0.5));
assertEquals(2.1, phi_float64_nan(1, -0.5));
assertEquals(5.5, phi_float64_nan(1, 0.5));
%OptimizeMaglevOnNextCall(phi_float64_nan);
assertEquals(4.25, phi_float64_nan(0, 0.5));
assertEquals(2.1, phi_float64_nan(1, -0.5));
assertEquals(5.5, phi_float64_nan(1, 0.5));
let arr = [1.5, , NaN, 0.0];
function phi_float64_holey(a, arr) {
let holey_f64 = arr[a];
let phi = arr ? holey_f64 : 4;
if (phi) {
return phi + 1.7;
} else {
// We should get here for:
// a == 1 ==> the_hole
// a == 2 ==> NaN
// a == 3 ==> 0.0
// To distinguish between the 3 cases, we add a branch on "a".
if (a != 2) {
return phi + 2.1;
} else {
return 4.25;
}
}
}
%PrepareFunctionForOptimization(phi_float64_holey);
assertEquals(3.2, phi_float64_holey(0, arr));
// We don't load the_hole during feedback collection, as this would lead to
// megamorphic feedback.
// assertEquals(NaN, phi_float64_holey(1, arr));
assertEquals(4.25, phi_float64_holey(2, arr));
assertEquals(2.1, phi_float64_holey(3, arr));
%OptimizeMaglevOnNextCall(phi_float64_holey);
assertEquals(3.2, phi_float64_holey(0, arr));
assertEquals(NaN, phi_float64_holey(1, arr));
assertEquals(4.25, phi_float64_holey(2, arr));
assertEquals(2.1, phi_float64_holey(3, arr));

View File

@ -0,0 +1,17 @@
// Copyright 2025 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 --maglev --no-always-turbofan
function f(x) {
return!!(x * 2) && true;
}
%PrepareFunctionForOptimization(f);
assertFalse(f(0));
assertTrue(f(1.5));
%OptimizeMaglevOnNextCall(f);
assertFalse(f(0));
assertTrue(f(1.5));

View File

@ -0,0 +1,17 @@
// Copyright 2025 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 --maglev --no-always-turbofan
function f(x) {
return!!(x * 2) && true;
}
%PrepareFunctionForOptimization(f);
assertFalse(f(0));
assertTrue(f(1));
%OptimizeMaglevOnNextCall(f);
assertFalse(f(0));
assertTrue(f(1));

View File

@ -0,0 +1,21 @@
// Copyright 2022 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 --maglev --no-always-turbofan
function Bar(x) {
this.bar = x
}
function foo(x) {
return new Bar(...x, 1);
}
%PrepareFunctionForOptimization(foo);
assertEquals(1, foo([1]).bar);
assertEquals(2, foo([2]).bar);
%OptimizeMaglevOnNextCall(foo);
assertEquals(1, foo([1]).bar);
assertEquals(2, foo([2]).bar);
assertTrue(isMaglevved(foo));

View File

@ -0,0 +1,23 @@
// Copyright 2022 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 --maglev --no-always-turbofan
function bar(x){
return x
}
function foo(x) {
with(bar){
return bar(x);
}
}
%PrepareFunctionForOptimization(foo);
assertEquals(1, foo(1));
assertEquals(2, foo(2));
%OptimizeMaglevOnNextCall(foo);
assertEquals(1, foo(1));
assertEquals(2, foo(2));
assertTrue(isMaglevved(foo));

View File

@ -0,0 +1,28 @@
// Copyright 2023 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: --maglev --allow-natives-syntax --max-valid-polymorphic-map-count=100
// Test based on regress-crbug-1445286.js; this will generate a lot of maps
// which are passed to CheckMaps.
const floats = new Float64Array(10);
function f(proto) {
const o = {
__proto__: proto,
};
o.h = 1601;
o.name;
[v0, ...rest] = floats;
return o;
}
%PrepareFunctionForOptimization(f);
for (let i = 0; i < 100; ++i) {
%OptimizeMaglevOnNextCall(f);
f();
const o = f({});
o.h = v0;
}

View File

@ -0,0 +1,40 @@
// 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 --maglev --no-always-turbofan
class Vector {
constructor(x) {
this.x = x;
}
}
function magnitude(v) {
return v.x;
}
const zero = new Vector(0); // Map1
const anotherOldObject = new Vector(0); // Map1
%PrepareFunctionForOptimization(magnitude);
magnitude(zero);
const nonzero = new Vector(0.6); // Map2
// Map1 is now deprecated but Map2 is not a migration target.
%OptimizeMaglevOnNextCall(magnitude);
magnitude(zero);
// The first call immediately deopts
assertFalse(isMaglevved(magnitude));
// But we learn and don't deopt any more.
%OptimizeMaglevOnNextCall(magnitude);
magnitude(zero);
assertTrue(isMaglevved(magnitude));
// Also passing other old objects won't deopt.
magnitude(anotherOldObject);
assertTrue(isMaglevved(magnitude));

View File

@ -0,0 +1,31 @@
// 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 --maglev --no-always-turbofan --turbolev
class Vector {
constructor(x) {
this.x = x;
}
}
function magnitude(v) {
return v.x;
}
const zero = new Vector(0); // Map1
const anotherOldObject = new Vector(0); // Map1
%PrepareFunctionForOptimization(magnitude);
magnitude(zero);
const nonzero = new Vector(0.6); // Map2
// Map1 is now deprecated but Map2 is not a migration target.
%OptimizeMaglevOnNextCall(magnitude);
magnitude(nonzero);
// The first doesn't deopt if we pass a new object right away.
assertTrue(isMaglevved(magnitude));

View File

@ -0,0 +1,44 @@
// 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 --maglev --no-always-turbofan
class Vector {
constructor(x) {
this.x = x;
}
}
function magnitude(v) {
return v.x;
}
const zero = new Vector(0); // Map1
const anotherOldObject = new Vector(0); // Map1
%PrepareFunctionForOptimization(magnitude);
magnitude(zero);
// Make the feedback polymorphic with an unrelated map.
const unrelated = {a: 0, b: 0, c: 0, x: 0};
magnitude(unrelated);
const nonzero = new Vector(0.6); // Map2
// Map1 is now deprecated but Map2 is not a migration target.
%OptimizeMaglevOnNextCall(magnitude);
magnitude(zero);
// The first call immediately deopts
assertFalse(isMaglevved(magnitude));
// But we learn and don't deopt any more.
%OptimizeMaglevOnNextCall(magnitude);
magnitude(zero);
assertTrue(isMaglevved(magnitude));
// Also passing other old objects won't deopt.
magnitude(anotherOldObject);
assertTrue(isMaglevved(magnitude));

View File

@ -0,0 +1,35 @@
// 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 --maglev --no-always-turbofan
class Vector {
constructor(x) {
this.x = x;
}
}
function magnitude(v) {
return v.x;
}
const zero = new Vector(0); // Map1
const anotherOldObject = new Vector(0); // Map1
%PrepareFunctionForOptimization(magnitude);
magnitude(zero);
// Make the feedback polymorphic with an unrelated map.
const unrelated = {a: 0, b: 0, c: 0, x: 0};
magnitude(unrelated);
const nonzero = new Vector(0.6); // Map2
// Map1 is now deprecated but Map2 is not a migration target.
%OptimizeMaglevOnNextCall(magnitude);
magnitude(nonzero);
// The first call doesn't deopt if called with a new object.
assertTrue(isMaglevved(magnitude));

View File

@ -0,0 +1,41 @@
// 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 --maglev --no-always-turbofan
// Flags: --no-optimize-maglev-optimizes-to-turbofan
class Vector {
constructor(x) {
this.x = x;
}
}
function magnitude(v) {
return v.x;
}
%PrepareFunctionForOptimization(magnitude);
const oldObject = new Vector(0); // Map1
const anotherOldObject = new Vector(0); // Map1
const newObject = new Vector(0.6); // Map2
// Make Map2 a migration target.
oldObject.x = 0.3;
// Make `magnitude` polymorphic with Map2 (a migration target) and an unrelated
// map.
magnitude(newObject);
const unrelated = {a: 0, b: 0, c: 0, x: 0};
magnitude(unrelated);
%OptimizeMaglevOnNextCall(magnitude);
magnitude(newObject);
assertTrue(isMaglevved(magnitude));
// It should now migrate old objects.
magnitude(anotherOldObject);
assertTrue(isMaglevved(magnitude));

View File

@ -0,0 +1,36 @@
// Copyright 2022 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: --maglev --allow-natives-syntax
function foo(bar) {
return bar.func();
}
class Bar {
func() {}
}
Bar.prototype.__proto__ = new Proxy(Bar.prototype.__proto__, {
get() {;
return "42";
}
});
%PrepareFunctionForOptimization(foo);
foo(new Bar());
foo(new Bar());
%OptimizeMaglevOnNextCall(foo);
foo(new Bar());
function foo_primitive(s) {
return s.substring();
}
String.prototype.__proto__ = new Proxy(String.prototype.__proto__, {
get() {;
return "42";
}
});
%PrepareFunctionForOptimization(foo_primitive);
foo_primitive("");
foo_primitive("");
%OptimizeMaglevOnNextCall(foo_primitive);
foo_primitive("");

View File

@ -0,0 +1,58 @@
// 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() {
function foo() {
let o = {x : 1};
with(o) {
x = 2;
}
return o.x;
}
%PrepareFunctionForOptimization(foo);
assertEquals(foo(), 2);
assertEquals(foo(), 2);
%OptimizeFunctionOnNextCall(foo);
assertEquals(foo(), 2);
})();
(function() {
function foo(args) {
var result = 0;
for (var i = 0; i < args.length; ++i) {
result += args[i];
args[i] += i;
}
return result;
}
function bar(a, b, c, d) {
return [foo(arguments), a, b, c, d];
}
function run(i) {
var result = bar(i, i + 1, i + 2, i + 3);
if (result.length != 5)
throw "Bad result length in " + result;
if (result[0] != i * 4 + 6)
throw "Bad first element in " + result + "; expected " + (i * 3 + 6);
if (result[1] != i)
throw "Bad second element in " + result + "; expected " + i;
if (result[2] != i + 1 + 1)
throw "Bad third element in " + result + "; expected " + (i + 1 + 1);
if (result[3] != i + 2 + 2)
throw "Bad fourth element in " + result + "; expected " + (i + 2 + 2);
if (result[4] != i + 3 + 3)
throw "Bad fifth element in " + result + "; expected " + (i + 3 + 3);
}
%PrepareFunctionForOptimization(bar);
%PrepareFunctionForOptimization(foo);
run(0);
run(1);
%OptimizeFunctionOnNextCall(bar);
run(2);
})();

View File

@ -0,0 +1,29 @@
// Copyright 2023 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: --maglev --maglev-inlining --allow-natives-syntax
function hasInstance(x) {
%DeoptimizeFunction(bar);
return 5;
}
function Foo() {}
Object.defineProperty(Foo, Symbol.hasInstance, {
value: hasInstance
})
let foo = new Foo();
function bar(x) {
return x instanceof Foo;
}
%PrepareFunctionForOptimization(bar);
%PrepareFunctionForOptimization(hasInstance);
assertTrue(bar(foo));
assertTrue(bar(foo));
%OptimizeMaglevOnNextCall(bar);
assertTrue(bar(foo));

View File

@ -0,0 +1,17 @@
// Copyright 2022 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 --maglev --no-always-turbofan
function foo(x) {
const { a, b, ...rest } = {a:1, b:1, c:1, d:1};
return rest
}
%PrepareFunctionForOptimization(foo);
assertEquals({c:1, d:1}, foo());
assertEquals({c:1, d:1}, foo());
%OptimizeMaglevOnNextCall(foo);
assertEquals({c:1, d:1}, foo());
assertTrue(isMaglevved(foo));

View File

@ -0,0 +1,23 @@
// Copyright 2022 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 --maglev --maglev-inlining
function inner(o) {
"use strict"
return 10 + o.x + 100;
}
function foo(o) {
return 1000 + inner(o) + 10000;
}
%PrepareFunctionForOptimization(inner);
%PrepareFunctionForOptimization(foo);
assertEquals(11111, foo({x:1}));
assertEquals(11111, foo({x:1}));
%OptimizeMaglevOnNextCall(foo);
// The inlined inner function will deopt -- this deopt should succeed.
assertEquals(11111, foo({y:2,x:1}));

View File

@ -0,0 +1,52 @@
// 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 --maglev
function equals(a, b) {
if (a == b) {
return 1;
}
return 0;
}
%PrepareFunctionForOptimization(equals);
// Add the NumberOrBoolean feedback.
equals(0, true);
equals(true, 1);
%OptimizeMaglevOnNextCall(equals);
equals(0, true);
assertEquals(0, equals(true, 0));
assertEquals(1, equals(true, 1));
assertEquals(0, equals(true, 3.14));
assertEquals(1, equals(false, 0));
assertEquals(0, equals(false, 1));
assertEquals(0, equals(false, 2.72));
assertEquals(0, equals(0, true));
assertEquals(1, equals(1, true));
assertEquals(0, equals(1.41, true));
assertEquals(1, equals(0, false));
assertEquals(0, equals(1, false));
assertEquals(0, equals(1.62, false));
assertEquals(1, equals(true, true));
assertEquals(1, equals(false, false));
assertEquals(1, equals(3, 3));
assertEquals(0, equals(false, true));
assertEquals(0, equals(true, false));
assertEquals(0, equals(3, 4));
assertTrue(isMaglevved(equals));
// Passing a non-boolean oddball deopts.
assertEquals(0, equals(undefined, true));
assertFalse(isMaglevved(equals));

View File

@ -0,0 +1,34 @@
// 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 --maglev --maglev-escape-analysis
function soft_deopt() {}
function foo(b) {
var x;
if (!b) return 0;
// We call a function here that will create a soft deopt
// point and kill all nodes from this point on. This entails
// that the function context will have no use, so we can elide
// its allocation.
soft_deopt();
let bar = function() {
x = 42;
}
bar();
return x;
}
%PrepareFunctionForOptimization(foo);
assertEquals(0, foo(false));
%OptimizeMaglevOnNextCall(foo);
assertEquals(0, foo(false));
assertTrue(isOptimized(foo));
// This will deopt and the context will be materialized during
// deoptimization.
assertEquals(42, foo(true));
assertFalse(isOptimized(foo));

View File

@ -0,0 +1,25 @@
// 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 bar(o) {
o.x = o.x + 1;
}
function foo() {
let o = {x : 1};
for (let i = 0; i < 2; i++) {
bar(o);
}
return o.x;
}
%PrepareFunctionForOptimization(bar);
%PrepareFunctionForOptimization(foo);
assertEquals(foo(), 3);
assertEquals(foo(), 3);
%OptimizeFunctionOnNextCall(foo);
assertEquals(foo(), 3);
assertEquals(foo(), 3);

View File

@ -0,0 +1,82 @@
// Copyright 2022 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 --maglev
// This examples creates a simple exception handler block where the trampoline
// has an int32 value and needs to convert to a tagged value.
function foo_int32() {
let x = 1;
try {
x = x + x;
throw "Error";
} catch {
return x;
}
}
%PrepareFunctionForOptimization(foo_int32);
assertEquals(foo_int32(), 2);
%OptimizeMaglevOnNextCall(foo_int32);
assertEquals(foo_int32(), 2);
// TODO(leszeks): There is currently no way for this to happen, because all
// Int32 ops are eagerly checked for Smi overflow.
//
// // This examples creates a simple exception handler block where the trampoline
// // has an int32 value that overflows and it needs to create a HeapNumber.
// function foo_int32_overflow(x) {
// try {
// x = x + x;
// throw "Error";
// } catch {
// return x;
// }
// }
// %PrepareFunctionForOptimization(foo_int32_overflow);
// assertEquals(foo_int32_overflow(1), 2);
// %OptimizeMaglevOnNextCall(foo_int32_overflow);
// assertEquals(foo_int32_overflow(0x3FFFFFFF), 0x7FFFFFFE);
// assertTrue(%ActiveTierIsMaglev(foo_int32_overflow));
// // If we call it with a HeapNumber, we deopt before the exception:
// assertEquals(foo_int32_overflow(1.1), 2.2);
// assertTrue(%ActiveTierIsMaglev(foo_int32_overflow));
// This examples creates a simple exception handler block where the trampoline
// has an float64 value and needs to convert to a tagged value.
function foo_float64() {
let x = 1.1;
try {
x = x + x;
throw "Error";
} catch {
return x;
}
}
%PrepareFunctionForOptimization(foo_float64);
assertEquals(foo_float64(), 2.2);
%OptimizeMaglevOnNextCall(foo_float64);
assertEquals(foo_float64(), 2.2);
// Combination of previous examples with a big number of registers.
// This creates a _quite_ large trampoline.
function foo() {
let x = 1;
let y = 1.1;
let a, b, c, d, e, f, g, h;
a = b = c = d = e = f = g = h = 0;
let p, q, r, s, t;
try {
x = x + x;
y = y + y;
p = q = r = s = t = x;
throw "Error";
} catch {
return x + y + a + b + c + d + e + f + g + h
+ p + q + r + s + t;
}
}
%PrepareFunctionForOptimization(foo);
assertEquals(foo(), 14.2);
%OptimizeMaglevOnNextCall(foo);
assertEquals(foo(), 14.2);

View File

@ -0,0 +1,33 @@
// 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 --maglev
const s = new Set();
function foo(o) {
// One of these stores will exhaust the slack and we need to add a property
// backing store.
o.b1 = 0;
o.b2 = 0;
o.b3 = 0;
}
%PrepareFunctionForOptimization(foo);
let o1 = {a: 1}; // One in-object property.
// Make the StoreIC in `foo` polymorphic.
foo(o1);
foo({a: 0, b: 2});
%OptimizeMaglevOnNextCall(foo);
foo({a: 1, b: 3});
let o2 = {a: 1};
s.add(o2); // Force creating the hash.
foo(o2);
// Assert that the hash value was preseved when adding the properties backing
// store.
assertTrue(s.has(o2));

View File

@ -0,0 +1,43 @@
// 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 --maglev
function addProperties(o) {
// Add enough properties to exhaust the slack, so that adding the property
// in `foo` will need to grow the property backing store.
o.a1 = 1;
o.a2 = 2;
o.a3 = 3;
o.a4 = 4;
o.a5 = 5;
o.a6 = 6;
o.a7 = 7;
}
const s = new Set();
function foo(o) {
o.b = 2;
}
%PrepareFunctionForOptimization(foo);
let o1 = {};
addProperties(o1);
// Make the StoreIC in `foo` polymorphic.
foo(o1);
foo({a: 0, b: 2});
%OptimizeMaglevOnNextCall(foo);
foo({a: 1, b: 3});
let o2 = {};
addProperties(o2);
s.add(o2); // Force creating the hash.
foo(o2);
// Assert that the hash value was preseved when extending the properties
// backing store.
assertTrue(s.has(o2));

View File

@ -0,0 +1,39 @@
// 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
const {
getExtrasBindingObject,
getContinuationPreservedEmbedderDataViaAPIForTesting,
} = d8;
const {
getContinuationPreservedEmbedderData,
setContinuationPreservedEmbedderData,
} = getExtrasBindingObject();
function testOpt(v) {
setContinuationPreservedEmbedderData(v);
return getContinuationPreservedEmbedderData();
}
const runTestOpt = (v) => {
const data = testOpt(v);
assertEquals(data, v);
assertEquals(getContinuationPreservedEmbedderDataViaAPIForTesting(), v);
};
%PrepareFunctionForOptimization(testOpt);
runTestOpt(5);
runTestOpt(5.5);
runTestOpt({});
%OptimizeMaglevOnNextCall(testOpt);
runTestOpt(5);
runTestOpt(5.5);
runTestOpt({});
assertTrue(isMaglevved(testOpt));

View File

@ -0,0 +1,126 @@
// Copyright 2023 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 --maglev
function foo(...args) {
return {'this': this, 'arguments': args};
}
function validCalls(a, ...args) {
let obj = {};
// No receiver or receiver is null or undefined.
assertEquals({'this': this, 'arguments': []}, foo.apply());
assertEquals({'this': this, 'arguments': []}, foo.apply(null));
assertEquals({'this': this, 'arguments': []}, foo.apply(undefined));
// Receiver is object.
assertEquals({'this': obj, 'arguments': []}, foo.apply(obj));
// Valid arguments array.
assertEquals({'this': this, 'arguments': [3, 4]}, foo.apply(null, args));
assertEquals({'this': obj, 'arguments': [3, 4]}, foo.apply(obj, args));
assertEquals(
{'this': this, 'arguments': [2, 3, 4]}, foo.apply(null, [a, ...args]));
assertEquals(
{'this': obj, 'arguments': [2, 3, 4]}, foo.apply(obj, [a, ...args]));
// Extra arguments are ignored.
assertEquals({'this': this, 'arguments': [3, 4]}, foo.apply(null, args, a));
assertEquals({'this': obj, 'arguments': [3, 4]}, foo.apply(obj, args, a));
}
%PrepareFunctionForOptimization(validCalls);
validCalls(2, 3, 4);
validCalls(2, 3, 4);
%OptimizeMaglevOnNextCall(validCalls);
validCalls(2, 3, 4);
function invalidArgsArrayExplicitReceiver(a) {
return foo.apply(null, a);
}
%PrepareFunctionForOptimization(invalidArgsArrayExplicitReceiver);
assertThrows(
() => invalidArgsArrayExplicitReceiver(2, 3, 4), TypeError,
'CreateListFromArrayLike called on non-object');
assertThrows(
() => invalidArgsArrayExplicitReceiver(2, 3, 4), TypeError,
'CreateListFromArrayLike called on non-object');
assertEquals(
{'this': this, 'arguments': []},
invalidArgsArrayExplicitReceiver(null, null, null));
%OptimizeMaglevOnNextCall(invalidArgsArrayExplicitReceiver);
assertThrows(
() => invalidArgsArrayExplicitReceiver(2, 3, 4), TypeError,
'CreateListFromArrayLike called on non-object');
assertEquals(
{'this': this, 'arguments': []},
invalidArgsArrayExplicitReceiver(null, null, null));
function invalidArgsArrayImplicitReceiver(...args) {
return foo.apply(...args);
}
%PrepareFunctionForOptimization(invalidArgsArrayImplicitReceiver);
assertThrows(
() => invalidArgsArrayImplicitReceiver(2, 3, 4), TypeError,
'CreateListFromArrayLike called on non-object');
assertThrows(
() => invalidArgsArrayImplicitReceiver(2, 3, 4), TypeError,
'CreateListFromArrayLike called on non-object');
assertEquals(
{'this': this, 'arguments': []},
invalidArgsArrayImplicitReceiver(null, null, null));
%OptimizeMaglevOnNextCall(invalidArgsArrayImplicitReceiver);
assertThrows(
() => invalidArgsArrayImplicitReceiver(2, 3, 4), TypeError,
'CreateListFromArrayLike called on non-object');
assertEquals(
{'this': this, 'arguments': []},
invalidArgsArrayImplicitReceiver(null, null, null));
function invalidArgsArrayWithExtraSpread(a, ...args) {
return foo.apply(null, a, ...args);
}
%PrepareFunctionForOptimization(invalidArgsArrayWithExtraSpread);
assertThrows(
() => invalidArgsArrayWithExtraSpread(2, 3, 4), TypeError,
'CreateListFromArrayLike called on non-object');
assertThrows(
() => invalidArgsArrayWithExtraSpread(2, 3, 4), TypeError,
'CreateListFromArrayLike called on non-object');
assertEquals(
{'this': this, 'arguments': []},
invalidArgsArrayWithExtraSpread(null, null, null));
%OptimizeMaglevOnNextCall(invalidArgsArrayWithExtraSpread);
assertThrows(
() => invalidArgsArrayWithExtraSpread(2, 3, 4), TypeError,
'CreateListFromArrayLike called on non-object');
assertEquals(
{'this': this, 'arguments': []},
invalidArgsArrayWithExtraSpread(null, null, null));
function nullArgsArray(a, ...args) {
assertEquals({'this': this, 'arguments': []}, foo.apply(null, null));
}
%PrepareFunctionForOptimization(nullArgsArray);
nullArgsArray(2, 3, 4);
nullArgsArray(2, 3, 4);
nullArgsArray(null, null, null);
%OptimizeMaglevOnNextCall(nullArgsArray);
nullArgsArray(2, 3, 4);
nullArgsArray(null, null, null);
function nullArgsArrayWithExtraSpread(a, ...args) {
assertEquals({'this': this, 'arguments': []}, foo.apply(null, null, ...args));
}
%PrepareFunctionForOptimization(nullArgsArrayWithExtraSpread);
nullArgsArrayWithExtraSpread(2, 3, 4);
nullArgsArrayWithExtraSpread(2, 3, 4);
nullArgsArrayWithExtraSpread(null, null, null);
%OptimizeMaglevOnNextCall(nullArgsArrayWithExtraSpread);
nullArgsArrayWithExtraSpread(2, 3, 4);
nullArgsArrayWithExtraSpread(null, null, null);

View File

@ -0,0 +1,51 @@
// 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 --maglev
function test(obj) {
var funs = [function(x) {
// Force a map check on x.x
x.size;
// Will be constantfolded
return Object.getPrototypeOf(x);
}, function(x) {
x.size;
try {
return Reflect.getPrototypeOf(x);
} catch(e) {
return x.__proto__;
}
}, function(x) {
x.size;
return x.__proto__;
}];
funs.forEach((f) => {
%PrepareFunctionForOptimization(f);
f(obj);
%OptimizeMaglevOnNextCall(f);
assertTrue(f(obj) == Object.getPrototypeOf(obj));
assertTrue(f(obj) == obj.__proto__);
assertFalse(f(obj) == 1);
});
}
test({});
test({x:1});
test(1);
test(1.1);
test([]);
test("");
test(true);
var f = function(x) {
console.log(x);
return Object.getPrototypeOf(x);
};
%PrepareFunctionForOptimization(f);
try{f();} catch(e) {}
%OptimizeMaglevOnNextCall(f);
let thr = false;
try{f();} catch(e) {thr = true}
assertTrue(thr);

View File

@ -0,0 +1,20 @@
// Copyright 2022 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 --maglev --no-always-turbofan
function bar(x, y){
return [...x, y]
}
function foo(x) {
return bar`123${x}`
}
%PrepareFunctionForOptimization(foo);
assertEquals(["123", "", 1], foo(1));
assertEquals(["123", "", 2], foo(2));
%OptimizeMaglevOnNextCall(foo);
assertEquals(["123", "", 1], foo(1));
assertEquals(["123", "", 2], foo(2));
assertTrue(isMaglevved(foo));

View File

@ -0,0 +1,22 @@
// Copyright 2022 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 --maglev --maglev-inlining
function inlined(x) {
return x + x;
}
function foo(y) {
let a = inlined(1);
let b = inlined(y);
return a + b;
}
%PrepareFunctionForOptimization(foo);
%PrepareFunctionForOptimization(inlined);
assertEquals(6, foo(2));
%OptimizeMaglevOnNextCall(foo);
assertEquals(6, foo(2));
assertEquals(6.2, foo(2.1));

View File

@ -0,0 +1,31 @@
// Copyright 2022 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 --maglev --maglev-inlining
function inlined(x) {
if (x < 10) {
x;
} else {
x;
}
// At a merge point, we should not think that we are merging the
// caller function Phi node.
}
function foo(y) {
y < 10;
let a = 1;
let b = 2;
for (let i = 0; i < y; i++) {
inlined(i); // Phi (representing i) can leak to the inlined function.
}
}
%PrepareFunctionForOptimization(inlined);
%PrepareFunctionForOptimization(foo);
foo();
foo();
%OptimizeFunctionOnNextCall(foo);
foo();

View File

@ -0,0 +1,20 @@
// Copyright 2022 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 --maglev
function foo(x) {
var inner = function() {
return x;
}
return inner();
}
%PrepareFunctionForOptimization(foo);
assertEquals(1, foo(1));
assertEquals(2, foo(2));
%OptimizeMaglevOnNextCall(foo);
assertEquals(1, foo(1));
assertEquals(2, foo(2));
assertTrue(isMaglevved(foo));

View File

@ -0,0 +1,42 @@
// Copyright 2022 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 --maglev --no-always-turbofan
function foo(x,y) {
if (x < y) {
return 42;
}
return 24;
}
%PrepareFunctionForOptimization(foo);
assertEquals(42, foo(1,2));
assertEquals(24, foo(6,2));
%OptimizeMaglevOnNextCall(foo);
assertEquals(42, foo(1,2));
assertEquals(24, foo(6,2));
assertTrue(isMaglevved(foo));
assertEquals(42, foo(1.1, 2.2));
assertEquals(24, foo(6.6, 2.2));
assertUnoptimized(foo);
function bar(x,y) {
if (!(x >= y)) {
return 42;
}
return 24;
}
%PrepareFunctionForOptimization(bar);
assertEquals(42, bar(1,2));
assertEquals(24, bar(6,2));
%OptimizeMaglevOnNextCall(bar);
assertEquals(42, bar(1,2));
assertEquals(24, bar(6,2));
assertTrue(isMaglevved(bar));
assertEquals(42, bar(1.1, 2.2));
assertEquals(24, bar(6.6, 2.2));
assertUnoptimized(bar);

View File

@ -0,0 +1,20 @@
// Copyright 2022 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 --maglev
function f(b, n) {
let a;
if (b) {
a = 2;
} else {
a = n%n;
}
return a;
}
%PrepareFunctionForOptimization(f);
f(false, 2);
%OptimizeMaglevOnNextCall(f);
f(false, 2);

View File

@ -0,0 +1,34 @@
// Copyright 2022 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 --maglev --no-always-turbofan
var x = 1;
var do_change = {};
do_change = false;
function g() {
if (do_change) {
x = 2;
return 40;
}
return 30;
}
function f() {
return g() + x;
}
%PrepareFunctionForOptimization(f);
assertEquals(31, f());
%OptimizeMaglevOnNextCall(f);
assertEquals(31, f());
assertTrue(isMaglevved(f));
// Trigger a lazy deopt on the next g() call.
do_change = true;
assertEquals(42, f());
assertFalse(isMaglevved(f));
assertUnoptimized(f);

View File

@ -0,0 +1,24 @@
// Copyright 2022 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 --maglev --no-always-turbofan
var x = 1;
function f(o) {
return x;
}
%PrepareFunctionForOptimization(f);
assertEquals(1, f());
%OptimizeMaglevOnNextCall(f);
assertEquals(1, f());
assertTrue(isMaglevved(f));
// Trigger a lazy deopt now, so that f() deopts on its next call.
x = 2;
assertFalse(isMaglevved(f));
assertUnoptimized(f);
assertEquals(2, f());

View File

@ -0,0 +1,23 @@
// Copyright 2022 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 --maglev --no-always-turbofan
var b = 1;
function foo() {
return typeof(b)
}
%PrepareFunctionForOptimization(foo);
assertEquals("number", foo());
assertEquals("number", foo());
%OptimizeMaglevOnNextCall(foo);
assertEquals("number", foo());
assertEquals("number", foo());
assertTrue(isMaglevved(foo));
// We should deopt here.
b = 2
assertFalse(isMaglevved(foo))
assertEquals("number", foo());

View File

@ -0,0 +1,23 @@
// Copyright 2022 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 --maglev --no-always-turbofan
var b = 1;
function foo(x) {
return b + x
}
%PrepareFunctionForOptimization(foo);
assertEquals(2, foo(1));
assertEquals(3, foo(2));
%OptimizeMaglevOnNextCall(foo);
assertEquals(4, foo(3));
assertEquals(5, foo(4));
assertTrue(isMaglevved(foo));
// We should deopt here.
b = 2
assertFalse(isMaglevved(foo))
assertEquals(7, foo(5));

View File

@ -0,0 +1,8 @@
// Copyright 2022 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 --maglev --no-always-turbofan
const b = 1;
export {b};

View File

@ -0,0 +1,33 @@
// Copyright 2022 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 --maglev --no-always-turbofan
// Test LdaModuleVariable with imports.
import {b} from './lda-module-variable-import.mjs'
function bar(y) {
// b = 1.
return b + y;
};
%PrepareFunctionForOptimization(bar);
assertEquals(2, bar(1));
assertEquals(3, bar(2));
%OptimizeMaglevOnNextCall(bar);
assertEquals(2, bar(1));
assertEquals(3, bar(2));
assertTrue(isMaglevved(bar));
// Test LdaModuleVariable with exports.
export let x = 1;
function foo(y) { return x + y };
%PrepareFunctionForOptimization(foo);
assertEquals(2, foo(1));
assertEquals(3, foo(2));
%OptimizeMaglevOnNextCall(foo);
assertEquals(2, foo(1));
assertEquals(3, foo(2));
assertTrue(isMaglevved(foo));

49
deps/v8/test/mjsunit/maglev/literals.js vendored Normal file
View File

@ -0,0 +1,49 @@
// Copyright 2022 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 --maglev
// Empty array.
(function() {
function f() {
return [];
}
%PrepareFunctionForOptimization(f);
f();
%OptimizeMaglevOnNextCall(f);
assertEquals(0, f().length);
assertTrue(isMaglevved(f));
})();
// Calls builtin create shallow object.
(function() {
function f() {
return {a: 42, b: 24};
}
%PrepareFunctionForOptimization(f);
f();
f();
%OptimizeMaglevOnNextCall(f);
assertEquals(42, f().a);
assertTrue(isMaglevved(f));
})();
// Calls runtime create literal object.
(function() {
function f() {
return { out: { in: 42 } }
}
%PrepareFunctionForOptimization(f);
f();
f();
%OptimizeMaglevOnNextCall(f);
assertEquals(42, f().out.in);
assertTrue(isMaglevved(f));
})();

View File

@ -0,0 +1,59 @@
// Copyright 2022 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 --maglev
// Checks simple monomorphic load of a Smi field works
(function() {
function load(o) {
return o.smi;
}
%PrepareFunctionForOptimization(load);
assertEquals(42, load({smi:42}));
%OptimizeMaglevOnNextCall(load);
assertEquals(42, load({smi:42}));
assertTrue(isMaglevved(load));
// We should deopt here.
assertEquals(42, load({y:0, smi:42}));
assertFalse(isMaglevved(load));
})();
// Checks simple monomorphic load of a Double field works
(function() {
function load(o) {
return o.float64;
}
%PrepareFunctionForOptimization(load);
assertEquals(42.5, load({float64:42.5}));
%OptimizeMaglevOnNextCall(load);
assertEquals(42.5, load({float64:42.5}));
assertTrue(isMaglevved(load));
// We should deopt here.
assertEquals(42.5, load({y:0, float64:42.5}));
assertFalse(isMaglevved(load));
})();
// Checks simple monomorphic load of a Double field works with a float64 add.
(function() {
function load(o) {
return o.float64 + o.float64;
}
%PrepareFunctionForOptimization(load);
assertEquals(85, load({float64:42.5}));
%OptimizeMaglevOnNextCall(load);
assertEquals(85, load({float64:42.5}));
assertTrue(isMaglevved(load));
// We should deopt here.
assertEquals(85, load({y:0, float64:42.5}));
assertFalse(isMaglevved(load));
})();

View File

@ -0,0 +1,87 @@
// 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 --maglev --no-always-turbofan
// Flags: --script-context-mutable-heap-number
// Flags: --maglev-function-context-specialization
let x = 42;
(function() {
function foo() {
return x + 1;
}
// It should optimize load as constant.
%PrepareFunctionForOptimization(foo);
assertEquals(43, foo());
assertEquals(43, foo());
%OptimizeMaglevOnNextCall(foo);
assertEquals(43, foo());
assertOptimized(foo);
// Deopt.
x = 4;
assertUnoptimized(foo);
// Kill potential opt jobs
%DeoptimizeFunction(foo);
// It should optimize as Smi load.
assertEquals(5, foo());
%OptimizeMaglevOnNextCall(foo);
assertEquals(5, foo());
assertOptimized(foo);
// Deopt.
x = 4.2;
assertUnoptimized(foo);
%DeoptimizeFunction(foo);
// It should optimize as Double load.
assertEquals(5.2, foo());
%OptimizeMaglevOnNextCall(foo);
assertEquals(5.2, foo());
assertOptimized(foo);
// Deopt.
x = null;
assertUnoptimized(foo);
%DeoptimizeFunction(foo);
// It should optimize generically and not add any dependency.
assertEquals(1, foo());
%OptimizeMaglevOnNextCall(foo);
assertEquals(1, foo());
assertOptimized(foo);
// It shouldn't deopt.
x = {};
assertOptimized(foo);
})();
// Dynamic look up with eval.
let y = 0.5;
(function() {
function foo() {
eval("var y = 0");
return function bar() {
%PrepareFunctionForOptimization(bar);
%OptimizeMaglevOnNextCall(bar);
return y;
};
}
// Ensure that the slot transition to MutableHeapNumber.
y = 2.5;
%PrepareFunctionForOptimization(foo);
assertEquals(0, foo()());
assertEquals(0, foo()());
%OptimizeMaglevOnNextCall(foo);
assertEquals(0, foo()());
assertOptimized(foo);
// We should not deopt when transitioning to kOther.
y = undefined;
assertOptimized(foo);
})();

View File

@ -0,0 +1,46 @@
// 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 --maglev --no-always-turbofan
// Flags: --script-context-mutable-heap-number
// Flags: --no-maglev-function-context-specialization
let x = 42;
(function() {
function foo() {
return x + 1;
}
%PrepareFunctionForOptimization(foo);
assertEquals(43, foo());
assertEquals(43, foo());
%OptimizeMaglevOnNextCall(foo);
assertEquals(43, foo());
assertOptimized(foo);
// No deopt.
x = 4;
assertEquals(5, foo());
assertOptimized(foo);
// No deopt due to transition to MutableHeapNumber cell.
x = 4.2;
assertOptimized(foo);
// It will eargely deopt due to + feedback.
assertEquals(5.2, foo());
assertUnoptimized(foo);
// Optimize again.
%OptimizeMaglevOnNextCall(foo);
assertEquals(5.2, foo());
assertOptimized(foo);
// It should be allocating a new HeapNumber in every load.
assertEquals(5.2, foo());
// It shouldn't deopt.
x = {};
assertOptimized(foo);
})();

View File

@ -0,0 +1,68 @@
// Copyright 2023 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 --maglev
// This is a fairly complex tests that tries to combine the following things:
//
// - compile a function in a garbage-initialized zone (ie, a zone that isn't
// initialized with 0s).
//
// - have a loop phi whose input count get reduced (because the graph builder
// realizes that one of its predecessor is dead)
//
// - have this loop phi have a Phi as backedge.
//
// A bit of context: in an optimization for Phi untagging, I was iterating Phi
// inputs on RecordUseHint, but I didn't want to visit the backedge if it wasn't
// bound. To know if it was bound or not, I would set it to nullptr when
// creating the loop phi, and I could thus check if the last input was nullptr
// or not. However, this doesn't work when phi inputs get shrunk, as the last
// input (the backedge) could then contain garbage before it's bound (but this
// garbage wouldn't be nullptr, so it would look like a regular valid
// pointer). This didn't show any bug in mjsunit; but this test reproduces the
// error.
function f(a) {
let x = 2;
let i = 0;
if (a) {
x += 14;
} else {
%DeoptimizeNow();
if (a === 0) {
// The following addition has no feedback, which will cause Maglev to
// replace it with an unconditional deopt, thus removing one of the
// predecessors of the while-loop header.
x += 25;
}
}
// The following loop has a Phi for `x`, which initially is seen by the graph
// builder as having 3 predecessors. And its backedge is a Phi (that's
// important). One of its predecessor is removed during graph building because
// the `x += 25` is replaced by a Deopt.
while (i < 5) {
// We now have an Int32 use of `x`. It should be recorded as such, and
// should be propagated upwards in the Phi inputs of `x`. However, the
// backedge hasn't been bound yet, so we should skip it. Note that the
// backedge is at offset 1 rather than 2 because we've reduced the number
// of predecessors of `x`.
x ^ 2;
x = a ? i - 2 : 8;
i++;
}
}
%PrepareFunctionForOptimization(f);
f(1);
%OptimizeMaglevOnNextCall(f);
f(1);
// We now cause `f` to deopt so that it can be re-optimized, ideally using the
// same zone as before (which is thus not 0-initialized anymore but rather
// filled with old garbage in release mode, and filled with non-zero invalid
// pointers in debug mode (something like 0xcdcdcdcdcdcdcdcd).
f();
%OptimizeMaglevOnNextCall(f);
f(1);

View File

@ -0,0 +1,46 @@
// Copyright 2022 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 --maglev
function foo(
x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x,
x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x,
x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x,
x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x,
x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x,
x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x,
x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x,
x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x,
x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x,
x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x,
x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x,
x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x,
x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x,
x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x,
x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x,
x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x,
x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x,
x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x,
x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x,
x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x,
x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x,
x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x,
x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x,
x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x,
x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x,
x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x,
x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x,
x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x,
x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x,
x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x,
x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x,
x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x
) { }
%PrepareFunctionForOptimization(foo);
foo();
foo();
%OptimizeMaglevOnNextCall(foo);
foo();

View File

@ -0,0 +1,59 @@
// Copyright 2022 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 --maglev
function foo() {
var x0 = 0;
var x1 = 1;
var x2 = 2;
var x3 = 3;
var x4 = 4;
var x5 = 5;
var x6 = 6;
var x7 = 7;
var x8 = 8;
var x9 = 9;
var x10 = 10;
var x11 = 11;
var x12 = 12;
var x13 = 13;
var x14 = 14;
var x15 = 15;
var x16 = 16;
var x17 = 17;
var x18 = 18;
var x19 = 19;
var x20 = 20;
var x21 = 21;
var x22 = 22;
var x23 = 23;
var x24 = 24;
var x25 = 25;
var x26 = 26;
var x27 = 27;
var x28 = 28;
var x29 = 29;
var x30 = 30;
var x31 = 31;
var x32 = 32;
var x33 = 33;
var x34 = 34;
var x35 = 35;
var x36 = 36;
var x37 = 37;
var x38 = 38;
var x39 = 39;
return x0 + x1 + x2 + x3 + x4 + x5 + x6 + x7 + x8 + x9 +
x10 + x11 + x12 + x13 + x14 + x15 + x16 + x17 + x18 + x19 +
x20 + x21 + x22 + x23 + x24 + x25 + x26 + x27 + x28 + x29 +
x30 + x31 + x32 + x33 + x34 + x35 + x36 + x37 + x38 + x39;
}
%PrepareFunctionForOptimization(foo);
print(foo());
print(foo());
%OptimizeMaglevOnNextCall(foo);
print(foo());

View File

@ -0,0 +1,20 @@
// 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 --no-lazy-feedback-allocation
function foo() {
for (let v1 = 0; v1 < 5; v1++) {
const v3 = [1];
for (const v4 of v3) {
v3[2033] = 1;
}
}
}
%PrepareFunctionForOptimization(foo);
foo();
foo();
%OptimizeMaglevOnNextCall(foo);
foo();

View File

@ -0,0 +1,232 @@
// 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 --maglev-non-eager-inlining
// Flags: --max-maglev-inlined-bytecode-size-small=0
function bar() {
try { fail(); } catch(e) {}
}
%PrepareFunctionForOptimization(bar);
// Simple phi pointing to the call result
// at input index 2 (last).
(function() {
function foo(a) {
let p = 0;
if (a < 3) {
p = bar();
}
return p;
}
%PrepareFunctionForOptimization(foo);
foo(1);
%OptimizeMaglevOnNextCall(foo);
foo(1);
})();
// Simple phi pointing to a dead use
// at input index 2 (last).
(function() {
function foo(a) {
let p = 0;
if (a < 3) {
bar();
p = 2;
}
return p;
}
%PrepareFunctionForOptimization(foo);
foo(1);
%OptimizeMaglevOnNextCall(foo);
foo(1);
})();
// Phi pointing to the call result
// at input index 1.
(function() {
function foo(a) {
let p = 0;
if (a < 3) {
p = bar();
} else {
p = 2;
}
return p;
}
%PrepareFunctionForOptimization(foo);
foo(1);
%OptimizeMaglevOnNextCall(foo);
foo(1);
})();
// Phi pointing to a dead use
// at input index 1.
(function() {
function foo(a) {
let p = 0;
if (a < 3) {
bar();
p = 2;
} else {
p = 3;
}
return p;
}
%PrepareFunctionForOptimization(foo);
foo(1);
%OptimizeMaglevOnNextCall(foo);
foo(1);
})();
// Phi pointing to a dead use
// at input index 1 with nested blocks.
(function() {
function foo(a) {
let p = 0;
if (a < 3) {
bar();
if (a == 42) {
p = 1;
} else {
p = 2;
}
} else {
p = 3;
}
return p;
}
%PrepareFunctionForOptimization(foo);
foo(1);
%OptimizeMaglevOnNextCall(foo);
foo(1);
})();
// Loop phi pointing to the call result.
(function() {
function foo(a) {
let p = 0;
for (let i = 0; i < 5; i++) {
if (a < 3) {
p = bar();
}
}
return p;
}
%PrepareFunctionForOptimization(foo);
foo(1);
%OptimizeMaglevOnNextCall(foo);
foo(1);
})();
// Loop phi pointing to a dead use.
(function() {
function foo(a) {
let p = 0;
for (let i = 0; i < 5; i++) {
if (a < 3) {
bar();
p = i + 2;
}
}
return p;
}
%PrepareFunctionForOptimization(foo);
foo(1);
%OptimizeMaglevOnNextCall(foo);
foo(1);
})();
// Loop phi pointing to a call result
// with index 2
(function() {
function foo(a) {
let p = 0;
for (let i = 0; i < 5; i++) {
if (a < 3) {
p = bar();
} else {
p = 3;
}
}
return p;
}
%PrepareFunctionForOptimization(foo);
foo(1);
%OptimizeMaglevOnNextCall(foo);
foo(1);
})();
// 3-value Phi pointing to the call result
// at input index 1.
(function() {
function foo(a) {
let p = 0;
if (a < 3) {
p = bar()
} else if (a == 4) {
p = 2;
} else {
p = 3;
}
return p;
}
%PrepareFunctionForOptimization(foo);
// This makes sure that the call has a high call frequency.
for (let i = 0; i < 20; i++) {
foo(1);
}
foo(4);
%OptimizeMaglevOnNextCall(foo);
foo(1);
})();
// 3-value Phi pointing to the call result
// at input index 2.
(function() {
function foo(a) {
let p = 0;
if (a < 3) {
p = 1;
} else if (a == 4) {
p = bar();
} else {
p = 3;
}
return p;
}
%PrepareFunctionForOptimization(foo);
// This makes sure that the call has a high call frequency.
for (let i = 0; i < 20; i++) {
foo(4);
}
foo(1);
%OptimizeMaglevOnNextCall(foo);
foo(1);
})();
// 3-value Phi pointing to the call result
// at input index 3.
(function() {
function foo(a) {
let p = 0;
if (a < 3) {
p = 1;
} else if (a == 4) {
p = 2;
} else {
p = bar();
}
return p;
}
%PrepareFunctionForOptimization(foo);
// This makes sure that the call has a high call frequency.
for (let i = 0; i < 20; i++) {
foo(5);
}
foo(1);
%OptimizeMaglevOnNextCall(foo);
foo(1);
})();

View File

@ -0,0 +1,30 @@
// Copyright 2025 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 --no-maglev-loop-peeling
// Flags: --max-inlined-bytecode-size-small=0
function bar() {
try { fail(); } catch(e) {};
}
function foo(c) {
let v = 1;
if (c == 1) {
v = 2;
}
while (v < 10) {
v += 2;
bar();
}
return v;
}
%PrepareFunctionForOptimization(foo);
assertEquals(10, foo(1));
assertEquals(11, foo(2));
%PrepareFunctionForOptimization(bar);
%OptimizeMaglevOnNextCall(foo);
assertEquals(10, foo(1));
assertEquals(11, foo(2));

View File

@ -0,0 +1,23 @@
// Copyright 2023 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 --maglev
function f(o) {
return Math.ceil(o.a);
}
%PrepareFunctionForOptimization(f);
f({a: {valueOf(){ return 7.5; }}});
f({a: {valueOf(){ return 7.5; }}});
f({a: {valueOf(){ return 7.5; }}});
f({a: {valueOf(){ return 7.5; }}});
%OptimizeMaglevOnNextCall(f);
assertEquals(NaN, f({a:NaN}));
assertEquals(Infinity, f({a:Infinity}));
assertEquals(-Infinity, f({a:-Infinity}));
assertEquals(-Infinity, 1/f({a:-0.5}));
assertEquals(1, 1/f({a:0.5}));
assertEquals(8, f({a: {valueOf(){
%DeoptimizeFunction(f);
return 7.5; }}}));

View File

@ -0,0 +1,23 @@
// Copyright 2023 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 --maglev
function f(o) {
return Math.floor(o.a);
}
%PrepareFunctionForOptimization(f);
f({a: {valueOf(){ return 7.5; }}});
f({a: {valueOf(){ return 7.5; }}});
f({a: {valueOf(){ return 7.5; }}});
f({a: {valueOf(){ return 7.5; }}});
%OptimizeMaglevOnNextCall(f);
assertEquals(NaN, f({a:NaN}));
assertEquals(Infinity, f({a:Infinity}));
assertEquals(-Infinity, f({a:-Infinity}));
assertEquals(-1, 1/f({a:-0.5}));
assertEquals(Infinity, 1/f({a:0.5}));
assertEquals(7, f({a: {valueOf(){
%DeoptimizeFunction(f);
return 7.5; }}}));

View File

@ -0,0 +1,23 @@
// Copyright 2023 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 --maglev
function f(o) {
return Math.round(o.a);
}
%PrepareFunctionForOptimization(f);
f({a: {valueOf(){ return 7.5; }}});
f({a: {valueOf(){ return 7.5; }}});
f({a: {valueOf(){ return 7.5; }}});
f({a: {valueOf(){ return 7.5; }}});
%OptimizeMaglevOnNextCall(f);
assertEquals(NaN, f({a:NaN}));
assertEquals(Infinity, f({a:Infinity}));
assertEquals(-Infinity, f({a:-Infinity}));
assertEquals(-Infinity, 1/f({a:-0.5}));
assertEquals(1, 1/f({a:0.5}));
assertEquals(8, f({a: {valueOf(){
%DeoptimizeFunction(f);
return 7.5; }}}));

View File

@ -0,0 +1,94 @@
// Copyright 2022 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 --maglev
function factory() {
var x = 1;
x = 2;
return function foo() {
return x;
}
}
let foo = factory();
%PrepareFunctionForOptimization(foo);
assertEquals(2, foo());
assertEquals(2, foo());
%OptimizeMaglevOnNextCall(foo);
assertEquals(2, foo());
function nested_factory() {
var x = 1;
x = 2;
return (function() {
var z = 3;
return function foo(){
// Add two values from different contexts to force an
// LdaImmutableCurrentContextSlot
return x+z;
}
})();
}
foo = nested_factory();
%PrepareFunctionForOptimization(foo);
assertEquals(5, foo());
assertEquals(5, foo());
%OptimizeMaglevOnNextCall(foo);
assertEquals(5, foo());
function nested_factory_mutable() {
var x = 1;
x = 2;
return (function() {
var z = 3;
z = 4;
return function foo(){
// Add two values from different contexts to force an
// LdaImmutableCurrentContextSlot
return x+z;
}
})();
}
foo = nested_factory_mutable();
%PrepareFunctionForOptimization(foo);
assertEquals(6, foo());
assertEquals(6, foo());
%OptimizeMaglevOnNextCall(foo);
assertEquals(6, foo());
function nested_factory_immutable() {
var x = 1;
return (function() {
var z = 3;
z = 4;
return function foo(){
// Add two values from different contexts to force an
// LdaImmutableCurrentContextSlot
return x+z;
}
})();
}
foo = nested_factory_immutable();
%PrepareFunctionForOptimization(foo);
assertEquals(5, foo());
assertEquals(5, foo());
%OptimizeMaglevOnNextCall(foo);
assertEquals(5, foo());

79
deps/v8/test/mjsunit/maglev/negate.js vendored Normal file
View File

@ -0,0 +1,79 @@
// Copyright 2022 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 --maglev
function negate(val) {
return -val;
}
function test_negate_int32(value, expected) {
// Warmup.
%PrepareFunctionForOptimization(negate);
%ClearFunctionFeedback(negate);
negate(1, -1);
%OptimizeMaglevOnNextCall(negate);
assertEquals(expected, negate(value));
assertTrue(isMaglevved(negate));
%DeoptimizeFunction(negate);
assertEquals(expected, negate(value));
}
test_negate_int32(1, -1);
test_negate_int32(-1, 1);
test_negate_int32(42, -42);
test_negate_int32(-42, 42);
function test_negate_float(value, expected) {
// Warmup.
%PrepareFunctionForOptimization(negate);
%ClearFunctionFeedback(negate);
negate(1.1, -1.1);
%OptimizeMaglevOnNextCall(negate);
assertEquals(expected, negate(value));
assertTrue(isMaglevved(negate));
%DeoptimizeFunction(negate);
assertEquals(expected, negate(value));
}
test_negate_float(1.23, -1.23);
test_negate_float(-1.001, 1.001);
test_negate_float(42.42, -42.42);
test_negate_float(-42.42, 42.42);
const int32_max = Math.pow(2,30)-1;
const int32_min = -Math.pow(2,31);
test_negate_float(int32_max, -int32_max);
test_negate_float(int32_min, -int32_min);
function test_negate_int32_expect_deopt(value, expected) {
// Warmup.
%PrepareFunctionForOptimization(negate);
%ClearFunctionFeedback(negate);
negate(12, -12);
%OptimizeMaglevOnNextCall(negate);
assertEquals(expected, negate(value));
assertFalse(isMaglevved(negate));
}
// -0 is not an int32
test_negate_int32_expect_deopt(0, -0);
test_negate_int32_expect_deopt(-0, 0);
// -int32_min doesn't fit inside an int32
assertTrue(-int32_min > int32_max)
test_negate_int32_expect_deopt(int32_min, -int32_min);
test_negate_int32_expect_deopt(-int32_min, int32_min);
// -int32_max does fit inside an int32, but might not fit inside a Smi
assertTrue(-int32_max >= int32_min)
if (%IsSmi(-int32_max)) {
test_negate_int32(int32_max, -int32_max);
test_negate_int32(-int32_max, int32_max);
} else {
test_negate_int32_expect_deopt(int32_max, -int32_max);
test_negate_int32_expect_deopt(-int32_max, int32_max);
}

View File

@ -0,0 +1,35 @@
// Copyright 2023 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: --maglev --allow-natives-syntax
function Foo() {}
Object.defineProperty(Foo, Symbol.hasInstance, { value: Math.round });
let foo = new Foo();
function bar(f) {
// `f instanceof Foo` runs `%ToBoolean(Foo[Symbol.hasInstance](f))`, where
// `Foo[Symbol.hasInstance]` is `Math.round`.
//
// So with sufficient builtin inlining, this will call
// `%ToBoolean(round(%ToNumber(f)))`, which will call `f.valueOf`. If this
// deopts (which in this test it will), we need to make sure to both round it,
// and then convert that rounded value to a boolean.
return f instanceof Foo;
}
foo.valueOf = () => {
%DeoptimizeFunction(bar);
// Return a value which, when rounded, has ToBoolean false, and when not
// rounded, has ToBoolean true.
return 0.2;
}
%PrepareFunctionForOptimization(bar);
assertFalse(bar(foo));
assertFalse(bar(foo));
%OptimizeMaglevOnNextCall(bar);
assertFalse(bar(foo));

View File

@ -0,0 +1,41 @@
// 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: --maglev --allow-natives-syntax
// Flags: --no-optimize-maglev-optimizes-to-turbofan
// This object will later have a deprecated map.
let o1 = {y: 0, a: 1};
// These 2 objects will always have the same map. We use two
// of them to make sure we're not embedding the object itself
// as a constant.
let o2_1 = {y: 0, a: 1};
let o2_2 = {y: 0, a: 1};
// An unrelated object just to make the IC polymorphic.
let o3 = {x: 0, y: 0, a: 1};
// Make o1's map deprecated. o2_1 and o2_2 have the same map.
o2_1.a = 3.1415;
o2_2.a = 4.12;
function foo(o) {
o.y = 2; // Polymorpic property store.
}
%PrepareFunctionForOptimization(foo);
// Collect the feedback.
foo(o2_1);
foo(o2_2);
foo(o3); // Make it polymorphic.
%OptimizeMaglevOnNextCall(foo);
foo(o2_1);
assertTrue(isMaglevved(foo));
// Calling foo with a deprecated map should not deopt.
foo(o1);
assertTrue(isMaglevved(foo));

View File

@ -0,0 +1,738 @@
// Copyright 2022 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: --omit-default-ctors --allow-natives-syntax --maglev --no-maglev-inlining
(function OmitDefaultBaseCtor() {
class A {}; // default base ctor -> will be omitted
class B extends A {};
%PrepareFunctionForOptimization(B);
new B();
%OptimizeMaglevOnNextCall(B);
const o = new B();
assertSame(B.prototype, o.__proto__);
assertTrue(isMaglevved(B)); // No deopt.
})();
(function OmitDefaultDerivedCtor() {
class A { constructor() {} };
class B extends A {}; // default derived ctor -> will be omitted
class C extends B {};
%PrepareFunctionForOptimization(C);
new C();
%OptimizeMaglevOnNextCall(C);
const o = new C();
assertSame(C.prototype, o.__proto__);
assertTrue(isMaglevved(C)); // No deopt.
})();
(function OmitDefaultBaseAndDerivedCtor() {
class A {}; // default base ctor -> will be omitted
class B extends A {}; // default derived ctor -> will be omitted
class C extends B {};
%PrepareFunctionForOptimization(C);
new C();
%OptimizeMaglevOnNextCall(C);
const o = new C();
assertSame(C.prototype, o.__proto__);
assertTrue(isMaglevved(C)); // No deopt.
})();
(function OmitDefaultBaseCtorWithExplicitSuper() {
class A {}; // default base ctor -> will be omitted
class B extends A { constructor() { super(); } };
%PrepareFunctionForOptimization(B);
new B();
%OptimizeMaglevOnNextCall(B);
const o = new B();
assertSame(B.prototype, o.__proto__);
assertTrue(isMaglevved(B)); // No deopt.
})();
(function OmitDefaultDerivedCtorWithExplicitSuper() {
class A { constructor() {} };
class B extends A {}; // default derived ctor -> will be omitted
class C extends B { constructor() { super(); } };
%PrepareFunctionForOptimization(C);
new C();
%OptimizeMaglevOnNextCall(C);
const o = new C();
assertSame(C.prototype, o.__proto__);
assertTrue(isMaglevved(C)); // No deopt.
})();
(function OmitDefaultBaseAndDerivedCtorWithExplicitSuper() {
class A {}; // default base ctor -> will be omitted
class B extends A {}; // default derived ctor -> will be omitted
class C extends B { constructor() { super(); } };
%PrepareFunctionForOptimization(C);
new C();
%OptimizeMaglevOnNextCall(C);
const o = new C();
assertSame(C.prototype, o.__proto__);
assertTrue(isMaglevved(C)); // No deopt.
})();
(function OmitDefaultBaseCtorWithExplicitSuperAndNonFinalSpread() {
class A {}; // default base ctor -> will be omitted
class B extends A { constructor(...args) { super(1, ...args, 2); } };
%PrepareFunctionForOptimization(B);
new B();
%OptimizeMaglevOnNextCall(B);
const o = new B(3, 4);
assertSame(B.prototype, o.__proto__);
// See https://bugs.chromium.org/p/v8/issues/detail?id=13337
// assertTrue(isMaglevved(B)); // No deopt.
// This assert will fail when the above bug is fixed:
assertFalse(isMaglevved(B));
})();
(function OmitDefaultDerivedCtorWithExplicitSuperAndNonFinalSpread() {
class A { constructor() {} };
class B extends A {}; // default derived ctor -> will be omitted
class C extends B { constructor(...args) { super(1, ...args, 2); } };
%PrepareFunctionForOptimization(C);
new C();
%OptimizeMaglevOnNextCall(C);
const o = new C(3, 4);
assertSame(C.prototype, o.__proto__);
// See https://bugs.chromium.org/p/v8/issues/detail?id=13337
// assertTrue(isMaglevved(C)); // No deopt.
// This assert will fail when the above bug is fixed:
assertFalse(isMaglevved(C));
})();
(function OmitDefaultBaseAndDerivedCtorWithExplicitSuperAndNonFinalSpread() {
class A {}; // default base ctor -> will be omitted
class B extends A {}; // default derived ctor -> will be omitted
class C extends B { constructor(...args) { super(1, ...args, 2); } };
%PrepareFunctionForOptimization(C);
new C();
%OptimizeMaglevOnNextCall(C);
const o = new C(3, 4);
assertSame(C.prototype, o.__proto__);
// See https://bugs.chromium.org/p/v8/issues/detail?id=13337
// assertTrue(isMaglevved(C)); // No deopt.
// This assert will fail when the above bug is fixed:
assertFalse(isMaglevved(C));
})();
(function NonDefaultBaseConstructorCalled() {
let ctorCallCount = 0;
let lastArgs;
class Base {
constructor(...args) {
++ctorCallCount;
this.baseTagged = true;
lastArgs = args;
}
};
// Nothing will be omitted.
class A extends Base {};
%PrepareFunctionForOptimization(A);
new A();
%OptimizeMaglevOnNextCall(A);
const a = new A(1, 2, 3);
assertEquals(2, ctorCallCount);
assertEquals([1, 2, 3], lastArgs);
assertTrue(a.baseTagged);
assertTrue(isMaglevved(A)); // No deopt.
// 'A' default ctor will be omitted.
class B1 extends A {};
%PrepareFunctionForOptimization(B1);
new B1();
%OptimizeMaglevOnNextCall(B1);
const b1 = new B1(4, 5, 6);
assertEquals(4, ctorCallCount);
assertEquals([4, 5, 6], lastArgs);
assertTrue(b1.baseTagged);
assertTrue(isMaglevved(B1)); // No deopt.
// The same test with non-final spread; 'A' default ctor will be omitted.
class B2 extends A {
constructor(...args) { super(1, ...args, 2); }
};
%PrepareFunctionForOptimization(B2);
new B2();
%OptimizeMaglevOnNextCall(B2);
const b2 = new B2(4, 5, 6);
assertEquals(6, ctorCallCount);
assertEquals([1, 4, 5, 6, 2], lastArgs);
assertTrue(b2.baseTagged);
// See https://bugs.chromium.org/p/v8/issues/detail?id=13337
// assertTrue(isMaglevved(B2)); // No deopt.
// This assert will fail when the above bug is fixed:
assertFalse(isMaglevved(B2)); // No deopt.
})();
(function NonDefaultDerivedConstructorCalled() {
let ctorCallCount = 0;
let lastArgs;
class Base {};
class Derived extends Base {
constructor(...args) {
super();
++ctorCallCount;
this.derivedTagged = true;
lastArgs = args;
}
};
// Nothing will be omitted.
class A extends Derived {};
%PrepareFunctionForOptimization(A);
new A();
%OptimizeMaglevOnNextCall(A);
const a = new A(1, 2, 3);
assertEquals(2, ctorCallCount);
assertEquals([1, 2, 3], lastArgs);
assertTrue(a.derivedTagged);
assertTrue(isMaglevved(A)); // No deopt.
// 'A' default ctor will be omitted.
class B1 extends A {};
%PrepareFunctionForOptimization(B1);
new B1();
%OptimizeMaglevOnNextCall(B1);
const b1 = new B1(4, 5, 6);
assertEquals(4, ctorCallCount);
assertEquals([4, 5, 6], lastArgs);
assertTrue(b1.derivedTagged);
assertTrue(isMaglevved(B1)); // No deopt.
// The same test with non-final spread. 'A' default ctor will be omitted.
class B2 extends A {
constructor(...args) { super(1, ...args, 2); }
};
%PrepareFunctionForOptimization(B2);
new B2();
%OptimizeMaglevOnNextCall(B2);
const b2 = new B2(4, 5, 6);
assertEquals(6, ctorCallCount);
assertEquals([1, 4, 5, 6, 2], lastArgs);
assertTrue(b2.derivedTagged);
// See https://bugs.chromium.org/p/v8/issues/detail?id=13337
// assertTrue(isMaglevved(B2)); // No deopt.
// This assert will fail when the above bug is fixed:
assertFalse(isMaglevved(B2)); // No deopt.
})();
(function BaseFunctionCalled() {
let baseFunctionCallCount = 0;
function BaseFunction() {
++baseFunctionCallCount;
this.baseTagged = true;
}
class A1 extends BaseFunction {};
%PrepareFunctionForOptimization(A1);
new A1();
%OptimizeMaglevOnNextCall(A1);
const a1 = new A1();
assertEquals(2, baseFunctionCallCount);
assertTrue(a1.baseTagged);
assertTrue(isMaglevved(A1)); // No deopt.
class A2 extends BaseFunction {
constructor(...args) { super(1, ...args, 2); }
};
%PrepareFunctionForOptimization(A2);
new A2();
%OptimizeMaglevOnNextCall(A2);
const a2 = new A2();
assertEquals(4, baseFunctionCallCount);
assertTrue(a2.baseTagged);
assertTrue(isMaglevved(A2)); // No deopt.
})();
(function NonSuperclassCtor() {
class A {};
class B extends A {};
class C extends B {};
class D1 extends C {};
class D2 extends C { constructor(...args) { super(1, ...args, 2); }};
%PrepareFunctionForOptimization(C);
%PrepareFunctionForOptimization(D1);
%PrepareFunctionForOptimization(D2);
new C();
new D1();
new D2();
%OptimizeMaglevOnNextCall(C);
%OptimizeMaglevOnNextCall(D1);
%OptimizeMaglevOnNextCall(D2);
// Install an object which is not a constructor into the class hierarchy.
C.__proto__ = {};
assertThrows(() => { new C(); }, TypeError);
assertThrows(() => { new D1(); }, TypeError);
assertThrows(() => { new D2(); }, TypeError);
})();
(function ArgumentsEvaluatedBeforeNonSuperclassCtorDetected() {
class A {};
class B extends A {};
class C extends B {};
class D1 extends C {};
class D2 extends C { constructor(...args) { super(1, ...args, 2); }};
%PrepareFunctionForOptimization(C);
%PrepareFunctionForOptimization(D1);
%PrepareFunctionForOptimization(D2);
new C();
new D1();
new D2();
%OptimizeMaglevOnNextCall(C);
%OptimizeMaglevOnNextCall(D1);
%OptimizeMaglevOnNextCall(D2);
// Install an object which is not a constructor into the class hierarchy.
C.__proto__ = {};
let callCount = 0;
function foo() {
++callCount;
}
assertThrows(() => { new C(foo()); }, TypeError);
assertEquals(1, callCount);
assertThrows(() => { new D1(foo()); }, TypeError);
assertEquals(2, callCount);
assertThrows(() => { new D2(foo()); }, TypeError);
assertEquals(3, callCount);
})();
(function ArgumentsEvaluatedBeforeNonSuperclassCtorDetected2() {
class A {};
class B extends A {};
class C extends B {};
class D1 extends C {
constructor() {
super(foo());
}
};
class D2 extends C {
constructor(...args) {
super(...args, foo());
}
};
let callCount = 0;
function foo() {
++callCount;
}
%PrepareFunctionForOptimization(D1);
%PrepareFunctionForOptimization(D2);
new D1();
new D2();
%OptimizeMaglevOnNextCall(D1);
%OptimizeMaglevOnNextCall(D2);
assertEquals(2, callCount);
// Install an object which is not a constructor into the class hierarchy.
C.__proto__ = {};
assertThrows(() => { new D1(); }, TypeError);
assertEquals(3, callCount);
assertThrows(() => { new D2(); }, TypeError);
assertEquals(4, callCount);
})();
(function EvaluatingArgumentsChangesClassHierarchy() {
let ctorCallCount = 0;
class A {};
class B extends A { constructor() {
super();
++ctorCallCount;
}};
class C extends B {};
class D extends C {
constructor() {
super(foo());
}
};
let fooCallCount = 0;
let changeHierarchy = false;
function foo() {
if (changeHierarchy) {
C.__proto__ = A;
C.prototype.__proto__ = A.prototype;
}
++fooCallCount;
}
%PrepareFunctionForOptimization(D);
new D();
assertEquals(1, fooCallCount);
assertEquals(1, ctorCallCount);
%OptimizeMaglevOnNextCall(D);
changeHierarchy = true;
new D();
assertEquals(2, fooCallCount);
assertEquals(1, ctorCallCount);
assertFalse(isMaglevved(D));
})();
// The same test as the previous one, but with a ctor with a non-final spread.
(function EvaluatingArgumentsChangesClassHierarchyThisTimeWithNonFinalSpread() {
let ctorCallCount = 0;
class A {};
class B extends A { constructor() {
super();
++ctorCallCount;
}};
class C extends B {};
class D extends C {
constructor(...args) {
super(...args, foo());
}
};
let fooCallCount = 0;
let changeHierarchy = false;
function foo() {
if (changeHierarchy) {
C.__proto__ = A;
C.prototype.__proto__ = A.prototype;
}
++fooCallCount;
}
%PrepareFunctionForOptimization(D);
new D();
assertEquals(1, fooCallCount);
assertEquals(1, ctorCallCount);
%OptimizeMaglevOnNextCall(D);
changeHierarchy = true;
new D();
assertEquals(2, fooCallCount);
assertEquals(1, ctorCallCount);
assertFalse(isMaglevved(D));
})();
(function BasePrivateField() {
class A {
#aBrand = true;
isA() {
return #aBrand in this;
}
};
class B extends A {};
class C1 extends B {};
class C2 extends B { constructor(...args) { super(1, ...args, 2); }};
%PrepareFunctionForOptimization(B);
new B();
%OptimizeMaglevOnNextCall(B);
const b = new B();
assertTrue(b.isA());
assertTrue(isMaglevved(B)); // No deopt.
%PrepareFunctionForOptimization(C1);
new C1();
%OptimizeMaglevOnNextCall(C1);
const c1 = new C1();
assertTrue(c1.isA());
assertTrue(isMaglevved(C1)); // No deopt.
%PrepareFunctionForOptimization(C2);
new C2();
%OptimizeMaglevOnNextCall(C2);
const c2 = new C2();
assertTrue(c2.isA());
assertTrue(isMaglevved(C2)); // No deopt.
})();
(function DerivedPrivateField() {
class A {};
class B extends A {
#bBrand = true;
isB() {
return #bBrand in this;
}
};
class C1 extends B {};
class C2 extends B { constructor(...args) { super(1, ...args, 2); }};
%PrepareFunctionForOptimization(C1);
new C1();
%OptimizeMaglevOnNextCall(C1);
const c1 = new C1();
assertTrue(c1.isB());
assertTrue(isMaglevved(C1)); // No deopt.
%PrepareFunctionForOptimization(C2);
new C2();
%OptimizeMaglevOnNextCall(C2);
const c2 = new C2();
assertTrue(c2.isB());
assertTrue(isMaglevved(C2)); // No deopt.
})();
(function BasePrivateMethod() {
class A {
#m() { return 'private'; }
callPrivate() {
return this.#m();
}
};
class B extends A {};
class C1 extends B {};
class C2 extends B { constructor(...args) { super(1, ...args, 2); }};
%PrepareFunctionForOptimization(B);
new B();
%OptimizeMaglevOnNextCall(B);
const b = new B();
assertEquals('private', b.callPrivate());
assertTrue(isMaglevved(B)); // No deopt.
%PrepareFunctionForOptimization(C1);
new C1();
%OptimizeMaglevOnNextCall(C1);
const c1 = new C1();
assertEquals('private', c1.callPrivate());
assertTrue(isMaglevved(C1)); // No deopt.
%PrepareFunctionForOptimization(C2);
new C2();
%OptimizeMaglevOnNextCall(C2);
const c2 = new C2();
assertEquals('private', c2.callPrivate());
assertTrue(isMaglevved(C2)); // No deopt.
})();
(function DerivedPrivateMethod() {
class A {};
class B extends A {
#m() { return 'private'; }
callPrivate() {
return this.#m();
}
};
class C1 extends B {};
class C2 extends B { constructor(...args) { super(1, ...args, 2); }};
%PrepareFunctionForOptimization(C1);
new C1();
%OptimizeMaglevOnNextCall(C1);
const c1 = new C1();
assertEquals('private', c1.callPrivate());
assertTrue(isMaglevved(C1)); // No deopt.
%PrepareFunctionForOptimization(C2);
new C2();
%OptimizeMaglevOnNextCall(C2);
const c2 = new C2();
assertEquals('private', c2.callPrivate());
assertTrue(isMaglevved(C2)); // No deopt.
})();
(function BasePrivateGetter() {
class A {
get #p() { return 'private'; }
getPrivate() {
return this.#p;
}
};
class B extends A {};
class C1 extends B {};
class C2 extends B { constructor(...args) { super(1, ...args, 2); }};
%PrepareFunctionForOptimization(B);
new B();
%OptimizeMaglevOnNextCall(B);
const b = new B();
assertEquals('private', b.getPrivate());
assertTrue(isMaglevved(B)); // No deopt.
%PrepareFunctionForOptimization(C1);
new C1();
%OptimizeMaglevOnNextCall(C1);
const c1 = new C1();
assertEquals('private', c1.getPrivate());
assertTrue(isMaglevved(C1)); // No deopt.
%PrepareFunctionForOptimization(C2);
new C2();
%OptimizeMaglevOnNextCall(C2);
const c2 = new C2();
assertEquals('private', c2.getPrivate());
assertTrue(isMaglevved(C2)); // No deopt.
})();
(function DerivedPrivateGetter() {
class A {};
class B extends A {
get #p() { return 'private'; }
getPrivate() {
return this.#p;
}
};
class C1 extends B {};
class C2 extends B { constructor(...args) { super(1, ...args, 2); }};
%PrepareFunctionForOptimization(C1);
new C1();
%OptimizeMaglevOnNextCall(C1);
const c1 = new C1();
assertEquals('private', c1.getPrivate());
assertTrue(isMaglevved(C1)); // No deopt.
%PrepareFunctionForOptimization(C2);
new C2();
%OptimizeMaglevOnNextCall(C2);
const c2 = new C2();
assertEquals('private', c2.getPrivate());
assertTrue(isMaglevved(C2)); // No deopt.
})();
(function BasePrivateSetter() {
class A {
set #p(value) { this.secret = value; }
setPrivate() {
this.#p = 'private';
}
};
class B extends A {};
class C1 extends B {};
class C2 extends B { constructor(...args) { super(1, ...args, 2); }};
%PrepareFunctionForOptimization(B);
new B();
%OptimizeMaglevOnNextCall(B);
const b = new B();
b.setPrivate();
assertEquals('private', b.secret);
%PrepareFunctionForOptimization(C1);
new C1();
%OptimizeMaglevOnNextCall(C1);
const c1 = new C1();
c1.setPrivate();
assertEquals('private', c1.secret);
assertTrue(isMaglevved(C1)); // No deopt.
%PrepareFunctionForOptimization(C2);
new C2();
%OptimizeMaglevOnNextCall(C2);
const c2 = new C2();
c2.setPrivate();
assertEquals('private', c2.secret);
assertTrue(isMaglevved(C2)); // No deopt.
})();
(function DerivedPrivateSetter() {
class A {};
class B extends A {
set #p(value) { this.secret = value; }
setPrivate() {
this.#p = 'private';
}
};
class C1 extends B {};
class C2 extends B { constructor(...args) { super(1, ...args, 2); }};
%PrepareFunctionForOptimization(C1);
new C1();
%OptimizeMaglevOnNextCall(C1);
const c1 = new C1();
c1.setPrivate();
assertEquals('private', c1.secret);
assertTrue(isMaglevved(C1)); // No deopt.
%PrepareFunctionForOptimization(C2);
new C2();
%OptimizeMaglevOnNextCall(C2);
const c2 = new C2();
c2.setPrivate();
assertEquals('private', c2.secret);
assertTrue(isMaglevved(C2)); // No deopt.
})();
(function BaseClassFields() {
class A {
aField = true;
};
class B extends A {};
class C1 extends B {};
class C2 extends B { constructor(...args) { super(1, ...args, 2); }};
%PrepareFunctionForOptimization(B);
new B();
%OptimizeMaglevOnNextCall(B);
const b = new B();
assertTrue(b.aField);
%PrepareFunctionForOptimization(C1);
new C1();
%OptimizeMaglevOnNextCall(C1);
const c1 = new C1();
assertTrue(c1.aField);
assertTrue(isMaglevved(C1)); // No deopt.
%PrepareFunctionForOptimization(C2);
new C2();
%OptimizeMaglevOnNextCall(C2);
const c2 = new C2();
assertTrue(c2.aField);
assertTrue(isMaglevved(C2)); // No deopt.
})();
(function DerivedClassFields() {
class A {};
class B extends A {
bField = true;
};
class C1 extends B {};
class C2 extends B { constructor(...args) { super(1, ...args, 2); }};
%PrepareFunctionForOptimization(C1);
new C1();
%OptimizeMaglevOnNextCall(C1);
const c1 = new C1();
assertTrue(c1.bField);
assertTrue(isMaglevved(C1)); // No deopt.
%PrepareFunctionForOptimization(C2);
new C2();
%OptimizeMaglevOnNextCall(C2);
const c2 = new C2();
assertTrue(c2.bField);
assertTrue(isMaglevved(C2)); // No deopt.
})();

View File

@ -0,0 +1,41 @@
// Copyright 2022 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 --maglev --no-stress-opt
// Flags: --no-baseline-batch-compilation --use-osr --turbofan
//
// Disable small-function TF optimization to avoid flakes that unexpectedly
// tier up `f` before we get a chance to enter the OSR loop.
// Flags: --max-bytecode-size-for-early-opt=0
// Flags: --osr-from-maglev --concurrent-osr --concurrent-recompilation
// Flags: --always-osr-from-maglev
let keep_going = 10000000; // A counter to avoid test hangs on failure.
let i; // The loop counter for the test function.
function f() {
let sum = i;
while (--i > 0 && !%CurrentFrameIsTurbofan() && --keep_going) {
// This loop should trigger OSR.
sum += i;
}
return sum;
}
function g() {
assertTrue(%IsMaglevEnabled());
assertTrue(%IsTurbofanEnabled());
while (!%ActiveTierIsMaglev(f) && --keep_going) {
i = 5.2;
f();
}
i = 66666666666;
f();
assertTrue(keep_going > 0);
}
%NeverOptimizeFunction(g);
g();

View File

@ -0,0 +1,40 @@
// Copyright 2022 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 --maglev --no-stress-opt
// Flags: --no-baseline-batch-compilation --use-osr --turbofan
// Flags: --concurrent-osr --concurrent-recompilation
// Flags: --osr-from-maglev --concurrent-osr --concurrent-recompilation
// Flags: --always-osr-from-maglev
let keep_going = 10000000; // A counter to avoid test hangs on failure.
function f() {
let reached_tf = false;
let prev_status = 0;
while (!reached_tf && --keep_going) {
// This loop should trigger OSR.
reached_tf = %CurrentFrameIsTurbofan();
let status = %GetOptimizationStatus(f);
if (status !== prev_status) {
let p = []
for (let k in V8OptimizationStatus) {
if (V8OptimizationStatus[k] & status) {
p.push(k);
}
}
print(p.join(","));
prev_status = status;
}
}
}
function g() {
assertTrue(%IsTurbofanEnabled());
f();
assertTrue(keep_going > 0);
}
%NeverOptimizeFunction(g);
g();

View File

@ -0,0 +1,136 @@
// Copyright 2023 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: --maglev --allow-natives-syntax --no-always-turbofan
// Flags: --no-optimize-maglev-optimizes-to-turbofan
// In this example, the final block of the graph will be something like:
//
// 1: Phi(#42, y)
// 2: CheckedSmiUntag(1)
// 3: Return(1)
//
// Note how the truncation is unused (but still required, as the graph builder
// doesn't know that all of the inputs of the Phi are Smis). After Phi
// untagging, the phi will be an Int32, and the truncation is thus not needed
// anymore. It's important that it's removed during Phi untagging, because its
// input is not tagged anymore (since the phi was untagged), and it's not
// necessary to replace it by something else.
function unused_unneeded_CheckedSmiUntag(x) {
let y = x + 1;
y = x ? 42 : y;
return y | 0;
}
%PrepareFunctionForOptimization(unused_unneeded_CheckedSmiUntag);
unused_unneeded_CheckedSmiUntag(1);
unused_unneeded_CheckedSmiUntag(0);
%OptimizeMaglevOnNextCall(unused_unneeded_CheckedSmiUntag);
unused_unneeded_CheckedSmiUntag(1);
// This example is similar as the previous one, except that the graph will
// contain a CheckedTruncateNumberToInt32 instead of the CheckedSmiUntag:
//
// 1: Phi(c1, c2)
// 2: CheckedTruncateNumberToInt32(1)
// 3: Return(undefined)
//
// The conversion only fails when its input is not a number. Since the Phi was
// untagged to a Float64, the conversion can never fail anymore, and should thus
// be omitted.
//
// Note that if the result of the CheckedTruncateNumberToInt32 would have been
// used, the it would have been automatically changed into a
// TruncateFloat64ToInt32.
//
// A side-effect of have this truncation is that it ensures that its input is a
// boxed Float64, which means that subsequent untagging can use
// UncheckedNumberToFloat64 instead of CheckedNumberToFloat64. This is what is
// used here when doing `let as_double = phi + 0.6`. This
// UncheckedNumberToFloat64 will just be dropped, since the input (the phi) is
// already an unboxed Float64.
function unused_unneeded_CheckedTruncateNumberToInt32(x) {
let c1 = x + 0.5;
let c2 = x + 1.5;
let phi = x ? c1 : c2;
let as_int = phi | 0;
let as_double = phi + 0.6;
}
%PrepareFunctionForOptimization(unused_unneeded_CheckedTruncateNumberToInt32);
unused_unneeded_CheckedTruncateNumberToInt32(1.5);
%OptimizeMaglevOnNextCall(unused_unneeded_CheckedTruncateNumberToInt32);
unused_unneeded_CheckedTruncateNumberToInt32(1.5);
// In this example, during feedback collection, we provide inputs that cause
// `phi` to always be a Smi, which means that `phi | 0` will have Smi
// feedback. The graph will thus be:
//
// 1: Phi(d, #42)
// 2: CheckedSmiUntag(1)
// 3: Return(1)
//
// Except that Phi untagging will realize that `phi` could be a Float64, and
// will thus decide that it should be a Float64 Phi. In this case, the
// conversion should not be dropped, because if the Phi is not an Int32, then it
// should not be returned directly, but instead be truncated. In practice
// though, we'll rather replace it by a CheckedTruncateFloat64ToInt32, which
// will fail if the Float64 isn't an Int32, causing a deopt, and the reoptimized
// code will have a better feedback (this is easier than to try to patch the
// `Return(1)` to return something else).
function unused_required_CheckedSmiUntag(x) {
x = x + 0.5; // ensuring Float64 alternative
let d = x + 2.53;
let phi = x ? d : 42;
return phi | 0;
}
%PrepareFunctionForOptimization(unused_required_CheckedSmiUntag);
unused_required_CheckedSmiUntag(-0.5);
%OptimizeMaglevOnNextCall(unused_required_CheckedSmiUntag);
assertEquals(42, unused_required_CheckedSmiUntag(-0.5));
assertOptimized(unused_required_CheckedSmiUntag);
// If the CheckedSmiUntag is dropped, then the truncation won't be done, and the
// non-truncated float (3.53) will be returned. Instead, if the conversion is
// changed to CheckedTruncateFloat64ToInt32, then it will deopt, and we'll get
// the correct result of 3.
assertEquals(3, unused_required_CheckedSmiUntag(0.5));
assertUnoptimized(unused_required_CheckedSmiUntag);
// Finally, int this example, during feedback collection, `phi` will always be a
// Smi, which means that `phi + 2` will be an Int32AddWithOverflow, preceeded by
// a CheckedSmiUntag(Phi):
//
// 1: Phi(d, #42)
// 2: CheckedSmiUntag(1)
// 3: Int32AddWithOverflow(2, #2)
//
// However, Phi untagging will detect that `phi` should be a Float64 phi. In
// that case, it's important that the CheckedSmiUntag conversion isn't dropped,
// and becomes a deopting Float64->Int32 conversion that deopts when its input
// cannot be converted to Int32 without loss of precision (ie, it should become
// a CheckedTruncateFloat64ToInt32 rather than a TruncateFloat64ToInt32). Then,
// when the Phi turns out to be a non-Smi Float64, the function should deopt.
function used_required_deopting_Float64ToInt32(x) {
x = x + 0.5; // ensuring Float64 alternative
let d = x + 2.53;
let phi = x ? d : 42;
return phi + 2;
}
%PrepareFunctionForOptimization(used_required_deopting_Float64ToInt32);
used_required_deopting_Float64ToInt32(-0.5);
%OptimizeMaglevOnNextCall(used_required_deopting_Float64ToInt32);
assertEquals(44, used_required_deopting_Float64ToInt32(-0.5));
// The next call should cause a deopt, since `phi` will be 4.53, which shouldn't
// be truncated to go into the Int32AddWithOverflow but should instead cause a
// deopt to allow the `phi + 2` to be computed on double values.
assertEquals(1.5+0.5+2.53+2, used_required_deopting_Float64ToInt32(1.5));
assertUnoptimized(used_required_deopting_Float64ToInt32);

View File

@ -0,0 +1,37 @@
// Copyright 2023 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 --maglev
function f(a, holey_double_arr) {
let int32 = a + 1;
// Make sure an int32 value can be an input to a holeyfloat64 phi.
let holey_float64_phi = a ? int32 : holey_double_arr[0];
return holey_float64_phi + 0.5;
}
%PrepareFunctionForOptimization(f);
assertEquals(43.5, f(42, [0.5,]));
assertEquals(1, f(0, [0.5,]));
%OptimizeMaglevOnNextCall(f);
assertEquals(43.5, f(42, [0.5,]));
assertEquals(1, f(0, [0.5,]));
assertEquals(NaN, f(0, [,0.5]));
function g(a, holey_double_arr) {
let int32 = a + 1;
let int32phi = a ? a + 2 : int32;
// Make sure an int32 phi can be an input to a holeyfloat64 phi.
let holey_float64_phi = a ? int32phi : holey_double_arr[0];
return holey_float64_phi + 0.5;
}
%PrepareFunctionForOptimization(g);
assertEquals(44.5, g(42, [0.5,]));
assertEquals(1, g(0, [0.5,]));
%OptimizeMaglevOnNextCall(g);
assertEquals(44.5, g(42, [0.5,]));
assertEquals(1, g(0, [0.5,]));
assertEquals(NaN, g(0, [,0.5]));

View File

@ -0,0 +1,32 @@
// 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 --maglev --no-always-turbofan
function poly_store(a, x) {
a[0] = x;
};
var y = new Array();
y[0] = 1.1;
y.x = 12;
// We don't use {y}, but it prevents the map packed double map with `x` from
// being GCed, which avoids {poly_store} from being deopted.
%PrepareFunctionForOptimization(poly_store);
poly_store([1.1], 'a');
poly_store([1.1], 2.1);
var x = new Array();
x[0] = 1.1;
x.x = 12;
poly_store(x, 'a');
%OptimizeMaglevOnNextCall(poly_store);
var c = new Array();
c[0] = 1.1;
assertTrue(%HasDoubleElements(c));
poly_store(c, 'a');
assertTrue(%HasObjectElements(c));
assertEquals(c[0], 'a');
assertTrue(isMaglevved(poly_store));

View File

@ -0,0 +1,55 @@
// Copyright 2023 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 --maglev --no-always-turbofan
function A() { this.x = 1 }
function B() { this.x = 1 }
const a = new A();
a.y = 1;
(new A()).x = 0.1; // deprecate a
const b = new B();
b.y = 1;
(new B()).x = 0.1; // deprecate b
function load(o) { return o.y }
// Make o.y polymorphic and compile it with maglev. a and b will be deprecated
// causing migrations in a way that o.y is still at the same offset. This allows
// maglev to optimize it behind a CheckMapsWithMigration() node.
// | a | | | a |
// |--------| | |-----------|
// | x: Smi | | | x: Double |
// |
// | -|-> |
// V -|-> V
// |
// | a | | | a |
// |--------| | |-----------|
// | x: Smi | | | x: Double |
// | y: Smi | | | y: Smi | <-- y did not change.
%PrepareFunctionForOptimization(load);
load(a);
load(b);
%OptimizeMaglevOnNextCall(load);
load(a);
load(b);
assertOptimized(load);
// Create a fresh deprecated map, to test the migration path in
// CheckMapsWithMigration().
function C() { this.x = 1 }
const c = new C();
c.y = 1;
(new C()).x = 0.1; // deprecate c
load(c);
assertUnoptimized(load);

View File

@ -0,0 +1,18 @@
// Copyright 2023 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 --maglev
function foo(o) {
return o.length;
}
%PrepareFunctionForOptimization(foo);
assertEquals(6, foo("string"));
assertEquals(undefined, foo(4.2));
%OptimizeMaglevOnNextCall(foo);
assertEquals(6, foo("string"));
assertEquals(undefined, foo(4.2));

View File

@ -0,0 +1,23 @@
// Copyright 2023 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 --maglev
function f(value) {
return value.x === 'abc';
}
let o1 = { x : 'abc' };
let o2 = { y : 'no' };
%PrepareFunctionForOptimization(f);
f(o1);
f(o2);
f(4);
// The feedback of `f` now contains 2 kNotFound maps (one for `o2`'s map, and
// one for HeapNumber map).
%OptimizeMaglevOnNextCall(f);
assertEquals(f(4), false);
assertOptimized(f);

View File

@ -0,0 +1,30 @@
// 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 --maglev
function f(o, newValue) {
o.x = newValue;
}
let o1 = { x : '' };
let o2 = { a: 0, x : '' };
let o3 = { a: 0, x : '' };
%PrepareFunctionForOptimization(f);
f(o1, 0);
f(o2, 0);
%OptimizeMaglevOnNextCall(f);
f(o1, 1);
f(o3, 2);
assertEquals(1, o1.x);
assertEquals(2, o3.x);
assertTrue(isMaglevved(f));
let o4 = {a: 0, b: 0, c: 0, x: 0};
f(o4, 3);
assertFalse(isMaglevved(f));
assertEquals(3, o4.x);

View File

@ -0,0 +1,29 @@
// Copyright 2022 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 --maglev
function foo(__v_4) {
var __v_5 = function () {
return __v_4;
}();
var __v_6 = __v_5.x;
arguments[42];
return __v_6 + __v_5.x;
}
var __v_0 = {x: 24};
__v_0.g = 43;
%PrepareFunctionForOptimization(foo);
foo({x: 42});
foo({x: 42});
%OptimizeMaglevOnNextCall(foo);
var __v_3 = {x: 42};
Object.prototype.__defineGetter__(42, function () {
__v_3.__defineGetter__("x", function () {
});
});
assertEquals(NaN, foo(__v_3));

View File

@ -0,0 +1,29 @@
// Copyright 2022 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 --maglev
'use strict';
function foo(obj, ...args) {
obj['apply'](...args);
}
var x = 0;
function bar() {
try {
this.x;
} catch (e) {
x++;
}
}
%PrepareFunctionForOptimization(foo);
foo(bar);
%OptimizeMaglevOnNextCall(foo);
foo(bar);
assertEquals(2, x);

View File

@ -0,0 +1,17 @@
// Copyright 2022 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 --maglev
function foo() {
const buffer = new SharedArrayBuffer(1395, {
"maxByteLength": 2110270,
});
const data = new DataView(buffer);
data.setInt16();
}
%PrepareFunctionForOptimization(foo);
foo();
%OptimizeMaglevOnNextCall(foo);
foo();

View File

@ -0,0 +1,18 @@
// Copyright 2022 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 --maglev
for (let v0 = 0; v0 < 100; v0++) {
for (let v1 = 0; v1 < 100; v1++) {
const v4 = new Float64Array(33519);
}
for (let v5 = 0; v5 < 100; v5++) {
function F8( a12) {
if (!new.target) { throw 'must be called with new'; }
a12--;
}
const v14 = new F8(- -1000000.0);
}
}

Some files were not shown because too many files have changed in this diff Show More