b9a59e3892
Turboprop doesn't use optimizations based on field constness to reduce the number of deoptimizations. While this is safe for loads, for stores if a different value is stored to a const field we should update the constness of the field. This is needed so we can safely deopt any other code that is relying on the constness of the field. Currently, turboprop doesn't do this. So for now treat stores to constant fields similar to TurboFan. In future, we may consider adding code to update the field constness if necessary to reduce the number of deoptimizations. Bug: chromium:1172797, v8:9684 Change-Id: I1d660457cb5d647e1283a495040a7e452fe1ac7e Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2673401 Commit-Queue: Mythri Alle <mythria@chromium.org> Reviewed-by: Georg Neis <neis@chromium.org> Reviewed-by: Sathya Gunasekaran <gsathya@chromium.org> Cr-Commit-Position: refs/heads/master@{#72590}
226 lines
6.6 KiB
JavaScript
226 lines
6.6 KiB
JavaScript
// Copyright 2020 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.
|
|
|
|
// TODO(gsathya): This test will probably break when v8 tiers up to turbofan
|
|
// from turboprop.
|
|
//
|
|
// Flags: --allow-natives-syntax --opt --no-always-opt --turboprop
|
|
|
|
var global = this;
|
|
var unique_id = 0;
|
|
// Creates a function with unique SharedFunctionInfo to ensure the feedback
|
|
// vector is unique for each test case.
|
|
function MakeFunctionWithUniqueSFI(...args) {
|
|
assertTrue(args.length > 0);
|
|
var body = `/* Unique comment: ${unique_id++} */ ` + args.pop();
|
|
return new Function(...args, body);
|
|
}
|
|
|
|
|
|
//
|
|
// Load constant field from constant object directly.
|
|
//
|
|
function TestLoadFromConstantFieldOfAConstantObject(the_value, other_value) {
|
|
function A(v) { this.v = v; }
|
|
function O() { this.a = new A(the_value); }
|
|
var the_object = new O();
|
|
|
|
// Ensure that {the_object.a}'s map is not stable to complicate compiler's
|
|
// life.
|
|
new A(the_value).blah = 0;
|
|
|
|
// Ensure that constant tracking is enabled for {contant_object}.
|
|
delete global.constant_object;
|
|
global.constant_object = the_object;
|
|
assertEquals(the_object, constant_object);
|
|
|
|
assertTrue(%HasFastProperties(the_object));
|
|
|
|
// {constant_object} is known to the compiler via global property cell
|
|
// tracking.
|
|
var load = MakeFunctionWithUniqueSFI("return constant_object.a.v;");
|
|
%PrepareFunctionForOptimization(load);
|
|
load();
|
|
load();
|
|
%OptimizeFunctionOnNextCall(load);
|
|
assertEquals(the_value, load());
|
|
assertOptimized(load);
|
|
var a = new A(other_value);
|
|
assertTrue(%HaveSameMap(a, the_object.a));
|
|
// Make constant field mutable by assigning another value
|
|
// to some other instance of A.
|
|
new A(the_value).v = other_value;
|
|
assertTrue(%HaveSameMap(a, new A(the_value)));
|
|
assertTrue(%HaveSameMap(a, the_object.a));
|
|
assertOptimized(load);
|
|
assertEquals(the_value, load());
|
|
assertOptimized(load);
|
|
assertEquals(the_value, load());
|
|
}
|
|
|
|
//Test constant tracking with Smi value.
|
|
(function() {
|
|
var the_value = 42;
|
|
var other_value = 153;
|
|
TestLoadFromConstantFieldOfAConstantObject(the_value, other_value);
|
|
})();
|
|
|
|
// Test constant tracking with double value.
|
|
(function() {
|
|
var the_value = 0.9;
|
|
var other_value = 0.42;
|
|
TestLoadFromConstantFieldOfAConstantObject(the_value, other_value);
|
|
})();
|
|
|
|
// Test constant tracking with function value.
|
|
(function() {
|
|
var the_value = function V() {};
|
|
var other_value = function W() {};
|
|
TestLoadFromConstantFieldOfAConstantObject(the_value, other_value);
|
|
})();
|
|
|
|
// Test constant tracking with heap object value.
|
|
(function() {
|
|
function V() {}
|
|
var the_value = new V();
|
|
var other_value = new V();
|
|
TestLoadFromConstantFieldOfAConstantObject(the_value, other_value);
|
|
})();
|
|
|
|
|
|
//
|
|
// Load constant field from a prototype.
|
|
//
|
|
function TestLoadFromConstantFieldOfAPrototype(the_value, other_value) {
|
|
function Proto() { this.v = the_value; }
|
|
var the_prototype = new Proto();
|
|
|
|
function O() {}
|
|
O.prototype = the_prototype;
|
|
var the_object = new O();
|
|
|
|
// Ensure O.prototype is in fast mode by loading from its field.
|
|
function warmup() { return new O().v; }
|
|
%EnsureFeedbackVectorForFunction(warmup);
|
|
warmup(); warmup(); warmup();
|
|
assertTrue(%HasFastProperties(O.prototype));
|
|
|
|
// The parameter object is not constant but all the values have the same
|
|
// map and therefore the compiler knows the prototype object and can
|
|
// optimize load of "v".
|
|
var load = MakeFunctionWithUniqueSFI("o", "return o.v;");
|
|
%PrepareFunctionForOptimization(load);
|
|
load(new O());
|
|
load(new O());
|
|
%OptimizeFunctionOnNextCall(load);
|
|
assertEquals(the_value, load(new O()));
|
|
assertOptimized(load);
|
|
// Invalidation of mutability should trigger deoptimization with a
|
|
// "field-owner" reason.
|
|
the_prototype.v = other_value;
|
|
assertUnoptimized(load);
|
|
}
|
|
|
|
// Test constant tracking with Smi value.
|
|
(function() {
|
|
var the_value = 42;
|
|
var other_value = 153;
|
|
TestLoadFromConstantFieldOfAPrototype(the_value, other_value);
|
|
})();
|
|
|
|
// Test constant tracking with double value.
|
|
(function() {
|
|
var the_value = 0.9;
|
|
var other_value = 0.42;
|
|
TestLoadFromConstantFieldOfAPrototype(the_value, other_value);
|
|
})();
|
|
|
|
// Test constant tracking with function value.
|
|
(function() {
|
|
var the_value = function V() {};
|
|
var other_value = function W() {};
|
|
TestLoadFromConstantFieldOfAPrototype(the_value, other_value);
|
|
})();
|
|
|
|
// Test constant tracking with heap object value.
|
|
(function() {
|
|
function V() {}
|
|
var the_value = new V();
|
|
var other_value = new V();
|
|
TestLoadFromConstantFieldOfAPrototype(the_value, other_value);
|
|
})();
|
|
|
|
|
|
//
|
|
// Store to constant field of a constant object.
|
|
//
|
|
function TestStoreToConstantFieldOfConstantObject(the_value, other_value) {
|
|
function A(v) { this.v = v; }
|
|
function O() { this.a = new A(the_value); }
|
|
var the_object = new O();
|
|
|
|
// Ensure that {the_object.a}'s map is not stable to complicate compiler's
|
|
// life.
|
|
new A(the_value).blah = 0;
|
|
|
|
// Ensure that constant tracking is enabled for {contant_object}.
|
|
delete global.constant_object;
|
|
global.constant_object = the_object;
|
|
assertEquals(the_object, constant_object);
|
|
|
|
assertTrue(%HasFastProperties(the_object));
|
|
|
|
// {constant_object} is known to the compiler via global property cell
|
|
// tracking.
|
|
var store = MakeFunctionWithUniqueSFI("v", "constant_object.a.v = v;");
|
|
%PrepareFunctionForOptimization(store);
|
|
store(the_value);
|
|
store(the_value);
|
|
%OptimizeFunctionOnNextCall(store);
|
|
store(the_value);
|
|
assertEquals(the_value, constant_object.a.v);
|
|
assertOptimized(store);
|
|
// Storing of the same value does not deoptimize.
|
|
store(the_value);
|
|
assertEquals(the_value, constant_object.a.v);
|
|
assertOptimized(store);
|
|
|
|
var a = new A(other_value);
|
|
|
|
assertOptimized(store);
|
|
// Storing other value deoptimizes because of failed value check.
|
|
store(other_value);
|
|
assertUnoptimized(store);
|
|
assertEquals(other_value, constant_object.a.v);
|
|
}
|
|
|
|
// Test constant tracking with Smi values.
|
|
(function() {
|
|
var the_value = 42;
|
|
var other_value = 153;
|
|
TestStoreToConstantFieldOfConstantObject(the_value, other_value);
|
|
})();
|
|
|
|
// Test constant tracking with double values.
|
|
(function() {
|
|
var the_value = 0.9;
|
|
var other_value = 0.42
|
|
TestStoreToConstantFieldOfConstantObject(the_value, other_value);
|
|
})();
|
|
|
|
// Test constant tracking with function values.
|
|
(function() {
|
|
var the_value = function V() {};
|
|
var other_value = function W() {};
|
|
TestStoreToConstantFieldOfConstantObject(the_value, other_value);
|
|
})();
|
|
|
|
// Test constant tracking with heap object values.
|
|
(function() {
|
|
function V() {}
|
|
var the_value = new V();
|
|
var other_value = new V();
|
|
TestStoreToConstantFieldOfConstantObject(the_value, other_value);
|
|
})();
|