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

Side by Side Diff: src/compiler/js-native-context-specialization.cc

Issue 2191823002: [turbofan] Refactor the lowering of element/property accesses. (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@master
Patch Set: Created 4 years, 4 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/js-native-context-specialization.h ('k') | src/compiler/load-elimination.cc » ('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 "src/compiler/js-native-context-specialization.h" 5 #include "src/compiler/js-native-context-specialization.h"
6 6
7 #include "src/accessors.h" 7 #include "src/accessors.h"
8 #include "src/code-factory.h" 8 #include "src/code-factory.h"
9 #include "src/compilation-dependencies.h" 9 #include "src/compilation-dependencies.h"
10 #include "src/compiler/access-builder.h" 10 #include "src/compiler/access-builder.h"
11 #include "src/compiler/access-info.h" 11 #include "src/compiler/access-info.h"
12 #include "src/compiler/js-graph.h" 12 #include "src/compiler/js-graph.h"
13 #include "src/compiler/js-operator.h" 13 #include "src/compiler/js-operator.h"
14 #include "src/compiler/linkage.h" 14 #include "src/compiler/linkage.h"
15 #include "src/compiler/node-matchers.h" 15 #include "src/compiler/node-matchers.h"
16 #include "src/field-index-inl.h" 16 #include "src/field-index-inl.h"
17 #include "src/isolate-inl.h" 17 #include "src/isolate-inl.h"
18 #include "src/type-cache.h" 18 #include "src/type-cache.h"
19 #include "src/type-feedback-vector.h" 19 #include "src/type-feedback-vector.h"
20 20
21 namespace v8 { 21 namespace v8 {
22 namespace internal { 22 namespace internal {
23 namespace compiler { 23 namespace compiler {
24 24
25 namespace {
26
27 bool HasNumberMaps(MapList const& maps) {
28 for (auto map : maps) {
29 if (map->instance_type() == HEAP_NUMBER_TYPE) return true;
30 }
31 return false;
32 }
33
34 bool HasOnlyJSArrayMaps(MapList const& maps) {
35 for (auto map : maps) {
36 if (!map->IsJSArrayMap()) return false;
37 }
38 return true;
39 }
40
41 bool HasOnlyNumberMaps(MapList const& maps) {
42 for (auto map : maps) {
43 if (map->instance_type() != HEAP_NUMBER_TYPE) return false;
44 }
45 return true;
46 }
47
48 bool HasOnlyStringMaps(MapList const& maps) {
49 for (auto map : maps) {
50 if (!map->IsStringMap()) return false;
51 }
52 return true;
53 }
54
55 } // namespace
56
25 JSNativeContextSpecialization::JSNativeContextSpecialization( 57 JSNativeContextSpecialization::JSNativeContextSpecialization(
26 Editor* editor, JSGraph* jsgraph, Flags flags, 58 Editor* editor, JSGraph* jsgraph, Flags flags,
27 MaybeHandle<Context> native_context, CompilationDependencies* dependencies, 59 MaybeHandle<Context> native_context, CompilationDependencies* dependencies,
28 Zone* zone) 60 Zone* zone)
29 : AdvancedReducer(editor), 61 : AdvancedReducer(editor),
30 jsgraph_(jsgraph), 62 jsgraph_(jsgraph),
31 flags_(flags), 63 flags_(flags),
32 native_context_(native_context), 64 native_context_(native_context),
33 dependencies_(dependencies), 65 dependencies_(dependencies),
34 zone_(zone), 66 zone_(zone),
(...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after
93 graph()->zone()); 125 graph()->zone());
94 ZoneVector<PropertyAccessInfo> access_infos(zone()); 126 ZoneVector<PropertyAccessInfo> access_infos(zone());
95 if (!access_info_factory.ComputePropertyAccessInfos( 127 if (!access_info_factory.ComputePropertyAccessInfos(
96 receiver_maps, name, access_mode, &access_infos)) { 128 receiver_maps, name, access_mode, &access_infos)) {
97 return NoChange(); 129 return NoChange();
98 } 130 }
99 131
100 // Nothing to do if we have no non-deprecated maps. 132 // Nothing to do if we have no non-deprecated maps.
101 if (access_infos.empty()) return NoChange(); 133 if (access_infos.empty()) return NoChange();
102 134
103 // The final states for every polymorphic branch. We join them with
104 // Merge++Phi+EffectPhi at the bottom.
105 ZoneVector<Node*> values(zone());
106 ZoneVector<Node*> effects(zone());
107 ZoneVector<Node*> controls(zone());
108
109 // Ensure that {index} matches the specified {name} (if {index} is given). 135 // Ensure that {index} matches the specified {name} (if {index} is given).
110 if (index != nullptr) { 136 if (index != nullptr) {
111 Node* check = graph()->NewNode(simplified()->ReferenceEqual(Type::Name()), 137 Node* check = graph()->NewNode(simplified()->ReferenceEqual(Type::Name()),
112 index, jsgraph()->HeapConstant(name)); 138 index, jsgraph()->HeapConstant(name));
113 effect = graph()->NewNode(simplified()->CheckIf(), check, effect, control); 139 effect = graph()->NewNode(simplified()->CheckIf(), check, effect, control);
114 } 140 }
115 141
116 // Check if {receiver} may be a number. 142 // Check for the monomorphic cases.
117 bool receiverissmi_possible = false; 143 if (access_infos.size() == 1 &&
118 for (PropertyAccessInfo const& access_info : access_infos) { 144 HasOnlyStringMaps(access_infos[0].receiver_maps())) {
119 if (access_info.receiver_type()->Is(Type::Number())) { 145 // Monormorphic string access (ignoring the fact that there are multiple
120 receiverissmi_possible = true; 146 // String maps).
121 break; 147 receiver = effect = graph()->NewNode(simplified()->CheckString(), receiver,
122 } 148 effect, control);
123 }
124
125 // Ensure that {receiver} is a heap object.
126 Node* receiverissmi_control = nullptr;
127 Node* receiverissmi_effect = effect;
128 if (receiverissmi_possible) {
129 Node* check = graph()->NewNode(simplified()->ObjectIsSmi(), receiver);
130 Node* branch = graph()->NewNode(common()->Branch(), check, control);
131 control = graph()->NewNode(common()->IfFalse(), branch);
132 receiverissmi_control = graph()->NewNode(common()->IfTrue(), branch);
133 receiverissmi_effect = effect;
134 } else if (access_infos.size() != 1 ||
135 !access_infos[0].receiver_type()->Is(Type::String())) {
136 // TODO(bmeurer): We omit the Smi check here if we are going to lower to
137 // the CheckString below; make this less horrible and adhoc.
138 receiver = effect = graph()->NewNode(simplified()->CheckTaggedPointer(),
139 receiver, effect, control);
140 }
141
142 // Load the {receiver} map. The resulting effect is the dominating effect for
143 // all (polymorphic) branches.
144 Node* receiver_map = effect =
145 graph()->NewNode(simplified()->LoadField(AccessBuilder::ForMap()),
146 receiver, effect, control);
147
148 // Generate code for the various different property access patterns.
149 Node* fallthrough_control = control;
150 for (size_t j = 0; j < access_infos.size(); ++j) {
151 PropertyAccessInfo const& access_info = access_infos[j];
152 Node* this_value = value;
153 Node* this_receiver = receiver;
154 Node* this_effect = effect;
155 Node* this_control;
156
157 // Perform map check on {receiver}.
158 Type* receiver_type = access_info.receiver_type();
159 if (receiver_type->Is(Type::String())) {
160 if (j == access_infos.size() - 1) {
161 this_receiver = this_effect =
162 graph()->NewNode(simplified()->CheckString(), receiver, this_effect,
163 fallthrough_control);
164 this_control = fallthrough_control;
165 fallthrough_control = nullptr;
166 } else {
167 Node* check =
168 graph()->NewNode(simplified()->ObjectIsString(), receiver);
169 Node* branch =
170 graph()->NewNode(common()->Branch(), check, fallthrough_control);
171 fallthrough_control = graph()->NewNode(common()->IfFalse(), branch);
172 this_control = graph()->NewNode(common()->IfTrue(), branch);
173 }
174 } else {
175 // Emit a (sequence of) map checks for other {receiver}s.
176 ZoneVector<Node*> this_controls(zone());
177 ZoneVector<Node*> this_effects(zone());
178 int num_classes = access_info.receiver_type()->NumClasses();
179 for (auto i = access_info.receiver_type()->Classes(); !i.Done();
180 i.Advance()) {
181 DCHECK_LT(0, num_classes);
182 Handle<Map> map = i.Current();
183 Node* check =
184 graph()->NewNode(simplified()->ReferenceEqual(Type::Internal()),
185 receiver_map, jsgraph()->Constant(map));
186 if (--num_classes == 0 && j == access_infos.size() - 1) {
187 check = graph()->NewNode(simplified()->CheckIf(), check, this_effect,
188 fallthrough_control);
189 this_controls.push_back(fallthrough_control);
190 this_effects.push_back(check);
191 fallthrough_control = nullptr;
192 } else {
193 Node* branch =
194 graph()->NewNode(common()->Branch(), check, fallthrough_control);
195 fallthrough_control = graph()->NewNode(common()->IfFalse(), branch);
196 this_controls.push_back(graph()->NewNode(common()->IfTrue(), branch));
197 this_effects.push_back(this_effect);
198 }
199 }
200
201 // The Number case requires special treatment to also deal with Smis.
202 if (receiver_type->Is(Type::Number())) {
203 // Join this check with the "receiver is smi" check above.
204 DCHECK_NOT_NULL(receiverissmi_effect);
205 DCHECK_NOT_NULL(receiverissmi_control);
206 this_effects.push_back(receiverissmi_effect);
207 this_controls.push_back(receiverissmi_control);
208 receiverissmi_effect = receiverissmi_control = nullptr;
209 }
210
211 // Create dominating Merge+EffectPhi for this {receiver} type.
212 int const this_control_count = static_cast<int>(this_controls.size());
213 this_control =
214 (this_control_count == 1)
215 ? this_controls.front()
216 : graph()->NewNode(common()->Merge(this_control_count),
217 this_control_count, &this_controls.front());
218 this_effects.push_back(this_control);
219 int const this_effect_count = static_cast<int>(this_effects.size());
220 this_effect =
221 (this_control_count == 1)
222 ? this_effects.front()
223 : graph()->NewNode(common()->EffectPhi(this_control_count),
224 this_effect_count, &this_effects.front());
225 }
226
227 // Determine actual holder and perform prototype chain checks.
228 Handle<JSObject> holder;
229 if (access_info.holder().ToHandle(&holder)) {
230 AssumePrototypesStable(receiver_type, native_context, holder);
231 }
232 149
233 // Generate the actual property access. 150 // Generate the actual property access.
234 if (access_info.IsNotFound()) { 151 ValueEffectControl continuation =
235 DCHECK_EQ(AccessMode::kLoad, access_mode); 152 BuildPropertyAccess(receiver, value, effect, control, name,
236 this_value = jsgraph()->UndefinedConstant(); 153 native_context, access_infos[0], access_mode);
237 } else if (access_info.IsDataConstant()) { 154 value = continuation.value();
238 this_value = jsgraph()->Constant(access_info.constant()); 155 effect = continuation.effect();
239 if (access_mode == AccessMode::kStore) { 156 control = continuation.control();
240 Node* check = graph()->NewNode( 157 } else if (access_infos.size() == 1 &&
241 simplified()->ReferenceEqual(Type::Tagged()), value, this_value); 158 HasOnlyNumberMaps(access_infos[0].receiver_maps())) {
242 this_effect = graph()->NewNode(simplified()->CheckIf(), check, 159 // Monomorphic number access (we also deal with Smis here).
243 this_effect, this_control); 160 receiver = effect = graph()->NewNode(simplified()->CheckNumber(), receiver,
244 } 161 effect, control);
245 } else {
246 DCHECK(access_info.IsDataField());
247 FieldIndex const field_index = access_info.field_index();
248 Type* const field_type = access_info.field_type();
249 if (access_mode == AccessMode::kLoad &&
250 access_info.holder().ToHandle(&holder)) {
251 this_receiver = jsgraph()->Constant(holder);
252 }
253 Node* this_storage = this_receiver;
254 if (!field_index.is_inobject()) {
255 this_storage = this_effect = graph()->NewNode(
256 simplified()->LoadField(AccessBuilder::ForJSObjectProperties()),
257 this_storage, this_effect, this_control);
258 }
259 FieldAccess field_access = {
260 kTaggedBase, field_index.offset(), name,
261 field_type, MachineType::AnyTagged(), kFullWriteBarrier};
262 if (access_mode == AccessMode::kLoad) {
263 if (field_type->Is(Type::UntaggedFloat64())) {
264 if (!field_index.is_inobject() || field_index.is_hidden_field() ||
265 !FLAG_unbox_double_fields) {
266 this_storage = this_effect =
267 graph()->NewNode(simplified()->LoadField(field_access),
268 this_storage, this_effect, this_control);
269 field_access.offset = HeapNumber::kValueOffset;
270 field_access.name = MaybeHandle<Name>();
271 }
272 field_access.machine_type = MachineType::Float64();
273 }
274 this_value = this_effect =
275 graph()->NewNode(simplified()->LoadField(field_access),
276 this_storage, this_effect, this_control);
277 } else {
278 DCHECK_EQ(AccessMode::kStore, access_mode);
279 if (field_type->Is(Type::UntaggedFloat64())) {
280 this_value = this_effect =
281 graph()->NewNode(simplified()->CheckNumber(), this_value,
282 this_effect, this_control);
283 162
284 if (!field_index.is_inobject() || field_index.is_hidden_field() || 163 // Generate the actual property access.
285 !FLAG_unbox_double_fields) { 164 ValueEffectControl continuation =
286 if (access_info.HasTransitionMap()) { 165 BuildPropertyAccess(receiver, value, effect, control, name,
287 // Allocate a MutableHeapNumber for the new property. 166 native_context, access_infos[0], access_mode);
288 this_effect = graph()->NewNode( 167 value = continuation.value();
289 common()->BeginRegion(RegionObservability::kNotObservable), 168 effect = continuation.effect();
290 this_effect); 169 control = continuation.control();
291 Node* this_box = this_effect = 170 } else {
292 graph()->NewNode(simplified()->Allocate(NOT_TENURED), 171 // The final states for every polymorphic branch. We join them with
293 jsgraph()->Constant(HeapNumber::kSize), 172 // Merge+Phi+EffectPhi at the bottom.
294 this_effect, this_control); 173 ZoneVector<Node*> values(zone());
295 this_effect = graph()->NewNode( 174 ZoneVector<Node*> effects(zone());
296 simplified()->StoreField(AccessBuilder::ForMap()), this_box, 175 ZoneVector<Node*> controls(zone());
297 jsgraph()->HeapConstant(factory()->mutable_heap_number_map()),
298 this_effect, this_control);
299 this_effect = graph()->NewNode(
300 simplified()->StoreField(AccessBuilder::ForHeapNumberValue()),
301 this_box, this_value, this_effect, this_control);
302 this_value = this_effect = graph()->NewNode(
303 common()->FinishRegion(), this_box, this_effect);
304 176
305 field_access.type = Type::TaggedPointer(); 177 // Check if {receiver} may be a number.
306 } else { 178 bool receiverissmi_possible = false;
307 // We just store directly to the MutableHeapNumber. 179 for (PropertyAccessInfo const& access_info : access_infos) {
308 this_storage = this_effect = 180 if (HasNumberMaps(access_info.receiver_maps())) {
309 graph()->NewNode(simplified()->LoadField(field_access), 181 receiverissmi_possible = true;
310 this_storage, this_effect, this_control); 182 break;
311 field_access.offset = HeapNumber::kValueOffset;
312 field_access.name = MaybeHandle<Name>();
313 field_access.machine_type = MachineType::Float64();
314 }
315 } else {
316 // Unboxed double field, we store directly to the field.
317 field_access.machine_type = MachineType::Float64();
318 }
319 } else if (field_type->Is(Type::TaggedSigned())) {
320 this_value = this_effect =
321 graph()->NewNode(simplified()->CheckTaggedSigned(), this_value,
322 this_effect, this_control);
323 } else if (field_type->Is(Type::TaggedPointer())) {
324 this_value = this_effect =
325 graph()->NewNode(simplified()->CheckTaggedPointer(), this_value,
326 this_effect, this_control);
327 if (field_type->NumClasses() == 1) {
328 // Emit a map check for the value.
329 Node* this_value_map = this_effect = graph()->NewNode(
330 simplified()->LoadField(AccessBuilder::ForMap()), this_value,
331 this_effect, this_control);
332 Node* check = graph()->NewNode(
333 simplified()->ReferenceEqual(Type::Internal()), this_value_map,
334 jsgraph()->Constant(field_type->Classes().Current()));
335 this_effect = graph()->NewNode(simplified()->CheckIf(), check,
336 this_effect, this_control);
337 } else {
338 DCHECK_EQ(0, field_type->NumClasses());
339 }
340 } else {
341 DCHECK(field_type->Is(Type::Tagged()));
342 }
343 Handle<Map> transition_map;
344 if (access_info.transition_map().ToHandle(&transition_map)) {
345 this_effect = graph()->NewNode(
346 common()->BeginRegion(RegionObservability::kObservable),
347 this_effect);
348 this_effect = graph()->NewNode(
349 simplified()->StoreField(AccessBuilder::ForMap()), this_receiver,
350 jsgraph()->Constant(transition_map), this_effect, this_control);
351 }
352 this_effect = graph()->NewNode(simplified()->StoreField(field_access),
353 this_storage, this_value, this_effect,
354 this_control);
355 if (access_info.HasTransitionMap()) {
356 this_effect =
357 graph()->NewNode(common()->FinishRegion(),
358 jsgraph()->UndefinedConstant(), this_effect);
359 }
360 } 183 }
361 } 184 }
362 185
363 // Remember the final state for this property access. 186 // Ensure that {receiver} is a heap object.
364 values.push_back(this_value); 187 Node* receiverissmi_control = nullptr;
365 effects.push_back(this_effect); 188 Node* receiverissmi_effect = effect;
366 controls.push_back(this_control); 189 if (receiverissmi_possible) {
367 } 190 Node* check = graph()->NewNode(simplified()->ObjectIsSmi(), receiver);
191 Node* branch = graph()->NewNode(common()->Branch(), check, control);
192 control = graph()->NewNode(common()->IfFalse(), branch);
193 receiverissmi_control = graph()->NewNode(common()->IfTrue(), branch);
194 receiverissmi_effect = effect;
195 } else {
196 receiver = effect = graph()->NewNode(simplified()->CheckTaggedPointer(),
197 receiver, effect, control);
198 }
368 199
369 DCHECK_NULL(fallthrough_control); 200 // Load the {receiver} map. The resulting effect is the dominating effect
201 // for all (polymorphic) branches.
202 Node* receiver_map = effect =
203 graph()->NewNode(simplified()->LoadField(AccessBuilder::ForMap()),
204 receiver, effect, control);
370 205
371 // Generate the final merge point for all (polymorphic) branches. 206 // Generate code for the various different property access patterns.
372 int const control_count = static_cast<int>(controls.size()); 207 Node* fallthrough_control = control;
373 if (control_count == 0) { 208 for (size_t j = 0; j < access_infos.size(); ++j) {
374 value = effect = control = jsgraph()->Dead(); 209 PropertyAccessInfo const& access_info = access_infos[j];
375 } else if (control_count == 1) { 210 Node* this_value = value;
376 value = values.front(); 211 Node* this_receiver = receiver;
377 effect = effects.front(); 212 Node* this_effect = effect;
378 control = controls.front(); 213 Node* this_control;
379 } else { 214
380 control = graph()->NewNode(common()->Merge(control_count), control_count, 215 // Perform map check on {receiver}.
381 &controls.front()); 216 MapList const& receiver_maps = access_info.receiver_maps();
382 values.push_back(control); 217 {
383 value = graph()->NewNode( 218 // Emit a (sequence of) map checks for other {receiver}s.
384 common()->Phi(MachineRepresentation::kTagged, control_count), 219 ZoneVector<Node*> this_controls(zone());
385 control_count + 1, &values.front()); 220 ZoneVector<Node*> this_effects(zone());
386 effects.push_back(control); 221 size_t num_classes = receiver_maps.size();
387 effect = graph()->NewNode(common()->EffectPhi(control_count), 222 for (auto map : receiver_maps) {
388 control_count + 1, &effects.front()); 223 DCHECK_LT(0u, num_classes);
224 Node* check =
225 graph()->NewNode(simplified()->ReferenceEqual(Type::Internal()),
226 receiver_map, jsgraph()->Constant(map));
227 if (--num_classes == 0 && j == access_infos.size() - 1) {
228 check = graph()->NewNode(simplified()->CheckIf(), check,
229 this_effect, fallthrough_control);
230 this_controls.push_back(fallthrough_control);
231 this_effects.push_back(check);
232 fallthrough_control = nullptr;
233 } else {
234 Node* branch = graph()->NewNode(common()->Branch(), check,
235 fallthrough_control);
236 fallthrough_control = graph()->NewNode(common()->IfFalse(), branch);
237 this_controls.push_back(
238 graph()->NewNode(common()->IfTrue(), branch));
239 this_effects.push_back(this_effect);
240 }
241 }
242
243 // The Number case requires special treatment to also deal with Smis.
244 if (HasNumberMaps(receiver_maps)) {
245 // Join this check with the "receiver is smi" check above.
246 DCHECK_NOT_NULL(receiverissmi_effect);
247 DCHECK_NOT_NULL(receiverissmi_control);
248 this_effects.push_back(receiverissmi_effect);
249 this_controls.push_back(receiverissmi_control);
250 receiverissmi_effect = receiverissmi_control = nullptr;
251 }
252
253 // Create dominating Merge+EffectPhi for this {receiver} type.
254 int const this_control_count = static_cast<int>(this_controls.size());
255 this_control =
256 (this_control_count == 1)
257 ? this_controls.front()
258 : graph()->NewNode(common()->Merge(this_control_count),
259 this_control_count, &this_controls.front());
260 this_effects.push_back(this_control);
261 int const this_effect_count = static_cast<int>(this_effects.size());
262 this_effect =
263 (this_control_count == 1)
264 ? this_effects.front()
265 : graph()->NewNode(common()->EffectPhi(this_control_count),
266 this_effect_count, &this_effects.front());
267 }
268
269 // Generate the actual property access.
270 ValueEffectControl continuation = BuildPropertyAccess(
271 this_receiver, this_value, this_effect, this_control, name,
272 native_context, access_info, access_mode);
273 values.push_back(continuation.value());
274 effects.push_back(continuation.effect());
275 controls.push_back(continuation.control());
276 }
277
278 DCHECK_NULL(fallthrough_control);
279
280 // Generate the final merge point for all (polymorphic) branches.
281 int const control_count = static_cast<int>(controls.size());
282 if (control_count == 0) {
283 value = effect = control = jsgraph()->Dead();
284 } else if (control_count == 1) {
285 value = values.front();
286 effect = effects.front();
287 control = controls.front();
288 } else {
289 control = graph()->NewNode(common()->Merge(control_count), control_count,
290 &controls.front());
291 values.push_back(control);
292 value = graph()->NewNode(
293 common()->Phi(MachineRepresentation::kTagged, control_count),
294 control_count + 1, &values.front());
295 effects.push_back(control);
296 effect = graph()->NewNode(common()->EffectPhi(control_count),
297 control_count + 1, &effects.front());
298 }
389 } 299 }
390 ReplaceWithValue(node, value, effect, control); 300 ReplaceWithValue(node, value, effect, control);
391 return Replace(value); 301 return Replace(value);
392 } 302 }
393 303
394
395 Reduction JSNativeContextSpecialization::ReduceNamedAccess( 304 Reduction JSNativeContextSpecialization::ReduceNamedAccess(
396 Node* node, Node* value, FeedbackNexus const& nexus, Handle<Name> name, 305 Node* node, Node* value, FeedbackNexus const& nexus, Handle<Name> name,
397 AccessMode access_mode, LanguageMode language_mode) { 306 AccessMode access_mode, LanguageMode language_mode) {
398 DCHECK(node->opcode() == IrOpcode::kJSLoadNamed || 307 DCHECK(node->opcode() == IrOpcode::kJSLoadNamed ||
399 node->opcode() == IrOpcode::kJSStoreNamed); 308 node->opcode() == IrOpcode::kJSStoreNamed);
400 Node* const receiver = NodeProperties::GetValueInput(node, 0); 309 Node* const receiver = NodeProperties::GetValueInput(node, 0);
401 Node* const effect = NodeProperties::GetEffectInput(node); 310 Node* const effect = NodeProperties::GetEffectInput(node);
402 311
403 // Check if the {nexus} reports type feedback for the IC. 312 // Check if the {nexus} reports type feedback for the IC.
404 if (nexus.IsUninitialized()) { 313 if (nexus.IsUninitialized()) {
(...skipping 148 matching lines...) Expand 10 before | Expand all | Expand 10 after
553 jsgraph()->HeapConstant(transition_target), this_effect, 462 jsgraph()->HeapConstant(transition_target), this_effect,
554 this_control); 463 this_control);
555 } 464 }
556 465
557 // Load the {receiver} map. 466 // Load the {receiver} map.
558 Node* receiver_map = this_effect = 467 Node* receiver_map = this_effect =
559 graph()->NewNode(simplified()->LoadField(AccessBuilder::ForMap()), 468 graph()->NewNode(simplified()->LoadField(AccessBuilder::ForMap()),
560 receiver, this_effect, this_control); 469 receiver, this_effect, this_control);
561 470
562 // Perform map check on {receiver}. 471 // Perform map check on {receiver}.
563 Type* receiver_type = access_info.receiver_type(); 472 MapList const& receiver_maps = access_info.receiver_maps();
564 bool receiver_is_jsarray = true;
565 { 473 {
566 ZoneVector<Node*> this_controls(zone()); 474 ZoneVector<Node*> this_controls(zone());
567 ZoneVector<Node*> this_effects(zone()); 475 ZoneVector<Node*> this_effects(zone());
568 int num_classes = access_info.receiver_type()->NumClasses(); 476 size_t num_classes = receiver_maps.size();
569 for (auto i = access_info.receiver_type()->Classes(); !i.Done(); 477 for (Handle<Map> map : receiver_maps) {
570 i.Advance()) { 478 DCHECK_LT(0u, num_classes);
571 DCHECK_LT(0, num_classes);
572 Handle<Map> map = i.Current();
573 Node* check = 479 Node* check =
574 graph()->NewNode(simplified()->ReferenceEqual(Type::Any()), 480 graph()->NewNode(simplified()->ReferenceEqual(Type::Any()),
575 receiver_map, jsgraph()->Constant(map)); 481 receiver_map, jsgraph()->Constant(map));
576 if (--num_classes == 0 && j == access_infos.size() - 1) { 482 if (--num_classes == 0 && j == access_infos.size() - 1) {
577 // Last map check on the fallthrough control path, do a conditional 483 // Last map check on the fallthrough control path, do a conditional
578 // eager deoptimization exit here. 484 // eager deoptimization exit here.
579 // TODO(turbofan): This is ugly as hell! We should probably introduce 485 // TODO(turbofan): This is ugly as hell! We should probably introduce
580 // macro-ish operators for property access that encapsulate this whole 486 // macro-ish operators for property access that encapsulate this whole
581 // mess. 487 // mess.
582 check = graph()->NewNode(simplified()->CheckIf(), check, this_effect, 488 check = graph()->NewNode(simplified()->CheckIf(), check, this_effect,
583 this_control); 489 this_control);
584 this_controls.push_back(this_control); 490 this_controls.push_back(this_control);
585 this_effects.push_back(check); 491 this_effects.push_back(check);
586 fallthrough_control = nullptr; 492 fallthrough_control = nullptr;
587 } else { 493 } else {
588 Node* branch = 494 Node* branch =
589 graph()->NewNode(common()->Branch(), check, fallthrough_control); 495 graph()->NewNode(common()->Branch(), check, fallthrough_control);
590 this_controls.push_back(graph()->NewNode(common()->IfTrue(), branch)); 496 this_controls.push_back(graph()->NewNode(common()->IfTrue(), branch));
591 this_effects.push_back(effect); 497 this_effects.push_back(effect);
592 fallthrough_control = graph()->NewNode(common()->IfFalse(), branch); 498 fallthrough_control = graph()->NewNode(common()->IfFalse(), branch);
593 } 499 }
594 if (!map->IsJSArrayMap()) receiver_is_jsarray = false;
595 } 500 }
596 501
597 // Create single chokepoint for the control. 502 // Create single chokepoint for the control.
598 int const this_control_count = static_cast<int>(this_controls.size()); 503 int const this_control_count = static_cast<int>(this_controls.size());
599 if (this_control_count == 1) { 504 if (this_control_count == 1) {
600 this_control = this_controls.front(); 505 this_control = this_controls.front();
601 this_effect = this_effects.front(); 506 this_effect = this_effects.front();
602 } else { 507 } else {
603 this_control = 508 this_control =
604 graph()->NewNode(common()->Merge(this_control_count), 509 graph()->NewNode(common()->Merge(this_control_count),
(...skipping 11 matching lines...) Expand all
616 this_effect = graph()->NewNode(common()->Checkpoint(), frame_state, 521 this_effect = graph()->NewNode(common()->Checkpoint(), frame_state,
617 this_effect, this_control); 522 this_effect, this_control);
618 } 523 }
619 } 524 }
620 525
621 // Certain stores need a prototype chain check because shape changes 526 // Certain stores need a prototype chain check because shape changes
622 // could allow callbacks on elements in the prototype chain that are 527 // could allow callbacks on elements in the prototype chain that are
623 // not compatible with (monomorphic) keyed stores. 528 // not compatible with (monomorphic) keyed stores.
624 Handle<JSObject> holder; 529 Handle<JSObject> holder;
625 if (access_info.holder().ToHandle(&holder)) { 530 if (access_info.holder().ToHandle(&holder)) {
626 AssumePrototypesStable(receiver_type, native_context, holder); 531 AssumePrototypesStable(receiver_maps, native_context, holder);
627 } 532 }
628 533
629 // TODO(bmeurer): We currently specialize based on elements kind. We should
630 // also be able to properly support strings and other JSObjects here.
631 ElementsKind elements_kind = access_info.elements_kind();
632
633 // Load the elements for the {receiver}.
634 Node* this_elements = this_effect = graph()->NewNode(
635 simplified()->LoadField(AccessBuilder::ForJSObjectElements()),
636 this_receiver, this_effect, this_control);
637
638 // Don't try to store to a copy-on-write backing store.
639 if (access_mode == AccessMode::kStore &&
640 IsFastSmiOrObjectElementsKind(elements_kind)) {
641 Node* this_elements_map = this_effect =
642 graph()->NewNode(simplified()->LoadField(AccessBuilder::ForMap()),
643 this_elements, this_effect, this_control);
644 Node* check = graph()->NewNode(
645 simplified()->ReferenceEqual(Type::Any()), this_elements_map,
646 jsgraph()->HeapConstant(factory()->fixed_array_map()));
647 this_effect = graph()->NewNode(simplified()->CheckIf(), check,
648 this_effect, this_control);
649 }
650
651 // Load the length of the {receiver}.
652 Node* this_length = this_effect =
653 receiver_is_jsarray
654 ? graph()->NewNode(
655 simplified()->LoadField(
656 AccessBuilder::ForJSArrayLength(elements_kind)),
657 this_receiver, this_effect, this_control)
658 : graph()->NewNode(
659 simplified()->LoadField(AccessBuilder::ForFixedArrayLength()),
660 this_elements, this_effect, this_control);
661
662 // Check that the {index} is in the valid range for the {receiver}.
663 this_index = this_effect =
664 graph()->NewNode(simplified()->CheckBounds(), this_index, this_length,
665 this_effect, this_control);
666
667 // Compute the element access.
668 Type* element_type = Type::Any();
669 MachineType element_machine_type = MachineType::AnyTagged();
670 if (IsFastDoubleElementsKind(elements_kind)) {
671 element_type = Type::Number();
672 element_machine_type = MachineType::Float64();
673 } else if (IsFastSmiElementsKind(elements_kind)) {
674 element_type = type_cache_.kSmi;
675 }
676 ElementAccess element_access = {kTaggedBase, FixedArray::kHeaderSize,
677 element_type, element_machine_type,
678 kFullWriteBarrier};
679
680 // Access the actual element. 534 // Access the actual element.
681 // TODO(bmeurer): Refactor this into separate methods or even a separate 535 ValueEffectControl continuation = BuildElementAccess(
682 // class that deals with the elements access. 536 this_receiver, this_index, this_value, this_effect, this_control,
683 if (access_mode == AccessMode::kLoad) { 537 native_context, access_info, access_mode);
684 // Compute the real element access type, which includes the hole in case 538 values.push_back(continuation.value());
685 // of holey backing stores. 539 effects.push_back(continuation.effect());
686 if (elements_kind == FAST_HOLEY_ELEMENTS || 540 controls.push_back(continuation.control());
687 elements_kind == FAST_HOLEY_SMI_ELEMENTS) {
688 element_access.type = Type::Union(
689 element_type,
690 Type::Constant(factory()->the_hole_value(), graph()->zone()),
691 graph()->zone());
692 }
693 // Perform the actual backing store access.
694 this_value = this_effect = graph()->NewNode(
695 simplified()->LoadElement(element_access), this_elements, this_index,
696 this_effect, this_control);
697 // Handle loading from holey backing stores correctly, by either mapping
698 // the hole to undefined if possible, or deoptimizing otherwise.
699 if (elements_kind == FAST_HOLEY_ELEMENTS ||
700 elements_kind == FAST_HOLEY_SMI_ELEMENTS) {
701 // Perform the hole check on the result.
702 CheckTaggedHoleMode mode = CheckTaggedHoleMode::kNeverReturnHole;
703 // Check if we are allowed to turn the hole into undefined.
704 Type* initial_holey_array_type = Type::Class(
705 handle(isolate()->get_initial_js_array_map(elements_kind)),
706 graph()->zone());
707 if (receiver_type->NowIs(initial_holey_array_type) &&
708 isolate()->IsFastArrayConstructorPrototypeChainIntact()) {
709 // Add a code dependency on the array protector cell.
710 AssumePrototypesStable(receiver_type, native_context,
711 isolate()->initial_object_prototype());
712 dependencies()->AssumePropertyCell(factory()->array_protector());
713 // Turn the hole into undefined.
714 mode = CheckTaggedHoleMode::kConvertHoleToUndefined;
715 }
716 this_value = this_effect =
717 graph()->NewNode(simplified()->CheckTaggedHole(mode), this_value,
718 this_effect, this_control);
719 } else if (elements_kind == FAST_HOLEY_DOUBLE_ELEMENTS) {
720 // Perform the hole check on the result.
721 CheckFloat64HoleMode mode = CheckFloat64HoleMode::kNeverReturnHole;
722 // Check if we are allowed to return the hole directly.
723 Type* initial_holey_array_type = Type::Class(
724 handle(isolate()->get_initial_js_array_map(elements_kind)),
725 graph()->zone());
726 if (receiver_type->NowIs(initial_holey_array_type) &&
727 isolate()->IsFastArrayConstructorPrototypeChainIntact()) {
728 // Add a code dependency on the array protector cell.
729 AssumePrototypesStable(receiver_type, native_context,
730 isolate()->initial_object_prototype());
731 dependencies()->AssumePropertyCell(factory()->array_protector());
732 // Return the signaling NaN hole directly if all uses are truncating.
733 mode = CheckFloat64HoleMode::kAllowReturnHole;
734 }
735 this_value = this_effect =
736 graph()->NewNode(simplified()->CheckFloat64Hole(mode), this_value,
737 this_effect, this_control);
738 }
739 } else {
740 DCHECK_EQ(AccessMode::kStore, access_mode);
741 if (IsFastSmiElementsKind(elements_kind)) {
742 this_value = this_effect =
743 graph()->NewNode(simplified()->CheckTaggedSigned(), this_value,
744 this_effect, this_control);
745 } else if (IsFastDoubleElementsKind(elements_kind)) {
746 this_value = this_effect = graph()->NewNode(
747 simplified()->CheckNumber(), this_value, this_effect, this_control);
748 // Make sure we do not store signalling NaNs into double arrays.
749 this_value =
750 graph()->NewNode(simplified()->NumberSilenceNaN(), this_value);
751 }
752 this_effect = graph()->NewNode(simplified()->StoreElement(element_access),
753 this_elements, this_index, this_value,
754 this_effect, this_control);
755 }
756
757 // Remember the final state for this element access.
758 values.push_back(this_value);
759 effects.push_back(this_effect);
760 controls.push_back(this_control);
761 } 541 }
762 542
763 DCHECK_NULL(fallthrough_control); 543 DCHECK_NULL(fallthrough_control);
764 544
765 // Generate the final merge point for all (polymorphic) branches. 545 // Generate the final merge point for all (polymorphic) branches.
766 int const control_count = static_cast<int>(controls.size()); 546 int const control_count = static_cast<int>(controls.size());
767 if (control_count == 0) { 547 if (control_count == 0) {
768 value = effect = control = jsgraph()->Dead(); 548 value = effect = control = jsgraph()->Dead();
769 } else if (control_count == 1) { 549 } else if (control_count == 1) {
770 value = values.front(); 550 value = values.front();
(...skipping 126 matching lines...) Expand 10 before | Expand all | Expand 10 after
897 KeyedStoreICNexus nexus(p.feedback().vector(), p.feedback().slot()); 677 KeyedStoreICNexus nexus(p.feedback().vector(), p.feedback().slot());
898 678
899 // Extract the keyed access store mode from the KEYED_STORE_IC. 679 // Extract the keyed access store mode from the KEYED_STORE_IC.
900 KeyedAccessStoreMode store_mode = nexus.GetKeyedAccessStoreMode(); 680 KeyedAccessStoreMode store_mode = nexus.GetKeyedAccessStoreMode();
901 681
902 // Try to lower the keyed access based on the {nexus}. 682 // Try to lower the keyed access based on the {nexus}.
903 return ReduceKeyedAccess(node, index, value, nexus, AccessMode::kStore, 683 return ReduceKeyedAccess(node, index, value, nexus, AccessMode::kStore,
904 p.language_mode(), store_mode); 684 p.language_mode(), store_mode);
905 } 685 }
906 686
687 JSNativeContextSpecialization::ValueEffectControl
688 JSNativeContextSpecialization::BuildPropertyAccess(
689 Node* receiver, Node* value, Node* effect, Node* control, Handle<Name> name,
690 Handle<Context> native_context, PropertyAccessInfo const& access_info,
691 AccessMode access_mode) {
692 // Determine actual holder and perform prototype chain checks.
693 Handle<JSObject> holder;
694 if (access_info.holder().ToHandle(&holder)) {
695 AssumePrototypesStable(access_info.receiver_maps(), native_context, holder);
696 }
697
698 // Generate the actual property access.
699 if (access_info.IsNotFound()) {
700 DCHECK_EQ(AccessMode::kLoad, access_mode);
701 value = jsgraph()->UndefinedConstant();
702 } else if (access_info.IsDataConstant()) {
703 value = jsgraph()->Constant(access_info.constant());
704 if (access_mode == AccessMode::kStore) {
705 Node* check = graph()->NewNode(
706 simplified()->ReferenceEqual(Type::Tagged()), value, value);
707 effect =
708 graph()->NewNode(simplified()->CheckIf(), check, effect, control);
709 }
710 } else {
711 DCHECK(access_info.IsDataField());
712 FieldIndex const field_index = access_info.field_index();
713 Type* const field_type = access_info.field_type();
714 if (access_mode == AccessMode::kLoad &&
715 access_info.holder().ToHandle(&holder)) {
716 receiver = jsgraph()->Constant(holder);
717 }
718 Node* storage = receiver;
719 if (!field_index.is_inobject()) {
720 storage = effect = graph()->NewNode(
721 simplified()->LoadField(AccessBuilder::ForJSObjectProperties()),
722 storage, effect, control);
723 }
724 FieldAccess field_access = {
725 kTaggedBase, field_index.offset(), name,
726 field_type, MachineType::AnyTagged(), kFullWriteBarrier};
727 if (access_mode == AccessMode::kLoad) {
728 if (field_type->Is(Type::UntaggedFloat64())) {
729 if (!field_index.is_inobject() || field_index.is_hidden_field() ||
730 !FLAG_unbox_double_fields) {
731 storage = effect = graph()->NewNode(
732 simplified()->LoadField(field_access), storage, effect, control);
733 field_access.offset = HeapNumber::kValueOffset;
734 field_access.name = MaybeHandle<Name>();
735 }
736 field_access.machine_type = MachineType::Float64();
737 }
738 value = effect = graph()->NewNode(simplified()->LoadField(field_access),
739 storage, effect, control);
740 } else {
741 DCHECK_EQ(AccessMode::kStore, access_mode);
742 if (field_type->Is(Type::UntaggedFloat64())) {
743 value = effect = graph()->NewNode(simplified()->CheckNumber(), value,
744 effect, control);
745
746 if (!field_index.is_inobject() || field_index.is_hidden_field() ||
747 !FLAG_unbox_double_fields) {
748 if (access_info.HasTransitionMap()) {
749 // Allocate a MutableHeapNumber for the new property.
750 effect = graph()->NewNode(
751 common()->BeginRegion(RegionObservability::kNotObservable),
752 effect);
753 Node* box = effect = graph()->NewNode(
754 simplified()->Allocate(NOT_TENURED),
755 jsgraph()->Constant(HeapNumber::kSize), effect, control);
756 effect = graph()->NewNode(
757 simplified()->StoreField(AccessBuilder::ForMap()), box,
758 jsgraph()->HeapConstant(factory()->mutable_heap_number_map()),
759 effect, control);
760 effect = graph()->NewNode(
761 simplified()->StoreField(AccessBuilder::ForHeapNumberValue()),
762 box, value, effect, control);
763 value = effect =
764 graph()->NewNode(common()->FinishRegion(), box, effect);
765
766 field_access.type = Type::TaggedPointer();
767 } else {
768 // We just store directly to the MutableHeapNumber.
769 storage = effect =
770 graph()->NewNode(simplified()->LoadField(field_access), storage,
771 effect, control);
772 field_access.offset = HeapNumber::kValueOffset;
773 field_access.name = MaybeHandle<Name>();
774 field_access.machine_type = MachineType::Float64();
775 }
776 } else {
777 // Unboxed double field, we store directly to the field.
778 field_access.machine_type = MachineType::Float64();
779 }
780 } else if (field_type->Is(Type::TaggedSigned())) {
781 value = effect = graph()->NewNode(simplified()->CheckTaggedSigned(),
782 value, effect, control);
783 } else if (field_type->Is(Type::TaggedPointer())) {
784 value = effect = graph()->NewNode(simplified()->CheckTaggedPointer(),
785 value, effect, control);
786 if (field_type->NumClasses() == 1) {
787 // Emit a map check for the value.
788 Node* value_map = effect =
789 graph()->NewNode(simplified()->LoadField(AccessBuilder::ForMap()),
790 value, effect, control);
791 Node* check = graph()->NewNode(
792 simplified()->ReferenceEqual(Type::Internal()), value_map,
793 jsgraph()->Constant(field_type->Classes().Current()));
794 effect =
795 graph()->NewNode(simplified()->CheckIf(), check, effect, control);
796 } else {
797 DCHECK_EQ(0, field_type->NumClasses());
798 }
799 } else {
800 DCHECK(field_type->Is(Type::Tagged()));
801 }
802 Handle<Map> transition_map;
803 if (access_info.transition_map().ToHandle(&transition_map)) {
804 effect = graph()->NewNode(
805 common()->BeginRegion(RegionObservability::kObservable), effect);
806 effect = graph()->NewNode(
807 simplified()->StoreField(AccessBuilder::ForMap()), receiver,
808 jsgraph()->Constant(transition_map), effect, control);
809 }
810 effect = graph()->NewNode(simplified()->StoreField(field_access), storage,
811 value, effect, control);
812 if (access_info.HasTransitionMap()) {
813 effect = graph()->NewNode(common()->FinishRegion(),
814 jsgraph()->UndefinedConstant(), effect);
815 }
816 }
817 }
818
819 return ValueEffectControl(value, effect, control);
820 }
821
822 JSNativeContextSpecialization::ValueEffectControl
823 JSNativeContextSpecialization::BuildElementAccess(
824 Node* receiver, Node* index, Node* value, Node* effect, Node* control,
825 Handle<Context> native_context, ElementAccessInfo const& access_info,
826 AccessMode access_mode) {
827 // Determine actual holder and perform prototype chain checks.
828 Handle<JSObject> holder;
829 if (access_info.holder().ToHandle(&holder)) {
830 AssumePrototypesStable(access_info.receiver_maps(), native_context, holder);
831 }
832
833 // TODO(bmeurer): We currently specialize based on elements kind. We should
834 // also be able to properly support strings and other JSObjects here.
835 ElementsKind elements_kind = access_info.elements_kind();
836 MapList const& receiver_maps = access_info.receiver_maps();
837
838 // Load the elements for the {receiver}.
839 Node* elements = effect = graph()->NewNode(
840 simplified()->LoadField(AccessBuilder::ForJSObjectElements()), receiver,
841 effect, control);
842
843 // Don't try to store to a copy-on-write backing store.
844 if (access_mode == AccessMode::kStore &&
845 IsFastSmiOrObjectElementsKind(elements_kind)) {
846 Node* elements_map = effect =
847 graph()->NewNode(simplified()->LoadField(AccessBuilder::ForMap()),
848 elements, effect, control);
849 Node* check = graph()->NewNode(
850 simplified()->ReferenceEqual(Type::Any()), elements_map,
851 jsgraph()->HeapConstant(factory()->fixed_array_map()));
852 effect = graph()->NewNode(simplified()->CheckIf(), check, effect, control);
853 }
854
855 // Load the length of the {receiver}.
856 Node* length = effect =
857 HasOnlyJSArrayMaps(receiver_maps)
858 ? graph()->NewNode(
859 simplified()->LoadField(
860 AccessBuilder::ForJSArrayLength(elements_kind)),
861 receiver, effect, control)
862 : graph()->NewNode(
863 simplified()->LoadField(AccessBuilder::ForFixedArrayLength()),
864 elements, effect, control);
865
866 // Check that the {index} is in the valid range for the {receiver}.
867 index = effect = graph()->NewNode(simplified()->CheckBounds(), index, length,
868 effect, control);
869
870 // Compute the element access.
871 Type* element_type = Type::Any();
872 MachineType element_machine_type = MachineType::AnyTagged();
873 if (IsFastDoubleElementsKind(elements_kind)) {
874 element_type = Type::Number();
875 element_machine_type = MachineType::Float64();
876 } else if (IsFastSmiElementsKind(elements_kind)) {
877 element_type = type_cache_.kSmi;
878 }
879 ElementAccess element_access = {kTaggedBase, FixedArray::kHeaderSize,
880 element_type, element_machine_type,
881 kFullWriteBarrier};
882
883 // Access the actual element.
884 // TODO(bmeurer): Refactor this into separate methods or even a separate
885 // class that deals with the elements access.
886 if (access_mode == AccessMode::kLoad) {
887 // Compute the real element access type, which includes the hole in case
888 // of holey backing stores.
889 if (elements_kind == FAST_HOLEY_ELEMENTS ||
890 elements_kind == FAST_HOLEY_SMI_ELEMENTS) {
891 element_access.type = Type::Union(
892 element_type,
893 Type::Constant(factory()->the_hole_value(), graph()->zone()),
894 graph()->zone());
895 }
896 // Perform the actual backing store access.
897 value = effect = graph()->NewNode(simplified()->LoadElement(element_access),
898 elements, index, effect, control);
899 // Handle loading from holey backing stores correctly, by either mapping
900 // the hole to undefined if possible, or deoptimizing otherwise.
901 if (elements_kind == FAST_HOLEY_ELEMENTS ||
902 elements_kind == FAST_HOLEY_SMI_ELEMENTS) {
903 // Perform the hole check on the result.
904 CheckTaggedHoleMode mode = CheckTaggedHoleMode::kNeverReturnHole;
905 // Check if we are allowed to turn the hole into undefined.
906 // TODO(bmeurer): We might check the JSArray map from a different
907 // context here; may need reinvestigation.
908 if (receiver_maps.size() == 1 &&
909 receiver_maps[0].is_identical_to(
910 handle(isolate()->get_initial_js_array_map(elements_kind))) &&
911 isolate()->IsFastArrayConstructorPrototypeChainIntact()) {
912 // Add a code dependency on the array protector cell.
913 dependencies()->AssumePrototypeMapsStable(
914 receiver_maps[0], isolate()->initial_object_prototype());
915 dependencies()->AssumePropertyCell(factory()->array_protector());
916 // Turn the hole into undefined.
917 mode = CheckTaggedHoleMode::kConvertHoleToUndefined;
918 }
919 value = effect = graph()->NewNode(simplified()->CheckTaggedHole(mode),
920 value, effect, control);
921 } else if (elements_kind == FAST_HOLEY_DOUBLE_ELEMENTS) {
922 // Perform the hole check on the result.
923 CheckFloat64HoleMode mode = CheckFloat64HoleMode::kNeverReturnHole;
924 // Check if we are allowed to return the hole directly.
925 // TODO(bmeurer): We might check the JSArray map from a different
926 // context here; may need reinvestigation.
927 if (receiver_maps.size() == 1 &&
928 receiver_maps[0].is_identical_to(
929 handle(isolate()->get_initial_js_array_map(elements_kind))) &&
930 isolate()->IsFastArrayConstructorPrototypeChainIntact()) {
931 // Add a code dependency on the array protector cell.
932 dependencies()->AssumePrototypeMapsStable(
933 receiver_maps[0], isolate()->initial_object_prototype());
934 dependencies()->AssumePropertyCell(factory()->array_protector());
935 // Return the signaling NaN hole directly if all uses are truncating.
936 mode = CheckFloat64HoleMode::kAllowReturnHole;
937 }
938 value = effect = graph()->NewNode(simplified()->CheckFloat64Hole(mode),
939 value, effect, control);
940 }
941 } else {
942 DCHECK_EQ(AccessMode::kStore, access_mode);
943 if (IsFastSmiElementsKind(elements_kind)) {
944 value = effect = graph()->NewNode(simplified()->CheckTaggedSigned(),
945 value, effect, control);
946 } else if (IsFastDoubleElementsKind(elements_kind)) {
947 value = effect =
948 graph()->NewNode(simplified()->CheckNumber(), value, effect, control);
949 // Make sure we do not store signalling NaNs into double arrays.
950 value = graph()->NewNode(simplified()->NumberSilenceNaN(), value);
951 }
952 effect = graph()->NewNode(simplified()->StoreElement(element_access),
953 elements, index, value, effect, control);
954 }
955
956 return ValueEffectControl(value, effect, control);
957 }
907 958
908 void JSNativeContextSpecialization::AssumePrototypesStable( 959 void JSNativeContextSpecialization::AssumePrototypesStable(
909 Type* receiver_type, Handle<Context> native_context, 960 std::vector<Handle<Map>> const& receiver_maps,
910 Handle<JSObject> holder) { 961 Handle<Context> native_context, Handle<JSObject> holder) {
911 // Determine actual holder and perform prototype chain checks. 962 // Determine actual holder and perform prototype chain checks.
912 for (auto i = receiver_type->Classes(); !i.Done(); i.Advance()) { 963 for (auto map : receiver_maps) {
913 Handle<Map> map = i.Current();
914 // Perform the implicit ToObject for primitives here. 964 // Perform the implicit ToObject for primitives here.
915 // Implemented according to ES6 section 7.3.2 GetV (V, P). 965 // Implemented according to ES6 section 7.3.2 GetV (V, P).
916 Handle<JSFunction> constructor; 966 Handle<JSFunction> constructor;
917 if (Map::GetConstructorFunction(map, native_context) 967 if (Map::GetConstructorFunction(map, native_context)
918 .ToHandle(&constructor)) { 968 .ToHandle(&constructor)) {
919 map = handle(constructor->initial_map(), isolate()); 969 map = handle(constructor->initial_map(), isolate());
920 } 970 }
921 dependencies()->AssumePrototypeMapsStable(map, holder); 971 dependencies()->AssumePrototypeMapsStable(map, holder);
922 } 972 }
923 } 973 }
(...skipping 115 matching lines...) Expand 10 before | Expand all | Expand 10 after
1039 } 1089 }
1040 1090
1041 1091
1042 SimplifiedOperatorBuilder* JSNativeContextSpecialization::simplified() const { 1092 SimplifiedOperatorBuilder* JSNativeContextSpecialization::simplified() const {
1043 return jsgraph()->simplified(); 1093 return jsgraph()->simplified();
1044 } 1094 }
1045 1095
1046 } // namespace compiler 1096 } // namespace compiler
1047 } // namespace internal 1097 } // namespace internal
1048 } // namespace v8 1098 } // namespace v8
OLDNEW
« no previous file with comments | « src/compiler/js-native-context-specialization.h ('k') | src/compiler/load-elimination.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698