Commit 088df4e1 authored by franzih's avatar franzih Committed by Commit bot

[turbofan] Use feedback from StoreDataPropertyInLiteral.

Lower StoreDataPropertyInLiteral() when storing
computed property names in object literals.

Add a new AccessMode, kStoreInLiteral. It is similar to
AccessMode::kStore but does not look
up properties on the prototype chain.

99% of all literal definitions with computed property names
end up with generic access_info because of how we count
properties. Once we fix
https://bugs.chromium.org/p/v8/issues/detail?id=5625,
they'll get lowered as well.

BUG=v8:5624

Review-Url: https://codereview.chromium.org/2619773002
Cr-Commit-Position: refs/heads/master@{#42210}
parent 9355f899
......@@ -52,6 +52,8 @@ std::ostream& operator<<(std::ostream& os, AccessMode access_mode) {
return os << "Load";
case AccessMode::kStore:
return os << "Store";
case AccessMode::kStoreInLiteral:
return os << "StoreInLiteral";
}
UNREACHABLE();
return os;
......@@ -282,7 +284,8 @@ bool AccessInfoFactory::ComputePropertyAccessInfo(
int const number = descriptors->SearchWithCache(isolate(), *name, *map);
if (number != DescriptorArray::kNotFound) {
PropertyDetails const details = descriptors->GetDetails(number);
if (access_mode == AccessMode::kStore) {
if (access_mode == AccessMode::kStore ||
access_mode == AccessMode::kStoreInLiteral) {
// Don't bother optimizing stores to read-only properties.
if (details.IsReadOnly()) {
return false;
......@@ -383,6 +386,11 @@ bool AccessInfoFactory::ComputePropertyAccessInfo(
return false;
}
// Don't search on the prototype when storing in literals
if (access_mode == AccessMode::kStoreInLiteral) {
return false;
}
// Don't lookup private symbols on the prototype chain.
if (name->IsPrivate()) return false;
......
......@@ -26,7 +26,8 @@ class Type;
class TypeCache;
// Whether we are loading a property or storing to a property.
enum class AccessMode { kLoad, kStore };
// For a store during literal creation, do not walk up the prototype chain.
enum class AccessMode { kLoad, kStore, kStoreInLiteral };
std::ostream& operator<<(std::ostream&, AccessMode);
......
......@@ -753,6 +753,8 @@ void BytecodeGraphBuilder::VisitStaGlobalStrict() {
}
void BytecodeGraphBuilder::VisitStaDataPropertyInLiteral() {
PrepareEagerCheckpoint();
Node* object =
environment()->LookupRegister(bytecode_iterator().GetRegisterOperand(0));
Node* name =
......
......@@ -129,8 +129,8 @@ Reduction JSNativeContextSpecialization::ReduceJSInstanceOf(Node* node) {
}
// Monomorphic property access.
effect =
BuildCheckMaps(constructor, effect, control, MapList{receiver_map});
effect = BuildCheckMaps(constructor, effect, control,
access_info.receiver_maps());
// Lower to OrdinaryHasInstance(C, O).
NodeProperties::ReplaceValueInput(node, constructor, 0);
......@@ -150,8 +150,8 @@ Reduction JSNativeContextSpecialization::ReduceJSInstanceOf(Node* node) {
}
// Monomorphic property access.
effect =
BuildCheckMaps(constructor, effect, control, MapList{receiver_map});
effect = BuildCheckMaps(constructor, effect, control,
access_info.receiver_maps());
// Call the @@hasInstance handler.
Node* target = jsgraph()->Constant(access_info.constant());
......@@ -968,6 +968,7 @@ JSNativeContextSpecialization::BuildPropertyAccess(
// Determine actual holder and perform prototype chain checks.
Handle<JSObject> holder;
if (access_info.holder().ToHandle(&holder)) {
DCHECK_NE(AccessMode::kStoreInLiteral, access_mode);
AssumePrototypesStable(access_info.receiver_maps(), holder);
}
......@@ -1028,6 +1029,7 @@ JSNativeContextSpecialization::BuildPropertyAccess(
}
break;
}
case AccessMode::kStoreInLiteral:
case AccessMode::kStore: {
// We need a FrameState for the setter stub to restore the correct
// context and return the appropriate value to fullcodegen.
......@@ -1258,8 +1260,75 @@ JSNativeContextSpecialization::BuildPropertyAccess(
Reduction JSNativeContextSpecialization::ReduceJSStoreDataPropertyInLiteral(
Node* node) {
// TODO(franzih): Use feedback
return NoChange();
DCHECK_EQ(IrOpcode::kJSStoreDataPropertyInLiteral, node->opcode());
// If deoptimization is disabled, we cannot optimize.
if (!(flags() & kDeoptimizationEnabled)) return NoChange();
DataPropertyParameters const& p = DataPropertyParametersOf(node->op());
if (!p.feedback().IsValid()) return NoChange();
StoreDataPropertyInLiteralICNexus nexus(p.feedback().vector(),
p.feedback().slot());
if (nexus.IsUninitialized()) {
return NoChange();
}
if (nexus.ic_state() == MEGAMORPHIC) {
return NoChange();
}
DCHECK_EQ(MONOMORPHIC, nexus.ic_state());
Handle<Map> receiver_map(nexus.FindFirstMap(), isolate());
Handle<Name> cached_name =
handle(Name::cast(nexus.GetFeedbackExtra()), isolate());
PropertyAccessInfo access_info;
AccessInfoFactory access_info_factory(dependencies(), native_context(),
graph()->zone());
if (!access_info_factory.ComputePropertyAccessInfo(
receiver_map, cached_name, AccessMode::kStoreInLiteral,
&access_info)) {
return NoChange();
}
if (access_info.IsGeneric()) {
return NoChange();
}
Node* receiver = NodeProperties::GetValueInput(node, 0);
Node* effect = NodeProperties::GetEffectInput(node);
Node* control = NodeProperties::GetControlInput(node);
// Monomorphic property access.
receiver = BuildCheckHeapObject(receiver, &effect, control);
effect =
BuildCheckMaps(receiver, effect, control, access_info.receiver_maps());
// Ensure that {name} matches the cached name.
Node* name = NodeProperties::GetValueInput(node, 1);
Node* check = graph()->NewNode(simplified()->ReferenceEqual(), name,
jsgraph()->HeapConstant(cached_name));
effect = graph()->NewNode(simplified()->CheckIf(), check, effect, control);
Node* value = NodeProperties::GetValueInput(node, 2);
Node* context = NodeProperties::GetContextInput(node);
Node* frame_state_lazy = NodeProperties::GetFrameStateInput(node);
// Generate the actual property access.
ValueEffectControl continuation = BuildPropertyAccess(
receiver, value, context, frame_state_lazy, effect, control, cached_name,
access_info, AccessMode::kStoreInLiteral, LanguageMode::SLOPPY,
p.feedback().vector(), p.feedback().slot());
value = continuation.value();
effect = continuation.effect();
control = continuation.control();
ReplaceWithValue(node, value, effect, control);
return Replace(value);
}
namespace {
......@@ -1285,6 +1354,8 @@ JSNativeContextSpecialization::BuildElementAccess(
Node* receiver, Node* index, Node* value, Node* effect, Node* control,
ElementAccessInfo const& access_info, AccessMode access_mode,
KeyedAccessStoreMode store_mode) {
DCHECK_NE(AccessMode::kStoreInLiteral, access_mode);
// TODO(bmeurer): We currently specialize based on elements kind. We should
// also be able to properly support strings and other JSObjects here.
ElementsKind elements_kind = access_info.elements_kind();
......@@ -1381,6 +1452,9 @@ JSNativeContextSpecialization::BuildElementAccess(
base_pointer, external_pointer, index, effect, control);
break;
}
case AccessMode::kStoreInLiteral:
UNREACHABLE();
break;
case AccessMode::kStore: {
// Ensure that the {value} is actually a Number.
value = effect = graph()->NewNode(simplified()->CheckNumber(), value,
......
......@@ -151,7 +151,7 @@ void Verifier::Visitor::Check(Node* node) {
"control");
}
// Verify that no-no-throw nodes only have IfSuccess/IfException control
// Verify that nodes that can throw only have IfSuccess/IfException control
// uses.
if (!node->op()->HasProperty(Operator::kNoThrow)) {
int count_success = 0, count_exception = 0;
......
......@@ -4,7 +4,7 @@
// Flags: --allow-natives-syntax
(function TestDeoptFromCopmputedNameInObjectLiteral() {
(function TestDeoptFromComputedNameInObjectLiteral() {
function f() {
var o = {
toString: function() {
......@@ -20,7 +20,38 @@
assertEquals(23, f().x());
})();
(function TestDeoptFromCopmputedNameInClassLiteral() {
(function TestDeoptFromComputedNameInObjectLiteralWithModifiedPrototype() {
// The prototype chain should not be used if the definition
// happens in the object literal.
Object.defineProperty(Object.prototype, 'x_proto', {
get: function () {
return 21;
},
set: function () {
}
});
function f() {
var o = {
toString: function() {
%DeoptimizeFunction(f);
return "x_proto";
}
};
return { [o]() { return 23 } };
}
assertEquals(23, f().x_proto());
assertEquals(23, f().x_proto());
%OptimizeFunctionOnNextCall(f);
assertEquals(23, f().x_proto());
delete Object.prototype.c;
})();
(function TestDeoptFromComputedNameInClassLiteral() {
function g() {
var o = {
toString: function() {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment