OLD | NEW |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 |
OLD | NEW |