Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(50)

Side by Side Diff: src/compiler/property-access-info.cc

Issue 1419173007: [turbofan] Add support for transitioning stores to double fields. (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@master
Patch Set: Created 5 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « src/compiler/property-access-info.h ('k') | src/interface-descriptors.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2015 the V8 project authors. All rights reserved. 1 // Copyright 2015 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include <ostream> 5 #include <ostream>
6 6
7 #include "src/accessors.h" 7 #include "src/accessors.h"
8 #include "src/compilation-dependencies.h" 8 #include "src/compilation-dependencies.h"
9 #include "src/compiler/property-access-info.h" 9 #include "src/compiler/property-access-info.h"
10 #include "src/field-index-inl.h" 10 #include "src/field-index-inl.h"
(...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after
80 80
81 81
82 bool PropertyAccessInfoFactory::ComputePropertyAccessInfo( 82 bool PropertyAccessInfoFactory::ComputePropertyAccessInfo(
83 Handle<Map> map, Handle<Name> name, PropertyAccessMode access_mode, 83 Handle<Map> map, Handle<Name> name, PropertyAccessMode access_mode,
84 PropertyAccessInfo* access_info) { 84 PropertyAccessInfo* access_info) {
85 // Check if it is safe to inline property access for the {map}. 85 // Check if it is safe to inline property access for the {map}.
86 if (!CanInlinePropertyAccess(map)) return false; 86 if (!CanInlinePropertyAccess(map)) return false;
87 87
88 // Compute the receiver type. 88 // Compute the receiver type.
89 Handle<Map> receiver_map = map; 89 Handle<Map> receiver_map = map;
90 Type* receiver_type = Type::Class(receiver_map, zone());
91 90
92 // We support fast inline cases for certain JSObject getters. 91 // We support fast inline cases for certain JSObject getters.
93 if (access_mode == PropertyAccessMode::kLoad) { 92 if (access_mode == PropertyAccessMode::kLoad &&
94 // Check for special JSObject field accessors. 93 LookupSpecialFieldAccessor(map, name, access_info)) {
95 int offset; 94 return true;
96 if (Accessors::IsJSObjectFieldAccessor(map, name, &offset)) {
97 FieldIndex field_index = FieldIndex::ForInObjectOffset(offset);
98 Type* field_type = Type::Tagged();
99 if (map->IsStringMap()) {
100 DCHECK(Name::Equals(factory()->length_string(), name));
101 // The String::length property is always a smi in the range
102 // [0, String::kMaxLength].
103 field_type = type_cache_.kStringLengthType;
104 } else if (map->IsJSArrayMap()) {
105 DCHECK(Name::Equals(factory()->length_string(), name));
106 // The JSArray::length property is a smi in the range
107 // [0, FixedDoubleArray::kMaxLength] in case of fast double
108 // elements, a smi in the range [0, FixedArray::kMaxLength]
109 // in case of other fast elements, and [0, kMaxUInt32] in
110 // case of other arrays.
111 if (IsFastDoubleElementsKind(map->elements_kind())) {
112 field_type = type_cache_.kFixedDoubleArrayLengthType;
113 } else if (IsFastElementsKind(map->elements_kind())) {
114 field_type = type_cache_.kFixedArrayLengthType;
115 } else {
116 field_type = type_cache_.kJSArrayLengthType;
117 }
118 }
119 *access_info =
120 PropertyAccessInfo::DataField(receiver_type, field_index, field_type);
121 return true;
122 }
123 } 95 }
124 96
125 MaybeHandle<JSObject> holder; 97 MaybeHandle<JSObject> holder;
126 while (true) { 98 while (true) {
127 // Lookup the named property on the {map}. 99 // Lookup the named property on the {map}.
128 Handle<DescriptorArray> descriptors(map->instance_descriptors(), isolate()); 100 Handle<DescriptorArray> descriptors(map->instance_descriptors(), isolate());
129 int const number = descriptors->SearchWithCache(*name, *map); 101 int const number = descriptors->SearchWithCache(*name, *map);
130 if (number != DescriptorArray::kNotFound) { 102 if (number != DescriptorArray::kNotFound) {
131 PropertyDetails const details = descriptors->GetDetails(number); 103 PropertyDetails const details = descriptors->GetDetails(number);
132 if (access_mode == PropertyAccessMode::kStore) { 104 if (access_mode == PropertyAccessMode::kStore) {
133 // Don't bother optimizing stores to read-only properties. 105 // Don't bother optimizing stores to read-only properties.
134 if (details.IsReadOnly()) { 106 if (details.IsReadOnly()) {
135 return false; 107 return false;
136 } 108 }
137 // Check for store to data property on a prototype. 109 // Check for store to data property on a prototype.
138 if (details.kind() == kData && !holder.is_null()) { 110 if (details.kind() == kData && !holder.is_null()) {
139 // We need to add the data field to the receiver. Leave the loop 111 // Store to property not found on the receiver but on a prototype, we
140 // and check whether we already have a transition for this field. 112 // need to transition to a new data property.
141 // Implemented according to ES6 section 9.1.9 [[Set]] (P, V, Receiver) 113 // Implemented according to ES6 section 9.1.9 [[Set]] (P, V, Receiver)
142 break; 114 return LookupTransition(receiver_map, name, holder, access_info);
143 } 115 }
144 } 116 }
145 if (details.type() == DATA_CONSTANT) { 117 if (details.type() == DATA_CONSTANT) {
146 *access_info = PropertyAccessInfo::DataConstant( 118 *access_info = PropertyAccessInfo::DataConstant(
147 receiver_type, handle(descriptors->GetValue(number), isolate()), 119 Type::Class(receiver_map, zone()),
148 holder); 120 handle(descriptors->GetValue(number), isolate()), holder);
149 return true; 121 return true;
150 } else if (details.type() == DATA) { 122 } else if (details.type() == DATA) {
151 int index = descriptors->GetFieldIndex(number); 123 int index = descriptors->GetFieldIndex(number);
152 Representation field_representation = details.representation(); 124 Representation field_representation = details.representation();
153 FieldIndex field_index = FieldIndex::ForPropertyIndex( 125 FieldIndex field_index = FieldIndex::ForPropertyIndex(
154 *map, index, field_representation.IsDouble()); 126 *map, index, field_representation.IsDouble());
155 Type* field_type = Type::Tagged(); 127 Type* field_type = Type::Tagged();
156 if (field_representation.IsSmi()) { 128 if (field_representation.IsSmi()) {
157 field_type = type_cache_.kSmi; 129 field_type = type_cache_.kSmi;
158 } else if (field_representation.IsDouble()) { 130 } else if (field_representation.IsDouble()) {
(...skipping 14 matching lines...) Expand all
173 // TODO(bmeurer): It would be awesome to make this saner in the 145 // TODO(bmeurer): It would be awesome to make this saner in the
174 // runtime/GC interaction. 146 // runtime/GC interaction.
175 field_type = Type::TaggedPointer(); 147 field_type = Type::TaggedPointer();
176 } else if (!Type::Any()->Is(field_type)) { 148 } else if (!Type::Any()->Is(field_type)) {
177 // Add proper code dependencies in case of stable field map(s). 149 // Add proper code dependencies in case of stable field map(s).
178 Handle<Map> field_owner_map(map->FindFieldOwner(number), isolate()); 150 Handle<Map> field_owner_map(map->FindFieldOwner(number), isolate());
179 dependencies()->AssumeFieldType(field_owner_map); 151 dependencies()->AssumeFieldType(field_owner_map);
180 } 152 }
181 DCHECK(field_type->Is(Type::TaggedPointer())); 153 DCHECK(field_type->Is(Type::TaggedPointer()));
182 } 154 }
183 *access_info = PropertyAccessInfo::DataField(receiver_type, field_index, 155 *access_info = PropertyAccessInfo::DataField(
184 field_type, holder); 156 Type::Class(receiver_map, zone()), field_index, field_type, holder);
185 return true; 157 return true;
186 } else { 158 } else {
187 // TODO(bmeurer): Add support for accessors. 159 // TODO(bmeurer): Add support for accessors.
188 return false; 160 return false;
189 } 161 }
190 } 162 }
191 163
192 // Don't search on the prototype chain for special indices in case of 164 // Don't search on the prototype chain for special indices in case of
193 // integer indexed exotic objects (see ES6 section 9.4.5). 165 // integer indexed exotic objects (see ES6 section 9.4.5).
194 if (map->IsJSTypedArrayMap() && name->IsString() && 166 if (map->IsJSTypedArrayMap() && name->IsString() &&
(...skipping 11 matching lines...) Expand all
206 Handle<JSFunction> constructor; 178 Handle<JSFunction> constructor;
207 if (Map::GetConstructorFunction(map, native_context()) 179 if (Map::GetConstructorFunction(map, native_context())
208 .ToHandle(&constructor)) { 180 .ToHandle(&constructor)) {
209 map = handle(constructor->initial_map(), isolate()); 181 map = handle(constructor->initial_map(), isolate());
210 DCHECK(map->prototype()->IsJSObject()); 182 DCHECK(map->prototype()->IsJSObject());
211 } else if (map->prototype()->IsNull()) { 183 } else if (map->prototype()->IsNull()) {
212 // Store to property not found on the receiver or any prototype, we need 184 // Store to property not found on the receiver or any prototype, we need
213 // to transition to a new data property. 185 // to transition to a new data property.
214 // Implemented according to ES6 section 9.1.9 [[Set]] (P, V, Receiver) 186 // Implemented according to ES6 section 9.1.9 [[Set]] (P, V, Receiver)
215 if (access_mode == PropertyAccessMode::kStore) { 187 if (access_mode == PropertyAccessMode::kStore) {
216 break; 188 return LookupTransition(receiver_map, name, holder, access_info);
217 } 189 }
218 // TODO(bmeurer): Handle the not found case if the prototype is null. 190 // TODO(bmeurer): Handle the not found case if the prototype is null.
219 return false; 191 return false;
220 } else { 192 } else {
221 return false; 193 return false;
222 } 194 }
223 } 195 }
224 Handle<JSObject> map_prototype(JSObject::cast(map->prototype()), isolate()); 196 Handle<JSObject> map_prototype(JSObject::cast(map->prototype()), isolate());
225 if (map_prototype->map()->is_deprecated()) { 197 if (map_prototype->map()->is_deprecated()) {
226 // Try to migrate the prototype object so we don't embed the deprecated 198 // Try to migrate the prototype object so we don't embed the deprecated
227 // map into the optimized code. 199 // map into the optimized code.
228 JSObject::TryMigrateInstance(map_prototype); 200 JSObject::TryMigrateInstance(map_prototype);
229 } 201 }
230 map = handle(map_prototype->map(), isolate()); 202 map = handle(map_prototype->map(), isolate());
231 holder = map_prototype; 203 holder = map_prototype;
232 204
233 // Check if it is safe to inline property access for the {map}. 205 // Check if it is safe to inline property access for the {map}.
234 if (!CanInlinePropertyAccess(map)) return false; 206 if (!CanInlinePropertyAccess(map)) return false;
235 } 207 }
236 DCHECK_EQ(PropertyAccessMode::kStore, access_mode); 208 return false;
209 }
237 210
238 // Check if the {receiver_map} has a data transition with the given {name}. 211
239 if (receiver_map->unused_property_fields() == 0) return false; 212 bool PropertyAccessInfoFactory::LookupSpecialFieldAccessor(
240 if (Map* transition = TransitionArray::SearchTransition(*receiver_map, kData, 213 Handle<Map> map, Handle<Name> name, PropertyAccessInfo* access_info) {
241 *name, NONE)) { 214 // Check for special JSObject field accessors.
242 Handle<Map> transition_map(transition, isolate()); 215 int offset;
216 if (Accessors::IsJSObjectFieldAccessor(map, name, &offset)) {
217 FieldIndex field_index = FieldIndex::ForInObjectOffset(offset);
218 Type* field_type = Type::Tagged();
219 if (map->IsStringMap()) {
220 DCHECK(Name::Equals(factory()->length_string(), name));
221 // The String::length property is always a smi in the range
222 // [0, String::kMaxLength].
223 field_type = type_cache_.kStringLengthType;
224 } else if (map->IsJSArrayMap()) {
225 DCHECK(Name::Equals(factory()->length_string(), name));
226 // The JSArray::length property is a smi in the range
227 // [0, FixedDoubleArray::kMaxLength] in case of fast double
228 // elements, a smi in the range [0, FixedArray::kMaxLength]
229 // in case of other fast elements, and [0, kMaxUInt32] in
230 // case of other arrays.
231 if (IsFastDoubleElementsKind(map->elements_kind())) {
232 field_type = type_cache_.kFixedDoubleArrayLengthType;
233 } else if (IsFastElementsKind(map->elements_kind())) {
234 field_type = type_cache_.kFixedArrayLengthType;
235 } else {
236 field_type = type_cache_.kJSArrayLengthType;
237 }
238 }
239 *access_info = PropertyAccessInfo::DataField(Type::Class(map, zone()),
240 field_index, field_type);
241 return true;
242 }
243 return false;
244 }
245
246
247 bool PropertyAccessInfoFactory::LookupTransition(
248 Handle<Map> map, Handle<Name> name, MaybeHandle<JSObject> holder,
249 PropertyAccessInfo* access_info) {
250 // Check if the {map} has a data transition with the given {name}.
251 if (map->unused_property_fields() == 0) return false;
252 Handle<Map> transition_map;
253 if (TransitionArray::SearchTransition(map, kData, name, NONE)
254 .ToHandle(&transition_map)) {
243 int const number = transition_map->LastAdded(); 255 int const number = transition_map->LastAdded();
244 PropertyDetails const details = 256 PropertyDetails const details =
245 transition_map->instance_descriptors()->GetDetails(number); 257 transition_map->instance_descriptors()->GetDetails(number);
246 // Don't bother optimizing stores to read-only properties. 258 // Don't bother optimizing stores to read-only properties.
247 if (details.IsReadOnly()) return false; 259 if (details.IsReadOnly()) return false;
248 // TODO(bmeurer): Handle transition to data constant? 260 // TODO(bmeurer): Handle transition to data constant?
249 if (details.type() != DATA) return false; 261 if (details.type() != DATA) return false;
250 int const index = details.field_index(); 262 int const index = details.field_index();
251 Representation field_representation = details.representation(); 263 Representation field_representation = details.representation();
252 FieldIndex field_index = FieldIndex::ForPropertyIndex( 264 FieldIndex field_index = FieldIndex::ForPropertyIndex(
253 *transition_map, index, field_representation.IsDouble()); 265 *transition_map, index, field_representation.IsDouble());
254 Type* field_type = Type::Tagged(); 266 Type* field_type = Type::Tagged();
255 if (field_representation.IsSmi()) { 267 if (field_representation.IsSmi()) {
256 field_type = type_cache_.kSmi; 268 field_type = type_cache_.kSmi;
257 } else if (field_representation.IsDouble()) { 269 } else if (field_representation.IsDouble()) {
258 // TODO(bmeurer): Add support for storing to double fields. 270 field_type = type_cache_.kFloat64;
259 return false;
260 } else if (field_representation.IsHeapObject()) { 271 } else if (field_representation.IsHeapObject()) {
261 // Extract the field type from the property details (make sure its 272 // Extract the field type from the property details (make sure its
262 // representation is TaggedPointer to reflect the heap object case). 273 // representation is TaggedPointer to reflect the heap object case).
263 field_type = Type::Intersect( 274 field_type = Type::Intersect(
264 Type::Convert<HeapType>( 275 Type::Convert<HeapType>(
265 handle( 276 handle(
266 transition_map->instance_descriptors()->GetFieldType(number), 277 transition_map->instance_descriptors()->GetFieldType(number),
267 isolate()), 278 isolate()),
268 zone()), 279 zone()),
269 Type::TaggedPointer(), zone()); 280 Type::TaggedPointer(), zone());
270 if (field_type->Is(Type::None())) { 281 if (field_type->Is(Type::None())) {
271 // Store is not safe if the field type was cleared. 282 // Store is not safe if the field type was cleared.
272 return false; 283 return false;
273 } else if (!Type::Any()->Is(field_type)) { 284 } else if (!Type::Any()->Is(field_type)) {
274 // Add proper code dependencies in case of stable field map(s). 285 // Add proper code dependencies in case of stable field map(s).
275 Handle<Map> field_owner_map(transition_map->FindFieldOwner(number), 286 Handle<Map> field_owner_map(transition_map->FindFieldOwner(number),
276 isolate()); 287 isolate());
277 dependencies()->AssumeFieldType(field_owner_map); 288 dependencies()->AssumeFieldType(field_owner_map);
278 } 289 }
279 DCHECK(field_type->Is(Type::TaggedPointer())); 290 DCHECK(field_type->Is(Type::TaggedPointer()));
280 } 291 }
281 dependencies()->AssumeMapNotDeprecated(transition_map); 292 dependencies()->AssumeMapNotDeprecated(transition_map);
282 *access_info = PropertyAccessInfo::DataField( 293 *access_info =
283 receiver_type, field_index, field_type, holder, transition_map); 294 PropertyAccessInfo::DataField(Type::Class(map, zone()), field_index,
295 field_type, holder, transition_map);
284 return true; 296 return true;
285 } 297 }
286 return false; 298 return false;
287 } 299 }
288 300
289 301
290 bool PropertyAccessInfoFactory::ComputePropertyAccessInfos( 302 bool PropertyAccessInfoFactory::ComputePropertyAccessInfos(
291 MapHandleList const& maps, Handle<Name> name, 303 MapHandleList const& maps, Handle<Name> name,
292 PropertyAccessMode access_mode, 304 PropertyAccessMode access_mode,
293 ZoneVector<PropertyAccessInfo>* access_infos) { 305 ZoneVector<PropertyAccessInfo>* access_infos) {
(...skipping 10 matching lines...) Expand all
304 } 316 }
305 317
306 318
307 Factory* PropertyAccessInfoFactory::factory() const { 319 Factory* PropertyAccessInfoFactory::factory() const {
308 return isolate()->factory(); 320 return isolate()->factory();
309 } 321 }
310 322
311 } // namespace compiler 323 } // namespace compiler
312 } // namespace internal 324 } // namespace internal
313 } // namespace v8 325 } // namespace v8
OLDNEW
« no previous file with comments | « src/compiler/property-access-info.h ('k') | src/interface-descriptors.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698