blob: 81d4cd04ca6935635c12e1af14dacab2d67371ad [file] [log] [blame]
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001// 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 "src/compiler/js-native-context-specialization.h"
6
7#include "src/accessors.h"
8#include "src/code-factory.h"
9#include "src/compilation-dependencies.h"
10#include "src/compiler/access-builder.h"
11#include "src/compiler/access-info.h"
12#include "src/compiler/js-graph.h"
13#include "src/compiler/js-operator.h"
14#include "src/compiler/linkage.h"
15#include "src/compiler/node-matchers.h"
16#include "src/field-index-inl.h"
17#include "src/isolate-inl.h"
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000018#include "src/type-cache.h"
19#include "src/type-feedback-vector.h"
20
21namespace v8 {
22namespace internal {
23namespace compiler {
24
25JSNativeContextSpecialization::JSNativeContextSpecialization(
26 Editor* editor, JSGraph* jsgraph, Flags flags,
27 MaybeHandle<Context> native_context, CompilationDependencies* dependencies,
28 Zone* zone)
29 : AdvancedReducer(editor),
30 jsgraph_(jsgraph),
31 flags_(flags),
32 native_context_(native_context),
33 dependencies_(dependencies),
34 zone_(zone),
35 type_cache_(TypeCache::Get()) {}
36
37
38Reduction JSNativeContextSpecialization::Reduce(Node* node) {
39 switch (node->opcode()) {
Ben Murdoch097c5b22016-05-18 11:27:45 +010040 case IrOpcode::kJSLoadContext:
41 return ReduceJSLoadContext(node);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000042 case IrOpcode::kJSLoadNamed:
43 return ReduceJSLoadNamed(node);
44 case IrOpcode::kJSStoreNamed:
45 return ReduceJSStoreNamed(node);
46 case IrOpcode::kJSLoadProperty:
47 return ReduceJSLoadProperty(node);
48 case IrOpcode::kJSStoreProperty:
49 return ReduceJSStoreProperty(node);
50 default:
51 break;
52 }
53 return NoChange();
54}
55
Ben Murdoch097c5b22016-05-18 11:27:45 +010056Reduction JSNativeContextSpecialization::ReduceJSLoadContext(Node* node) {
57 DCHECK_EQ(IrOpcode::kJSLoadContext, node->opcode());
58 ContextAccess const& access = ContextAccessOf(node->op());
59 Handle<Context> native_context;
60 // Specialize JSLoadContext(NATIVE_CONTEXT_INDEX) to the known native
61 // context (if any), so we can constant-fold those fields, which is
62 // safe, since the NATIVE_CONTEXT_INDEX slot is always immutable.
63 if (access.index() == Context::NATIVE_CONTEXT_INDEX &&
64 GetNativeContext(node).ToHandle(&native_context)) {
65 Node* value = jsgraph()->HeapConstant(native_context);
66 ReplaceWithValue(node, value);
67 return Replace(value);
68 }
69 return NoChange();
70}
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000071
72Reduction JSNativeContextSpecialization::ReduceNamedAccess(
73 Node* node, Node* value, MapHandleList const& receiver_maps,
74 Handle<Name> name, AccessMode access_mode, LanguageMode language_mode,
75 Node* index) {
76 DCHECK(node->opcode() == IrOpcode::kJSLoadNamed ||
77 node->opcode() == IrOpcode::kJSStoreNamed ||
78 node->opcode() == IrOpcode::kJSLoadProperty ||
79 node->opcode() == IrOpcode::kJSStoreProperty);
80 Node* receiver = NodeProperties::GetValueInput(node, 0);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000081 Node* effect = NodeProperties::GetEffectInput(node);
82 Node* control = NodeProperties::GetControlInput(node);
Ben Murdoch61f157c2016-09-16 13:49:30 +010083 Node* frame_state = NodeProperties::FindFrameStateBefore(node);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000084
85 // Not much we can do if deoptimization support is disabled.
86 if (!(flags() & kDeoptimizationEnabled)) return NoChange();
87
88 // Retrieve the native context from the given {node}.
89 Handle<Context> native_context;
90 if (!GetNativeContext(node).ToHandle(&native_context)) return NoChange();
91
92 // Compute property access infos for the receiver maps.
93 AccessInfoFactory access_info_factory(dependencies(), native_context,
94 graph()->zone());
95 ZoneVector<PropertyAccessInfo> access_infos(zone());
96 if (!access_info_factory.ComputePropertyAccessInfos(
97 receiver_maps, name, access_mode, &access_infos)) {
98 return NoChange();
99 }
100
101 // Nothing to do if we have no non-deprecated maps.
102 if (access_infos.empty()) return NoChange();
103
104 // The final states for every polymorphic branch. We join them with
105 // Merge++Phi+EffectPhi at the bottom.
106 ZoneVector<Node*> values(zone());
107 ZoneVector<Node*> effects(zone());
108 ZoneVector<Node*> controls(zone());
109
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000110 // Ensure that {index} matches the specified {name} (if {index} is given).
111 if (index != nullptr) {
112 Node* check = graph()->NewNode(simplified()->ReferenceEqual(Type::Name()),
113 index, jsgraph()->HeapConstant(name));
Ben Murdoch61f157c2016-09-16 13:49:30 +0100114 control = effect = graph()->NewNode(common()->DeoptimizeUnless(), check,
115 frame_state, effect, control);
Ben Murdochda12d292016-06-02 14:46:10 +0100116 }
117
118 // Check if {receiver} may be a number.
119 bool receiverissmi_possible = false;
120 for (PropertyAccessInfo const& access_info : access_infos) {
121 if (access_info.receiver_type()->Is(Type::Number())) {
122 receiverissmi_possible = true;
123 break;
124 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000125 }
126
127 // Ensure that {receiver} is a heap object.
Ben Murdochda12d292016-06-02 14:46:10 +0100128 Node* receiverissmi_control = nullptr;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000129 Node* receiverissmi_effect = effect;
Ben Murdochda12d292016-06-02 14:46:10 +0100130 if (receiverissmi_possible) {
Ben Murdoch61f157c2016-09-16 13:49:30 +0100131 Node* check = graph()->NewNode(simplified()->ObjectIsSmi(), receiver);
Ben Murdochda12d292016-06-02 14:46:10 +0100132 Node* branch = graph()->NewNode(common()->Branch(), check, control);
133 control = graph()->NewNode(common()->IfFalse(), branch);
134 receiverissmi_control = graph()->NewNode(common()->IfTrue(), branch);
135 receiverissmi_effect = effect;
136 } else {
Ben Murdoch61f157c2016-09-16 13:49:30 +0100137 receiver = effect = graph()->NewNode(simplified()->CheckTaggedPointer(),
138 receiver, effect, control);
Ben Murdochda12d292016-06-02 14:46:10 +0100139 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000140
141 // Load the {receiver} map. The resulting effect is the dominating effect for
142 // all (polymorphic) branches.
143 Node* receiver_map = effect =
144 graph()->NewNode(simplified()->LoadField(AccessBuilder::ForMap()),
145 receiver, effect, control);
146
147 // Generate code for the various different property access patterns.
148 Node* fallthrough_control = control;
Ben Murdochda12d292016-06-02 14:46:10 +0100149 for (size_t j = 0; j < access_infos.size(); ++j) {
150 PropertyAccessInfo const& access_info = access_infos[j];
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000151 Node* this_value = value;
152 Node* this_receiver = receiver;
153 Node* this_effect = effect;
154 Node* this_control;
155
156 // Perform map check on {receiver}.
157 Type* receiver_type = access_info.receiver_type();
158 if (receiver_type->Is(Type::String())) {
Ben Murdochc5610432016-08-08 18:44:38 +0100159 Node* check = graph()->NewNode(simplified()->ObjectIsString(), receiver);
Ben Murdochda12d292016-06-02 14:46:10 +0100160 if (j == access_infos.size() - 1) {
Ben Murdoch61f157c2016-09-16 13:49:30 +0100161 this_control = this_effect =
Ben Murdochda12d292016-06-02 14:46:10 +0100162 graph()->NewNode(common()->DeoptimizeUnless(), check, frame_state,
163 this_effect, fallthrough_control);
164 fallthrough_control = nullptr;
165 } else {
166 Node* branch =
167 graph()->NewNode(common()->Branch(), check, fallthrough_control);
168 fallthrough_control = graph()->NewNode(common()->IfFalse(), branch);
169 this_control = graph()->NewNode(common()->IfTrue(), branch);
170 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000171 } else {
172 // Emit a (sequence of) map checks for other {receiver}s.
173 ZoneVector<Node*> this_controls(zone());
174 ZoneVector<Node*> this_effects(zone());
Ben Murdochda12d292016-06-02 14:46:10 +0100175 int num_classes = access_info.receiver_type()->NumClasses();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000176 for (auto i = access_info.receiver_type()->Classes(); !i.Done();
177 i.Advance()) {
Ben Murdochda12d292016-06-02 14:46:10 +0100178 DCHECK_LT(0, num_classes);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000179 Handle<Map> map = i.Current();
180 Node* check =
181 graph()->NewNode(simplified()->ReferenceEqual(Type::Internal()),
182 receiver_map, jsgraph()->Constant(map));
Ben Murdochda12d292016-06-02 14:46:10 +0100183 if (--num_classes == 0 && j == access_infos.size() - 1) {
Ben Murdoch61f157c2016-09-16 13:49:30 +0100184 Node* deoptimize =
Ben Murdochda12d292016-06-02 14:46:10 +0100185 graph()->NewNode(common()->DeoptimizeUnless(), check, frame_state,
Ben Murdoch61f157c2016-09-16 13:49:30 +0100186 this_effect, fallthrough_control);
187 this_controls.push_back(deoptimize);
188 this_effects.push_back(deoptimize);
Ben Murdochda12d292016-06-02 14:46:10 +0100189 fallthrough_control = nullptr;
190 } else {
191 Node* branch =
192 graph()->NewNode(common()->Branch(), check, fallthrough_control);
193 fallthrough_control = graph()->NewNode(common()->IfFalse(), branch);
194 this_controls.push_back(graph()->NewNode(common()->IfTrue(), branch));
195 this_effects.push_back(this_effect);
196 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000197 }
198
199 // The Number case requires special treatment to also deal with Smis.
200 if (receiver_type->Is(Type::Number())) {
Ben Murdochda12d292016-06-02 14:46:10 +0100201 // Join this check with the "receiver is smi" check above.
202 DCHECK_NOT_NULL(receiverissmi_effect);
203 DCHECK_NOT_NULL(receiverissmi_control);
204 this_effects.push_back(receiverissmi_effect);
205 this_controls.push_back(receiverissmi_control);
206 receiverissmi_effect = receiverissmi_control = nullptr;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000207 }
208
209 // Create dominating Merge+EffectPhi for this {receiver} type.
210 int const this_control_count = static_cast<int>(this_controls.size());
211 this_control =
212 (this_control_count == 1)
213 ? this_controls.front()
214 : graph()->NewNode(common()->Merge(this_control_count),
215 this_control_count, &this_controls.front());
216 this_effects.push_back(this_control);
217 int const this_effect_count = static_cast<int>(this_effects.size());
218 this_effect =
219 (this_control_count == 1)
220 ? this_effects.front()
221 : graph()->NewNode(common()->EffectPhi(this_control_count),
222 this_effect_count, &this_effects.front());
223 }
224
225 // Determine actual holder and perform prototype chain checks.
226 Handle<JSObject> holder;
227 if (access_info.holder().ToHandle(&holder)) {
228 AssumePrototypesStable(receiver_type, native_context, holder);
229 }
230
231 // Generate the actual property access.
232 if (access_info.IsNotFound()) {
233 DCHECK_EQ(AccessMode::kLoad, access_mode);
Ben Murdochda12d292016-06-02 14:46:10 +0100234 this_value = jsgraph()->UndefinedConstant();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000235 } else if (access_info.IsDataConstant()) {
236 this_value = jsgraph()->Constant(access_info.constant());
237 if (access_mode == AccessMode::kStore) {
238 Node* check = graph()->NewNode(
239 simplified()->ReferenceEqual(Type::Tagged()), value, this_value);
Ben Murdoch61f157c2016-09-16 13:49:30 +0100240 this_control = this_effect =
241 graph()->NewNode(common()->DeoptimizeUnless(), check, frame_state,
242 this_effect, this_control);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000243 }
244 } else {
245 DCHECK(access_info.IsDataField());
246 FieldIndex const field_index = access_info.field_index();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000247 Type* const field_type = access_info.field_type();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000248 if (access_mode == AccessMode::kLoad &&
249 access_info.holder().ToHandle(&holder)) {
250 this_receiver = jsgraph()->Constant(holder);
251 }
252 Node* this_storage = this_receiver;
253 if (!field_index.is_inobject()) {
254 this_storage = this_effect = graph()->NewNode(
255 simplified()->LoadField(AccessBuilder::ForJSObjectProperties()),
256 this_storage, this_effect, this_control);
257 }
Ben Murdochc5610432016-08-08 18:44:38 +0100258 FieldAccess field_access = {
259 kTaggedBase, field_index.offset(), name,
260 field_type, MachineType::AnyTagged(), kFullWriteBarrier};
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000261 if (access_mode == AccessMode::kLoad) {
262 if (field_type->Is(Type::UntaggedFloat64())) {
Ben Murdoch61f157c2016-09-16 13:49:30 +0100263 // TODO(turbofan): We remove the representation axis from the type to
264 // avoid uninhabited representation types. This is a workaround until
265 // the {PropertyAccessInfo} is using {MachineRepresentation} instead.
266 field_access.type = Type::Union(
267 field_type, Type::Representation(Type::Number(), zone()), zone());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000268 if (!field_index.is_inobject() || field_index.is_hidden_field() ||
269 !FLAG_unbox_double_fields) {
270 this_storage = this_effect =
271 graph()->NewNode(simplified()->LoadField(field_access),
272 this_storage, this_effect, this_control);
273 field_access.offset = HeapNumber::kValueOffset;
274 field_access.name = MaybeHandle<Name>();
275 }
276 field_access.machine_type = MachineType::Float64();
277 }
278 this_value = this_effect =
279 graph()->NewNode(simplified()->LoadField(field_access),
280 this_storage, this_effect, this_control);
281 } else {
282 DCHECK_EQ(AccessMode::kStore, access_mode);
283 if (field_type->Is(Type::UntaggedFloat64())) {
Ben Murdoch61f157c2016-09-16 13:49:30 +0100284 // TODO(turbofan): We remove the representation axis from the type to
285 // avoid uninhabited representation types. This is a workaround until
286 // the {PropertyAccessInfo} is using {MachineRepresentation} instead.
287 field_access.type = Type::Union(
288 field_type, Type::Representation(Type::Number(), zone()), zone());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000289 Node* check =
290 graph()->NewNode(simplified()->ObjectIsNumber(), this_value);
Ben Murdoch61f157c2016-09-16 13:49:30 +0100291 this_control = this_effect =
Ben Murdochda12d292016-06-02 14:46:10 +0100292 graph()->NewNode(common()->DeoptimizeUnless(), check, frame_state,
293 this_effect, this_control);
Ben Murdochc5610432016-08-08 18:44:38 +0100294 this_value = graph()->NewNode(simplified()->TypeGuard(Type::Number()),
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000295 this_value, this_control);
296
297 if (!field_index.is_inobject() || field_index.is_hidden_field() ||
298 !FLAG_unbox_double_fields) {
299 if (access_info.HasTransitionMap()) {
300 // Allocate a MutableHeapNumber for the new property.
Ben Murdoch61f157c2016-09-16 13:49:30 +0100301 this_effect = graph()->NewNode(
302 common()->BeginRegion(RegionObservability::kNotObservable),
303 this_effect);
Ben Murdochc5610432016-08-08 18:44:38 +0100304 Node* this_box = this_effect =
305 graph()->NewNode(simplified()->Allocate(NOT_TENURED),
306 jsgraph()->Constant(HeapNumber::kSize),
307 this_effect, this_control);
308 this_effect = graph()->NewNode(
309 simplified()->StoreField(AccessBuilder::ForMap()), this_box,
310 jsgraph()->HeapConstant(factory()->mutable_heap_number_map()),
311 this_effect, this_control);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000312 this_effect = graph()->NewNode(
313 simplified()->StoreField(AccessBuilder::ForHeapNumberValue()),
314 this_box, this_value, this_effect, this_control);
Ben Murdochc5610432016-08-08 18:44:38 +0100315 this_value = this_effect = graph()->NewNode(
316 common()->FinishRegion(), this_box, this_effect);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000317
318 field_access.type = Type::TaggedPointer();
319 } else {
320 // We just store directly to the MutableHeapNumber.
321 this_storage = this_effect =
322 graph()->NewNode(simplified()->LoadField(field_access),
323 this_storage, this_effect, this_control);
324 field_access.offset = HeapNumber::kValueOffset;
325 field_access.name = MaybeHandle<Name>();
326 field_access.machine_type = MachineType::Float64();
327 }
328 } else {
329 // Unboxed double field, we store directly to the field.
330 field_access.machine_type = MachineType::Float64();
331 }
332 } else if (field_type->Is(Type::TaggedSigned())) {
Ben Murdoch61f157c2016-09-16 13:49:30 +0100333 this_value = this_effect =
334 graph()->NewNode(simplified()->CheckTaggedSigned(), this_value,
Ben Murdochda12d292016-06-02 14:46:10 +0100335 this_effect, this_control);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000336 } else if (field_type->Is(Type::TaggedPointer())) {
Ben Murdoch61f157c2016-09-16 13:49:30 +0100337 this_value = this_effect =
338 graph()->NewNode(simplified()->CheckTaggedPointer(), this_value,
Ben Murdochda12d292016-06-02 14:46:10 +0100339 this_effect, this_control);
340 if (field_type->NumClasses() == 1) {
341 // Emit a map check for the value.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000342 Node* this_value_map = this_effect = graph()->NewNode(
343 simplified()->LoadField(AccessBuilder::ForMap()), this_value,
344 this_effect, this_control);
Ben Murdochda12d292016-06-02 14:46:10 +0100345 Node* check = graph()->NewNode(
346 simplified()->ReferenceEqual(Type::Internal()), this_value_map,
347 jsgraph()->Constant(field_type->Classes().Current()));
Ben Murdoch61f157c2016-09-16 13:49:30 +0100348 this_control = this_effect =
Ben Murdochda12d292016-06-02 14:46:10 +0100349 graph()->NewNode(common()->DeoptimizeUnless(), check,
350 frame_state, this_effect, this_control);
351 } else {
352 DCHECK_EQ(0, field_type->NumClasses());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000353 }
354 } else {
355 DCHECK(field_type->Is(Type::Tagged()));
356 }
357 Handle<Map> transition_map;
358 if (access_info.transition_map().ToHandle(&transition_map)) {
Ben Murdoch61f157c2016-09-16 13:49:30 +0100359 this_effect = graph()->NewNode(
360 common()->BeginRegion(RegionObservability::kObservable),
361 this_effect);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000362 this_effect = graph()->NewNode(
363 simplified()->StoreField(AccessBuilder::ForMap()), this_receiver,
364 jsgraph()->Constant(transition_map), this_effect, this_control);
365 }
366 this_effect = graph()->NewNode(simplified()->StoreField(field_access),
367 this_storage, this_value, this_effect,
368 this_control);
369 if (access_info.HasTransitionMap()) {
370 this_effect =
371 graph()->NewNode(common()->FinishRegion(),
372 jsgraph()->UndefinedConstant(), this_effect);
373 }
374 }
375 }
376
377 // Remember the final state for this property access.
378 values.push_back(this_value);
379 effects.push_back(this_effect);
380 controls.push_back(this_control);
381 }
382
Ben Murdochda12d292016-06-02 14:46:10 +0100383 DCHECK_NULL(fallthrough_control);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000384
385 // Generate the final merge point for all (polymorphic) branches.
386 int const control_count = static_cast<int>(controls.size());
387 if (control_count == 0) {
388 value = effect = control = jsgraph()->Dead();
389 } else if (control_count == 1) {
390 value = values.front();
391 effect = effects.front();
392 control = controls.front();
393 } else {
394 control = graph()->NewNode(common()->Merge(control_count), control_count,
395 &controls.front());
396 values.push_back(control);
397 value = graph()->NewNode(
398 common()->Phi(MachineRepresentation::kTagged, control_count),
399 control_count + 1, &values.front());
400 effects.push_back(control);
401 effect = graph()->NewNode(common()->EffectPhi(control_count),
402 control_count + 1, &effects.front());
403 }
404 ReplaceWithValue(node, value, effect, control);
405 return Replace(value);
406}
407
408
Ben Murdoch097c5b22016-05-18 11:27:45 +0100409Reduction JSNativeContextSpecialization::ReduceNamedAccess(
410 Node* node, Node* value, FeedbackNexus const& nexus, Handle<Name> name,
411 AccessMode access_mode, LanguageMode language_mode) {
412 DCHECK(node->opcode() == IrOpcode::kJSLoadNamed ||
413 node->opcode() == IrOpcode::kJSStoreNamed);
Ben Murdochc5610432016-08-08 18:44:38 +0100414 Node* const receiver = NodeProperties::GetValueInput(node, 0);
415 Node* const effect = NodeProperties::GetEffectInput(node);
Ben Murdoch097c5b22016-05-18 11:27:45 +0100416
417 // Check if the {nexus} reports type feedback for the IC.
418 if (nexus.IsUninitialized()) {
419 if ((flags() & kDeoptimizationEnabled) &&
420 (flags() & kBailoutOnUninitialized)) {
Ben Murdochc5610432016-08-08 18:44:38 +0100421 return ReduceSoftDeoptimize(node);
Ben Murdoch097c5b22016-05-18 11:27:45 +0100422 }
423 return NoChange();
424 }
425
426 // Extract receiver maps from the IC using the {nexus}.
427 MapHandleList receiver_maps;
Ben Murdochc5610432016-08-08 18:44:38 +0100428 if (!ExtractReceiverMaps(receiver, effect, nexus, &receiver_maps)) {
429 return NoChange();
430 } else if (receiver_maps.length() == 0) {
431 if ((flags() & kDeoptimizationEnabled) &&
432 (flags() & kBailoutOnUninitialized)) {
433 return ReduceSoftDeoptimize(node);
434 }
435 return NoChange();
436 }
Ben Murdoch097c5b22016-05-18 11:27:45 +0100437
438 // Try to lower the named access based on the {receiver_maps}.
439 return ReduceNamedAccess(node, value, receiver_maps, name, access_mode,
440 language_mode);
441}
442
443
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000444Reduction JSNativeContextSpecialization::ReduceJSLoadNamed(Node* node) {
445 DCHECK_EQ(IrOpcode::kJSLoadNamed, node->opcode());
446 NamedAccess const& p = NamedAccessOf(node->op());
Ben Murdochc5610432016-08-08 18:44:38 +0100447 Node* const receiver = NodeProperties::GetValueInput(node, 0);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000448 Node* const value = jsgraph()->Dead();
449
Ben Murdochc5610432016-08-08 18:44:38 +0100450 // Check if we have a constant receiver.
451 HeapObjectMatcher m(receiver);
452 if (m.HasValue()) {
453 // Optimize "prototype" property of functions.
454 if (m.Value()->IsJSFunction() &&
455 p.name().is_identical_to(factory()->prototype_string())) {
456 Handle<JSFunction> function = Handle<JSFunction>::cast(m.Value());
457 if (function->has_initial_map()) {
458 // We need to add a code dependency on the initial map of the
459 // {function} in order to be notified about changes to the
460 // "prototype" of {function}, so it doesn't make sense to
461 // continue unless deoptimization is enabled.
462 if (flags() & kDeoptimizationEnabled) {
463 Handle<Map> initial_map(function->initial_map(), isolate());
464 dependencies()->AssumeInitialMapCantChange(initial_map);
465 Handle<Object> prototype(initial_map->prototype(), isolate());
466 Node* value = jsgraph()->Constant(prototype);
467 ReplaceWithValue(node, value);
468 return Replace(value);
469 }
470 }
471 }
472 }
473
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000474 // Extract receiver maps from the LOAD_IC using the LoadICNexus.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000475 if (!p.feedback().IsValid()) return NoChange();
476 LoadICNexus nexus(p.feedback().vector(), p.feedback().slot());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000477
478 // Try to lower the named access based on the {receiver_maps}.
Ben Murdoch097c5b22016-05-18 11:27:45 +0100479 return ReduceNamedAccess(node, value, nexus, p.name(), AccessMode::kLoad,
480 p.language_mode());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000481}
482
483
484Reduction JSNativeContextSpecialization::ReduceJSStoreNamed(Node* node) {
485 DCHECK_EQ(IrOpcode::kJSStoreNamed, node->opcode());
486 NamedAccess const& p = NamedAccessOf(node->op());
487 Node* const value = NodeProperties::GetValueInput(node, 1);
488
489 // Extract receiver maps from the STORE_IC using the StoreICNexus.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000490 if (!p.feedback().IsValid()) return NoChange();
491 StoreICNexus nexus(p.feedback().vector(), p.feedback().slot());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000492
493 // Try to lower the named access based on the {receiver_maps}.
Ben Murdoch097c5b22016-05-18 11:27:45 +0100494 return ReduceNamedAccess(node, value, nexus, p.name(), AccessMode::kStore,
495 p.language_mode());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000496}
497
498
499Reduction JSNativeContextSpecialization::ReduceElementAccess(
500 Node* node, Node* index, Node* value, MapHandleList const& receiver_maps,
501 AccessMode access_mode, LanguageMode language_mode,
502 KeyedAccessStoreMode store_mode) {
503 DCHECK(node->opcode() == IrOpcode::kJSLoadProperty ||
504 node->opcode() == IrOpcode::kJSStoreProperty);
505 Node* receiver = NodeProperties::GetValueInput(node, 0);
506 Node* context = NodeProperties::GetContextInput(node);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000507 Node* effect = NodeProperties::GetEffectInput(node);
508 Node* control = NodeProperties::GetControlInput(node);
Ben Murdoch61f157c2016-09-16 13:49:30 +0100509 Node* frame_state = NodeProperties::FindFrameStateBefore(node);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000510
511 // Not much we can do if deoptimization support is disabled.
512 if (!(flags() & kDeoptimizationEnabled)) return NoChange();
513
514 // TODO(bmeurer): Add support for non-standard stores.
515 if (store_mode != STANDARD_STORE) return NoChange();
516
517 // Retrieve the native context from the given {node}.
518 Handle<Context> native_context;
519 if (!GetNativeContext(node).ToHandle(&native_context)) return NoChange();
520
521 // Compute element access infos for the receiver maps.
522 AccessInfoFactory access_info_factory(dependencies(), native_context,
523 graph()->zone());
524 ZoneVector<ElementAccessInfo> access_infos(zone());
525 if (!access_info_factory.ComputeElementAccessInfos(receiver_maps, access_mode,
526 &access_infos)) {
527 return NoChange();
528 }
529
530 // Nothing to do if we have no non-deprecated maps.
531 if (access_infos.empty()) return NoChange();
532
533 // The final states for every polymorphic branch. We join them with
534 // Merge+Phi+EffectPhi at the bottom.
535 ZoneVector<Node*> values(zone());
536 ZoneVector<Node*> effects(zone());
537 ZoneVector<Node*> controls(zone());
538
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000539 // Ensure that {receiver} is a heap object.
Ben Murdoch61f157c2016-09-16 13:49:30 +0100540 receiver = effect = graph()->NewNode(simplified()->CheckTaggedPointer(),
541 receiver, effect, control);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000542
543 // Load the {receiver} map. The resulting effect is the dominating effect for
544 // all (polymorphic) branches.
545 Node* receiver_map = effect =
546 graph()->NewNode(simplified()->LoadField(AccessBuilder::ForMap()),
547 receiver, effect, control);
548
549 // Generate code for the various different element access patterns.
550 Node* fallthrough_control = control;
Ben Murdochda12d292016-06-02 14:46:10 +0100551 for (size_t j = 0; j < access_infos.size(); ++j) {
552 ElementAccessInfo const& access_info = access_infos[j];
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000553 Node* this_receiver = receiver;
554 Node* this_value = value;
555 Node* this_index = index;
556 Node* this_effect;
557 Node* this_control;
558
559 // Perform map check on {receiver}.
560 Type* receiver_type = access_info.receiver_type();
561 bool receiver_is_jsarray = true;
562 {
563 ZoneVector<Node*> this_controls(zone());
564 ZoneVector<Node*> this_effects(zone());
Ben Murdochda12d292016-06-02 14:46:10 +0100565 size_t num_transitions = access_info.transitions().size();
566 int num_classes = access_info.receiver_type()->NumClasses();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000567 for (auto i = access_info.receiver_type()->Classes(); !i.Done();
568 i.Advance()) {
Ben Murdochda12d292016-06-02 14:46:10 +0100569 DCHECK_LT(0, num_classes);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000570 Handle<Map> map = i.Current();
571 Node* check =
572 graph()->NewNode(simplified()->ReferenceEqual(Type::Any()),
573 receiver_map, jsgraph()->Constant(map));
Ben Murdochda12d292016-06-02 14:46:10 +0100574 if (--num_classes == 0 && num_transitions == 0 &&
575 j == access_infos.size() - 1) {
576 // Last map check on the fallthrough control path, do a conditional
577 // eager deoptimization exit here.
578 // TODO(turbofan): This is ugly as hell! We should probably introduce
579 // macro-ish operators for property access that encapsulate this whole
580 // mess.
Ben Murdoch61f157c2016-09-16 13:49:30 +0100581 Node* deoptimize =
582 graph()->NewNode(common()->DeoptimizeUnless(), check, frame_state,
583 effect, fallthrough_control);
584 this_controls.push_back(deoptimize);
585 this_effects.push_back(deoptimize);
Ben Murdochda12d292016-06-02 14:46:10 +0100586 fallthrough_control = nullptr;
587 } else {
588 Node* branch =
589 graph()->NewNode(common()->Branch(), check, fallthrough_control);
590 this_controls.push_back(graph()->NewNode(common()->IfTrue(), branch));
Ben Murdoch61f157c2016-09-16 13:49:30 +0100591 this_effects.push_back(effect);
Ben Murdochda12d292016-06-02 14:46:10 +0100592 fallthrough_control = graph()->NewNode(common()->IfFalse(), branch);
593 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000594 if (!map->IsJSArrayMap()) receiver_is_jsarray = false;
595 }
596
597 // Generate possible elements kind transitions.
598 for (auto transition : access_info.transitions()) {
Ben Murdochda12d292016-06-02 14:46:10 +0100599 DCHECK_LT(0u, num_transitions);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000600 Handle<Map> transition_source = transition.first;
601 Handle<Map> transition_target = transition.second;
Ben Murdochda12d292016-06-02 14:46:10 +0100602 Node* transition_control;
603 Node* transition_effect = effect;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000604
605 // Check if {receiver} has the specified {transition_source} map.
606 Node* check = graph()->NewNode(
607 simplified()->ReferenceEqual(Type::Any()), receiver_map,
608 jsgraph()->HeapConstant(transition_source));
Ben Murdochda12d292016-06-02 14:46:10 +0100609 if (--num_transitions == 0 && j == access_infos.size() - 1) {
Ben Murdoch61f157c2016-09-16 13:49:30 +0100610 transition_control = transition_effect =
Ben Murdochda12d292016-06-02 14:46:10 +0100611 graph()->NewNode(common()->DeoptimizeUnless(), check, frame_state,
612 transition_effect, fallthrough_control);
613 fallthrough_control = nullptr;
614 } else {
615 Node* branch =
616 graph()->NewNode(common()->Branch(), check, fallthrough_control);
617 fallthrough_control = graph()->NewNode(common()->IfFalse(), branch);
618 transition_control = graph()->NewNode(common()->IfTrue(), branch);
619 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000620
621 // Migrate {receiver} from {transition_source} to {transition_target}.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000622 if (IsSimpleMapChangeTransition(transition_source->elements_kind(),
623 transition_target->elements_kind())) {
624 // In-place migration, just store the {transition_target} map.
625 transition_effect = graph()->NewNode(
626 simplified()->StoreField(AccessBuilder::ForMap()), receiver,
627 jsgraph()->HeapConstant(transition_target), transition_effect,
628 transition_control);
629 } else {
630 // Instance migration, let the stub deal with the {receiver}.
631 TransitionElementsKindStub stub(isolate(),
632 transition_source->elements_kind(),
Ben Murdoch61f157c2016-09-16 13:49:30 +0100633 transition_target->elements_kind());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000634 CallDescriptor const* const desc = Linkage::GetStubCallDescriptor(
635 isolate(), graph()->zone(), stub.GetCallInterfaceDescriptor(), 0,
636 CallDescriptor::kNeedsFrameState, node->op()->properties());
637 transition_effect = graph()->NewNode(
638 common()->Call(desc), jsgraph()->HeapConstant(stub.GetCode()),
639 receiver, jsgraph()->HeapConstant(transition_target), context,
640 frame_state, transition_effect, transition_control);
641 }
Ben Murdoch61f157c2016-09-16 13:49:30 +0100642
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000643 this_controls.push_back(transition_control);
644 this_effects.push_back(transition_effect);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000645 }
646
647 // Create single chokepoint for the control.
648 int const this_control_count = static_cast<int>(this_controls.size());
649 if (this_control_count == 1) {
650 this_control = this_controls.front();
651 this_effect = this_effects.front();
652 } else {
653 this_control =
654 graph()->NewNode(common()->Merge(this_control_count),
655 this_control_count, &this_controls.front());
656 this_effects.push_back(this_control);
657 this_effect =
658 graph()->NewNode(common()->EffectPhi(this_control_count),
659 this_control_count + 1, &this_effects.front());
660 }
Ben Murdoch61f157c2016-09-16 13:49:30 +0100661
662 // TODO(turbofan): The effect/control linearization will not find a
663 // FrameState after the StoreField or Call that is generated for the
664 // elements kind transition above. This is because those operators
665 // don't have the kNoWrite flag on it, even though they are not
666 // observable by JavaScript.
667 this_effect = graph()->NewNode(common()->Checkpoint(), frame_state,
668 this_effect, this_control);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000669 }
670
671 // Certain stores need a prototype chain check because shape changes
672 // could allow callbacks on elements in the prototype chain that are
673 // not compatible with (monomorphic) keyed stores.
674 Handle<JSObject> holder;
675 if (access_info.holder().ToHandle(&holder)) {
676 AssumePrototypesStable(receiver_type, native_context, holder);
677 }
678
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000679 // TODO(bmeurer): We currently specialize based on elements kind. We should
680 // also be able to properly support strings and other JSObjects here.
681 ElementsKind elements_kind = access_info.elements_kind();
682
683 // Load the elements for the {receiver}.
684 Node* this_elements = this_effect = graph()->NewNode(
685 simplified()->LoadField(AccessBuilder::ForJSObjectElements()),
686 this_receiver, this_effect, this_control);
687
688 // Don't try to store to a copy-on-write backing store.
689 if (access_mode == AccessMode::kStore &&
690 IsFastSmiOrObjectElementsKind(elements_kind)) {
691 Node* this_elements_map = this_effect =
692 graph()->NewNode(simplified()->LoadField(AccessBuilder::ForMap()),
693 this_elements, this_effect, this_control);
Ben Murdochda12d292016-06-02 14:46:10 +0100694 Node* check = graph()->NewNode(
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000695 simplified()->ReferenceEqual(Type::Any()), this_elements_map,
696 jsgraph()->HeapConstant(factory()->fixed_array_map()));
Ben Murdoch61f157c2016-09-16 13:49:30 +0100697 this_control = this_effect =
698 graph()->NewNode(common()->DeoptimizeUnless(), check, frame_state,
699 this_effect, this_control);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000700 }
701
702 // Load the length of the {receiver}.
703 Node* this_length = this_effect =
704 receiver_is_jsarray
705 ? graph()->NewNode(
706 simplified()->LoadField(
707 AccessBuilder::ForJSArrayLength(elements_kind)),
708 this_receiver, this_effect, this_control)
709 : graph()->NewNode(
710 simplified()->LoadField(AccessBuilder::ForFixedArrayLength()),
711 this_elements, this_effect, this_control);
712
713 // Check that the {index} is in the valid range for the {receiver}.
Ben Murdoch61f157c2016-09-16 13:49:30 +0100714 this_index = this_effect =
715 graph()->NewNode(simplified()->CheckBounds(), this_index, this_length,
716 this_effect, this_control);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000717
718 // Compute the element access.
719 Type* element_type = Type::Any();
720 MachineType element_machine_type = MachineType::AnyTagged();
721 if (IsFastDoubleElementsKind(elements_kind)) {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100722 element_type = Type::Number();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000723 element_machine_type = MachineType::Float64();
724 } else if (IsFastSmiElementsKind(elements_kind)) {
725 element_type = type_cache_.kSmi;
726 }
727 ElementAccess element_access = {kTaggedBase, FixedArray::kHeaderSize,
Ben Murdochc5610432016-08-08 18:44:38 +0100728 element_type, element_machine_type,
729 kFullWriteBarrier};
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000730
731 // Access the actual element.
732 // TODO(bmeurer): Refactor this into separate methods or even a separate
733 // class that deals with the elements access.
734 if (access_mode == AccessMode::kLoad) {
735 // Compute the real element access type, which includes the hole in case
736 // of holey backing stores.
737 if (elements_kind == FAST_HOLEY_ELEMENTS ||
738 elements_kind == FAST_HOLEY_SMI_ELEMENTS) {
739 element_access.type = Type::Union(
740 element_type,
741 Type::Constant(factory()->the_hole_value(), graph()->zone()),
742 graph()->zone());
743 }
744 // Perform the actual backing store access.
745 this_value = this_effect = graph()->NewNode(
746 simplified()->LoadElement(element_access), this_elements, this_index,
747 this_effect, this_control);
748 // Handle loading from holey backing stores correctly, by either mapping
749 // the hole to undefined if possible, or deoptimizing otherwise.
750 if (elements_kind == FAST_HOLEY_ELEMENTS ||
751 elements_kind == FAST_HOLEY_SMI_ELEMENTS) {
752 // Perform the hole check on the result.
Ben Murdoch61f157c2016-09-16 13:49:30 +0100753 CheckTaggedHoleMode mode = CheckTaggedHoleMode::kNeverReturnHole;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000754 // Check if we are allowed to turn the hole into undefined.
755 Type* initial_holey_array_type = Type::Class(
756 handle(isolate()->get_initial_js_array_map(elements_kind)),
757 graph()->zone());
758 if (receiver_type->NowIs(initial_holey_array_type) &&
759 isolate()->IsFastArrayConstructorPrototypeChainIntact()) {
760 // Add a code dependency on the array protector cell.
761 AssumePrototypesStable(receiver_type, native_context,
762 isolate()->initial_object_prototype());
763 dependencies()->AssumePropertyCell(factory()->array_protector());
764 // Turn the hole into undefined.
Ben Murdoch61f157c2016-09-16 13:49:30 +0100765 mode = CheckTaggedHoleMode::kConvertHoleToUndefined;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000766 }
Ben Murdoch61f157c2016-09-16 13:49:30 +0100767 this_value = this_effect =
768 graph()->NewNode(simplified()->CheckTaggedHole(mode), this_value,
769 this_effect, this_control);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000770 } else if (elements_kind == FAST_HOLEY_DOUBLE_ELEMENTS) {
771 // Perform the hole check on the result.
Ben Murdoch61f157c2016-09-16 13:49:30 +0100772 CheckFloat64HoleMode mode = CheckFloat64HoleMode::kNeverReturnHole;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000773 // Check if we are allowed to return the hole directly.
774 Type* initial_holey_array_type = Type::Class(
775 handle(isolate()->get_initial_js_array_map(elements_kind)),
776 graph()->zone());
777 if (receiver_type->NowIs(initial_holey_array_type) &&
778 isolate()->IsFastArrayConstructorPrototypeChainIntact()) {
779 // Add a code dependency on the array protector cell.
780 AssumePrototypesStable(receiver_type, native_context,
781 isolate()->initial_object_prototype());
782 dependencies()->AssumePropertyCell(factory()->array_protector());
Ben Murdoch61f157c2016-09-16 13:49:30 +0100783 // Return the signaling NaN hole directly if all uses are truncating.
784 mode = CheckFloat64HoleMode::kAllowReturnHole;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000785 }
Ben Murdoch61f157c2016-09-16 13:49:30 +0100786 this_value = this_effect =
787 graph()->NewNode(simplified()->CheckFloat64Hole(mode), this_value,
788 this_effect, this_control);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000789 }
790 } else {
791 DCHECK_EQ(AccessMode::kStore, access_mode);
792 if (IsFastSmiElementsKind(elements_kind)) {
Ben Murdoch61f157c2016-09-16 13:49:30 +0100793 this_value = this_effect =
794 graph()->NewNode(simplified()->CheckTaggedSigned(), this_value,
795 this_effect, this_control);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000796 } else if (IsFastDoubleElementsKind(elements_kind)) {
797 Node* check =
798 graph()->NewNode(simplified()->ObjectIsNumber(), this_value);
Ben Murdoch61f157c2016-09-16 13:49:30 +0100799 this_control = this_effect =
800 graph()->NewNode(common()->DeoptimizeUnless(), check, frame_state,
801 this_effect, this_control);
Ben Murdochc5610432016-08-08 18:44:38 +0100802 this_value = graph()->NewNode(simplified()->TypeGuard(Type::Number()),
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000803 this_value, this_control);
Ben Murdoch61f157c2016-09-16 13:49:30 +0100804 // Make sure we do not store signalling NaNs into holey double arrays.
805 if (elements_kind == FAST_HOLEY_DOUBLE_ELEMENTS) {
806 this_value =
807 graph()->NewNode(simplified()->NumberSilenceNaN(), this_value);
808 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000809 }
810 this_effect = graph()->NewNode(simplified()->StoreElement(element_access),
811 this_elements, this_index, this_value,
812 this_effect, this_control);
813 }
814
815 // Remember the final state for this element access.
816 values.push_back(this_value);
817 effects.push_back(this_effect);
818 controls.push_back(this_control);
819 }
820
Ben Murdochda12d292016-06-02 14:46:10 +0100821 DCHECK_NULL(fallthrough_control);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000822
823 // Generate the final merge point for all (polymorphic) branches.
824 int const control_count = static_cast<int>(controls.size());
825 if (control_count == 0) {
826 value = effect = control = jsgraph()->Dead();
827 } else if (control_count == 1) {
828 value = values.front();
829 effect = effects.front();
830 control = controls.front();
831 } else {
832 control = graph()->NewNode(common()->Merge(control_count), control_count,
833 &controls.front());
834 values.push_back(control);
835 value = graph()->NewNode(
836 common()->Phi(MachineRepresentation::kTagged, control_count),
837 control_count + 1, &values.front());
838 effects.push_back(control);
839 effect = graph()->NewNode(common()->EffectPhi(control_count),
840 control_count + 1, &effects.front());
841 }
842 ReplaceWithValue(node, value, effect, control);
843 return Replace(value);
844}
845
846
847Reduction JSNativeContextSpecialization::ReduceKeyedAccess(
848 Node* node, Node* index, Node* value, FeedbackNexus const& nexus,
849 AccessMode access_mode, LanguageMode language_mode,
850 KeyedAccessStoreMode store_mode) {
851 DCHECK(node->opcode() == IrOpcode::kJSLoadProperty ||
852 node->opcode() == IrOpcode::kJSStoreProperty);
Ben Murdochc5610432016-08-08 18:44:38 +0100853 Node* const receiver = NodeProperties::GetValueInput(node, 0);
854 Node* const effect = NodeProperties::GetEffectInput(node);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000855
Ben Murdoch097c5b22016-05-18 11:27:45 +0100856 // Check if the {nexus} reports type feedback for the IC.
857 if (nexus.IsUninitialized()) {
858 if ((flags() & kDeoptimizationEnabled) &&
859 (flags() & kBailoutOnUninitialized)) {
Ben Murdochc5610432016-08-08 18:44:38 +0100860 return ReduceSoftDeoptimize(node);
Ben Murdoch097c5b22016-05-18 11:27:45 +0100861 }
862 return NoChange();
863 }
864
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000865 // Extract receiver maps from the {nexus}.
866 MapHandleList receiver_maps;
Ben Murdochc5610432016-08-08 18:44:38 +0100867 if (!ExtractReceiverMaps(receiver, effect, nexus, &receiver_maps)) {
868 return NoChange();
869 } else if (receiver_maps.length() == 0) {
870 if ((flags() & kDeoptimizationEnabled) &&
871 (flags() & kBailoutOnUninitialized)) {
872 return ReduceSoftDeoptimize(node);
873 }
874 return NoChange();
875 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000876
877 // Optimize access for constant {index}.
878 HeapObjectMatcher mindex(index);
879 if (mindex.HasValue() && mindex.Value()->IsPrimitive()) {
880 // Keyed access requires a ToPropertyKey on the {index} first before
881 // looking up the property on the object (see ES6 section 12.3.2.1).
882 // We can only do this for non-observable ToPropertyKey invocations,
883 // so we limit the constant indices to primitives at this point.
884 Handle<Name> name;
885 if (Object::ToName(isolate(), mindex.Value()).ToHandle(&name)) {
886 uint32_t array_index;
887 if (name->AsArrayIndex(&array_index)) {
888 // Use the constant array index.
889 index = jsgraph()->Constant(static_cast<double>(array_index));
890 } else {
891 name = factory()->InternalizeName(name);
892 return ReduceNamedAccess(node, value, receiver_maps, name, access_mode,
893 language_mode);
894 }
895 }
896 }
897
898 // Check if we have feedback for a named access.
899 if (Name* name = nexus.FindFirstName()) {
900 return ReduceNamedAccess(node, value, receiver_maps,
901 handle(name, isolate()), access_mode,
902 language_mode, index);
903 }
904
905 // Try to lower the element access based on the {receiver_maps}.
906 return ReduceElementAccess(node, index, value, receiver_maps, access_mode,
907 language_mode, store_mode);
908}
909
910
Ben Murdoch097c5b22016-05-18 11:27:45 +0100911Reduction JSNativeContextSpecialization::ReduceSoftDeoptimize(Node* node) {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100912 Node* effect = NodeProperties::GetEffectInput(node);
913 Node* control = NodeProperties::GetControlInput(node);
Ben Murdoch61f157c2016-09-16 13:49:30 +0100914 Node* frame_state = NodeProperties::FindFrameStateBefore(node);
Ben Murdoch097c5b22016-05-18 11:27:45 +0100915 Node* deoptimize =
916 graph()->NewNode(common()->Deoptimize(DeoptimizeKind::kSoft), frame_state,
917 effect, control);
918 // TODO(bmeurer): This should be on the AdvancedReducer somehow.
919 NodeProperties::MergeControlToEnd(graph(), common(), deoptimize);
920 Revisit(graph()->end());
921 node->TrimInputCount(0);
922 NodeProperties::ChangeOp(node, common()->Dead());
923 return Changed(node);
924}
925
926
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000927Reduction JSNativeContextSpecialization::ReduceJSLoadProperty(Node* node) {
928 DCHECK_EQ(IrOpcode::kJSLoadProperty, node->opcode());
929 PropertyAccess const& p = PropertyAccessOf(node->op());
930 Node* const index = NodeProperties::GetValueInput(node, 1);
931 Node* const value = jsgraph()->Dead();
932
933 // Extract receiver maps from the KEYED_LOAD_IC using the KeyedLoadICNexus.
934 if (!p.feedback().IsValid()) return NoChange();
935 KeyedLoadICNexus nexus(p.feedback().vector(), p.feedback().slot());
936
937 // Try to lower the keyed access based on the {nexus}.
938 return ReduceKeyedAccess(node, index, value, nexus, AccessMode::kLoad,
939 p.language_mode(), STANDARD_STORE);
940}
941
942
943Reduction JSNativeContextSpecialization::ReduceJSStoreProperty(Node* node) {
944 DCHECK_EQ(IrOpcode::kJSStoreProperty, node->opcode());
945 PropertyAccess const& p = PropertyAccessOf(node->op());
946 Node* const index = NodeProperties::GetValueInput(node, 1);
947 Node* const value = NodeProperties::GetValueInput(node, 2);
948
949 // Extract receiver maps from the KEYED_STORE_IC using the KeyedStoreICNexus.
950 if (!p.feedback().IsValid()) return NoChange();
951 KeyedStoreICNexus nexus(p.feedback().vector(), p.feedback().slot());
952
953 // Extract the keyed access store mode from the KEYED_STORE_IC.
954 KeyedAccessStoreMode store_mode = nexus.GetKeyedAccessStoreMode();
955
956 // Try to lower the keyed access based on the {nexus}.
957 return ReduceKeyedAccess(node, index, value, nexus, AccessMode::kStore,
958 p.language_mode(), store_mode);
959}
960
961
962void JSNativeContextSpecialization::AssumePrototypesStable(
963 Type* receiver_type, Handle<Context> native_context,
964 Handle<JSObject> holder) {
965 // Determine actual holder and perform prototype chain checks.
966 for (auto i = receiver_type->Classes(); !i.Done(); i.Advance()) {
967 Handle<Map> map = i.Current();
968 // Perform the implicit ToObject for primitives here.
969 // Implemented according to ES6 section 7.3.2 GetV (V, P).
970 Handle<JSFunction> constructor;
971 if (Map::GetConstructorFunction(map, native_context)
972 .ToHandle(&constructor)) {
973 map = handle(constructor->initial_map(), isolate());
974 }
975 dependencies()->AssumePrototypeMapsStable(map, holder);
976 }
977}
978
Ben Murdochc5610432016-08-08 18:44:38 +0100979bool JSNativeContextSpecialization::ExtractReceiverMaps(
980 Node* receiver, Node* effect, FeedbackNexus const& nexus,
981 MapHandleList* receiver_maps) {
982 DCHECK_EQ(0, receiver_maps->length());
983 // See if we can infer a concrete type for the {receiver}.
984 Handle<Map> receiver_map;
985 if (InferReceiverMap(receiver, effect).ToHandle(&receiver_map)) {
986 // We can assume that the {receiver} still has the infered {receiver_map}.
987 receiver_maps->Add(receiver_map);
988 return true;
989 }
990 // Try to extract some maps from the {nexus}.
991 if (nexus.ExtractMaps(receiver_maps) != 0) {
992 // Try to filter impossible candidates based on infered root map.
993 if (InferReceiverRootMap(receiver).ToHandle(&receiver_map)) {
994 for (int i = receiver_maps->length(); --i >= 0;) {
995 if (receiver_maps->at(i)->FindRootMap() != *receiver_map) {
996 receiver_maps->Remove(i);
997 }
998 }
999 }
1000 return true;
1001 }
1002 return false;
1003}
1004
1005MaybeHandle<Map> JSNativeContextSpecialization::InferReceiverMap(Node* receiver,
1006 Node* effect) {
1007 NodeMatcher m(receiver);
1008 if (m.IsJSCreate()) {
1009 HeapObjectMatcher mtarget(m.InputAt(0));
1010 HeapObjectMatcher mnewtarget(m.InputAt(1));
1011 if (mtarget.HasValue() && mnewtarget.HasValue()) {
1012 Handle<JSFunction> constructor =
1013 Handle<JSFunction>::cast(mtarget.Value());
1014 if (constructor->has_initial_map()) {
1015 Handle<Map> initial_map(constructor->initial_map(), isolate());
1016 if (initial_map->constructor_or_backpointer() == *mnewtarget.Value()) {
1017 // Walk up the {effect} chain to see if the {receiver} is the
1018 // dominating effect and there's no other observable write in
1019 // between.
1020 while (true) {
1021 if (receiver == effect) return initial_map;
1022 if (!effect->op()->HasProperty(Operator::kNoWrite) ||
1023 effect->op()->EffectInputCount() != 1) {
1024 break;
1025 }
1026 effect = NodeProperties::GetEffectInput(effect);
1027 }
1028 }
1029 }
1030 }
1031 }
1032 return MaybeHandle<Map>();
1033}
1034
1035MaybeHandle<Map> JSNativeContextSpecialization::InferReceiverRootMap(
1036 Node* receiver) {
1037 HeapObjectMatcher m(receiver);
1038 if (m.HasValue()) {
1039 return handle(m.Value()->map()->FindRootMap(), isolate());
1040 } else if (m.IsJSCreate()) {
1041 HeapObjectMatcher mtarget(m.InputAt(0));
1042 HeapObjectMatcher mnewtarget(m.InputAt(1));
1043 if (mtarget.HasValue() && mnewtarget.HasValue()) {
1044 Handle<JSFunction> constructor =
1045 Handle<JSFunction>::cast(mtarget.Value());
1046 if (constructor->has_initial_map()) {
1047 Handle<Map> initial_map(constructor->initial_map(), isolate());
1048 if (initial_map->constructor_or_backpointer() == *mnewtarget.Value()) {
1049 DCHECK_EQ(*initial_map, initial_map->FindRootMap());
1050 return initial_map;
1051 }
1052 }
1053 }
1054 }
1055 return MaybeHandle<Map>();
1056}
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001057
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001058MaybeHandle<Context> JSNativeContextSpecialization::GetNativeContext(
1059 Node* node) {
1060 Node* const context = NodeProperties::GetContextInput(node);
1061 return NodeProperties::GetSpecializationNativeContext(context,
1062 native_context());
1063}
1064
1065
1066Graph* JSNativeContextSpecialization::graph() const {
1067 return jsgraph()->graph();
1068}
1069
1070
1071Isolate* JSNativeContextSpecialization::isolate() const {
1072 return jsgraph()->isolate();
1073}
1074
1075
1076Factory* JSNativeContextSpecialization::factory() const {
1077 return isolate()->factory();
1078}
1079
1080
1081MachineOperatorBuilder* JSNativeContextSpecialization::machine() const {
1082 return jsgraph()->machine();
1083}
1084
1085
1086CommonOperatorBuilder* JSNativeContextSpecialization::common() const {
1087 return jsgraph()->common();
1088}
1089
1090
1091JSOperatorBuilder* JSNativeContextSpecialization::javascript() const {
1092 return jsgraph()->javascript();
1093}
1094
1095
1096SimplifiedOperatorBuilder* JSNativeContextSpecialization::simplified() const {
1097 return jsgraph()->simplified();
1098}
1099
1100} // namespace compiler
1101} // namespace internal
1102} // namespace v8