summaryrefslogtreecommitdiff
path: root/deps/v8/src/compiler/js-native-context-specialization.cc
diff options
context:
space:
mode:
Diffstat (limited to 'deps/v8/src/compiler/js-native-context-specialization.cc')
-rw-r--r--deps/v8/src/compiler/js-native-context-specialization.cc849
1 files changed, 393 insertions, 456 deletions
diff --git a/deps/v8/src/compiler/js-native-context-specialization.cc b/deps/v8/src/compiler/js-native-context-specialization.cc
index 8a3fab5e6e..68f6541ab0 100644
--- a/deps/v8/src/compiler/js-native-context-specialization.cc
+++ b/deps/v8/src/compiler/js-native-context-specialization.cc
@@ -67,8 +67,7 @@ JSNativeContextSpecialization::JSNativeContextSpecialization(
broker_(broker),
flags_(flags),
global_object_(native_context->global_object(), jsgraph->isolate()),
- global_proxy_(JSGlobalProxy::cast(native_context->global_proxy()),
- jsgraph->isolate()),
+ global_proxy_(native_context->global_proxy(), jsgraph->isolate()),
dependencies_(dependencies),
zone_(zone),
shared_zone_(shared_zone),
@@ -354,8 +353,12 @@ Reduction JSNativeContextSpecialization::ReduceJSGetSuperConstructor(
if (!m.HasValue()) return NoChange();
JSFunctionRef function = m.Ref(broker()).AsJSFunction();
MapRef function_map = function.map();
- // TODO(neis): Remove SerializePrototype call once brokerization is complete.
- function_map.SerializePrototype();
+ if (!FLAG_concurrent_inlining) {
+ function_map.SerializePrototype();
+ } else if (!function_map.serialized_prototype()) {
+ TRACE_BROKER_MISSING(broker(), "data for map " << function_map);
+ return NoChange();
+ }
ObjectRef function_prototype = function_map.prototype();
// We can constant-fold the super constructor access if the
@@ -397,16 +400,12 @@ Reduction JSNativeContextSpecialization::ReduceJSInstanceOf(Node* node) {
Handle<Map> receiver_map(receiver->map(), isolate());
// Compute property access info for @@hasInstance on the constructor.
- PropertyAccessInfo access_info;
AccessInfoFactory access_info_factory(broker(), dependencies(),
graph()->zone());
- if (!access_info_factory.ComputePropertyAccessInfo(
- receiver_map, factory()->has_instance_symbol(), AccessMode::kLoad,
- &access_info)) {
- return NoChange();
- }
- DCHECK_EQ(access_info.receiver_maps().size(), 1);
- DCHECK_EQ(access_info.receiver_maps()[0].address(), receiver_map.address());
+ PropertyAccessInfo access_info =
+ access_info_factory.ComputePropertyAccessInfo(
+ receiver_map, factory()->has_instance_symbol(), AccessMode::kLoad);
+ if (access_info.IsInvalid()) return NoChange();
PropertyAccessBuilder access_builder(jsgraph(), broker(), dependencies());
@@ -415,12 +414,8 @@ Reduction JSNativeContextSpecialization::ReduceJSInstanceOf(Node* node) {
// takes over, but that requires the constructor to be callable.
if (!receiver_map->is_callable()) return NoChange();
- // Determine actual holder and perform prototype chain checks.
- Handle<JSObject> holder;
- if (access_info.holder().ToHandle(&holder)) {
- dependencies()->DependOnStablePrototypeChains(
- access_info.receiver_maps(), JSObjectRef(broker(), holder));
- }
+ dependencies()->DependOnStablePrototypeChains(access_info.receiver_maps(),
+ kStartAtPrototype);
// Monomorphic property access.
constructor =
@@ -474,7 +469,8 @@ Reduction JSNativeContextSpecialization::ReduceJSInstanceOf(Node* node) {
if (found_on_proto) {
dependencies()->DependOnStablePrototypeChains(
- access_info.receiver_maps(), JSObjectRef(broker(), holder));
+ access_info.receiver_maps(), kStartAtPrototype,
+ JSObjectRef(broker(), holder));
}
DCHECK(constant->IsCallable());
@@ -531,8 +527,9 @@ JSNativeContextSpecialization::InferHasInPrototypeChain(
&receiver_maps);
if (result == NodeProperties::kNoReceiverMaps) return kMayBeInPrototypeChain;
- // Check if either all or none of the {receiver_maps} have the given
- // {prototype} in their prototype chain.
+ // Try to determine either that all of the {receiver_maps} have the given
+ // {prototype} in their chain, or that none do. If we can't tell, return
+ // kMayBeInPrototypeChain.
bool all = true;
bool none = true;
for (size_t i = 0; i < receiver_maps.size(); ++i) {
@@ -540,22 +537,17 @@ JSNativeContextSpecialization::InferHasInPrototypeChain(
if (receiver_map->instance_type() <= LAST_SPECIAL_RECEIVER_TYPE) {
return kMayBeInPrototypeChain;
}
- if (result == NodeProperties::kUnreliableReceiverMaps) {
- // In case of an unreliable {result} we need to ensure that all
- // {receiver_maps} are stable, because otherwise we cannot trust
- // the {receiver_maps} information, since arbitrary side-effects
- // may have happened.
- if (!receiver_map->is_stable()) {
- return kMayBeInPrototypeChain;
- }
+ if (result == NodeProperties::kUnreliableReceiverMaps &&
+ !receiver_map->is_stable()) {
+ return kMayBeInPrototypeChain;
}
- for (PrototypeIterator j(isolate(), receiver_map);; j.Advance()) {
- if (j.IsAtEnd()) {
+ for (PrototypeIterator it(isolate(), receiver_map);; it.Advance()) {
+ if (it.IsAtEnd()) {
all = false;
break;
}
- Handle<HeapObject> const current =
- PrototypeIterator::GetCurrent<HeapObject>(j);
+ Handle<HeapObject> current =
+ PrototypeIterator::GetCurrent<HeapObject>(it);
if (current.is_identical_to(prototype)) {
none = false;
break;
@@ -567,10 +559,29 @@ JSNativeContextSpecialization::InferHasInPrototypeChain(
}
}
DCHECK_IMPLIES(all, !none);
+ if (!all && !none) return kMayBeInPrototypeChain;
+
+ {
+ base::Optional<JSObjectRef> last_prototype;
+ if (all) {
+ // We don't need to protect the full chain if we found the prototype, we
+ // can stop at {prototype}. In fact we could stop at the one before
+ // {prototype} but since we're dealing with multiple receiver maps this
+ // might be a different object each time, so it's much simpler to include
+ // {prototype}. That does, however, mean that we must check {prototype}'s
+ // map stability.
+ if (!prototype->map()->is_stable()) return kMayBeInPrototypeChain;
+ last_prototype.emplace(broker(), Handle<JSObject>::cast(prototype));
+ }
+ WhereToStart start = result == NodeProperties::kUnreliableReceiverMaps
+ ? kStartAtReceiver
+ : kStartAtPrototype;
+ dependencies()->DependOnStablePrototypeChains(receiver_maps, start,
+ last_prototype);
+ }
- if (all) return kIsInPrototypeChain;
- if (none) return kIsNotInPrototypeChain;
- return kMayBeInPrototypeChain;
+ DCHECK_EQ(all, !none);
+ return all ? kIsInPrototypeChain : kIsNotInPrototypeChain;
}
Reduction JSNativeContextSpecialization::ReduceJSHasInPrototypeChain(
@@ -714,33 +725,22 @@ Reduction JSNativeContextSpecialization::ReduceJSResolvePromise(Node* node) {
}
// Compute property access info for "then" on {resolution}.
- PropertyAccessInfo access_info;
AccessInfoFactory access_info_factory(broker(), dependencies(),
graph()->zone());
- if (!access_info_factory.ComputePropertyAccessInfo(
+ PropertyAccessInfo access_info =
+ access_info_factory.ComputePropertyAccessInfo(
MapHandles(resolution_maps.begin(), resolution_maps.end()),
- factory()->then_string(), AccessMode::kLoad, &access_info)) {
- return NoChange();
- }
+ factory()->then_string(), AccessMode::kLoad);
+ if (access_info.IsInvalid()) return NoChange();
// We can further optimize the case where {resolution}
// definitely doesn't have a "then" property.
if (!access_info.IsNotFound()) return NoChange();
- PropertyAccessBuilder access_builder(jsgraph(), broker(), dependencies());
- // Add proper dependencies on the {resolution}s [[Prototype]]s.
- Handle<JSObject> holder;
- if (access_info.holder().ToHandle(&holder)) {
- dependencies()->DependOnStablePrototypeChains(
- access_info.receiver_maps(), JSObjectRef(broker(), holder));
- }
-
- // Add stability dependencies on the {resolution_maps}.
- if (result == NodeProperties::kUnreliableReceiverMaps) {
- for (Handle<Map> resolution_map : resolution_maps) {
- dependencies()->DependOnStableMap(MapRef(broker(), resolution_map));
- }
- }
+ dependencies()->DependOnStablePrototypeChains(
+ access_info.receiver_maps(),
+ result == NodeProperties::kUnreliableReceiverMaps ? kStartAtReceiver
+ : kStartAtPrototype);
// Simply fulfill the {promise} with the {resolution}.
Node* value = effect =
@@ -768,7 +768,7 @@ namespace {
FieldAccess ForPropertyCellValue(MachineRepresentation representation,
Type type, MaybeHandle<Map> map,
- Handle<Name> name) {
+ NameRef const& name) {
WriteBarrierKind kind = kFullWriteBarrier;
if (representation == MachineRepresentation::kTaggedSigned) {
kind = kNoWriteBarrier;
@@ -777,39 +777,38 @@ FieldAccess ForPropertyCellValue(MachineRepresentation representation,
}
MachineType r = MachineType::TypeForRepresentation(representation);
FieldAccess access = {
- kTaggedBase, PropertyCell::kValueOffset, name, map, type, r, kind};
+ kTaggedBase, PropertyCell::kValueOffset, name.object(), map, type, r,
+ kind};
return access;
}
} // namespace
Reduction JSNativeContextSpecialization::ReduceGlobalAccess(
- Node* node, Node* receiver, Node* value, Handle<Name> name,
- AccessMode access_mode, Node* index) {
- // 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);
- it.TryLookupCachedProperty();
- if (it.state() != LookupIterator::DATA) return NoChange();
- if (!it.GetHolder<JSObject>()->IsJSGlobalObject()) return NoChange();
- Handle<PropertyCell> property_cell = it.GetPropertyCell();
- return ReduceGlobalAccess(node, receiver, value, name, access_mode, index,
- property_cell);
+ Node* node, Node* receiver, Node* value, NameRef const& name,
+ AccessMode access_mode, Node* key) {
+ base::Optional<PropertyCellRef> cell =
+ native_context().global_proxy_object().GetPropertyCell(name);
+ return cell.has_value() ? ReduceGlobalAccess(node, receiver, value, name,
+ access_mode, key, *cell)
+ : NoChange();
}
Reduction JSNativeContextSpecialization::ReduceGlobalAccess(
- Node* node, Node* receiver, Node* value, Handle<Name> name,
- AccessMode access_mode, Node* index, Handle<PropertyCell> property_cell) {
+ Node* node, Node* receiver, Node* value, NameRef const& name,
+ AccessMode access_mode, Node* key, PropertyCellRef const& 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())) {
+ ObjectRef property_cell_value = property_cell.value();
+ if (property_cell_value.IsHeapObject() &&
+ property_cell_value.AsHeapObject().map().oddball_type() ==
+ OddballType::kHole) {
// The property cell is no longer valid.
return NoChange();
}
- PropertyDetails property_details = property_cell->property_details();
+ PropertyDetails property_details = property_cell.property_details();
PropertyCellType property_cell_type = property_details.cell_type();
DCHECK_EQ(kData, property_details.kind());
@@ -824,8 +823,8 @@ Reduction JSNativeContextSpecialization::ReduceGlobalAccess(
} else if (property_cell_type == PropertyCellType::kConstantType) {
// There's also no fast-path to store to a global cell which pretended
// to be stable, but is no longer stable now.
- if (property_cell_value->IsHeapObject() &&
- !Handle<HeapObject>::cast(property_cell_value)->map()->is_stable()) {
+ if (property_cell_value.IsHeapObject() &&
+ !property_cell_value.AsHeapObject().map().is_stable()) {
return NoChange();
}
}
@@ -838,9 +837,9 @@ Reduction JSNativeContextSpecialization::ReduceGlobalAccess(
return NoChange();
}
- // Ensure that {index} matches the specified {name} (if {index} is given).
- if (index != nullptr) {
- effect = BuildCheckEqualsName(name, index, effect, control);
+ // Ensure that {key} matches the specified {name} (if {key} is given).
+ if (key != nullptr) {
+ effect = BuildCheckEqualsName(name, key, effect, control);
}
// Check if we have a {receiver} to validate. If so, we need to check that
@@ -867,8 +866,7 @@ Reduction JSNativeContextSpecialization::ReduceGlobalAccess(
// can be deleted or reconfigured to an accessor property).
if (property_details.cell_type() != PropertyCellType::kMutable ||
property_details.IsConfigurable()) {
- dependencies()->DependOnGlobalProperty(
- PropertyCellRef(broker(), property_cell));
+ dependencies()->DependOnGlobalProperty(property_cell);
}
// Load from constant/undefined global property can be constant-folded.
@@ -877,8 +875,9 @@ Reduction JSNativeContextSpecialization::ReduceGlobalAccess(
value = access_mode == AccessMode::kHas
? jsgraph()->TrueConstant()
: jsgraph()->Constant(property_cell_value);
- CHECK(
- !property_cell_value.is_identical_to(factory()->the_hole_value()));
+ DCHECK(!property_cell_value.IsHeapObject() ||
+ property_cell_value.AsHeapObject().map().oddball_type() !=
+ OddballType::kHole);
} else {
DCHECK_NE(AccessMode::kHas, access_mode);
@@ -888,16 +887,15 @@ Reduction JSNativeContextSpecialization::ReduceGlobalAccess(
MachineRepresentation representation = MachineRepresentation::kTagged;
if (property_details.cell_type() == PropertyCellType::kConstantType) {
// Compute proper type based on the current value in the cell.
- if (property_cell_value->IsSmi()) {
+ if (property_cell_value.IsSmi()) {
property_cell_value_type = Type::SignedSmall();
representation = MachineRepresentation::kTaggedSigned;
- } else if (property_cell_value->IsNumber()) {
+ } else if (property_cell_value.IsHeapNumber()) {
property_cell_value_type = Type::Number();
representation = MachineRepresentation::kTaggedPointer;
} else {
- MapRef property_cell_value_map(
- broker(), handle(HeapObject::cast(*property_cell_value)->map(),
- isolate()));
+ MapRef property_cell_value_map =
+ property_cell_value.AsHeapObject().map();
property_cell_value_type = Type::For(property_cell_value_map);
representation = MachineRepresentation::kTaggedPointer;
@@ -913,7 +911,7 @@ Reduction JSNativeContextSpecialization::ReduceGlobalAccess(
value = effect = graph()->NewNode(
simplified()->LoadField(ForPropertyCellValue(
representation, property_cell_value_type, map, name)),
- jsgraph()->HeapConstant(property_cell), effect, control);
+ jsgraph()->Constant(property_cell), effect, control);
}
}
} else {
@@ -927,8 +925,7 @@ Reduction JSNativeContextSpecialization::ReduceGlobalAccess(
case PropertyCellType::kConstant: {
// Record a code dependency on the cell, and just deoptimize if the new
// value doesn't match the previous value stored inside the cell.
- dependencies()->DependOnGlobalProperty(
- PropertyCellRef(broker(), property_cell));
+ dependencies()->DependOnGlobalProperty(property_cell);
Node* check =
graph()->NewNode(simplified()->ReferenceEqual(), value,
jsgraph()->Constant(property_cell_value));
@@ -941,29 +938,26 @@ Reduction JSNativeContextSpecialization::ReduceGlobalAccess(
// Record a code dependency on the cell, and just deoptimize if the new
// values' type doesn't match the type of the previous value in the
// cell.
- dependencies()->DependOnGlobalProperty(
- PropertyCellRef(broker(), property_cell));
+ dependencies()->DependOnGlobalProperty(property_cell);
Type property_cell_value_type;
MachineRepresentation representation = MachineRepresentation::kTagged;
- if (property_cell_value->IsHeapObject()) {
+ if (property_cell_value.IsHeapObject()) {
// We cannot do anything if the {property_cell_value}s map is no
// longer stable.
- Handle<Map> property_cell_value_map(
- Handle<HeapObject>::cast(property_cell_value)->map(), isolate());
- DCHECK(property_cell_value_map->is_stable());
- dependencies()->DependOnStableMap(
- MapRef(broker(), property_cell_value_map));
+ MapRef property_cell_value_map =
+ property_cell_value.AsHeapObject().map();
+ dependencies()->DependOnStableMap(property_cell_value_map);
// Check that the {value} is a HeapObject.
value = effect = graph()->NewNode(simplified()->CheckHeapObject(),
value, effect, control);
// Check {value} map against the {property_cell} map.
- effect =
- graph()->NewNode(simplified()->CheckMaps(
- CheckMapsFlag::kNone,
- ZoneHandleSet<Map>(property_cell_value_map)),
- value, effect, control);
+ effect = graph()->NewNode(
+ simplified()->CheckMaps(
+ CheckMapsFlag::kNone,
+ ZoneHandleSet<Map>(property_cell_value_map.object())),
+ value, effect, control);
property_cell_value_type = Type::OtherInternal();
representation = MachineRepresentation::kTaggedPointer;
} else {
@@ -976,20 +970,19 @@ Reduction JSNativeContextSpecialization::ReduceGlobalAccess(
effect = graph()->NewNode(simplified()->StoreField(ForPropertyCellValue(
representation, property_cell_value_type,
MaybeHandle<Map>(), name)),
- jsgraph()->HeapConstant(property_cell), value,
+ jsgraph()->Constant(property_cell), value,
effect, control);
break;
}
case PropertyCellType::kMutable: {
// Record a code dependency on the cell, and just deoptimize if the
// property ever becomes read-only.
- dependencies()->DependOnGlobalProperty(
- PropertyCellRef(broker(), property_cell));
+ dependencies()->DependOnGlobalProperty(property_cell);
effect = graph()->NewNode(
simplified()->StoreField(ForPropertyCellValue(
MachineRepresentation::kTagged, Type::NonInternal(),
MaybeHandle<Map>(), name)),
- jsgraph()->HeapConstant(property_cell), value, effect, control);
+ jsgraph()->Constant(property_cell), value, effect, control);
break;
}
}
@@ -1001,109 +994,75 @@ Reduction JSNativeContextSpecialization::ReduceGlobalAccess(
Reduction JSNativeContextSpecialization::ReduceJSLoadGlobal(Node* node) {
DCHECK_EQ(IrOpcode::kJSLoadGlobal, node->opcode());
- Node* effect = NodeProperties::GetEffectInput(node);
+ DisallowHeapAccessIf no_heap_acess(FLAG_concurrent_inlining);
LoadGlobalParameters const& p = LoadGlobalParametersOf(node->op());
if (!p.feedback().IsValid()) return NoChange();
- FeedbackNexus nexus(p.feedback().vector(), p.feedback().slot());
+ FeedbackSource source(p.feedback());
- DCHECK(nexus.kind() == FeedbackSlotKind::kLoadGlobalInsideTypeof ||
- nexus.kind() == FeedbackSlotKind::kLoadGlobalNotInsideTypeof);
- if (nexus.ic_state() != MONOMORPHIC || 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 number = feedback->Number();
- int const script_context_index =
- FeedbackNexus::ContextIndexBits::decode(number);
- int const context_slot_index = FeedbackNexus::SlotIndexBits::decode(number);
- bool const immutable = FeedbackNexus::ImmutabilityBit::decode(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())));
- }
+ GlobalAccessFeedback const* processed =
+ FLAG_concurrent_inlining
+ ? broker()->GetGlobalAccessFeedback(source)
+ : broker()->ProcessFeedbackForGlobalAccess(source);
+ if (processed == nullptr) return NoChange();
- Node* context_constant = jsgraph()->Constant(context);
- Node* value = effect = graph()->NewNode(
- javascript()->LoadContext(0, context_slot_index, immutable),
- context_constant, effect);
+ if (processed->IsScriptContextSlot()) {
+ Node* effect = NodeProperties::GetEffectInput(node);
+ Node* script_context = jsgraph()->Constant(processed->script_context());
+ Node* value = effect =
+ graph()->NewNode(javascript()->LoadContext(0, processed->slot_index(),
+ processed->immutable()),
+ script_context, effect);
ReplaceWithValue(node, value, effect);
return Replace(value);
}
- 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));
+ CHECK(processed->IsPropertyCell());
+ return ReduceGlobalAccess(node, nullptr, nullptr, NameRef(broker(), p.name()),
+ AccessMode::kLoad, nullptr,
+ processed->property_cell());
}
Reduction JSNativeContextSpecialization::ReduceJSStoreGlobal(Node* node) {
DCHECK_EQ(IrOpcode::kJSStoreGlobal, node->opcode());
+ DisallowHeapAccessIf no_heap_acess(FLAG_concurrent_inlining);
+
Node* value = NodeProperties::GetValueInput(node, 0);
- Node* effect = NodeProperties::GetEffectInput(node);
- Node* control = NodeProperties::GetControlInput(node);
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.ic_state() != MONOMORPHIC || 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);
+ FeedbackSource source(p.feedback());
- if (immutable) return NoChange();
+ GlobalAccessFeedback const* processed =
+ FLAG_concurrent_inlining
+ ? broker()->GetGlobalAccessFeedback(source)
+ : broker()->ProcessFeedbackForGlobalAccess(source);
+ if (processed == nullptr) return NoChange();
- {
- ObjectRef contents(broker(),
- handle(context->get(context_slot_index), isolate()));
- CHECK(!contents.equals(ObjectRef(broker(), factory()->the_hole_value())));
- }
-
- Node* context_constant = jsgraph()->Constant(context);
- effect = graph()->NewNode(javascript()->StoreContext(0, context_slot_index),
- value, context_constant, effect, control);
+ if (processed->IsScriptContextSlot()) {
+ if (processed->immutable()) return NoChange();
+ Node* effect = NodeProperties::GetEffectInput(node);
+ Node* control = NodeProperties::GetControlInput(node);
+ Node* script_context = jsgraph()->Constant(processed->script_context());
+ effect =
+ graph()->NewNode(javascript()->StoreContext(0, processed->slot_index()),
+ value, script_context, effect, control);
ReplaceWithValue(node, value, effect, control);
return Replace(value);
}
- 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));
+ if (processed->IsPropertyCell()) {
+ return ReduceGlobalAccess(node, nullptr, value, NameRef(broker(), p.name()),
+ AccessMode::kStore, nullptr,
+ processed->property_cell());
+ }
+
+ UNREACHABLE();
}
Reduction JSNativeContextSpecialization::ReduceNamedAccess(
- Node* node, Node* value, MapHandles const& receiver_maps, Handle<Name> name,
- AccessMode access_mode, Node* index) {
+ Node* node, Node* value, MapHandles const& receiver_maps,
+ NameRef const& name, AccessMode access_mode, Node* key) {
DCHECK(node->opcode() == IrOpcode::kJSLoadNamed ||
node->opcode() == IrOpcode::kJSStoreNamed ||
node->opcode() == IrOpcode::kJSLoadProperty ||
@@ -1120,37 +1079,27 @@ Reduction JSNativeContextSpecialization::ReduceNamedAccess(
// native contexts' global proxy, and turn that into a direct access
// to the current native contexts' global object instead.
if (receiver_maps.size() == 1) {
- Handle<Map> receiver_map = receiver_maps.front();
- if (receiver_map->IsJSGlobalProxyMap()) {
- Object maybe_constructor = receiver_map->GetConstructor();
- // Detached global proxies have |null| as their constructor.
- if (maybe_constructor->IsJSFunction() &&
- JSFunction::cast(maybe_constructor)->native_context() ==
- *native_context().object()) {
- return ReduceGlobalAccess(node, receiver, value, name, access_mode,
- index);
- }
+ MapRef receiver_map(broker(), receiver_maps.front());
+ if (receiver_map.IsMapOfCurrentGlobalProxy()) {
+ return ReduceGlobalAccess(node, receiver, value, name, access_mode, key);
}
}
// Compute property access infos for the receiver maps.
AccessInfoFactory access_info_factory(broker(), dependencies(),
graph()->zone());
+ ZoneVector<PropertyAccessInfo> raw_access_infos(zone());
+ access_info_factory.ComputePropertyAccessInfos(
+ receiver_maps, name.object(), access_mode, &raw_access_infos);
ZoneVector<PropertyAccessInfo> access_infos(zone());
- if (!access_info_factory.ComputePropertyAccessInfos(
- receiver_maps, name, access_mode, &access_infos)) {
+ if (!access_info_factory.FinalizePropertyAccessInfos(
+ raw_access_infos, access_mode, &access_infos)) {
return NoChange();
}
- // Nothing to do if we have no non-deprecated maps.
- if (access_infos.empty()) {
- return ReduceSoftDeoptimize(
- node, DeoptimizeReason::kInsufficientTypeFeedbackForGenericNamedAccess);
- }
-
- // Ensure that {index} matches the specified {name} (if {index} is given).
- if (index != nullptr) {
- effect = BuildCheckEqualsName(name, index, effect, control);
+ // Ensure that {key} matches the specified {name} (if {key} is given).
+ if (key != nullptr) {
+ effect = BuildCheckEqualsName(name, key, effect, control);
}
// Collect call nodes to rewire exception edges.
@@ -1168,9 +1117,11 @@ Reduction JSNativeContextSpecialization::ReduceNamedAccess(
PropertyAccessInfo access_info = access_infos.front();
// Try to build string check or number check if possible.
// Otherwise build a map check.
- if (!access_builder.TryBuildStringCheck(access_info.receiver_maps(),
+ if (!access_builder.TryBuildStringCheck(broker(),
+ access_info.receiver_maps(),
&receiver, &effect, control) &&
- !access_builder.TryBuildNumberCheck(access_info.receiver_maps(),
+ !access_builder.TryBuildNumberCheck(broker(),
+ access_info.receiver_maps(),
&receiver, &effect, control)) {
if (HasNumberMaps(broker(), access_info.receiver_maps())) {
// We need to also let Smi {receiver}s through in this case, so
@@ -1310,7 +1261,7 @@ Reduction JSNativeContextSpecialization::ReduceNamedAccess(
// {receiver} here to make sure that TurboFan knows that along this
// path the {this_receiver} is a String. This is because we want
// strict checking of types, for example for StringLength operators.
- if (HasOnlyStringMaps(receiver_maps)) {
+ if (HasOnlyStringMaps(broker(), receiver_maps)) {
this_receiver = this_effect =
graph()->NewNode(common()->TypeGuard(Type::String()), receiver,
this_effect, this_control);
@@ -1371,7 +1322,7 @@ Reduction JSNativeContextSpecialization::ReduceNamedAccess(
}
Reduction JSNativeContextSpecialization::ReduceNamedAccessFromNexus(
- Node* node, Node* value, FeedbackNexus const& nexus, Handle<Name> name,
+ Node* node, Node* value, FeedbackNexus const& nexus, NameRef const& name,
AccessMode access_mode) {
DCHECK(node->opcode() == IrOpcode::kJSLoadNamed ||
node->opcode() == IrOpcode::kJSStoreNamed ||
@@ -1381,7 +1332,8 @@ Reduction JSNativeContextSpecialization::ReduceNamedAccessFromNexus(
// Check if we are accessing the current native contexts' global proxy.
HeapObjectMatcher m(receiver);
- if (m.HasValue() && m.Value().is_identical_to(global_proxy())) {
+ if (m.HasValue() &&
+ m.Ref(broker()).equals(native_context().global_proxy_object())) {
// Optimize accesses to the current native contexts' global proxy.
return ReduceGlobalAccess(node, nullptr, value, name, access_mode);
}
@@ -1404,19 +1356,22 @@ Reduction JSNativeContextSpecialization::ReduceJSLoadNamed(Node* node) {
DCHECK_EQ(IrOpcode::kJSLoadNamed, node->opcode());
NamedAccess const& p = NamedAccessOf(node->op());
Node* const receiver = NodeProperties::GetValueInput(node, 0);
+ NameRef name(broker(), p.name());
// Check if we have a constant receiver.
HeapObjectMatcher m(receiver);
if (m.HasValue()) {
ObjectRef object = m.Ref(broker());
- NameRef name(broker(), p.name());
if (object.IsJSFunction() &&
name.equals(ObjectRef(broker(), factory()->prototype_string()))) {
// Optimize "prototype" property of functions.
JSFunctionRef function = object.AsJSFunction();
- // TODO(neis): This is a temporary hack needed because the copy reducer
- // runs only after this pass.
- function.Serialize();
+ if (!FLAG_concurrent_inlining) {
+ function.Serialize();
+ } else if (!function.serialized()) {
+ TRACE_BROKER_MISSING(broker(), "data for function " << function);
+ return NoChange();
+ }
// TODO(neis): Remove the has_prototype_slot condition once the broker is
// always enabled.
if (!function.map().has_prototype_slot() || !function.has_prototype() ||
@@ -1441,7 +1396,7 @@ Reduction JSNativeContextSpecialization::ReduceJSLoadNamed(Node* node) {
FeedbackNexus nexus(p.feedback().vector(), p.feedback().slot());
// Try to lower the named access based on the {receiver_maps}.
- return ReduceNamedAccessFromNexus(node, jsgraph()->Dead(), nexus, p.name(),
+ return ReduceNamedAccessFromNexus(node, jsgraph()->Dead(), nexus, name,
AccessMode::kLoad);
}
@@ -1455,8 +1410,8 @@ Reduction JSNativeContextSpecialization::ReduceJSStoreNamed(Node* node) {
FeedbackNexus nexus(p.feedback().vector(), p.feedback().slot());
// Try to lower the named access based on the {receiver_maps}.
- return ReduceNamedAccessFromNexus(node, value, nexus, p.name(),
- AccessMode::kStore);
+ return ReduceNamedAccessFromNexus(
+ node, value, nexus, NameRef(broker(), p.name()), AccessMode::kStore);
}
Reduction JSNativeContextSpecialization::ReduceJSStoreNamedOwn(Node* node) {
@@ -1469,7 +1424,8 @@ Reduction JSNativeContextSpecialization::ReduceJSStoreNamedOwn(Node* node) {
FeedbackNexus nexus(p.feedback().vector(), p.feedback().slot());
// Try to lower the creation of a named property based on the {receiver_maps}.
- return ReduceNamedAccessFromNexus(node, value, nexus, p.name(),
+ return ReduceNamedAccessFromNexus(node, value, nexus,
+ NameRef(broker(), p.name()),
AccessMode::kStoreInLiteral);
}
@@ -1483,6 +1439,9 @@ Reduction JSNativeContextSpecialization::ReduceElementAccessOnString(
// Strings are immutable in JavaScript.
if (access_mode == AccessMode::kStore) return NoChange();
+ // `in` cannot be used on strings.
+ if (access_mode == AccessMode::kHas) return NoChange();
+
// Ensure that the {receiver} is actually a String.
receiver = effect = graph()->NewNode(
simplified()->CheckString(VectorSlotPair()), receiver, effect, control);
@@ -1499,10 +1458,25 @@ Reduction JSNativeContextSpecialization::ReduceElementAccessOnString(
return Replace(value);
}
+namespace {
+base::Optional<JSTypedArrayRef> GetTypedArrayConstant(JSHeapBroker* broker,
+ Node* receiver) {
+ HeapObjectMatcher m(receiver);
+ if (!m.HasValue()) return base::nullopt;
+ ObjectRef object = m.Ref(broker);
+ if (!object.IsJSTypedArray()) return base::nullopt;
+ JSTypedArrayRef typed_array = object.AsJSTypedArray();
+ if (typed_array.is_on_heap()) return base::nullopt;
+ return typed_array;
+}
+} // namespace
+
Reduction JSNativeContextSpecialization::ReduceElementAccess(
Node* node, Node* index, Node* value, FeedbackNexus const& nexus,
MapHandles const& receiver_maps, AccessMode access_mode,
KeyedAccessLoadMode load_mode, KeyedAccessStoreMode store_mode) {
+ DisallowHeapAccessIf no_heap_access(FLAG_concurrent_inlining);
+
DCHECK(node->opcode() == IrOpcode::kJSLoadProperty ||
node->opcode() == IrOpcode::kJSStoreProperty ||
node->opcode() == IrOpcode::kJSStoreInArrayLiteral ||
@@ -1512,7 +1486,7 @@ Reduction JSNativeContextSpecialization::ReduceElementAccess(
Node* control = NodeProperties::GetControlInput(node);
Node* frame_state = NodeProperties::FindFrameStateBefore(node);
- if (HasOnlyStringMaps(receiver_maps)) {
+ if (HasOnlyStringMaps(broker(), receiver_maps)) {
return ReduceElementAccessOnString(node, index, value, access_mode,
load_mode);
}
@@ -1539,33 +1513,24 @@ Reduction JSNativeContextSpecialization::ReduceElementAccess(
// TODO(turbofan): We could have a fast path here, that checks for the
// common case of Array or Object prototype only and therefore avoids
// the zone allocation of this vector.
- ZoneVector<Handle<Map>> prototype_maps(zone());
+ ZoneVector<MapRef> prototype_maps(zone());
for (ElementAccessInfo const& access_info : access_infos) {
- for (Handle<Map> receiver_map : access_info.receiver_maps()) {
+ for (Handle<Map> map : access_info.receiver_maps()) {
+ MapRef receiver_map(broker(), map);
// If the {receiver_map} has a prototype and its elements backing
// store is either holey, or we have a potentially growing store,
// then we need to check that all prototypes have stable maps with
// fast elements (and we need to guard against changes to that below).
- if (IsHoleyOrDictionaryElementsKind(receiver_map->elements_kind()) ||
- IsGrowStoreMode(store_mode)) {
- // Make sure all prototypes are stable and have fast elements.
- for (Handle<Map> map = receiver_map;;) {
- Handle<Object> map_prototype(map->prototype(), isolate());
- if (map_prototype->IsNull(isolate())) break;
- if (!map_prototype->IsJSObject()) return NoChange();
- map =
- handle(Handle<JSObject>::cast(map_prototype)->map(), isolate());
- if (!map->is_stable()) return NoChange();
- if (!IsFastElementsKind(map->elements_kind())) return NoChange();
- prototype_maps.push_back(map);
- }
+ if ((IsHoleyOrDictionaryElementsKind(receiver_map.elements_kind()) ||
+ IsGrowStoreMode(store_mode)) &&
+ !receiver_map.HasOnlyStablePrototypesWithFastElements(
+ &prototype_maps)) {
+ return NoChange();
}
}
}
-
- // Install dependencies on the relevant prototype maps.
- for (Handle<Map> prototype_map : prototype_maps) {
- dependencies()->DependOnStableMap(MapRef(broker(), prototype_map));
+ for (MapRef const& prototype_map : prototype_maps) {
+ dependencies()->DependOnStableMap(prototype_map);
}
} else if (access_mode == AccessMode::kHas) {
// If we have any fast arrays, we need to check and depend on
@@ -1584,21 +1549,37 @@ Reduction JSNativeContextSpecialization::ReduceElementAccess(
PropertyAccessBuilder access_builder(jsgraph(), broker(), dependencies());
receiver = access_builder.BuildCheckHeapObject(receiver, &effect, control);
+ // Check if we have the necessary data for building element accesses.
+ for (ElementAccessInfo const& access_info : access_infos) {
+ if (!IsFixedTypedArrayElementsKind(access_info.elements_kind())) continue;
+ base::Optional<JSTypedArrayRef> typed_array =
+ GetTypedArrayConstant(broker(), receiver);
+ if (typed_array.has_value()) {
+ if (!FLAG_concurrent_inlining) {
+ typed_array->Serialize();
+ } else if (!typed_array->serialized()) {
+ TRACE_BROKER_MISSING(broker(), "data for typed array " << *typed_array);
+ return NoChange();
+ }
+ }
+ }
+
// Check for the monomorphic case.
if (access_infos.size() == 1) {
ElementAccessInfo access_info = access_infos.front();
// Perform possible elements kind transitions.
- Handle<Map> const transition_target = access_info.receiver_maps().front();
- for (auto transition_source : access_info.transition_sources()) {
+ MapRef transition_target(broker(), access_info.receiver_maps().front());
+ for (auto source : access_info.transition_sources()) {
DCHECK_EQ(access_info.receiver_maps().size(), 1);
+ MapRef transition_source(broker(), source);
effect = graph()->NewNode(
simplified()->TransitionElementsKind(ElementsTransition(
- IsSimpleMapChangeTransition(transition_source->elements_kind(),
- transition_target->elements_kind())
+ IsSimpleMapChangeTransition(transition_source.elements_kind(),
+ transition_target.elements_kind())
? ElementsTransition::kFastTransition
: ElementsTransition::kSlowTransition,
- transition_source, transition_target)),
+ transition_source.object(), transition_target.object())),
receiver, effect, control);
}
@@ -1639,17 +1620,18 @@ Reduction JSNativeContextSpecialization::ReduceElementAccess(
Node* this_control = fallthrough_control;
// Perform possible elements kind transitions.
- Handle<Map> const transition_target = access_info.receiver_maps().front();
- for (auto transition_source : access_info.transition_sources()) {
+ MapRef transition_target(broker(), access_info.receiver_maps().front());
+ for (auto source : access_info.transition_sources()) {
+ MapRef transition_source(broker(), source);
DCHECK_EQ(access_info.receiver_maps().size(), 1);
this_effect = graph()->NewNode(
simplified()->TransitionElementsKind(ElementsTransition(
- IsSimpleMapChangeTransition(transition_source->elements_kind(),
- transition_target->elements_kind())
+ IsSimpleMapChangeTransition(transition_source.elements_kind(),
+ transition_target.elements_kind())
? ElementsTransition::kFastTransition
: ElementsTransition::kSlowTransition,
- transition_source, transition_target)),
- receiver, this_effect, this_control);
+ transition_source.object(), transition_target.object())),
+ receiver, effect, control);
}
// Perform map check(s) on {receiver}.
@@ -1716,90 +1698,73 @@ Reduction JSNativeContextSpecialization::ReduceElementAccess(
}
Reduction JSNativeContextSpecialization::ReduceKeyedLoadFromHeapConstant(
- Node* node, Node* index, FeedbackNexus const& nexus, AccessMode access_mode,
+ Node* node, Node* key, FeedbackNexus const& nexus, AccessMode access_mode,
KeyedAccessLoadMode load_mode) {
- DCHECK_EQ(node->opcode(), IrOpcode::kJSLoadProperty);
+ DCHECK(node->opcode() == IrOpcode::kJSLoadProperty ||
+ node->opcode() == IrOpcode::kJSHasProperty);
Node* receiver = NodeProperties::GetValueInput(node, 0);
Node* effect = NodeProperties::GetEffectInput(node);
Node* control = NodeProperties::GetControlInput(node);
HeapObjectMatcher mreceiver(receiver);
- HeapObjectRef receiver_ref = mreceiver.Ref(broker()).AsHeapObject();
+ HeapObjectRef receiver_ref = mreceiver.Ref(broker());
if (receiver_ref.map().oddball_type() == OddballType::kHole ||
receiver_ref.map().oddball_type() == OddballType::kNull ||
receiver_ref.map().oddball_type() == OddballType::kUndefined ||
- (receiver_ref.map().IsString() && access_mode == AccessMode::kHas)) {
+ // The 'in' operator throws a TypeError on primitive values.
+ (receiver_ref.IsString() && access_mode == AccessMode::kHas)) {
return NoChange();
}
- // Check whether we're accessing a known element on the {receiver}
- // that is non-configurable, non-writable (e.g. the {receiver} was
- // frozen using Object.freeze).
- NumberMatcher mindex(index);
- if (mindex.IsInteger() && mindex.IsInRange(0.0, kMaxUInt32 - 1.0)) {
- LookupIterator it(isolate(), receiver_ref.object(),
- static_cast<uint32_t>(mindex.Value()),
- LookupIterator::OWN);
- if (it.state() == LookupIterator::DATA) {
- if (it.IsReadOnly() && !it.IsConfigurable()) {
- // We can safely constant-fold the {index} access to {receiver},
- // since the element is non-configurable, non-writable and thus
- // cannot change anymore.
- Node* value = access_mode == AccessMode::kHas
- ? jsgraph()->TrueConstant()
- : jsgraph()->Constant(it.GetDataValue());
- ReplaceWithValue(node, value, effect, control);
- return Replace(value);
- }
-
- // Check if the {receiver} is a known constant with a copy-on-write
- // backing store, and whether {index} is within the appropriate
- // bounds. In that case we can constant-fold the access and only
- // check that the {elements} didn't change. This is sufficient as
- // the backing store of a copy-on-write JSArray is defensively
- // copied whenever the length or the elements (might) change.
- //
- // What's interesting here is that we don't need to map check the
- // {receiver}, since JSArray's will always have their elements in
- // the backing store.
- if (receiver_ref.IsJSArray()) {
- Handle<JSArray> array = receiver_ref.AsJSArray().object();
- if (array->elements()->IsCowArray()) {
- Node* elements = effect = graph()->NewNode(
- simplified()->LoadField(AccessBuilder::ForJSObjectElements()),
- receiver, effect, control);
- Handle<FixedArray> array_elements(FixedArray::cast(array->elements()),
- isolate());
- Node* check =
- graph()->NewNode(simplified()->ReferenceEqual(), elements,
- jsgraph()->HeapConstant(array_elements));
- effect = graph()->NewNode(
- simplified()->CheckIf(DeoptimizeReason::kCowArrayElementsChanged),
- check, effect, control);
- Node* value = access_mode == AccessMode::kHas
- ? jsgraph()->TrueConstant()
- : jsgraph()->Constant(it.GetDataValue());
- ReplaceWithValue(node, value, effect, control);
- return Replace(value);
- }
+ // Check whether we're accessing a known element on the {receiver} and can
+ // constant-fold the load.
+ NumberMatcher mkey(key);
+ if (mkey.IsInteger() && mkey.IsInRange(0.0, kMaxUInt32 - 1.0)) {
+ uint32_t index = static_cast<uint32_t>(mkey.Value());
+ base::Optional<ObjectRef> element =
+ receiver_ref.GetOwnConstantElement(index);
+ if (!element.has_value() && receiver_ref.IsJSArray()) {
+ // We didn't find a constant element, but if the receiver is a cow-array
+ // we can exploit the fact that any future write to the element will
+ // replace the whole elements storage.
+ element = receiver_ref.AsJSArray().GetOwnCowElement(index);
+ if (element.has_value()) {
+ Node* elements = effect = graph()->NewNode(
+ simplified()->LoadField(AccessBuilder::ForJSObjectElements()),
+ receiver, effect, control);
+ FixedArrayRef array_elements =
+ receiver_ref.AsJSArray().elements().AsFixedArray();
+ Node* check = graph()->NewNode(simplified()->ReferenceEqual(), elements,
+ jsgraph()->Constant(array_elements));
+ effect = graph()->NewNode(
+ simplified()->CheckIf(DeoptimizeReason::kCowArrayElementsChanged),
+ check, effect, control);
}
}
+ if (element.has_value()) {
+ Node* value = access_mode == AccessMode::kHas
+ ? jsgraph()->TrueConstant()
+ : jsgraph()->Constant(*element);
+ ReplaceWithValue(node, value, effect, control);
+ return Replace(value);
+ }
}
// For constant Strings we can eagerly strength-reduce the keyed
// accesses using the known length, which doesn't change.
- if (receiver_ref.IsString() && access_mode != AccessMode::kHas) {
+ if (receiver_ref.IsString()) {
+ DCHECK_NE(access_mode, AccessMode::kHas);
// We can only assume that the {index} is a valid array index if the
// IC is in element access mode and not MEGAMORPHIC, otherwise there's
// no guard for the bounds check below.
if (nexus.ic_state() != MEGAMORPHIC && nexus.GetKeyType() == ELEMENT) {
- // Ensure that {index} is less than {receiver} length.
+ // Ensure that {key} is less than {receiver} length.
Node* length = jsgraph()->Constant(receiver_ref.AsString().length());
// Load the single character string from {receiver} or yield
- // undefined if the {index} is out of bounds (depending on the
+ // undefined if the {key} is out of bounds (depending on the
// {load_mode}).
- Node* value = BuildIndexedStringLoad(receiver, index, length, &effect,
+ Node* value = BuildIndexedStringLoad(receiver, key, length, &effect,
&control, load_mode);
ReplaceWithValue(node, value, effect, control);
return Replace(value);
@@ -1809,8 +1774,17 @@ Reduction JSNativeContextSpecialization::ReduceKeyedLoadFromHeapConstant(
return NoChange();
}
+namespace {
+base::Optional<NameRef> GetNameFeedback(JSHeapBroker* broker,
+ FeedbackNexus const& nexus) {
+ Name raw_name = nexus.GetName();
+ if (raw_name.is_null()) return base::nullopt;
+ return NameRef(broker, handle(raw_name, broker->isolate()));
+}
+} // namespace
+
Reduction JSNativeContextSpecialization::ReduceKeyedAccess(
- Node* node, Node* index, Node* value, FeedbackNexus const& nexus,
+ Node* node, Node* key, Node* value, FeedbackNexus const& nexus,
AccessMode access_mode, KeyedAccessLoadMode load_mode,
KeyedAccessStoreMode store_mode) {
DCHECK(node->opcode() == IrOpcode::kJSLoadProperty ||
@@ -1820,10 +1794,10 @@ Reduction JSNativeContextSpecialization::ReduceKeyedAccess(
Node* receiver = NodeProperties::GetValueInput(node, 0);
Node* effect = NodeProperties::GetEffectInput(node);
- if (access_mode == AccessMode::kLoad &&
+ if ((access_mode == AccessMode::kLoad || access_mode == AccessMode::kHas) &&
receiver->opcode() == IrOpcode::kHeapConstant) {
Reduction reduction = ReduceKeyedLoadFromHeapConstant(
- node, index, nexus, access_mode, load_mode);
+ node, key, nexus, access_mode, load_mode);
if (reduction.Changed()) return reduction;
}
@@ -1837,46 +1811,23 @@ Reduction JSNativeContextSpecialization::ReduceKeyedAccess(
}
DCHECK(!nexus.IsUninitialized());
- // Optimize access for constant {index}.
- HeapObjectMatcher mindex(index);
- if (mindex.HasValue()) {
- ObjectRef name = mindex.Ref(broker());
- if (name.IsSymbol()) {
- return ReduceNamedAccess(node, value, receiver_maps,
- name.AsName().object(), access_mode);
- }
- if (name.IsInternalizedString()) {
- uint32_t array_index = name.AsInternalizedString().array_index();
- if (array_index != InternalizedStringRef::kNotAnArrayIndex) {
- index = jsgraph()->Constant(static_cast<double>(array_index));
- } else {
- return ReduceNamedAccess(node, value, receiver_maps,
- name.AsName().object(), access_mode);
- }
- }
+ // Check if we have feedback for a named access.
+ base::Optional<NameRef> name = GetNameFeedback(broker(), nexus);
+ if (name.has_value()) {
+ DCHECK_EQ(nexus.GetKeyType(), PROPERTY);
+ return ReduceNamedAccess(node, value, receiver_maps, *name, access_mode,
+ key);
}
- // Check if we have feedback for a named access.
- Name name = nexus.GetName();
- if (!name.is_null()) {
- return ReduceNamedAccess(node, value, receiver_maps,
- handle(name, isolate()), access_mode, index);
- } else if (nexus.GetKeyType() != ELEMENT) {
- // The KeyedLoad/StoreIC has seen non-element accesses, so we cannot assume
- // that the {index} is a valid array index, thus we just let the IC continue
- // to deal with this load/store.
- return NoChange();
- } else if (nexus.ic_state() == MEGAMORPHIC) {
- // The KeyedLoad/StoreIC uses the MEGAMORPHIC state to guard the assumption
- // that a numeric {index} is within the valid bounds for {receiver}, i.e.
- // it transitions to MEGAMORPHIC once it sees an out-of-bounds access. Thus
- // we cannot continue here if the IC state is MEGAMORPHIC.
- return NoChange();
+ // Try to lower element access based on the {receiver_maps}.
+ // Only do so if the feedback is not megamorphic so that we can learn
+ // something when the ReduceElementAccess code deopts.
+ if (nexus.GetKeyType() == ELEMENT && nexus.ic_state() != MEGAMORPHIC) {
+ return ReduceElementAccess(node, key, value, nexus, receiver_maps,
+ access_mode, load_mode, store_mode);
}
- // Try to lower the element access based on the {receiver_maps}.
- return ReduceElementAccess(node, index, value, nexus, receiver_maps,
- access_mode, load_mode, store_mode);
+ return NoChange();
}
Reduction JSNativeContextSpecialization::ReduceSoftDeoptimize(
@@ -1901,16 +1852,19 @@ Reduction JSNativeContextSpecialization::ReduceSoftDeoptimize(
Reduction JSNativeContextSpecialization::ReduceJSHasProperty(Node* node) {
DCHECK_EQ(IrOpcode::kJSHasProperty, node->opcode());
PropertyAccess const& p = PropertyAccessOf(node->op());
- Node* index = NodeProperties::GetValueInput(node, 1);
+ Node* key = NodeProperties::GetValueInput(node, 1);
Node* value = jsgraph()->Dead();
// Extract receiver maps from the has property IC using the FeedbackNexus.
if (!p.feedback().IsValid()) return NoChange();
FeedbackNexus nexus(p.feedback().vector(), p.feedback().slot());
+ // Extract the keyed access load mode from the keyed load IC.
+ KeyedAccessLoadMode load_mode = nexus.GetKeyedAccessLoadMode();
+
// Try to lower the keyed access based on the {nexus}.
- return ReduceKeyedAccess(node, index, value, nexus, AccessMode::kHas,
- STANDARD_LOAD, STANDARD_STORE);
+ return ReduceKeyedAccess(node, key, value, nexus, AccessMode::kHas, load_mode,
+ STANDARD_STORE);
}
Reduction JSNativeContextSpecialization::ReduceJSLoadPropertyWithEnumeratedKey(
@@ -1966,7 +1920,7 @@ Reduction JSNativeContextSpecialization::ReduceJSLoadPropertyWithEnumeratedKey(
Node* object = NodeProperties::GetValueInput(name, 0);
Node* enumerator = NodeProperties::GetValueInput(name, 2);
- Node* index = NodeProperties::GetValueInput(name, 3);
+ Node* key = NodeProperties::GetValueInput(name, 3);
if (object->opcode() == IrOpcode::kJSToObject) {
object = NodeProperties::GetValueInput(object, 0);
}
@@ -2006,15 +1960,15 @@ Reduction JSNativeContextSpecialization::ReduceJSLoadPropertyWithEnumeratedKey(
simplified()->CheckIf(DeoptimizeReason::kWrongEnumIndices), check, effect,
control);
- // Determine the index from the {enum_indices}.
- index = effect = graph()->NewNode(
+ // Determine the key from the {enum_indices}.
+ key = effect = graph()->NewNode(
simplified()->LoadElement(
AccessBuilder::ForFixedArrayElement(PACKED_SMI_ELEMENTS)),
- enum_indices, index, effect, control);
+ enum_indices, key, effect, control);
// Load the actual field value.
Node* value = effect = graph()->NewNode(simplified()->LoadFieldByIndex(),
- receiver, index, effect, control);
+ receiver, key, effect, control);
ReplaceWithValue(node, value, effect, control);
return Replace(value);
}
@@ -2045,7 +1999,7 @@ Reduction JSNativeContextSpecialization::ReduceJSLoadProperty(Node* node) {
Reduction JSNativeContextSpecialization::ReduceJSStoreProperty(Node* node) {
DCHECK_EQ(IrOpcode::kJSStoreProperty, node->opcode());
PropertyAccess const& p = PropertyAccessOf(node->op());
- Node* const index = NodeProperties::GetValueInput(node, 1);
+ Node* const key = NodeProperties::GetValueInput(node, 1);
Node* const value = NodeProperties::GetValueInput(node, 2);
// Extract receiver maps from the keyed store IC using the FeedbackNexus.
@@ -2056,7 +2010,7 @@ Reduction JSNativeContextSpecialization::ReduceJSStoreProperty(Node* node) {
KeyedAccessStoreMode store_mode = nexus.GetKeyedAccessStoreMode();
// Try to lower the keyed access based on the {nexus}.
- return ReduceKeyedAccess(node, index, value, nexus, AccessMode::kStore,
+ return ReduceKeyedAccess(node, key, value, nexus, AccessMode::kStore,
STANDARD_LOAD, store_mode);
}
@@ -2066,24 +2020,23 @@ Node* JSNativeContextSpecialization::InlinePropertyGetterCall(
PropertyAccessInfo const& access_info) {
Node* target = jsgraph()->Constant(access_info.constant());
FrameStateInfo const& frame_info = FrameStateInfoOf(frame_state->op());
- Handle<SharedFunctionInfo> shared_info =
- frame_info.shared_info().ToHandleChecked();
// Introduce the call to the getter function.
Node* value;
- if (access_info.constant()->IsJSFunction()) {
+ ObjectRef constant(broker(), access_info.constant());
+ if (constant.IsJSFunction()) {
value = *effect = *control = graph()->NewNode(
jsgraph()->javascript()->Call(2, CallFrequency(), VectorSlotPair(),
ConvertReceiverMode::kNotNullOrUndefined),
target, receiver, context, frame_state, *effect, *control);
} else {
- DCHECK(access_info.constant()->IsFunctionTemplateInfo());
- Handle<FunctionTemplateInfo> function_template_info(
- Handle<FunctionTemplateInfo>::cast(access_info.constant()));
- DCHECK(!function_template_info->call_code()->IsUndefined(isolate()));
+ auto function_template_info = constant.AsFunctionTemplateInfo();
+ function_template_info.Serialize();
Node* holder =
access_info.holder().is_null()
? receiver
: jsgraph()->Constant(access_info.holder().ToHandleChecked());
+ SharedFunctionInfoRef shared_info(
+ broker(), frame_info.shared_info().ToHandleChecked());
value = InlineApiCall(receiver, holder, frame_state, nullptr, effect,
control, shared_info, function_template_info);
}
@@ -2105,23 +2058,22 @@ void JSNativeContextSpecialization::InlinePropertySetterCall(
PropertyAccessInfo const& access_info) {
Node* target = jsgraph()->Constant(access_info.constant());
FrameStateInfo const& frame_info = FrameStateInfoOf(frame_state->op());
- Handle<SharedFunctionInfo> shared_info =
- frame_info.shared_info().ToHandleChecked();
// Introduce the call to the setter function.
- if (access_info.constant()->IsJSFunction()) {
+ ObjectRef constant(broker(), access_info.constant());
+ if (constant.IsJSFunction()) {
*effect = *control = graph()->NewNode(
jsgraph()->javascript()->Call(3, CallFrequency(), VectorSlotPair(),
ConvertReceiverMode::kNotNullOrUndefined),
target, receiver, value, context, frame_state, *effect, *control);
} else {
- DCHECK(access_info.constant()->IsFunctionTemplateInfo());
- Handle<FunctionTemplateInfo> function_template_info(
- Handle<FunctionTemplateInfo>::cast(access_info.constant()));
- DCHECK(!function_template_info->call_code()->IsUndefined(isolate()));
+ auto function_template_info = constant.AsFunctionTemplateInfo();
+ function_template_info.Serialize();
Node* holder =
access_info.holder().is_null()
? receiver
: jsgraph()->Constant(access_info.holder().ToHandleChecked());
+ SharedFunctionInfoRef shared_info(
+ broker(), frame_info.shared_info().ToHandleChecked());
InlineApiCall(receiver, holder, frame_state, value, effect, control,
shared_info, function_template_info);
}
@@ -2138,11 +2090,10 @@ void JSNativeContextSpecialization::InlinePropertySetterCall(
Node* JSNativeContextSpecialization::InlineApiCall(
Node* receiver, Node* holder, Node* frame_state, Node* value, Node** effect,
- Node** control, Handle<SharedFunctionInfo> shared_info,
- Handle<FunctionTemplateInfo> function_template_info) {
- Handle<CallHandlerInfo> call_handler_info = handle(
- CallHandlerInfo::cast(function_template_info->call_code()), isolate());
- Handle<Object> call_data_object(call_handler_info->data(), isolate());
+ Node** control, SharedFunctionInfoRef const& shared_info,
+ FunctionTemplateInfoRef const& function_template_info) {
+ auto call_handler_info =
+ function_template_info.call_code().AsCallHandlerInfo();
// Only setters have a value.
int const argc = value == nullptr ? 0 : 1;
@@ -2156,8 +2107,8 @@ Node* JSNativeContextSpecialization::InlineApiCall(
1 /* implicit receiver */,
CallDescriptor::kNeedsFrameState);
- Node* data = jsgraph()->Constant(call_data_object);
- ApiFunction function(v8::ToCData<Address>(call_handler_info->callback()));
+ Node* data = jsgraph()->Constant(call_handler_info.data());
+ ApiFunction function(call_handler_info.callback());
Node* function_reference =
graph()->NewNode(common()->ExternalConstant(ExternalReference::Create(
&function, ExternalReference::DIRECT_API_CALL)));
@@ -2186,14 +2137,14 @@ Node* JSNativeContextSpecialization::InlineApiCall(
JSNativeContextSpecialization::ValueEffectControl
JSNativeContextSpecialization::BuildPropertyLoad(
Node* receiver, Node* context, Node* frame_state, Node* effect,
- Node* control, Handle<Name> name, ZoneVector<Node*>* if_exceptions,
+ Node* control, NameRef const& name, ZoneVector<Node*>* if_exceptions,
PropertyAccessInfo const& access_info) {
// Determine actual holder and perform prototype chain checks.
Handle<JSObject> holder;
- PropertyAccessBuilder access_builder(jsgraph(), broker(), dependencies());
if (access_info.holder().ToHandle(&holder)) {
dependencies()->DependOnStablePrototypeChains(
- access_info.receiver_maps(), JSObjectRef(broker(), holder));
+ access_info.receiver_maps(), kStartAtPrototype,
+ JSObjectRef(broker(), holder));
}
// Generate the actual property access.
@@ -2215,6 +2166,7 @@ JSNativeContextSpecialization::BuildPropertyLoad(
value = graph()->NewNode(simplified()->StringLength(), receiver);
} else {
DCHECK(access_info.IsDataField() || access_info.IsDataConstantField());
+ PropertyAccessBuilder access_builder(jsgraph(), broker(), dependencies());
value = access_builder.BuildLoadDataField(name, access_info, receiver,
&effect, &control);
}
@@ -2229,19 +2181,19 @@ JSNativeContextSpecialization::BuildPropertyTest(
Handle<JSObject> holder;
if (access_info.holder().ToHandle(&holder)) {
dependencies()->DependOnStablePrototypeChains(
- access_info.receiver_maps(), JSObjectRef(broker(), holder));
+ access_info.receiver_maps(), kStartAtPrototype,
+ JSObjectRef(broker(), holder));
}
Node* value = access_info.IsNotFound() ? jsgraph()->FalseConstant()
: jsgraph()->TrueConstant();
-
return ValueEffectControl(value, effect, control);
}
JSNativeContextSpecialization::ValueEffectControl
JSNativeContextSpecialization::BuildPropertyAccess(
Node* receiver, Node* value, Node* context, Node* frame_state, Node* effect,
- Node* control, Handle<Name> name, ZoneVector<Node*>* if_exceptions,
+ Node* control, NameRef const& name, ZoneVector<Node*>* if_exceptions,
PropertyAccessInfo const& access_info, AccessMode access_mode) {
switch (access_mode) {
case AccessMode::kLoad:
@@ -2256,13 +2208,12 @@ JSNativeContextSpecialization::BuildPropertyAccess(
return BuildPropertyTest(effect, control, access_info);
}
UNREACHABLE();
- return ValueEffectControl();
}
JSNativeContextSpecialization::ValueEffectControl
JSNativeContextSpecialization::BuildPropertyStore(
Node* receiver, Node* value, Node* context, Node* frame_state, Node* effect,
- Node* control, Handle<Name> name, ZoneVector<Node*>* if_exceptions,
+ Node* control, NameRef const& name, ZoneVector<Node*>* if_exceptions,
PropertyAccessInfo const& access_info, AccessMode access_mode) {
// Determine actual holder and perform prototype chain checks.
Handle<JSObject> holder;
@@ -2270,7 +2221,8 @@ JSNativeContextSpecialization::BuildPropertyStore(
if (access_info.holder().ToHandle(&holder)) {
DCHECK_NE(AccessMode::kStoreInLiteral, access_mode);
dependencies()->DependOnStablePrototypeChains(
- access_info.receiver_maps(), JSObjectRef(broker(), holder));
+ access_info.receiver_maps(), kStartAtPrototype,
+ JSObjectRef(broker(), holder));
}
DCHECK(!access_info.IsNotFound());
@@ -2303,7 +2255,7 @@ JSNativeContextSpecialization::BuildPropertyStore(
FieldAccess field_access = {
kTaggedBase,
field_index.offset(),
- name,
+ name.object(),
MaybeHandle<Map>(),
field_type,
MachineType::TypeForRepresentation(field_representation),
@@ -2324,7 +2276,8 @@ JSNativeContextSpecialization::BuildPropertyStore(
if (access_info.HasTransitionMap()) {
// Allocate a MutableHeapNumber for the new property.
AllocationBuilder a(jsgraph(), effect, control);
- a.Allocate(HeapNumber::kSize, NOT_TENURED, Type::OtherInternal());
+ a.Allocate(HeapNumber::kSize, AllocationType::kYoung,
+ Type::OtherInternal());
a.Store(AccessBuilder::ForMap(),
factory()->mutable_heap_number_map());
a.Store(AccessBuilder::ForHeapNumberValue(), value);
@@ -2335,13 +2288,11 @@ JSNativeContextSpecialization::BuildPropertyStore(
field_access.write_barrier_kind = kPointerWriteBarrier;
} else {
// We just store directly to the MutableHeapNumber.
- FieldAccess const storage_access = {kTaggedBase,
- field_index.offset(),
- name,
- MaybeHandle<Map>(),
- Type::OtherInternal(),
- MachineType::TaggedPointer(),
- kPointerWriteBarrier};
+ FieldAccess const storage_access = {
+ kTaggedBase, field_index.offset(),
+ name.object(), MaybeHandle<Map>(),
+ Type::OtherInternal(), MachineType::TaggedPointer(),
+ kPointerWriteBarrier};
storage = effect =
graph()->NewNode(simplified()->LoadField(storage_access),
storage, effect, control);
@@ -2357,8 +2308,8 @@ JSNativeContextSpecialization::BuildPropertyStore(
Node* current_value = effect = graph()->NewNode(
simplified()->LoadField(field_access), storage, effect, control);
- Node* check = graph()->NewNode(simplified()->NumberEqual(),
- current_value, value);
+ Node* check =
+ graph()->NewNode(simplified()->SameValue(), current_value, value);
effect = graph()->NewNode(
simplified()->CheckIf(DeoptimizeReason::kWrongValue), check,
effect, control);
@@ -2369,6 +2320,9 @@ JSNativeContextSpecialization::BuildPropertyStore(
case MachineRepresentation::kTaggedSigned:
case MachineRepresentation::kTaggedPointer:
case MachineRepresentation::kTagged:
+ case MachineRepresentation::kCompressedSigned:
+ case MachineRepresentation::kCompressedPointer:
+ case MachineRepresentation::kCompressed:
if (store_to_constant_field) {
DCHECK(!access_info.HasTransitionMap());
// If the field is constant check that the value we are going
@@ -2384,13 +2338,16 @@ JSNativeContextSpecialization::BuildPropertyStore(
return ValueEffectControl(value, effect, control);
}
- if (field_representation == MachineRepresentation::kTaggedSigned) {
+ if (field_representation == MachineRepresentation::kTaggedSigned ||
+ field_representation == MachineRepresentation::kCompressedSigned) {
value = effect = graph()->NewNode(
simplified()->CheckSmi(VectorSlotPair()), value, effect, control);
field_access.write_barrier_kind = kNoWriteBarrier;
} else if (field_representation ==
- MachineRepresentation::kTaggedPointer) {
+ MachineRepresentation::kTaggedPointer ||
+ field_representation ==
+ MachineRepresentation::kCompressedPointer) {
// Ensure that {value} is a HeapObject.
value = access_builder.BuildCheckHeapObject(value, &effect, control);
Handle<Map> field_map;
@@ -2404,7 +2361,8 @@ JSNativeContextSpecialization::BuildPropertyStore(
field_access.write_barrier_kind = kPointerWriteBarrier;
} else {
- DCHECK_EQ(MachineRepresentation::kTagged, field_representation);
+ DCHECK(field_representation == MachineRepresentation::kTagged ||
+ field_representation == MachineRepresentation::kCompressed);
}
break;
case MachineRepresentation::kNone:
@@ -2423,14 +2381,15 @@ JSNativeContextSpecialization::BuildPropertyStore(
if (access_info.transition_map().ToHandle(&transition_map)) {
// Check if we need to grow the properties backing store
// with this transitioning store.
- Handle<Map> original_map(Map::cast(transition_map->GetBackPointer()),
- isolate());
- if (original_map->UnusedPropertyFields() == 0) {
+ MapRef transition_map_ref(broker(), transition_map);
+ transition_map_ref.SerializeBackPointer();
+ MapRef original_map = transition_map_ref.GetBackPointer().AsMap();
+ if (original_map.UnusedPropertyFields() == 0) {
DCHECK(!field_index.is_inobject());
// Reallocate the properties {storage}.
storage = effect = BuildExtendPropertiesBackingStore(
- MapRef(broker(), original_map), storage, effect, control);
+ original_map, storage, effect, control);
// Perform the actual store.
effect = graph()->NewNode(simplified()->StoreField(field_access),
@@ -2489,18 +2448,17 @@ Reduction JSNativeContextSpecialization::ReduceJSStoreDataPropertyInLiteral(
if (!Map::TryUpdate(isolate(), receiver_map).ToHandle(&receiver_map))
return NoChange();
- Handle<Name> cached_name(
- Name::cast(nexus.GetFeedbackExtra()->GetHeapObjectAssumeStrong()),
- isolate());
+ NameRef cached_name(
+ broker(),
+ handle(Name::cast(nexus.GetFeedbackExtra()->GetHeapObjectAssumeStrong()),
+ isolate()));
- PropertyAccessInfo access_info;
AccessInfoFactory access_info_factory(broker(), dependencies(),
graph()->zone());
- if (!access_info_factory.ComputePropertyAccessInfo(
- receiver_map, cached_name, AccessMode::kStoreInLiteral,
- &access_info)) {
- return NoChange();
- }
+ PropertyAccessInfo access_info =
+ access_info_factory.ComputePropertyAccessInfo(
+ receiver_map, cached_name.object(), AccessMode::kStoreInLiteral);
+ if (access_info.IsInvalid()) return NoChange();
Node* receiver = NodeProperties::GetValueInput(node, 0);
Node* effect = NodeProperties::GetEffectInput(node);
@@ -2515,7 +2473,7 @@ Reduction JSNativeContextSpecialization::ReduceJSStoreDataPropertyInLiteral(
// Ensure that {name} matches the cached name.
Node* name = NodeProperties::GetValueInput(node, 1);
Node* check = graph()->NewNode(simplified()->ReferenceEqual(), name,
- jsgraph()->HeapConstant(cached_name));
+ jsgraph()->Constant(cached_name));
effect = graph()->NewNode(simplified()->CheckIf(DeoptimizeReason::kWrongName),
check, effect, control);
@@ -2604,17 +2562,6 @@ ExternalArrayType GetArrayTypeFromElementsKind(ElementsKind kind) {
UNREACHABLE();
}
-base::Optional<JSTypedArrayRef> GetTypedArrayConstant(JSHeapBroker* broker,
- Node* receiver) {
- HeapObjectMatcher m(receiver);
- if (!m.HasValue()) return base::nullopt;
- ObjectRef object = m.Ref(broker);
- if (!object.IsJSTypedArray()) return base::nullopt;
- JSTypedArrayRef typed_array = object.AsJSTypedArray();
- if (typed_array.is_on_heap()) return base::nullopt;
- return typed_array;
-}
-
} // namespace
JSNativeContextSpecialization::ValueEffectControl
@@ -2633,12 +2580,11 @@ JSNativeContextSpecialization::BuildElementAccess(
Node* base_pointer;
Node* external_pointer;
- // Check if we can constant-fold information about the {receiver} (i.e.
+ // Check if we can constant-fold information about the {receiver} (e.g.
// for asm.js-like code patterns).
base::Optional<JSTypedArrayRef> typed_array =
GetTypedArrayConstant(broker(), receiver);
if (typed_array.has_value()) {
- typed_array->Serialize();
buffer = jsgraph()->Constant(typed_array->buffer());
length =
jsgraph()->Constant(static_cast<double>(typed_array->length_value()));
@@ -2716,7 +2662,7 @@ JSNativeContextSpecialization::BuildElementAccess(
// below are performed on unsigned values, which means that all the
// Negative32 values are treated as out-of-bounds.
index = graph()->NewNode(simplified()->NumberToUint32(), index);
- } else if (access_mode != AccessMode::kHas) {
+ } else {
// Check that the {index} is in the valid range for the {receiver}.
index = effect =
graph()->NewNode(simplified()->CheckBounds(VectorSlotPair()), index,
@@ -2874,8 +2820,7 @@ JSNativeContextSpecialization::BuildElementAccess(
index = effect = graph()->NewNode(
simplified()->CheckBounds(VectorSlotPair()), index,
jsgraph()->Constant(Smi::kMaxValue), effect, control);
- } else if (access_mode != AccessMode::kHas ||
- load_mode != LOAD_IGNORE_OUT_OF_BOUNDS) {
+ } else {
// Check that the {index} is in the valid range for the {receiver}.
index = effect =
graph()->NewNode(simplified()->CheckBounds(VectorSlotPair()), index,
@@ -3283,7 +3228,7 @@ Node* JSNativeContextSpecialization::BuildExtendPropertiesBackingStore(
// Allocate and initialize the new properties.
AllocationBuilder a(jsgraph(), effect, control);
- a.Allocate(PropertyArray::SizeFor(new_length), NOT_TENURED,
+ a.Allocate(PropertyArray::SizeFor(new_length), AllocationType::kYoung,
Type::OtherInternal());
a.Store(AccessBuilder::ForMap(), jsgraph()->PropertyArrayMapConstant());
a.Store(AccessBuilder::ForPropertyArrayLengthAndHash(), new_length_and_hash);
@@ -3293,15 +3238,15 @@ Node* JSNativeContextSpecialization::BuildExtendPropertiesBackingStore(
return a.Finish();
}
-Node* JSNativeContextSpecialization::BuildCheckEqualsName(Handle<Name> name,
+Node* JSNativeContextSpecialization::BuildCheckEqualsName(NameRef const& name,
Node* value,
Node* effect,
Node* control) {
- DCHECK(name->IsUniqueName());
+ DCHECK(name.IsUniqueName());
Operator const* const op =
- name->IsSymbol() ? simplified()->CheckEqualsSymbol()
- : simplified()->CheckEqualsInternalizedString();
- return graph()->NewNode(op, jsgraph()->HeapConstant(name), value, effect,
+ name.IsSymbol() ? simplified()->CheckEqualsSymbol()
+ : simplified()->CheckEqualsInternalizedString();
+ return graph()->NewNode(op, jsgraph()->Constant(name), value, effect,
control);
}
@@ -3312,9 +3257,7 @@ bool JSNativeContextSpecialization::CanTreatHoleAsUndefined(
// native contexts, as the global Array protector works isolate-wide).
for (Handle<Map> map : receiver_maps) {
MapRef receiver_map(broker(), map);
- // TODO(neis): Remove SerializePrototype call once brokerization is
- // complete.
- receiver_map.SerializePrototype();
+ if (!FLAG_concurrent_inlining) receiver_map.SerializePrototype();
ObjectRef receiver_prototype = receiver_map.prototype();
if (!receiver_prototype.IsJSObject() ||
!broker()->IsArrayOrObjectPrototype(receiver_prototype.AsJSObject())) {
@@ -3361,15 +3304,15 @@ bool JSNativeContextSpecialization::ExtractReceiverMaps(
// Try to extract some maps from the {nexus}.
if (nexus.ExtractMaps(receiver_maps) != 0) {
// Try to filter impossible candidates based on inferred root map.
- Handle<Map> receiver_map;
- if (InferReceiverRootMap(receiver).ToHandle(&receiver_map)) {
- DCHECK(!receiver_map->is_abandoned_prototype_map());
+ Handle<Map> root_map;
+ if (InferReceiverRootMap(receiver).ToHandle(&root_map)) {
+ DCHECK(!root_map->is_abandoned_prototype_map());
Isolate* isolate = this->isolate();
receiver_maps->erase(
std::remove_if(receiver_maps->begin(), receiver_maps->end(),
- [receiver_map, isolate](const Handle<Map>& map) {
+ [root_map, isolate](Handle<Map> map) {
return map->is_abandoned_prototype_map() ||
- map->FindRootMap(isolate) != *receiver_map;
+ map->FindRootMap(isolate) != *root_map;
}),
receiver_maps->end());
}
@@ -3411,18 +3354,12 @@ MaybeHandle<Map> JSNativeContextSpecialization::InferReceiverRootMap(
if (m.HasValue()) {
return handle(m.Value()->map()->FindRootMap(isolate()), isolate());
} else if (m.IsJSCreate()) {
- HeapObjectMatcher mtarget(m.InputAt(0));
- HeapObjectMatcher mnewtarget(m.InputAt(1));
- if (mtarget.HasValue() && mnewtarget.HasValue()) {
- Handle<JSFunction> constructor =
- Handle<JSFunction>::cast(mtarget.Value());
- if (constructor->has_initial_map()) {
- Handle<Map> initial_map(constructor->initial_map(), isolate());
- if (initial_map->constructor_or_backpointer() == *mnewtarget.Value()) {
- DCHECK_EQ(*initial_map, initial_map->FindRootMap(isolate()));
- return initial_map;
- }
- }
+ base::Optional<MapRef> initial_map =
+ NodeProperties::GetJSCreateMap(broker(), receiver);
+ if (initial_map.has_value()) {
+ DCHECK_EQ(*initial_map->object(),
+ initial_map->object()->FindRootMap(isolate()));
+ return initial_map->object();
}
}
return MaybeHandle<Map>();