[turbofan] Initial support for transitioning stores.
Add support for stores that transition to writable data fields, based on the BeginRegion/FinishRegion mechanism for atomic regions in the scheduler. This is early work and still a bit rough around the edges, and similar to regular stores, we don't support transitioning stores to double fields yet. R=jarin@chromium.org BUG=v8:4470 LOG=n Review URL: https://codereview.chromium.org/1406153010 Cr-Commit-Position: refs/heads/master@{#31645}
This commit is contained in:
parent
40f43c91a5
commit
a0b8650e65
@ -106,6 +106,15 @@ void CompilationDependencies::Rollback() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void CompilationDependencies::AssumeMapNotDeprecated(Handle<Map> map) {
|
||||||
|
DCHECK(!map->is_deprecated());
|
||||||
|
// Do nothing if the map cannot be deprecated.
|
||||||
|
if (map->CanBeDeprecated()) {
|
||||||
|
Insert(DependentCode::kTransitionGroup, map);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void CompilationDependencies::AssumeMapStable(Handle<Map> map) {
|
void CompilationDependencies::AssumeMapStable(Handle<Map> map) {
|
||||||
DCHECK(map->is_stable());
|
DCHECK(map->is_stable());
|
||||||
// Do nothing if the map cannot transition.
|
// Do nothing if the map cannot transition.
|
||||||
|
@ -32,6 +32,7 @@ class CompilationDependencies {
|
|||||||
Insert(DependentCode::kFieldTypeGroup, map);
|
Insert(DependentCode::kFieldTypeGroup, map);
|
||||||
}
|
}
|
||||||
void AssumeMapStable(Handle<Map> map);
|
void AssumeMapStable(Handle<Map> map);
|
||||||
|
void AssumeMapNotDeprecated(Handle<Map> map);
|
||||||
void AssumePropertyCell(Handle<PropertyCell> cell) {
|
void AssumePropertyCell(Handle<PropertyCell> cell) {
|
||||||
Insert(DependentCode::kPropertyCellChangedGroup, cell);
|
Insert(DependentCode::kPropertyCellChangedGroup, cell);
|
||||||
}
|
}
|
||||||
|
@ -248,18 +248,26 @@ Reduction JSNativeContextSpecialization::ReduceJSStoreGlobal(Node* node) {
|
|||||||
// object property, either on the object itself or on the prototype chain.
|
// object property, either on the object itself or on the prototype chain.
|
||||||
class JSNativeContextSpecialization::PropertyAccessInfo final {
|
class JSNativeContextSpecialization::PropertyAccessInfo final {
|
||||||
public:
|
public:
|
||||||
enum Kind { kInvalid, kDataConstant, kDataField };
|
enum Kind { kInvalid, kDataConstant, kDataField, kTransitionToField };
|
||||||
|
|
||||||
static PropertyAccessInfo DataConstant(Type* receiver_type,
|
static PropertyAccessInfo DataConstant(Type* receiver_type,
|
||||||
Handle<Object> constant,
|
Handle<Object> constant,
|
||||||
MaybeHandle<JSObject> holder) {
|
MaybeHandle<JSObject> holder) {
|
||||||
return PropertyAccessInfo(holder, constant, receiver_type);
|
return PropertyAccessInfo(holder, constant, receiver_type);
|
||||||
}
|
}
|
||||||
static PropertyAccessInfo DataField(Type* receiver_type,
|
static PropertyAccessInfo DataField(
|
||||||
FieldIndex field_index, Type* field_type,
|
Type* receiver_type, FieldIndex field_index, Type* field_type,
|
||||||
MaybeHandle<JSObject> holder) {
|
MaybeHandle<JSObject> holder = MaybeHandle<JSObject>()) {
|
||||||
return PropertyAccessInfo(holder, field_index, field_type, receiver_type);
|
return PropertyAccessInfo(holder, field_index, field_type, receiver_type);
|
||||||
}
|
}
|
||||||
|
static PropertyAccessInfo TransitionToField(Type* receiver_type,
|
||||||
|
FieldIndex field_index,
|
||||||
|
Type* field_type,
|
||||||
|
Handle<Map> transition_map,
|
||||||
|
MaybeHandle<JSObject> holder) {
|
||||||
|
return PropertyAccessInfo(holder, transition_map, field_index, field_type,
|
||||||
|
receiver_type);
|
||||||
|
}
|
||||||
|
|
||||||
PropertyAccessInfo() : kind_(kInvalid) {}
|
PropertyAccessInfo() : kind_(kInvalid) {}
|
||||||
PropertyAccessInfo(MaybeHandle<JSObject> holder, Handle<Object> constant,
|
PropertyAccessInfo(MaybeHandle<JSObject> holder, Handle<Object> constant,
|
||||||
@ -275,13 +283,24 @@ class JSNativeContextSpecialization::PropertyAccessInfo final {
|
|||||||
holder_(holder),
|
holder_(holder),
|
||||||
field_index_(field_index),
|
field_index_(field_index),
|
||||||
field_type_(field_type) {}
|
field_type_(field_type) {}
|
||||||
|
PropertyAccessInfo(MaybeHandle<JSObject> holder, Handle<Map> transition_map,
|
||||||
|
FieldIndex field_index, Type* field_type,
|
||||||
|
Type* receiver_type)
|
||||||
|
: kind_(kTransitionToField),
|
||||||
|
receiver_type_(receiver_type),
|
||||||
|
transition_map_(transition_map),
|
||||||
|
holder_(holder),
|
||||||
|
field_index_(field_index),
|
||||||
|
field_type_(field_type) {}
|
||||||
|
|
||||||
bool IsDataConstant() const { return kind() == kDataConstant; }
|
bool IsDataConstant() const { return kind() == kDataConstant; }
|
||||||
bool IsDataField() const { return kind() == kDataField; }
|
bool IsDataField() const { return kind() == kDataField; }
|
||||||
|
bool IsTransitionToField() const { return kind() == kTransitionToField; }
|
||||||
|
|
||||||
Kind kind() const { return kind_; }
|
Kind kind() const { return kind_; }
|
||||||
MaybeHandle<JSObject> holder() const { return holder_; }
|
MaybeHandle<JSObject> holder() const { return holder_; }
|
||||||
Handle<Object> constant() const { return constant_; }
|
Handle<Object> constant() const { return constant_; }
|
||||||
|
Handle<Object> transition_map() const { return transition_map_; }
|
||||||
FieldIndex field_index() const { return field_index_; }
|
FieldIndex field_index() const { return field_index_; }
|
||||||
Type* field_type() const { return field_type_; }
|
Type* field_type() const { return field_type_; }
|
||||||
Type* receiver_type() const { return receiver_type_; }
|
Type* receiver_type() const { return receiver_type_; }
|
||||||
@ -290,6 +309,7 @@ class JSNativeContextSpecialization::PropertyAccessInfo final {
|
|||||||
Kind kind_;
|
Kind kind_;
|
||||||
Type* receiver_type_;
|
Type* receiver_type_;
|
||||||
Handle<Object> constant_;
|
Handle<Object> constant_;
|
||||||
|
Handle<Map> transition_map_;
|
||||||
MaybeHandle<JSObject> holder_;
|
MaybeHandle<JSObject> holder_;
|
||||||
FieldIndex field_index_;
|
FieldIndex field_index_;
|
||||||
Type* field_type_ = Type::Any();
|
Type* field_type_ = Type::Any();
|
||||||
@ -314,17 +334,18 @@ bool CanInlinePropertyAccess(Handle<Map> map) {
|
|||||||
bool JSNativeContextSpecialization::ComputePropertyAccessInfo(
|
bool JSNativeContextSpecialization::ComputePropertyAccessInfo(
|
||||||
Handle<Map> map, Handle<Name> name, PropertyAccessMode access_mode,
|
Handle<Map> map, Handle<Name> name, PropertyAccessMode access_mode,
|
||||||
PropertyAccessInfo* access_info) {
|
PropertyAccessInfo* access_info) {
|
||||||
MaybeHandle<JSObject> holder;
|
// Check if it is safe to inline property access for the {map}.
|
||||||
|
if (!CanInlinePropertyAccess(map)) return false;
|
||||||
|
|
||||||
|
// Compute the receiver type.
|
||||||
Handle<Map> receiver_map = map;
|
Handle<Map> receiver_map = map;
|
||||||
Type* receiver_type = Type::Class(receiver_map, graph()->zone());
|
Type* receiver_type = Type::Class(receiver_map, graph()->zone());
|
||||||
while (CanInlinePropertyAccess(map)) {
|
|
||||||
|
// We support fast inline cases for certain JSObject getters.
|
||||||
|
if (access_mode == kLoad) {
|
||||||
// Check for special JSObject field accessors.
|
// Check for special JSObject field accessors.
|
||||||
int offset;
|
int offset;
|
||||||
if (Accessors::IsJSObjectFieldAccessor(map, name, &offset)) {
|
if (Accessors::IsJSObjectFieldAccessor(map, name, &offset)) {
|
||||||
// Don't bother optimizing stores to special JSObject field accessors.
|
|
||||||
if (access_mode == kStore) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
FieldIndex field_index = FieldIndex::ForInObjectOffset(offset);
|
FieldIndex field_index = FieldIndex::ForInObjectOffset(offset);
|
||||||
Type* field_type = Type::Tagged();
|
Type* field_type = Type::Tagged();
|
||||||
if (map->IsStringMap()) {
|
if (map->IsStringMap()) {
|
||||||
@ -347,29 +368,38 @@ bool JSNativeContextSpecialization::ComputePropertyAccessInfo(
|
|||||||
field_type = type_cache_.kJSArrayLengthType;
|
field_type = type_cache_.kJSArrayLengthType;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
*access_info = PropertyAccessInfo::DataField(receiver_type, field_index,
|
*access_info =
|
||||||
field_type, holder);
|
PropertyAccessInfo::DataField(receiver_type, field_index, field_type);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MaybeHandle<JSObject> holder;
|
||||||
|
while (true) {
|
||||||
// Lookup the named property on the {map}.
|
// Lookup the named property on the {map}.
|
||||||
Handle<DescriptorArray> descriptors(map->instance_descriptors(), isolate());
|
Handle<DescriptorArray> descriptors(map->instance_descriptors(), isolate());
|
||||||
int const number = descriptors->SearchWithCache(*name, *map);
|
int const number = descriptors->SearchWithCache(*name, *map);
|
||||||
if (number != DescriptorArray::kNotFound) {
|
if (number != DescriptorArray::kNotFound) {
|
||||||
if (access_mode == kStore && !map.is_identical_to(receiver_map)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
PropertyDetails const details = descriptors->GetDetails(number);
|
PropertyDetails const details = descriptors->GetDetails(number);
|
||||||
|
if (access_mode == kStore) {
|
||||||
|
// Don't bother optimizing stores to read-only properties.
|
||||||
|
if (details.IsReadOnly()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// Check for store to data property on a prototype.
|
||||||
|
if (details.kind() == kData && !holder.is_null()) {
|
||||||
|
// We need to add the data field to the receiver. Leave the loop
|
||||||
|
// and check whether we already have a transition for this field.
|
||||||
|
// Implemented according to ES6 section 9.1.9 [[Set]] (P, V, Receiver)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
if (details.type() == DATA_CONSTANT) {
|
if (details.type() == DATA_CONSTANT) {
|
||||||
*access_info = PropertyAccessInfo::DataConstant(
|
*access_info = PropertyAccessInfo::DataConstant(
|
||||||
receiver_type, handle(descriptors->GetValue(number), isolate()),
|
receiver_type, handle(descriptors->GetValue(number), isolate()),
|
||||||
holder);
|
holder);
|
||||||
return true;
|
return true;
|
||||||
} else if (details.type() == DATA) {
|
} else if (details.type() == DATA) {
|
||||||
// Don't bother optimizing stores to read-only properties.
|
|
||||||
if (access_mode == kStore && details.IsReadOnly()) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
int index = descriptors->GetFieldIndex(number);
|
int index = descriptors->GetFieldIndex(number);
|
||||||
Representation field_representation = details.representation();
|
Representation field_representation = details.representation();
|
||||||
FieldIndex field_index = FieldIndex::ForPropertyIndex(
|
FieldIndex field_index = FieldIndex::ForPropertyIndex(
|
||||||
@ -380,7 +410,7 @@ bool JSNativeContextSpecialization::ComputePropertyAccessInfo(
|
|||||||
} else if (field_representation.IsDouble()) {
|
} else if (field_representation.IsDouble()) {
|
||||||
if (access_mode == kStore) {
|
if (access_mode == kStore) {
|
||||||
// TODO(bmeurer): Add support for storing to double fields.
|
// TODO(bmeurer): Add support for storing to double fields.
|
||||||
break;
|
return false;
|
||||||
}
|
}
|
||||||
field_type = type_cache_.kFloat64;
|
field_type = type_cache_.kFloat64;
|
||||||
} else if (field_representation.IsHeapObject()) {
|
} else if (field_representation.IsHeapObject()) {
|
||||||
@ -392,10 +422,8 @@ bool JSNativeContextSpecialization::ComputePropertyAccessInfo(
|
|||||||
graph()->zone()),
|
graph()->zone()),
|
||||||
Type::TaggedPointer(), graph()->zone());
|
Type::TaggedPointer(), graph()->zone());
|
||||||
if (field_type->Is(Type::None())) {
|
if (field_type->Is(Type::None())) {
|
||||||
if (access_mode == kStore) {
|
// Store is not safe if the field type was cleared.
|
||||||
// Store is not safe if the field type was cleared.
|
if (access_mode == kStore) return false;
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// The field type was cleared by the GC, so we don't know anything
|
// The field type was cleared by the GC, so we don't know anything
|
||||||
// about the contents now.
|
// about the contents now.
|
||||||
@ -414,7 +442,7 @@ bool JSNativeContextSpecialization::ComputePropertyAccessInfo(
|
|||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
// TODO(bmeurer): Add support for accessors.
|
// TODO(bmeurer): Add support for accessors.
|
||||||
break;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -422,7 +450,7 @@ bool JSNativeContextSpecialization::ComputePropertyAccessInfo(
|
|||||||
// integer indexed exotic objects (see ES6 section 9.4.5).
|
// integer indexed exotic objects (see ES6 section 9.4.5).
|
||||||
if (map->IsJSTypedArrayMap() && name->IsString() &&
|
if (map->IsJSTypedArrayMap() && name->IsString() &&
|
||||||
IsSpecialIndex(isolate()->unicode_cache(), String::cast(*name))) {
|
IsSpecialIndex(isolate()->unicode_cache(), String::cast(*name))) {
|
||||||
break;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Walk up the prototype chain.
|
// Walk up the prototype chain.
|
||||||
@ -434,9 +462,17 @@ bool JSNativeContextSpecialization::ComputePropertyAccessInfo(
|
|||||||
.ToHandle(&constructor)) {
|
.ToHandle(&constructor)) {
|
||||||
map = handle(constructor->initial_map(), isolate());
|
map = handle(constructor->initial_map(), isolate());
|
||||||
DCHECK(map->prototype()->IsJSObject());
|
DCHECK(map->prototype()->IsJSObject());
|
||||||
} else {
|
} else if (map->prototype()->IsNull()) {
|
||||||
|
// Store to property not found on the receiver or any prototype, we need
|
||||||
|
// to transition to a new data property.
|
||||||
|
// Implemented according to ES6 section 9.1.9 [[Set]] (P, V, Receiver)
|
||||||
|
if (access_mode == kStore) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
// TODO(bmeurer): Handle the not found case if the prototype is null.
|
// TODO(bmeurer): Handle the not found case if the prototype is null.
|
||||||
break;
|
return false;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Handle<JSObject> map_prototype(JSObject::cast(map->prototype()), isolate());
|
Handle<JSObject> map_prototype(JSObject::cast(map->prototype()), isolate());
|
||||||
@ -447,6 +483,59 @@ bool JSNativeContextSpecialization::ComputePropertyAccessInfo(
|
|||||||
}
|
}
|
||||||
map = handle(map_prototype->map(), isolate());
|
map = handle(map_prototype->map(), isolate());
|
||||||
holder = map_prototype;
|
holder = map_prototype;
|
||||||
|
|
||||||
|
// Check if it is safe to inline property access for the {map}.
|
||||||
|
if (!CanInlinePropertyAccess(map)) return false;
|
||||||
|
}
|
||||||
|
DCHECK_EQ(kStore, access_mode);
|
||||||
|
|
||||||
|
// Check if the {receiver_map} has a data transition with the given {name}.
|
||||||
|
if (receiver_map->unused_property_fields() == 0) return false;
|
||||||
|
if (Map* transition = TransitionArray::SearchTransition(*receiver_map, kData,
|
||||||
|
*name, NONE)) {
|
||||||
|
Handle<Map> transition_map(transition, isolate());
|
||||||
|
int const number = transition_map->LastAdded();
|
||||||
|
PropertyDetails const details =
|
||||||
|
transition_map->instance_descriptors()->GetDetails(number);
|
||||||
|
// Don't bother optimizing stores to read-only properties.
|
||||||
|
if (details.IsReadOnly()) return false;
|
||||||
|
// TODO(bmeurer): Handle transition to data constant?
|
||||||
|
if (details.type() != DATA) return false;
|
||||||
|
int const index = details.field_index();
|
||||||
|
Representation field_representation = details.representation();
|
||||||
|
FieldIndex field_index = FieldIndex::ForPropertyIndex(
|
||||||
|
*transition_map, index, field_representation.IsDouble());
|
||||||
|
Type* field_type = Type::Tagged();
|
||||||
|
if (field_representation.IsSmi()) {
|
||||||
|
field_type = type_cache_.kSmi;
|
||||||
|
} else if (field_representation.IsDouble()) {
|
||||||
|
// TODO(bmeurer): Add support for storing to double fields.
|
||||||
|
return false;
|
||||||
|
} else if (field_representation.IsHeapObject()) {
|
||||||
|
// Extract the field type from the property details (make sure its
|
||||||
|
// representation is TaggedPointer to reflect the heap object case).
|
||||||
|
field_type = Type::Intersect(
|
||||||
|
Type::Convert<HeapType>(
|
||||||
|
handle(
|
||||||
|
transition_map->instance_descriptors()->GetFieldType(number),
|
||||||
|
isolate()),
|
||||||
|
graph()->zone()),
|
||||||
|
Type::TaggedPointer(), graph()->zone());
|
||||||
|
if (field_type->Is(Type::None())) {
|
||||||
|
// Store is not safe if the field type was cleared.
|
||||||
|
return false;
|
||||||
|
} else if (!Type::Any()->Is(field_type)) {
|
||||||
|
// Add proper code dependencies in case of stable field map(s).
|
||||||
|
Handle<Map> field_owner_map(transition_map->FindFieldOwner(number),
|
||||||
|
isolate());
|
||||||
|
dependencies()->AssumeFieldType(field_owner_map);
|
||||||
|
}
|
||||||
|
DCHECK(field_type->Is(Type::TaggedPointer()));
|
||||||
|
}
|
||||||
|
dependencies()->AssumeMapNotDeprecated(transition_map);
|
||||||
|
*access_info = PropertyAccessInfo::TransitionToField(
|
||||||
|
receiver_type, field_index, field_type, transition_map, holder);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -564,9 +653,6 @@ Reduction JSNativeContextSpecialization::ReduceNamedAccess(
|
|||||||
Handle<JSObject> holder;
|
Handle<JSObject> holder;
|
||||||
if (access_info.holder().ToHandle(&holder)) {
|
if (access_info.holder().ToHandle(&holder)) {
|
||||||
AssumePrototypesStable(receiver_type, holder);
|
AssumePrototypesStable(receiver_type, holder);
|
||||||
if (access_mode == kLoad) {
|
|
||||||
this_receiver = jsgraph()->Constant(holder);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Generate the actual property access.
|
// Generate the actual property access.
|
||||||
@ -581,13 +667,17 @@ Reduction JSNativeContextSpecialization::ReduceNamedAccess(
|
|||||||
this_control = graph()->NewNode(common()->IfTrue(), branch);
|
this_control = graph()->NewNode(common()->IfTrue(), branch);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
DCHECK(access_info.IsDataField());
|
DCHECK(access_info.IsDataField() || access_info.IsTransitionToField());
|
||||||
FieldIndex const field_index = access_info.field_index();
|
FieldIndex const field_index = access_info.field_index();
|
||||||
Type* const field_type = access_info.field_type();
|
Type* const field_type = access_info.field_type();
|
||||||
|
if (access_mode == kLoad && access_info.holder().ToHandle(&holder)) {
|
||||||
|
this_receiver = jsgraph()->Constant(holder);
|
||||||
|
}
|
||||||
|
Node* this_storage = this_receiver;
|
||||||
if (!field_index.is_inobject()) {
|
if (!field_index.is_inobject()) {
|
||||||
this_receiver = this_effect = graph()->NewNode(
|
this_storage = this_effect = graph()->NewNode(
|
||||||
simplified()->LoadField(AccessBuilder::ForJSObjectProperties()),
|
simplified()->LoadField(AccessBuilder::ForJSObjectProperties()),
|
||||||
this_receiver, this_effect, this_control);
|
this_storage, this_effect, this_control);
|
||||||
}
|
}
|
||||||
FieldAccess field_access = {kTaggedBase, field_index.offset(), name,
|
FieldAccess field_access = {kTaggedBase, field_index.offset(), name,
|
||||||
field_type, kMachAnyTagged};
|
field_type, kMachAnyTagged};
|
||||||
@ -595,9 +685,9 @@ Reduction JSNativeContextSpecialization::ReduceNamedAccess(
|
|||||||
if (field_type->Is(Type::UntaggedFloat64())) {
|
if (field_type->Is(Type::UntaggedFloat64())) {
|
||||||
if (!field_index.is_inobject() || field_index.is_hidden_field() ||
|
if (!field_index.is_inobject() || field_index.is_hidden_field() ||
|
||||||
!FLAG_unbox_double_fields) {
|
!FLAG_unbox_double_fields) {
|
||||||
this_receiver = this_effect =
|
this_storage = this_effect =
|
||||||
graph()->NewNode(simplified()->LoadField(field_access),
|
graph()->NewNode(simplified()->LoadField(field_access),
|
||||||
this_receiver, this_effect, this_control);
|
this_storage, this_effect, this_control);
|
||||||
field_access.offset = HeapNumber::kValueOffset;
|
field_access.offset = HeapNumber::kValueOffset;
|
||||||
field_access.name = MaybeHandle<Name>();
|
field_access.name = MaybeHandle<Name>();
|
||||||
}
|
}
|
||||||
@ -605,7 +695,7 @@ Reduction JSNativeContextSpecialization::ReduceNamedAccess(
|
|||||||
}
|
}
|
||||||
this_value = this_effect =
|
this_value = this_effect =
|
||||||
graph()->NewNode(simplified()->LoadField(field_access),
|
graph()->NewNode(simplified()->LoadField(field_access),
|
||||||
this_receiver, this_effect, this_control);
|
this_storage, this_effect, this_control);
|
||||||
} else {
|
} else {
|
||||||
DCHECK_EQ(kStore, access_mode);
|
DCHECK_EQ(kStore, access_mode);
|
||||||
if (field_type->Is(Type::TaggedSigned())) {
|
if (field_type->Is(Type::TaggedSigned())) {
|
||||||
@ -651,9 +741,21 @@ Reduction JSNativeContextSpecialization::ReduceNamedAccess(
|
|||||||
} else {
|
} else {
|
||||||
DCHECK(field_type->Is(Type::Tagged()));
|
DCHECK(field_type->Is(Type::Tagged()));
|
||||||
}
|
}
|
||||||
|
if (access_info.IsTransitionToField()) {
|
||||||
|
this_effect = graph()->NewNode(common()->BeginRegion(), this_effect);
|
||||||
|
this_effect = graph()->NewNode(
|
||||||
|
simplified()->StoreField(AccessBuilder::ForMap()), this_receiver,
|
||||||
|
jsgraph()->Constant(access_info.transition_map()), this_effect,
|
||||||
|
this_control);
|
||||||
|
}
|
||||||
this_effect = graph()->NewNode(simplified()->StoreField(field_access),
|
this_effect = graph()->NewNode(simplified()->StoreField(field_access),
|
||||||
this_receiver, this_value, this_effect,
|
this_storage, this_value, this_effect,
|
||||||
this_control);
|
this_control);
|
||||||
|
if (access_info.IsTransitionToField()) {
|
||||||
|
this_effect =
|
||||||
|
graph()->NewNode(common()->FinishRegion(),
|
||||||
|
jsgraph()->UndefinedConstant(), this_effect);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -60,7 +60,7 @@ class TypeCache final {
|
|||||||
// The JSArray::length property always contains a tagged number in the range
|
// The JSArray::length property always contains a tagged number in the range
|
||||||
// [0, kMaxUInt32].
|
// [0, kMaxUInt32].
|
||||||
Type* const kJSArrayLengthType =
|
Type* const kJSArrayLengthType =
|
||||||
CreateNative(CreateRange(0.0, kMaxUInt32), Type::Tagged());
|
CreateNative(Type::Unsigned32(), Type::Tagged());
|
||||||
|
|
||||||
// The String::length property always contains a smi in the range
|
// The String::length property always contains a smi in the range
|
||||||
// [0, String::kMaxLength].
|
// [0, String::kMaxLength].
|
||||||
|
Loading…
Reference in New Issue
Block a user