[turbofan] Use feedback when reducing global loads/stores.

We already record the script context location or the property cell
as feedback of the global load/store IC, so Turbofan doesn't need
to do the lookups again.

Change-Id: I6cbd2937de344729cd8e146b4ff85ddf3de6a56e
Reviewed-on: https://chromium-review.googlesource.com/c/1335691
Commit-Queue: Georg Neis <neis@chromium.org>
Reviewed-by: Benedikt Meurer <bmeurer@chromium.org>
Cr-Commit-Position: refs/heads/master@{#57555}
This commit is contained in:
Georg Neis 2018-11-15 14:56:58 +01:00 committed by Commit Bot
parent b2f7f40a13
commit 9c91b6877a
5 changed files with 114 additions and 45 deletions

View File

@ -794,9 +794,6 @@ FieldAccess ForPropertyCellValue(MachineRepresentation representation,
Reduction JSNativeContextSpecialization::ReduceGlobalAccess(
Node* node, Node* receiver, Node* value, Handle<Name> name,
AccessMode access_mode, Node* index) {
Node* effect = NodeProperties::GetEffectInput(node);
Node* control = NodeProperties::GetControlInput(node);
// Lookup on the global object. We only deal with own data properties
// of the global object here (represented as PropertyCell).
LookupIterator it(isolate(), global_object(), name, LookupIterator::OWN);
@ -804,9 +801,25 @@ Reduction JSNativeContextSpecialization::ReduceGlobalAccess(
if (it.state() != LookupIterator::DATA) return NoChange();
if (!it.GetHolder<JSObject>()->IsJSGlobalObject()) return NoChange();
Handle<PropertyCell> property_cell = it.GetPropertyCell();
PropertyDetails property_details = property_cell->property_details();
return ReduceGlobalAccess(node, receiver, value, name, access_mode, index,
property_cell);
}
Reduction JSNativeContextSpecialization::ReduceGlobalAccess(
Node* node, Node* receiver, Node* value, Handle<Name> name,
AccessMode access_mode, Node* index, Handle<PropertyCell> property_cell) {
Node* effect = NodeProperties::GetEffectInput(node);
Node* control = NodeProperties::GetControlInput(node);
Handle<Object> property_cell_value(property_cell->value(), isolate());
if (property_cell_value.is_identical_to(factory()->the_hole_value())) {
// The property cell is no longer valid.
return NoChange();
}
PropertyDetails property_details = property_cell->property_details();
PropertyCellType property_cell_type = property_details.cell_type();
DCHECK_EQ(kData, property_details.kind());
// We have additional constraints for stores.
if (access_mode == AccessMode::kStore) {
@ -981,58 +994,101 @@ Reduction JSNativeContextSpecialization::ReduceGlobalAccess(
Reduction JSNativeContextSpecialization::ReduceJSLoadGlobal(Node* node) {
DCHECK_EQ(IrOpcode::kJSLoadGlobal, node->opcode());
NameRef name(broker(), LoadGlobalParametersOf(node->op()).name());
Node* effect = NodeProperties::GetEffectInput(node);
// Try to lookup the name on the script context table first (lexical scoping).
base::Optional<ScriptContextTableRef::LookupResult> result =
native_context().script_context_table().lookup(name);
if (result) {
ObjectRef contents = result->context.get(result->index);
if (contents.IsHeapObject() &&
contents.AsHeapObject().map().oddball_type() == OddballType::kHole) {
return NoChange();
LoadGlobalParameters const& p = LoadGlobalParametersOf(node->op());
if (!p.feedback().IsValid()) return NoChange();
FeedbackNexus nexus(p.feedback().vector(), p.feedback().slot());
DCHECK(nexus.kind() == FeedbackSlotKind::kLoadGlobalInsideTypeof ||
nexus.kind() == FeedbackSlotKind::kLoadGlobalNotInsideTypeof);
if (nexus.GetFeedback()->IsCleared()) return NoChange();
Handle<Object> feedback(nexus.GetFeedback()->GetHeapObjectOrSmi(), isolate());
if (feedback->IsSmi()) {
// The wanted name belongs to a script-scope variable and the feedback tells
// us where to find its value.
int const script_context_index =
FeedbackNexus::ContextIndexBits::decode(feedback->Number());
int const context_slot_index =
FeedbackNexus::SlotIndexBits::decode(feedback->Number());
bool const immutable =
FeedbackNexus::ImmutabilityBit::decode(feedback->Number());
Handle<Context> context = ScriptContextTable::GetContext(
isolate(), native_context().script_context_table().object(),
script_context_index);
{
ObjectRef contents(broker(),
handle(context->get(context_slot_index), isolate()));
CHECK(!contents.equals(ObjectRef(broker(), factory()->the_hole_value())));
}
Node* context = jsgraph()->Constant(result->context);
Node* context_constant = jsgraph()->Constant(context);
Node* value = effect = graph()->NewNode(
javascript()->LoadContext(0, result->index, result->immutable), context,
effect);
javascript()->LoadContext(0, context_slot_index, immutable),
context_constant, effect);
ReplaceWithValue(node, value, effect);
return Replace(value);
}
// Lookup the {name} on the global object instead.
return ReduceGlobalAccess(node, nullptr, nullptr, name.object(),
AccessMode::kLoad);
CHECK(feedback->IsPropertyCell());
// The wanted name belongs (or did belong) to a property on the global object
// and the feedback is the cell holding its value.
return ReduceGlobalAccess(node, nullptr, nullptr, p.name(), AccessMode::kLoad,
nullptr, Handle<PropertyCell>::cast(feedback));
}
Reduction JSNativeContextSpecialization::ReduceJSStoreGlobal(Node* node) {
DCHECK_EQ(IrOpcode::kJSStoreGlobal, node->opcode());
NameRef name(broker(), StoreGlobalParametersOf(node->op()).name());
Node* value = NodeProperties::GetValueInput(node, 0);
Node* effect = NodeProperties::GetEffectInput(node);
Node* control = NodeProperties::GetControlInput(node);
// Try to lookup the name on the script context table first (lexical scoping).
base::Optional<ScriptContextTableRef::LookupResult> result =
native_context().script_context_table().lookup(name);
if (result) {
ObjectRef contents = result->context.get(result->index);
if ((contents.IsHeapObject() &&
contents.AsHeapObject().map().oddball_type() == OddballType::kHole) ||
result->immutable) {
return NoChange();
StoreGlobalParameters const& p = StoreGlobalParametersOf(node->op());
if (!p.feedback().IsValid()) return NoChange();
FeedbackNexus nexus(p.feedback().vector(), p.feedback().slot());
DCHECK(nexus.kind() == FeedbackSlotKind::kStoreGlobalSloppy ||
nexus.kind() == FeedbackSlotKind::kStoreGlobalStrict);
if (nexus.GetFeedback()->IsCleared()) return NoChange();
Handle<Object> feedback(nexus.GetFeedback()->GetHeapObjectOrSmi(), isolate());
if (feedback->IsSmi()) {
// The wanted name belongs to a script-scope variable and the feedback tells
// us where to find its value.
int const script_context_index =
FeedbackNexus::ContextIndexBits::decode(feedback->Number());
int const context_slot_index =
FeedbackNexus::SlotIndexBits::decode(feedback->Number());
bool const immutable =
FeedbackNexus::ImmutabilityBit::decode(feedback->Number());
Handle<Context> context = ScriptContextTable::GetContext(
isolate(), native_context().script_context_table().object(),
script_context_index);
if (immutable) return NoChange();
{
ObjectRef contents(broker(),
handle(context->get(context_slot_index), isolate()));
CHECK(!contents.equals(ObjectRef(broker(), factory()->the_hole_value())));
}
Node* context = jsgraph()->Constant(result->context);
effect = graph()->NewNode(javascript()->StoreContext(0, result->index),
value, context, effect, control);
Node* context_constant = jsgraph()->Constant(context);
effect = graph()->NewNode(javascript()->StoreContext(0, context_slot_index),
value, context_constant, effect, control);
ReplaceWithValue(node, value, effect, control);
return Replace(value);
}
// Lookup the {name} on the global object instead.
return ReduceGlobalAccess(node, nullptr, value, name.object(),
AccessMode::kStore);
CHECK(feedback->IsPropertyCell());
// The wanted name belongs (or did belong) to a property on the global object
// and the feedback is the cell holding its value.
return ReduceGlobalAccess(node, nullptr, value, p.name(), AccessMode::kStore,
nullptr, Handle<PropertyCell>::cast(feedback));
}
Reduction JSNativeContextSpecialization::ReduceNamedAccess(

View File

@ -112,6 +112,9 @@ class V8_EXPORT_PRIVATE JSNativeContextSpecialization final
Reduction ReduceGlobalAccess(Node* node, Node* receiver, Node* value,
Handle<Name> name, AccessMode access_mode,
Node* index = nullptr);
Reduction ReduceGlobalAccess(Node* node, Node* receiver, Node* value,
Handle<Name> name, AccessMode access_mode,
Node* index, Handle<PropertyCell> property_cell);
Reduction ReduceSoftDeoptimize(Node* node, DeoptimizeReason reason);
Reduction ReduceJSToString(Node* node);

View File

@ -725,16 +725,23 @@ void FeedbackNexus::ConfigurePropertyCellMode(Handle<PropertyCell> cell) {
}
bool FeedbackNexus::ConfigureLexicalVarMode(int script_context_index,
int context_slot_index) {
int context_slot_index,
bool immutable) {
DCHECK(IsGlobalICKind(kind()));
DCHECK_LE(0, script_context_index);
DCHECK_LE(0, context_slot_index);
if (!ContextIndexBits::is_valid(script_context_index) ||
!SlotIndexBits::is_valid(context_slot_index)) {
!SlotIndexBits::is_valid(context_slot_index) ||
!ImmutabilityBit::is_valid(immutable)) {
return false;
}
int config = ContextIndexBits::encode(script_context_index) |
SlotIndexBits::encode(context_slot_index);
SlotIndexBits::encode(context_slot_index) |
ImmutabilityBit::encode(immutable);
// Force {config} to be in Smi range by propagating the most significant Smi
// bit. This does not change any of the bitfield's bits.
config = (config << (32 - kSmiValueSize)) >> (32 - kSmiValueSize);
SetFeedback(Smi::FromInt(config));
Isolate* isolate = GetIsolate();

View File

@ -666,8 +666,8 @@ class FeedbackNexus final {
// For Global Load and Store ICs.
void ConfigurePropertyCellMode(Handle<PropertyCell> cell);
// Returns false if given combination of indices is not allowed.
bool ConfigureLexicalVarMode(int script_context_index,
int context_slot_index);
bool ConfigureLexicalVarMode(int script_context_index, int context_slot_index,
bool immutable);
void ConfigureHandlerMode(const MaybeObjectHandle& handler);
// For CloneObject ICs
@ -677,7 +677,8 @@ class FeedbackNexus final {
// Bit positions in a smi that encodes lexical environment variable access.
#define LEXICAL_MODE_BIT_FIELDS(V, _) \
V(ContextIndexBits, unsigned, 12, _) \
V(SlotIndexBits, unsigned, 19, _)
V(SlotIndexBits, unsigned, 18, _) \
V(ImmutabilityBit, bool, 1, _)
DEFINE_BIT_FIELDS(LEXICAL_MODE_BIT_FIELDS)
#undef LEXICAL_MODE_BIT_FIELDS

View File

@ -501,8 +501,9 @@ MaybeHandle<Object> LoadGlobalIC::Load(Handle<Name> name) {
}
if (FLAG_use_ic) {
if (nexus()->ConfigureLexicalVarMode(lookup_result.context_index,
lookup_result.slot_index)) {
if (nexus()->ConfigureLexicalVarMode(
lookup_result.context_index, lookup_result.slot_index,
lookup_result.mode == VariableMode::kConst)) {
TRACE_HANDLER_STATS(isolate(), LoadGlobalIC_LoadScriptContextField);
} else {
// Given combination of indices can't be encoded, so use slow stub.
@ -1358,8 +1359,9 @@ MaybeHandle<Object> StoreGlobalIC::Store(Handle<Name> name,
}
if (FLAG_use_ic) {
if (nexus()->ConfigureLexicalVarMode(lookup_result.context_index,
lookup_result.slot_index)) {
if (nexus()->ConfigureLexicalVarMode(
lookup_result.context_index, lookup_result.slot_index,
lookup_result.mode == VariableMode::kConst)) {
TRACE_HANDLER_STATS(isolate(), StoreGlobalIC_StoreScriptContextField);
} else {
// Given combination of indices can't be encoded, so use slow stub.