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

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

Issue 2936673005: [turbofan] Refactor property access building. (Closed)
Patch Set: Address reviewer comments Created 3 years, 6 months 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-builder.h ('k') | src/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 2017 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 "src/compiler/property-access-builder.h"
6
7 #include "src/compilation-dependencies.h"
8 #include "src/compiler/access-builder.h"
9 #include "src/compiler/access-info.h"
10 #include "src/compiler/js-graph.h"
11 #include "src/compiler/node-matchers.h"
12 #include "src/compiler/simplified-operator.h"
13 #include "src/lookup.h"
14
15 #include "src/field-index-inl.h"
16 #include "src/isolate-inl.h"
17
18 namespace v8 {
19 namespace internal {
20 namespace compiler {
21
22 Graph* PropertyAccessBuilder::graph() const { return jsgraph()->graph(); }
23
24 Isolate* PropertyAccessBuilder::isolate() const { return jsgraph()->isolate(); }
25
26 CommonOperatorBuilder* PropertyAccessBuilder::common() const {
27 return jsgraph()->common();
28 }
29
30 SimplifiedOperatorBuilder* PropertyAccessBuilder::simplified() const {
31 return jsgraph()->simplified();
32 }
33
34 namespace {
35
36 bool HasOnlyNumberMaps(MapHandles const& maps) {
37 for (auto map : maps) {
38 if (map->instance_type() != HEAP_NUMBER_TYPE) return false;
39 }
40 return true;
41 }
42
43 bool HasOnlyStringMaps(MapHandles const& maps) {
44 for (auto map : maps) {
45 if (!map->IsStringMap()) return false;
46 }
47 return true;
48 }
49
50 bool HasOnlySequentialStringMaps(MapHandles const& maps) {
51 for (auto map : maps) {
52 if (!map->IsStringMap()) return false;
53 if (!StringShape(map->instance_type()).IsSequential()) {
54 return false;
55 }
56 }
57 return true;
58 }
59
60 } // namespace
61
62 bool PropertyAccessBuilder::TryBuildStringCheck(MapHandles const& maps,
63 Node** receiver, Node** effect,
64 Node* control) {
65 if (HasOnlyStringMaps(maps)) {
66 if (HasOnlySequentialStringMaps(maps)) {
67 *receiver = *effect = graph()->NewNode(simplified()->CheckSeqString(),
68 *receiver, *effect, control);
69 } else {
70 // Monormorphic string access (ignoring the fact that there are multiple
71 // String maps).
72 *receiver = *effect = graph()->NewNode(simplified()->CheckString(),
73 *receiver, *effect, control);
74 }
75 return true;
76 }
77 return false;
78 }
79
80 bool PropertyAccessBuilder::TryBuildNumberCheck(MapHandles const& maps,
81 Node** receiver, Node** effect,
82 Node* control) {
83 if (HasOnlyNumberMaps(maps)) {
84 // Monomorphic number access (we also deal with Smis here).
85 *receiver = *effect = graph()->NewNode(simplified()->CheckNumber(),
86 *receiver, *effect, control);
87 return true;
88 }
89 return false;
90 }
91
92 Node* PropertyAccessBuilder::BuildCheckHeapObject(Node* receiver, Node** effect,
93 Node* control) {
94 switch (receiver->opcode()) {
95 case IrOpcode::kHeapConstant:
96 case IrOpcode::kJSCreate:
97 case IrOpcode::kJSCreateArguments:
98 case IrOpcode::kJSCreateArray:
99 case IrOpcode::kJSCreateClosure:
100 case IrOpcode::kJSCreateIterResultObject:
101 case IrOpcode::kJSCreateLiteralArray:
102 case IrOpcode::kJSCreateLiteralObject:
103 case IrOpcode::kJSCreateLiteralRegExp:
104 case IrOpcode::kJSConvertReceiver:
105 case IrOpcode::kJSToName:
106 case IrOpcode::kJSToString:
107 case IrOpcode::kJSToObject:
108 case IrOpcode::kJSTypeOf: {
109 return receiver;
110 }
111 default: {
112 return *effect = graph()->NewNode(simplified()->CheckHeapObject(),
113 receiver, *effect, control);
114 }
115 }
116 UNREACHABLE();
117 return nullptr;
118 }
119
120 void PropertyAccessBuilder::BuildCheckMaps(
121 Node* receiver, Node** effect, Node* control,
122 std::vector<Handle<Map>> const& receiver_maps) {
123 HeapObjectMatcher m(receiver);
124 if (m.HasValue()) {
125 Handle<Map> receiver_map(m.Value()->map(), isolate());
126 if (receiver_map->is_stable()) {
127 for (Handle<Map> map : receiver_maps) {
128 if (map.is_identical_to(receiver_map)) {
129 dependencies()->AssumeMapStable(receiver_map);
130 return;
131 }
132 }
133 }
134 }
135 ZoneHandleSet<Map> maps;
136 CheckMapsFlags flags = CheckMapsFlag::kNone;
137 for (Handle<Map> map : receiver_maps) {
138 maps.insert(map, graph()->zone());
139 if (map->is_migration_target()) {
140 flags |= CheckMapsFlag::kTryMigrateInstance;
141 }
142 }
143 *effect = graph()->NewNode(simplified()->CheckMaps(flags, maps), receiver,
144 *effect, control);
145 }
146
147 void PropertyAccessBuilder::AssumePrototypesStable(
148 Handle<Context> native_context,
149 std::vector<Handle<Map>> const& receiver_maps, Handle<JSObject> holder) {
150 // Determine actual holder and perform prototype chain checks.
151 for (auto map : receiver_maps) {
152 // Perform the implicit ToObject for primitives here.
153 // Implemented according to ES6 section 7.3.2 GetV (V, P).
154 Handle<JSFunction> constructor;
155 if (Map::GetConstructorFunction(map, native_context)
156 .ToHandle(&constructor)) {
157 map = handle(constructor->initial_map(), holder->GetIsolate());
158 }
159 dependencies()->AssumePrototypeMapsStable(map, holder);
160 }
161 }
162
163 Node* PropertyAccessBuilder::ResolveHolder(
164 PropertyAccessInfo const& access_info, Node* receiver) {
165 Handle<JSObject> holder;
166 if (access_info.holder().ToHandle(&holder)) {
167 return jsgraph()->Constant(holder);
168 }
169 return receiver;
170 }
171
172 Node* PropertyAccessBuilder::TryBuildLoadConstantDataField(
173 Handle<Name> name, PropertyAccessInfo const& access_info, Node* receiver) {
174 // Optimize immutable property loads.
175 HeapObjectMatcher m(receiver);
176 if (m.HasValue() && m.Value()->IsJSObject()) {
177 // TODO(ishell): Use something simpler like
178 //
179 // Handle<Object> value =
180 // JSObject::FastPropertyAt(Handle<JSObject>::cast(m.Value()),
181 // Representation::Tagged(), field_index);
182 //
183 // here, once we have the immutable bit in the access_info.
184
185 // TODO(turbofan): Given that we already have the field_index here, we
186 // might be smarter in the future and not rely on the LookupIterator,
187 // but for now let's just do what Crankshaft does.
188 LookupIterator it(m.Value(), name, LookupIterator::OWN_SKIP_INTERCEPTOR);
189 if (it.state() == LookupIterator::DATA) {
190 bool is_reaonly_non_configurable =
191 it.IsReadOnly() && !it.IsConfigurable();
192 if (is_reaonly_non_configurable ||
193 (FLAG_track_constant_fields && access_info.IsDataConstantField())) {
194 Node* value = jsgraph()->Constant(JSReceiver::GetDataProperty(&it));
195 if (!is_reaonly_non_configurable) {
196 // It's necessary to add dependency on the map that introduced
197 // the field.
198 DCHECK(access_info.IsDataConstantField());
199 DCHECK(!it.is_dictionary_holder());
200 Handle<Map> field_owner_map = it.GetFieldOwnerMap();
201 dependencies()->AssumeFieldOwner(field_owner_map);
202 }
203 return value;
204 }
205 }
206 }
207 return nullptr;
208 }
209
210 Node* PropertyAccessBuilder::BuildLoadDataField(
211 Handle<Name> name, PropertyAccessInfo const& access_info, Node* receiver,
212 Node** effect, Node** control) {
213 DCHECK(access_info.IsDataField() || access_info.IsDataConstantField());
214 receiver = ResolveHolder(access_info, receiver);
215 if (Node* value =
216 TryBuildLoadConstantDataField(name, access_info, receiver)) {
217 return value;
218 }
219
220 FieldIndex const field_index = access_info.field_index();
221 Type* const field_type = access_info.field_type();
222 MachineRepresentation const field_representation =
223 access_info.field_representation();
224 Node* storage = receiver;
225 if (!field_index.is_inobject()) {
226 storage = *effect = graph()->NewNode(
227 simplified()->LoadField(AccessBuilder::ForJSObjectProperties()),
228 storage, *effect, *control);
229 }
230 FieldAccess field_access = {
231 kTaggedBase,
232 field_index.offset(),
233 name,
234 MaybeHandle<Map>(),
235 field_type,
236 MachineType::TypeForRepresentation(field_representation),
237 kFullWriteBarrier};
238 if (field_representation == MachineRepresentation::kFloat64) {
239 if (!field_index.is_inobject() || field_index.is_hidden_field() ||
240 !FLAG_unbox_double_fields) {
241 FieldAccess const storage_access = {kTaggedBase,
242 field_index.offset(),
243 name,
244 MaybeHandle<Map>(),
245 Type::OtherInternal(),
246 MachineType::TaggedPointer(),
247 kPointerWriteBarrier};
248 storage = *effect = graph()->NewNode(
249 simplified()->LoadField(storage_access), storage, *effect, *control);
250 field_access.offset = HeapNumber::kValueOffset;
251 field_access.name = MaybeHandle<Name>();
252 }
253 } else if (field_representation == MachineRepresentation::kTaggedPointer) {
254 // Remember the map of the field value, if its map is stable. This is
255 // used by the LoadElimination to eliminate map checks on the result.
256 Handle<Map> field_map;
257 if (access_info.field_map().ToHandle(&field_map)) {
258 if (field_map->is_stable()) {
259 dependencies()->AssumeMapStable(field_map);
260 field_access.map = field_map;
261 }
262 }
263 }
264 Node* value = *effect = graph()->NewNode(
265 simplified()->LoadField(field_access), storage, *effect, *control);
266 return value;
267 }
268
269 } // namespace compiler
270 } // namespace internal
271 } // namespace v8
OLDNEW
« no previous file with comments | « src/compiler/property-access-builder.h ('k') | src/v8.gyp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698