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

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

Issue 1410353002: [turbofan] Rename JSGlobalSpecialization to JSNativeContextSpecialization. (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@master
Patch Set: Created 5 years, 2 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-global-specialization.h ('k') | src/compiler/js-inlining.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright 2015 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "src/compiler/js-global-specialization.h"
6
7 #include "src/compilation-dependencies.h"
8 #include "src/compiler/access-builder.h"
9 #include "src/compiler/js-graph.h"
10 #include "src/compiler/js-operator.h"
11 #include "src/contexts.h"
12 #include "src/field-index-inl.h"
13 #include "src/lookup.h"
14 #include "src/objects-inl.h" // TODO(mstarzinger): Temporary cycle breaker!
15 #include "src/type-feedback-vector.h"
16
17 namespace v8 {
18 namespace internal {
19 namespace compiler {
20
21 struct JSGlobalSpecialization::ScriptContextTableLookupResult {
22 Handle<Context> context;
23 bool immutable;
24 int index;
25 };
26
27
28 JSGlobalSpecialization::JSGlobalSpecialization(
29 Editor* editor, JSGraph* jsgraph, Flags flags,
30 Handle<GlobalObject> global_object, CompilationDependencies* dependencies,
31 Zone* zone)
32 : AdvancedReducer(editor),
33 jsgraph_(jsgraph),
34 flags_(flags),
35 global_object_(global_object),
36 dependencies_(dependencies),
37 zone_(zone) {}
38
39
40 Reduction JSGlobalSpecialization::Reduce(Node* node) {
41 switch (node->opcode()) {
42 case IrOpcode::kJSLoadGlobal:
43 return ReduceJSLoadGlobal(node);
44 case IrOpcode::kJSStoreGlobal:
45 return ReduceJSStoreGlobal(node);
46 case IrOpcode::kJSLoadNamed:
47 return ReduceJSLoadNamed(node);
48 default:
49 break;
50 }
51 return NoChange();
52 }
53
54
55 Reduction JSGlobalSpecialization::ReduceJSLoadGlobal(Node* node) {
56 DCHECK_EQ(IrOpcode::kJSLoadGlobal, node->opcode());
57 Handle<Name> name = LoadGlobalParametersOf(node->op()).name();
58 Node* effect = NodeProperties::GetEffectInput(node);
59 Node* control = NodeProperties::GetControlInput(node);
60
61 // Try to lookup the name on the script context table first (lexical scoping).
62 ScriptContextTableLookupResult result;
63 if (LookupInScriptContextTable(name, &result)) {
64 Node* context = jsgraph()->Constant(result.context);
65 Node* value = effect = graph()->NewNode(
66 javascript()->LoadContext(0, result.index, result.immutable), context,
67 context, effect);
68 return Replace(node, value, effect);
69 }
70
71 // Lookup on the global object instead. We only deal with own data
72 // properties of the global object here (represented as PropertyCell).
73 LookupIterator it(global_object(), name, LookupIterator::OWN);
74 if (it.state() != LookupIterator::DATA) return NoChange();
75 Handle<PropertyCell> property_cell = it.GetPropertyCell();
76 PropertyDetails property_details = property_cell->property_details();
77 Handle<Object> property_cell_value(property_cell->value(), isolate());
78
79 // Load from non-configurable, read-only data property on the global
80 // object can be constant-folded, even without deoptimization support.
81 if (!property_details.IsConfigurable() && property_details.IsReadOnly()) {
82 return Replace(node, property_cell_value);
83 }
84
85 // Load from constant/undefined global property can be constant-folded
86 // with deoptimization support, by adding a code dependency on the cell.
87 if ((property_details.cell_type() == PropertyCellType::kConstant ||
88 property_details.cell_type() == PropertyCellType::kUndefined) &&
89 (flags() & kDeoptimizationEnabled)) {
90 dependencies()->AssumePropertyCell(property_cell);
91 return Replace(node, property_cell_value);
92 }
93
94 // Load from constant type global property can benefit from representation
95 // (and map) feedback with deoptimization support (requires code dependency).
96 if (property_details.cell_type() == PropertyCellType::kConstantType &&
97 (flags() & kDeoptimizationEnabled)) {
98 dependencies()->AssumePropertyCell(property_cell);
99 // Compute proper type based on the current value in the cell.
100 Type* property_cell_value_type;
101 if (property_cell_value->IsSmi()) {
102 property_cell_value_type = Type::Intersect(
103 Type::SignedSmall(), Type::TaggedSigned(), graph()->zone());
104 } else if (property_cell_value->IsNumber()) {
105 property_cell_value_type = Type::Intersect(
106 Type::Number(), Type::TaggedPointer(), graph()->zone());
107 } else {
108 property_cell_value_type = Type::Of(property_cell_value, graph()->zone());
109 }
110 Node* value = effect = graph()->NewNode(
111 simplified()->LoadField(
112 AccessBuilder::ForPropertyCellValue(property_cell_value_type)),
113 jsgraph()->Constant(property_cell), effect, control);
114 return Replace(node, value, effect);
115 }
116
117 // Load from non-configurable, data property on the global can be lowered to
118 // a field load, even without deoptimization, because the property cannot be
119 // deleted or reconfigured to an accessor/interceptor property.
120 if (property_details.IsConfigurable()) {
121 // With deoptimization support, we can lower loads even from configurable
122 // data properties on the global object, by adding a code dependency on
123 // the cell.
124 if (!(flags() & kDeoptimizationEnabled)) return NoChange();
125 dependencies()->AssumePropertyCell(property_cell);
126 }
127 Node* value = effect = graph()->NewNode(
128 simplified()->LoadField(AccessBuilder::ForPropertyCellValue()),
129 jsgraph()->Constant(property_cell), effect, control);
130 return Replace(node, value, effect);
131 }
132
133
134 Reduction JSGlobalSpecialization::ReduceJSStoreGlobal(Node* node) {
135 DCHECK_EQ(IrOpcode::kJSStoreGlobal, node->opcode());
136 Handle<Name> name = StoreGlobalParametersOf(node->op()).name();
137 Node* value = NodeProperties::GetValueInput(node, 2);
138 Node* frame_state = NodeProperties::GetFrameStateInput(node, 1);
139 Node* effect = NodeProperties::GetEffectInput(node);
140 Node* control = NodeProperties::GetControlInput(node);
141
142 // Try to lookup the name on the script context table first (lexical scoping).
143 ScriptContextTableLookupResult result;
144 if (LookupInScriptContextTable(name, &result)) {
145 if (result.immutable) return NoChange();
146 Node* context = jsgraph()->Constant(result.context);
147 effect = graph()->NewNode(javascript()->StoreContext(0, result.index),
148 context, value, context, effect, control);
149 return Replace(node, value, effect, control);
150 }
151
152 // Lookup on the global object instead. We only deal with own data
153 // properties of the global object here (represented as PropertyCell).
154 LookupIterator it(global_object(), name, LookupIterator::OWN);
155 if (it.state() != LookupIterator::DATA) return NoChange();
156 Handle<PropertyCell> property_cell = it.GetPropertyCell();
157 PropertyDetails property_details = property_cell->property_details();
158 Handle<Object> property_cell_value(property_cell->value(), isolate());
159
160 // Don't even bother trying to lower stores to read-only data properties.
161 if (property_details.IsReadOnly()) return NoChange();
162 switch (property_details.cell_type()) {
163 case PropertyCellType::kUndefined: {
164 return NoChange();
165 }
166 case PropertyCellType::kConstant: {
167 // Store to constant property cell requires deoptimization support,
168 // because we might even need to eager deoptimize for mismatch.
169 if (!(flags() & kDeoptimizationEnabled)) return NoChange();
170 dependencies()->AssumePropertyCell(property_cell);
171 Node* check =
172 graph()->NewNode(simplified()->ReferenceEqual(Type::Tagged()), value,
173 jsgraph()->Constant(property_cell_value));
174 Node* branch =
175 graph()->NewNode(common()->Branch(BranchHint::kTrue), check, control);
176 Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
177 Node* deoptimize = graph()->NewNode(common()->Deoptimize(), frame_state,
178 effect, if_false);
179 // TODO(bmeurer): This should be on the AdvancedReducer somehow.
180 NodeProperties::MergeControlToEnd(graph(), common(), deoptimize);
181 control = graph()->NewNode(common()->IfTrue(), branch);
182 return Replace(node, value, effect, control);
183 }
184 case PropertyCellType::kConstantType: {
185 // Store to constant-type property cell requires deoptimization support,
186 // because we might even need to eager deoptimize for mismatch.
187 if (!(flags() & kDeoptimizationEnabled)) return NoChange();
188 dependencies()->AssumePropertyCell(property_cell);
189 Node* check = graph()->NewNode(simplified()->ObjectIsSmi(), value);
190 if (property_cell_value->IsHeapObject()) {
191 Node* branch = graph()->NewNode(common()->Branch(BranchHint::kFalse),
192 check, control);
193 Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
194 Node* deoptimize = graph()->NewNode(common()->Deoptimize(), frame_state,
195 effect, if_true);
196 // TODO(bmeurer): This should be on the AdvancedReducer somehow.
197 NodeProperties::MergeControlToEnd(graph(), common(), deoptimize);
198 control = graph()->NewNode(common()->IfFalse(), branch);
199 Node* value_map =
200 graph()->NewNode(simplified()->LoadField(AccessBuilder::ForMap()),
201 value, effect, control);
202 Handle<Map> property_cell_value_map(
203 Handle<HeapObject>::cast(property_cell_value)->map(), isolate());
204 check = graph()->NewNode(simplified()->ReferenceEqual(Type::Internal()),
205 value_map,
206 jsgraph()->Constant(property_cell_value_map));
207 }
208 Node* branch =
209 graph()->NewNode(common()->Branch(BranchHint::kTrue), check, control);
210 Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
211 Node* deoptimize = graph()->NewNode(common()->Deoptimize(), frame_state,
212 effect, if_false);
213 // TODO(bmeurer): This should be on the AdvancedReducer somehow.
214 NodeProperties::MergeControlToEnd(graph(), common(), deoptimize);
215 control = graph()->NewNode(common()->IfTrue(), branch);
216 break;
217 }
218 case PropertyCellType::kMutable: {
219 // Store to non-configurable, data property on the global can be lowered
220 // to a field store, even without deoptimization, because the property
221 // cannot be deleted or reconfigured to an accessor/interceptor property.
222 if (property_details.IsConfigurable()) {
223 // With deoptimization support, we can lower stores even to configurable
224 // data properties on the global object, by adding a code dependency on
225 // the cell.
226 if (!(flags() & kDeoptimizationEnabled)) return NoChange();
227 dependencies()->AssumePropertyCell(property_cell);
228 }
229 break;
230 }
231 }
232 effect = graph()->NewNode(
233 simplified()->StoreField(AccessBuilder::ForPropertyCellValue()),
234 jsgraph()->Constant(property_cell), value, effect, control);
235 return Replace(node, value, effect, control);
236 }
237
238
239 // This class encapsulates all information required to access a certain
240 // object property, either on the object itself or on the prototype chain.
241 class JSGlobalSpecialization::PropertyAccessInfo final {
242 public:
243 enum Kind { kInvalid, kData, kDataConstant };
244
245 static PropertyAccessInfo DataConstant(Type* receiver_type,
246 Handle<Object> constant,
247 MaybeHandle<JSObject> holder) {
248 return PropertyAccessInfo(holder, constant, receiver_type);
249 }
250 static PropertyAccessInfo Data(Type* receiver_type, FieldIndex field_index,
251 Representation field_representation,
252 MaybeHandle<JSObject> holder) {
253 return PropertyAccessInfo(holder, field_index, field_representation,
254 receiver_type);
255 }
256
257 PropertyAccessInfo() : kind_(kInvalid) {}
258 PropertyAccessInfo(MaybeHandle<JSObject> holder, Handle<Object> constant,
259 Type* receiver_type)
260 : kind_(kDataConstant),
261 receiver_type_(receiver_type),
262 constant_(constant),
263 holder_(holder) {}
264 PropertyAccessInfo(MaybeHandle<JSObject> holder, FieldIndex field_index,
265 Representation field_representation, Type* receiver_type)
266 : kind_(kData),
267 receiver_type_(receiver_type),
268 holder_(holder),
269 field_index_(field_index),
270 field_representation_(field_representation) {}
271
272 bool IsDataConstant() const { return kind() == kDataConstant; }
273 bool IsData() const { return kind() == kData; }
274
275 Kind kind() const { return kind_; }
276 MaybeHandle<JSObject> holder() const { return holder_; }
277 Handle<Object> constant() const { return constant_; }
278 FieldIndex field_index() const { return field_index_; }
279 Representation field_representation() const { return field_representation_; }
280 Type* receiver_type() const { return receiver_type_; }
281
282 private:
283 Kind kind_;
284 Type* receiver_type_;
285 Handle<Object> constant_;
286 MaybeHandle<JSObject> holder_;
287 FieldIndex field_index_;
288 Representation field_representation_;
289 };
290
291
292 namespace {
293
294 bool CanInlinePropertyAccess(Handle<Map> map) {
295 // TODO(bmeurer): Do something about the number stuff.
296 if (map->instance_type() == HEAP_NUMBER_TYPE) return false;
297 if (map->instance_type() < FIRST_NONSTRING_TYPE) return true;
298 return map->IsJSObjectMap() && !map->is_dictionary_map() &&
299 !map->has_named_interceptor() &&
300 // TODO(verwaest): Whitelist contexts to which we have access.
301 !map->is_access_check_needed();
302 }
303
304 } // namespace
305
306
307 bool JSGlobalSpecialization::ComputePropertyAccessInfo(
308 Handle<Map> map, Handle<Name> name, PropertyAccessInfo* access_info) {
309 MaybeHandle<JSObject> holder;
310 Type* receiver_type = Type::Class(map, graph()->zone());
311 while (CanInlinePropertyAccess(map)) {
312 // Lookup the named property on the {map}.
313 Handle<DescriptorArray> descriptors(map->instance_descriptors(), isolate());
314 int const number = descriptors->SearchWithCache(*name, *map);
315 if (number != DescriptorArray::kNotFound) {
316 PropertyDetails const details = descriptors->GetDetails(number);
317 if (details.type() == DATA_CONSTANT) {
318 *access_info = PropertyAccessInfo::DataConstant(
319 receiver_type, handle(descriptors->GetValue(number), isolate()),
320 holder);
321 return true;
322 } else if (details.type() == DATA) {
323 int index = descriptors->GetFieldIndex(number);
324 Representation field_representation = details.representation();
325 FieldIndex field_index = FieldIndex::ForPropertyIndex(
326 *map, index, field_representation.IsDouble());
327 *access_info = PropertyAccessInfo::Data(receiver_type, field_index,
328 field_representation, holder);
329 return true;
330 } else {
331 // TODO(bmeurer): Add support for accessors.
332 break;
333 }
334 }
335
336 // Don't search on the prototype chain for special indices in case of
337 // integer indexed exotic objects (see ES6 section 9.4.5).
338 if (map->IsJSTypedArrayMap() && name->IsString() &&
339 IsSpecialIndex(isolate()->unicode_cache(), String::cast(*name))) {
340 break;
341 }
342
343 // Walk up the prototype chain.
344 if (!map->prototype()->IsJSObject()) {
345 // TODO(bmeurer): Handle the not found case if the prototype is null.
346 break;
347 }
348 Handle<JSObject> map_prototype(JSObject::cast(map->prototype()), isolate());
349 if (map_prototype->map()->is_deprecated()) {
350 // Try to migrate the prototype object so we don't embed the deprecated
351 // map into the optimized code.
352 JSObject::TryMigrateInstance(map_prototype);
353 }
354 map = handle(map_prototype->map(), isolate());
355 holder = map_prototype;
356 }
357 return false;
358 }
359
360
361 bool JSGlobalSpecialization::ComputePropertyAccessInfos(
362 MapHandleList const& maps, Handle<Name> name,
363 ZoneVector<PropertyAccessInfo>* access_infos) {
364 for (Handle<Map> map : maps) {
365 PropertyAccessInfo access_info;
366 if (!ComputePropertyAccessInfo(map, name, &access_info)) return false;
367 access_infos->push_back(access_info);
368 }
369 return true;
370 }
371
372
373 Reduction JSGlobalSpecialization::ReduceJSLoadNamed(Node* node) {
374 DCHECK_EQ(IrOpcode::kJSLoadNamed, node->opcode());
375 LoadNamedParameters const p = LoadNamedParametersOf(node->op());
376 Handle<Name> name = p.name();
377 Node* receiver = NodeProperties::GetValueInput(node, 0);
378 Node* frame_state = NodeProperties::GetFrameStateInput(node, 1);
379 Node* effect = NodeProperties::GetEffectInput(node);
380 Node* control = NodeProperties::GetControlInput(node);
381
382 // Not much we can do if deoptimization support is disabled.
383 if (!(flags() & kDeoptimizationEnabled)) return NoChange();
384
385 // Extract receiver maps from the LOAD_IC using the LoadICNexus.
386 MapHandleList receiver_maps;
387 if (!p.feedback().IsValid()) return NoChange();
388 LoadICNexus nexus(p.feedback().vector(), p.feedback().slot());
389 if (nexus.ExtractMaps(&receiver_maps) == 0) return NoChange();
390 DCHECK_LT(0, receiver_maps.length());
391
392 // Compute property access infos for the receiver maps.
393 ZoneVector<PropertyAccessInfo> access_infos(zone());
394 if (!ComputePropertyAccessInfos(receiver_maps, name, &access_infos)) {
395 return NoChange();
396 }
397 DCHECK(!access_infos.empty());
398
399 // The final states for every polymorphic branch. We join them with
400 // Merge+Phi+EffectPhi at the bottom.
401 ZoneVector<Node*> values(zone());
402 ZoneVector<Node*> effects(zone());
403 ZoneVector<Node*> controls(zone());
404
405 // The list of "exiting" controls, which currently go to a single deoptimize.
406 // TODO(bmeurer): Consider using an IC as fallback.
407 Node* const exit_effect = effect;
408 ZoneVector<Node*> exit_controls(zone());
409
410 // Ensure that {receiver} is a heap object.
411 Node* check = graph()->NewNode(simplified()->ObjectIsSmi(), receiver);
412 Node* branch =
413 graph()->NewNode(common()->Branch(BranchHint::kFalse), check, control);
414 exit_controls.push_back(graph()->NewNode(common()->IfTrue(), branch));
415 control = graph()->NewNode(common()->IfFalse(), branch);
416
417 // Load the {receiver} map. The resulting effect is the dominating effect for
418 // all (polymorphic) branches.
419 Node* receiver_map = effect =
420 graph()->NewNode(simplified()->LoadField(AccessBuilder::ForMap()),
421 receiver, effect, control);
422
423 // Generate code for the various different property access patterns.
424 Node* fallthrough_control = control;
425 for (PropertyAccessInfo const& access_info : access_infos) {
426 Node* this_value = receiver;
427 Node* this_effect = effect;
428 Node* this_control;
429
430 // Perform map check on {receiver}.
431 Type* receiver_type = access_info.receiver_type();
432 if (receiver_type->Is(Type::String())) {
433 // Emit an instance type check for strings.
434 Node* receiver_instance_type = this_effect = graph()->NewNode(
435 simplified()->LoadField(AccessBuilder::ForMapInstanceType()),
436 receiver_map, this_effect, fallthrough_control);
437 Node* check =
438 graph()->NewNode(machine()->Uint32LessThan(), receiver_instance_type,
439 jsgraph()->Uint32Constant(FIRST_NONSTRING_TYPE));
440 Node* branch = graph()->NewNode(common()->Branch(BranchHint::kTrue),
441 check, fallthrough_control);
442 fallthrough_control = graph()->NewNode(common()->IfFalse(), branch);
443 this_control = graph()->NewNode(common()->IfTrue(), branch);
444 } else {
445 // Emit a (sequence of) map checks for other properties.
446 ZoneVector<Node*> this_controls(zone());
447 for (auto i = access_info.receiver_type()->Classes(); !i.Done();
448 i.Advance()) {
449 Handle<Map> map = i.Current();
450 Node* check =
451 graph()->NewNode(simplified()->ReferenceEqual(Type::Internal()),
452 receiver_map, jsgraph()->Constant(map));
453 Node* branch = graph()->NewNode(common()->Branch(BranchHint::kTrue),
454 check, fallthrough_control);
455 this_controls.push_back(graph()->NewNode(common()->IfTrue(), branch));
456 fallthrough_control = graph()->NewNode(common()->IfFalse(), branch);
457 }
458 int const this_control_count = static_cast<int>(this_controls.size());
459 this_control =
460 (this_control_count == 1)
461 ? this_controls.front()
462 : graph()->NewNode(common()->Merge(this_control_count),
463 this_control_count, &this_controls.front());
464 }
465
466 // Determine actual holder and perform prototype chain checks.
467 Handle<JSObject> holder;
468 if (access_info.holder().ToHandle(&holder)) {
469 this_value = jsgraph()->Constant(holder);
470 for (auto i = access_info.receiver_type()->Classes(); !i.Done();
471 i.Advance()) {
472 Handle<Map> map = i.Current();
473 PrototypeIterator j(map);
474 while (true) {
475 // Check that the {prototype} still has the same map. For stable
476 // maps, we can add a stability dependency on the prototype map;
477 // for everything else we need to perform a map check at runtime.
478 Handle<JSReceiver> prototype =
479 PrototypeIterator::GetCurrent<JSReceiver>(j);
480 if (prototype->map()->is_stable()) {
481 dependencies()->AssumeMapStable(
482 handle(prototype->map(), isolate()));
483 } else {
484 Node* prototype_map = this_effect = graph()->NewNode(
485 simplified()->LoadField(AccessBuilder::ForMap()),
486 jsgraph()->Constant(prototype), this_effect, this_control);
487 Node* check = graph()->NewNode(
488 simplified()->ReferenceEqual(Type::Internal()), prototype_map,
489 jsgraph()->Constant(handle(prototype->map(), isolate())));
490 Node* branch = graph()->NewNode(common()->Branch(BranchHint::kTrue),
491 check, this_control);
492 exit_controls.push_back(
493 graph()->NewNode(common()->IfFalse(), branch));
494 this_control = graph()->NewNode(common()->IfTrue(), branch);
495 }
496 // Stop once we get to the holder.
497 if (prototype.is_identical_to(holder)) break;
498 j.Advance();
499 }
500 }
501 }
502
503 // Generate the actual property access.
504 if (access_info.IsDataConstant()) {
505 this_value = jsgraph()->Constant(access_info.constant());
506 } else {
507 // TODO(bmeurer): This is sort of adhoc, and must be refactored into some
508 // common code once we also have support for stores.
509 DCHECK(access_info.IsData());
510 FieldIndex const field_index = access_info.field_index();
511 Representation const field_representation =
512 access_info.field_representation();
513 if (!field_index.is_inobject()) {
514 this_value = this_effect = graph()->NewNode(
515 simplified()->LoadField(AccessBuilder::ForJSObjectProperties()),
516 this_value, this_effect, this_control);
517 }
518 FieldAccess field_access;
519 field_access.base_is_tagged = kTaggedBase;
520 field_access.offset = field_index.offset();
521 field_access.name = name;
522 field_access.type = Type::Any();
523 field_access.machine_type = kMachAnyTagged;
524 if (field_representation.IsSmi()) {
525 field_access.type = Type::Intersect(
526 Type::SignedSmall(), Type::TaggedSigned(), graph()->zone());
527 } else if (field_representation.IsDouble()) {
528 if (!field_index.is_inobject() || field_index.is_hidden_field() ||
529 !FLAG_unbox_double_fields) {
530 this_value = this_effect =
531 graph()->NewNode(simplified()->LoadField(field_access),
532 this_value, this_effect, this_control);
533 field_access.offset = HeapNumber::kValueOffset;
534 field_access.name = MaybeHandle<Name>();
535 }
536 field_access.type = Type::Intersect(
537 Type::Number(), Type::UntaggedFloat64(), graph()->zone());
538 field_access.machine_type = kMachFloat64;
539 } else if (field_representation.IsHeapObject()) {
540 field_access.type = Type::TaggedPointer();
541 }
542 this_value = this_effect =
543 graph()->NewNode(simplified()->LoadField(field_access), this_value,
544 this_effect, this_control);
545 }
546
547 // Remember the final state for this property access.
548 values.push_back(this_value);
549 effects.push_back(this_effect);
550 controls.push_back(this_control);
551 }
552
553 // Collect the fallthru control as final "exit" control.
554 exit_controls.push_back(fallthrough_control);
555
556 // TODO(bmeurer/mtrofin): Splintering cannot currently deal with deferred
557 // blocks that contain only a single non-deoptimize instruction (i.e. a
558 // jump). Generating a single Merge here, which joins all the deoptimizing
559 // controls would generate a lot of these basic blocks, however. So this
560 // is disabled for now until splintering is fixed.
561 #if 0
562 // Generate the single "exit" point, where we get if either all map/instance
563 // type checks failed, or one of the assumptions inside one of the cases
564 // failes (i.e. failing prototype chain check).
565 // TODO(bmeurer): Consider falling back to IC here if deoptimization is
566 // disabled.
567 int const exit_control_count = static_cast<int>(exit_controls.size());
568 Node* exit_control =
569 (exit_control_count == 1)
570 ? exit_controls.front()
571 : graph()->NewNode(common()->Merge(exit_control_count),
572 exit_control_count, &exit_controls.front());
573 Node* deoptimize = graph()->NewNode(common()->Deoptimize(), frame_state,
574 exit_effect, exit_control);
575 // TODO(bmeurer): This should be on the AdvancedReducer somehow.
576 NodeProperties::MergeControlToEnd(graph(), common(), deoptimize);
577 #else
578 for (Node* const exit_control : exit_controls) {
579 Node* deoptimize = graph()->NewNode(common()->Deoptimize(), frame_state,
580 exit_effect, exit_control);
581 // TODO(bmeurer): This should be on the AdvancedReducer somehow.
582 NodeProperties::MergeControlToEnd(graph(), common(), deoptimize);
583 }
584 #endif
585
586 // Generate the final merge point for all (polymorphic) branches.
587 Node* value;
588 int const control_count = static_cast<int>(controls.size());
589 if (control_count == 1) {
590 value = values.front();
591 effect = effects.front();
592 control = controls.front();
593 } else {
594 control = graph()->NewNode(common()->Merge(control_count), control_count,
595 &controls.front());
596 values.push_back(control);
597 value = graph()->NewNode(common()->Phi(kMachAnyTagged, control_count),
598 control_count + 1, &values.front());
599 effects.push_back(control);
600 effect = graph()->NewNode(common()->EffectPhi(control_count),
601 control_count + 1, &effects.front());
602 }
603 return Replace(node, value, effect, control);
604 }
605
606
607 Reduction JSGlobalSpecialization::Replace(Node* node, Handle<Object> value) {
608 return Replace(node, jsgraph()->Constant(value));
609 }
610
611
612 bool JSGlobalSpecialization::LookupInScriptContextTable(
613 Handle<Name> name, ScriptContextTableLookupResult* result) {
614 if (!name->IsString()) return false;
615 Handle<ScriptContextTable> script_context_table(
616 global_object()->native_context()->script_context_table());
617 ScriptContextTable::LookupResult lookup_result;
618 if (!ScriptContextTable::Lookup(script_context_table,
619 Handle<String>::cast(name), &lookup_result)) {
620 return false;
621 }
622 Handle<Context> script_context = ScriptContextTable::GetContext(
623 script_context_table, lookup_result.context_index);
624 if (script_context->is_the_hole(lookup_result.slot_index)) return false;
625 result->context = script_context;
626 result->immutable = IsImmutableVariableMode(lookup_result.mode);
627 result->index = lookup_result.slot_index;
628 return true;
629 }
630
631
632 Graph* JSGlobalSpecialization::graph() const { return jsgraph()->graph(); }
633
634
635 Isolate* JSGlobalSpecialization::isolate() const {
636 return jsgraph()->isolate();
637 }
638
639
640 MachineOperatorBuilder* JSGlobalSpecialization::machine() const {
641 return jsgraph()->machine();
642 }
643
644
645 CommonOperatorBuilder* JSGlobalSpecialization::common() const {
646 return jsgraph()->common();
647 }
648
649
650 JSOperatorBuilder* JSGlobalSpecialization::javascript() const {
651 return jsgraph()->javascript();
652 }
653
654
655 SimplifiedOperatorBuilder* JSGlobalSpecialization::simplified() const {
656 return jsgraph()->simplified();
657 }
658
659 } // namespace compiler
660 } // namespace internal
661 } // namespace v8
OLDNEW
« no previous file with comments | « src/compiler/js-global-specialization.h ('k') | src/compiler/js-inlining.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698