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

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

Issue 1418213010: [turbofan] Initial support for keyed access to fast JSArrays. (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@master
Patch Set: Address comments 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/access-info.h ('k') | src/compiler/js-native-context-specialization.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/access-info.h"
10 #include "src/field-index-inl.h" 10 #include "src/field-index-inl.h"
11 #include "src/objects-inl.h" // TODO(mstarzinger): Temporary cycle breaker! 11 #include "src/objects-inl.h" // TODO(mstarzinger): Temporary cycle breaker!
12 #include "src/type-cache.h" 12 #include "src/type-cache.h"
13 #include "src/types-inl.h" 13 #include "src/types-inl.h"
14 14
15 namespace v8 { 15 namespace v8 {
16 namespace internal { 16 namespace internal {
17 namespace compiler { 17 namespace compiler {
18 18
19 std::ostream& operator<<(std::ostream& os, PropertyAccessMode access_mode) { 19 namespace {
20
21 bool CanInlineElementAccess(Handle<Map> map) {
22 // TODO(bmeurer): IsJSObjectMap
23 // TODO(bmeurer): !map->has_dictionary_elements()
24 // TODO(bmeurer): !map->has_sloppy_arguments_elements()
25 return map->IsJSArrayMap() && map->has_fast_elements() &&
26 !map->has_indexed_interceptor() && !map->is_access_check_needed();
27 }
28
29
30 bool CanInlinePropertyAccess(Handle<Map> map) {
31 // TODO(bmeurer): Add support for Number primitives.
32 // if (map->instance_type() == HEAP_NUMBER_TYPE) return false;
33 if (map->instance_type() < FIRST_NONSTRING_TYPE) return true;
34 return map->IsJSObjectMap() && !map->is_dictionary_map() &&
35 !map->has_named_interceptor() &&
36 // TODO(verwaest): Whitelist contexts to which we have access.
37 !map->is_access_check_needed();
38 }
39
40 } // namespace
41
42
43 std::ostream& operator<<(std::ostream& os, AccessMode access_mode) {
20 switch (access_mode) { 44 switch (access_mode) {
21 case PropertyAccessMode::kLoad: 45 case AccessMode::kLoad:
22 return os << "Load"; 46 return os << "Load";
23 case PropertyAccessMode::kStore: 47 case AccessMode::kStore:
24 return os << "Store"; 48 return os << "Store";
25 } 49 }
26 UNREACHABLE(); 50 UNREACHABLE();
27 return os; 51 return os;
28 } 52 }
29 53
30 54
31 // static 55 // static
32 PropertyAccessInfo PropertyAccessInfo::NotFound(Type* receiver_type, 56 PropertyAccessInfo PropertyAccessInfo::NotFound(Type* receiver_type,
33 MaybeHandle<JSObject> holder) { 57 MaybeHandle<JSObject> holder) {
(...skipping 11 matching lines...) Expand all
45 69
46 // static 70 // static
47 PropertyAccessInfo PropertyAccessInfo::DataField( 71 PropertyAccessInfo PropertyAccessInfo::DataField(
48 Type* receiver_type, FieldIndex field_index, Type* field_type, 72 Type* receiver_type, FieldIndex field_index, Type* field_type,
49 MaybeHandle<JSObject> holder, MaybeHandle<Map> transition_map) { 73 MaybeHandle<JSObject> holder, MaybeHandle<Map> transition_map) {
50 return PropertyAccessInfo(holder, transition_map, field_index, field_type, 74 return PropertyAccessInfo(holder, transition_map, field_index, field_type,
51 receiver_type); 75 receiver_type);
52 } 76 }
53 77
54 78
79 ElementAccessInfo::ElementAccessInfo() : receiver_type_(Type::None()) {}
80
81
55 PropertyAccessInfo::PropertyAccessInfo() 82 PropertyAccessInfo::PropertyAccessInfo()
56 : kind_(kInvalid), receiver_type_(Type::None()), field_type_(Type::Any()) {} 83 : kind_(kInvalid), receiver_type_(Type::None()), field_type_(Type::Any()) {}
57 84
58 85
59 PropertyAccessInfo::PropertyAccessInfo(MaybeHandle<JSObject> holder, 86 PropertyAccessInfo::PropertyAccessInfo(MaybeHandle<JSObject> holder,
60 Type* receiver_type) 87 Type* receiver_type)
61 : kind_(kNotFound), 88 : kind_(kNotFound),
62 receiver_type_(receiver_type), 89 receiver_type_(receiver_type),
63 holder_(holder), 90 holder_(holder),
64 field_type_(Type::Any()) {} 91 field_type_(Type::Any()) {}
(...skipping 14 matching lines...) Expand all
79 FieldIndex field_index, Type* field_type, 106 FieldIndex field_index, Type* field_type,
80 Type* receiver_type) 107 Type* receiver_type)
81 : kind_(kDataField), 108 : kind_(kDataField),
82 receiver_type_(receiver_type), 109 receiver_type_(receiver_type),
83 transition_map_(transition_map), 110 transition_map_(transition_map),
84 holder_(holder), 111 holder_(holder),
85 field_index_(field_index), 112 field_index_(field_index),
86 field_type_(field_type) {} 113 field_type_(field_type) {}
87 114
88 115
89 PropertyAccessInfoFactory::PropertyAccessInfoFactory( 116 AccessInfoFactory::AccessInfoFactory(CompilationDependencies* dependencies,
90 CompilationDependencies* dependencies, Handle<Context> native_context, 117 Handle<Context> native_context, Zone* zone)
91 Zone* zone)
92 : dependencies_(dependencies), 118 : dependencies_(dependencies),
93 native_context_(native_context), 119 native_context_(native_context),
94 isolate_(native_context->GetIsolate()), 120 isolate_(native_context->GetIsolate()),
95 type_cache_(TypeCache::Get()), 121 type_cache_(TypeCache::Get()),
96 zone_(zone) {} 122 zone_(zone) {}
97 123
98 124
99 namespace { 125 bool AccessInfoFactory::ComputeElementAccessInfo(
126 Handle<Map> map, AccessMode access_mode, ElementAccessInfo* access_info) {
127 // Check if it is safe to inline element access for the {map}.
128 if (!CanInlineElementAccess(map)) return false;
100 129
101 bool CanInlinePropertyAccess(Handle<Map> map) { 130 // TODO(bmeurer): Add support for holey elements.
102 // TODO(bmeurer): Do something about the number stuff. 131 ElementsKind elements_kind = map->elements_kind();
103 if (map->instance_type() == HEAP_NUMBER_TYPE) return false; 132 if (IsHoleyElementsKind(elements_kind)) return false;
104 if (map->instance_type() < FIRST_NONSTRING_TYPE) return true; 133
105 return map->IsJSObjectMap() && !map->is_dictionary_map() && 134 // Certain (monomorphic) stores need a prototype chain check because shape
106 !map->has_named_interceptor() && 135 // changes could allow callbacks on elements in the chain that are not
107 // TODO(verwaest): Whitelist contexts to which we have access. 136 // compatible with monomorphic keyed stores.
108 !map->is_access_check_needed(); 137 MaybeHandle<JSObject> holder;
138 if (access_mode == AccessMode::kStore && map->prototype()->IsJSObject()) {
139 for (PrototypeIterator i(map); !i.IsAtEnd(); i.Advance()) {
140 Handle<JSReceiver> prototype =
141 PrototypeIterator::GetCurrent<JSReceiver>(i);
142 if (!prototype->IsJSObject()) return false;
143 holder = Handle<JSObject>::cast(prototype);
144 }
145 }
146
147 *access_info =
148 ElementAccessInfo(Type::Class(map, zone()), elements_kind, holder);
149 return true;
109 } 150 }
110 151
111 } // namespace 152
153 bool AccessInfoFactory::ComputeElementAccessInfos(
154 MapHandleList const& maps, AccessMode access_mode,
155 ZoneVector<ElementAccessInfo>* access_infos) {
156 for (Handle<Map> map : maps) {
157 if (Map::TryUpdate(map).ToHandle(&map)) {
158 ElementAccessInfo access_info;
159 if (!ComputeElementAccessInfo(map, access_mode, &access_info)) {
160 return false;
161 }
162 access_infos->push_back(access_info);
163 }
164 }
165 return true;
166 }
112 167
113 168
114 bool PropertyAccessInfoFactory::ComputePropertyAccessInfo( 169 bool AccessInfoFactory::ComputePropertyAccessInfo(
115 Handle<Map> map, Handle<Name> name, PropertyAccessMode access_mode, 170 Handle<Map> map, Handle<Name> name, AccessMode access_mode,
116 PropertyAccessInfo* access_info) { 171 PropertyAccessInfo* access_info) {
117 // Check if it is safe to inline property access for the {map}. 172 // Check if it is safe to inline property access for the {map}.
118 if (!CanInlinePropertyAccess(map)) return false; 173 if (!CanInlinePropertyAccess(map)) return false;
119 174
120 // Compute the receiver type. 175 // Compute the receiver type.
121 Handle<Map> receiver_map = map; 176 Handle<Map> receiver_map = map;
122 177
123 // We support fast inline cases for certain JSObject getters. 178 // We support fast inline cases for certain JSObject getters.
124 if (access_mode == PropertyAccessMode::kLoad && 179 if (access_mode == AccessMode::kLoad &&
125 LookupSpecialFieldAccessor(map, name, access_info)) { 180 LookupSpecialFieldAccessor(map, name, access_info)) {
126 return true; 181 return true;
127 } 182 }
128 183
129 MaybeHandle<JSObject> holder; 184 MaybeHandle<JSObject> holder;
130 do { 185 do {
131 // Lookup the named property on the {map}. 186 // Lookup the named property on the {map}.
132 Handle<DescriptorArray> descriptors(map->instance_descriptors(), isolate()); 187 Handle<DescriptorArray> descriptors(map->instance_descriptors(), isolate());
133 int const number = descriptors->SearchWithCache(*name, *map); 188 int const number = descriptors->SearchWithCache(*name, *map);
134 if (number != DescriptorArray::kNotFound) { 189 if (number != DescriptorArray::kNotFound) {
135 PropertyDetails const details = descriptors->GetDetails(number); 190 PropertyDetails const details = descriptors->GetDetails(number);
136 if (access_mode == PropertyAccessMode::kStore) { 191 if (access_mode == AccessMode::kStore) {
137 // Don't bother optimizing stores to read-only properties. 192 // Don't bother optimizing stores to read-only properties.
138 if (details.IsReadOnly()) { 193 if (details.IsReadOnly()) {
139 return false; 194 return false;
140 } 195 }
141 // Check for store to data property on a prototype. 196 // Check for store to data property on a prototype.
142 if (details.kind() == kData && !holder.is_null()) { 197 if (details.kind() == kData && !holder.is_null()) {
143 // Store to property not found on the receiver but on a prototype, we 198 // Store to property not found on the receiver but on a prototype, we
144 // need to transition to a new data property. 199 // need to transition to a new data property.
145 // Implemented according to ES6 section 9.1.9 [[Set]] (P, V, Receiver) 200 // Implemented according to ES6 section 9.1.9 [[Set]] (P, V, Receiver)
146 return LookupTransition(receiver_map, name, holder, access_info); 201 return LookupTransition(receiver_map, name, holder, access_info);
(...skipping 16 matching lines...) Expand all
163 field_type = type_cache_.kFloat64; 218 field_type = type_cache_.kFloat64;
164 } else if (field_representation.IsHeapObject()) { 219 } else if (field_representation.IsHeapObject()) {
165 // Extract the field type from the property details (make sure its 220 // Extract the field type from the property details (make sure its
166 // representation is TaggedPointer to reflect the heap object case). 221 // representation is TaggedPointer to reflect the heap object case).
167 field_type = Type::Intersect( 222 field_type = Type::Intersect(
168 Type::Convert<HeapType>( 223 Type::Convert<HeapType>(
169 handle(descriptors->GetFieldType(number), isolate()), zone()), 224 handle(descriptors->GetFieldType(number), isolate()), zone()),
170 Type::TaggedPointer(), zone()); 225 Type::TaggedPointer(), zone());
171 if (field_type->Is(Type::None())) { 226 if (field_type->Is(Type::None())) {
172 // Store is not safe if the field type was cleared. 227 // Store is not safe if the field type was cleared.
173 if (access_mode == PropertyAccessMode::kStore) return false; 228 if (access_mode == AccessMode::kStore) return false;
174 229
175 // The field type was cleared by the GC, so we don't know anything 230 // The field type was cleared by the GC, so we don't know anything
176 // about the contents now. 231 // about the contents now.
177 // TODO(bmeurer): It would be awesome to make this saner in the 232 // TODO(bmeurer): It would be awesome to make this saner in the
178 // runtime/GC interaction. 233 // runtime/GC interaction.
179 field_type = Type::TaggedPointer(); 234 field_type = Type::TaggedPointer();
180 } else if (!Type::Any()->Is(field_type)) { 235 } else if (!Type::Any()->Is(field_type)) {
181 // Add proper code dependencies in case of stable field map(s). 236 // Add proper code dependencies in case of stable field map(s).
182 Handle<Map> field_owner_map(map->FindFieldOwner(number), isolate()); 237 Handle<Map> field_owner_map(map->FindFieldOwner(number), isolate());
183 dependencies()->AssumeFieldType(field_owner_map); 238 dependencies()->AssumeFieldType(field_owner_map);
(...skipping 25 matching lines...) Expand all
209 // Implemented according to ES6 section 7.3.2 GetV (V, P). 264 // Implemented according to ES6 section 7.3.2 GetV (V, P).
210 Handle<JSFunction> constructor; 265 Handle<JSFunction> constructor;
211 if (Map::GetConstructorFunction(map, native_context()) 266 if (Map::GetConstructorFunction(map, native_context())
212 .ToHandle(&constructor)) { 267 .ToHandle(&constructor)) {
213 map = handle(constructor->initial_map(), isolate()); 268 map = handle(constructor->initial_map(), isolate());
214 DCHECK(map->prototype()->IsJSObject()); 269 DCHECK(map->prototype()->IsJSObject());
215 } else if (map->prototype()->IsNull()) { 270 } else if (map->prototype()->IsNull()) {
216 // Store to property not found on the receiver or any prototype, we need 271 // Store to property not found on the receiver or any prototype, we need
217 // to transition to a new data property. 272 // to transition to a new data property.
218 // Implemented according to ES6 section 9.1.9 [[Set]] (P, V, Receiver) 273 // Implemented according to ES6 section 9.1.9 [[Set]] (P, V, Receiver)
219 if (access_mode == PropertyAccessMode::kStore) { 274 if (access_mode == AccessMode::kStore) {
220 return LookupTransition(receiver_map, name, holder, access_info); 275 return LookupTransition(receiver_map, name, holder, access_info);
221 } 276 }
222 // The property was not found, return undefined or throw depending 277 // The property was not found, return undefined or throw depending
223 // on the language mode of the load operation. 278 // on the language mode of the load operation.
224 // Implemented according to ES6 section 9.1.8 [[Get]] (P, Receiver) 279 // Implemented according to ES6 section 9.1.8 [[Get]] (P, Receiver)
225 *access_info = PropertyAccessInfo::NotFound( 280 *access_info = PropertyAccessInfo::NotFound(
226 Type::Class(receiver_map, zone()), holder); 281 Type::Class(receiver_map, zone()), holder);
227 return true; 282 return true;
228 } else { 283 } else {
229 return false; 284 return false;
230 } 285 }
231 } 286 }
232 Handle<JSObject> map_prototype(JSObject::cast(map->prototype()), isolate()); 287 Handle<JSObject> map_prototype(JSObject::cast(map->prototype()), isolate());
233 if (map_prototype->map()->is_deprecated()) { 288 if (map_prototype->map()->is_deprecated()) {
234 // Try to migrate the prototype object so we don't embed the deprecated 289 // Try to migrate the prototype object so we don't embed the deprecated
235 // map into the optimized code. 290 // map into the optimized code.
236 JSObject::TryMigrateInstance(map_prototype); 291 JSObject::TryMigrateInstance(map_prototype);
237 } 292 }
238 map = handle(map_prototype->map(), isolate()); 293 map = handle(map_prototype->map(), isolate());
239 holder = map_prototype; 294 holder = map_prototype;
240 } while (CanInlinePropertyAccess(map)); 295 } while (CanInlinePropertyAccess(map));
241 return false; 296 return false;
242 } 297 }
243 298
244 299
245 bool PropertyAccessInfoFactory::ComputePropertyAccessInfos( 300 bool AccessInfoFactory::ComputePropertyAccessInfos(
246 MapHandleList const& maps, Handle<Name> name, 301 MapHandleList const& maps, Handle<Name> name, AccessMode access_mode,
247 PropertyAccessMode access_mode,
248 ZoneVector<PropertyAccessInfo>* access_infos) { 302 ZoneVector<PropertyAccessInfo>* access_infos) {
249 for (Handle<Map> map : maps) { 303 for (Handle<Map> map : maps) {
250 if (Map::TryUpdate(map).ToHandle(&map)) { 304 if (Map::TryUpdate(map).ToHandle(&map)) {
251 PropertyAccessInfo access_info; 305 PropertyAccessInfo access_info;
252 if (!ComputePropertyAccessInfo(map, name, access_mode, &access_info)) { 306 if (!ComputePropertyAccessInfo(map, name, access_mode, &access_info)) {
253 return false; 307 return false;
254 } 308 }
255 access_infos->push_back(access_info); 309 access_infos->push_back(access_info);
256 } 310 }
257 } 311 }
258 return true; 312 return true;
259 } 313 }
260 314
261 315
262 bool PropertyAccessInfoFactory::LookupSpecialFieldAccessor( 316 bool AccessInfoFactory::LookupSpecialFieldAccessor(
263 Handle<Map> map, Handle<Name> name, PropertyAccessInfo* access_info) { 317 Handle<Map> map, Handle<Name> name, PropertyAccessInfo* access_info) {
264 // Check for special JSObject field accessors. 318 // Check for special JSObject field accessors.
265 int offset; 319 int offset;
266 if (Accessors::IsJSObjectFieldAccessor(map, name, &offset)) { 320 if (Accessors::IsJSObjectFieldAccessor(map, name, &offset)) {
267 FieldIndex field_index = FieldIndex::ForInObjectOffset(offset); 321 FieldIndex field_index = FieldIndex::ForInObjectOffset(offset);
268 Type* field_type = Type::Tagged(); 322 Type* field_type = Type::Tagged();
269 if (map->IsStringMap()) { 323 if (map->IsStringMap()) {
270 DCHECK(Name::Equals(factory()->length_string(), name)); 324 DCHECK(Name::Equals(factory()->length_string(), name));
271 // The String::length property is always a smi in the range 325 // The String::length property is always a smi in the range
272 // [0, String::kMaxLength]. 326 // [0, String::kMaxLength].
(...skipping 14 matching lines...) Expand all
287 } 341 }
288 } 342 }
289 *access_info = PropertyAccessInfo::DataField(Type::Class(map, zone()), 343 *access_info = PropertyAccessInfo::DataField(Type::Class(map, zone()),
290 field_index, field_type); 344 field_index, field_type);
291 return true; 345 return true;
292 } 346 }
293 return false; 347 return false;
294 } 348 }
295 349
296 350
297 bool PropertyAccessInfoFactory::LookupTransition( 351 bool AccessInfoFactory::LookupTransition(Handle<Map> map, Handle<Name> name,
298 Handle<Map> map, Handle<Name> name, MaybeHandle<JSObject> holder, 352 MaybeHandle<JSObject> holder,
299 PropertyAccessInfo* access_info) { 353 PropertyAccessInfo* access_info) {
300 // Check if the {map} has a data transition with the given {name}. 354 // Check if the {map} has a data transition with the given {name}.
301 if (map->unused_property_fields() == 0) return false; 355 if (map->unused_property_fields() == 0) return false;
302 Handle<Map> transition_map; 356 Handle<Map> transition_map;
303 if (TransitionArray::SearchTransition(map, kData, name, NONE) 357 if (TransitionArray::SearchTransition(map, kData, name, NONE)
304 .ToHandle(&transition_map)) { 358 .ToHandle(&transition_map)) {
305 int const number = transition_map->LastAdded(); 359 int const number = transition_map->LastAdded();
306 PropertyDetails const details = 360 PropertyDetails const details =
307 transition_map->instance_descriptors()->GetDetails(number); 361 transition_map->instance_descriptors()->GetDetails(number);
308 // Don't bother optimizing stores to read-only properties. 362 // Don't bother optimizing stores to read-only properties.
309 if (details.IsReadOnly()) return false; 363 if (details.IsReadOnly()) return false;
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after
342 dependencies()->AssumeMapNotDeprecated(transition_map); 396 dependencies()->AssumeMapNotDeprecated(transition_map);
343 *access_info = 397 *access_info =
344 PropertyAccessInfo::DataField(Type::Class(map, zone()), field_index, 398 PropertyAccessInfo::DataField(Type::Class(map, zone()), field_index,
345 field_type, holder, transition_map); 399 field_type, holder, transition_map);
346 return true; 400 return true;
347 } 401 }
348 return false; 402 return false;
349 } 403 }
350 404
351 405
352 Factory* PropertyAccessInfoFactory::factory() const { 406 Factory* AccessInfoFactory::factory() const { return isolate()->factory(); }
353 return isolate()->factory();
354 }
355 407
356 } // namespace compiler 408 } // namespace compiler
357 } // namespace internal 409 } // namespace internal
358 } // namespace v8 410 } // namespace v8
OLDNEW
« no previous file with comments | « src/compiler/access-info.h ('k') | src/compiler/js-native-context-specialization.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698