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

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

Issue 1416973014: [turbofan] Move PropertyAccessInfo and friends to a separate file. (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@master
Patch Set: Add missing factory() method. 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') | tools/gyp/v8.gyp » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
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
3 // found in the LICENSE file.
4
5 #include <ostream>
6
7 #include "src/accessors.h"
8 #include "src/compilation-dependencies.h"
9 #include "src/compiler/property-access-info.h"
10 #include "src/field-index-inl.h"
11 #include "src/objects-inl.h" // TODO(mstarzinger): Temporary cycle breaker!
12 #include "src/type-cache.h"
13 #include "src/types-inl.h"
14
15 namespace v8 {
16 namespace internal {
17 namespace compiler {
18
19 std::ostream& operator<<(std::ostream& os, PropertyAccessMode access_mode) {
20 switch (access_mode) {
21 case PropertyAccessMode::kLoad:
22 return os << "Load";
23 case PropertyAccessMode::kStore:
24 return os << "Store";
25 }
26 UNREACHABLE();
27 return os;
28 }
29
30
31 PropertyAccessInfo::PropertyAccessInfo()
32 : kind_(kInvalid), receiver_type_(Type::None()), field_type_(Type::Any()) {}
33
34
35 PropertyAccessInfo::PropertyAccessInfo(MaybeHandle<JSObject> holder,
36 Handle<Object> constant,
37 Type* receiver_type)
38 : kind_(kDataConstant),
39 receiver_type_(receiver_type),
40 constant_(constant),
41 holder_(holder),
42 field_type_(Type::Any()) {}
43
44
45 PropertyAccessInfo::PropertyAccessInfo(MaybeHandle<JSObject> holder,
46 MaybeHandle<Map> transition_map,
47 FieldIndex field_index, Type* field_type,
48 Type* receiver_type)
49 : kind_(kDataField),
50 receiver_type_(receiver_type),
51 transition_map_(transition_map),
52 holder_(holder),
53 field_index_(field_index),
54 field_type_(field_type) {}
55
56
57 PropertyAccessInfoFactory::PropertyAccessInfoFactory(
58 CompilationDependencies* dependencies, Handle<Context> native_context,
59 Zone* zone)
60 : dependencies_(dependencies),
61 native_context_(native_context),
62 isolate_(native_context->GetIsolate()),
63 type_cache_(TypeCache::Get()),
64 zone_(zone) {}
65
66
67 namespace {
68
69 bool CanInlinePropertyAccess(Handle<Map> map) {
70 // TODO(bmeurer): Do something about the number stuff.
71 if (map->instance_type() == HEAP_NUMBER_TYPE) return false;
72 if (map->instance_type() < FIRST_NONSTRING_TYPE) return true;
73 return map->IsJSObjectMap() && !map->is_dictionary_map() &&
74 !map->has_named_interceptor() &&
75 // TODO(verwaest): Whitelist contexts to which we have access.
76 !map->is_access_check_needed();
77 }
78
79 } // namespace
80
81
82 bool PropertyAccessInfoFactory::ComputePropertyAccessInfo(
83 Handle<Map> map, Handle<Name> name, PropertyAccessMode access_mode,
84 PropertyAccessInfo* access_info) {
85 // Check if it is safe to inline property access for the {map}.
86 if (!CanInlinePropertyAccess(map)) return false;
87
88 // Compute the receiver type.
89 Handle<Map> receiver_map = map;
90 Type* receiver_type = Type::Class(receiver_map, zone());
91
92 // We support fast inline cases for certain JSObject getters.
93 if (access_mode == PropertyAccessMode::kLoad) {
94 // Check for special JSObject field accessors.
95 int offset;
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 }
124
125 MaybeHandle<JSObject> holder;
126 while (true) {
127 // Lookup the named property on the {map}.
128 Handle<DescriptorArray> descriptors(map->instance_descriptors(), isolate());
129 int const number = descriptors->SearchWithCache(*name, *map);
130 if (number != DescriptorArray::kNotFound) {
131 PropertyDetails const details = descriptors->GetDetails(number);
132 if (access_mode == PropertyAccessMode::kStore) {
133 // Don't bother optimizing stores to read-only properties.
134 if (details.IsReadOnly()) {
135 return false;
136 }
137 // Check for store to data property on a prototype.
138 if (details.kind() == kData && !holder.is_null()) {
139 // We need to add the data field to the receiver. Leave the loop
140 // and check whether we already have a transition for this field.
141 // Implemented according to ES6 section 9.1.9 [[Set]] (P, V, Receiver)
142 break;
143 }
144 }
145 if (details.type() == DATA_CONSTANT) {
146 *access_info = PropertyAccessInfo::DataConstant(
147 receiver_type, handle(descriptors->GetValue(number), isolate()),
148 holder);
149 return true;
150 } else if (details.type() == DATA) {
151 int index = descriptors->GetFieldIndex(number);
152 Representation field_representation = details.representation();
153 FieldIndex field_index = FieldIndex::ForPropertyIndex(
154 *map, index, field_representation.IsDouble());
155 Type* field_type = Type::Tagged();
156 if (field_representation.IsSmi()) {
157 field_type = type_cache_.kSmi;
158 } else if (field_representation.IsDouble()) {
159 field_type = type_cache_.kFloat64;
160 } else if (field_representation.IsHeapObject()) {
161 // Extract the field type from the property details (make sure its
162 // representation is TaggedPointer to reflect the heap object case).
163 field_type = Type::Intersect(
164 Type::Convert<HeapType>(
165 handle(descriptors->GetFieldType(number), isolate()), zone()),
166 Type::TaggedPointer(), zone());
167 if (field_type->Is(Type::None())) {
168 // Store is not safe if the field type was cleared.
169 if (access_mode == PropertyAccessMode::kStore) return false;
170
171 // The field type was cleared by the GC, so we don't know anything
172 // about the contents now.
173 // TODO(bmeurer): It would be awesome to make this saner in the
174 // runtime/GC interaction.
175 field_type = Type::TaggedPointer();
176 } else if (!Type::Any()->Is(field_type)) {
177 // Add proper code dependencies in case of stable field map(s).
178 Handle<Map> field_owner_map(map->FindFieldOwner(number), isolate());
179 dependencies()->AssumeFieldType(field_owner_map);
180 }
181 DCHECK(field_type->Is(Type::TaggedPointer()));
182 }
183 *access_info = PropertyAccessInfo::DataField(receiver_type, field_index,
184 field_type, holder);
185 return true;
186 } else {
187 // TODO(bmeurer): Add support for accessors.
188 return false;
189 }
190 }
191
192 // Don't search on the prototype chain for special indices in case of
193 // integer indexed exotic objects (see ES6 section 9.4.5).
194 if (map->IsJSTypedArrayMap() && name->IsString() &&
195 IsSpecialIndex(isolate()->unicode_cache(), String::cast(*name))) {
196 return false;
197 }
198
199 // Don't lookup private symbols on the prototype chain.
200 if (name->IsPrivate()) return false;
201
202 // Walk up the prototype chain.
203 if (!map->prototype()->IsJSObject()) {
204 // Perform the implicit ToObject for primitives here.
205 // Implemented according to ES6 section 7.3.2 GetV (V, P).
206 Handle<JSFunction> constructor;
207 if (Map::GetConstructorFunction(map, native_context())
208 .ToHandle(&constructor)) {
209 map = handle(constructor->initial_map(), isolate());
210 DCHECK(map->prototype()->IsJSObject());
211 } else if (map->prototype()->IsNull()) {
212 // Store to property not found on the receiver or any prototype, we need
213 // to transition to a new data property.
214 // Implemented according to ES6 section 9.1.9 [[Set]] (P, V, Receiver)
215 if (access_mode == PropertyAccessMode::kStore) {
216 break;
217 }
218 // TODO(bmeurer): Handle the not found case if the prototype is null.
219 return false;
220 } else {
221 return false;
222 }
223 }
224 Handle<JSObject> map_prototype(JSObject::cast(map->prototype()), isolate());
225 if (map_prototype->map()->is_deprecated()) {
226 // Try to migrate the prototype object so we don't embed the deprecated
227 // map into the optimized code.
228 JSObject::TryMigrateInstance(map_prototype);
229 }
230 map = handle(map_prototype->map(), isolate());
231 holder = map_prototype;
232
233 // Check if it is safe to inline property access for the {map}.
234 if (!CanInlinePropertyAccess(map)) return false;
235 }
236 DCHECK_EQ(PropertyAccessMode::kStore, access_mode);
237
238 // Check if the {receiver_map} has a data transition with the given {name}.
239 if (receiver_map->unused_property_fields() == 0) return false;
240 if (Map* transition = TransitionArray::SearchTransition(*receiver_map, kData,
241 *name, NONE)) {
242 Handle<Map> transition_map(transition, isolate());
243 int const number = transition_map->LastAdded();
244 PropertyDetails const details =
245 transition_map->instance_descriptors()->GetDetails(number);
246 // Don't bother optimizing stores to read-only properties.
247 if (details.IsReadOnly()) return false;
248 // TODO(bmeurer): Handle transition to data constant?
249 if (details.type() != DATA) return false;
250 int const index = details.field_index();
251 Representation field_representation = details.representation();
252 FieldIndex field_index = FieldIndex::ForPropertyIndex(
253 *transition_map, index, field_representation.IsDouble());
254 Type* field_type = Type::Tagged();
255 if (field_representation.IsSmi()) {
256 field_type = type_cache_.kSmi;
257 } else if (field_representation.IsDouble()) {
258 // TODO(bmeurer): Add support for storing to double fields.
259 return false;
260 } else if (field_representation.IsHeapObject()) {
261 // Extract the field type from the property details (make sure its
262 // representation is TaggedPointer to reflect the heap object case).
263 field_type = Type::Intersect(
264 Type::Convert<HeapType>(
265 handle(
266 transition_map->instance_descriptors()->GetFieldType(number),
267 isolate()),
268 zone()),
269 Type::TaggedPointer(), zone());
270 if (field_type->Is(Type::None())) {
271 // Store is not safe if the field type was cleared.
272 return false;
273 } else if (!Type::Any()->Is(field_type)) {
274 // Add proper code dependencies in case of stable field map(s).
275 Handle<Map> field_owner_map(transition_map->FindFieldOwner(number),
276 isolate());
277 dependencies()->AssumeFieldType(field_owner_map);
278 }
279 DCHECK(field_type->Is(Type::TaggedPointer()));
280 }
281 dependencies()->AssumeMapNotDeprecated(transition_map);
282 *access_info = PropertyAccessInfo::DataField(
283 receiver_type, field_index, field_type, holder, transition_map);
284 return true;
285 }
286 return false;
287 }
288
289
290 bool PropertyAccessInfoFactory::ComputePropertyAccessInfos(
291 MapHandleList const& maps, Handle<Name> name,
292 PropertyAccessMode access_mode,
293 ZoneVector<PropertyAccessInfo>* access_infos) {
294 for (Handle<Map> map : maps) {
295 if (Map::TryUpdate(map).ToHandle(&map)) {
296 PropertyAccessInfo access_info;
297 if (!ComputePropertyAccessInfo(map, name, access_mode, &access_info)) {
298 return false;
299 }
300 access_infos->push_back(access_info);
301 }
302 }
303 return true;
304 }
305
306
307 Factory* PropertyAccessInfoFactory::factory() const {
308 return isolate()->factory();
309 }
310
311 } // namespace compiler
312 } // namespace internal
313 } // namespace v8
OLDNEW
« no previous file with comments | « src/compiler/property-access-info.h ('k') | tools/gyp/v8.gyp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698