[turbofan] Preprocess context slots for immutable global context loads
Main changes: ContextData class to hold a map of slots to ObjectData for known necessary lookups. LdaGlobal* and StaGlobal now receive an accumulator hint of the constant found at the lookup slot for immutable global context operations. Bug: v8:7790 Change-Id: I63dc9eb8ebbbdfa4ce3b71c6aba63b3c06a3da9b Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1532074 Reviewed-by: Georg Neis <neis@chromium.org> Commit-Queue: Michael Stanton <mvstanton@chromium.org> Cr-Commit-Position: refs/heads/master@{#60386}
This commit is contained in:
parent
c4eae87a1a
commit
9b929cdc65
@ -144,7 +144,7 @@ Reduction JSContextSpecialization::ReduceJSLoadContext(Node* node) {
|
||||
|
||||
// Now walk up the concrete context chain for the remaining depth.
|
||||
ContextRef concrete = maybe_concrete.value();
|
||||
concrete.Serialize(); // TODO(neis): Remove later.
|
||||
concrete.SerializeContextChain(); // TODO(neis): Remove later.
|
||||
for (; depth > 0; --depth) {
|
||||
concrete = concrete.previous();
|
||||
}
|
||||
@ -158,6 +158,7 @@ Reduction JSContextSpecialization::ReduceJSLoadContext(Node* node) {
|
||||
// This will hold the final value, if we can figure it out.
|
||||
base::Optional<ObjectRef> maybe_value;
|
||||
|
||||
concrete.SerializeSlot(static_cast<int>(access.index()));
|
||||
maybe_value = concrete.get(static_cast<int>(access.index()));
|
||||
if (maybe_value.has_value() && !maybe_value->IsSmi()) {
|
||||
// Even though the context slot is immutable, the context might have escaped
|
||||
@ -206,7 +207,7 @@ Reduction JSContextSpecialization::ReduceJSStoreContext(Node* node) {
|
||||
|
||||
// Now walk up the concrete context chain for the remaining depth.
|
||||
ContextRef concrete = maybe_concrete.value();
|
||||
concrete.Serialize(); // TODO(neis): Remove later.
|
||||
concrete.SerializeContextChain(); // TODO(neis): Remove later.
|
||||
for (; depth > 0; --depth) {
|
||||
concrete = concrete.previous();
|
||||
}
|
||||
|
@ -406,37 +406,55 @@ class ContextData : public HeapObjectData {
|
||||
public:
|
||||
ContextData(JSHeapBroker* broker, ObjectData** storage,
|
||||
Handle<Context> object);
|
||||
void Serialize(JSHeapBroker* broker);
|
||||
void SerializeContextChain(JSHeapBroker* broker);
|
||||
|
||||
ContextData* previous() const {
|
||||
CHECK(serialized_);
|
||||
CHECK(serialized_context_chain_);
|
||||
return previous_;
|
||||
}
|
||||
|
||||
void SerializeSlot(JSHeapBroker* broker, int index);
|
||||
|
||||
ObjectData* GetSlot(int index) {
|
||||
auto search = slots_.find(index);
|
||||
CHECK(search != slots_.end());
|
||||
return search->second;
|
||||
}
|
||||
|
||||
private:
|
||||
bool serialized_ = false;
|
||||
ZoneMap<int, ObjectData*> slots_;
|
||||
bool serialized_context_chain_ = false;
|
||||
ContextData* previous_ = nullptr;
|
||||
};
|
||||
|
||||
ContextData::ContextData(JSHeapBroker* broker, ObjectData** storage,
|
||||
Handle<Context> object)
|
||||
: HeapObjectData(broker, storage, object) {}
|
||||
: HeapObjectData(broker, storage, object), slots_(broker->zone()) {}
|
||||
|
||||
void ContextData::Serialize(JSHeapBroker* broker) {
|
||||
if (serialized_) return;
|
||||
serialized_ = true;
|
||||
void ContextData::SerializeContextChain(JSHeapBroker* broker) {
|
||||
if (serialized_context_chain_) return;
|
||||
serialized_context_chain_ = true;
|
||||
|
||||
TraceScope tracer(broker, this, "ContextData::Serialize");
|
||||
TraceScope tracer(broker, this, "ContextData::SerializeContextChain");
|
||||
Handle<Context> context = Handle<Context>::cast(object());
|
||||
|
||||
DCHECK_NULL(previous_);
|
||||
// Context::previous DCHECK-fails when called on the native context.
|
||||
if (!context->IsNativeContext()) {
|
||||
previous_ = broker->GetOrCreateData(context->previous())->AsContext();
|
||||
previous_->Serialize(broker);
|
||||
previous_->SerializeContextChain(broker);
|
||||
}
|
||||
}
|
||||
|
||||
void ContextData::SerializeSlot(JSHeapBroker* broker, int index) {
|
||||
TraceScope tracer(broker, this, "ContextData::SerializeSlot");
|
||||
TRACE(broker, "Serializing script context slot " << index << ".");
|
||||
Handle<Context> context = Handle<Context>::cast(object());
|
||||
CHECK(index >= 0 && index < context->length());
|
||||
ObjectData* odata = broker->GetOrCreateData(context->get(index));
|
||||
slots_.insert(std::make_pair(index, odata));
|
||||
}
|
||||
|
||||
class NativeContextData : public ContextData {
|
||||
public:
|
||||
#define DECL_ACCESSOR(type, name) \
|
||||
@ -1574,10 +1592,13 @@ ContextRef ContextRef::previous() const {
|
||||
|
||||
// Not needed for TypedLowering.
|
||||
ObjectRef ContextRef::get(int index) const {
|
||||
AllowHandleAllocation handle_allocation;
|
||||
AllowHandleDereference handle_dereference;
|
||||
Handle<Object> value(object()->get(index), broker()->isolate());
|
||||
return ObjectRef(broker(), value);
|
||||
if (broker()->mode() == JSHeapBroker::kDisabled) {
|
||||
AllowHandleAllocation handle_allocation;
|
||||
AllowHandleDereference handle_dereference;
|
||||
Handle<Object> value(object()->get(index), broker()->isolate());
|
||||
return ObjectRef(broker(), value);
|
||||
}
|
||||
return ObjectRef(broker(), data()->AsContext()->GetSlot(index));
|
||||
}
|
||||
|
||||
JSHeapBroker::JSHeapBroker(Isolate* isolate, Zone* broker_zone)
|
||||
@ -2813,10 +2834,16 @@ void ModuleRef::Serialize() {
|
||||
data()->AsModule()->Serialize(broker());
|
||||
}
|
||||
|
||||
void ContextRef::Serialize() {
|
||||
void ContextRef::SerializeContextChain() {
|
||||
if (broker()->mode() == JSHeapBroker::kDisabled) return;
|
||||
CHECK_EQ(broker()->mode(), JSHeapBroker::kSerializing);
|
||||
data()->AsContext()->Serialize(broker());
|
||||
data()->AsContext()->SerializeContextChain(broker());
|
||||
}
|
||||
|
||||
void ContextRef::SerializeSlot(int index) {
|
||||
if (broker()->mode() == JSHeapBroker::kDisabled) return;
|
||||
CHECK_EQ(broker()->mode(), JSHeapBroker::kSerializing);
|
||||
data()->AsContext()->SerializeSlot(broker(), index);
|
||||
}
|
||||
|
||||
void NativeContextRef::Serialize() {
|
||||
@ -2898,6 +2925,15 @@ bool GlobalAccessFeedback::immutable() const {
|
||||
return FeedbackNexus::ImmutabilityBit::decode(index_and_immutable_);
|
||||
}
|
||||
|
||||
base::Optional<ObjectRef> GlobalAccessFeedback::GetConstantValue() const {
|
||||
if (IsScriptContextSlot() && immutable()) {
|
||||
// Return the value of this global variable if it's guaranteed to be
|
||||
// constant.
|
||||
return script_context().get(slot_index());
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
ElementAccessFeedback::ElementAccessFeedback(Zone* zone)
|
||||
: ProcessedFeedback(kElementAccess),
|
||||
receiver_maps(zone),
|
||||
@ -3053,8 +3089,12 @@ GlobalAccessFeedback const* JSHeapBroker::ProcessFeedbackForGlobalAccess(
|
||||
CHECK(!contents.equals(
|
||||
ObjectRef(this, isolate()->factory()->the_hole_value())));
|
||||
}
|
||||
return new (zone()) GlobalAccessFeedback(ContextRef(this, context),
|
||||
context_slot_index, immutable);
|
||||
ContextRef context_ref(this, context);
|
||||
if (immutable) {
|
||||
context_ref.SerializeSlot(context_slot_index);
|
||||
}
|
||||
return new (zone())
|
||||
GlobalAccessFeedback(context_ref, context_slot_index, immutable);
|
||||
}
|
||||
|
||||
CHECK(feedback_value->IsPropertyCell());
|
||||
|
@ -286,8 +286,10 @@ class ContextRef : public HeapObjectRef {
|
||||
using HeapObjectRef::HeapObjectRef;
|
||||
Handle<Context> object() const;
|
||||
|
||||
void Serialize();
|
||||
void SerializeContextChain();
|
||||
ContextRef previous() const;
|
||||
|
||||
void SerializeSlot(int index);
|
||||
ObjectRef get(int index) const;
|
||||
};
|
||||
|
||||
@ -651,6 +653,8 @@ class GlobalAccessFeedback : public ProcessedFeedback {
|
||||
int slot_index() const;
|
||||
bool immutable() const;
|
||||
|
||||
base::Optional<ObjectRef> GetConstantValue() const;
|
||||
|
||||
private:
|
||||
ObjectRef const cell_or_context_;
|
||||
int const index_and_immutable_;
|
||||
|
@ -31,7 +31,7 @@ Reduction JSHeapCopyReducer::Reduce(Node* node) {
|
||||
if (object.IsJSFunction()) object.AsJSFunction().Serialize();
|
||||
if (object.IsJSObject()) object.AsJSObject().SerializeObjectCreateMap();
|
||||
if (object.IsModule()) object.AsModule().Serialize();
|
||||
if (object.IsContext()) object.AsContext().Serialize();
|
||||
if (object.IsContext()) object.AsContext().SerializeContextChain();
|
||||
break;
|
||||
}
|
||||
case IrOpcode::kJSCreateArray: {
|
||||
|
@ -683,27 +683,33 @@ void SerializerForBackgroundCompilation::VisitConstructWithSpread(
|
||||
ProcessCallOrConstruct(callee, new_target, arguments, slot, true);
|
||||
}
|
||||
|
||||
void SerializerForBackgroundCompilation::ProcessFeedbackForGlobalAccess(
|
||||
GlobalAccessFeedback const*
|
||||
SerializerForBackgroundCompilation::ProcessFeedbackForGlobalAccess(
|
||||
FeedbackSlot slot) {
|
||||
if (slot.IsInvalid()) return;
|
||||
if (environment()->function().feedback_vector.is_null()) return;
|
||||
if (slot.IsInvalid()) return nullptr;
|
||||
if (environment()->function().feedback_vector.is_null()) return nullptr;
|
||||
FeedbackSource source(environment()->function().feedback_vector, slot);
|
||||
if (!broker()->HasFeedback(source)) {
|
||||
broker()->SetFeedback(source,
|
||||
broker()->ProcessFeedbackForGlobalAccess(source));
|
||||
const GlobalAccessFeedback* feedback =
|
||||
broker()->ProcessFeedbackForGlobalAccess(source);
|
||||
broker()->SetFeedback(source, feedback);
|
||||
return feedback;
|
||||
}
|
||||
// TODO(neis, mvstanton): In the case of an immutable script context slot, we
|
||||
// must also serialize that slot such that ContextRef::get can retrieve the
|
||||
// value.
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void SerializerForBackgroundCompilation::VisitLdaGlobal(
|
||||
BytecodeArrayIterator* iterator) {
|
||||
FeedbackSlot slot = iterator->GetSlotOperand(1);
|
||||
ProcessFeedbackForGlobalAccess(slot);
|
||||
// TODO(neis, mvstanton): In the case of an immutable script context slot, add
|
||||
// the value as constant hint here and below
|
||||
environment()->accumulator_hints().Clear();
|
||||
GlobalAccessFeedback const* feedback = ProcessFeedbackForGlobalAccess(slot);
|
||||
if (feedback != nullptr) {
|
||||
// We may be able to contribute to accumulator constant hints.
|
||||
base::Optional<ObjectRef> value = feedback->GetConstantValue();
|
||||
if (value.has_value()) {
|
||||
environment()->accumulator_hints().AddConstant(value->object());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SerializerForBackgroundCompilation::VisitLdaGlobalInsideTypeof(
|
||||
|
@ -248,7 +248,7 @@ class SerializerForBackgroundCompilation {
|
||||
base::Optional<Hints> new_target,
|
||||
const HintsVector& arguments, bool with_spread);
|
||||
|
||||
void ProcessFeedbackForGlobalAccess(FeedbackSlot slot);
|
||||
GlobalAccessFeedback const* ProcessFeedbackForGlobalAccess(FeedbackSlot slot);
|
||||
void ProcessFeedbackForKeyedPropertyAccess(FeedbackSlot slot,
|
||||
AccessMode mode);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user