Line data Source code
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-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/compiler/type-cache.h"
17 : #include "src/feedback-vector.h"
18 : #include "src/field-index-inl.h"
19 : #include "src/isolate-inl.h"
20 :
21 : namespace v8 {
22 : namespace internal {
23 : namespace compiler {
24 :
25 : namespace {
26 :
27 : bool HasNumberMaps(MapList const& maps) {
28 28300 : for (auto map : maps) {
29 10448 : if (map->instance_type() == HEAP_NUMBER_TYPE) return true;
30 : }
31 : return false;
32 : }
33 :
34 : bool HasOnlyJSArrayMaps(MapList const& maps) {
35 64223 : for (auto map : maps) {
36 22903 : if (!map->IsJSArrayMap()) return false;
37 : }
38 : return true;
39 : }
40 :
41 : bool HasOnlyNumberMaps(MapList const& maps) {
42 165074 : for (auto map : maps) {
43 82414 : if (map->instance_type() != HEAP_NUMBER_TYPE) return false;
44 : }
45 : return true;
46 : }
47 :
48 : template <typename T>
49 : bool HasOnlyStringMaps(T const& maps) {
50 225224 : for (auto map : maps) {
51 111689 : if (!map->IsStringMap()) return false;
52 : }
53 : return true;
54 : }
55 :
56 : } // namespace
57 :
58 : struct JSNativeContextSpecialization::ScriptContextTableLookupResult {
59 : Handle<Context> context;
60 : bool immutable;
61 : int index;
62 : };
63 :
64 395342 : JSNativeContextSpecialization::JSNativeContextSpecialization(
65 : Editor* editor, JSGraph* jsgraph, Flags flags,
66 : Handle<Context> native_context, CompilationDependencies* dependencies,
67 : Zone* zone)
68 : : AdvancedReducer(editor),
69 : jsgraph_(jsgraph),
70 : flags_(flags),
71 : global_object_(native_context->global_object()),
72 395343 : global_proxy_(JSGlobalProxy::cast(native_context->global_proxy())),
73 : native_context_(native_context),
74 : dependencies_(dependencies),
75 : zone_(zone),
76 1186027 : type_cache_(TypeCache::Get()) {}
77 :
78 33010996 : Reduction JSNativeContextSpecialization::Reduce(Node* node) {
79 33010996 : switch (node->opcode()) {
80 : case IrOpcode::kJSAdd:
81 119015 : return ReduceJSAdd(node);
82 : case IrOpcode::kJSGetSuperConstructor:
83 489 : return ReduceJSGetSuperConstructor(node);
84 : case IrOpcode::kJSInstanceOf:
85 2080 : return ReduceJSInstanceOf(node);
86 : case IrOpcode::kJSOrdinaryHasInstance:
87 1098 : return ReduceJSOrdinaryHasInstance(node);
88 : case IrOpcode::kJSLoadContext:
89 745205 : return ReduceJSLoadContext(node);
90 : case IrOpcode::kJSLoadGlobal:
91 523986 : return ReduceJSLoadGlobal(node);
92 : case IrOpcode::kJSStoreGlobal:
93 36670 : return ReduceJSStoreGlobal(node);
94 : case IrOpcode::kJSLoadNamed:
95 453799 : return ReduceJSLoadNamed(node);
96 : case IrOpcode::kJSStoreNamed:
97 64462 : return ReduceJSStoreNamed(node);
98 : case IrOpcode::kJSLoadProperty:
99 76291 : return ReduceJSLoadProperty(node);
100 : case IrOpcode::kJSStoreProperty:
101 43969 : return ReduceJSStoreProperty(node);
102 : case IrOpcode::kJSStoreNamedOwn:
103 36313 : return ReduceJSStoreNamedOwn(node);
104 : case IrOpcode::kJSStoreDataPropertyInLiteral:
105 44202 : return ReduceJSStoreDataPropertyInLiteral(node);
106 : default:
107 : break;
108 : }
109 : return NoChange();
110 : }
111 :
112 121950 : Reduction JSNativeContextSpecialization::ReduceJSAdd(Node* node) {
113 : // TODO(turbofan): This has to run together with the inlining and
114 : // native context specialization to be able to leverage the string
115 : // constant-folding for optimizing property access, but we should
116 : // nevertheless find a better home for this at some point.
117 : DCHECK_EQ(IrOpcode::kJSAdd, node->opcode());
118 :
119 : // Constant-fold string concatenation.
120 119015 : HeapObjectBinopMatcher m(node);
121 274153 : if (m.left().HasValue() && m.left().Value()->IsString() &&
122 140022 : m.right().HasValue() && m.right().Value()->IsString()) {
123 : Handle<String> left = Handle<String>::cast(m.left().Value());
124 : Handle<String> right = Handle<String>::cast(m.right().Value());
125 2935 : if (left->length() + right->length() <= String::kMaxLength) {
126 : Handle<String> result =
127 5870 : factory()->NewConsString(left, right).ToHandleChecked();
128 2935 : Node* value = jsgraph()->HeapConstant(result);
129 2935 : ReplaceWithValue(node, value);
130 : return Replace(value);
131 : }
132 : }
133 : return NoChange();
134 : }
135 :
136 489 : Reduction JSNativeContextSpecialization::ReduceJSGetSuperConstructor(
137 876 : Node* node) {
138 : DCHECK_EQ(IrOpcode::kJSGetSuperConstructor, node->opcode());
139 489 : Node* constructor = NodeProperties::GetValueInput(node, 0);
140 :
141 : // Check if the input is a known JSFunction.
142 : HeapObjectMatcher m(constructor);
143 489 : if (!m.HasValue()) return NoChange();
144 : Handle<JSFunction> function = Handle<JSFunction>::cast(m.Value());
145 : Handle<Map> function_map(function->map(), isolate());
146 : Handle<Object> function_prototype(function_map->prototype(), isolate());
147 :
148 : // We can constant-fold the super constructor access if the
149 : // {function}s map is stable, i.e. we can use a code dependency
150 : // to guard against [[Prototype]] changes of {function}.
151 442 : if (function_map->is_stable()) {
152 438 : Node* value = jsgraph()->Constant(function_prototype);
153 438 : dependencies()->AssumeMapStable(function_map);
154 438 : if (function_prototype->IsConstructor()) {
155 406 : ReplaceWithValue(node, value);
156 : return Replace(value);
157 : }
158 : }
159 :
160 : return NoChange();
161 : }
162 :
163 4398 : Reduction JSNativeContextSpecialization::ReduceJSInstanceOf(Node* node) {
164 : DCHECK_EQ(IrOpcode::kJSInstanceOf, node->opcode());
165 2088 : Node* object = NodeProperties::GetValueInput(node, 0);
166 2088 : Node* constructor = NodeProperties::GetValueInput(node, 1);
167 2088 : Node* context = NodeProperties::GetContextInput(node);
168 2088 : Node* effect = NodeProperties::GetEffectInput(node);
169 2088 : Node* control = NodeProperties::GetControlInput(node);
170 :
171 : // Check if the right hand side is a known {receiver}.
172 : HeapObjectMatcher m(constructor);
173 3294 : if (!m.HasValue() || !m.Value()->IsJSObject()) return NoChange();
174 : Handle<JSObject> receiver = Handle<JSObject>::cast(m.Value());
175 : Handle<Map> receiver_map(receiver->map(), isolate());
176 :
177 : // Compute property access info for @@hasInstance on {receiver}.
178 1200 : PropertyAccessInfo access_info;
179 : AccessInfoFactory access_info_factory(dependencies(), native_context(),
180 2400 : graph()->zone());
181 1200 : if (!access_info_factory.ComputePropertyAccessInfo(
182 : receiver_map, factory()->has_instance_symbol(), AccessMode::kLoad,
183 1200 : &access_info)) {
184 : return NoChange();
185 : }
186 :
187 1119 : if (access_info.IsNotFound()) {
188 : // If there's no @@hasInstance handler, the OrdinaryHasInstance operation
189 : // takes over, but that requires the {receiver} to be callable.
190 8 : if (receiver->IsCallable()) {
191 : // Determine actual holder and perform prototype chain checks.
192 : Handle<JSObject> holder;
193 8 : if (access_info.holder().ToHandle(&holder)) {
194 0 : AssumePrototypesStable(access_info.receiver_maps(), holder);
195 : }
196 :
197 : // Monomorphic property access.
198 : effect = BuildCheckMaps(constructor, effect, control,
199 8 : access_info.receiver_maps());
200 :
201 : // Lower to OrdinaryHasInstance(C, O).
202 8 : NodeProperties::ReplaceValueInput(node, constructor, 0);
203 8 : NodeProperties::ReplaceValueInput(node, object, 1);
204 8 : NodeProperties::ReplaceEffectInput(node, effect);
205 8 : NodeProperties::ChangeOp(node, javascript()->OrdinaryHasInstance());
206 8 : Reduction const reduction = ReduceJSOrdinaryHasInstance(node);
207 8 : return reduction.Changed() ? reduction : Changed(node);
208 : }
209 1111 : } else if (access_info.IsDataConstant() ||
210 : access_info.IsDataConstantField()) {
211 : // Determine actual holder and perform prototype chain checks.
212 : Handle<JSObject> holder;
213 1110 : if (access_info.holder().ToHandle(&holder)) {
214 1086 : AssumePrototypesStable(access_info.receiver_maps(), holder);
215 : } else {
216 24 : holder = receiver;
217 : }
218 :
219 : Handle<Object> constant;
220 1110 : if (access_info.IsDataConstant()) {
221 : DCHECK(!FLAG_track_constant_fields);
222 1110 : constant = access_info.constant();
223 : } else {
224 : DCHECK(FLAG_track_constant_fields);
225 : DCHECK(access_info.IsDataConstantField());
226 : // The value must be callable therefore tagged.
227 : DCHECK(CanBeTaggedPointer(access_info.field_representation()));
228 0 : FieldIndex field_index = access_info.field_index();
229 : constant = JSObject::FastPropertyAt(holder, Representation::Tagged(),
230 0 : field_index);
231 : }
232 : DCHECK(constant->IsCallable());
233 :
234 : // Monomorphic property access.
235 : effect = BuildCheckMaps(constructor, effect, control,
236 1110 : access_info.receiver_maps());
237 :
238 : // Call the @@hasInstance handler.
239 1110 : Node* target = jsgraph()->Constant(constant);
240 1110 : node->InsertInput(graph()->zone(), 0, target);
241 1110 : node->ReplaceInput(1, constructor);
242 1110 : node->ReplaceInput(2, object);
243 1110 : node->ReplaceInput(5, effect);
244 : NodeProperties::ChangeOp(
245 : node,
246 : javascript()->Call(3, 0.0f, VectorSlotPair(),
247 2220 : ConvertReceiverMode::kNotNullOrUndefined));
248 :
249 : // Rewire the value uses of {node} to ToBoolean conversion of the result.
250 : Node* value = graph()->NewNode(javascript()->ToBoolean(ToBooleanHint::kAny),
251 2220 : node, context);
252 12724 : for (Edge edge : node->use_edges()) {
253 8354 : if (NodeProperties::IsValueEdge(edge) && edge.from() != value) {
254 1437 : edge.UpdateTo(value);
255 2874 : Revisit(edge.from());
256 : }
257 : }
258 : return Changed(node);
259 : }
260 :
261 : return NoChange();
262 : }
263 :
264 1106 : Reduction JSNativeContextSpecialization::ReduceJSOrdinaryHasInstance(
265 8924 : Node* node) {
266 : DCHECK_EQ(IrOpcode::kJSOrdinaryHasInstance, node->opcode());
267 1106 : Node* constructor = NodeProperties::GetValueInput(node, 0);
268 1106 : Node* object = NodeProperties::GetValueInput(node, 1);
269 1106 : Node* context = NodeProperties::GetContextInput(node);
270 1106 : Node* frame_state = NodeProperties::GetFrameStateInput(node);
271 1106 : Node* effect = NodeProperties::GetEffectInput(node);
272 1106 : Node* control = NodeProperties::GetControlInput(node);
273 :
274 : // Check if the {constructor} is known at compile time.
275 : HeapObjectMatcher m(constructor);
276 1106 : if (!m.HasValue()) return NoChange();
277 :
278 : // Check if the {constructor} is a JSBoundFunction.
279 1106 : if (m.Value()->IsJSBoundFunction()) {
280 : // OrdinaryHasInstance on bound functions turns into a recursive
281 : // invocation of the instanceof operator again.
282 : // ES6 section 7.3.19 OrdinaryHasInstance (C, O) step 2.
283 : Handle<JSBoundFunction> function = Handle<JSBoundFunction>::cast(m.Value());
284 : Handle<JSReceiver> bound_target_function(function->bound_target_function());
285 8 : NodeProperties::ReplaceValueInput(node, object, 0);
286 : NodeProperties::ReplaceValueInput(
287 8 : node, jsgraph()->HeapConstant(bound_target_function), 1);
288 8 : NodeProperties::ChangeOp(node, javascript()->InstanceOf());
289 8 : Reduction const reduction = ReduceJSInstanceOf(node);
290 8 : return reduction.Changed() ? reduction : Changed(node);
291 : }
292 :
293 : // Check if the {constructor} is a JSFunction.
294 1098 : if (m.Value()->IsJSFunction()) {
295 : // Check if the {function} is a constructor and has an instance "prototype".
296 : Handle<JSFunction> function = Handle<JSFunction>::cast(m.Value());
297 3159 : if (function->IsConstructor() && function->has_instance_prototype() &&
298 1011 : function->prototype()->IsJSReceiver()) {
299 : // Ensure that the {function} has a valid initial map, so we can
300 : // depend on that for the prototype constant-folding below.
301 1000 : JSFunction::EnsureHasInitialMap(function);
302 :
303 : // Install a code dependency on the {function}s initial map.
304 : Handle<Map> initial_map(function->initial_map(), isolate());
305 : dependencies()->AssumeInitialMapCantChange(initial_map);
306 : Handle<JSReceiver> function_prototype =
307 : handle(JSReceiver::cast(initial_map->prototype()), isolate());
308 :
309 : // Check if we can constant-fold the prototype chain walk
310 : // for the given {object} and the {function_prototype}.
311 : InferHasInPrototypeChainResult result =
312 1000 : InferHasInPrototypeChain(object, effect, function_prototype);
313 1000 : if (result != kMayBeInPrototypeChain) {
314 24 : Node* value = jsgraph()->BooleanConstant(result == kIsInPrototypeChain);
315 1206 : ReplaceWithValue(node, value, effect, control);
316 : return Replace(value);
317 : }
318 :
319 988 : Node* prototype = jsgraph()->Constant(function_prototype);
320 :
321 988 : Node* check0 = graph()->NewNode(simplified()->ObjectIsSmi(), object);
322 : Node* branch0 = graph()->NewNode(common()->Branch(BranchHint::kFalse),
323 988 : check0, control);
324 :
325 988 : Node* if_true0 = graph()->NewNode(common()->IfTrue(), branch0);
326 : Node* etrue0 = effect;
327 988 : Node* vtrue0 = jsgraph()->FalseConstant();
328 :
329 988 : control = graph()->NewNode(common()->IfFalse(), branch0);
330 :
331 : // Loop through the {object}s prototype chain looking for the {prototype}.
332 : Node* loop = control =
333 988 : graph()->NewNode(common()->Loop(2), control, control);
334 : Node* eloop = effect =
335 988 : graph()->NewNode(common()->EffectPhi(2), effect, effect, loop);
336 : Node* vloop = object =
337 : graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2),
338 988 : object, object, loop);
339 :
340 : // Load the {object} map and instance type.
341 : Node* object_map = effect =
342 : graph()->NewNode(simplified()->LoadField(AccessBuilder::ForMap()),
343 2964 : object, effect, control);
344 : Node* object_instance_type = effect = graph()->NewNode(
345 : simplified()->LoadField(AccessBuilder::ForMapInstanceType()),
346 2964 : object_map, effect, control);
347 :
348 : // Check if the {object} is a special receiver, because for special
349 : // receivers, i.e. proxies or API objects that need access checks,
350 : // we have to use the %HasInPrototypeChain runtime function instead.
351 : Node* check1 = graph()->NewNode(
352 : simplified()->NumberLessThanOrEqual(), object_instance_type,
353 1976 : jsgraph()->Constant(LAST_SPECIAL_RECEIVER_TYPE));
354 : Node* branch1 = graph()->NewNode(common()->Branch(BranchHint::kFalse),
355 988 : check1, control);
356 :
357 988 : control = graph()->NewNode(common()->IfFalse(), branch1);
358 :
359 988 : Node* if_true1 = graph()->NewNode(common()->IfTrue(), branch1);
360 : Node* etrue1 = effect;
361 : Node* vtrue1;
362 :
363 : // Check if the {object} is not a receiver at all.
364 : Node* check10 =
365 : graph()->NewNode(simplified()->NumberLessThan(), object_instance_type,
366 1976 : jsgraph()->Constant(FIRST_JS_RECEIVER_TYPE));
367 : Node* branch10 = graph()->NewNode(common()->Branch(BranchHint::kTrue),
368 988 : check10, if_true1);
369 :
370 : // A primitive value cannot match the {prototype} we're looking for.
371 988 : if_true1 = graph()->NewNode(common()->IfTrue(), branch10);
372 988 : vtrue1 = jsgraph()->FalseConstant();
373 :
374 988 : Node* if_false1 = graph()->NewNode(common()->IfFalse(), branch10);
375 : Node* efalse1 = etrue1;
376 : Node* vfalse1;
377 : {
378 : // Slow path, need to call the %HasInPrototypeChain runtime function.
379 : vfalse1 = efalse1 = if_false1 = graph()->NewNode(
380 : javascript()->CallRuntime(Runtime::kHasInPrototypeChain), object,
381 988 : prototype, context, frame_state, efalse1, if_false1);
382 :
383 : // Replace any potential {IfException} uses of {node} to catch
384 : // exceptions from this %HasInPrototypeChain runtime call instead.
385 988 : Node* on_exception = nullptr;
386 988 : if (NodeProperties::IsExceptionalCall(node, &on_exception)) {
387 206 : NodeProperties::ReplaceControlInput(on_exception, vfalse1);
388 206 : NodeProperties::ReplaceEffectInput(on_exception, efalse1);
389 206 : if_false1 = graph()->NewNode(common()->IfSuccess(), vfalse1);
390 206 : Revisit(on_exception);
391 : }
392 : }
393 :
394 : // Load the {object} prototype.
395 : Node* object_prototype = effect = graph()->NewNode(
396 : simplified()->LoadField(AccessBuilder::ForMapPrototype()), object_map,
397 2964 : effect, control);
398 :
399 : // Check if we reached the end of {object}s prototype chain.
400 : Node* check2 =
401 : graph()->NewNode(simplified()->ReferenceEqual(), object_prototype,
402 1976 : jsgraph()->NullConstant());
403 988 : Node* branch2 = graph()->NewNode(common()->Branch(), check2, control);
404 :
405 988 : Node* if_true2 = graph()->NewNode(common()->IfTrue(), branch2);
406 : Node* etrue2 = effect;
407 988 : Node* vtrue2 = jsgraph()->FalseConstant();
408 :
409 988 : control = graph()->NewNode(common()->IfFalse(), branch2);
410 :
411 : // Check if we reached the {prototype}.
412 : Node* check3 = graph()->NewNode(simplified()->ReferenceEqual(),
413 988 : object_prototype, prototype);
414 988 : Node* branch3 = graph()->NewNode(common()->Branch(), check3, control);
415 :
416 988 : Node* if_true3 = graph()->NewNode(common()->IfTrue(), branch3);
417 : Node* etrue3 = effect;
418 988 : Node* vtrue3 = jsgraph()->TrueConstant();
419 :
420 988 : control = graph()->NewNode(common()->IfFalse(), branch3);
421 :
422 : // Close the loop.
423 988 : vloop->ReplaceInput(1, object_prototype);
424 988 : eloop->ReplaceInput(1, effect);
425 988 : loop->ReplaceInput(1, control);
426 :
427 : control = graph()->NewNode(common()->Merge(5), if_true0, if_true1,
428 988 : if_true2, if_true3, if_false1);
429 : effect = graph()->NewNode(common()->EffectPhi(5), etrue0, etrue1, etrue2,
430 988 : etrue3, efalse1, control);
431 :
432 : // Morph the {node} into an appropriate Phi.
433 : ReplaceWithValue(node, node, effect, control);
434 988 : node->ReplaceInput(0, vtrue0);
435 988 : node->ReplaceInput(1, vtrue1);
436 988 : node->ReplaceInput(2, vtrue2);
437 988 : node->ReplaceInput(3, vtrue3);
438 988 : node->ReplaceInput(4, vfalse1);
439 988 : node->ReplaceInput(5, control);
440 988 : node->TrimInputCount(6);
441 : NodeProperties::ChangeOp(
442 988 : node, common()->Phi(MachineRepresentation::kTagged, 5));
443 : return Changed(node);
444 : }
445 : }
446 :
447 : return NoChange();
448 : }
449 :
450 762684 : Reduction JSNativeContextSpecialization::ReduceJSLoadContext(Node* node) {
451 : DCHECK_EQ(IrOpcode::kJSLoadContext, node->opcode());
452 745205 : ContextAccess const& access = ContextAccessOf(node->op());
453 : // Specialize JSLoadContext(NATIVE_CONTEXT_INDEX) to the known native
454 : // context (if any), so we can constant-fold those fields, which is
455 : // safe, since the NATIVE_CONTEXT_INDEX slot is always immutable.
456 745205 : if (access.index() == Context::NATIVE_CONTEXT_INDEX) {
457 17479 : Node* value = jsgraph()->HeapConstant(native_context());
458 17479 : ReplaceWithValue(node, value);
459 : return Replace(value);
460 : }
461 : return NoChange();
462 : }
463 :
464 : namespace {
465 :
466 68106 : FieldAccess ForPropertyCellValue(MachineRepresentation representation,
467 : Type* type, MaybeHandle<Map> map,
468 : Handle<Name> name) {
469 : WriteBarrierKind kind = kFullWriteBarrier;
470 68106 : if (representation == MachineRepresentation::kTaggedSigned) {
471 : kind = kNoWriteBarrier;
472 38939 : } else if (representation == MachineRepresentation::kTaggedPointer) {
473 : kind = kPointerWriteBarrier;
474 : }
475 68106 : MachineType r = MachineType::TypeForRepresentation(representation);
476 : FieldAccess access = {
477 136212 : kTaggedBase, PropertyCell::kValueOffset, name, map, type, r, kind};
478 68106 : return access;
479 : }
480 :
481 : } // namespace
482 :
483 554868 : Reduction JSNativeContextSpecialization::ReduceGlobalAccess(
484 : Node* node, Node* receiver, Node* value, Handle<Name> name,
485 873709 : AccessMode access_mode, Node* index) {
486 554868 : Node* effect = NodeProperties::GetEffectInput(node);
487 554868 : Node* control = NodeProperties::GetControlInput(node);
488 :
489 : // Lookup on the global object. We only deal with own data properties
490 : // of the global object here (represented as PropertyCell).
491 554868 : LookupIterator it(global_object(), name, LookupIterator::OWN);
492 554868 : it.TryLookupCachedProperty();
493 554868 : if (it.state() != LookupIterator::DATA) return NoChange();
494 450444 : if (!it.GetHolder<JSObject>()->IsJSGlobalObject()) return NoChange();
495 450444 : Handle<PropertyCell> property_cell = it.GetPropertyCell();
496 : PropertyDetails property_details = property_cell->property_details();
497 : Handle<Object> property_cell_value(property_cell->value(), isolate());
498 : PropertyCellType property_cell_type = property_details.cell_type();
499 :
500 : // We have additional constraints for stores.
501 450444 : if (access_mode == AccessMode::kStore) {
502 21584 : if (property_details.IsReadOnly()) {
503 : // Don't even bother trying to lower stores to read-only data properties.
504 : return NoChange();
505 21513 : } else if (property_cell_type == PropertyCellType::kUndefined) {
506 : // There's no fast-path for dealing with undefined property cells.
507 : return NoChange();
508 21004 : } else if (property_cell_type == PropertyCellType::kConstantType) {
509 : // There's also no fast-path to store to a global cell which pretended
510 : // to be stable, but is no longer stable now.
511 11499 : if (property_cell_value->IsHeapObject() &&
512 : !Handle<HeapObject>::cast(property_cell_value)->map()->is_stable()) {
513 : return NoChange();
514 : }
515 : }
516 : }
517 :
518 : // Ensure that {index} matches the specified {name} (if {index} is given).
519 449864 : if (index != nullptr) {
520 : Node* check = graph()->NewNode(simplified()->ReferenceEqual(), index,
521 39 : jsgraph()->HeapConstant(name));
522 13 : effect = graph()->NewNode(simplified()->CheckIf(), check, effect, control);
523 : }
524 :
525 : // Check if we have a {receiver} to validate. If so, we need to check that
526 : // the {receiver} is actually the JSGlobalProxy for the native context that
527 : // we are specializing to.
528 449864 : if (receiver != nullptr) {
529 : Node* check = graph()->NewNode(simplified()->ReferenceEqual(), receiver,
530 639 : jsgraph()->HeapConstant(global_proxy()));
531 213 : effect = graph()->NewNode(simplified()->CheckIf(), check, effect, control);
532 : }
533 :
534 449864 : if (access_mode == AccessMode::kLoad) {
535 : // Load from non-configurable, read-only data property on the global
536 : // object can be constant-folded, even without deoptimization support.
537 666592 : if (!property_details.IsConfigurable() && property_details.IsReadOnly()) {
538 15190 : value = jsgraph()->Constant(property_cell_value);
539 : } else {
540 : // Record a code dependency on the cell if we can benefit from the
541 : // additional feedback, or the global property is configurable (i.e.
542 : // can be deleted or reconfigured to an accessor property).
543 413670 : if (property_details.cell_type() != PropertyCellType::kMutable ||
544 : property_details.IsConfigurable()) {
545 : dependencies()->AssumePropertyCell(property_cell);
546 : }
547 :
548 : // Load from constant/undefined global property can be constant-folded.
549 413670 : if (property_details.cell_type() == PropertyCellType::kConstant ||
550 : property_details.cell_type() == PropertyCellType::kUndefined) {
551 364149 : value = jsgraph()->Constant(property_cell_value);
552 : } else {
553 : // Load from constant type cell can benefit from type feedback.
554 : MaybeHandle<Map> map;
555 : Type* property_cell_value_type = Type::NonInternal();
556 : MachineRepresentation representation = MachineRepresentation::kTagged;
557 49521 : if (property_details.cell_type() == PropertyCellType::kConstantType) {
558 : // Compute proper type based on the current value in the cell.
559 27160 : if (property_cell_value->IsSmi()) {
560 : property_cell_value_type = Type::SignedSmall();
561 : representation = MachineRepresentation::kTaggedSigned;
562 8348 : } else if (property_cell_value->IsNumber()) {
563 : property_cell_value_type = Type::Number();
564 : representation = MachineRepresentation::kTaggedPointer;
565 : } else {
566 : Handle<Map> property_cell_value_map(
567 : Handle<HeapObject>::cast(property_cell_value)->map(),
568 : isolate());
569 : property_cell_value_type = Type::For(property_cell_value_map);
570 : representation = MachineRepresentation::kTaggedPointer;
571 :
572 : // We can only use the property cell value map for map check
573 : // elimination if it's stable, i.e. the HeapObject wasn't
574 : // mutated without the cell state being updated.
575 6900 : if (property_cell_value_map->is_stable()) {
576 6828 : dependencies()->AssumeMapStable(property_cell_value_map);
577 : map = property_cell_value_map;
578 : }
579 : }
580 : }
581 : value = effect = graph()->NewNode(
582 : simplified()->LoadField(ForPropertyCellValue(
583 : representation, property_cell_value_type, map, name)),
584 148563 : jsgraph()->HeapConstant(property_cell), effect, control);
585 : }
586 : }
587 : } else {
588 : DCHECK_EQ(AccessMode::kStore, access_mode);
589 : DCHECK(!property_details.IsReadOnly());
590 21004 : switch (property_details.cell_type()) {
591 : case PropertyCellType::kUndefined: {
592 0 : UNREACHABLE();
593 : break;
594 : }
595 : case PropertyCellType::kConstant: {
596 : // Record a code dependency on the cell, and just deoptimize if the new
597 : // value doesn't match the previous value stored inside the cell.
598 : dependencies()->AssumePropertyCell(property_cell);
599 : Node* check =
600 : graph()->NewNode(simplified()->ReferenceEqual(), value,
601 4838 : jsgraph()->Constant(property_cell_value));
602 : effect =
603 2419 : graph()->NewNode(simplified()->CheckIf(), check, effect, control);
604 2419 : break;
605 : }
606 : case PropertyCellType::kConstantType: {
607 : // Record a code dependency on the cell, and just deoptimize if the new
608 : // values' type doesn't match the type of the previous value in the
609 : // cell.
610 : dependencies()->AssumePropertyCell(property_cell);
611 : Type* property_cell_value_type;
612 : MachineRepresentation representation = MachineRepresentation::kTagged;
613 10927 : if (property_cell_value->IsHeapObject()) {
614 : // We cannot do anything if the {property_cell_value}s map is no
615 : // longer stable.
616 : Handle<Map> property_cell_value_map(
617 : Handle<HeapObject>::cast(property_cell_value)->map(), isolate());
618 : DCHECK(property_cell_value_map->is_stable());
619 572 : dependencies()->AssumeMapStable(property_cell_value_map);
620 :
621 : // Check that the {value} is a HeapObject.
622 : value = effect = graph()->NewNode(simplified()->CheckHeapObject(),
623 572 : value, effect, control);
624 :
625 : // Check {value} map agains the {property_cell} map.
626 : effect =
627 : graph()->NewNode(simplified()->CheckMaps(
628 : CheckMapsFlag::kNone,
629 : ZoneHandleSet<Map>(property_cell_value_map)),
630 1144 : value, effect, control);
631 : property_cell_value_type = Type::OtherInternal();
632 : representation = MachineRepresentation::kTaggedPointer;
633 : } else {
634 : // Check that the {value} is a Smi.
635 : value = effect = graph()->NewNode(simplified()->CheckSmi(), value,
636 10355 : effect, control);
637 : property_cell_value_type = Type::SignedSmall();
638 : representation = MachineRepresentation::kTaggedSigned;
639 : }
640 : effect = graph()->NewNode(simplified()->StoreField(ForPropertyCellValue(
641 : representation, property_cell_value_type,
642 : MaybeHandle<Map>(), name)),
643 : jsgraph()->HeapConstant(property_cell), value,
644 43708 : effect, control);
645 10927 : break;
646 : }
647 : case PropertyCellType::kMutable: {
648 : // Record a code dependency on the cell, and just deoptimize if the
649 : // property ever becomes read-only.
650 : dependencies()->AssumePropertyCell(property_cell);
651 : effect = graph()->NewNode(
652 : simplified()->StoreField(ForPropertyCellValue(
653 : MachineRepresentation::kTagged, Type::NonInternal(),
654 : MaybeHandle<Map>(), name)),
655 30632 : jsgraph()->HeapConstant(property_cell), value, effect, control);
656 7658 : break;
657 : }
658 : }
659 : }
660 :
661 449864 : ReplaceWithValue(node, value, effect, control);
662 : return Replace(value);
663 : }
664 :
665 530455 : Reduction JSNativeContextSpecialization::ReduceJSLoadGlobal(Node* node) {
666 : DCHECK_EQ(IrOpcode::kJSLoadGlobal, node->opcode());
667 523986 : Handle<Name> name = LoadGlobalParametersOf(node->op()).name();
668 523986 : Node* effect = NodeProperties::GetEffectInput(node);
669 :
670 : // Try to lookup the name on the script context table first (lexical scoping).
671 : ScriptContextTableLookupResult result;
672 523986 : if (LookupInScriptContextTable(name, &result)) {
673 13146 : if (result.context->is_the_hole(isolate(), result.index)) return NoChange();
674 6469 : Node* context = jsgraph()->HeapConstant(result.context);
675 : Node* value = effect = graph()->NewNode(
676 : javascript()->LoadContext(0, result.index, result.immutable), context,
677 12938 : effect);
678 6469 : ReplaceWithValue(node, value, effect);
679 : return Replace(value);
680 : }
681 :
682 : // Lookup the {name} on the global object instead.
683 517413 : return ReduceGlobalAccess(node, nullptr, nullptr, name, AccessMode::kLoad);
684 : }
685 :
686 36690 : Reduction JSNativeContextSpecialization::ReduceJSStoreGlobal(Node* node) {
687 : DCHECK_EQ(IrOpcode::kJSStoreGlobal, node->opcode());
688 36670 : Handle<Name> name = StoreGlobalParametersOf(node->op()).name();
689 36670 : Node* value = NodeProperties::GetValueInput(node, 0);
690 36670 : Node* effect = NodeProperties::GetEffectInput(node);
691 36670 : Node* control = NodeProperties::GetControlInput(node);
692 :
693 : // Try to lookup the name on the script context table first (lexical scoping).
694 : ScriptContextTableLookupResult result;
695 36670 : if (LookupInScriptContextTable(name, &result)) {
696 50 : if (result.context->is_the_hole(isolate(), result.index)) return NoChange();
697 24 : if (result.immutable) return NoChange();
698 20 : Node* context = jsgraph()->HeapConstant(result.context);
699 : effect = graph()->NewNode(javascript()->StoreContext(0, result.index),
700 40 : value, context, effect, control);
701 20 : ReplaceWithValue(node, value, effect, control);
702 : return Replace(value);
703 : }
704 :
705 : // Lookup the {name} on the global object instead.
706 36645 : return ReduceGlobalAccess(node, nullptr, value, name, AccessMode::kStore);
707 : }
708 :
709 88417 : Reduction JSNativeContextSpecialization::ReduceNamedAccess(
710 88417 : Node* node, Node* value, MapHandleList const& receiver_maps,
711 : Handle<Name> name, AccessMode access_mode, LanguageMode language_mode,
712 185881 : Node* index) {
713 : DCHECK(node->opcode() == IrOpcode::kJSLoadNamed ||
714 : node->opcode() == IrOpcode::kJSStoreNamed ||
715 : node->opcode() == IrOpcode::kJSLoadProperty ||
716 : node->opcode() == IrOpcode::kJSStoreProperty ||
717 : node->opcode() == IrOpcode::kJSStoreNamedOwn);
718 88417 : Node* receiver = NodeProperties::GetValueInput(node, 0);
719 88417 : Node* context = NodeProperties::GetContextInput(node);
720 88417 : Node* frame_state = NodeProperties::GetFrameStateInput(node);
721 88417 : Node* effect = NodeProperties::GetEffectInput(node);
722 88417 : Node* control = NodeProperties::GetControlInput(node);
723 :
724 : // Check if we have an access o.x or o.x=v where o is the current
725 : // native contexts' global proxy, and turn that into a direct access
726 : // to the current native contexts' global object instead.
727 88417 : if (receiver_maps.length() == 1) {
728 84636 : Handle<Map> receiver_map = receiver_maps.first();
729 84636 : if (receiver_map->IsJSGlobalProxyMap()) {
730 233 : Object* maybe_constructor = receiver_map->GetConstructor();
731 : // Detached global proxies have |null| as their constructor.
732 466 : if (maybe_constructor->IsJSFunction() &&
733 : JSFunction::cast(maybe_constructor)->native_context() ==
734 : *native_context()) {
735 : return ReduceGlobalAccess(node, receiver, value, name, access_mode,
736 233 : index);
737 : }
738 : }
739 : }
740 :
741 : // Compute property access infos for the receiver maps.
742 : AccessInfoFactory access_info_factory(dependencies(), native_context(),
743 176368 : graph()->zone());
744 : ZoneVector<PropertyAccessInfo> access_infos(zone());
745 88184 : if (!access_info_factory.ComputePropertyAccessInfos(
746 88184 : receiver_maps, name, access_mode, &access_infos)) {
747 : return NoChange();
748 : }
749 :
750 : // TODO(turbofan): Add support for inlining into try blocks.
751 86835 : bool is_exceptional = NodeProperties::IsExceptionalCall(node);
752 262897 : for (const auto& access_info : access_infos) {
753 89323 : if (access_info.IsAccessorConstant()) {
754 : // Accessor in try-blocks are not supported yet.
755 2478 : if (is_exceptional || !(flags() & kAccessorInliningEnabled)) {
756 : return NoChange();
757 : }
758 : }
759 : }
760 :
761 : // Nothing to do if we have no non-deprecated maps.
762 86739 : if (access_infos.empty()) {
763 : return ReduceSoftDeoptimize(
764 11 : node, DeoptimizeReason::kInsufficientTypeFeedbackForGenericNamedAccess);
765 : }
766 :
767 : // Ensure that {index} matches the specified {name} (if {index} is given).
768 86728 : if (index != nullptr) {
769 : Node* check = graph()->NewNode(simplified()->ReferenceEqual(), index,
770 594 : jsgraph()->HeapConstant(name));
771 594 : effect = graph()->NewNode(simplified()->CheckIf(), check, effect, control);
772 : }
773 :
774 : // Check for the monomorphic cases.
775 173456 : if (access_infos.size() == 1) {
776 84670 : PropertyAccessInfo access_info = access_infos.front();
777 84670 : if (HasOnlyStringMaps(access_info.receiver_maps())) {
778 : // Monormorphic string access (ignoring the fact that there are multiple
779 : // String maps).
780 : receiver = effect = graph()->NewNode(simplified()->CheckString(),
781 6768 : receiver, effect, control);
782 82414 : } else if (HasOnlyNumberMaps(access_info.receiver_maps())) {
783 : // Monomorphic number access (we also deal with Smis here).
784 : receiver = effect = graph()->NewNode(simplified()->CheckNumber(),
785 738 : receiver, effect, control);
786 : } else {
787 : // Monomorphic property access.
788 82168 : receiver = BuildCheckHeapObject(receiver, &effect, control);
789 : effect = BuildCheckMaps(receiver, effect, control,
790 82168 : access_info.receiver_maps());
791 : }
792 :
793 : // Generate the actual property access.
794 : ValueEffectControl continuation = BuildPropertyAccess(
795 : receiver, value, context, frame_state, effect, control, name,
796 84670 : access_info, access_mode, language_mode);
797 84670 : value = continuation.value();
798 84670 : effect = continuation.effect();
799 84670 : control = continuation.control();
800 : } else {
801 : // The final states for every polymorphic branch. We join them with
802 : // Merge+Phi+EffectPhi at the bottom.
803 : ZoneVector<Node*> values(zone());
804 : ZoneVector<Node*> effects(zone());
805 : ZoneVector<Node*> controls(zone());
806 :
807 : // Check if {receiver} may be a number.
808 : bool receiverissmi_possible = false;
809 8485 : for (PropertyAccessInfo const& access_info : access_infos) {
810 4449 : if (HasNumberMaps(access_info.receiver_maps())) {
811 : receiverissmi_possible = true;
812 : break;
813 : }
814 : }
815 :
816 : // Ensure that {receiver} is a heap object.
817 2058 : Node* receiverissmi_control = nullptr;
818 2058 : Node* receiverissmi_effect = effect;
819 2058 : if (receiverissmi_possible) {
820 80 : Node* check = graph()->NewNode(simplified()->ObjectIsSmi(), receiver);
821 160 : Node* branch = graph()->NewNode(common()->Branch(), check, control);
822 160 : control = graph()->NewNode(common()->IfFalse(), branch);
823 160 : receiverissmi_control = graph()->NewNode(common()->IfTrue(), branch);
824 80 : receiverissmi_effect = effect;
825 : } else {
826 1978 : receiver = BuildCheckHeapObject(receiver, &effect, control);
827 : }
828 :
829 : // Load the {receiver} map. The resulting effect is the dominating effect
830 : // for all (polymorphic) branches.
831 : Node* receiver_map = effect =
832 : graph()->NewNode(simplified()->LoadField(AccessBuilder::ForMap()),
833 6174 : receiver, effect, control);
834 :
835 : // Generate code for the various different property access patterns.
836 2058 : Node* fallthrough_control = control;
837 13230 : for (size_t j = 0; j < access_infos.size(); ++j) {
838 : PropertyAccessInfo const& access_info = access_infos[j];
839 : Node* this_value = value;
840 : Node* this_receiver = receiver;
841 4557 : Node* this_effect = effect;
842 4557 : Node* this_control = fallthrough_control;
843 :
844 : // Perform map check on {receiver}.
845 4557 : MapList const& receiver_maps = access_info.receiver_maps();
846 : {
847 : // Emit a (sequence of) map checks for other {receiver}s.
848 : ZoneVector<Node*> this_controls(zone());
849 : ZoneVector<Node*> this_effects(zone());
850 4557 : if (j == access_infos.size() - 1) {
851 : // Last map check on the fallthrough control path, do a
852 : // conditional eager deoptimization exit here.
853 : this_effect = BuildCheckMaps(receiver, this_effect, this_control,
854 2058 : receiver_maps);
855 2058 : this_effects.push_back(this_effect);
856 2058 : this_controls.push_back(fallthrough_control);
857 2058 : fallthrough_control = nullptr;
858 : } else {
859 7698 : for (auto map : receiver_maps) {
860 : Node* check =
861 : graph()->NewNode(simplified()->ReferenceEqual(), receiver_map,
862 8100 : jsgraph()->Constant(map));
863 : Node* branch = graph()->NewNode(common()->Branch(), check,
864 5400 : fallthrough_control);
865 5400 : fallthrough_control = graph()->NewNode(common()->IfFalse(), branch);
866 : this_controls.push_back(
867 8100 : graph()->NewNode(common()->IfTrue(), branch));
868 2700 : this_effects.push_back(this_effect);
869 : }
870 : }
871 :
872 : // The Number case requires special treatment to also deal with Smis.
873 4557 : if (HasNumberMaps(receiver_maps)) {
874 : // Join this check with the "receiver is smi" check above.
875 : DCHECK_NOT_NULL(receiverissmi_effect);
876 : DCHECK_NOT_NULL(receiverissmi_control);
877 80 : this_effects.push_back(receiverissmi_effect);
878 80 : this_controls.push_back(receiverissmi_control);
879 80 : receiverissmi_effect = receiverissmi_control = nullptr;
880 : }
881 :
882 : // Create single chokepoint for the control.
883 9114 : int const this_control_count = static_cast<int>(this_controls.size());
884 4557 : if (this_control_count == 1) {
885 4276 : this_control = this_controls.front();
886 4276 : this_effect = this_effects.front();
887 : } else {
888 : this_control =
889 : graph()->NewNode(common()->Merge(this_control_count),
890 562 : this_control_count, &this_controls.front());
891 281 : this_effects.push_back(this_control);
892 : this_effect =
893 : graph()->NewNode(common()->EffectPhi(this_control_count),
894 843 : this_control_count + 1, &this_effects.front());
895 : }
896 : }
897 :
898 : // Generate the actual property access.
899 : ValueEffectControl continuation = BuildPropertyAccess(
900 : this_receiver, this_value, context, frame_state, this_effect,
901 4557 : this_control, name, access_info, access_mode, language_mode);
902 9114 : values.push_back(continuation.value());
903 9114 : effects.push_back(continuation.effect());
904 9114 : controls.push_back(continuation.control());
905 : }
906 :
907 : DCHECK_NULL(fallthrough_control);
908 :
909 : // Generate the final merge point for all (polymorphic) branches.
910 4116 : int const control_count = static_cast<int>(controls.size());
911 2058 : if (control_count == 0) {
912 0 : value = effect = control = jsgraph()->Dead();
913 2058 : } else if (control_count == 1) {
914 0 : value = values.front();
915 0 : effect = effects.front();
916 0 : control = controls.front();
917 : } else {
918 : control = graph()->NewNode(common()->Merge(control_count), control_count,
919 4116 : &controls.front());
920 2058 : values.push_back(control);
921 : value = graph()->NewNode(
922 : common()->Phi(MachineRepresentation::kTagged, control_count),
923 6174 : control_count + 1, &values.front());
924 2058 : effects.push_back(control);
925 : effect = graph()->NewNode(common()->EffectPhi(control_count),
926 4116 : control_count + 1, &effects.front());
927 : }
928 : }
929 86728 : ReplaceWithValue(node, value, effect, control);
930 : return Replace(value);
931 : }
932 :
933 551039 : Reduction JSNativeContextSpecialization::ReduceNamedAccessFromNexus(
934 : Node* node, Node* value, FeedbackNexus const& nexus, Handle<Name> name,
935 : AccessMode access_mode, LanguageMode language_mode) {
936 : DCHECK(node->opcode() == IrOpcode::kJSLoadNamed ||
937 : node->opcode() == IrOpcode::kJSStoreNamed ||
938 : node->opcode() == IrOpcode::kJSStoreNamedOwn);
939 551039 : Node* const receiver = NodeProperties::GetValueInput(node, 0);
940 551040 : Node* const effect = NodeProperties::GetEffectInput(node);
941 :
942 : // Check if we are accessing the current native contexts' global proxy.
943 : HeapObjectMatcher m(receiver);
944 673007 : if (m.HasValue() && m.Value().is_identical_to(global_proxy())) {
945 : // Optimize accesses to the current native contexts' global proxy.
946 577 : return ReduceGlobalAccess(node, nullptr, value, name, access_mode);
947 : }
948 :
949 : // Check if the {nexus} reports type feedback for the IC.
950 550463 : if (nexus.IsUninitialized()) {
951 438941 : if (flags() & kBailoutOnUninitialized) {
952 : return ReduceSoftDeoptimize(
953 : node,
954 462 : DeoptimizeReason::kInsufficientTypeFeedbackForGenericNamedAccess);
955 : }
956 : return NoChange();
957 : }
958 :
959 : // Extract receiver maps from the IC using the {nexus}.
960 : MapHandleList receiver_maps;
961 111522 : if (!ExtractReceiverMaps(receiver, effect, nexus, &receiver_maps)) {
962 : return NoChange();
963 87824 : } else if (receiver_maps.length() == 0) {
964 0 : if (flags() & kBailoutOnUninitialized) {
965 : return ReduceSoftDeoptimize(
966 : node,
967 0 : DeoptimizeReason::kInsufficientTypeFeedbackForGenericNamedAccess);
968 : }
969 : return NoChange();
970 : }
971 :
972 : // Try to lower the named access based on the {receiver_maps}.
973 : return ReduceNamedAccess(node, value, receiver_maps, name, access_mode,
974 87824 : language_mode);
975 : }
976 :
977 914542 : Reduction JSNativeContextSpecialization::ReduceJSLoadNamed(Node* node) {
978 : DCHECK_EQ(IrOpcode::kJSLoadNamed, node->opcode());
979 904063 : NamedAccess const& p = NamedAccessOf(node->op());
980 453799 : Node* const receiver = NodeProperties::GetValueInput(node, 0);
981 453799 : Node* const value = jsgraph()->Dead();
982 :
983 : // Check if we have a constant receiver.
984 : HeapObjectMatcher m(receiver);
985 453799 : if (m.HasValue()) {
986 139397 : if (m.Value()->IsJSFunction() &&
987 : p.name().is_identical_to(factory()->prototype_string())) {
988 : // Optimize "prototype" property of functions.
989 : Handle<JSFunction> function = Handle<JSFunction>::cast(m.Value());
990 3414 : if (function->IsConstructor()) {
991 : // We need to add a code dependency on the initial map of the
992 : // {function} in order to be notified about changes to the
993 : // "prototype" of {function}.
994 3409 : JSFunction::EnsureHasInitialMap(function);
995 : Handle<Map> initial_map(function->initial_map(), isolate());
996 : dependencies()->AssumeInitialMapCantChange(initial_map);
997 3409 : Handle<Object> prototype(function->prototype(), isolate());
998 3409 : Node* value = jsgraph()->Constant(prototype);
999 3535 : ReplaceWithValue(node, value);
1000 : return Replace(value);
1001 : }
1002 122778 : } else if (m.Value()->IsString() &&
1003 : p.name().is_identical_to(factory()->length_string())) {
1004 : // Constant-fold "length" property on constant strings.
1005 : Handle<String> string = Handle<String>::cast(m.Value());
1006 126 : Node* value = jsgraph()->Constant(string->length());
1007 : ReplaceWithValue(node, value);
1008 : return Replace(value);
1009 : }
1010 : }
1011 :
1012 : // Extract receiver maps from the LOAD_IC using the LoadICNexus.
1013 450264 : if (!p.feedback().IsValid()) return NoChange();
1014 : LoadICNexus nexus(p.feedback().vector(), p.feedback().slot());
1015 :
1016 : // Try to lower the named access based on the {receiver_maps}.
1017 : return ReduceNamedAccessFromNexus(node, value, nexus, p.name(),
1018 450264 : AccessMode::kLoad, p.language_mode());
1019 : }
1020 :
1021 :
1022 64462 : Reduction JSNativeContextSpecialization::ReduceJSStoreNamed(Node* node) {
1023 : DCHECK_EQ(IrOpcode::kJSStoreNamed, node->opcode());
1024 128924 : NamedAccess const& p = NamedAccessOf(node->op());
1025 64462 : Node* const value = NodeProperties::GetValueInput(node, 1);
1026 :
1027 : // Extract receiver maps from the STORE_IC using the StoreICNexus.
1028 64462 : if (!p.feedback().IsValid()) return NoChange();
1029 : StoreICNexus nexus(p.feedback().vector(), p.feedback().slot());
1030 :
1031 : // Try to lower the named access based on the {receiver_maps}.
1032 : return ReduceNamedAccessFromNexus(node, value, nexus, p.name(),
1033 64462 : AccessMode::kStore, p.language_mode());
1034 : }
1035 :
1036 36313 : Reduction JSNativeContextSpecialization::ReduceJSStoreNamedOwn(Node* node) {
1037 : DCHECK_EQ(IrOpcode::kJSStoreNamedOwn, node->opcode());
1038 36313 : StoreNamedOwnParameters const& p = StoreNamedOwnParametersOf(node->op());
1039 36313 : Node* const value = NodeProperties::GetValueInput(node, 1);
1040 :
1041 : // Extract receiver maps from the IC using the StoreOwnICNexus.
1042 36313 : if (!p.feedback().IsValid()) return NoChange();
1043 : StoreOwnICNexus nexus(p.feedback().vector(), p.feedback().slot());
1044 :
1045 : // Try to lower the creation of a named property based on the {receiver_maps}.
1046 : return ReduceNamedAccessFromNexus(node, value, nexus, p.name(),
1047 36313 : AccessMode::kStoreInLiteral, STRICT);
1048 : }
1049 :
1050 26477 : Reduction JSNativeContextSpecialization::ReduceElementAccess(
1051 : Node* node, Node* index, Node* value, MapHandleList const& receiver_maps,
1052 : AccessMode access_mode, LanguageMode language_mode,
1053 71045 : KeyedAccessStoreMode store_mode) {
1054 : DCHECK(node->opcode() == IrOpcode::kJSLoadProperty ||
1055 : node->opcode() == IrOpcode::kJSStoreProperty);
1056 26477 : Node* receiver = NodeProperties::GetValueInput(node, 0);
1057 26477 : Node* effect = NodeProperties::GetEffectInput(node);
1058 26477 : Node* control = NodeProperties::GetControlInput(node);
1059 26477 : Node* frame_state = NodeProperties::FindFrameStateBefore(node);
1060 :
1061 : // Check for keyed access to strings.
1062 26477 : if (HasOnlyStringMaps(receiver_maps)) {
1063 : // Strings are immutable in JavaScript.
1064 62 : if (access_mode == AccessMode::kStore) return NoChange();
1065 :
1066 : // Ensure that the {receiver} is actually a String.
1067 : receiver = effect = graph()->NewNode(simplified()->CheckString(), receiver,
1068 186 : effect, control);
1069 :
1070 : // Determine the {receiver} length.
1071 : Node* length = effect = graph()->NewNode(
1072 : simplified()->LoadField(AccessBuilder::ForStringLength()), receiver,
1073 186 : effect, control);
1074 :
1075 : // Ensure that {index} is less than {receiver} length.
1076 : index = effect = graph()->NewNode(simplified()->CheckBounds(), index,
1077 186 : length, effect, control);
1078 :
1079 : // Return the character from the {receiver} as single character string.
1080 : value = graph()->NewNode(simplified()->StringCharAt(), receiver, index,
1081 124 : control);
1082 : } else {
1083 : // Retrieve the native context from the given {node}.
1084 : // Compute element access infos for the receiver maps.
1085 : AccessInfoFactory access_info_factory(dependencies(), native_context(),
1086 52830 : graph()->zone());
1087 : ZoneVector<ElementAccessInfo> access_infos(zone());
1088 26415 : if (!access_info_factory.ComputeElementAccessInfos(
1089 26415 : receiver_maps, access_mode, &access_infos)) {
1090 : return NoChange();
1091 : }
1092 :
1093 : // Nothing to do if we have no non-deprecated maps.
1094 25720 : if (access_infos.empty()) {
1095 : return ReduceSoftDeoptimize(
1096 : node,
1097 0 : DeoptimizeReason::kInsufficientTypeFeedbackForGenericKeyedAccess);
1098 : }
1099 :
1100 : // For holey stores or growing stores, we need to check that the prototype
1101 : // chain contains no setters for elements, and we need to guard those checks
1102 : // via code dependencies on the relevant prototype maps.
1103 25720 : if (access_mode == AccessMode::kStore) {
1104 : // TODO(turbofan): We could have a fast path here, that checks for the
1105 : // common case of Array or Object prototype only and therefore avoids
1106 : // the zone allocation of this vector.
1107 : ZoneVector<Handle<Map>> prototype_maps(zone());
1108 31436 : for (ElementAccessInfo const& access_info : access_infos) {
1109 33188 : for (Handle<Map> receiver_map : access_info.receiver_maps()) {
1110 : // If the {receiver_map} has a prototype and it's elements backing
1111 : // store is either holey, or we have a potentially growing store,
1112 : // then we need to check that all prototypes have stable maps with
1113 : // fast elements (and we need to guard against changes to that below).
1114 19600 : if (IsHoleyElementsKind(receiver_map->elements_kind()) ||
1115 : IsGrowStoreMode(store_mode)) {
1116 : // Make sure all prototypes are stable and have fast elements.
1117 2957 : for (Handle<Map> map = receiver_map;;) {
1118 : Handle<Object> map_prototype(map->prototype(), isolate());
1119 7602 : if (map_prototype->IsNull(isolate())) break;
1120 4679 : if (!map_prototype->IsJSObject()) return NoChange();
1121 : map = handle(Handle<JSObject>::cast(map_prototype)->map(),
1122 4679 : isolate());
1123 4679 : if (!map->is_stable()) return NoChange();
1124 4646 : if (!IsFastElementsKind(map->elements_kind())) return NoChange();
1125 4645 : prototype_maps.push_back(map);
1126 4645 : }
1127 : }
1128 : }
1129 : }
1130 :
1131 : // Install dependencies on the relevant prototype maps.
1132 24985 : for (Handle<Map> prototype_map : prototype_maps) {
1133 4637 : dependencies()->AssumeMapStable(prototype_map);
1134 : }
1135 : }
1136 :
1137 : // Ensure that {receiver} is a heap object.
1138 25686 : receiver = BuildCheckHeapObject(receiver, &effect, control);
1139 :
1140 : // Check for the monomorphic case.
1141 51372 : if (access_infos.size() == 1) {
1142 24634 : ElementAccessInfo access_info = access_infos.front();
1143 :
1144 : // Perform possible elements kind transitions.
1145 49680 : for (auto transition : access_info.transitions()) {
1146 : Handle<Map> const transition_source = transition.first;
1147 : Handle<Map> const transition_target = transition.second;
1148 : effect = graph()->NewNode(
1149 : simplified()->TransitionElementsKind(ElementsTransition(
1150 : IsSimpleMapChangeTransition(transition_source->elements_kind(),
1151 : transition_target->elements_kind())
1152 : ? ElementsTransition::kFastTransition
1153 : : ElementsTransition::kSlowTransition,
1154 : transition_source, transition_target)),
1155 1648 : receiver, effect, control);
1156 : }
1157 :
1158 : // TODO(turbofan): The effect/control linearization will not find a
1159 : // FrameState after the StoreField or Call that is generated for the
1160 : // elements kind transition above. This is because those operators
1161 : // don't have the kNoWrite flag on it, even though they are not
1162 : // observable by JavaScript.
1163 : effect = graph()->NewNode(common()->Checkpoint(), frame_state, effect,
1164 73902 : control);
1165 :
1166 : // Perform map check on the {receiver}.
1167 : effect = BuildCheckMaps(receiver, effect, control,
1168 24634 : access_info.receiver_maps());
1169 :
1170 : // Access the actual element.
1171 : ValueEffectControl continuation =
1172 : BuildElementAccess(receiver, index, value, effect, control,
1173 24634 : access_info, access_mode, store_mode);
1174 24634 : value = continuation.value();
1175 24634 : effect = continuation.effect();
1176 24634 : control = continuation.control();
1177 : } else {
1178 : // The final states for every polymorphic branch. We join them with
1179 : // Merge+Phi+EffectPhi at the bottom.
1180 : ZoneVector<Node*> values(zone());
1181 : ZoneVector<Node*> effects(zone());
1182 : ZoneVector<Node*> controls(zone());
1183 :
1184 : // Generate code for the various different element access patterns.
1185 1052 : Node* fallthrough_control = control;
1186 6526 : for (size_t j = 0; j < access_infos.size(); ++j) {
1187 : ElementAccessInfo const& access_info = access_infos[j];
1188 : Node* this_receiver = receiver;
1189 : Node* this_value = value;
1190 : Node* this_index = index;
1191 2211 : Node* this_effect = effect;
1192 2211 : Node* this_control = fallthrough_control;
1193 :
1194 : // Perform possible elements kind transitions.
1195 4443 : for (auto transition : access_info.transitions()) {
1196 : Handle<Map> const transition_source = transition.first;
1197 : Handle<Map> const transition_target = transition.second;
1198 : this_effect = graph()->NewNode(
1199 : simplified()->TransitionElementsKind(
1200 : ElementsTransition(IsSimpleMapChangeTransition(
1201 : transition_source->elements_kind(),
1202 : transition_target->elements_kind())
1203 : ? ElementsTransition::kFastTransition
1204 : : ElementsTransition::kSlowTransition,
1205 : transition_source, transition_target)),
1206 84 : receiver, this_effect, this_control);
1207 : }
1208 :
1209 : // Load the {receiver} map.
1210 : Node* receiver_map = this_effect =
1211 : graph()->NewNode(simplified()->LoadField(AccessBuilder::ForMap()),
1212 6633 : receiver, this_effect, this_control);
1213 :
1214 : // Perform map check(s) on {receiver}.
1215 2211 : MapList const& receiver_maps = access_info.receiver_maps();
1216 4422 : if (j == access_infos.size() - 1) {
1217 : // Last map check on the fallthrough control path, do a
1218 : // conditional eager deoptimization exit here.
1219 : this_effect = BuildCheckMaps(receiver, this_effect, this_control,
1220 1052 : receiver_maps);
1221 : fallthrough_control = nullptr;
1222 : } else {
1223 : ZoneVector<Node*> this_controls(zone());
1224 : ZoneVector<Node*> this_effects(zone());
1225 3477 : for (Handle<Map> map : receiver_maps) {
1226 : Node* check =
1227 : graph()->NewNode(simplified()->ReferenceEqual(), receiver_map,
1228 3477 : jsgraph()->Constant(map));
1229 : Node* branch = graph()->NewNode(common()->Branch(), check,
1230 1159 : fallthrough_control);
1231 : this_controls.push_back(
1232 3477 : graph()->NewNode(common()->IfTrue(), branch));
1233 1159 : this_effects.push_back(this_effect);
1234 1159 : fallthrough_control = graph()->NewNode(common()->IfFalse(), branch);
1235 : }
1236 :
1237 : // Create single chokepoint for the control.
1238 2318 : int const this_control_count = static_cast<int>(this_controls.size());
1239 1159 : if (this_control_count == 1) {
1240 1159 : this_control = this_controls.front();
1241 1159 : this_effect = this_effects.front();
1242 : } else {
1243 : this_control =
1244 : graph()->NewNode(common()->Merge(this_control_count),
1245 0 : this_control_count, &this_controls.front());
1246 0 : this_effects.push_back(this_control);
1247 : this_effect =
1248 : graph()->NewNode(common()->EffectPhi(this_control_count),
1249 0 : this_control_count + 1, &this_effects.front());
1250 : }
1251 : }
1252 :
1253 : // Access the actual element.
1254 : ValueEffectControl continuation = BuildElementAccess(
1255 : this_receiver, this_index, this_value, this_effect, this_control,
1256 2211 : access_info, access_mode, store_mode);
1257 4422 : values.push_back(continuation.value());
1258 4422 : effects.push_back(continuation.effect());
1259 4422 : controls.push_back(continuation.control());
1260 : }
1261 :
1262 : DCHECK_NULL(fallthrough_control);
1263 :
1264 : // Generate the final merge point for all (polymorphic) branches.
1265 2104 : int const control_count = static_cast<int>(controls.size());
1266 1052 : if (control_count == 0) {
1267 0 : value = effect = control = jsgraph()->Dead();
1268 1052 : } else if (control_count == 1) {
1269 0 : value = values.front();
1270 0 : effect = effects.front();
1271 0 : control = controls.front();
1272 : } else {
1273 : control = graph()->NewNode(common()->Merge(control_count),
1274 2104 : control_count, &controls.front());
1275 1052 : values.push_back(control);
1276 : value = graph()->NewNode(
1277 : common()->Phi(MachineRepresentation::kTagged, control_count),
1278 3156 : control_count + 1, &values.front());
1279 1052 : effects.push_back(control);
1280 : effect = graph()->NewNode(common()->EffectPhi(control_count),
1281 2104 : control_count + 1, &effects.front());
1282 : }
1283 : }
1284 : }
1285 :
1286 25748 : ReplaceWithValue(node, value, effect, control);
1287 : return Replace(value);
1288 : }
1289 :
1290 : template <typename KeyedICNexus>
1291 120260 : Reduction JSNativeContextSpecialization::ReduceKeyedAccess(
1292 : Node* node, Node* index, Node* value, KeyedICNexus const& nexus,
1293 : AccessMode access_mode, LanguageMode language_mode,
1294 107 : KeyedAccessStoreMode store_mode) {
1295 : DCHECK(node->opcode() == IrOpcode::kJSLoadProperty ||
1296 : node->opcode() == IrOpcode::kJSStoreProperty);
1297 120260 : Node* receiver = NodeProperties::GetValueInput(node, 0);
1298 120260 : Node* effect = NodeProperties::GetEffectInput(node);
1299 120260 : Node* control = NodeProperties::GetControlInput(node);
1300 :
1301 : // Optimize access for constant {receiver}.
1302 : HeapObjectMatcher mreceiver(receiver);
1303 131589 : if (mreceiver.HasValue() && mreceiver.Value()->IsString()) {
1304 : Handle<String> string = Handle<String>::cast(mreceiver.Value());
1305 :
1306 : // Strings are immutable in JavaScript.
1307 143 : if (access_mode == AccessMode::kStore) return NoChange();
1308 :
1309 : // Properly deal with constant {index}.
1310 : NumberMatcher mindex(index);
1311 249 : if (mindex.IsInteger() && mindex.IsInRange(0.0, string->length() - 1)) {
1312 : // Constant-fold the {index} access to {string}.
1313 : Node* value = jsgraph()->HeapConstant(
1314 : factory()->LookupSingleCharacterStringFromCode(
1315 100 : string->Get(static_cast<int>(mindex.Value()))));
1316 107 : ReplaceWithValue(node, value, effect, control);
1317 : return Replace(value);
1318 : }
1319 :
1320 : // We can only assume that the {index} is a valid array index if the IC
1321 : // is in element access mode and not MEGAMORPHIC, otherwise there's no
1322 : // guard for the bounds check below.
1323 216 : if (nexus.ic_state() != MEGAMORPHIC && nexus.GetKeyType() == ELEMENT) {
1324 : // Ensure that {index} is less than {receiver} length.
1325 82 : Node* length = jsgraph()->Constant(string->length());
1326 : index = effect = graph()->NewNode(simplified()->CheckBounds(), index,
1327 82 : length, effect, control);
1328 :
1329 : // Return the character from the {receiver} as single character string.
1330 : value = graph()->NewNode(simplified()->StringCharAt(), receiver, index,
1331 82 : control);
1332 : ReplaceWithValue(node, value, effect, control);
1333 : return Replace(value);
1334 : }
1335 : }
1336 :
1337 : // Check if the {nexus} reports type feedback for the IC.
1338 240286 : if (nexus.IsUninitialized()) {
1339 84205 : if (flags() & kBailoutOnUninitialized) {
1340 : return ReduceSoftDeoptimize(
1341 : node,
1342 545 : DeoptimizeReason::kInsufficientTypeFeedbackForGenericKeyedAccess);
1343 : }
1344 : return NoChange();
1345 : }
1346 :
1347 : // Extract receiver maps from the {nexus}.
1348 : MapHandleList receiver_maps;
1349 35938 : if (!ExtractReceiverMaps(receiver, effect, nexus, &receiver_maps)) {
1350 : return NoChange();
1351 28506 : } else if (receiver_maps.length() == 0) {
1352 0 : if (flags() & kBailoutOnUninitialized) {
1353 : return ReduceSoftDeoptimize(
1354 : node,
1355 0 : DeoptimizeReason::kInsufficientTypeFeedbackForGenericKeyedAccess);
1356 : }
1357 : return NoChange();
1358 : }
1359 :
1360 : // Optimize access for constant {index}.
1361 : HeapObjectMatcher mindex(index);
1362 28894 : if (mindex.HasValue() && mindex.Value()->IsPrimitive()) {
1363 : // Keyed access requires a ToPropertyKey on the {index} first before
1364 : // looking up the property on the object (see ES6 section 12.3.2.1).
1365 : // We can only do this for non-observable ToPropertyKey invocations,
1366 : // so we limit the constant indices to primitives at this point.
1367 : Handle<Name> name;
1368 748 : if (Object::ToName(isolate(), mindex.Value()).ToHandle(&name)) {
1369 : uint32_t array_index;
1370 374 : if (name->AsArrayIndex(&array_index)) {
1371 : // Use the constant array index.
1372 0 : index = jsgraph()->Constant(static_cast<double>(array_index));
1373 : } else {
1374 374 : name = factory()->InternalizeName(name);
1375 : return ReduceNamedAccess(node, value, receiver_maps, name, access_mode,
1376 374 : language_mode);
1377 : }
1378 : }
1379 : }
1380 :
1381 : // Check if we have feedback for a named access.
1382 28132 : if (Name* name = nexus.FindFirstName()) {
1383 : return ReduceNamedAccess(node, value, receiver_maps,
1384 : handle(name, isolate()), access_mode,
1385 219 : language_mode, index);
1386 27913 : } else if (nexus.GetKeyType() != ELEMENT) {
1387 : // The KeyedLoad/StoreIC has seen non-element accesses, so we cannot assume
1388 : // that the {index} is a valid array index, thus we just let the IC continue
1389 : // to deal with this load/store.
1390 : return NoChange();
1391 27888 : } else if (nexus.ic_state() == MEGAMORPHIC) {
1392 : // The KeyedLoad/StoreIC uses the MEGAMORPHIC state to guard the assumption
1393 : // that a numeric {index} is within the valid bounds for {receiver}, i.e.
1394 : // it transitions to MEGAMORPHIC once it sees an out-of-bounds access. Thus
1395 : // we cannot continue here if the IC state is MEGAMORPHIC.
1396 : return NoChange();
1397 : }
1398 :
1399 : // Try to lower the element access based on the {receiver_maps}.
1400 : return ReduceElementAccess(node, index, value, receiver_maps, access_mode,
1401 26477 : language_mode, store_mode);
1402 : }
1403 :
1404 1018 : Reduction JSNativeContextSpecialization::ReduceSoftDeoptimize(
1405 : Node* node, DeoptimizeReason reason) {
1406 1018 : Node* effect = NodeProperties::GetEffectInput(node);
1407 1018 : Node* control = NodeProperties::GetControlInput(node);
1408 1018 : Node* frame_state = NodeProperties::FindFrameStateBefore(node);
1409 : Node* deoptimize =
1410 : graph()->NewNode(common()->Deoptimize(DeoptimizeKind::kSoft, reason),
1411 1018 : frame_state, effect, control);
1412 : // TODO(bmeurer): This should be on the AdvancedReducer somehow.
1413 1018 : NodeProperties::MergeControlToEnd(graph(), common(), deoptimize);
1414 1018 : Revisit(graph()->end());
1415 1018 : node->TrimInputCount(0);
1416 1018 : NodeProperties::ChangeOp(node, common()->Dead());
1417 1018 : return Changed(node);
1418 : }
1419 :
1420 :
1421 152582 : Reduction JSNativeContextSpecialization::ReduceJSLoadProperty(Node* node) {
1422 : DCHECK_EQ(IrOpcode::kJSLoadProperty, node->opcode());
1423 152582 : PropertyAccess const& p = PropertyAccessOf(node->op());
1424 76291 : Node* const index = NodeProperties::GetValueInput(node, 1);
1425 76291 : Node* const value = jsgraph()->Dead();
1426 :
1427 : // Extract receiver maps from the KEYED_LOAD_IC using the KeyedLoadICNexus.
1428 76291 : if (!p.feedback().IsValid()) return NoChange();
1429 : KeyedLoadICNexus nexus(p.feedback().vector(), p.feedback().slot());
1430 :
1431 : // Try to lower the keyed access based on the {nexus}.
1432 : return ReduceKeyedAccess(node, index, value, nexus, AccessMode::kLoad,
1433 76291 : p.language_mode(), STANDARD_STORE);
1434 : }
1435 :
1436 :
1437 43969 : Reduction JSNativeContextSpecialization::ReduceJSStoreProperty(Node* node) {
1438 : DCHECK_EQ(IrOpcode::kJSStoreProperty, node->opcode());
1439 87938 : PropertyAccess const& p = PropertyAccessOf(node->op());
1440 43969 : Node* const index = NodeProperties::GetValueInput(node, 1);
1441 43969 : Node* const value = NodeProperties::GetValueInput(node, 2);
1442 :
1443 : // Extract receiver maps from the KEYED_STORE_IC using the KeyedStoreICNexus.
1444 43969 : if (!p.feedback().IsValid()) return NoChange();
1445 : KeyedStoreICNexus nexus(p.feedback().vector(), p.feedback().slot());
1446 :
1447 : // Extract the keyed access store mode from the KEYED_STORE_IC.
1448 43969 : KeyedAccessStoreMode store_mode = nexus.GetKeyedAccessStoreMode();
1449 :
1450 : // Try to lower the keyed access based on the {nexus}.
1451 : return ReduceKeyedAccess(node, index, value, nexus, AccessMode::kStore,
1452 43969 : p.language_mode(), store_mode);
1453 : }
1454 :
1455 : JSNativeContextSpecialization::ValueEffectControl
1456 89343 : JSNativeContextSpecialization::BuildPropertyAccess(
1457 : Node* receiver, Node* value, Node* context, Node* frame_state, Node* effect,
1458 27654 : Node* control, Handle<Name> name, PropertyAccessInfo const& access_info,
1459 75352 : AccessMode access_mode, LanguageMode language_mode) {
1460 : // Determine actual holder and perform prototype chain checks.
1461 : Handle<JSObject> holder;
1462 89343 : if (access_info.holder().ToHandle(&holder)) {
1463 : DCHECK_NE(AccessMode::kStoreInLiteral, access_mode);
1464 19218 : AssumePrototypesStable(access_info.receiver_maps(), holder);
1465 : }
1466 :
1467 : // Generate the actual property access.
1468 89343 : if (access_info.IsNotFound()) {
1469 : DCHECK_EQ(AccessMode::kLoad, access_mode);
1470 2287 : value = jsgraph()->UndefinedConstant();
1471 87056 : } else if (access_info.IsDataConstant()) {
1472 : DCHECK(!FLAG_track_constant_fields);
1473 58211 : Node* constant_value = jsgraph()->Constant(access_info.constant());
1474 58211 : if (access_mode == AccessMode::kStore) {
1475 : Node* check = graph()->NewNode(simplified()->ReferenceEqual(), value,
1476 7 : constant_value);
1477 : effect =
1478 21 : graph()->NewNode(simplified()->CheckIf(), check, effect, control);
1479 : }
1480 : value = constant_value;
1481 28845 : } else if (access_info.IsAccessorConstant()) {
1482 : // TODO(bmeurer): Properly rewire the IfException edge here if there's any.
1483 1191 : Node* target = jsgraph()->Constant(access_info.constant());
1484 1191 : FrameStateInfo const& frame_info = OpParameter<FrameStateInfo>(frame_state);
1485 : Handle<SharedFunctionInfo> shared_info =
1486 1191 : frame_info.shared_info().ToHandleChecked();
1487 1191 : switch (access_mode) {
1488 : case AccessMode::kLoad: {
1489 : // We need a FrameState for the getter stub to restore the correct
1490 : // context before returning to fullcodegen.
1491 : FrameStateFunctionInfo const* frame_info0 =
1492 : common()->CreateFrameStateFunctionInfo(FrameStateType::kGetterStub,
1493 736 : 1, 0, shared_info);
1494 : Node* frame_state0 = graph()->NewNode(
1495 : common()->FrameState(BailoutId::None(),
1496 : OutputFrameStateCombine::Ignore(),
1497 : frame_info0),
1498 : graph()->NewNode(common()->StateValues(1, SparseInputMask::Dense()),
1499 : receiver),
1500 : jsgraph()->EmptyStateValues(), jsgraph()->EmptyStateValues(),
1501 2944 : context, target, frame_state);
1502 :
1503 : // Introduce the call to the getter function.
1504 736 : if (access_info.constant()->IsJSFunction()) {
1505 : value = effect = control = graph()->NewNode(
1506 : javascript()->Call(2, 0.0f, VectorSlotPair(),
1507 : ConvertReceiverMode::kNotNullOrUndefined),
1508 2205 : target, receiver, context, frame_state0, effect, control);
1509 : } else {
1510 : DCHECK(access_info.constant()->IsFunctionTemplateInfo());
1511 : Handle<FunctionTemplateInfo> function_template_info(
1512 1 : Handle<FunctionTemplateInfo>::cast(access_info.constant()));
1513 : DCHECK(!function_template_info->call_code()->IsUndefined(isolate()));
1514 : ValueEffectControl value_effect_control = InlineApiCall(
1515 : receiver, context, target, frame_state0, nullptr, effect, control,
1516 1 : shared_info, function_template_info);
1517 1 : value = value_effect_control.value();
1518 1 : effect = value_effect_control.effect();
1519 1 : control = value_effect_control.control();
1520 : }
1521 : break;
1522 : }
1523 : case AccessMode::kStoreInLiteral:
1524 : case AccessMode::kStore: {
1525 : // We need a FrameState for the setter stub to restore the correct
1526 : // context and return the appropriate value to fullcodegen.
1527 : FrameStateFunctionInfo const* frame_info0 =
1528 : common()->CreateFrameStateFunctionInfo(FrameStateType::kSetterStub,
1529 455 : 2, 0, shared_info);
1530 : Node* frame_state0 = graph()->NewNode(
1531 : common()->FrameState(BailoutId::None(),
1532 : OutputFrameStateCombine::Ignore(),
1533 : frame_info0),
1534 : graph()->NewNode(common()->StateValues(2, SparseInputMask::Dense()),
1535 : receiver, value),
1536 : jsgraph()->EmptyStateValues(), jsgraph()->EmptyStateValues(),
1537 1820 : context, target, frame_state);
1538 :
1539 : // Introduce the call to the setter function.
1540 455 : if (access_info.constant()->IsJSFunction()) {
1541 : effect = control = graph()->NewNode(
1542 : javascript()->Call(3, 0.0f, VectorSlotPair(),
1543 : ConvertReceiverMode::kNotNullOrUndefined),
1544 1365 : target, receiver, value, context, frame_state0, effect, control);
1545 : } else {
1546 : DCHECK(access_info.constant()->IsFunctionTemplateInfo());
1547 : Handle<FunctionTemplateInfo> function_template_info(
1548 0 : Handle<FunctionTemplateInfo>::cast(access_info.constant()));
1549 : DCHECK(!function_template_info->call_code()->IsUndefined(isolate()));
1550 : ValueEffectControl value_effect_control = InlineApiCall(
1551 : receiver, context, target, frame_state0, value, effect, control,
1552 0 : shared_info, function_template_info);
1553 0 : value = value_effect_control.value();
1554 0 : effect = value_effect_control.effect();
1555 0 : control = value_effect_control.control();
1556 : }
1557 : break;
1558 : }
1559 : }
1560 : } else {
1561 : DCHECK(access_info.IsDataField() || access_info.IsDataConstantField());
1562 : FieldIndex const field_index = access_info.field_index();
1563 : Type* const field_type = access_info.field_type();
1564 : MachineRepresentation const field_representation =
1565 27654 : access_info.field_representation();
1566 27654 : if (access_mode == AccessMode::kLoad) {
1567 20401 : if (access_info.holder().ToHandle(&holder)) {
1568 190 : receiver = jsgraph()->Constant(holder);
1569 : }
1570 : // Optimize immutable property loads.
1571 : HeapObjectMatcher m(receiver);
1572 22054 : if (m.HasValue() && m.Value()->IsJSObject()) {
1573 : // TODO(ishell): Use something simpler like
1574 : //
1575 : // Handle<Object> value =
1576 : // JSObject::FastPropertyAt(Handle<JSObject>::cast(m.Value()),
1577 : // Representation::Tagged(), field_index);
1578 : //
1579 : // here, once we have the immutable bit in the access_info.
1580 :
1581 : // TODO(turbofan): Given that we already have the field_index here, we
1582 : // might be smarter in the future and not rely on the LookupIterator,
1583 : // but for now let's just do what Crankshaft does.
1584 : LookupIterator it(m.Value(), name,
1585 1653 : LookupIterator::OWN_SKIP_INTERCEPTOR);
1586 1653 : if (it.state() == LookupIterator::DATA) {
1587 : bool is_reaonly_non_configurable =
1588 1679 : it.IsReadOnly() && !it.IsConfigurable();
1589 1508 : if (is_reaonly_non_configurable ||
1590 : (FLAG_track_constant_fields &&
1591 : access_info.IsDataConstantField())) {
1592 342 : Node* value = jsgraph()->Constant(JSReceiver::GetDataProperty(&it));
1593 171 : if (!is_reaonly_non_configurable) {
1594 : // It's necessary to add dependency on the map that introduced
1595 : // the field.
1596 : DCHECK(access_info.IsDataConstantField());
1597 : DCHECK(!it.is_dictionary_holder());
1598 0 : Handle<Map> field_owner_map = it.GetFieldOwnerMap();
1599 : dependencies()->AssumeFieldOwner(field_owner_map);
1600 : }
1601 342 : return ValueEffectControl(value, effect, control);
1602 : }
1603 : }
1604 : }
1605 : }
1606 : Node* storage = receiver;
1607 27483 : if (!field_index.is_inobject()) {
1608 : storage = effect = graph()->NewNode(
1609 : simplified()->LoadField(AccessBuilder::ForJSObjectProperties()),
1610 4443 : storage, effect, control);
1611 : }
1612 : FieldAccess field_access = {
1613 : kTaggedBase,
1614 : field_index.offset(),
1615 : name,
1616 : MaybeHandle<Map>(),
1617 : field_type,
1618 : MachineType::TypeForRepresentation(field_representation),
1619 82449 : kFullWriteBarrier};
1620 27483 : if (access_mode == AccessMode::kLoad) {
1621 20230 : if (field_representation == MachineRepresentation::kFloat64) {
1622 686 : if (!field_index.is_inobject() || field_index.is_hidden_field() ||
1623 : !FLAG_unbox_double_fields) {
1624 : FieldAccess const storage_access = {kTaggedBase,
1625 : field_index.offset(),
1626 : name,
1627 : MaybeHandle<Map>(),
1628 : Type::OtherInternal(),
1629 : MachineType::TaggedPointer(),
1630 60 : kPointerWriteBarrier};
1631 : storage = effect =
1632 : graph()->NewNode(simplified()->LoadField(storage_access), storage,
1633 90 : effect, control);
1634 30 : field_access.offset = HeapNumber::kValueOffset;
1635 30 : field_access.name = MaybeHandle<Name>();
1636 : }
1637 19872 : } else if (field_representation ==
1638 : MachineRepresentation::kTaggedPointer) {
1639 : // Remember the map of the field value, if its map is stable. This is
1640 : // used by the LoadElimination to eliminate map checks on the result.
1641 : Handle<Map> field_map;
1642 5532 : if (access_info.field_map().ToHandle(&field_map)) {
1643 1912 : if (field_map->is_stable()) {
1644 1877 : dependencies()->AssumeMapStable(field_map);
1645 1877 : field_access.map = field_map;
1646 : }
1647 : }
1648 : }
1649 : value = effect = graph()->NewNode(simplified()->LoadField(field_access),
1650 60690 : storage, effect, control);
1651 : } else {
1652 : bool store_to_constant_field = FLAG_track_constant_fields &&
1653 : (access_mode == AccessMode::kStore) &&
1654 : access_info.IsDataConstantField();
1655 :
1656 : DCHECK(access_mode == AccessMode::kStore ||
1657 : access_mode == AccessMode::kStoreInLiteral);
1658 7253 : switch (field_representation) {
1659 : case MachineRepresentation::kFloat64: {
1660 : value = effect = graph()->NewNode(simplified()->CheckNumber(), value,
1661 738 : effect, control);
1662 438 : if (!field_index.is_inobject() || field_index.is_hidden_field() ||
1663 : !FLAG_unbox_double_fields) {
1664 54 : if (access_info.HasTransitionMap()) {
1665 : // Allocate a MutableHeapNumber for the new property.
1666 : effect = graph()->NewNode(
1667 : common()->BeginRegion(RegionObservability::kNotObservable),
1668 18 : effect);
1669 : Node* box = effect = graph()->NewNode(
1670 : simplified()->Allocate(Type::OtherInternal(), NOT_TENURED),
1671 27 : jsgraph()->Constant(HeapNumber::kSize), effect, control);
1672 : effect = graph()->NewNode(
1673 : simplified()->StoreField(AccessBuilder::ForMap()), box,
1674 : jsgraph()->HeapConstant(factory()->mutable_heap_number_map()),
1675 27 : effect, control);
1676 : effect = graph()->NewNode(
1677 : simplified()->StoreField(AccessBuilder::ForHeapNumberValue()),
1678 27 : box, value, effect, control);
1679 : value = effect =
1680 18 : graph()->NewNode(common()->FinishRegion(), box, effect);
1681 :
1682 9 : field_access.type = Type::Any();
1683 9 : field_access.machine_type = MachineType::TaggedPointer();
1684 9 : field_access.write_barrier_kind = kPointerWriteBarrier;
1685 : } else {
1686 : // We just store directly to the MutableHeapNumber.
1687 : FieldAccess const storage_access = {kTaggedBase,
1688 : field_index.offset(),
1689 : name,
1690 : MaybeHandle<Map>(),
1691 : Type::OtherInternal(),
1692 : MachineType::TaggedPointer(),
1693 90 : kPointerWriteBarrier};
1694 : storage = effect =
1695 : graph()->NewNode(simplified()->LoadField(storage_access),
1696 90 : storage, effect, control);
1697 45 : field_access.offset = HeapNumber::kValueOffset;
1698 45 : field_access.name = MaybeHandle<Name>();
1699 45 : field_access.machine_type = MachineType::Float64();
1700 : }
1701 : }
1702 : if (store_to_constant_field) {
1703 : DCHECK(!access_info.HasTransitionMap());
1704 : // If the field is constant check that the value we are going
1705 : // to store matches current value.
1706 : Node* current_value = effect =
1707 : graph()->NewNode(simplified()->LoadField(field_access), storage,
1708 : effect, control);
1709 :
1710 : Node* check = graph()->NewNode(simplified()->NumberEqual(),
1711 : current_value, value);
1712 : effect = graph()->NewNode(simplified()->CheckIf(), check, effect,
1713 : control);
1714 : return ValueEffectControl(value, effect, control);
1715 : }
1716 : break;
1717 : }
1718 : case MachineRepresentation::kTaggedSigned:
1719 : case MachineRepresentation::kTaggedPointer:
1720 : case MachineRepresentation::kTagged:
1721 : if (store_to_constant_field) {
1722 : DCHECK(!access_info.HasTransitionMap());
1723 : // If the field is constant check that the value we are going
1724 : // to store matches current value.
1725 : Node* current_value = effect =
1726 : graph()->NewNode(simplified()->LoadField(field_access), storage,
1727 : effect, control);
1728 :
1729 : Node* check = graph()->NewNode(simplified()->ReferenceEqual(),
1730 : current_value, value);
1731 : effect = graph()->NewNode(simplified()->CheckIf(), check, effect,
1732 : control);
1733 : return ValueEffectControl(value, effect, control);
1734 : }
1735 :
1736 7007 : if (field_representation == MachineRepresentation::kTaggedSigned) {
1737 : value = effect = graph()->NewNode(simplified()->CheckSmi(), value,
1738 12768 : effect, control);
1739 4256 : field_access.write_barrier_kind = kNoWriteBarrier;
1740 :
1741 2751 : } else if (field_representation ==
1742 : MachineRepresentation::kTaggedPointer) {
1743 : // Ensure that {value} is a HeapObject.
1744 2297 : value = BuildCheckHeapObject(value, &effect, control);
1745 : Handle<Map> field_map;
1746 2297 : if (access_info.field_map().ToHandle(&field_map)) {
1747 : // Emit a map check for the value.
1748 : effect = graph()->NewNode(
1749 : simplified()->CheckMaps(CheckMapsFlag::kNone,
1750 : ZoneHandleSet<Map>(field_map)),
1751 1185 : value, effect, control);
1752 : }
1753 2297 : field_access.write_barrier_kind = kPointerWriteBarrier;
1754 :
1755 : } else {
1756 : DCHECK_EQ(MachineRepresentation::kTagged, field_representation);
1757 : }
1758 : break;
1759 : case MachineRepresentation::kNone:
1760 : case MachineRepresentation::kBit:
1761 : case MachineRepresentation::kWord8:
1762 : case MachineRepresentation::kWord16:
1763 : case MachineRepresentation::kWord32:
1764 : case MachineRepresentation::kWord64:
1765 : case MachineRepresentation::kFloat32:
1766 : case MachineRepresentation::kSimd128:
1767 : case MachineRepresentation::kSimd1x4:
1768 : case MachineRepresentation::kSimd1x8:
1769 : case MachineRepresentation::kSimd1x16:
1770 0 : UNREACHABLE();
1771 : break;
1772 : }
1773 : // Check if we need to perform a transitioning store.
1774 : Handle<Map> transition_map;
1775 7253 : if (access_info.transition_map().ToHandle(&transition_map)) {
1776 : // Check if we need to grow the properties backing store
1777 : // with this transitioning store.
1778 : Handle<Map> original_map(Map::cast(transition_map->GetBackPointer()),
1779 4517 : isolate());
1780 4517 : if (original_map->unused_property_fields() == 0) {
1781 : DCHECK(!field_index.is_inobject());
1782 :
1783 : // Reallocate the properties {storage}.
1784 : storage = effect = BuildExtendPropertiesBackingStore(
1785 257 : original_map, storage, effect, control);
1786 :
1787 : // Perform the actual store.
1788 : effect = graph()->NewNode(simplified()->StoreField(field_access),
1789 514 : storage, value, effect, control);
1790 :
1791 : // Atomically switch to the new properties below.
1792 257 : field_access = AccessBuilder::ForJSObjectProperties();
1793 : value = storage;
1794 : storage = receiver;
1795 : }
1796 : effect = graph()->NewNode(
1797 13551 : common()->BeginRegion(RegionObservability::kObservable), effect);
1798 : effect = graph()->NewNode(
1799 : simplified()->StoreField(AccessBuilder::ForMap()), receiver,
1800 13551 : jsgraph()->Constant(transition_map), effect, control);
1801 : effect = graph()->NewNode(simplified()->StoreField(field_access),
1802 9034 : storage, value, effect, control);
1803 : effect = graph()->NewNode(common()->FinishRegion(),
1804 13551 : jsgraph()->UndefinedConstant(), effect);
1805 : } else {
1806 : // Regular non-transitioning field store.
1807 : effect = graph()->NewNode(simplified()->StoreField(field_access),
1808 8208 : storage, value, effect, control);
1809 : }
1810 : }
1811 : }
1812 :
1813 89172 : return ValueEffectControl(value, effect, control);
1814 : }
1815 :
1816 44202 : Reduction JSNativeContextSpecialization::ReduceJSStoreDataPropertyInLiteral(
1817 44489 : Node* node) {
1818 : DCHECK_EQ(IrOpcode::kJSStoreDataPropertyInLiteral, node->opcode());
1819 :
1820 44202 : FeedbackParameter const& p = FeedbackParameterOf(node->op());
1821 :
1822 44202 : if (!p.feedback().IsValid()) return NoChange();
1823 :
1824 : StoreDataPropertyInLiteralICNexus nexus(p.feedback().vector(),
1825 : p.feedback().slot());
1826 44202 : if (nexus.IsUninitialized()) {
1827 : return NoChange();
1828 : }
1829 :
1830 214 : if (nexus.ic_state() == MEGAMORPHIC) {
1831 : return NoChange();
1832 : }
1833 :
1834 : DCHECK_EQ(MONOMORPHIC, nexus.ic_state());
1835 :
1836 171 : Map* map = nexus.FindFirstMap();
1837 171 : if (map == nullptr) {
1838 : // Maps are weakly held in the type feedback vector, we may not have one.
1839 : return NoChange();
1840 : }
1841 :
1842 : Handle<Map> receiver_map(map, isolate());
1843 : Handle<Name> cached_name =
1844 171 : handle(Name::cast(nexus.GetFeedbackExtra()), isolate());
1845 :
1846 171 : PropertyAccessInfo access_info;
1847 : AccessInfoFactory access_info_factory(dependencies(), native_context(),
1848 342 : graph()->zone());
1849 171 : if (!access_info_factory.ComputePropertyAccessInfo(
1850 : receiver_map, cached_name, AccessMode::kStoreInLiteral,
1851 171 : &access_info)) {
1852 : return NoChange();
1853 : }
1854 :
1855 116 : Node* receiver = NodeProperties::GetValueInput(node, 0);
1856 116 : Node* effect = NodeProperties::GetEffectInput(node);
1857 116 : Node* control = NodeProperties::GetControlInput(node);
1858 :
1859 : // Monomorphic property access.
1860 116 : receiver = BuildCheckHeapObject(receiver, &effect, control);
1861 :
1862 : effect =
1863 116 : BuildCheckMaps(receiver, effect, control, access_info.receiver_maps());
1864 :
1865 : // Ensure that {name} matches the cached name.
1866 116 : Node* name = NodeProperties::GetValueInput(node, 1);
1867 : Node* check = graph()->NewNode(simplified()->ReferenceEqual(), name,
1868 348 : jsgraph()->HeapConstant(cached_name));
1869 348 : effect = graph()->NewNode(simplified()->CheckIf(), check, effect, control);
1870 :
1871 116 : Node* value = NodeProperties::GetValueInput(node, 2);
1872 116 : Node* context = NodeProperties::GetContextInput(node);
1873 116 : Node* frame_state_lazy = NodeProperties::GetFrameStateInput(node);
1874 :
1875 : // Generate the actual property access.
1876 : ValueEffectControl continuation = BuildPropertyAccess(
1877 : receiver, value, context, frame_state_lazy, effect, control, cached_name,
1878 116 : access_info, AccessMode::kStoreInLiteral, LanguageMode::SLOPPY);
1879 116 : value = continuation.value();
1880 116 : effect = continuation.effect();
1881 116 : control = continuation.control();
1882 :
1883 116 : ReplaceWithValue(node, value, effect, control);
1884 : return Replace(value);
1885 : }
1886 :
1887 : namespace {
1888 :
1889 4994 : ExternalArrayType GetArrayTypeFromElementsKind(ElementsKind kind) {
1890 4994 : switch (kind) {
1891 : #define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) \
1892 : case TYPE##_ELEMENTS: \
1893 : return kExternal##Type##Array;
1894 385 : TYPED_ARRAYS(TYPED_ARRAY_CASE)
1895 : #undef TYPED_ARRAY_CASE
1896 : default:
1897 : break;
1898 : }
1899 0 : UNREACHABLE();
1900 : return kExternalInt8Array;
1901 : }
1902 :
1903 : } // namespace
1904 :
1905 : JSNativeContextSpecialization::ValueEffectControl
1906 26845 : JSNativeContextSpecialization::BuildElementAccess(
1907 : Node* receiver, Node* index, Node* value, Node* effect, Node* control,
1908 26845 : ElementAccessInfo const& access_info, AccessMode access_mode,
1909 13331 : KeyedAccessStoreMode store_mode) {
1910 : DCHECK_NE(AccessMode::kStoreInLiteral, access_mode);
1911 :
1912 : // TODO(bmeurer): We currently specialize based on elements kind. We should
1913 : // also be able to properly support strings and other JSObjects here.
1914 : ElementsKind elements_kind = access_info.elements_kind();
1915 26845 : MapList const& receiver_maps = access_info.receiver_maps();
1916 :
1917 26845 : if (IsFixedTypedArrayElementsKind(elements_kind)) {
1918 : Node* buffer;
1919 : Node* length;
1920 : Node* base_pointer;
1921 : Node* external_pointer;
1922 :
1923 : // Check if we can constant-fold information about the {receiver} (i.e.
1924 : // for asm.js-like code patterns).
1925 : HeapObjectMatcher m(receiver);
1926 6939 : if (m.HasValue() && m.Value()->IsJSTypedArray()) {
1927 : Handle<JSTypedArray> typed_array = Handle<JSTypedArray>::cast(m.Value());
1928 :
1929 : // Determine the {receiver}s (known) length.
1930 3890 : length = jsgraph()->Constant(typed_array->length_value());
1931 :
1932 : // Check if the {receiver}s buffer was neutered.
1933 3890 : buffer = jsgraph()->HeapConstant(typed_array->GetBuffer());
1934 :
1935 : // Load the (known) base and external pointer for the {receiver}. The
1936 : // {external_pointer} might be invalid if the {buffer} was neutered, so
1937 : // we need to make sure that any access is properly guarded.
1938 1945 : base_pointer = jsgraph()->ZeroConstant();
1939 : external_pointer = jsgraph()->PointerConstant(
1940 : FixedTypedArrayBase::cast(typed_array->elements())
1941 : ->external_pointer());
1942 : } else {
1943 : // Load the {receiver}s length.
1944 : length = effect = graph()->NewNode(
1945 : simplified()->LoadField(AccessBuilder::ForJSTypedArrayLength()),
1946 9147 : receiver, effect, control);
1947 :
1948 : // Load the buffer for the {receiver}.
1949 : buffer = effect = graph()->NewNode(
1950 : simplified()->LoadField(AccessBuilder::ForJSArrayBufferViewBuffer()),
1951 9147 : receiver, effect, control);
1952 :
1953 : // Load the elements for the {receiver}.
1954 : Node* elements = effect = graph()->NewNode(
1955 : simplified()->LoadField(AccessBuilder::ForJSObjectElements()),
1956 9147 : receiver, effect, control);
1957 :
1958 : // Load the base and external pointer for the {receiver}s {elements}.
1959 : base_pointer = effect = graph()->NewNode(
1960 : simplified()->LoadField(
1961 : AccessBuilder::ForFixedTypedArrayBaseBasePointer()),
1962 9147 : elements, effect, control);
1963 : external_pointer = effect = graph()->NewNode(
1964 : simplified()->LoadField(
1965 : AccessBuilder::ForFixedTypedArrayBaseExternalPointer()),
1966 9147 : elements, effect, control);
1967 : }
1968 :
1969 : // See if we can skip the neutering check.
1970 4994 : if (isolate()->IsArrayBufferNeuteringIntact()) {
1971 : // Add a code dependency so we are deoptimized in case an ArrayBuffer
1972 : // gets neutered.
1973 : dependencies()->AssumePropertyCell(
1974 : factory()->array_buffer_neutering_protector());
1975 : } else {
1976 : // Default to zero if the {receiver}s buffer was neutered.
1977 : Node* check = effect = graph()->NewNode(
1978 150 : simplified()->ArrayBufferWasNeutered(), buffer, effect, control);
1979 : length = graph()->NewNode(
1980 : common()->Select(MachineRepresentation::kTagged, BranchHint::kFalse),
1981 300 : check, jsgraph()->ZeroConstant(), length);
1982 : }
1983 :
1984 4994 : if (store_mode == STORE_NO_TRANSITION_IGNORE_OUT_OF_BOUNDS) {
1985 : // Check that the {index} is a valid array index, we do the actual
1986 : // bounds check below and just skip the store below if it's out of
1987 : // bounds for the {receiver}.
1988 : index = effect = graph()->NewNode(simplified()->CheckBounds(), index,
1989 : jsgraph()->Constant(Smi::kMaxValue),
1990 188 : effect, control);
1991 : } else {
1992 : // Check that the {index} is in the valid range for the {receiver}.
1993 : index = effect = graph()->NewNode(simplified()->CheckBounds(), index,
1994 4900 : length, effect, control);
1995 : }
1996 :
1997 : // Access the actual element.
1998 : ExternalArrayType external_array_type =
1999 4994 : GetArrayTypeFromElementsKind(elements_kind);
2000 4994 : switch (access_mode) {
2001 : case AccessMode::kLoad: {
2002 : value = effect = graph()->NewNode(
2003 : simplified()->LoadTypedElement(external_array_type), buffer,
2004 2546 : base_pointer, external_pointer, index, effect, control);
2005 2546 : break;
2006 : }
2007 : case AccessMode::kStoreInLiteral:
2008 0 : UNREACHABLE();
2009 : break;
2010 : case AccessMode::kStore: {
2011 : // Ensure that the {value} is actually a Number.
2012 : value = effect = graph()->NewNode(simplified()->CheckNumber(), value,
2013 2448 : effect, control);
2014 :
2015 : // Introduce the appropriate truncation for {value}. Currently we
2016 : // only need to do this for ClamedUint8Array {receiver}s, as the
2017 : // other truncations are implicit in the StoreTypedElement, but we
2018 : // might want to change that at some point.
2019 2448 : if (external_array_type == kExternalUint8ClampedArray) {
2020 457 : value = graph()->NewNode(simplified()->NumberToUint8Clamped(), value);
2021 : }
2022 :
2023 : // Check if we can skip the out-of-bounds store.
2024 2448 : if (store_mode == STORE_NO_TRANSITION_IGNORE_OUT_OF_BOUNDS) {
2025 : Node* check =
2026 94 : graph()->NewNode(simplified()->NumberLessThan(), index, length);
2027 : Node* branch = graph()->NewNode(common()->Branch(BranchHint::kTrue),
2028 94 : check, control);
2029 :
2030 94 : Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
2031 : Node* etrue = effect;
2032 : {
2033 : // Perform the actual store.
2034 : etrue = graph()->NewNode(
2035 : simplified()->StoreTypedElement(external_array_type), buffer,
2036 94 : base_pointer, external_pointer, index, value, etrue, if_true);
2037 : }
2038 :
2039 94 : Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
2040 : Node* efalse = effect;
2041 : {
2042 : // Just ignore the out-of-bounds write.
2043 : }
2044 :
2045 94 : control = graph()->NewNode(common()->Merge(2), if_true, if_false);
2046 : effect =
2047 94 : graph()->NewNode(common()->EffectPhi(2), etrue, efalse, control);
2048 : } else {
2049 : // Perform the actual store
2050 : effect = graph()->NewNode(
2051 : simplified()->StoreTypedElement(external_array_type), buffer,
2052 2354 : base_pointer, external_pointer, index, value, effect, control);
2053 : }
2054 : break;
2055 : }
2056 : }
2057 : } else {
2058 : // Load the elements for the {receiver}.
2059 : Node* elements = effect = graph()->NewNode(
2060 : simplified()->LoadField(AccessBuilder::ForJSObjectElements()), receiver,
2061 65553 : effect, control);
2062 :
2063 : // Don't try to store to a copy-on-write backing store.
2064 30423 : if (access_mode == AccessMode::kStore &&
2065 29546 : IsFastSmiOrObjectElementsKind(elements_kind) &&
2066 : store_mode != STORE_NO_TRANSITION_HANDLE_COW) {
2067 : effect = graph()->NewNode(
2068 : simplified()->CheckMaps(
2069 : CheckMapsFlag::kNone,
2070 : ZoneHandleSet<Map>(factory()->fixed_array_map())),
2071 15178 : elements, effect, control);
2072 : }
2073 :
2074 : // Check if the {receiver} is a JSArray.
2075 : bool receiver_is_jsarray = HasOnlyJSArrayMaps(receiver_maps);
2076 :
2077 : // Load the length of the {receiver}.
2078 : Node* length = effect =
2079 : receiver_is_jsarray
2080 : ? graph()->NewNode(
2081 : simplified()->LoadField(
2082 : AccessBuilder::ForJSArrayLength(elements_kind)),
2083 80258 : receiver, effect, control)
2084 : : graph()->NewNode(
2085 : simplified()->LoadField(AccessBuilder::ForFixedArrayLength()),
2086 50848 : elements, effect, control);
2087 :
2088 : // Check if we might need to grow the {elements} backing store.
2089 21851 : if (IsGrowStoreMode(store_mode)) {
2090 : DCHECK_EQ(AccessMode::kStore, access_mode);
2091 :
2092 : // Check that the {index} is a valid array index; the actual checking
2093 : // happens below right before the element store.
2094 : index = effect = graph()->NewNode(simplified()->CheckBounds(), index,
2095 : jsgraph()->Constant(Smi::kMaxValue),
2096 926 : effect, control);
2097 : } else {
2098 : // Check that the {index} is in the valid range for the {receiver}.
2099 : index = effect = graph()->NewNode(simplified()->CheckBounds(), index,
2100 21388 : length, effect, control);
2101 : }
2102 :
2103 : // Compute the element access.
2104 : Type* element_type = Type::NonInternal();
2105 : MachineType element_machine_type = MachineType::AnyTagged();
2106 21851 : if (IsFastDoubleElementsKind(elements_kind)) {
2107 : element_type = Type::Number();
2108 : element_machine_type = MachineType::Float64();
2109 20010 : } else if (IsFastSmiElementsKind(elements_kind)) {
2110 : element_type = Type::SignedSmall();
2111 : element_machine_type = MachineType::TaggedSigned();
2112 : }
2113 : ElementAccess element_access = {kTaggedBase, FixedArray::kHeaderSize,
2114 : element_type, element_machine_type,
2115 21851 : kFullWriteBarrier};
2116 :
2117 : // Access the actual element.
2118 21851 : if (access_mode == AccessMode::kLoad) {
2119 : // Compute the real element access type, which includes the hole in case
2120 : // of holey backing stores.
2121 13279 : if (IsHoleyElementsKind(elements_kind)) {
2122 : element_access.type =
2123 3147 : Type::Union(element_type, Type::Hole(), graph()->zone());
2124 : }
2125 13279 : if (elements_kind == FAST_HOLEY_ELEMENTS ||
2126 : elements_kind == FAST_HOLEY_SMI_ELEMENTS) {
2127 2375 : element_access.machine_type = MachineType::AnyTagged();
2128 : }
2129 : // Perform the actual backing store access.
2130 : value = effect =
2131 : graph()->NewNode(simplified()->LoadElement(element_access), elements,
2132 13279 : index, effect, control);
2133 : // Handle loading from holey backing stores correctly, by either mapping
2134 : // the hole to undefined if possible, or deoptimizing otherwise.
2135 13279 : if (elements_kind == FAST_HOLEY_ELEMENTS ||
2136 : elements_kind == FAST_HOLEY_SMI_ELEMENTS) {
2137 : // Check if we are allowed to turn the hole into undefined.
2138 2375 : if (CanTreatHoleAsUndefined(receiver_maps)) {
2139 : // Turn the hole into undefined.
2140 : value = graph()->NewNode(simplified()->ConvertTaggedHoleToUndefined(),
2141 1566 : value);
2142 : } else {
2143 : // Bailout if we see the hole.
2144 : value = effect = graph()->NewNode(simplified()->CheckTaggedHole(),
2145 809 : value, effect, control);
2146 : }
2147 10904 : } else if (elements_kind == FAST_HOLEY_DOUBLE_ELEMENTS) {
2148 : // Perform the hole check on the result.
2149 : CheckFloat64HoleMode mode = CheckFloat64HoleMode::kNeverReturnHole;
2150 : // Check if we are allowed to return the hole directly.
2151 772 : if (CanTreatHoleAsUndefined(receiver_maps)) {
2152 : // Return the signaling NaN hole directly if all uses are truncating.
2153 : mode = CheckFloat64HoleMode::kAllowReturnHole;
2154 : }
2155 : value = effect = graph()->NewNode(simplified()->CheckFloat64Hole(mode),
2156 772 : value, effect, control);
2157 : }
2158 : } else {
2159 : DCHECK_EQ(AccessMode::kStore, access_mode);
2160 8572 : if (IsFastSmiElementsKind(elements_kind)) {
2161 : value = effect =
2162 1828 : graph()->NewNode(simplified()->CheckSmi(), value, effect, control);
2163 6744 : } else if (IsFastDoubleElementsKind(elements_kind)) {
2164 : value = effect = graph()->NewNode(simplified()->CheckNumber(), value,
2165 877 : effect, control);
2166 : // Make sure we do not store signalling NaNs into double arrays.
2167 877 : value = graph()->NewNode(simplified()->NumberSilenceNaN(), value);
2168 : }
2169 :
2170 : // Ensure that copy-on-write backing store is writable.
2171 8572 : if (IsFastSmiOrObjectElementsKind(elements_kind) &&
2172 : store_mode == STORE_NO_TRANSITION_HANDLE_COW) {
2173 : elements = effect =
2174 : graph()->NewNode(simplified()->EnsureWritableFastElements(),
2175 106 : receiver, elements, effect, control);
2176 8466 : } else if (IsGrowStoreMode(store_mode)) {
2177 : // Grow {elements} backing store if necessary. Also updates the
2178 : // "length" property for JSArray {receiver}s, hence there must
2179 : // not be any other check after this operation, as the write
2180 : // to the "length" property is observable.
2181 : GrowFastElementsFlags flags = GrowFastElementsFlag::kNone;
2182 463 : if (receiver_is_jsarray) {
2183 : flags |= GrowFastElementsFlag::kArrayObject;
2184 : }
2185 463 : if (IsHoleyElementsKind(elements_kind)) {
2186 : flags |= GrowFastElementsFlag::kHoleyElements;
2187 : }
2188 463 : if (IsFastDoubleElementsKind(elements_kind)) {
2189 : flags |= GrowFastElementsFlag::kDoubleElements;
2190 : }
2191 : elements = effect = graph()->NewNode(
2192 : simplified()->MaybeGrowFastElements(flags), receiver, elements,
2193 463 : index, length, effect, control);
2194 : }
2195 :
2196 : // Perform the actual element access.
2197 : effect = graph()->NewNode(simplified()->StoreElement(element_access),
2198 8572 : elements, index, value, effect, control);
2199 : }
2200 : }
2201 :
2202 26845 : return ValueEffectControl(value, effect, control);
2203 : }
2204 :
2205 : JSNativeContextSpecialization::ValueEffectControl
2206 1 : JSNativeContextSpecialization::InlineApiCall(
2207 : Node* receiver, Node* context, Node* target, Node* frame_state, Node* value,
2208 : Node* effect, Node* control, Handle<SharedFunctionInfo> shared_info,
2209 2 : Handle<FunctionTemplateInfo> function_template_info) {
2210 : Handle<CallHandlerInfo> call_handler_info = handle(
2211 : CallHandlerInfo::cast(function_template_info->call_code()), isolate());
2212 : Handle<Object> call_data_object(call_handler_info->data(), isolate());
2213 :
2214 : // Only setters have a value.
2215 1 : int const argc = value == nullptr ? 0 : 1;
2216 : // The stub always expects the receiver as the first param on the stack.
2217 : CallApiCallbackStub stub(
2218 : isolate(), argc,
2219 : true /* FunctionTemplateInfo doesn't have an associated context. */);
2220 : CallInterfaceDescriptor call_interface_descriptor =
2221 : stub.GetCallInterfaceDescriptor();
2222 : CallDescriptor* call_descriptor = Linkage::GetStubCallDescriptor(
2223 : isolate(), graph()->zone(), call_interface_descriptor,
2224 1 : call_interface_descriptor.GetStackParameterCount() + argc +
2225 : 1 /* implicit receiver */,
2226 : CallDescriptor::kNeedsFrameState, Operator::kNoProperties,
2227 3 : MachineType::AnyTagged(), 1);
2228 :
2229 1 : Node* data = jsgraph()->Constant(call_data_object);
2230 : ApiFunction function(v8::ToCData<Address>(call_handler_info->callback()));
2231 : Node* function_reference =
2232 : graph()->NewNode(common()->ExternalConstant(ExternalReference(
2233 3 : &function, ExternalReference::DIRECT_API_CALL, isolate())));
2234 2 : Node* code = jsgraph()->HeapConstant(stub.GetCode());
2235 :
2236 : // Add CallApiCallbackStub's register argument as well.
2237 : Node* inputs[11] = {
2238 1 : code, target, data, receiver /* holder */, function_reference, receiver};
2239 1 : int index = 6 + argc;
2240 1 : inputs[index++] = context;
2241 1 : inputs[index++] = frame_state;
2242 1 : inputs[index++] = effect;
2243 1 : inputs[index++] = control;
2244 : // This needs to stay here because of the edge case described in
2245 : // http://crbug.com/675648.
2246 1 : if (value != nullptr) {
2247 0 : inputs[6] = value;
2248 : }
2249 :
2250 : Node* control0;
2251 : Node* effect0;
2252 : Node* value0 = effect0 = control0 =
2253 2 : graph()->NewNode(common()->Call(call_descriptor), index, inputs);
2254 1 : return ValueEffectControl(value0, effect0, control0);
2255 : }
2256 :
2257 112245 : Node* JSNativeContextSpecialization::BuildCheckHeapObject(Node* receiver,
2258 : Node** effect,
2259 : Node* control) {
2260 112245 : switch (receiver->opcode()) {
2261 : case IrOpcode::kHeapConstant:
2262 : case IrOpcode::kJSCreate:
2263 : case IrOpcode::kJSCreateArguments:
2264 : case IrOpcode::kJSCreateArray:
2265 : case IrOpcode::kJSCreateClosure:
2266 : case IrOpcode::kJSCreateIterResultObject:
2267 : case IrOpcode::kJSCreateLiteralArray:
2268 : case IrOpcode::kJSCreateLiteralObject:
2269 : case IrOpcode::kJSCreateLiteralRegExp:
2270 : case IrOpcode::kJSConvertReceiver:
2271 : case IrOpcode::kJSToName:
2272 : case IrOpcode::kJSToString:
2273 : case IrOpcode::kJSToObject:
2274 : case IrOpcode::kJSTypeOf: {
2275 : return receiver;
2276 : }
2277 : default: {
2278 : return *effect = graph()->NewNode(simplified()->CheckHeapObject(),
2279 120252 : receiver, *effect, control);
2280 : }
2281 : }
2282 : }
2283 :
2284 111146 : Node* JSNativeContextSpecialization::BuildCheckMaps(
2285 : Node* receiver, Node* effect, Node* control,
2286 51271 : std::vector<Handle<Map>> const& receiver_maps) {
2287 : HeapObjectMatcher m(receiver);
2288 111146 : if (m.HasValue()) {
2289 : Handle<Map> receiver_map(m.Value()->map(), isolate());
2290 55073 : if (receiver_map->is_stable()) {
2291 102542 : for (Handle<Map> map : receiver_maps) {
2292 51271 : if (map.is_identical_to(receiver_map)) {
2293 51271 : dependencies()->AssumeMapStable(receiver_map);
2294 : return effect;
2295 : }
2296 : }
2297 : }
2298 : }
2299 : ZoneHandleSet<Map> maps;
2300 : CheckMapsFlags flags = CheckMapsFlag::kNone;
2301 182833 : for (Handle<Map> map : receiver_maps) {
2302 63083 : maps.insert(map, graph()->zone());
2303 63083 : if (map->is_migration_target()) {
2304 : flags |= CheckMapsFlag::kTryMigrateInstance;
2305 : }
2306 : }
2307 : return graph()->NewNode(simplified()->CheckMaps(flags, maps), receiver,
2308 119750 : effect, control);
2309 : }
2310 :
2311 257 : Node* JSNativeContextSpecialization::BuildExtendPropertiesBackingStore(
2312 1799 : Handle<Map> map, Node* properties, Node* effect, Node* control) {
2313 : // TODO(bmeurer/jkummerow): Property deletions can undo map transitions
2314 : // while keeping the backing store around, meaning that even though the
2315 : // map might believe that objects have no unused property fields, there
2316 : // might actually be some. It would be nice to not create a new backing
2317 : // store in that case (i.e. when properties->length() >= new_length).
2318 : // However, introducing branches and Phi nodes here would make it more
2319 : // difficult for escape analysis to get rid of the backing stores used
2320 : // for intermediate states of chains of property additions. That makes
2321 : // it unclear what the best approach is here.
2322 : DCHECK_EQ(0, map->unused_property_fields());
2323 : // Compute the length of the old {properties} and the new properties.
2324 514 : int length = map->NextFreePropertyIndex() - map->GetInObjectProperties();
2325 257 : int new_length = length + JSObject::kFieldsAdded;
2326 : // Collect the field values from the {properties}.
2327 : ZoneVector<Node*> values(zone());
2328 257 : values.reserve(new_length);
2329 278 : for (int i = 0; i < length; ++i) {
2330 : Node* value = effect = graph()->NewNode(
2331 : simplified()->LoadField(AccessBuilder::ForFixedArraySlot(i)),
2332 63 : properties, effect, control);
2333 21 : values.push_back(value);
2334 : }
2335 : // Initialize the new fields to undefined.
2336 771 : for (int i = 0; i < JSObject::kFieldsAdded; ++i) {
2337 1542 : values.push_back(jsgraph()->UndefinedConstant());
2338 : }
2339 : // Allocate and initialize the new properties.
2340 : effect = graph()->NewNode(
2341 257 : common()->BeginRegion(RegionObservability::kNotObservable), effect);
2342 : Node* new_properties = effect = graph()->NewNode(
2343 : simplified()->Allocate(Type::OtherInternal(), NOT_TENURED),
2344 514 : jsgraph()->Constant(FixedArray::SizeFor(new_length)), effect, control);
2345 : effect = graph()->NewNode(simplified()->StoreField(AccessBuilder::ForMap()),
2346 : new_properties, jsgraph()->FixedArrayMapConstant(),
2347 771 : effect, control);
2348 : effect = graph()->NewNode(
2349 : simplified()->StoreField(AccessBuilder::ForFixedArrayLength()),
2350 771 : new_properties, jsgraph()->Constant(new_length), effect, control);
2351 1049 : for (int i = 0; i < new_length; ++i) {
2352 : effect = graph()->NewNode(
2353 : simplified()->StoreField(AccessBuilder::ForFixedArraySlot(i)),
2354 3168 : new_properties, values[i], effect, control);
2355 : }
2356 514 : return graph()->NewNode(common()->FinishRegion(), new_properties, effect);
2357 : }
2358 :
2359 20304 : void JSNativeContextSpecialization::AssumePrototypesStable(
2360 20918 : std::vector<Handle<Map>> const& receiver_maps, Handle<JSObject> holder) {
2361 : // Determine actual holder and perform prototype chain checks.
2362 61526 : for (auto map : receiver_maps) {
2363 : // Perform the implicit ToObject for primitives here.
2364 : // Implemented according to ES6 section 7.3.2 GetV (V, P).
2365 : Handle<JSFunction> constructor;
2366 20918 : if (Map::GetConstructorFunction(map, native_context())
2367 41836 : .ToHandle(&constructor)) {
2368 2589 : map = handle(constructor->initial_map(), isolate());
2369 : }
2370 20918 : dependencies()->AssumePrototypeMapsStable(map, holder);
2371 : }
2372 20304 : }
2373 :
2374 3147 : bool JSNativeContextSpecialization::CanTreatHoleAsUndefined(
2375 4763 : std::vector<Handle<Map>> const& receiver_maps) {
2376 : // Check if the array prototype chain is intact.
2377 3147 : if (!isolate()->IsFastArrayConstructorPrototypeChainIntact()) return false;
2378 :
2379 : // Make sure both the initial Array and Object prototypes are stable.
2380 : Handle<JSObject> initial_array_prototype(
2381 : native_context()->initial_array_prototype(), isolate());
2382 : Handle<JSObject> initial_object_prototype(
2383 : native_context()->initial_object_prototype(), isolate());
2384 6130 : if (!initial_array_prototype->map()->is_stable() ||
2385 : !initial_object_prototype->map()->is_stable()) {
2386 : return false;
2387 : }
2388 :
2389 : // Check if all {receiver_maps} either have the initial Array.prototype
2390 : // or the initial Object.prototype as their prototype, as those are
2391 : // guarded by the array protector cell.
2392 8593 : for (Handle<Map> map : receiver_maps) {
2393 4536 : if (map->prototype() != *initial_array_prototype &&
2394 : map->prototype() != *initial_object_prototype) {
2395 : return false;
2396 : }
2397 : }
2398 :
2399 : // Install code dependencies on the prototype maps.
2400 7250 : for (Handle<Map> map : receiver_maps) {
2401 2487 : dependencies()->AssumePrototypeMapsStable(map, initial_object_prototype);
2402 : }
2403 :
2404 : // Install code dependency on the array protector cell.
2405 : dependencies()->AssumePropertyCell(factory()->array_protector());
2406 2276 : return true;
2407 : }
2408 :
2409 : JSNativeContextSpecialization::InferHasInPrototypeChainResult
2410 1000 : JSNativeContextSpecialization::InferHasInPrototypeChain(
2411 : Node* receiver, Node* effect, Handle<JSReceiver> prototype) {
2412 : ZoneHandleSet<Map> receiver_maps;
2413 : NodeProperties::InferReceiverMapsResult result =
2414 1000 : NodeProperties::InferReceiverMaps(receiver, effect, &receiver_maps);
2415 1000 : if (result == NodeProperties::kNoReceiverMaps) return kMayBeInPrototypeChain;
2416 :
2417 : // Check if either all or none of the {receiver_maps} have the given
2418 : // {prototype} in their prototype chain.
2419 : bool all = true;
2420 : bool none = true;
2421 36 : for (size_t i = 0; i < receiver_maps.size(); ++i) {
2422 : Handle<Map> receiver_map = receiver_maps[i];
2423 12 : if (receiver_map->instance_type() <= LAST_SPECIAL_RECEIVER_TYPE) {
2424 : return kMayBeInPrototypeChain;
2425 : }
2426 12 : if (result == NodeProperties::kUnreliableReceiverMaps) {
2427 : // In case of an unreliable {result} we need to ensure that all
2428 : // {receiver_maps} are stable, because otherwise we cannot trust
2429 : // the {receiver_maps} information, since arbitrary side-effects
2430 : // may have happened.
2431 5 : if (!receiver_map->is_stable()) {
2432 : return kMayBeInPrototypeChain;
2433 : }
2434 : }
2435 15 : for (PrototypeIterator j(receiver_map);; j.Advance()) {
2436 15 : if (j.IsAtEnd()) {
2437 : all = false;
2438 : break;
2439 : }
2440 : Handle<JSReceiver> const current =
2441 : PrototypeIterator::GetCurrent<JSReceiver>(j);
2442 14 : if (current.is_identical_to(prototype)) {
2443 : none = false;
2444 : break;
2445 : }
2446 6 : if (!current->map()->is_stable() ||
2447 3 : current->map()->instance_type() <= LAST_SPECIAL_RECEIVER_TYPE) {
2448 : return kMayBeInPrototypeChain;
2449 : }
2450 : }
2451 : }
2452 : DCHECK_IMPLIES(all, !none);
2453 : DCHECK_IMPLIES(none, !all);
2454 :
2455 12 : if (all) return kIsInPrototypeChain;
2456 1 : if (none) return kIsNotInPrototypeChain;
2457 0 : return kMayBeInPrototypeChain;
2458 : }
2459 :
2460 147460 : bool JSNativeContextSpecialization::ExtractReceiverMaps(
2461 : Node* receiver, Node* effect, FeedbackNexus const& nexus,
2462 2240 : MapHandleList* receiver_maps) {
2463 : DCHECK_EQ(0, receiver_maps->length());
2464 : // See if we can infer a concrete type for the {receiver}.
2465 147460 : if (InferReceiverMaps(receiver, effect, receiver_maps)) {
2466 : // We can assume that the {receiver} still has the infered {receiver_maps}.
2467 : return true;
2468 : }
2469 : // Try to extract some maps from the {nexus}.
2470 75774 : if (nexus.ExtractMaps(receiver_maps) != 0) {
2471 : // Try to filter impossible candidates based on infered root map.
2472 : Handle<Map> receiver_map;
2473 89288 : if (InferReceiverRootMap(receiver).ToHandle(&receiver_map)) {
2474 6752 : for (int i = receiver_maps->length(); --i >= 0;) {
2475 4544 : if (receiver_maps->at(i)->FindRootMap() != *receiver_map) {
2476 32 : receiver_maps->Remove(i);
2477 : }
2478 : }
2479 : }
2480 : return true;
2481 : }
2482 : return false;
2483 : }
2484 :
2485 147460 : bool JSNativeContextSpecialization::InferReceiverMaps(
2486 : Node* receiver, Node* effect, MapHandleList* receiver_maps) {
2487 : ZoneHandleSet<Map> maps;
2488 : NodeProperties::InferReceiverMapsResult result =
2489 147460 : NodeProperties::InferReceiverMaps(receiver, effect, &maps);
2490 147460 : if (result == NodeProperties::kReliableReceiverMaps) {
2491 52321 : for (size_t i = 0; i < maps.size(); ++i) {
2492 17746 : receiver_maps->Add(maps[i]);
2493 : }
2494 : return true;
2495 130631 : } else if (result == NodeProperties::kUnreliableReceiverMaps) {
2496 : // For untrusted receiver maps, we can still use the information
2497 : // if the maps are stable.
2498 169824 : for (size_t i = 0; i < maps.size(); ++i) {
2499 59854 : if (!maps[i]->is_stable()) return false;
2500 : }
2501 164741 : for (size_t i = 0; i < maps.size(); ++i) {
2502 54942 : receiver_maps->Add(maps[i]);
2503 : }
2504 : return true;
2505 : }
2506 : return false;
2507 : }
2508 :
2509 44644 : MaybeHandle<Map> JSNativeContextSpecialization::InferReceiverRootMap(
2510 : Node* receiver) {
2511 : HeapObjectMatcher m(receiver);
2512 44644 : if (m.HasValue()) {
2513 2025 : return handle(m.Value()->map()->FindRootMap(), isolate());
2514 42619 : } else if (m.IsJSCreate()) {
2515 : HeapObjectMatcher mtarget(m.InputAt(0));
2516 : HeapObjectMatcher mnewtarget(m.InputAt(1));
2517 215 : if (mtarget.HasValue() && mnewtarget.HasValue()) {
2518 : Handle<JSFunction> constructor =
2519 : Handle<JSFunction>::cast(mtarget.Value());
2520 215 : if (constructor->has_initial_map()) {
2521 : Handle<Map> initial_map(constructor->initial_map(), isolate());
2522 215 : if (initial_map->constructor_or_backpointer() == *mnewtarget.Value()) {
2523 : DCHECK_EQ(*initial_map, initial_map->FindRootMap());
2524 : return initial_map;
2525 : }
2526 : }
2527 : }
2528 : }
2529 : return MaybeHandle<Map>();
2530 : }
2531 :
2532 560656 : bool JSNativeContextSpecialization::LookupInScriptContextTable(
2533 : Handle<Name> name, ScriptContextTableLookupResult* result) {
2534 560656 : if (!name->IsString()) return false;
2535 : Handle<ScriptContextTable> script_context_table(
2536 : global_object()->native_context()->script_context_table(), isolate());
2537 : ScriptContextTable::LookupResult lookup_result;
2538 560656 : if (!ScriptContextTable::Lookup(script_context_table,
2539 560656 : Handle<String>::cast(name), &lookup_result)) {
2540 : return false;
2541 : }
2542 : Handle<Context> script_context = ScriptContextTable::GetContext(
2543 6598 : script_context_table, lookup_result.context_index);
2544 6598 : result->context = script_context;
2545 6598 : result->immutable = lookup_result.mode == CONST;
2546 6598 : result->index = lookup_result.slot_index;
2547 6598 : return true;
2548 : }
2549 :
2550 649952 : Graph* JSNativeContextSpecialization::graph() const {
2551 650970 : return jsgraph()->graph();
2552 : }
2553 :
2554 1168249 : Isolate* JSNativeContextSpecialization::isolate() const {
2555 1168250 : return jsgraph()->isolate();
2556 : }
2557 :
2558 0 : Factory* JSNativeContextSpecialization::factory() const {
2559 0 : return isolate()->factory();
2560 : }
2561 :
2562 0 : MachineOperatorBuilder* JSNativeContextSpecialization::machine() const {
2563 0 : return jsgraph()->machine();
2564 : }
2565 :
2566 84112 : CommonOperatorBuilder* JSNativeContextSpecialization::common() const {
2567 84112 : return jsgraph()->common();
2568 : }
2569 :
2570 10903 : JSOperatorBuilder* JSNativeContextSpecialization::javascript() const {
2571 10903 : return jsgraph()->javascript();
2572 : }
2573 :
2574 368210 : SimplifiedOperatorBuilder* JSNativeContextSpecialization::simplified() const {
2575 375949 : return jsgraph()->simplified();
2576 : }
2577 :
2578 : } // namespace compiler
2579 : } // namespace internal
2580 : } // namespace v8
|