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/api-inl.h"
9 : #include "src/code-factory.h"
10 : #include "src/compiler/access-builder.h"
11 : #include "src/compiler/access-info.h"
12 : #include "src/compiler/allocation-builder.h"
13 : #include "src/compiler/compilation-dependencies.h"
14 : #include "src/compiler/js-graph.h"
15 : #include "src/compiler/js-operator.h"
16 : #include "src/compiler/linkage.h"
17 : #include "src/compiler/node-matchers.h"
18 : #include "src/compiler/property-access-builder.h"
19 : #include "src/compiler/type-cache.h"
20 : #include "src/dtoa.h"
21 : #include "src/feedback-vector.h"
22 : #include "src/field-index-inl.h"
23 : #include "src/isolate-inl.h"
24 : #include "src/objects/heap-number.h"
25 : #include "src/objects/js-array-buffer-inl.h"
26 : #include "src/objects/js-array-inl.h"
27 : #include "src/objects/templates.h"
28 : #include "src/string-constants.h"
29 : #include "src/vector-slot-pair.h"
30 :
31 : namespace v8 {
32 : namespace internal {
33 : namespace compiler {
34 :
35 : // This is needed for gc_mole which will compile this file without the full set
36 : // of GN defined macros.
37 : #ifndef V8_TYPED_ARRAY_MAX_SIZE_IN_HEAP
38 : #define V8_TYPED_ARRAY_MAX_SIZE_IN_HEAP 64
39 : #endif
40 :
41 : namespace {
42 :
43 133507 : bool HasNumberMaps(JSHeapBroker* broker, MapHandles const& maps) {
44 273220 : for (auto map : maps) {
45 : MapRef map_ref(broker, map);
46 139892 : if (map_ref.IsHeapNumberMap()) return true;
47 : }
48 : return false;
49 : }
50 :
51 15781 : bool HasOnlyJSArrayMaps(JSHeapBroker* broker, MapHandles const& maps) {
52 31004 : for (auto map : maps) {
53 : MapRef map_ref(broker, map);
54 16979 : if (!map_ref.IsJSArrayMap()) return false;
55 : }
56 : return true;
57 : }
58 :
59 : } // namespace
60 :
61 463856 : JSNativeContextSpecialization::JSNativeContextSpecialization(
62 : Editor* editor, JSGraph* jsgraph, JSHeapBroker* broker, Flags flags,
63 : Handle<Context> native_context, CompilationDependencies* dependencies,
64 : Zone* zone, Zone* shared_zone)
65 : : AdvancedReducer(editor),
66 : jsgraph_(jsgraph),
67 : broker_(broker),
68 : flags_(flags),
69 : global_object_(native_context->global_object(), jsgraph->isolate()),
70 : global_proxy_(native_context->global_proxy(), jsgraph->isolate()),
71 : dependencies_(dependencies),
72 : zone_(zone),
73 : shared_zone_(shared_zone),
74 2319343 : type_cache_(TypeCache::Get()) {}
75 :
76 35260492 : Reduction JSNativeContextSpecialization::Reduce(Node* node) {
77 35260492 : switch (node->opcode()) {
78 : case IrOpcode::kJSAdd:
79 92664 : return ReduceJSAdd(node);
80 : case IrOpcode::kJSAsyncFunctionEnter:
81 1250 : return ReduceJSAsyncFunctionEnter(node);
82 : case IrOpcode::kJSAsyncFunctionReject:
83 1204 : return ReduceJSAsyncFunctionReject(node);
84 : case IrOpcode::kJSAsyncFunctionResolve:
85 1112 : return ReduceJSAsyncFunctionResolve(node);
86 : case IrOpcode::kJSGetSuperConstructor:
87 2438 : return ReduceJSGetSuperConstructor(node);
88 : case IrOpcode::kJSInstanceOf:
89 3800 : return ReduceJSInstanceOf(node);
90 : case IrOpcode::kJSHasInPrototypeChain:
91 889 : return ReduceJSHasInPrototypeChain(node);
92 : case IrOpcode::kJSOrdinaryHasInstance:
93 1064 : return ReduceJSOrdinaryHasInstance(node);
94 : case IrOpcode::kJSPromiseResolve:
95 190 : return ReduceJSPromiseResolve(node);
96 : case IrOpcode::kJSResolvePromise:
97 1047 : return ReduceJSResolvePromise(node);
98 : case IrOpcode::kJSLoadContext:
99 545005 : return ReduceJSLoadContext(node);
100 : case IrOpcode::kJSLoadGlobal:
101 1000369 : return ReduceJSLoadGlobal(node);
102 : case IrOpcode::kJSStoreGlobal:
103 219047 : return ReduceJSStoreGlobal(node);
104 : case IrOpcode::kJSLoadNamed:
105 544244 : return ReduceJSLoadNamed(node);
106 : case IrOpcode::kJSStoreNamed:
107 106481 : return ReduceJSStoreNamed(node);
108 : case IrOpcode::kJSHasProperty:
109 1586 : return ReduceJSHasProperty(node);
110 : case IrOpcode::kJSLoadProperty:
111 45066 : return ReduceJSLoadProperty(node);
112 : case IrOpcode::kJSStoreProperty:
113 12435 : return ReduceJSStoreProperty(node);
114 : case IrOpcode::kJSStoreNamedOwn:
115 36034 : return ReduceJSStoreNamedOwn(node);
116 : case IrOpcode::kJSStoreDataPropertyInLiteral:
117 540 : return ReduceJSStoreDataPropertyInLiteral(node);
118 : case IrOpcode::kJSStoreInArrayLiteral:
119 49848 : return ReduceJSStoreInArrayLiteral(node);
120 : case IrOpcode::kJSToObject:
121 1999 : return ReduceJSToObject(node);
122 : case IrOpcode::kJSToString:
123 2790 : return ReduceJSToString(node);
124 : default:
125 : break;
126 : }
127 : return NoChange();
128 : }
129 :
130 : // static
131 185330 : base::Optional<size_t> JSNativeContextSpecialization::GetMaxStringLength(
132 : JSHeapBroker* broker, Node* node) {
133 185330 : if (node->opcode() == IrOpcode::kDelayedStringConstant) {
134 3776 : return StringConstantBaseOf(node->op())->GetMaxStringConstantLength();
135 : }
136 :
137 : HeapObjectMatcher matcher(node);
138 226340 : if (matcher.HasValue() && matcher.Ref(broker).IsString()) {
139 44358 : StringRef input = matcher.Ref(broker).AsString();
140 88716 : return input.length();
141 : }
142 :
143 : NumberMatcher number_matcher(node);
144 137196 : if (number_matcher.HasValue()) {
145 19919 : return kBase10MaximalLength + 1;
146 : }
147 :
148 : // We don't support objects with possibly monkey-patched prototype.toString
149 : // as it might have side-effects, so we shouldn't attempt lowering them.
150 117277 : return base::nullopt;
151 : }
152 :
153 2790 : Reduction JSNativeContextSpecialization::ReduceJSToString(Node* node) {
154 : DCHECK_EQ(IrOpcode::kJSToString, node->opcode());
155 : Node* const input = node->InputAt(0);
156 : Reduction reduction;
157 :
158 : HeapObjectMatcher matcher(input);
159 3441 : if (matcher.HasValue() && matcher.Ref(broker()).IsString()) {
160 : reduction = Changed(input); // JSToString(x:string) => x
161 : ReplaceWithValue(node, reduction.replacement());
162 646 : return reduction;
163 : }
164 :
165 : // TODO(turbofan): This optimization is weaker than what we used to have
166 : // in js-typed-lowering for OrderedNumbers. We don't have types here though,
167 : // so alternative approach should be designed if this causes performance
168 : // regressions and the stronger optimization should be re-implemented.
169 : NumberMatcher number_matcher(input);
170 2144 : if (number_matcher.HasValue()) {
171 : const StringConstantBase* base =
172 : new (shared_zone()) NumberToStringConstant(number_matcher.Value());
173 : reduction =
174 9 : Replace(graph()->NewNode(common()->DelayedStringConstant(base)));
175 : ReplaceWithValue(node, reduction.replacement());
176 9 : return reduction;
177 : }
178 :
179 : return NoChange();
180 : }
181 :
182 : const StringConstantBase*
183 10038 : JSNativeContextSpecialization::CreateDelayedStringConstant(Node* node) {
184 10038 : if (node->opcode() == IrOpcode::kDelayedStringConstant) {
185 3115 : return StringConstantBaseOf(node->op());
186 : } else {
187 : NumberMatcher number_matcher(node);
188 6923 : if (number_matcher.HasValue()) {
189 260 : return new (shared_zone()) NumberToStringConstant(number_matcher.Value());
190 : } else {
191 : HeapObjectMatcher matcher(node);
192 13326 : if (matcher.HasValue() && matcher.Ref(broker()).IsString()) {
193 6663 : StringRef s = matcher.Ref(broker()).AsString();
194 : return new (shared_zone())
195 13326 : StringLiteral(s.object(), static_cast<size_t>(s.length()));
196 : } else {
197 0 : UNREACHABLE();
198 : }
199 : }
200 : }
201 : }
202 :
203 : namespace {
204 7732 : bool IsStringConstant(JSHeapBroker* broker, Node* node) {
205 7732 : if (node->opcode() == IrOpcode::kDelayedStringConstant) {
206 : return true;
207 : }
208 :
209 : HeapObjectMatcher matcher(node);
210 6545 : return matcher.HasValue() && matcher.Ref(broker).IsString();
211 : }
212 : } // namespace
213 :
214 1250 : Reduction JSNativeContextSpecialization::ReduceJSAsyncFunctionEnter(
215 : Node* node) {
216 : DCHECK_EQ(IrOpcode::kJSAsyncFunctionEnter, node->opcode());
217 1250 : Node* closure = NodeProperties::GetValueInput(node, 0);
218 1250 : Node* receiver = NodeProperties::GetValueInput(node, 1);
219 1250 : Node* context = NodeProperties::GetContextInput(node);
220 1250 : Node* frame_state = NodeProperties::GetFrameStateInput(node);
221 1250 : Node* effect = NodeProperties::GetEffectInput(node);
222 1250 : Node* control = NodeProperties::GetControlInput(node);
223 :
224 1250 : if (!dependencies()->DependOnPromiseHookProtector()) return NoChange();
225 :
226 : // Create the promise for the async function.
227 : Node* promise = effect =
228 1127 : graph()->NewNode(javascript()->CreatePromise(), context, effect);
229 :
230 : // Create the JSAsyncFunctionObject based on the SharedFunctionInfo
231 : // extracted from the top-most frame in {frame_state}.
232 : Handle<SharedFunctionInfo> shared =
233 1127 : FrameStateInfoOf(frame_state->op()).shared_info().ToHandleChecked();
234 : DCHECK(shared->is_compiled());
235 1127 : int register_count = shared->internal_formal_parameter_count() +
236 2254 : shared->GetBytecodeArray()->register_count();
237 : Node* value = effect =
238 1127 : graph()->NewNode(javascript()->CreateAsyncFunctionObject(register_count),
239 : closure, receiver, promise, context, effect, control);
240 : ReplaceWithValue(node, value, effect, control);
241 : return Replace(value);
242 : }
243 :
244 1204 : Reduction JSNativeContextSpecialization::ReduceJSAsyncFunctionReject(
245 : Node* node) {
246 : DCHECK_EQ(IrOpcode::kJSAsyncFunctionReject, node->opcode());
247 1204 : Node* async_function_object = NodeProperties::GetValueInput(node, 0);
248 1204 : Node* reason = NodeProperties::GetValueInput(node, 1);
249 1204 : Node* context = NodeProperties::GetContextInput(node);
250 1204 : Node* frame_state = NodeProperties::GetFrameStateInput(node);
251 1204 : Node* effect = NodeProperties::GetEffectInput(node);
252 1204 : Node* control = NodeProperties::GetControlInput(node);
253 :
254 1204 : if (!dependencies()->DependOnPromiseHookProtector()) return NoChange();
255 :
256 : // Load the promise from the {async_function_object}.
257 1084 : Node* promise = effect = graph()->NewNode(
258 2168 : simplified()->LoadField(AccessBuilder::ForJSAsyncFunctionObjectPromise()),
259 : async_function_object, effect, control);
260 :
261 : // Create a nested frame state inside the current method's most-recent
262 : // {frame_state} that will ensure that lazy deoptimizations at this
263 : // point will still return the {promise} instead of the result of the
264 : // JSRejectPromise operation (which yields undefined).
265 1084 : Node* parameters[] = {promise};
266 : frame_state = CreateStubBuiltinContinuationFrameState(
267 : jsgraph(), Builtins::kAsyncFunctionLazyDeoptContinuation, context,
268 : parameters, arraysize(parameters), frame_state,
269 1084 : ContinuationFrameStateMode::LAZY);
270 :
271 : // Disable the additional debug event for the rejection since a
272 : // debug event already happend for the exception that got us here.
273 1084 : Node* debug_event = jsgraph()->FalseConstant();
274 1084 : effect = graph()->NewNode(javascript()->RejectPromise(), promise, reason,
275 : debug_event, context, frame_state, effect, control);
276 : ReplaceWithValue(node, promise, effect, control);
277 : return Replace(promise);
278 : }
279 :
280 1112 : Reduction JSNativeContextSpecialization::ReduceJSAsyncFunctionResolve(
281 : Node* node) {
282 : DCHECK_EQ(IrOpcode::kJSAsyncFunctionResolve, node->opcode());
283 1112 : Node* async_function_object = NodeProperties::GetValueInput(node, 0);
284 1112 : Node* value = NodeProperties::GetValueInput(node, 1);
285 1112 : Node* context = NodeProperties::GetContextInput(node);
286 1112 : Node* frame_state = NodeProperties::GetFrameStateInput(node);
287 1112 : Node* effect = NodeProperties::GetEffectInput(node);
288 1112 : Node* control = NodeProperties::GetControlInput(node);
289 :
290 1112 : if (!dependencies()->DependOnPromiseHookProtector()) return NoChange();
291 :
292 : // Load the promise from the {async_function_object}.
293 1001 : Node* promise = effect = graph()->NewNode(
294 2002 : simplified()->LoadField(AccessBuilder::ForJSAsyncFunctionObjectPromise()),
295 : async_function_object, effect, control);
296 :
297 : // Create a nested frame state inside the current method's most-recent
298 : // {frame_state} that will ensure that lazy deoptimizations at this
299 : // point will still return the {promise} instead of the result of the
300 : // JSResolvePromise operation (which yields undefined).
301 1001 : Node* parameters[] = {promise};
302 : frame_state = CreateStubBuiltinContinuationFrameState(
303 : jsgraph(), Builtins::kAsyncFunctionLazyDeoptContinuation, context,
304 : parameters, arraysize(parameters), frame_state,
305 1001 : ContinuationFrameStateMode::LAZY);
306 :
307 1001 : effect = graph()->NewNode(javascript()->ResolvePromise(), promise, value,
308 : context, frame_state, effect, control);
309 : ReplaceWithValue(node, promise, effect, control);
310 : return Replace(promise);
311 : }
312 :
313 92664 : Reduction JSNativeContextSpecialization::ReduceJSAdd(Node* node) {
314 : // TODO(turbofan): This has to run together with the inlining and
315 : // native context specialization to be able to leverage the string
316 : // constant-folding for optimizing property access, but we should
317 : // nevertheless find a better home for this at some point.
318 : DCHECK_EQ(IrOpcode::kJSAdd, node->opcode());
319 :
320 : Node* const lhs = node->InputAt(0);
321 : Node* const rhs = node->InputAt(1);
322 :
323 92664 : base::Optional<size_t> lhs_len = GetMaxStringLength(broker(), lhs);
324 92664 : base::Optional<size_t> rhs_len = GetMaxStringLength(broker(), rhs);
325 92664 : if (!lhs_len || !rhs_len) {
326 : return NoChange();
327 : }
328 :
329 : // Fold into DelayedStringConstant if at least one of the parameters is a
330 : // string constant and the addition won't throw due to too long result.
331 19077 : if (*lhs_len + *rhs_len <= String::kMaxLength &&
332 7732 : (IsStringConstant(broker(), lhs) || IsStringConstant(broker(), rhs))) {
333 5019 : const StringConstantBase* left = CreateDelayedStringConstant(lhs);
334 5019 : const StringConstantBase* right = CreateDelayedStringConstant(rhs);
335 : const StringConstantBase* cons =
336 : new (shared_zone()) StringCons(left, right);
337 :
338 5019 : Node* reduced = graph()->NewNode(common()->DelayedStringConstant(cons));
339 : ReplaceWithValue(node, reduced);
340 : return Replace(reduced);
341 : }
342 :
343 : return NoChange();
344 : }
345 :
346 2438 : Reduction JSNativeContextSpecialization::ReduceJSGetSuperConstructor(
347 : Node* node) {
348 : DCHECK_EQ(IrOpcode::kJSGetSuperConstructor, node->opcode());
349 2438 : Node* constructor = NodeProperties::GetValueInput(node, 0);
350 :
351 : // Check if the input is a known JSFunction.
352 : HeapObjectMatcher m(constructor);
353 2438 : if (!m.HasValue()) return NoChange();
354 2413 : JSFunctionRef function = m.Ref(broker()).AsJSFunction();
355 2413 : MapRef function_map = function.map();
356 : // TODO(neis): Remove SerializePrototype call once brokerization is complete.
357 2413 : function_map.SerializePrototype();
358 2413 : ObjectRef function_prototype = function_map.prototype();
359 :
360 : // We can constant-fold the super constructor access if the
361 : // {function}s map is stable, i.e. we can use a code dependency
362 : // to guard against [[Prototype]] changes of {function}.
363 7239 : if (function_map.is_stable() && function_prototype.IsHeapObject() &&
364 7181 : function_prototype.AsHeapObject().map().is_constructor()) {
365 2362 : dependencies()->DependOnStableMap(function_map);
366 2362 : Node* value = jsgraph()->Constant(function_prototype);
367 : ReplaceWithValue(node, value);
368 : return Replace(value);
369 : }
370 :
371 : return NoChange();
372 : }
373 :
374 3807 : Reduction JSNativeContextSpecialization::ReduceJSInstanceOf(Node* node) {
375 : DCHECK_EQ(IrOpcode::kJSInstanceOf, node->opcode());
376 3807 : FeedbackParameter const& p = FeedbackParameterOf(node->op());
377 3807 : Node* object = NodeProperties::GetValueInput(node, 0);
378 3807 : Node* constructor = NodeProperties::GetValueInput(node, 1);
379 3807 : Node* context = NodeProperties::GetContextInput(node);
380 3807 : Node* effect = NodeProperties::GetEffectInput(node);
381 3807 : Node* frame_state = NodeProperties::GetFrameStateInput(node);
382 3807 : Node* control = NodeProperties::GetControlInput(node);
383 :
384 : // Check if the right hand side is a known {receiver}, or
385 : // we have feedback from the InstanceOfIC.
386 : Handle<JSObject> receiver;
387 : HeapObjectMatcher m(constructor);
388 4789 : if (m.HasValue() && m.Value()->IsJSObject()) {
389 : receiver = Handle<JSObject>::cast(m.Value());
390 2835 : } else if (p.feedback().IsValid()) {
391 : FeedbackNexus nexus(p.feedback().vector(), p.feedback().slot());
392 5670 : if (!nexus.GetConstructorFeedback().ToHandle(&receiver)) return NoChange();
393 : } else {
394 : return NoChange();
395 : }
396 : Handle<Map> receiver_map(receiver->map(), isolate());
397 :
398 : // Compute property access info for @@hasInstance on the constructor.
399 1003 : PropertyAccessInfo access_info;
400 : AccessInfoFactory access_info_factory(broker(), dependencies(),
401 1003 : graph()->zone());
402 1003 : if (!access_info_factory.ComputePropertyAccessInfo(
403 : receiver_map, factory()->has_instance_symbol(), AccessMode::kLoad,
404 : &access_info)) {
405 : return NoChange();
406 : }
407 : DCHECK_EQ(access_info.receiver_maps().size(), 1);
408 : DCHECK_EQ(access_info.receiver_maps()[0].address(), receiver_map.address());
409 :
410 : PropertyAccessBuilder access_builder(jsgraph(), broker(), dependencies());
411 :
412 987 : if (access_info.IsNotFound()) {
413 : // If there's no @@hasInstance handler, the OrdinaryHasInstance operation
414 : // takes over, but that requires the constructor to be callable.
415 15 : if (!receiver_map->is_callable()) return NoChange();
416 :
417 : // Determine actual holder and perform prototype chain checks.
418 : Handle<JSObject> holder;
419 15 : if (access_info.holder().ToHandle(&holder)) {
420 0 : dependencies()->DependOnStablePrototypeChains(
421 0 : access_info.receiver_maps(), JSObjectRef(broker(), holder));
422 : }
423 :
424 : // Monomorphic property access.
425 : constructor =
426 15 : access_builder.BuildCheckHeapObject(constructor, &effect, control);
427 : access_builder.BuildCheckMaps(constructor, &effect, control,
428 15 : access_info.receiver_maps());
429 :
430 : // Lower to OrdinaryHasInstance(C, O).
431 15 : NodeProperties::ReplaceValueInput(node, constructor, 0);
432 15 : NodeProperties::ReplaceValueInput(node, object, 1);
433 15 : NodeProperties::ReplaceEffectInput(node, effect);
434 15 : NodeProperties::ChangeOp(node, javascript()->OrdinaryHasInstance());
435 15 : Reduction const reduction = ReduceJSOrdinaryHasInstance(node);
436 15 : return reduction.Changed() ? reduction : Changed(node);
437 : }
438 :
439 972 : if (access_info.IsDataConstant() || access_info.IsDataConstantField()) {
440 : // Determine actual holder.
441 : Handle<JSObject> holder;
442 : bool found_on_proto = access_info.holder().ToHandle(&holder);
443 956 : if (!found_on_proto) holder = receiver;
444 :
445 : Handle<Object> constant;
446 956 : if (access_info.IsDataConstant()) {
447 : DCHECK(!FLAG_track_constant_fields);
448 : constant = access_info.constant();
449 : } else {
450 : DCHECK(FLAG_track_constant_fields);
451 : DCHECK(access_info.IsDataConstantField());
452 956 : FieldIndex field_index = access_info.field_index();
453 : constant = JSObject::FastPropertyAt(holder, Representation::Tagged(),
454 956 : field_index);
455 956 : if (!constant->IsCallable()) {
456 1 : return NoChange();
457 : }
458 :
459 : // Install dependency on constness. Unfortunately, access_info does not
460 : // track descriptor index, so we have to search for it.
461 : MapRef holder_map(broker(), handle(holder->map(), isolate()));
462 : Handle<DescriptorArray> descriptors(
463 1910 : holder_map.object()->instance_descriptors(), isolate());
464 1910 : int descriptor_index = descriptors->Search(
465 1910 : *(factory()->has_instance_symbol()), *(holder_map.object()));
466 955 : CHECK_NE(descriptor_index, DescriptorArray::kNotFound);
467 955 : holder_map.SerializeOwnDescriptors();
468 955 : if (dependencies()->DependOnFieldConstness(
469 : holder_map, descriptor_index) != PropertyConstness::kConst) {
470 : return NoChange();
471 : }
472 : }
473 :
474 955 : if (found_on_proto) {
475 924 : dependencies()->DependOnStablePrototypeChains(
476 924 : access_info.receiver_maps(), JSObjectRef(broker(), holder));
477 : }
478 :
479 : DCHECK(constant->IsCallable());
480 :
481 : // Check that {constructor} is actually {receiver}.
482 : constructor =
483 955 : access_builder.BuildCheckValue(constructor, &effect, control, receiver);
484 :
485 : // Monomorphic property access.
486 : access_builder.BuildCheckMaps(constructor, &effect, control,
487 955 : access_info.receiver_maps());
488 :
489 : // Create a nested frame state inside the current method's most-recent frame
490 : // state that will ensure that deopts that happen after this point will not
491 : // fallback to the last Checkpoint--which would completely re-execute the
492 : // instanceof logic--but rather create an activation of a version of the
493 : // ToBoolean stub that finishes the remaining work of instanceof and returns
494 : // to the caller without duplicating side-effects upon a lazy deopt.
495 : Node* continuation_frame_state = CreateStubBuiltinContinuationFrameState(
496 : jsgraph(), Builtins::kToBooleanLazyDeoptContinuation, context, nullptr,
497 955 : 0, frame_state, ContinuationFrameStateMode::LAZY);
498 :
499 : // Call the @@hasInstance handler.
500 955 : Node* target = jsgraph()->Constant(constant);
501 955 : node->InsertInput(graph()->zone(), 0, target);
502 955 : node->ReplaceInput(1, constructor);
503 955 : node->ReplaceInput(2, object);
504 955 : node->ReplaceInput(4, continuation_frame_state);
505 955 : node->ReplaceInput(5, effect);
506 2865 : NodeProperties::ChangeOp(
507 : node, javascript()->Call(3, CallFrequency(), VectorSlotPair(),
508 955 : ConvertReceiverMode::kNotNullOrUndefined));
509 :
510 : // Rewire the value uses of {node} to ToBoolean conversion of the result.
511 955 : Node* value = graph()->NewNode(simplified()->ToBoolean(), node);
512 10317 : for (Edge edge : node->use_edges()) {
513 6601 : if (NodeProperties::IsValueEdge(edge) && edge.from() != value) {
514 965 : edge.UpdateTo(value);
515 : Revisit(edge.from());
516 : }
517 : }
518 : return Changed(node);
519 : }
520 :
521 : return NoChange();
522 : }
523 :
524 : JSNativeContextSpecialization::InferHasInPrototypeChainResult
525 1647 : JSNativeContextSpecialization::InferHasInPrototypeChain(
526 : Node* receiver, Node* effect, Handle<HeapObject> prototype) {
527 : ZoneHandleSet<Map> receiver_maps;
528 : NodeProperties::InferReceiverMapsResult result =
529 : NodeProperties::InferReceiverMaps(broker(), receiver, effect,
530 1647 : &receiver_maps);
531 1647 : if (result == NodeProperties::kNoReceiverMaps) return kMayBeInPrototypeChain;
532 :
533 : // Check if either all or none of the {receiver_maps} have the given
534 : // {prototype} in their prototype chain.
535 : bool all = true;
536 : bool none = true;
537 370 : for (size_t i = 0; i < receiver_maps.size(); ++i) {
538 : Handle<Map> receiver_map = receiver_maps[i];
539 298 : if (receiver_map->instance_type() <= LAST_SPECIAL_RECEIVER_TYPE) {
540 : return kMayBeInPrototypeChain;
541 : }
542 44 : if (result == NodeProperties::kUnreliableReceiverMaps) {
543 : // In case of an unreliable {result} we need to ensure that all
544 : // {receiver_maps} are stable, because otherwise we cannot trust
545 : // the {receiver_maps} information, since arbitrary side-effects
546 : // may have happened.
547 23 : if (!receiver_map->is_stable()) {
548 : return kMayBeInPrototypeChain;
549 : }
550 : }
551 58 : for (PrototypeIterator j(isolate(), receiver_map);; j.Advance()) {
552 58 : if (j.IsAtEnd()) {
553 : all = false;
554 : break;
555 : }
556 : Handle<HeapObject> const current =
557 : PrototypeIterator::GetCurrent<HeapObject>(j);
558 51 : if (current.is_identical_to(prototype)) {
559 : none = false;
560 : break;
561 : }
562 36 : if (!current->map()->is_stable() ||
563 : current->map()->instance_type() <= LAST_SPECIAL_RECEIVER_TYPE) {
564 : return kMayBeInPrototypeChain;
565 : }
566 : }
567 : }
568 : DCHECK_IMPLIES(all, !none);
569 :
570 36 : if (all) return kIsInPrototypeChain;
571 7 : if (none) return kIsNotInPrototypeChain;
572 0 : return kMayBeInPrototypeChain;
573 : }
574 :
575 1647 : Reduction JSNativeContextSpecialization::ReduceJSHasInPrototypeChain(
576 : Node* node) {
577 : DCHECK_EQ(IrOpcode::kJSHasInPrototypeChain, node->opcode());
578 1647 : Node* value = NodeProperties::GetValueInput(node, 0);
579 1647 : Node* prototype = NodeProperties::GetValueInput(node, 1);
580 1647 : Node* effect = NodeProperties::GetEffectInput(node);
581 :
582 : // Check if we can constant-fold the prototype chain walk
583 : // for the given {value} and the {prototype}.
584 : HeapObjectMatcher m(prototype);
585 1647 : if (m.HasValue()) {
586 : InferHasInPrototypeChainResult result =
587 1647 : InferHasInPrototypeChain(value, effect, m.Value());
588 1647 : if (result != kMayBeInPrototypeChain) {
589 : Node* value = jsgraph()->BooleanConstant(result == kIsInPrototypeChain);
590 : ReplaceWithValue(node, value);
591 : return Replace(value);
592 : }
593 : }
594 :
595 : return NoChange();
596 : }
597 :
598 1079 : Reduction JSNativeContextSpecialization::ReduceJSOrdinaryHasInstance(
599 : Node* node) {
600 : DCHECK_EQ(IrOpcode::kJSOrdinaryHasInstance, node->opcode());
601 1079 : Node* constructor = NodeProperties::GetValueInput(node, 0);
602 1079 : Node* object = NodeProperties::GetValueInput(node, 1);
603 :
604 : // Check if the {constructor} is known at compile time.
605 : HeapObjectMatcher m(constructor);
606 1079 : if (!m.HasValue()) return NoChange();
607 :
608 : // Check if the {constructor} is a JSBoundFunction.
609 1065 : if (m.Value()->IsJSBoundFunction()) {
610 : // OrdinaryHasInstance on bound functions turns into a recursive
611 : // invocation of the instanceof operator again.
612 : // ES6 section 7.3.19 OrdinaryHasInstance (C, O) step 2.
613 : Handle<JSBoundFunction> function = Handle<JSBoundFunction>::cast(m.Value());
614 : Handle<JSReceiver> bound_target_function(function->bound_target_function(),
615 : isolate());
616 7 : NodeProperties::ReplaceValueInput(node, object, 0);
617 14 : NodeProperties::ReplaceValueInput(
618 7 : node, jsgraph()->HeapConstant(bound_target_function), 1);
619 7 : NodeProperties::ChangeOp(node, javascript()->InstanceOf(VectorSlotPair()));
620 7 : Reduction const reduction = ReduceJSInstanceOf(node);
621 7 : return reduction.Changed() ? reduction : Changed(node);
622 : }
623 :
624 : // Optimize if we currently know the "prototype" property.
625 1058 : if (m.Value()->IsJSFunction()) {
626 1044 : JSFunctionRef function = m.Ref(broker()).AsJSFunction();
627 : // TODO(neis): This is a temporary hack needed because the copy reducer
628 : // runs only after this pass.
629 1044 : function.Serialize();
630 : // TODO(neis): Remove the has_prototype_slot condition once the broker is
631 : // always enabled.
632 1932 : if (!function.map().has_prototype_slot() || !function.has_prototype() ||
633 888 : function.PrototypeRequiresRuntimeLookup()) {
634 : return NoChange();
635 : }
636 758 : ObjectRef prototype = dependencies()->DependOnPrototypeProperty(function);
637 758 : Node* prototype_constant = jsgraph()->Constant(prototype);
638 :
639 : // Lower the {node} to JSHasInPrototypeChain.
640 758 : NodeProperties::ReplaceValueInput(node, object, 0);
641 758 : NodeProperties::ReplaceValueInput(node, prototype_constant, 1);
642 758 : NodeProperties::ChangeOp(node, javascript()->HasInPrototypeChain());
643 758 : Reduction const reduction = ReduceJSHasInPrototypeChain(node);
644 758 : return reduction.Changed() ? reduction : Changed(node);
645 : }
646 :
647 : return NoChange();
648 : }
649 :
650 : // ES section #sec-promise-resolve
651 190 : Reduction JSNativeContextSpecialization::ReduceJSPromiseResolve(Node* node) {
652 : DCHECK_EQ(IrOpcode::kJSPromiseResolve, node->opcode());
653 190 : Node* constructor = NodeProperties::GetValueInput(node, 0);
654 190 : Node* value = NodeProperties::GetValueInput(node, 1);
655 190 : Node* context = NodeProperties::GetContextInput(node);
656 190 : Node* frame_state = NodeProperties::GetFrameStateInput(node);
657 190 : Node* effect = NodeProperties::GetEffectInput(node);
658 190 : Node* control = NodeProperties::GetControlInput(node);
659 :
660 : // Check if the {constructor} is the %Promise% function.
661 : HeapObjectMatcher m(constructor);
662 570 : if (!m.HasValue() ||
663 760 : !m.Ref(broker()).equals(broker()->native_context().promise_function())) {
664 : return NoChange();
665 : }
666 :
667 : // Check if we know something about the {value}.
668 : ZoneHandleSet<Map> value_maps;
669 : NodeProperties::InferReceiverMapsResult result =
670 94 : NodeProperties::InferReceiverMaps(broker(), value, effect, &value_maps);
671 94 : if (result == NodeProperties::kNoReceiverMaps) return NoChange();
672 : DCHECK_NE(0, value_maps.size());
673 :
674 : // Check that the {value} cannot be a JSPromise.
675 84 : for (Handle<Map> const value_map : value_maps) {
676 42 : if (value_map->IsJSPromiseMap()) return NoChange();
677 : }
678 :
679 42 : if (!dependencies()->DependOnPromiseHookProtector()) return NoChange();
680 :
681 : // Create a %Promise% instance and resolve it with {value}.
682 : Node* promise = effect =
683 36 : graph()->NewNode(javascript()->CreatePromise(), context, effect);
684 36 : effect = graph()->NewNode(javascript()->ResolvePromise(), promise, value,
685 : context, frame_state, effect, control);
686 : ReplaceWithValue(node, promise, effect, control);
687 : return Replace(promise);
688 : }
689 :
690 : // ES section #sec-promise-resolve-functions
691 1047 : Reduction JSNativeContextSpecialization::ReduceJSResolvePromise(Node* node) {
692 : DCHECK_EQ(IrOpcode::kJSResolvePromise, node->opcode());
693 1047 : Node* promise = NodeProperties::GetValueInput(node, 0);
694 1047 : Node* resolution = NodeProperties::GetValueInput(node, 1);
695 1047 : Node* context = NodeProperties::GetContextInput(node);
696 1047 : Node* effect = NodeProperties::GetEffectInput(node);
697 1047 : Node* control = NodeProperties::GetControlInput(node);
698 :
699 : // Check if we know something about the {resolution}.
700 : ZoneHandleSet<Map> resolution_maps;
701 : NodeProperties::InferReceiverMapsResult result =
702 : NodeProperties::InferReceiverMaps(broker(), resolution, effect,
703 1047 : &resolution_maps);
704 1047 : if (result == NodeProperties::kNoReceiverMaps) return NoChange();
705 : DCHECK_NE(0, resolution_maps.size());
706 :
707 : // When the {resolution_maps} information is unreliable, we can
708 : // still optimize if all individual {resolution_maps} are stable.
709 718 : if (result == NodeProperties::kUnreliableReceiverMaps) {
710 1420 : for (Handle<Map> resolution_map : resolution_maps) {
711 710 : if (!resolution_map->is_stable()) return NoChange();
712 : }
713 : }
714 :
715 : // Compute property access info for "then" on {resolution}.
716 718 : PropertyAccessInfo access_info;
717 : AccessInfoFactory access_info_factory(broker(), dependencies(),
718 718 : graph()->zone());
719 2154 : if (!access_info_factory.ComputePropertyAccessInfo(
720 718 : MapHandles(resolution_maps.begin(), resolution_maps.end()),
721 : factory()->then_string(), AccessMode::kLoad, &access_info)) {
722 : return NoChange();
723 : }
724 :
725 : // We can further optimize the case where {resolution}
726 : // definitely doesn't have a "then" property.
727 28 : if (!access_info.IsNotFound()) return NoChange();
728 : PropertyAccessBuilder access_builder(jsgraph(), broker(), dependencies());
729 :
730 : // Add proper dependencies on the {resolution}s [[Prototype]]s.
731 : Handle<JSObject> holder;
732 28 : if (access_info.holder().ToHandle(&holder)) {
733 28 : dependencies()->DependOnStablePrototypeChains(
734 28 : access_info.receiver_maps(), JSObjectRef(broker(), holder));
735 : }
736 :
737 : // Add stability dependencies on the {resolution_maps}.
738 28 : if (result == NodeProperties::kUnreliableReceiverMaps) {
739 40 : for (Handle<Map> resolution_map : resolution_maps) {
740 20 : dependencies()->DependOnStableMap(MapRef(broker(), resolution_map));
741 : }
742 : }
743 :
744 : // Simply fulfill the {promise} with the {resolution}.
745 : Node* value = effect =
746 28 : graph()->NewNode(javascript()->FulfillPromise(), promise, resolution,
747 : context, effect, control);
748 : ReplaceWithValue(node, value, effect, control);
749 : return Replace(value);
750 : }
751 :
752 545005 : Reduction JSNativeContextSpecialization::ReduceJSLoadContext(Node* node) {
753 : DCHECK_EQ(IrOpcode::kJSLoadContext, node->opcode());
754 545005 : ContextAccess const& access = ContextAccessOf(node->op());
755 : // Specialize JSLoadContext(NATIVE_CONTEXT_INDEX) to the known native
756 : // context (if any), so we can constant-fold those fields, which is
757 : // safe, since the NATIVE_CONTEXT_INDEX slot is always immutable.
758 545005 : if (access.index() == Context::NATIVE_CONTEXT_INDEX) {
759 172 : Node* value = jsgraph()->Constant(native_context());
760 : ReplaceWithValue(node, value);
761 : return Replace(value);
762 : }
763 : return NoChange();
764 : }
765 :
766 : namespace {
767 :
768 : FieldAccess ForPropertyCellValue(MachineRepresentation representation,
769 : Type type, MaybeHandle<Map> map,
770 : Handle<Name> name) {
771 : WriteBarrierKind kind = kFullWriteBarrier;
772 39501 : if (representation == MachineRepresentation::kTaggedSigned) {
773 : kind = kNoWriteBarrier;
774 9987 : } else if (representation == MachineRepresentation::kTaggedPointer) {
775 : kind = kPointerWriteBarrier;
776 : }
777 41688 : MachineType r = MachineType::TypeForRepresentation(representation);
778 : FieldAccess access = {
779 : kTaggedBase, PropertyCell::kValueOffset, name, map, type, r, kind};
780 : return access;
781 : }
782 :
783 : } // namespace
784 :
785 278 : Reduction JSNativeContextSpecialization::ReduceGlobalAccess(
786 : Node* node, Node* receiver, Node* value, Handle<Name> name,
787 : AccessMode access_mode, Node* index) {
788 : // Lookup on the global object. We only deal with own data properties
789 : // of the global object here (represented as PropertyCell).
790 278 : LookupIterator it(isolate(), global_object(), name, LookupIterator::OWN);
791 278 : it.TryLookupCachedProperty();
792 278 : if (it.state() != LookupIterator::DATA) return NoChange();
793 251 : if (!it.GetHolder<JSObject>()->IsJSGlobalObject()) return NoChange();
794 251 : PropertyCellRef property_cell(broker(), it.GetPropertyCell());
795 251 : property_cell.Serialize();
796 : return ReduceGlobalAccess(node, receiver, value, name, access_mode, index,
797 251 : property_cell);
798 : }
799 :
800 192987 : Reduction JSNativeContextSpecialization::ReduceGlobalAccess(
801 : Node* node, Node* receiver, Node* value, Handle<Name> name,
802 : AccessMode access_mode, Node* index, PropertyCellRef const& property_cell) {
803 192987 : Node* effect = NodeProperties::GetEffectInput(node);
804 192987 : Node* control = NodeProperties::GetControlInput(node);
805 :
806 192987 : ObjectRef property_cell_value = property_cell.value();
807 578961 : if (property_cell_value.IsHeapObject() &&
808 516019 : property_cell_value.AsHeapObject().map().oddball_type() ==
809 : OddballType::kHole) {
810 : // The property cell is no longer valid.
811 : return NoChange();
812 : }
813 :
814 192959 : PropertyDetails property_details = property_cell.property_details();
815 : PropertyCellType property_cell_type = property_details.cell_type();
816 : DCHECK_EQ(kData, property_details.kind());
817 :
818 : // We have additional constraints for stores.
819 192959 : if (access_mode == AccessMode::kStore) {
820 16272 : if (property_details.IsReadOnly()) {
821 : // Don't even bother trying to lower stores to read-only data properties.
822 : return NoChange();
823 16272 : } else if (property_cell_type == PropertyCellType::kUndefined) {
824 : // There's no fast-path for dealing with undefined property cells.
825 : return NoChange();
826 16272 : } else if (property_cell_type == PropertyCellType::kConstantType) {
827 : // There's also no fast-path to store to a global cell which pretended
828 : // to be stable, but is no longer stable now.
829 41706 : if (property_cell_value.IsHeapObject() &&
830 15380 : !property_cell_value.AsHeapObject().map().is_stable()) {
831 : return NoChange();
832 : }
833 : }
834 176687 : } else if (access_mode == AccessMode::kHas) {
835 : // has checks cannot follow the fast-path used by loads when these
836 : // conditions hold.
837 84 : if ((property_details.IsConfigurable() || !property_details.IsReadOnly()) &&
838 63 : property_details.cell_type() != PropertyCellType::kConstant &&
839 : property_details.cell_type() != PropertyCellType::kUndefined)
840 : return NoChange();
841 : }
842 :
843 : // Ensure that {index} matches the specified {name} (if {index} is given).
844 192945 : if (index != nullptr) {
845 8 : effect = BuildCheckEqualsName(name, index, effect, control);
846 : }
847 :
848 : // Check if we have a {receiver} to validate. If so, we need to check that
849 : // the {receiver} is actually the JSGlobalProxy for the native context that
850 : // we are specializing to.
851 192945 : if (receiver != nullptr) {
852 422 : Node* check = graph()->NewNode(simplified()->ReferenceEqual(), receiver,
853 : jsgraph()->HeapConstant(global_proxy()));
854 422 : effect = graph()->NewNode(
855 : simplified()->CheckIf(DeoptimizeReason::kReceiverNotAGlobalProxy),
856 : check, effect, control);
857 : }
858 :
859 192945 : if (access_mode == AccessMode::kLoad || access_mode == AccessMode::kHas) {
860 : // Load from non-configurable, read-only data property on the global
861 : // object can be constant-folded, even without deoptimization support.
862 287060 : if (!property_details.IsConfigurable() && property_details.IsReadOnly()) {
863 : value = access_mode == AccessMode::kHas
864 : ? jsgraph()->TrueConstant()
865 4091 : : jsgraph()->Constant(property_cell_value);
866 : } else {
867 : // Record a code dependency on the cell if we can benefit from the
868 : // additional feedback, or the global property is configurable (i.e.
869 : // can be deleted or reconfigured to an accessor property).
870 172582 : if (property_details.cell_type() != PropertyCellType::kMutable ||
871 : property_details.IsConfigurable()) {
872 167936 : dependencies()->DependOnGlobalProperty(property_cell);
873 : }
874 :
875 : // Load from constant/undefined global property can be constant-folded.
876 172582 : if (property_details.cell_type() == PropertyCellType::kConstant ||
877 : property_details.cell_type() == PropertyCellType::kUndefined) {
878 : value = access_mode == AccessMode::kHas
879 : ? jsgraph()->TrueConstant()
880 146983 : : jsgraph()->Constant(property_cell_value);
881 : DCHECK(!property_cell_value.IsHeapObject() ||
882 : property_cell_value.AsHeapObject().map().oddball_type() !=
883 : OddballType::kHole);
884 : } else {
885 : DCHECK_NE(AccessMode::kHas, access_mode);
886 :
887 : // Load from constant type cell can benefit from type feedback.
888 : MaybeHandle<Map> map;
889 : Type property_cell_value_type = Type::NonInternal();
890 : MachineRepresentation representation = MachineRepresentation::kTagged;
891 25599 : if (property_details.cell_type() == PropertyCellType::kConstantType) {
892 : // Compute proper type based on the current value in the cell.
893 18944 : if (property_cell_value.IsSmi()) {
894 : property_cell_value_type = Type::SignedSmall();
895 : representation = MachineRepresentation::kTaggedSigned;
896 2593 : } else if (property_cell_value.IsHeapNumber()) {
897 : property_cell_value_type = Type::Number();
898 : representation = MachineRepresentation::kTaggedPointer;
899 : } else {
900 : MapRef property_cell_value_map =
901 1421 : property_cell_value.AsHeapObject().map();
902 1421 : property_cell_value_type = Type::For(property_cell_value_map);
903 : representation = MachineRepresentation::kTaggedPointer;
904 :
905 : // We can only use the property cell value map for map check
906 : // elimination if it's stable, i.e. the HeapObject wasn't
907 : // mutated without the cell state being updated.
908 1421 : if (property_cell_value_map.is_stable()) {
909 1417 : dependencies()->DependOnStableMap(property_cell_value_map);
910 1417 : map = property_cell_value_map.object();
911 : }
912 : }
913 : }
914 51198 : value = effect = graph()->NewNode(
915 25599 : simplified()->LoadField(ForPropertyCellValue(
916 : representation, property_cell_value_type, map, name)),
917 : jsgraph()->Constant(property_cell), effect, control);
918 : }
919 : }
920 : } else {
921 : DCHECK_EQ(AccessMode::kStore, access_mode);
922 : DCHECK(!property_details.IsReadOnly());
923 16272 : switch (property_details.cell_type()) {
924 : case PropertyCellType::kUndefined: {
925 0 : UNREACHABLE();
926 : break;
927 : }
928 : case PropertyCellType::kConstant: {
929 : // Record a code dependency on the cell, and just deoptimize if the new
930 : // value doesn't match the previous value stored inside the cell.
931 183 : dependencies()->DependOnGlobalProperty(property_cell);
932 : Node* check =
933 183 : graph()->NewNode(simplified()->ReferenceEqual(), value,
934 : jsgraph()->Constant(property_cell_value));
935 366 : effect = graph()->NewNode(
936 : simplified()->CheckIf(DeoptimizeReason::kValueMismatch), check,
937 : effect, control);
938 183 : break;
939 : }
940 : case PropertyCellType::kConstantType: {
941 : // Record a code dependency on the cell, and just deoptimize if the new
942 : // values' type doesn't match the type of the previous value in the
943 : // cell.
944 13902 : dependencies()->DependOnGlobalProperty(property_cell);
945 : Type property_cell_value_type;
946 : MachineRepresentation representation = MachineRepresentation::kTagged;
947 13902 : if (property_cell_value.IsHeapObject()) {
948 : // We cannot do anything if the {property_cell_value}s map is no
949 : // longer stable.
950 : MapRef property_cell_value_map =
951 739 : property_cell_value.AsHeapObject().map();
952 739 : dependencies()->DependOnStableMap(property_cell_value_map);
953 :
954 : // Check that the {value} is a HeapObject.
955 739 : value = effect = graph()->NewNode(simplified()->CheckHeapObject(),
956 : value, effect, control);
957 :
958 : // Check {value} map against the {property_cell} map.
959 2217 : effect = graph()->NewNode(
960 : simplified()->CheckMaps(
961 : CheckMapsFlag::kNone,
962 : ZoneHandleSet<Map>(property_cell_value_map.object())),
963 : value, effect, control);
964 : property_cell_value_type = Type::OtherInternal();
965 : representation = MachineRepresentation::kTaggedPointer;
966 : } else {
967 : // Check that the {value} is a Smi.
968 26326 : value = effect = graph()->NewNode(
969 : simplified()->CheckSmi(VectorSlotPair()), value, effect, control);
970 : property_cell_value_type = Type::SignedSmall();
971 : representation = MachineRepresentation::kTaggedSigned;
972 : }
973 41706 : effect = graph()->NewNode(simplified()->StoreField(ForPropertyCellValue(
974 : representation, property_cell_value_type,
975 : MaybeHandle<Map>(), name)),
976 : jsgraph()->Constant(property_cell), value,
977 : effect, control);
978 : break;
979 : }
980 : case PropertyCellType::kMutable: {
981 : // Record a code dependency on the cell, and just deoptimize if the
982 : // property ever becomes read-only.
983 2187 : dependencies()->DependOnGlobalProperty(property_cell);
984 4374 : effect = graph()->NewNode(
985 2187 : simplified()->StoreField(ForPropertyCellValue(
986 : MachineRepresentation::kTagged, Type::NonInternal(),
987 : MaybeHandle<Map>(), name)),
988 : jsgraph()->Constant(property_cell), value, effect, control);
989 2187 : break;
990 : }
991 : }
992 : }
993 :
994 : ReplaceWithValue(node, value, effect, control);
995 : return Replace(value);
996 : }
997 :
998 1000369 : Reduction JSNativeContextSpecialization::ReduceJSLoadGlobal(Node* node) {
999 : DCHECK_EQ(IrOpcode::kJSLoadGlobal, node->opcode());
1000 : DisallowHeapAccessIf no_heap_acess(FLAG_concurrent_inlining);
1001 :
1002 1000369 : LoadGlobalParameters const& p = LoadGlobalParametersOf(node->op());
1003 1000370 : if (!p.feedback().IsValid()) return NoChange();
1004 1000370 : FeedbackSource source(p.feedback());
1005 :
1006 : GlobalAccessFeedback const* processed;
1007 1000371 : if (FLAG_concurrent_inlining) {
1008 16 : processed = broker()->GetGlobalAccessFeedback(source);
1009 16 : TRACE_BROKER(broker(), "ReduceJSLoadGlobal: using preprocessed feedback "
1010 : << "(slot " << p.feedback().slot()
1011 : << " of feedback vector handle "
1012 : << p.feedback().vector().address() << ").\n");
1013 : } else {
1014 1000355 : processed = broker()->ProcessFeedbackForGlobalAccess(source);
1015 : }
1016 :
1017 1000370 : if (processed == nullptr) return NoChange();
1018 :
1019 176584 : if (processed->IsScriptContextSlot()) {
1020 105 : Node* effect = NodeProperties::GetEffectInput(node);
1021 105 : Node* script_context = jsgraph()->Constant(processed->script_context());
1022 : Node* value = effect =
1023 105 : graph()->NewNode(javascript()->LoadContext(0, processed->slot_index(),
1024 105 : processed->immutable()),
1025 : script_context, effect);
1026 : ReplaceWithValue(node, value, effect);
1027 : return Replace(value);
1028 : }
1029 :
1030 176479 : CHECK(processed->IsPropertyCell());
1031 : return ReduceGlobalAccess(node, nullptr, nullptr, p.name(), AccessMode::kLoad,
1032 352958 : nullptr, processed->property_cell());
1033 : }
1034 :
1035 219047 : Reduction JSNativeContextSpecialization::ReduceJSStoreGlobal(Node* node) {
1036 : DCHECK_EQ(IrOpcode::kJSStoreGlobal, node->opcode());
1037 : DisallowHeapAccessIf no_heap_acess(FLAG_concurrent_inlining);
1038 :
1039 219047 : Node* value = NodeProperties::GetValueInput(node, 0);
1040 :
1041 219047 : StoreGlobalParameters const& p = StoreGlobalParametersOf(node->op());
1042 219047 : if (!p.feedback().IsValid()) return NoChange();
1043 219047 : FeedbackSource source(p.feedback());
1044 :
1045 : GlobalAccessFeedback const* processed;
1046 219047 : if (FLAG_concurrent_inlining) {
1047 35 : processed = broker()->GetGlobalAccessFeedback(source);
1048 35 : TRACE_BROKER(broker(), "ReduceJSStoreGlobal: using preprocessed feedback "
1049 : << "(slot " << p.feedback().slot()
1050 : << " of feedback vector handle "
1051 : << p.feedback().vector().address() << ").\n");
1052 : } else {
1053 219012 : processed = broker()->ProcessFeedbackForGlobalAccess(source);
1054 : }
1055 :
1056 219047 : if (processed == nullptr) return NoChange();
1057 :
1058 16266 : if (processed->IsScriptContextSlot()) {
1059 9 : if (processed->immutable()) return NoChange();
1060 9 : Node* effect = NodeProperties::GetEffectInput(node);
1061 9 : Node* control = NodeProperties::GetControlInput(node);
1062 9 : Node* script_context = jsgraph()->Constant(processed->script_context());
1063 : effect =
1064 9 : graph()->NewNode(javascript()->StoreContext(0, processed->slot_index()),
1065 : value, script_context, effect, control);
1066 : ReplaceWithValue(node, value, effect, control);
1067 : return Replace(value);
1068 : }
1069 :
1070 16257 : if (processed->IsPropertyCell()) {
1071 : return ReduceGlobalAccess(node, nullptr, value, p.name(),
1072 : AccessMode::kStore, nullptr,
1073 32514 : processed->property_cell());
1074 : }
1075 :
1076 0 : UNREACHABLE();
1077 : }
1078 :
1079 138609 : Reduction JSNativeContextSpecialization::ReduceNamedAccess(
1080 : Node* node, Node* value, MapHandles const& receiver_maps, Handle<Name> name,
1081 : AccessMode access_mode, Node* index) {
1082 : DCHECK(node->opcode() == IrOpcode::kJSLoadNamed ||
1083 : node->opcode() == IrOpcode::kJSStoreNamed ||
1084 : node->opcode() == IrOpcode::kJSLoadProperty ||
1085 : node->opcode() == IrOpcode::kJSStoreProperty ||
1086 : node->opcode() == IrOpcode::kJSStoreNamedOwn ||
1087 : node->opcode() == IrOpcode::kJSHasProperty);
1088 138609 : Node* receiver = NodeProperties::GetValueInput(node, 0);
1089 138609 : Node* context = NodeProperties::GetContextInput(node);
1090 138609 : Node* frame_state = NodeProperties::GetFrameStateInput(node);
1091 138609 : Node* effect = NodeProperties::GetEffectInput(node);
1092 138609 : Node* control = NodeProperties::GetControlInput(node);
1093 :
1094 : // Check if we have an access o.x or o.x=v where o is the current
1095 : // native contexts' global proxy, and turn that into a direct access
1096 : // to the current native contexts' global object instead.
1097 138609 : if (receiver_maps.size() == 1) {
1098 123609 : Handle<Map> receiver_map = receiver_maps.front();
1099 123609 : if (receiver_map->IsJSGlobalProxyMap()) {
1100 251 : Object maybe_constructor = receiver_map->GetConstructor();
1101 : // Detached global proxies have |null| as their constructor.
1102 753 : if (maybe_constructor->IsJSFunction() &&
1103 502 : JSFunction::cast(maybe_constructor)->native_context() ==
1104 753 : *native_context().object()) {
1105 : return ReduceGlobalAccess(node, receiver, value, name, access_mode,
1106 251 : index);
1107 : }
1108 : }
1109 : }
1110 :
1111 : // Compute property access infos for the receiver maps.
1112 : AccessInfoFactory access_info_factory(broker(), dependencies(),
1113 138358 : graph()->zone());
1114 : ZoneVector<PropertyAccessInfo> access_infos(zone());
1115 138358 : if (!access_info_factory.ComputePropertyAccessInfos(
1116 : receiver_maps, name, access_mode, &access_infos)) {
1117 : return NoChange();
1118 : }
1119 :
1120 : // Nothing to do if we have no non-deprecated maps.
1121 124455 : if (access_infos.empty()) {
1122 : return ReduceSoftDeoptimize(
1123 0 : node, DeoptimizeReason::kInsufficientTypeFeedbackForGenericNamedAccess);
1124 : }
1125 :
1126 : // Ensure that {index} matches the specified {name} (if {index} is given).
1127 124455 : if (index != nullptr) {
1128 147 : effect = BuildCheckEqualsName(name, index, effect, control);
1129 : }
1130 :
1131 : // Collect call nodes to rewire exception edges.
1132 : ZoneVector<Node*> if_exception_nodes(zone());
1133 : ZoneVector<Node*>* if_exceptions = nullptr;
1134 124455 : Node* if_exception = nullptr;
1135 124455 : if (NodeProperties::IsExceptionalCall(node, &if_exception)) {
1136 : if_exceptions = &if_exception_nodes;
1137 : }
1138 :
1139 : PropertyAccessBuilder access_builder(jsgraph(), broker(), dependencies());
1140 :
1141 : // Check for the monomorphic cases.
1142 124455 : if (access_infos.size() == 1) {
1143 118915 : PropertyAccessInfo access_info = access_infos.front();
1144 : // Try to build string check or number check if possible.
1145 : // Otherwise build a map check.
1146 237830 : if (!access_builder.TryBuildStringCheck(broker(),
1147 : access_info.receiver_maps(),
1148 230637 : &receiver, &effect, control) &&
1149 111722 : !access_builder.TryBuildNumberCheck(broker(),
1150 : access_info.receiver_maps(),
1151 : &receiver, &effect, control)) {
1152 110432 : if (HasNumberMaps(broker(), access_info.receiver_maps())) {
1153 : // We need to also let Smi {receiver}s through in this case, so
1154 : // we construct a diamond, guarded by the Sminess of the {receiver}
1155 : // and if {receiver} is not a Smi just emit a sequence of map checks.
1156 7 : Node* check = graph()->NewNode(simplified()->ObjectIsSmi(), receiver);
1157 7 : Node* branch = graph()->NewNode(common()->Branch(), check, control);
1158 :
1159 7 : Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
1160 7 : Node* etrue = effect;
1161 :
1162 7 : Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
1163 7 : Node* efalse = effect;
1164 : {
1165 : access_builder.BuildCheckMaps(receiver, &efalse, if_false,
1166 7 : access_info.receiver_maps());
1167 : }
1168 :
1169 14 : control = graph()->NewNode(common()->Merge(2), if_true, if_false);
1170 : effect =
1171 14 : graph()->NewNode(common()->EffectPhi(2), etrue, efalse, control);
1172 : } else {
1173 : receiver =
1174 110425 : access_builder.BuildCheckHeapObject(receiver, &effect, control);
1175 : access_builder.BuildCheckMaps(receiver, &effect, control,
1176 110425 : access_info.receiver_maps());
1177 : }
1178 : }
1179 :
1180 : // Generate the actual property access.
1181 : ValueEffectControl continuation = BuildPropertyAccess(
1182 : receiver, value, context, frame_state, effect, control, name,
1183 118915 : if_exceptions, access_info, access_mode);
1184 : value = continuation.value();
1185 118915 : effect = continuation.effect();
1186 118915 : control = continuation.control();
1187 : } else {
1188 : // The final states for every polymorphic branch. We join them with
1189 : // Merge+Phi+EffectPhi at the bottom.
1190 : ZoneVector<Node*> values(zone());
1191 : ZoneVector<Node*> effects(zone());
1192 : ZoneVector<Node*> controls(zone());
1193 :
1194 : // Check if {receiver} may be a number.
1195 : bool receiverissmi_possible = false;
1196 16940 : for (PropertyAccessInfo const& access_info : access_infos) {
1197 11486 : if (HasNumberMaps(broker(), access_info.receiver_maps())) {
1198 : receiverissmi_possible = true;
1199 : break;
1200 : }
1201 : }
1202 :
1203 : // Ensure that {receiver} is a heap object.
1204 : Node* receiverissmi_control = nullptr;
1205 5540 : Node* receiverissmi_effect = effect;
1206 5540 : if (receiverissmi_possible) {
1207 86 : Node* check = graph()->NewNode(simplified()->ObjectIsSmi(), receiver);
1208 86 : Node* branch = graph()->NewNode(common()->Branch(), check, control);
1209 172 : control = graph()->NewNode(common()->IfFalse(), branch);
1210 86 : receiverissmi_control = graph()->NewNode(common()->IfTrue(), branch);
1211 86 : receiverissmi_effect = effect;
1212 : } else {
1213 : receiver =
1214 5454 : access_builder.BuildCheckHeapObject(receiver, &effect, control);
1215 : }
1216 :
1217 : // Generate code for the various different property access patterns.
1218 5540 : Node* fallthrough_control = control;
1219 28718 : for (size_t j = 0; j < access_infos.size(); ++j) {
1220 : PropertyAccessInfo const& access_info = access_infos[j];
1221 : Node* this_value = value;
1222 11589 : Node* this_receiver = receiver;
1223 11589 : Node* this_effect = effect;
1224 : Node* this_control = fallthrough_control;
1225 :
1226 : // Perform map check on {receiver}.
1227 : MapHandles const& receiver_maps = access_info.receiver_maps();
1228 : {
1229 : // Whether to insert a dedicated MapGuard node into the
1230 : // effect to be able to learn from the control flow.
1231 : bool insert_map_guard = true;
1232 :
1233 : // Check maps for the {receiver}s.
1234 11589 : if (j == access_infos.size() - 1) {
1235 : // Last map check on the fallthrough control path, do a
1236 : // conditional eager deoptimization exit here.
1237 : access_builder.BuildCheckMaps(receiver, &this_effect, this_control,
1238 5540 : receiver_maps);
1239 : fallthrough_control = nullptr;
1240 :
1241 : // Don't insert a MapGuard in this case, as the CheckMaps
1242 : // node already gives you all the information you need
1243 : // along the effect chain.
1244 : insert_map_guard = false;
1245 : } else {
1246 : // Explicitly branch on the {receiver_maps}.
1247 : ZoneHandleSet<Map> maps;
1248 12228 : for (Handle<Map> map : receiver_maps) {
1249 6179 : maps.insert(map, graph()->zone());
1250 : }
1251 : Node* check = this_effect =
1252 6049 : graph()->NewNode(simplified()->CompareMaps(maps), receiver,
1253 6049 : this_effect, this_control);
1254 : Node* branch =
1255 6049 : graph()->NewNode(common()->Branch(), check, this_control);
1256 6049 : fallthrough_control = graph()->NewNode(common()->IfFalse(), branch);
1257 6049 : this_control = graph()->NewNode(common()->IfTrue(), branch);
1258 : }
1259 :
1260 : // The Number case requires special treatment to also deal with Smis.
1261 11589 : if (HasNumberMaps(broker(), receiver_maps)) {
1262 : // Join this check with the "receiver is smi" check above.
1263 : DCHECK_NOT_NULL(receiverissmi_effect);
1264 : DCHECK_NOT_NULL(receiverissmi_control);
1265 86 : this_control = graph()->NewNode(common()->Merge(2), this_control,
1266 : receiverissmi_control);
1267 86 : this_effect = graph()->NewNode(common()->EffectPhi(2), this_effect,
1268 86 : receiverissmi_effect, this_control);
1269 : receiverissmi_effect = receiverissmi_control = nullptr;
1270 :
1271 : // The {receiver} can also be a Smi in this case, so
1272 : // a MapGuard doesn't make sense for this at all.
1273 : insert_map_guard = false;
1274 : }
1275 :
1276 : // Introduce a MapGuard to learn from this on the effect chain.
1277 11589 : if (insert_map_guard) {
1278 : ZoneHandleSet<Map> maps;
1279 12086 : for (auto receiver_map : receiver_maps) {
1280 6108 : maps.insert(receiver_map, graph()->zone());
1281 : }
1282 5978 : this_effect = graph()->NewNode(simplified()->MapGuard(maps), receiver,
1283 5978 : this_effect, this_control);
1284 : }
1285 :
1286 : // If all {receiver_maps} are Strings we also need to rename the
1287 : // {receiver} here to make sure that TurboFan knows that along this
1288 : // path the {this_receiver} is a String. This is because we want
1289 : // strict checking of types, for example for StringLength operators.
1290 11589 : if (HasOnlyStringMaps(broker(), receiver_maps)) {
1291 : this_receiver = this_effect =
1292 100 : graph()->NewNode(common()->TypeGuard(Type::String()), receiver,
1293 100 : this_effect, this_control);
1294 : }
1295 : }
1296 :
1297 : // Generate the actual property access.
1298 : ValueEffectControl continuation = BuildPropertyAccess(
1299 : this_receiver, this_value, context, frame_state, this_effect,
1300 11589 : this_control, name, if_exceptions, access_info, access_mode);
1301 23178 : values.push_back(continuation.value());
1302 23178 : effects.push_back(continuation.effect());
1303 23178 : controls.push_back(continuation.control());
1304 : }
1305 :
1306 : DCHECK_NULL(fallthrough_control);
1307 :
1308 : // Generate the final merge point for all (polymorphic) branches.
1309 5540 : int const control_count = static_cast<int>(controls.size());
1310 5540 : if (control_count == 0) {
1311 0 : value = effect = control = jsgraph()->Dead();
1312 5540 : } else if (control_count == 1) {
1313 0 : value = values.front();
1314 0 : effect = effects.front();
1315 0 : control = controls.front();
1316 : } else {
1317 5540 : control = graph()->NewNode(common()->Merge(control_count), control_count,
1318 5540 : &controls.front());
1319 5540 : values.push_back(control);
1320 5540 : value = graph()->NewNode(
1321 : common()->Phi(MachineRepresentation::kTagged, control_count),
1322 5540 : control_count + 1, &values.front());
1323 5540 : effects.push_back(control);
1324 5540 : effect = graph()->NewNode(common()->EffectPhi(control_count),
1325 5540 : control_count + 1, &effects.front());
1326 : }
1327 : }
1328 :
1329 : // Properly rewire IfException edges if {node} is inside a try-block.
1330 124455 : if (!if_exception_nodes.empty()) {
1331 : DCHECK_NOT_NULL(if_exception);
1332 : DCHECK_EQ(if_exceptions, &if_exception_nodes);
1333 261 : int const if_exception_count = static_cast<int>(if_exceptions->size());
1334 261 : Node* merge = graph()->NewNode(common()->Merge(if_exception_count),
1335 261 : if_exception_count, &if_exceptions->front());
1336 261 : if_exceptions->push_back(merge);
1337 : Node* ephi =
1338 261 : graph()->NewNode(common()->EffectPhi(if_exception_count),
1339 261 : if_exception_count + 1, &if_exceptions->front());
1340 261 : Node* phi = graph()->NewNode(
1341 : common()->Phi(MachineRepresentation::kTagged, if_exception_count),
1342 261 : if_exception_count + 1, &if_exceptions->front());
1343 261 : ReplaceWithValue(if_exception, phi, ephi, merge);
1344 : }
1345 :
1346 124455 : ReplaceWithValue(node, value, effect, control);
1347 : return Replace(value);
1348 : }
1349 :
1350 483986 : Reduction JSNativeContextSpecialization::ReduceNamedAccessFromNexus(
1351 : Node* node, Node* value, FeedbackNexus const& nexus, Handle<Name> name,
1352 : AccessMode access_mode) {
1353 : DCHECK(node->opcode() == IrOpcode::kJSLoadNamed ||
1354 : node->opcode() == IrOpcode::kJSStoreNamed ||
1355 : node->opcode() == IrOpcode::kJSStoreNamedOwn);
1356 483986 : Node* const receiver = NodeProperties::GetValueInput(node, 0);
1357 483986 : Node* const effect = NodeProperties::GetEffectInput(node);
1358 :
1359 : // Check if we are accessing the current native contexts' global proxy.
1360 : HeapObjectMatcher m(receiver);
1361 547595 : if (m.HasValue() && m.Value().is_identical_to(global_proxy())) {
1362 : // Optimize accesses to the current native contexts' global proxy.
1363 27 : return ReduceGlobalAccess(node, nullptr, value, name, access_mode);
1364 : }
1365 :
1366 : // Extract receiver maps from the IC using the {nexus}.
1367 : MapHandles receiver_maps;
1368 483960 : if (!ExtractReceiverMaps(receiver, effect, nexus, &receiver_maps)) {
1369 : return NoChange();
1370 477156 : } else if (receiver_maps.empty()) {
1371 : return ReduceSoftDeoptimize(
1372 339606 : node, DeoptimizeReason::kInsufficientTypeFeedbackForGenericNamedAccess);
1373 : }
1374 : DCHECK(!nexus.IsUninitialized());
1375 :
1376 : // Try to lower the named access based on the {receiver_maps}.
1377 137550 : return ReduceNamedAccess(node, value, receiver_maps, name, access_mode);
1378 : }
1379 :
1380 544244 : Reduction JSNativeContextSpecialization::ReduceJSLoadNamed(Node* node) {
1381 : DCHECK_EQ(IrOpcode::kJSLoadNamed, node->opcode());
1382 544244 : NamedAccess const& p = NamedAccessOf(node->op());
1383 544245 : Node* const receiver = NodeProperties::GetValueInput(node, 0);
1384 :
1385 : // Check if we have a constant receiver.
1386 : HeapObjectMatcher m(receiver);
1387 544245 : if (m.HasValue()) {
1388 65799 : ObjectRef object = m.Ref(broker());
1389 : NameRef name(broker(), p.name());
1390 136918 : if (object.IsJSFunction() &&
1391 71119 : name.equals(ObjectRef(broker(), factory()->prototype_string()))) {
1392 : // Optimize "prototype" property of functions.
1393 570 : JSFunctionRef function = object.AsJSFunction();
1394 : // TODO(neis): This is a temporary hack needed because the copy reducer
1395 : // runs only after this pass.
1396 570 : function.Serialize();
1397 : // TODO(neis): Remove the has_prototype_slot condition once the broker is
1398 : // always enabled.
1399 1138 : if (!function.map().has_prototype_slot() || !function.has_prototype() ||
1400 568 : function.PrototypeRequiresRuntimeLookup()) {
1401 : return NoChange();
1402 : }
1403 561 : ObjectRef prototype = dependencies()->DependOnPrototypeProperty(function);
1404 561 : Node* value = jsgraph()->Constant(prototype);
1405 : ReplaceWithValue(node, value);
1406 : return Replace(value);
1407 134044 : } else if (object.IsString() &&
1408 68815 : name.equals(ObjectRef(broker(), factory()->length_string()))) {
1409 : // Constant-fold "length" property on constant strings.
1410 276 : Node* value = jsgraph()->Constant(object.AsString().length());
1411 : ReplaceWithValue(node, value);
1412 : return Replace(value);
1413 : }
1414 : }
1415 :
1416 : // Extract receiver maps from the load IC using the FeedbackNexus.
1417 543399 : if (!p.feedback().IsValid()) return NoChange();
1418 : FeedbackNexus nexus(p.feedback().vector(), p.feedback().slot());
1419 :
1420 : // Try to lower the named access based on the {receiver_maps}.
1421 : return ReduceNamedAccessFromNexus(node, jsgraph()->Dead(), nexus, p.name(),
1422 360670 : AccessMode::kLoad);
1423 : }
1424 :
1425 106481 : Reduction JSNativeContextSpecialization::ReduceJSStoreNamed(Node* node) {
1426 : DCHECK_EQ(IrOpcode::kJSStoreNamed, node->opcode());
1427 106481 : NamedAccess const& p = NamedAccessOf(node->op());
1428 106481 : Node* const value = NodeProperties::GetValueInput(node, 1);
1429 :
1430 : // Extract receiver maps from the store IC using the FeedbackNexus.
1431 106481 : if (!p.feedback().IsValid()) return NoChange();
1432 : FeedbackNexus nexus(p.feedback().vector(), p.feedback().slot());
1433 :
1434 : // Try to lower the named access based on the {receiver_maps}.
1435 : return ReduceNamedAccessFromNexus(node, value, nexus, p.name(),
1436 87282 : AccessMode::kStore);
1437 : }
1438 :
1439 36033 : Reduction JSNativeContextSpecialization::ReduceJSStoreNamedOwn(Node* node) {
1440 : DCHECK_EQ(IrOpcode::kJSStoreNamedOwn, node->opcode());
1441 36033 : StoreNamedOwnParameters const& p = StoreNamedOwnParametersOf(node->op());
1442 36033 : Node* const value = NodeProperties::GetValueInput(node, 1);
1443 :
1444 : // Extract receiver maps from the IC using the FeedbackNexus.
1445 36034 : if (!p.feedback().IsValid()) return NoChange();
1446 : FeedbackNexus nexus(p.feedback().vector(), p.feedback().slot());
1447 :
1448 : // Try to lower the creation of a named property based on the {receiver_maps}.
1449 : return ReduceNamedAccessFromNexus(node, value, nexus, p.name(),
1450 36034 : AccessMode::kStoreInLiteral);
1451 : }
1452 :
1453 377 : Reduction JSNativeContextSpecialization::ReduceElementAccessOnString(
1454 : Node* node, Node* index, Node* value, AccessMode access_mode,
1455 : KeyedAccessLoadMode load_mode) {
1456 377 : Node* receiver = NodeProperties::GetValueInput(node, 0);
1457 377 : Node* effect = NodeProperties::GetEffectInput(node);
1458 377 : Node* control = NodeProperties::GetControlInput(node);
1459 :
1460 : // Strings are immutable in JavaScript.
1461 377 : if (access_mode == AccessMode::kStore) return NoChange();
1462 :
1463 : // `in` cannot be used on strings.
1464 377 : if (access_mode == AccessMode::kHas) return NoChange();
1465 :
1466 : // Ensure that the {receiver} is actually a String.
1467 726 : receiver = effect = graph()->NewNode(
1468 363 : simplified()->CheckString(VectorSlotPair()), receiver, effect, control);
1469 :
1470 : // Determine the {receiver} length.
1471 363 : Node* length = graph()->NewNode(simplified()->StringLength(), receiver);
1472 :
1473 : // Load the single character string from {receiver} or yield undefined
1474 : // if the {index} is out of bounds (depending on the {load_mode}).
1475 : value = BuildIndexedStringLoad(receiver, index, length, &effect, &control,
1476 363 : load_mode);
1477 :
1478 363 : ReplaceWithValue(node, value, effect, control);
1479 : return Replace(value);
1480 : }
1481 :
1482 : namespace {
1483 13808 : base::Optional<JSTypedArrayRef> GetTypedArrayConstant(JSHeapBroker* broker,
1484 : Node* receiver) {
1485 : HeapObjectMatcher m(receiver);
1486 13808 : if (!m.HasValue()) return base::nullopt;
1487 4172 : ObjectRef object = m.Ref(broker);
1488 4172 : if (!object.IsJSTypedArray()) return base::nullopt;
1489 4172 : JSTypedArrayRef typed_array = object.AsJSTypedArray();
1490 4172 : if (typed_array.is_on_heap()) return base::nullopt;
1491 : return typed_array;
1492 : }
1493 : } // namespace
1494 :
1495 23524 : Reduction JSNativeContextSpecialization::ReduceElementAccess(
1496 : Node* node, Node* index, Node* value, FeedbackNexus const& nexus,
1497 : MapHandles const& receiver_maps, AccessMode access_mode,
1498 : KeyedAccessLoadMode load_mode, KeyedAccessStoreMode store_mode) {
1499 : DisallowHeapAccessIf no_heap_access(FLAG_concurrent_inlining);
1500 :
1501 : DCHECK(node->opcode() == IrOpcode::kJSLoadProperty ||
1502 : node->opcode() == IrOpcode::kJSStoreProperty ||
1503 : node->opcode() == IrOpcode::kJSStoreInArrayLiteral ||
1504 : node->opcode() == IrOpcode::kJSHasProperty);
1505 23524 : Node* receiver = NodeProperties::GetValueInput(node, 0);
1506 23524 : Node* effect = NodeProperties::GetEffectInput(node);
1507 23524 : Node* control = NodeProperties::GetControlInput(node);
1508 23524 : Node* frame_state = NodeProperties::FindFrameStateBefore(node);
1509 :
1510 23524 : if (HasOnlyStringMaps(broker(), receiver_maps)) {
1511 : return ReduceElementAccessOnString(node, index, value, access_mode,
1512 377 : load_mode);
1513 : }
1514 :
1515 : // Compute element access infos for the receiver maps.
1516 : AccessInfoFactory access_info_factory(broker(), dependencies(),
1517 23147 : graph()->zone());
1518 : ZoneVector<ElementAccessInfo> access_infos(zone());
1519 23147 : if (!access_info_factory.ComputeElementAccessInfos(
1520 : nexus, receiver_maps, access_mode, &access_infos)) {
1521 : return NoChange();
1522 : }
1523 :
1524 : // Nothing to do if we have no non-deprecated maps.
1525 22079 : if (access_infos.empty()) {
1526 : return ReduceSoftDeoptimize(
1527 0 : node, DeoptimizeReason::kInsufficientTypeFeedbackForGenericKeyedAccess);
1528 : }
1529 :
1530 : // For holey stores or growing stores, we need to check that the prototype
1531 : // chain contains no setters for elements, and we need to guard those checks
1532 : // via code dependencies on the relevant prototype maps.
1533 22079 : if (access_mode == AccessMode::kStore) {
1534 : // TODO(turbofan): We could have a fast path here, that checks for the
1535 : // common case of Array or Object prototype only and therefore avoids
1536 : // the zone allocation of this vector.
1537 : ZoneVector<MapRef> prototype_maps(zone());
1538 11349 : for (ElementAccessInfo const& access_info : access_infos) {
1539 11617 : for (Handle<Map> map : access_info.receiver_maps()) {
1540 : MapRef receiver_map(broker(), map);
1541 : // If the {receiver_map} has a prototype and its elements backing
1542 : // store is either holey, or we have a potentially growing store,
1543 : // then we need to check that all prototypes have stable maps with
1544 : // fast elements (and we need to guard against changes to that below).
1545 15761 : if ((IsHoleyOrDictionaryElementsKind(receiver_map.elements_kind()) ||
1546 7769 : IsGrowStoreMode(store_mode)) &&
1547 1957 : !receiver_map.HasOnlyStablePrototypesWithFastElements(
1548 : &prototype_maps)) {
1549 7 : return NoChange();
1550 : }
1551 : }
1552 : }
1553 9339 : for (MapRef const& prototype_map : prototype_maps) {
1554 3802 : dependencies()->DependOnStableMap(prototype_map);
1555 : }
1556 16535 : } else if (access_mode == AccessMode::kHas) {
1557 : // If we have any fast arrays, we need to check and depend on
1558 : // NoElementsProtector.
1559 58 : for (ElementAccessInfo const& access_info : access_infos) {
1560 50 : if (IsFastElementsKind(access_info.elements_kind())) {
1561 42 : if (!isolate()->IsNoElementsProtectorIntact()) return NoChange();
1562 34 : dependencies()->DependOnProtector(
1563 34 : PropertyCellRef(broker(), factory()->no_elements_protector()));
1564 34 : break;
1565 : }
1566 : }
1567 : }
1568 :
1569 : // Ensure that {receiver} is a heap object.
1570 : PropertyAccessBuilder access_builder(jsgraph(), broker(), dependencies());
1571 22064 : receiver = access_builder.BuildCheckHeapObject(receiver, &effect, control);
1572 :
1573 : // Check if we have the necessary data for building element accesses.
1574 44749 : for (ElementAccessInfo const& access_info : access_infos) {
1575 38466 : if (!IsFixedTypedArrayElementsKind(access_info.elements_kind())) continue;
1576 : base::Optional<JSTypedArrayRef> typed_array =
1577 6904 : GetTypedArrayConstant(broker(), receiver);
1578 6904 : if (typed_array.has_value()) {
1579 1327 : if (!FLAG_concurrent_inlining) {
1580 1327 : typed_array->Serialize();
1581 0 : } else if (!typed_array->serialized()) {
1582 0 : TRACE_BROKER(broker(),
1583 : "ReduceElementAccess: missing data for typed array "
1584 : << typed_array->object().address() << "\n");
1585 0 : return NoChange();
1586 : }
1587 : }
1588 : }
1589 :
1590 : // Check for the monomorphic case.
1591 22064 : if (access_infos.size() == 1) {
1592 21597 : ElementAccessInfo access_info = access_infos.front();
1593 :
1594 : // Perform possible elements kind transitions.
1595 : MapRef transition_target(broker(), access_info.receiver_maps().front());
1596 22081 : for (auto source : access_info.transition_sources()) {
1597 : DCHECK_EQ(access_info.receiver_maps().size(), 1);
1598 : MapRef transition_source(broker(), source);
1599 1936 : effect = graph()->NewNode(
1600 : simplified()->TransitionElementsKind(ElementsTransition(
1601 484 : IsSimpleMapChangeTransition(transition_source.elements_kind(),
1602 484 : transition_target.elements_kind())
1603 : ? ElementsTransition::kFastTransition
1604 : : ElementsTransition::kSlowTransition,
1605 : transition_source.object(), transition_target.object())),
1606 484 : receiver, effect, control);
1607 : }
1608 :
1609 : // TODO(turbofan): The effect/control linearization will not find a
1610 : // FrameState after the StoreField or Call that is generated for the
1611 : // elements kind transition above. This is because those operators
1612 : // don't have the kNoWrite flag on it, even though they are not
1613 : // observable by JavaScript.
1614 : effect =
1615 43194 : graph()->NewNode(common()->Checkpoint(), frame_state, effect, control);
1616 :
1617 : // Perform map check on the {receiver}.
1618 : access_builder.BuildCheckMaps(receiver, &effect, control,
1619 21597 : access_info.receiver_maps());
1620 :
1621 : // Access the actual element.
1622 : ValueEffectControl continuation =
1623 : BuildElementAccess(receiver, index, value, effect, control, access_info,
1624 21597 : access_mode, load_mode, store_mode);
1625 : value = continuation.value();
1626 21597 : effect = continuation.effect();
1627 21597 : control = continuation.control();
1628 : } else {
1629 : // The final states for every polymorphic branch. We join them with
1630 : // Merge+Phi+EffectPhi at the bottom.
1631 : ZoneVector<Node*> values(zone());
1632 : ZoneVector<Node*> effects(zone());
1633 : ZoneVector<Node*> controls(zone());
1634 :
1635 : // Generate code for the various different element access patterns.
1636 467 : Node* fallthrough_control = control;
1637 2643 : for (size_t j = 0; j < access_infos.size(); ++j) {
1638 : ElementAccessInfo const& access_info = access_infos[j];
1639 : Node* this_receiver = receiver;
1640 : Node* this_value = value;
1641 : Node* this_index = index;
1642 1088 : Node* this_effect = effect;
1643 : Node* this_control = fallthrough_control;
1644 :
1645 : // Perform possible elements kind transitions.
1646 : MapRef transition_target(broker(), access_info.receiver_maps().front());
1647 1174 : for (auto source : access_info.transition_sources()) {
1648 : MapRef transition_source(broker(), source);
1649 : DCHECK_EQ(access_info.receiver_maps().size(), 1);
1650 344 : this_effect = graph()->NewNode(
1651 : simplified()->TransitionElementsKind(ElementsTransition(
1652 86 : IsSimpleMapChangeTransition(transition_source.elements_kind(),
1653 86 : transition_target.elements_kind())
1654 : ? ElementsTransition::kFastTransition
1655 : : ElementsTransition::kSlowTransition,
1656 : transition_source.object(), transition_target.object())),
1657 86 : receiver, effect, control);
1658 : }
1659 :
1660 : // Perform map check(s) on {receiver}.
1661 : MapHandles const& receiver_maps = access_info.receiver_maps();
1662 1088 : if (j == access_infos.size() - 1) {
1663 : // Last map check on the fallthrough control path, do a
1664 : // conditional eager deoptimization exit here.
1665 : access_builder.BuildCheckMaps(receiver, &this_effect, this_control,
1666 467 : receiver_maps);
1667 : fallthrough_control = nullptr;
1668 : } else {
1669 : // Explicitly branch on the {receiver_maps}.
1670 : ZoneHandleSet<Map> maps;
1671 1242 : for (Handle<Map> map : receiver_maps) {
1672 621 : maps.insert(map, graph()->zone());
1673 : }
1674 : Node* check = this_effect =
1675 621 : graph()->NewNode(simplified()->CompareMaps(maps), receiver,
1676 621 : this_effect, fallthrough_control);
1677 : Node* branch =
1678 621 : graph()->NewNode(common()->Branch(), check, fallthrough_control);
1679 621 : fallthrough_control = graph()->NewNode(common()->IfFalse(), branch);
1680 621 : this_control = graph()->NewNode(common()->IfTrue(), branch);
1681 :
1682 : // Introduce a MapGuard to learn from this on the effect chain.
1683 621 : this_effect = graph()->NewNode(simplified()->MapGuard(maps), receiver,
1684 621 : this_effect, this_control);
1685 : }
1686 :
1687 : // Access the actual element.
1688 : ValueEffectControl continuation = BuildElementAccess(
1689 : this_receiver, this_index, this_value, this_effect, this_control,
1690 1088 : access_info, access_mode, load_mode, store_mode);
1691 2176 : values.push_back(continuation.value());
1692 2176 : effects.push_back(continuation.effect());
1693 2176 : controls.push_back(continuation.control());
1694 : }
1695 :
1696 : DCHECK_NULL(fallthrough_control);
1697 :
1698 : // Generate the final merge point for all (polymorphic) branches.
1699 467 : int const control_count = static_cast<int>(controls.size());
1700 467 : if (control_count == 0) {
1701 0 : value = effect = control = jsgraph()->Dead();
1702 467 : } else if (control_count == 1) {
1703 0 : value = values.front();
1704 0 : effect = effects.front();
1705 0 : control = controls.front();
1706 : } else {
1707 467 : control = graph()->NewNode(common()->Merge(control_count), control_count,
1708 467 : &controls.front());
1709 467 : values.push_back(control);
1710 467 : value = graph()->NewNode(
1711 : common()->Phi(MachineRepresentation::kTagged, control_count),
1712 467 : control_count + 1, &values.front());
1713 467 : effects.push_back(control);
1714 467 : effect = graph()->NewNode(common()->EffectPhi(control_count),
1715 467 : control_count + 1, &effects.front());
1716 : }
1717 : }
1718 :
1719 22064 : ReplaceWithValue(node, value, effect, control);
1720 : return Replace(value);
1721 : }
1722 :
1723 5470 : Reduction JSNativeContextSpecialization::ReduceKeyedLoadFromHeapConstant(
1724 : Node* node, Node* index, FeedbackNexus const& nexus, AccessMode access_mode,
1725 : KeyedAccessLoadMode load_mode) {
1726 : DCHECK(node->opcode() == IrOpcode::kJSLoadProperty ||
1727 : node->opcode() == IrOpcode::kJSHasProperty);
1728 5470 : Node* receiver = NodeProperties::GetValueInput(node, 0);
1729 5470 : Node* effect = NodeProperties::GetEffectInput(node);
1730 5470 : Node* control = NodeProperties::GetControlInput(node);
1731 :
1732 : HeapObjectMatcher mreceiver(receiver);
1733 5470 : HeapObjectRef receiver_ref = mreceiver.Ref(broker()).AsHeapObject();
1734 16406 : if (receiver_ref.map().oddball_type() == OddballType::kHole ||
1735 16182 : receiver_ref.map().oddball_type() == OddballType::kNull ||
1736 21368 : receiver_ref.map().oddball_type() == OddballType::kUndefined ||
1737 5447 : (receiver_ref.IsString() && access_mode == AccessMode::kHas)) {
1738 : return NoChange();
1739 : }
1740 :
1741 : // Check whether we're accessing a known element on the {receiver}
1742 : // that is non-configurable, non-writable (e.g. the {receiver} was
1743 : // frozen using Object.freeze).
1744 : NumberMatcher mindex(index);
1745 6722 : if (mindex.IsInteger() && mindex.IsInRange(0.0, kMaxUInt32 - 1.0)) {
1746 : LookupIterator it(isolate(), receiver_ref.object(),
1747 : static_cast<uint32_t>(mindex.Value()),
1748 3078 : LookupIterator::OWN);
1749 1539 : if (it.state() == LookupIterator::DATA) {
1750 1371 : if (it.IsReadOnly() && !it.IsConfigurable()) {
1751 : // We can safely constant-fold the {index} access to {receiver},
1752 : // since the element is non-configurable, non-writable and thus
1753 : // cannot change anymore.
1754 : Node* value = access_mode == AccessMode::kHas
1755 : ? jsgraph()->TrueConstant()
1756 24 : : jsgraph()->Constant(it.GetDataValue());
1757 24 : ReplaceWithValue(node, value, effect, control);
1758 88 : return Replace(value);
1759 : }
1760 :
1761 : // Check if the {receiver} is a known constant with a copy-on-write
1762 : // backing store, and whether {index} is within the appropriate
1763 : // bounds. In that case we can constant-fold the access and only
1764 : // check that the {elements} didn't change. This is sufficient as
1765 : // the backing store of a copy-on-write JSArray is defensively
1766 : // copied whenever the length or the elements (might) change.
1767 : //
1768 : // What's interesting here is that we don't need to map check the
1769 : // {receiver}, since JSArray's will always have their elements in
1770 : // the backing store.
1771 1323 : if (receiver_ref.IsJSArray()) {
1772 894 : Handle<JSArray> array = receiver_ref.AsJSArray().object();
1773 894 : if (array->elements()->IsCowArray()) {
1774 128 : Node* elements = effect = graph()->NewNode(
1775 128 : simplified()->LoadField(AccessBuilder::ForJSObjectElements()),
1776 64 : receiver, effect, control);
1777 : Handle<FixedArray> array_elements(FixedArray::cast(array->elements()),
1778 : isolate());
1779 : Node* check =
1780 128 : graph()->NewNode(simplified()->ReferenceEqual(), elements,
1781 : jsgraph()->HeapConstant(array_elements));
1782 128 : effect = graph()->NewNode(
1783 : simplified()->CheckIf(DeoptimizeReason::kCowArrayElementsChanged),
1784 64 : check, effect, control);
1785 : Node* value = access_mode == AccessMode::kHas
1786 : ? jsgraph()->TrueConstant()
1787 64 : : jsgraph()->Constant(it.GetDataValue());
1788 64 : ReplaceWithValue(node, value, effect, control);
1789 : return Replace(value);
1790 : }
1791 : }
1792 : }
1793 : }
1794 :
1795 : // For constant Strings we can eagerly strength-reduce the keyed
1796 : // accesses using the known length, which doesn't change.
1797 5084 : if (receiver_ref.IsString() && access_mode != AccessMode::kHas) {
1798 : // We can only assume that the {index} is a valid array index if the
1799 : // IC is in element access mode and not MEGAMORPHIC, otherwise there's
1800 : // no guard for the bounds check below.
1801 239 : if (nexus.ic_state() != MEGAMORPHIC && nexus.GetKeyType() == ELEMENT) {
1802 : // Ensure that {index} is less than {receiver} length.
1803 216 : Node* length = jsgraph()->Constant(receiver_ref.AsString().length());
1804 :
1805 : // Load the single character string from {receiver} or yield
1806 : // undefined if the {index} is out of bounds (depending on the
1807 : // {load_mode}).
1808 : Node* value = BuildIndexedStringLoad(receiver, index, length, &effect,
1809 216 : &control, load_mode);
1810 216 : ReplaceWithValue(node, value, effect, control);
1811 : return Replace(value);
1812 : }
1813 : }
1814 :
1815 : return NoChange();
1816 : }
1817 :
1818 58736 : Reduction JSNativeContextSpecialization::ReduceKeyedAccess(
1819 : Node* node, Node* index, Node* value, FeedbackNexus const& nexus,
1820 : AccessMode access_mode, KeyedAccessLoadMode load_mode,
1821 : KeyedAccessStoreMode store_mode) {
1822 : DCHECK(node->opcode() == IrOpcode::kJSLoadProperty ||
1823 : node->opcode() == IrOpcode::kJSStoreProperty ||
1824 : node->opcode() == IrOpcode::kJSHasProperty);
1825 :
1826 58736 : Node* receiver = NodeProperties::GetValueInput(node, 0);
1827 58736 : Node* effect = NodeProperties::GetEffectInput(node);
1828 :
1829 105037 : if ((access_mode == AccessMode::kLoad || access_mode == AccessMode::kHas) &&
1830 : receiver->opcode() == IrOpcode::kHeapConstant) {
1831 : Reduction reduction = ReduceKeyedLoadFromHeapConstant(
1832 5470 : node, index, nexus, access_mode, load_mode);
1833 5470 : if (reduction.Changed()) return reduction;
1834 : }
1835 :
1836 : // Extract receiver maps from the {nexus}.
1837 : MapHandles receiver_maps;
1838 58432 : if (!ExtractReceiverMaps(receiver, effect, nexus, &receiver_maps)) {
1839 : return NoChange();
1840 52622 : } else if (receiver_maps.empty()) {
1841 : return ReduceSoftDeoptimize(
1842 29710 : node, DeoptimizeReason::kInsufficientTypeFeedbackForGenericKeyedAccess);
1843 : }
1844 : DCHECK(!nexus.IsUninitialized());
1845 :
1846 : // Optimize access for constant {index}.
1847 : HeapObjectMatcher mindex(index);
1848 22912 : if (mindex.HasValue()) {
1849 703 : ObjectRef name = mindex.Ref(broker());
1850 703 : if (name.IsSymbol()) {
1851 : return ReduceNamedAccess(node, value, receiver_maps,
1852 254 : name.AsName().object(), access_mode);
1853 : }
1854 449 : if (name.IsInternalizedString()) {
1855 449 : uint32_t array_index = name.AsInternalizedString().array_index();
1856 449 : if (array_index != InternalizedStringRef::kNotAnArrayIndex) {
1857 0 : index = jsgraph()->Constant(static_cast<double>(array_index));
1858 : } else {
1859 : return ReduceNamedAccess(node, value, receiver_maps,
1860 449 : name.AsName().object(), access_mode);
1861 : }
1862 : }
1863 : }
1864 :
1865 : // Check if we have feedback for a named access.
1866 22209 : Name name = nexus.GetName();
1867 22209 : if (!name.is_null()) {
1868 : return ReduceNamedAccess(node, value, receiver_maps,
1869 356 : handle(name, isolate()), access_mode, index);
1870 21853 : } else if (nexus.GetKeyType() != ELEMENT) {
1871 : // The KeyedLoad/StoreIC has seen non-element accesses, so we cannot assume
1872 : // that the {index} is a valid array index, thus we just let the IC continue
1873 : // to deal with this load/store.
1874 : return NoChange();
1875 21818 : } else if (nexus.ic_state() == MEGAMORPHIC) {
1876 : // The KeyedLoad/StoreIC uses the MEGAMORPHIC state to guard the assumption
1877 : // that a numeric {index} is within the valid bounds for {receiver}, i.e.
1878 : // it transitions to MEGAMORPHIC once it sees an out-of-bounds access. Thus
1879 : // we cannot continue here if the IC state is MEGAMORPHIC.
1880 : return NoChange();
1881 : }
1882 :
1883 : // Try to lower the element access based on the {receiver_maps}.
1884 : return ReduceElementAccess(node, index, value, nexus, receiver_maps,
1885 20600 : access_mode, load_mode, store_mode);
1886 : }
1887 :
1888 416241 : Reduction JSNativeContextSpecialization::ReduceSoftDeoptimize(
1889 : Node* node, DeoptimizeReason reason) {
1890 416241 : if (flags() & kBailoutOnUninitialized) {
1891 284 : Node* effect = NodeProperties::GetEffectInput(node);
1892 284 : Node* control = NodeProperties::GetControlInput(node);
1893 284 : Node* frame_state = NodeProperties::FindFrameStateBefore(node);
1894 568 : Node* deoptimize = graph()->NewNode(
1895 : common()->Deoptimize(DeoptimizeKind::kSoft, reason, VectorSlotPair()),
1896 : frame_state, effect, control);
1897 : // TODO(bmeurer): This should be on the AdvancedReducer somehow.
1898 284 : NodeProperties::MergeControlToEnd(graph(), common(), deoptimize);
1899 : Revisit(graph()->end());
1900 284 : node->TrimInputCount(0);
1901 284 : NodeProperties::ChangeOp(node, common()->Dead());
1902 : return Changed(node);
1903 : }
1904 : return NoChange();
1905 : }
1906 :
1907 1586 : Reduction JSNativeContextSpecialization::ReduceJSHasProperty(Node* node) {
1908 : DCHECK_EQ(IrOpcode::kJSHasProperty, node->opcode());
1909 1586 : PropertyAccess const& p = PropertyAccessOf(node->op());
1910 1586 : Node* index = NodeProperties::GetValueInput(node, 1);
1911 1586 : Node* value = jsgraph()->Dead();
1912 :
1913 : // Extract receiver maps from the has property IC using the FeedbackNexus.
1914 1586 : if (!p.feedback().IsValid()) return NoChange();
1915 : FeedbackNexus nexus(p.feedback().vector(), p.feedback().slot());
1916 :
1917 : // Extract the keyed access load mode from the keyed load IC.
1918 1546 : KeyedAccessLoadMode load_mode = nexus.GetKeyedAccessLoadMode();
1919 :
1920 : // Try to lower the keyed access based on the {nexus}.
1921 : return ReduceKeyedAccess(node, index, value, nexus, AccessMode::kHas,
1922 1546 : load_mode, STANDARD_STORE);
1923 : }
1924 :
1925 1258 : Reduction JSNativeContextSpecialization::ReduceJSLoadPropertyWithEnumeratedKey(
1926 : Node* node) {
1927 : // We can optimize a property load if it's being used inside a for..in:
1928 : // for (name in receiver) {
1929 : // value = receiver[name];
1930 : // ...
1931 : // }
1932 : //
1933 : // If the for..in is in fast-mode, we know that the {receiver} has {name}
1934 : // as own property, otherwise the enumeration wouldn't include it. The graph
1935 : // constructed by the BytecodeGraphBuilder in this case looks like this:
1936 :
1937 : // receiver
1938 : // ^ ^
1939 : // | |
1940 : // | +-+
1941 : // | |
1942 : // | JSToObject
1943 : // | ^
1944 : // | |
1945 : // | |
1946 : // | JSForInNext
1947 : // | ^
1948 : // | |
1949 : // +----+ |
1950 : // | |
1951 : // | |
1952 : // JSLoadProperty
1953 :
1954 : // If the for..in has only seen maps with enum cache consisting of keys
1955 : // and indices so far, we can turn the {JSLoadProperty} into a map check
1956 : // on the {receiver} and then just load the field value dynamically via
1957 : // the {LoadFieldByIndex} operator. The map check is only necessary when
1958 : // TurboFan cannot prove that there is no observable side effect between
1959 : // the {JSForInNext} and the {JSLoadProperty} node.
1960 : //
1961 : // Also note that it's safe to look through the {JSToObject}, since the
1962 : // [[Get]] operation does an implicit ToObject anyway, and these operations
1963 : // are not observable.
1964 :
1965 : DCHECK_EQ(IrOpcode::kJSLoadProperty, node->opcode());
1966 1258 : Node* receiver = NodeProperties::GetValueInput(node, 0);
1967 1258 : Node* name = NodeProperties::GetValueInput(node, 1);
1968 : DCHECK_EQ(IrOpcode::kJSForInNext, name->opcode());
1969 1258 : Node* effect = NodeProperties::GetEffectInput(node);
1970 1258 : Node* control = NodeProperties::GetControlInput(node);
1971 :
1972 1258 : if (ForInModeOf(name->op()) != ForInMode::kUseEnumCacheKeysAndIndices) {
1973 : return NoChange();
1974 : }
1975 :
1976 683 : Node* object = NodeProperties::GetValueInput(name, 0);
1977 683 : Node* enumerator = NodeProperties::GetValueInput(name, 2);
1978 683 : Node* index = NodeProperties::GetValueInput(name, 3);
1979 683 : if (object->opcode() == IrOpcode::kJSToObject) {
1980 613 : object = NodeProperties::GetValueInput(object, 0);
1981 : }
1982 683 : if (object != receiver) return NoChange();
1983 :
1984 : // No need to repeat the map check if we can prove that there's no
1985 : // observable side effect between {effect} and {name].
1986 311 : if (!NodeProperties::NoObservableSideEffectBetween(effect, name)) {
1987 : // Check that the {receiver} map is still valid.
1988 : Node* receiver_map = effect =
1989 486 : graph()->NewNode(simplified()->LoadField(AccessBuilder::ForMap()),
1990 : receiver, effect, control);
1991 243 : Node* check = graph()->NewNode(simplified()->ReferenceEqual(), receiver_map,
1992 : enumerator);
1993 : effect =
1994 486 : graph()->NewNode(simplified()->CheckIf(DeoptimizeReason::kWrongMap),
1995 : check, effect, control);
1996 : }
1997 :
1998 : // Load the enum cache indices from the {cache_type}.
1999 311 : Node* descriptor_array = effect = graph()->NewNode(
2000 622 : simplified()->LoadField(AccessBuilder::ForMapDescriptors()), enumerator,
2001 : effect, control);
2002 311 : Node* enum_cache = effect = graph()->NewNode(
2003 622 : simplified()->LoadField(AccessBuilder::ForDescriptorArrayEnumCache()),
2004 : descriptor_array, effect, control);
2005 311 : Node* enum_indices = effect = graph()->NewNode(
2006 622 : simplified()->LoadField(AccessBuilder::ForEnumCacheIndices()), enum_cache,
2007 : effect, control);
2008 :
2009 : // Ensure that the {enum_indices} are valid.
2010 622 : Node* check = graph()->NewNode(
2011 : simplified()->BooleanNot(),
2012 : graph()->NewNode(simplified()->ReferenceEqual(), enum_indices,
2013 : jsgraph()->EmptyFixedArrayConstant()));
2014 622 : effect = graph()->NewNode(
2015 : simplified()->CheckIf(DeoptimizeReason::kWrongEnumIndices), check, effect,
2016 : control);
2017 :
2018 : // Determine the index from the {enum_indices}.
2019 311 : index = effect = graph()->NewNode(
2020 : simplified()->LoadElement(
2021 622 : AccessBuilder::ForFixedArrayElement(PACKED_SMI_ELEMENTS)),
2022 : enum_indices, index, effect, control);
2023 :
2024 : // Load the actual field value.
2025 311 : Node* value = effect = graph()->NewNode(simplified()->LoadFieldByIndex(),
2026 : receiver, index, effect, control);
2027 : ReplaceWithValue(node, value, effect, control);
2028 : return Replace(value);
2029 : }
2030 :
2031 45066 : Reduction JSNativeContextSpecialization::ReduceJSLoadProperty(Node* node) {
2032 : DCHECK_EQ(IrOpcode::kJSLoadProperty, node->opcode());
2033 45066 : PropertyAccess const& p = PropertyAccessOf(node->op());
2034 45066 : Node* name = NodeProperties::GetValueInput(node, 1);
2035 :
2036 45066 : if (name->opcode() == IrOpcode::kJSForInNext) {
2037 1258 : Reduction reduction = ReduceJSLoadPropertyWithEnumeratedKey(node);
2038 1258 : if (reduction.Changed()) return reduction;
2039 : }
2040 :
2041 : // Extract receiver maps from the keyed load IC using the FeedbackNexus.
2042 44755 : if (!p.feedback().IsValid()) return NoChange();
2043 : FeedbackNexus nexus(p.feedback().vector(), p.feedback().slot());
2044 :
2045 : // Extract the keyed access load mode from the keyed load IC.
2046 44755 : KeyedAccessLoadMode load_mode = nexus.GetKeyedAccessLoadMode();
2047 :
2048 : // Try to lower the keyed access based on the {nexus}.
2049 44755 : Node* value = jsgraph()->Dead();
2050 : return ReduceKeyedAccess(node, name, value, nexus, AccessMode::kLoad,
2051 44755 : load_mode, STANDARD_STORE);
2052 : }
2053 :
2054 12435 : Reduction JSNativeContextSpecialization::ReduceJSStoreProperty(Node* node) {
2055 : DCHECK_EQ(IrOpcode::kJSStoreProperty, node->opcode());
2056 12435 : PropertyAccess const& p = PropertyAccessOf(node->op());
2057 12435 : Node* const index = NodeProperties::GetValueInput(node, 1);
2058 12435 : Node* const value = NodeProperties::GetValueInput(node, 2);
2059 :
2060 : // Extract receiver maps from the keyed store IC using the FeedbackNexus.
2061 12435 : if (!p.feedback().IsValid()) return NoChange();
2062 : FeedbackNexus nexus(p.feedback().vector(), p.feedback().slot());
2063 :
2064 : // Extract the keyed access store mode from the keyed store IC.
2065 12435 : KeyedAccessStoreMode store_mode = nexus.GetKeyedAccessStoreMode();
2066 :
2067 : // Try to lower the keyed access based on the {nexus}.
2068 : return ReduceKeyedAccess(node, index, value, nexus, AccessMode::kStore,
2069 12435 : STANDARD_LOAD, store_mode);
2070 : }
2071 :
2072 2416 : Node* JSNativeContextSpecialization::InlinePropertyGetterCall(
2073 : Node* receiver, Node* context, Node* frame_state, Node** effect,
2074 : Node** control, ZoneVector<Node*>* if_exceptions,
2075 : PropertyAccessInfo const& access_info) {
2076 2416 : Node* target = jsgraph()->Constant(access_info.constant());
2077 2416 : FrameStateInfo const& frame_info = FrameStateInfoOf(frame_state->op());
2078 : Handle<SharedFunctionInfo> shared_info =
2079 2416 : frame_info.shared_info().ToHandleChecked();
2080 : // Introduce the call to the getter function.
2081 : Node* value;
2082 2416 : if (access_info.constant()->IsJSFunction()) {
2083 7056 : value = *effect = *control = graph()->NewNode(
2084 : jsgraph()->javascript()->Call(2, CallFrequency(), VectorSlotPair(),
2085 : ConvertReceiverMode::kNotNullOrUndefined),
2086 2352 : target, receiver, context, frame_state, *effect, *control);
2087 : } else {
2088 : DCHECK(access_info.constant()->IsFunctionTemplateInfo());
2089 : Handle<FunctionTemplateInfo> function_template_info(
2090 64 : Handle<FunctionTemplateInfo>::cast(access_info.constant()));
2091 : DCHECK(!function_template_info->call_code()->IsUndefined(isolate()));
2092 : Node* holder =
2093 : access_info.holder().is_null()
2094 : ? receiver
2095 64 : : jsgraph()->Constant(access_info.holder().ToHandleChecked());
2096 : value = InlineApiCall(receiver, holder, frame_state, nullptr, effect,
2097 64 : control, shared_info, function_template_info);
2098 : }
2099 : // Remember to rewire the IfException edge if this is inside a try-block.
2100 2416 : if (if_exceptions != nullptr) {
2101 : // Create the appropriate IfException/IfSuccess projections.
2102 : Node* const if_exception =
2103 460 : graph()->NewNode(common()->IfException(), *control, *effect);
2104 230 : Node* const if_success = graph()->NewNode(common()->IfSuccess(), *control);
2105 230 : if_exceptions->push_back(if_exception);
2106 230 : *control = if_success;
2107 : }
2108 2416 : return value;
2109 : }
2110 :
2111 850 : void JSNativeContextSpecialization::InlinePropertySetterCall(
2112 : Node* receiver, Node* value, Node* context, Node* frame_state,
2113 : Node** effect, Node** control, ZoneVector<Node*>* if_exceptions,
2114 : PropertyAccessInfo const& access_info) {
2115 850 : Node* target = jsgraph()->Constant(access_info.constant());
2116 850 : FrameStateInfo const& frame_info = FrameStateInfoOf(frame_state->op());
2117 : Handle<SharedFunctionInfo> shared_info =
2118 850 : frame_info.shared_info().ToHandleChecked();
2119 : // Introduce the call to the setter function.
2120 850 : if (access_info.constant()->IsJSFunction()) {
2121 2358 : *effect = *control = graph()->NewNode(
2122 : jsgraph()->javascript()->Call(3, CallFrequency(), VectorSlotPair(),
2123 : ConvertReceiverMode::kNotNullOrUndefined),
2124 786 : target, receiver, value, context, frame_state, *effect, *control);
2125 : } else {
2126 : DCHECK(access_info.constant()->IsFunctionTemplateInfo());
2127 : Handle<FunctionTemplateInfo> function_template_info(
2128 64 : Handle<FunctionTemplateInfo>::cast(access_info.constant()));
2129 : DCHECK(!function_template_info->call_code()->IsUndefined(isolate()));
2130 : Node* holder =
2131 : access_info.holder().is_null()
2132 : ? receiver
2133 64 : : jsgraph()->Constant(access_info.holder().ToHandleChecked());
2134 : InlineApiCall(receiver, holder, frame_state, value, effect, control,
2135 64 : shared_info, function_template_info);
2136 : }
2137 : // Remember to rewire the IfException edge if this is inside a try-block.
2138 850 : if (if_exceptions != nullptr) {
2139 : // Create the appropriate IfException/IfSuccess projections.
2140 : Node* const if_exception =
2141 62 : graph()->NewNode(common()->IfException(), *control, *effect);
2142 31 : Node* const if_success = graph()->NewNode(common()->IfSuccess(), *control);
2143 31 : if_exceptions->push_back(if_exception);
2144 31 : *control = if_success;
2145 : }
2146 850 : }
2147 :
2148 128 : Node* JSNativeContextSpecialization::InlineApiCall(
2149 : Node* receiver, Node* holder, Node* frame_state, Node* value, Node** effect,
2150 : Node** control, Handle<SharedFunctionInfo> shared_info,
2151 : Handle<FunctionTemplateInfo> function_template_info) {
2152 : Handle<CallHandlerInfo> call_handler_info = handle(
2153 : CallHandlerInfo::cast(function_template_info->call_code()), isolate());
2154 : Handle<Object> call_data_object(call_handler_info->data(), isolate());
2155 :
2156 : // Only setters have a value.
2157 128 : int const argc = value == nullptr ? 0 : 1;
2158 : // The stub always expects the receiver as the first param on the stack.
2159 128 : Callable call_api_callback = CodeFactory::CallApiCallback(isolate());
2160 : CallInterfaceDescriptor call_interface_descriptor =
2161 : call_api_callback.descriptor();
2162 256 : auto call_descriptor = Linkage::GetStubCallDescriptor(
2163 : graph()->zone(), call_interface_descriptor,
2164 128 : call_interface_descriptor.GetStackParameterCount() + argc +
2165 : 1 /* implicit receiver */,
2166 128 : CallDescriptor::kNeedsFrameState);
2167 :
2168 128 : Node* data = jsgraph()->Constant(call_data_object);
2169 : ApiFunction function(v8::ToCData<Address>(call_handler_info->callback()));
2170 : Node* function_reference =
2171 256 : graph()->NewNode(common()->ExternalConstant(ExternalReference::Create(
2172 : &function, ExternalReference::DIRECT_API_CALL)));
2173 128 : Node* code = jsgraph()->HeapConstant(call_api_callback.code());
2174 :
2175 : // Add CallApiCallbackStub's register argument as well.
2176 128 : Node* context = jsgraph()->Constant(native_context());
2177 : Node* inputs[11] = {
2178 128 : code, function_reference, jsgraph()->Constant(argc), data, holder,
2179 256 : receiver};
2180 128 : int index = 6 + argc;
2181 128 : inputs[index++] = context;
2182 128 : inputs[index++] = frame_state;
2183 128 : inputs[index++] = *effect;
2184 128 : inputs[index++] = *control;
2185 : // This needs to stay here because of the edge case described in
2186 : // http://crbug.com/675648.
2187 128 : if (value != nullptr) {
2188 64 : inputs[6] = value;
2189 : }
2190 :
2191 : return *effect = *control =
2192 256 : graph()->NewNode(common()->Call(call_descriptor), index, inputs);
2193 : }
2194 :
2195 : JSNativeContextSpecialization::ValueEffectControl
2196 102342 : JSNativeContextSpecialization::BuildPropertyLoad(
2197 : Node* receiver, Node* context, Node* frame_state, Node* effect,
2198 : Node* control, Handle<Name> name, ZoneVector<Node*>* if_exceptions,
2199 : PropertyAccessInfo const& access_info) {
2200 : // Determine actual holder and perform prototype chain checks.
2201 : Handle<JSObject> holder;
2202 : PropertyAccessBuilder access_builder(jsgraph(), broker(), dependencies());
2203 102342 : if (access_info.holder().ToHandle(&holder)) {
2204 27680 : dependencies()->DependOnStablePrototypeChains(
2205 27680 : access_info.receiver_maps(), JSObjectRef(broker(), holder));
2206 : }
2207 :
2208 : // Generate the actual property access.
2209 : Node* value;
2210 102342 : if (access_info.IsNotFound()) {
2211 3201 : value = jsgraph()->UndefinedConstant();
2212 99141 : } else if (access_info.IsDataConstant()) {
2213 : DCHECK(!FLAG_track_constant_fields);
2214 0 : value = jsgraph()->Constant(access_info.constant());
2215 99141 : } else if (access_info.IsAccessorConstant()) {
2216 : value = InlinePropertyGetterCall(receiver, context, frame_state, &effect,
2217 2416 : &control, if_exceptions, access_info);
2218 96725 : } else if (access_info.IsModuleExport()) {
2219 14 : Node* cell = jsgraph()->Constant(access_info.export_cell());
2220 : value = effect =
2221 14 : graph()->NewNode(simplified()->LoadField(AccessBuilder::ForCellValue()),
2222 7 : cell, effect, control);
2223 96718 : } else if (access_info.IsStringLength()) {
2224 1817 : value = graph()->NewNode(simplified()->StringLength(), receiver);
2225 : } else {
2226 : DCHECK(access_info.IsDataField() || access_info.IsDataConstantField());
2227 : value = access_builder.BuildLoadDataField(name, access_info, receiver,
2228 94901 : &effect, &control);
2229 : }
2230 :
2231 204684 : return ValueEffectControl(value, effect, control);
2232 : }
2233 :
2234 : JSNativeContextSpecialization::ValueEffectControl
2235 242 : JSNativeContextSpecialization::BuildPropertyTest(
2236 : Node* effect, Node* control, PropertyAccessInfo const& access_info) {
2237 : // Determine actual holder and perform prototype chain checks.
2238 : Handle<JSObject> holder;
2239 242 : if (access_info.holder().ToHandle(&holder)) {
2240 173 : dependencies()->DependOnStablePrototypeChains(
2241 173 : access_info.receiver_maps(), JSObjectRef(broker(), holder));
2242 : }
2243 :
2244 : Node* value = access_info.IsNotFound() ? jsgraph()->FalseConstant()
2245 242 : : jsgraph()->TrueConstant();
2246 :
2247 242 : return ValueEffectControl(value, effect, control);
2248 : }
2249 :
2250 : JSNativeContextSpecialization::ValueEffectControl
2251 130601 : JSNativeContextSpecialization::BuildPropertyAccess(
2252 : Node* receiver, Node* value, Node* context, Node* frame_state, Node* effect,
2253 : Node* control, Handle<Name> name, ZoneVector<Node*>* if_exceptions,
2254 : PropertyAccessInfo const& access_info, AccessMode access_mode) {
2255 130601 : switch (access_mode) {
2256 : case AccessMode::kLoad:
2257 : return BuildPropertyLoad(receiver, context, frame_state, effect, control,
2258 102342 : name, if_exceptions, access_info);
2259 : case AccessMode::kStore:
2260 : case AccessMode::kStoreInLiteral:
2261 : return BuildPropertyStore(receiver, value, context, frame_state, effect,
2262 : control, name, if_exceptions, access_info,
2263 28017 : access_mode);
2264 : case AccessMode::kHas:
2265 242 : return BuildPropertyTest(effect, control, access_info);
2266 : }
2267 0 : UNREACHABLE();
2268 : return ValueEffectControl();
2269 : }
2270 :
2271 : JSNativeContextSpecialization::ValueEffectControl
2272 28017 : JSNativeContextSpecialization::BuildPropertyStore(
2273 : Node* receiver, Node* value, Node* context, Node* frame_state, Node* effect,
2274 : Node* control, Handle<Name> name, ZoneVector<Node*>* if_exceptions,
2275 : PropertyAccessInfo const& access_info, AccessMode access_mode) {
2276 : // Determine actual holder and perform prototype chain checks.
2277 : Handle<JSObject> holder;
2278 : PropertyAccessBuilder access_builder(jsgraph(), broker(), dependencies());
2279 28017 : if (access_info.holder().ToHandle(&holder)) {
2280 : DCHECK_NE(AccessMode::kStoreInLiteral, access_mode);
2281 21735 : dependencies()->DependOnStablePrototypeChains(
2282 21735 : access_info.receiver_maps(), JSObjectRef(broker(), holder));
2283 : }
2284 :
2285 : DCHECK(!access_info.IsNotFound());
2286 :
2287 : // Generate the actual property access.
2288 28017 : if (access_info.IsDataConstant()) {
2289 : DCHECK(!FLAG_track_constant_fields);
2290 0 : Node* constant_value = jsgraph()->Constant(access_info.constant());
2291 : Node* check =
2292 0 : graph()->NewNode(simplified()->ReferenceEqual(), value, constant_value);
2293 : effect =
2294 0 : graph()->NewNode(simplified()->CheckIf(DeoptimizeReason::kWrongValue),
2295 0 : check, effect, control);
2296 : value = constant_value;
2297 28017 : } else if (access_info.IsAccessorConstant()) {
2298 : InlinePropertySetterCall(receiver, value, context, frame_state, &effect,
2299 850 : &control, if_exceptions, access_info);
2300 : } else {
2301 : DCHECK(access_info.IsDataField() || access_info.IsDataConstantField());
2302 : FieldIndex const field_index = access_info.field_index();
2303 : Type const field_type = access_info.field_type();
2304 : MachineRepresentation const field_representation =
2305 27167 : access_info.field_representation();
2306 : Node* storage = receiver;
2307 27167 : if (!field_index.is_inobject()) {
2308 13354 : storage = effect = graph()->NewNode(
2309 13354 : simplified()->LoadField(AccessBuilder::ForJSObjectPropertiesOrHash()),
2310 6677 : storage, effect, control);
2311 : }
2312 : FieldAccess field_access = {
2313 : kTaggedBase,
2314 : field_index.offset(),
2315 : name,
2316 : MaybeHandle<Map>(),
2317 : field_type,
2318 : MachineType::TypeForRepresentation(field_representation),
2319 27167 : kFullWriteBarrier};
2320 : bool store_to_constant_field = FLAG_track_constant_fields &&
2321 27167 : (access_mode == AccessMode::kStore) &&
2322 : access_info.IsDataConstantField();
2323 :
2324 : DCHECK(access_mode == AccessMode::kStore ||
2325 : access_mode == AccessMode::kStoreInLiteral);
2326 27167 : switch (field_representation) {
2327 : case MachineRepresentation::kFloat64: {
2328 : value = effect =
2329 640 : graph()->NewNode(simplified()->CheckNumber(VectorSlotPair()), value,
2330 320 : effect, control);
2331 : if (!field_index.is_inobject() || field_index.is_hidden_field() ||
2332 : !FLAG_unbox_double_fields) {
2333 320 : if (access_info.HasTransitionMap()) {
2334 : // Allocate a MutableHeapNumber for the new property.
2335 155 : AllocationBuilder a(jsgraph(), effect, control);
2336 : a.Allocate(HeapNumber::kSize, AllocationType::kYoung,
2337 155 : Type::OtherInternal());
2338 310 : a.Store(AccessBuilder::ForMap(),
2339 155 : factory()->mutable_heap_number_map());
2340 155 : a.Store(AccessBuilder::ForHeapNumberValue(), value);
2341 155 : value = effect = a.Finish();
2342 :
2343 155 : field_access.type = Type::Any();
2344 155 : field_access.machine_type = MachineType::TaggedPointer();
2345 155 : field_access.write_barrier_kind = kPointerWriteBarrier;
2346 : } else {
2347 : // We just store directly to the MutableHeapNumber.
2348 : FieldAccess const storage_access = {kTaggedBase,
2349 : field_index.offset(),
2350 : name,
2351 : MaybeHandle<Map>(),
2352 : Type::OtherInternal(),
2353 : MachineType::TaggedPointer(),
2354 : kPointerWriteBarrier};
2355 : storage = effect =
2356 165 : graph()->NewNode(simplified()->LoadField(storage_access),
2357 165 : storage, effect, control);
2358 165 : field_access.offset = HeapNumber::kValueOffset;
2359 165 : field_access.name = MaybeHandle<Name>();
2360 165 : field_access.machine_type = MachineType::Float64();
2361 : }
2362 : }
2363 320 : if (store_to_constant_field) {
2364 : DCHECK(!access_info.HasTransitionMap());
2365 : // If the field is constant check that the value we are going
2366 : // to store matches current value.
2367 39 : Node* current_value = effect = graph()->NewNode(
2368 39 : simplified()->LoadField(field_access), storage, effect, control);
2369 :
2370 39 : Node* check = graph()->NewNode(simplified()->NumberEqual(),
2371 : current_value, value);
2372 78 : effect = graph()->NewNode(
2373 : simplified()->CheckIf(DeoptimizeReason::kWrongValue), check,
2374 39 : effect, control);
2375 297 : return ValueEffectControl(value, effect, control);
2376 : }
2377 : break;
2378 : }
2379 : case MachineRepresentation::kTaggedSigned:
2380 : case MachineRepresentation::kTaggedPointer:
2381 : case MachineRepresentation::kTagged:
2382 26847 : if (store_to_constant_field) {
2383 : DCHECK(!access_info.HasTransitionMap());
2384 : // If the field is constant check that the value we are going
2385 : // to store matches current value.
2386 219 : Node* current_value = effect = graph()->NewNode(
2387 219 : simplified()->LoadField(field_access), storage, effect, control);
2388 :
2389 219 : Node* check = graph()->NewNode(simplified()->ReferenceEqual(),
2390 : current_value, value);
2391 438 : effect = graph()->NewNode(
2392 : simplified()->CheckIf(DeoptimizeReason::kWrongValue), check,
2393 219 : effect, control);
2394 219 : return ValueEffectControl(value, effect, control);
2395 : }
2396 :
2397 26628 : if (field_representation == MachineRepresentation::kTaggedSigned) {
2398 40168 : value = effect = graph()->NewNode(
2399 20084 : simplified()->CheckSmi(VectorSlotPair()), value, effect, control);
2400 20084 : field_access.write_barrier_kind = kNoWriteBarrier;
2401 :
2402 6544 : } else if (field_representation ==
2403 : MachineRepresentation::kTaggedPointer) {
2404 : // Ensure that {value} is a HeapObject.
2405 3385 : value = access_builder.BuildCheckHeapObject(value, &effect, control);
2406 : Handle<Map> field_map;
2407 3385 : if (access_info.field_map().ToHandle(&field_map)) {
2408 : // Emit a map check for the value.
2409 783 : effect = graph()->NewNode(
2410 : simplified()->CheckMaps(CheckMapsFlag::kNone,
2411 : ZoneHandleSet<Map>(field_map)),
2412 261 : value, effect, control);
2413 : }
2414 3385 : field_access.write_barrier_kind = kPointerWriteBarrier;
2415 :
2416 : } else {
2417 : DCHECK_EQ(MachineRepresentation::kTagged, field_representation);
2418 : }
2419 : break;
2420 : case MachineRepresentation::kNone:
2421 : case MachineRepresentation::kBit:
2422 : case MachineRepresentation::kWord8:
2423 : case MachineRepresentation::kWord16:
2424 : case MachineRepresentation::kWord32:
2425 : case MachineRepresentation::kWord64:
2426 : case MachineRepresentation::kFloat32:
2427 : case MachineRepresentation::kSimd128:
2428 : // TODO(solanes): Create the code for the compressed values
2429 : case MachineRepresentation::kCompressedSigned:
2430 : case MachineRepresentation::kCompressedPointer:
2431 : case MachineRepresentation::kCompressed:
2432 0 : UNREACHABLE();
2433 : break;
2434 : }
2435 : // Check if we need to perform a transitioning store.
2436 : Handle<Map> transition_map;
2437 26909 : if (access_info.transition_map().ToHandle(&transition_map)) {
2438 : // Check if we need to grow the properties backing store
2439 : // with this transitioning store.
2440 : Handle<Map> original_map(Map::cast(transition_map->GetBackPointer()),
2441 42904 : isolate());
2442 21452 : if (original_map->UnusedPropertyFields() == 0) {
2443 : DCHECK(!field_index.is_inobject());
2444 :
2445 : // Reallocate the properties {storage}.
2446 6894 : storage = effect = BuildExtendPropertiesBackingStore(
2447 2298 : MapRef(broker(), original_map), storage, effect, control);
2448 :
2449 : // Perform the actual store.
2450 2298 : effect = graph()->NewNode(simplified()->StoreField(field_access),
2451 2298 : storage, value, effect, control);
2452 :
2453 : // Atomically switch to the new properties below.
2454 2298 : field_access = AccessBuilder::ForJSObjectPropertiesOrHash();
2455 : value = storage;
2456 : storage = receiver;
2457 : }
2458 21452 : effect = graph()->NewNode(
2459 21452 : common()->BeginRegion(RegionObservability::kObservable), effect);
2460 85808 : effect = graph()->NewNode(
2461 42904 : simplified()->StoreField(AccessBuilder::ForMap()), receiver,
2462 21452 : jsgraph()->Constant(transition_map), effect, control);
2463 21452 : effect = graph()->NewNode(simplified()->StoreField(field_access), storage,
2464 21452 : value, effect, control);
2465 21452 : effect = graph()->NewNode(common()->FinishRegion(),
2466 21452 : jsgraph()->UndefinedConstant(), effect);
2467 : } else {
2468 : // Regular non-transitioning field store.
2469 5457 : effect = graph()->NewNode(simplified()->StoreField(field_access), storage,
2470 5457 : value, effect, control);
2471 : }
2472 : }
2473 :
2474 27759 : return ValueEffectControl(value, effect, control);
2475 : }
2476 :
2477 540 : Reduction JSNativeContextSpecialization::ReduceJSStoreDataPropertyInLiteral(
2478 : Node* node) {
2479 : DCHECK_EQ(IrOpcode::kJSStoreDataPropertyInLiteral, node->opcode());
2480 :
2481 540 : FeedbackParameter const& p = FeedbackParameterOf(node->op());
2482 :
2483 540 : if (!p.feedback().IsValid()) return NoChange();
2484 :
2485 : FeedbackNexus nexus(p.feedback().vector(), p.feedback().slot());
2486 540 : if (nexus.IsUninitialized()) {
2487 : return NoChange();
2488 : }
2489 :
2490 144 : if (nexus.ic_state() == MEGAMORPHIC) {
2491 : return NoChange();
2492 : }
2493 :
2494 : DCHECK_EQ(MONOMORPHIC, nexus.ic_state());
2495 :
2496 128 : Map map = nexus.GetFirstMap();
2497 128 : if (map.is_null()) {
2498 : // Maps are weakly held in the type feedback vector, we may not have one.
2499 : return NoChange();
2500 : }
2501 :
2502 : Handle<Map> receiver_map(map, isolate());
2503 256 : if (!Map::TryUpdate(isolate(), receiver_map).ToHandle(&receiver_map))
2504 : return NoChange();
2505 :
2506 : Handle<Name> cached_name(
2507 256 : Name::cast(nexus.GetFeedbackExtra()->GetHeapObjectAssumeStrong()),
2508 : isolate());
2509 :
2510 128 : PropertyAccessInfo access_info;
2511 : AccessInfoFactory access_info_factory(broker(), dependencies(),
2512 128 : graph()->zone());
2513 128 : if (!access_info_factory.ComputePropertyAccessInfo(
2514 : receiver_map, cached_name, AccessMode::kStoreInLiteral,
2515 : &access_info)) {
2516 : return NoChange();
2517 : }
2518 :
2519 97 : Node* receiver = NodeProperties::GetValueInput(node, 0);
2520 97 : Node* effect = NodeProperties::GetEffectInput(node);
2521 97 : Node* control = NodeProperties::GetControlInput(node);
2522 :
2523 : // Monomorphic property access.
2524 : PropertyAccessBuilder access_builder(jsgraph(), broker(), dependencies());
2525 97 : receiver = access_builder.BuildCheckHeapObject(receiver, &effect, control);
2526 : access_builder.BuildCheckMaps(receiver, &effect, control,
2527 97 : access_info.receiver_maps());
2528 :
2529 : // Ensure that {name} matches the cached name.
2530 97 : Node* name = NodeProperties::GetValueInput(node, 1);
2531 194 : Node* check = graph()->NewNode(simplified()->ReferenceEqual(), name,
2532 : jsgraph()->HeapConstant(cached_name));
2533 194 : effect = graph()->NewNode(simplified()->CheckIf(DeoptimizeReason::kWrongName),
2534 97 : check, effect, control);
2535 :
2536 97 : Node* value = NodeProperties::GetValueInput(node, 2);
2537 97 : Node* context = NodeProperties::GetContextInput(node);
2538 97 : Node* frame_state_lazy = NodeProperties::GetFrameStateInput(node);
2539 :
2540 : // Generate the actual property access.
2541 : ValueEffectControl continuation = BuildPropertyAccess(
2542 : receiver, value, context, frame_state_lazy, effect, control, cached_name,
2543 97 : nullptr, access_info, AccessMode::kStoreInLiteral);
2544 : value = continuation.value();
2545 97 : effect = continuation.effect();
2546 : control = continuation.control();
2547 :
2548 : ReplaceWithValue(node, value, effect, control);
2549 : return Replace(value);
2550 : }
2551 :
2552 49847 : Reduction JSNativeContextSpecialization::ReduceJSStoreInArrayLiteral(
2553 : Node* node) {
2554 : DCHECK_EQ(IrOpcode::kJSStoreInArrayLiteral, node->opcode());
2555 49847 : FeedbackParameter const& p = FeedbackParameterOf(node->op());
2556 49848 : Node* const receiver = NodeProperties::GetValueInput(node, 0);
2557 49848 : Node* const index = NodeProperties::GetValueInput(node, 1);
2558 49848 : Node* const value = NodeProperties::GetValueInput(node, 2);
2559 49848 : Node* const effect = NodeProperties::GetEffectInput(node);
2560 :
2561 : // Extract receiver maps from the keyed store IC using the FeedbackNexus.
2562 49848 : if (!p.feedback().IsValid()) return NoChange();
2563 : FeedbackNexus nexus(p.feedback().vector(), p.feedback().slot());
2564 :
2565 : // Extract the keyed access store mode from the keyed store IC.
2566 49848 : KeyedAccessStoreMode store_mode = nexus.GetKeyedAccessStoreMode();
2567 :
2568 : // Extract receiver maps from the {nexus}.
2569 : MapHandles receiver_maps;
2570 49847 : if (!ExtractReceiverMaps(receiver, effect, nexus, &receiver_maps)) {
2571 : return NoChange();
2572 49848 : } else if (receiver_maps.empty()) {
2573 : return ReduceSoftDeoptimize(
2574 46924 : node, DeoptimizeReason::kInsufficientTypeFeedbackForGenericKeyedAccess);
2575 : }
2576 : DCHECK(!nexus.IsUninitialized());
2577 : DCHECK_EQ(ELEMENT, nexus.GetKeyType());
2578 :
2579 2924 : if (nexus.ic_state() == MEGAMORPHIC) return NoChange();
2580 :
2581 : // Try to lower the element access based on the {receiver_maps}.
2582 : return ReduceElementAccess(node, index, value, nexus, receiver_maps,
2583 : AccessMode::kStoreInLiteral, STANDARD_LOAD,
2584 2924 : store_mode);
2585 : }
2586 :
2587 1999 : Reduction JSNativeContextSpecialization::ReduceJSToObject(Node* node) {
2588 : DCHECK_EQ(IrOpcode::kJSToObject, node->opcode());
2589 1999 : Node* receiver = NodeProperties::GetValueInput(node, 0);
2590 1999 : Node* effect = NodeProperties::GetEffectInput(node);
2591 :
2592 : ZoneHandleSet<Map> receiver_maps;
2593 : NodeProperties::InferReceiverMapsResult result =
2594 : NodeProperties::InferReceiverMaps(broker(), receiver, effect,
2595 1999 : &receiver_maps);
2596 1999 : if (result == NodeProperties::kNoReceiverMaps) return NoChange();
2597 :
2598 262 : for (size_t i = 0; i < receiver_maps.size(); ++i) {
2599 141 : if (!receiver_maps[i]->IsJSReceiverMap()) return NoChange();
2600 : }
2601 :
2602 : ReplaceWithValue(node, receiver, effect);
2603 : return Replace(receiver);
2604 : }
2605 :
2606 : namespace {
2607 :
2608 6904 : ExternalArrayType GetArrayTypeFromElementsKind(ElementsKind kind) {
2609 6904 : switch (kind) {
2610 : #define TYPED_ARRAY_CASE(Type, type, TYPE, ctype) \
2611 : case TYPE##_ELEMENTS: \
2612 : return kExternal##Type##Array;
2613 492 : TYPED_ARRAYS(TYPED_ARRAY_CASE)
2614 : #undef TYPED_ARRAY_CASE
2615 : default:
2616 : break;
2617 : }
2618 0 : UNREACHABLE();
2619 : }
2620 :
2621 : } // namespace
2622 :
2623 : JSNativeContextSpecialization::ValueEffectControl
2624 22685 : JSNativeContextSpecialization::BuildElementAccess(
2625 : Node* receiver, Node* index, Node* value, Node* effect, Node* control,
2626 : ElementAccessInfo const& access_info, AccessMode access_mode,
2627 : KeyedAccessLoadMode load_mode, KeyedAccessStoreMode store_mode) {
2628 : // TODO(bmeurer): We currently specialize based on elements kind. We should
2629 : // also be able to properly support strings and other JSObjects here.
2630 : ElementsKind elements_kind = access_info.elements_kind();
2631 : MapHandles const& receiver_maps = access_info.receiver_maps();
2632 :
2633 22685 : if (IsFixedTypedArrayElementsKind(elements_kind)) {
2634 : Node* buffer;
2635 : Node* length;
2636 : Node* base_pointer;
2637 : Node* external_pointer;
2638 :
2639 : // Check if we can constant-fold information about the {receiver} (e.g.
2640 : // for asm.js-like code patterns).
2641 : base::Optional<JSTypedArrayRef> typed_array =
2642 6904 : GetTypedArrayConstant(broker(), receiver);
2643 6904 : if (typed_array.has_value()) {
2644 1327 : buffer = jsgraph()->Constant(typed_array->buffer());
2645 : length =
2646 1327 : jsgraph()->Constant(static_cast<double>(typed_array->length_value()));
2647 :
2648 : // Load the (known) base and external pointer for the {receiver}. The
2649 : // {external_pointer} might be invalid if the {buffer} was detached, so
2650 : // we need to make sure that any access is properly guarded.
2651 1327 : base_pointer = jsgraph()->ZeroConstant();
2652 : external_pointer =
2653 1327 : jsgraph()->PointerConstant(typed_array->elements_external_pointer());
2654 : } else {
2655 : // Load the {receiver}s length.
2656 5577 : length = effect = graph()->NewNode(
2657 11154 : simplified()->LoadField(AccessBuilder::ForJSTypedArrayLength()),
2658 : receiver, effect, control);
2659 :
2660 : // Load the buffer for the {receiver}.
2661 5577 : buffer = effect = graph()->NewNode(
2662 11154 : simplified()->LoadField(AccessBuilder::ForJSArrayBufferViewBuffer()),
2663 : receiver, effect, control);
2664 :
2665 : // Load the elements for the {receiver}.
2666 5577 : Node* elements = effect = graph()->NewNode(
2667 11154 : simplified()->LoadField(AccessBuilder::ForJSObjectElements()),
2668 : receiver, effect, control);
2669 :
2670 : // Load the base pointer for the {receiver}. This will always be Smi
2671 : // zero unless we allow on-heap TypedArrays, which is only the case
2672 : // for Chrome. Node and Electron both set this limit to 0. Setting
2673 : // the base to Smi zero here allows the EffectControlLinearizer to
2674 : // optimize away the tricky part of the access later.
2675 : if (V8_TYPED_ARRAY_MAX_SIZE_IN_HEAP == 0) {
2676 : base_pointer = jsgraph()->ZeroConstant();
2677 : } else {
2678 5577 : base_pointer = effect = graph()->NewNode(
2679 : simplified()->LoadField(
2680 11154 : AccessBuilder::ForFixedTypedArrayBaseBasePointer()),
2681 : elements, effect, control);
2682 : }
2683 :
2684 : // Load the external pointer for the {receiver}s {elements}.
2685 5577 : external_pointer = effect = graph()->NewNode(
2686 : simplified()->LoadField(
2687 11154 : AccessBuilder::ForFixedTypedArrayBaseExternalPointer()),
2688 : elements, effect, control);
2689 : }
2690 :
2691 : // See if we can skip the detaching check.
2692 6904 : if (!dependencies()->DependOnArrayBufferDetachingProtector()) {
2693 : // Deopt if the {buffer} was detached.
2694 : // Note: A detached buffer leads to megamorphic feedback.
2695 183 : Node* buffer_bit_field = effect = graph()->NewNode(
2696 366 : simplified()->LoadField(AccessBuilder::ForJSArrayBufferBitField()),
2697 : buffer, effect, control);
2698 366 : Node* check = graph()->NewNode(
2699 : simplified()->NumberEqual(),
2700 : graph()->NewNode(
2701 : simplified()->NumberBitwiseAnd(), buffer_bit_field,
2702 : jsgraph()->Constant(JSArrayBuffer::WasDetachedBit::kMask)),
2703 : jsgraph()->ZeroConstant());
2704 366 : effect = graph()->NewNode(
2705 : simplified()->CheckIf(DeoptimizeReason::kArrayBufferWasDetached),
2706 : check, effect, control);
2707 : }
2708 :
2709 13808 : if (load_mode == LOAD_IGNORE_OUT_OF_BOUNDS ||
2710 6904 : store_mode == STORE_NO_TRANSITION_IGNORE_OUT_OF_BOUNDS) {
2711 : // Only check that the {index} is in SignedSmall range. We do the actual
2712 : // bounds check below and just skip the property access if it's out of
2713 : // bounds for the {receiver}.
2714 984 : index = effect = graph()->NewNode(
2715 : simplified()->CheckSmi(VectorSlotPair()), index, effect, control);
2716 :
2717 : // Cast the {index} to Unsigned32 range, so that the bounds checks
2718 : // below are performed on unsigned values, which means that all the
2719 : // Negative32 values are treated as out-of-bounds.
2720 492 : index = graph()->NewNode(simplified()->NumberToUint32(), index);
2721 6412 : } else if (access_mode != AccessMode::kHas) {
2722 : // Check that the {index} is in the valid range for the {receiver}.
2723 : index = effect =
2724 12824 : graph()->NewNode(simplified()->CheckBounds(VectorSlotPair()), index,
2725 : length, effect, control);
2726 : }
2727 :
2728 : // Access the actual element.
2729 : ExternalArrayType external_array_type =
2730 6904 : GetArrayTypeFromElementsKind(elements_kind);
2731 6904 : switch (access_mode) {
2732 : case AccessMode::kLoad: {
2733 : // Check if we can return undefined for out-of-bounds loads.
2734 3433 : if (load_mode == LOAD_IGNORE_OUT_OF_BOUNDS) {
2735 : Node* check =
2736 314 : graph()->NewNode(simplified()->NumberLessThan(), index, length);
2737 314 : Node* branch = graph()->NewNode(
2738 : common()->Branch(BranchHint::kTrue,
2739 : IsSafetyCheck::kCriticalSafetyCheck),
2740 : check, control);
2741 :
2742 314 : Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
2743 : Node* etrue = effect;
2744 : Node* vtrue;
2745 : {
2746 : // Perform the actual load
2747 314 : vtrue = etrue = graph()->NewNode(
2748 : simplified()->LoadTypedElement(external_array_type), buffer,
2749 : base_pointer, external_pointer, index, etrue, if_true);
2750 : }
2751 :
2752 314 : Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
2753 : Node* efalse = effect;
2754 : Node* vfalse;
2755 : {
2756 : // Materialize undefined for out-of-bounds loads.
2757 314 : vfalse = jsgraph()->UndefinedConstant();
2758 : }
2759 :
2760 314 : control = graph()->NewNode(common()->Merge(2), if_true, if_false);
2761 : effect =
2762 314 : graph()->NewNode(common()->EffectPhi(2), etrue, efalse, control);
2763 : value =
2764 314 : graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2),
2765 : vtrue, vfalse, control);
2766 : } else {
2767 : // Perform the actual load.
2768 3119 : value = effect = graph()->NewNode(
2769 : simplified()->LoadTypedElement(external_array_type), buffer,
2770 : base_pointer, external_pointer, index, effect, control);
2771 : }
2772 : break;
2773 : }
2774 : case AccessMode::kStoreInLiteral:
2775 0 : UNREACHABLE();
2776 : break;
2777 : case AccessMode::kStore: {
2778 : // Ensure that the {value} is actually a Number or an Oddball,
2779 : // and truncate it to a Number appropriately.
2780 6926 : value = effect = graph()->NewNode(
2781 : simplified()->SpeculativeToNumber(
2782 : NumberOperationHint::kNumberOrOddball, VectorSlotPair()),
2783 : value, effect, control);
2784 :
2785 : // Introduce the appropriate truncation for {value}. Currently we
2786 : // only need to do this for ClamedUint8Array {receiver}s, as the
2787 : // other truncations are implicit in the StoreTypedElement, but we
2788 : // might want to change that at some point.
2789 3463 : if (external_array_type == kExternalUint8ClampedArray) {
2790 475 : value = graph()->NewNode(simplified()->NumberToUint8Clamped(), value);
2791 : }
2792 :
2793 : // Check if we can skip the out-of-bounds store.
2794 3463 : if (store_mode == STORE_NO_TRANSITION_IGNORE_OUT_OF_BOUNDS) {
2795 : Node* check =
2796 170 : graph()->NewNode(simplified()->NumberLessThan(), index, length);
2797 170 : Node* branch = graph()->NewNode(common()->Branch(BranchHint::kTrue),
2798 : check, control);
2799 :
2800 170 : Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
2801 : Node* etrue = effect;
2802 : {
2803 : // Perform the actual store.
2804 170 : etrue = graph()->NewNode(
2805 : simplified()->StoreTypedElement(external_array_type), buffer,
2806 : base_pointer, external_pointer, index, value, etrue, if_true);
2807 : }
2808 :
2809 170 : Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
2810 : Node* efalse = effect;
2811 : {
2812 : // Just ignore the out-of-bounds write.
2813 : }
2814 :
2815 170 : control = graph()->NewNode(common()->Merge(2), if_true, if_false);
2816 : effect =
2817 170 : graph()->NewNode(common()->EffectPhi(2), etrue, efalse, control);
2818 : } else {
2819 : // Perform the actual store
2820 3293 : effect = graph()->NewNode(
2821 : simplified()->StoreTypedElement(external_array_type), buffer,
2822 : base_pointer, external_pointer, index, value, effect, control);
2823 : }
2824 : break;
2825 : }
2826 : case AccessMode::kHas:
2827 : // For has property on a typed array, all we need is a bounds check.
2828 : value = effect =
2829 8 : graph()->NewNode(simplified()->SpeculativeNumberLessThan(
2830 : NumberOperationHint::kSignedSmall),
2831 : index, length, effect, control);
2832 8 : break;
2833 : }
2834 : } else {
2835 : // Load the elements for the {receiver}.
2836 15781 : Node* elements = effect = graph()->NewNode(
2837 31562 : simplified()->LoadField(AccessBuilder::ForJSObjectElements()), receiver,
2838 : effect, control);
2839 :
2840 : // Don't try to store to a copy-on-write backing store (unless supported by
2841 : // the store mode).
2842 18123 : if (access_mode == AccessMode::kStore &&
2843 17178 : IsSmiOrObjectElementsKind(elements_kind) &&
2844 : !IsCOWHandlingStoreMode(store_mode)) {
2845 2844 : effect = graph()->NewNode(
2846 : simplified()->CheckMaps(
2847 : CheckMapsFlag::kNone,
2848 : ZoneHandleSet<Map>(factory()->fixed_array_map())),
2849 : elements, effect, control);
2850 : }
2851 :
2852 : // Check if the {receiver} is a JSArray.
2853 15781 : bool receiver_is_jsarray = HasOnlyJSArrayMaps(broker(), receiver_maps);
2854 :
2855 : // Load the length of the {receiver}.
2856 : Node* length = effect =
2857 : receiver_is_jsarray
2858 14025 : ? graph()->NewNode(
2859 : simplified()->LoadField(
2860 43831 : AccessBuilder::ForJSArrayLength(elements_kind)),
2861 : receiver, effect, control)
2862 1756 : : graph()->NewNode(
2863 17537 : simplified()->LoadField(AccessBuilder::ForFixedArrayLength()),
2864 17537 : elements, effect, control);
2865 :
2866 : // Check if we might need to grow the {elements} backing store.
2867 15781 : if (IsGrowStoreMode(store_mode)) {
2868 : // For growing stores we validate the {index} below.
2869 : DCHECK(access_mode == AccessMode::kStore ||
2870 : access_mode == AccessMode::kStoreInLiteral);
2871 15258 : } else if (load_mode == LOAD_IGNORE_OUT_OF_BOUNDS &&
2872 424 : CanTreatHoleAsUndefined(receiver_maps)) {
2873 : // Check that the {index} is a valid array index, we do the actual
2874 : // bounds check below and just skip the store below if it's out of
2875 : // bounds for the {receiver}.
2876 804 : index = effect = graph()->NewNode(
2877 : simplified()->CheckBounds(VectorSlotPair()), index,
2878 : jsgraph()->Constant(Smi::kMaxValue), effect, control);
2879 : } else {
2880 : // Check that the {index} is in the valid range for the {receiver}.
2881 : index = effect =
2882 28864 : graph()->NewNode(simplified()->CheckBounds(VectorSlotPair()), index,
2883 : length, effect, control);
2884 : }
2885 :
2886 : // Compute the element access.
2887 : Type element_type = Type::NonInternal();
2888 : MachineType element_machine_type = MachineType::AnyTagged();
2889 15781 : if (IsDoubleElementsKind(elements_kind)) {
2890 : element_type = Type::Number();
2891 : element_machine_type = MachineType::Float64();
2892 13240 : } else if (IsSmiElementsKind(elements_kind)) {
2893 : element_type = Type::SignedSmall();
2894 : element_machine_type = MachineType::TaggedSigned();
2895 : }
2896 : ElementAccess element_access = {
2897 : kTaggedBase, FixedArray::kHeaderSize,
2898 : element_type, element_machine_type,
2899 : kFullWriteBarrier, LoadSensitivity::kCritical};
2900 :
2901 : // Access the actual element.
2902 15781 : if (access_mode == AccessMode::kLoad) {
2903 : // Compute the real element access type, which includes the hole in case
2904 : // of holey backing stores.
2905 10481 : if (IsHoleyElementsKind(elements_kind)) {
2906 : element_access.type =
2907 2541 : Type::Union(element_type, Type::Hole(), graph()->zone());
2908 : }
2909 10481 : if (elements_kind == HOLEY_ELEMENTS ||
2910 : elements_kind == HOLEY_SMI_ELEMENTS) {
2911 1629 : element_access.machine_type = MachineType::AnyTagged();
2912 : }
2913 :
2914 : // Check if we can return undefined for out-of-bounds loads.
2915 10880 : if (load_mode == LOAD_IGNORE_OUT_OF_BOUNDS &&
2916 399 : CanTreatHoleAsUndefined(receiver_maps)) {
2917 : Node* check =
2918 384 : graph()->NewNode(simplified()->NumberLessThan(), index, length);
2919 384 : Node* branch = graph()->NewNode(
2920 : common()->Branch(BranchHint::kTrue,
2921 : IsSafetyCheck::kCriticalSafetyCheck),
2922 : check, control);
2923 :
2924 384 : Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
2925 : Node* etrue = effect;
2926 : Node* vtrue;
2927 : {
2928 : // Perform the actual load
2929 : vtrue = etrue =
2930 384 : graph()->NewNode(simplified()->LoadElement(element_access),
2931 : elements, index, etrue, if_true);
2932 :
2933 : // Handle loading from holey backing stores correctly, by either
2934 : // mapping the hole to undefined if possible, or deoptimizing
2935 : // otherwise.
2936 384 : if (elements_kind == HOLEY_ELEMENTS ||
2937 : elements_kind == HOLEY_SMI_ELEMENTS) {
2938 : // Turn the hole into undefined.
2939 60 : vtrue = graph()->NewNode(
2940 : simplified()->ConvertTaggedHoleToUndefined(), vtrue);
2941 324 : } else if (elements_kind == HOLEY_DOUBLE_ELEMENTS) {
2942 : // Return the signaling NaN hole directly if all uses are
2943 : // truncating.
2944 86 : vtrue = etrue = graph()->NewNode(
2945 : simplified()->CheckFloat64Hole(
2946 : CheckFloat64HoleMode::kAllowReturnHole, VectorSlotPair()),
2947 : vtrue, etrue, if_true);
2948 : }
2949 : }
2950 :
2951 384 : Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
2952 : Node* efalse = effect;
2953 : Node* vfalse;
2954 : {
2955 : // Materialize undefined for out-of-bounds loads.
2956 384 : vfalse = jsgraph()->UndefinedConstant();
2957 : }
2958 :
2959 384 : control = graph()->NewNode(common()->Merge(2), if_true, if_false);
2960 : effect =
2961 384 : graph()->NewNode(common()->EffectPhi(2), etrue, efalse, control);
2962 : value =
2963 384 : graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2),
2964 : vtrue, vfalse, control);
2965 : } else {
2966 : // Perform the actual load.
2967 : value = effect =
2968 10097 : graph()->NewNode(simplified()->LoadElement(element_access),
2969 : elements, index, effect, control);
2970 :
2971 : // Handle loading from holey backing stores correctly, by either mapping
2972 : // the hole to undefined if possible, or deoptimizing otherwise.
2973 10097 : if (elements_kind == HOLEY_ELEMENTS ||
2974 : elements_kind == HOLEY_SMI_ELEMENTS) {
2975 : // Check if we are allowed to turn the hole into undefined.
2976 1569 : if (CanTreatHoleAsUndefined(receiver_maps)) {
2977 : // Turn the hole into undefined.
2978 1459 : value = graph()->NewNode(
2979 : simplified()->ConvertTaggedHoleToUndefined(), value);
2980 : } else {
2981 : // Bailout if we see the hole.
2982 110 : value = effect = graph()->NewNode(
2983 : simplified()->CheckNotTaggedHole(), value, effect, control);
2984 : }
2985 8528 : } else if (elements_kind == HOLEY_DOUBLE_ELEMENTS) {
2986 : // Perform the hole check on the result.
2987 : CheckFloat64HoleMode mode = CheckFloat64HoleMode::kNeverReturnHole;
2988 : // Check if we are allowed to return the hole directly.
2989 869 : if (CanTreatHoleAsUndefined(receiver_maps)) {
2990 : // Return the signaling NaN hole directly if all uses are
2991 : // truncating.
2992 : mode = CheckFloat64HoleMode::kAllowReturnHole;
2993 : }
2994 1738 : value = effect = graph()->NewNode(
2995 : simplified()->CheckFloat64Hole(mode, VectorSlotPair()), value,
2996 : effect, control);
2997 : }
2998 : }
2999 5300 : } else if (access_mode == AccessMode::kHas) {
3000 : // For packed arrays with NoElementsProctector valid, a bound check
3001 : // is equivalent to HasProperty.
3002 41 : value = effect = graph()->NewNode(simplified()->SpeculativeNumberLessThan(
3003 : NumberOperationHint::kSignedSmall),
3004 : index, length, effect, control);
3005 41 : if (IsHoleyElementsKind(elements_kind)) {
3006 : // If the index is in bounds, do a load and hole check.
3007 :
3008 23 : Node* branch = graph()->NewNode(common()->Branch(), value, control);
3009 :
3010 23 : Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
3011 : Node* efalse = effect;
3012 23 : Node* vfalse = jsgraph()->FalseConstant();
3013 :
3014 : element_access.type =
3015 23 : Type::Union(element_type, Type::Hole(), graph()->zone());
3016 :
3017 23 : if (elements_kind == HOLEY_ELEMENTS ||
3018 : elements_kind == HOLEY_SMI_ELEMENTS) {
3019 23 : element_access.machine_type = MachineType::AnyTagged();
3020 : }
3021 :
3022 23 : Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
3023 : Node* etrue = effect;
3024 :
3025 : Node* checked = etrue =
3026 46 : graph()->NewNode(simplified()->CheckBounds(VectorSlotPair()), index,
3027 : length, etrue, if_true);
3028 :
3029 : Node* element = etrue =
3030 23 : graph()->NewNode(simplified()->LoadElement(element_access),
3031 : elements, checked, etrue, if_true);
3032 :
3033 : Node* vtrue;
3034 23 : if (CanTreatHoleAsUndefined(receiver_maps)) {
3035 7 : if (elements_kind == HOLEY_ELEMENTS ||
3036 : elements_kind == HOLEY_SMI_ELEMENTS) {
3037 : // Check if we are allowed to turn the hole into undefined.
3038 : // Turn the hole into undefined.
3039 7 : vtrue = graph()->NewNode(simplified()->ReferenceEqual(), element,
3040 : jsgraph()->TheHoleConstant());
3041 : } else {
3042 : vtrue =
3043 0 : graph()->NewNode(simplified()->NumberIsFloat64Hole(), element);
3044 : }
3045 :
3046 : // has == !IsHole
3047 7 : vtrue = graph()->NewNode(simplified()->BooleanNot(), vtrue);
3048 : } else {
3049 16 : if (elements_kind == HOLEY_ELEMENTS ||
3050 : elements_kind == HOLEY_SMI_ELEMENTS) {
3051 : // Bailout if we see the hole.
3052 16 : etrue = graph()->NewNode(simplified()->CheckNotTaggedHole(),
3053 : element, etrue, if_true);
3054 : } else {
3055 0 : etrue = graph()->NewNode(
3056 : simplified()->CheckFloat64Hole(
3057 : CheckFloat64HoleMode::kNeverReturnHole, VectorSlotPair()),
3058 : element, etrue, if_true);
3059 : }
3060 :
3061 16 : vtrue = jsgraph()->TrueConstant();
3062 : }
3063 :
3064 23 : control = graph()->NewNode(common()->Merge(2), if_true, if_false);
3065 : effect =
3066 23 : graph()->NewNode(common()->EffectPhi(2), etrue, efalse, control);
3067 : value =
3068 23 : graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2),
3069 : vtrue, vfalse, control);
3070 : }
3071 : } else {
3072 : DCHECK(access_mode == AccessMode::kStore ||
3073 : access_mode == AccessMode::kStoreInLiteral);
3074 5259 : if (IsSmiElementsKind(elements_kind)) {
3075 2978 : value = effect = graph()->NewNode(
3076 : simplified()->CheckSmi(VectorSlotPair()), value, effect, control);
3077 3770 : } else if (IsDoubleElementsKind(elements_kind)) {
3078 : value = effect =
3079 2240 : graph()->NewNode(simplified()->CheckNumber(VectorSlotPair()), value,
3080 : effect, control);
3081 : // Make sure we do not store signalling NaNs into double arrays.
3082 1120 : value = graph()->NewNode(simplified()->NumberSilenceNaN(), value);
3083 : }
3084 :
3085 : // Ensure that copy-on-write backing store is writable.
3086 5259 : if (IsSmiOrObjectElementsKind(elements_kind) &&
3087 : store_mode == STORE_NO_TRANSITION_HANDLE_COW) {
3088 : elements = effect =
3089 168 : graph()->NewNode(simplified()->EnsureWritableFastElements(),
3090 : receiver, elements, effect, control);
3091 5091 : } else if (IsGrowStoreMode(store_mode)) {
3092 : // Determine the length of the {elements} backing store.
3093 947 : Node* elements_length = effect = graph()->NewNode(
3094 1894 : simplified()->LoadField(AccessBuilder::ForFixedArrayLength()),
3095 : elements, effect, control);
3096 :
3097 : // Validate the {index} depending on holeyness:
3098 : //
3099 : // For HOLEY_*_ELEMENTS the {index} must not exceed the {elements}
3100 : // backing store capacity plus the maximum allowed gap, as otherwise
3101 : // the (potential) backing store growth would normalize and thus
3102 : // the elements kind of the {receiver} would change to slow mode.
3103 : //
3104 : // For PACKED_*_ELEMENTS the {index} must be within the range
3105 : // [0,length+1[ to be valid. In case {index} equals {length},
3106 : // the {receiver} will be extended, but kept packed.
3107 : Node* limit =
3108 : IsHoleyElementsKind(elements_kind)
3109 200 : ? graph()->NewNode(simplified()->NumberAdd(), elements_length,
3110 : jsgraph()->Constant(JSObject::kMaxGap))
3111 747 : : graph()->NewNode(simplified()->NumberAdd(), length,
3112 947 : jsgraph()->OneConstant());
3113 : index = effect =
3114 1894 : graph()->NewNode(simplified()->CheckBounds(VectorSlotPair()), index,
3115 : limit, effect, control);
3116 :
3117 : // Grow {elements} backing store if necessary.
3118 : GrowFastElementsMode mode =
3119 : IsDoubleElementsKind(elements_kind)
3120 : ? GrowFastElementsMode::kDoubleElements
3121 947 : : GrowFastElementsMode::kSmiOrObjectElements;
3122 1894 : elements = effect = graph()->NewNode(
3123 : simplified()->MaybeGrowFastElements(mode, VectorSlotPair()),
3124 : receiver, elements, index, elements_length, effect, control);
3125 :
3126 : // If we didn't grow {elements}, it might still be COW, in which case we
3127 : // copy it now.
3128 947 : if (IsSmiOrObjectElementsKind(elements_kind) &&
3129 : store_mode == STORE_AND_GROW_NO_TRANSITION_HANDLE_COW) {
3130 : elements = effect =
3131 760 : graph()->NewNode(simplified()->EnsureWritableFastElements(),
3132 : receiver, elements, effect, control);
3133 : }
3134 :
3135 : // Also update the "length" property if {receiver} is a JSArray.
3136 947 : if (receiver_is_jsarray) {
3137 : Node* check =
3138 929 : graph()->NewNode(simplified()->NumberLessThan(), index, length);
3139 929 : Node* branch = graph()->NewNode(common()->Branch(), check, control);
3140 :
3141 929 : Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
3142 : Node* etrue = effect;
3143 : {
3144 : // We don't need to do anything, the {index} is within
3145 : // the valid bounds for the JSArray {receiver}.
3146 : }
3147 :
3148 929 : Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
3149 : Node* efalse = effect;
3150 : {
3151 : // Update the JSArray::length field. Since this is observable,
3152 : // there must be no other check after this.
3153 929 : Node* new_length = graph()->NewNode(
3154 : simplified()->NumberAdd(), index, jsgraph()->OneConstant());
3155 929 : efalse = graph()->NewNode(
3156 : simplified()->StoreField(
3157 1858 : AccessBuilder::ForJSArrayLength(elements_kind)),
3158 : receiver, new_length, efalse, if_false);
3159 : }
3160 :
3161 929 : control = graph()->NewNode(common()->Merge(2), if_true, if_false);
3162 : effect =
3163 929 : graph()->NewNode(common()->EffectPhi(2), etrue, efalse, control);
3164 : }
3165 : }
3166 :
3167 : // Perform the actual element access.
3168 5259 : effect = graph()->NewNode(simplified()->StoreElement(element_access),
3169 : elements, index, value, effect, control);
3170 : }
3171 : }
3172 :
3173 22685 : return ValueEffectControl(value, effect, control);
3174 : }
3175 :
3176 579 : Node* JSNativeContextSpecialization::BuildIndexedStringLoad(
3177 : Node* receiver, Node* index, Node* length, Node** effect, Node** control,
3178 : KeyedAccessLoadMode load_mode) {
3179 627 : if (load_mode == LOAD_IGNORE_OUT_OF_BOUNDS &&
3180 48 : dependencies()->DependOnNoElementsProtector()) {
3181 : // Ensure that the {index} is a valid String length.
3182 96 : index = *effect = graph()->NewNode(
3183 : simplified()->CheckBounds(VectorSlotPair()), index,
3184 48 : jsgraph()->Constant(String::kMaxLength), *effect, *control);
3185 :
3186 : // Load the single character string from {receiver} or yield
3187 : // undefined if the {index} is not within the valid bounds.
3188 : Node* check =
3189 48 : graph()->NewNode(simplified()->NumberLessThan(), index, length);
3190 : Node* branch =
3191 48 : graph()->NewNode(common()->Branch(BranchHint::kTrue,
3192 : IsSafetyCheck::kCriticalSafetyCheck),
3193 : check, *control);
3194 :
3195 48 : Node* masked_index = graph()->NewNode(simplified()->PoisonIndex(), index);
3196 :
3197 48 : Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
3198 : Node* etrue;
3199 : Node* vtrue = etrue =
3200 48 : graph()->NewNode(simplified()->StringCharCodeAt(), receiver,
3201 : masked_index, *effect, if_true);
3202 48 : vtrue = graph()->NewNode(simplified()->StringFromSingleCharCode(), vtrue);
3203 :
3204 48 : Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
3205 48 : Node* vfalse = jsgraph()->UndefinedConstant();
3206 :
3207 96 : *control = graph()->NewNode(common()->Merge(2), if_true, if_false);
3208 : *effect =
3209 96 : graph()->NewNode(common()->EffectPhi(2), etrue, *effect, *control);
3210 48 : return graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2),
3211 48 : vtrue, vfalse, *control);
3212 : } else {
3213 : // Ensure that {index} is less than {receiver} length.
3214 : index = *effect =
3215 1062 : graph()->NewNode(simplified()->CheckBounds(VectorSlotPair()), index,
3216 531 : length, *effect, *control);
3217 :
3218 531 : Node* masked_index = graph()->NewNode(simplified()->PoisonIndex(), index);
3219 :
3220 : // Return the character from the {receiver} as single character string.
3221 : Node* value = *effect =
3222 531 : graph()->NewNode(simplified()->StringCharCodeAt(), receiver,
3223 531 : masked_index, *effect, *control);
3224 531 : value = graph()->NewNode(simplified()->StringFromSingleCharCode(), value);
3225 531 : return value;
3226 : }
3227 : }
3228 :
3229 2298 : Node* JSNativeContextSpecialization::BuildExtendPropertiesBackingStore(
3230 : const MapRef& map, Node* properties, Node* effect, Node* control) {
3231 : // TODO(bmeurer/jkummerow): Property deletions can undo map transitions
3232 : // while keeping the backing store around, meaning that even though the
3233 : // map might believe that objects have no unused property fields, there
3234 : // might actually be some. It would be nice to not create a new backing
3235 : // store in that case (i.e. when properties->length() >= new_length).
3236 : // However, introducing branches and Phi nodes here would make it more
3237 : // difficult for escape analysis to get rid of the backing stores used
3238 : // for intermediate states of chains of property additions. That makes
3239 : // it unclear what the best approach is here.
3240 : DCHECK_EQ(0, map.UnusedPropertyFields());
3241 : // Compute the length of the old {properties} and the new properties.
3242 2298 : int length = map.NextFreePropertyIndex() - map.GetInObjectProperties();
3243 2298 : int new_length = length + JSObject::kFieldsAdded;
3244 : // Collect the field values from the {properties}.
3245 : ZoneVector<Node*> values(zone());
3246 2298 : values.reserve(new_length);
3247 1569144 : for (int i = 0; i < length; ++i) {
3248 783423 : Node* value = effect = graph()->NewNode(
3249 1566846 : simplified()->LoadField(AccessBuilder::ForFixedArraySlot(i)),
3250 783423 : properties, effect, control);
3251 783423 : values.push_back(value);
3252 : }
3253 : // Initialize the new fields to undefined.
3254 16086 : for (int i = 0; i < JSObject::kFieldsAdded; ++i) {
3255 13788 : values.push_back(jsgraph()->UndefinedConstant());
3256 : }
3257 :
3258 : // Compute new length and hash.
3259 : Node* hash;
3260 2298 : if (length == 0) {
3261 474 : hash = graph()->NewNode(
3262 : common()->Select(MachineRepresentation::kTaggedSigned),
3263 : graph()->NewNode(simplified()->ObjectIsSmi(), properties), properties,
3264 : jsgraph()->SmiConstant(PropertyArray::kNoHashSentinel));
3265 237 : hash = effect = graph()->NewNode(common()->TypeGuard(Type::SignedSmall()),
3266 : hash, effect, control);
3267 : hash =
3268 237 : graph()->NewNode(simplified()->NumberShiftLeft(), hash,
3269 : jsgraph()->Constant(PropertyArray::HashField::kShift));
3270 : } else {
3271 2061 : hash = effect = graph()->NewNode(
3272 4122 : simplified()->LoadField(AccessBuilder::ForPropertyArrayLengthAndHash()),
3273 : properties, effect, control);
3274 : hash =
3275 2061 : graph()->NewNode(simplified()->NumberBitwiseAnd(), hash,
3276 : jsgraph()->Constant(PropertyArray::HashField::kMask));
3277 : }
3278 2298 : Node* new_length_and_hash = graph()->NewNode(
3279 : simplified()->NumberBitwiseOr(), jsgraph()->Constant(new_length), hash);
3280 : // TDOO(jarin): Fix the typer to infer tighter bound for NumberBitwiseOr.
3281 : new_length_and_hash = effect =
3282 2298 : graph()->NewNode(common()->TypeGuard(Type::SignedSmall()),
3283 : new_length_and_hash, effect, control);
3284 :
3285 : // Allocate and initialize the new properties.
3286 : AllocationBuilder a(jsgraph(), effect, control);
3287 : a.Allocate(PropertyArray::SizeFor(new_length), AllocationType::kYoung,
3288 2298 : Type::OtherInternal());
3289 2298 : a.Store(AccessBuilder::ForMap(), jsgraph()->PropertyArrayMapConstant());
3290 2298 : a.Store(AccessBuilder::ForPropertyArrayLengthAndHash(), new_length_and_hash);
3291 1582932 : for (int i = 0; i < new_length; ++i) {
3292 1580634 : a.Store(AccessBuilder::ForFixedArraySlot(i), values[i]);
3293 : }
3294 4596 : return a.Finish();
3295 : }
3296 :
3297 155 : Node* JSNativeContextSpecialization::BuildCheckEqualsName(Handle<Name> name,
3298 : Node* value,
3299 : Node* effect,
3300 : Node* control) {
3301 : DCHECK(name->IsUniqueName());
3302 : Operator const* const op =
3303 : name->IsSymbol() ? simplified()->CheckEqualsSymbol()
3304 155 : : simplified()->CheckEqualsInternalizedString();
3305 310 : return graph()->NewNode(op, jsgraph()->HeapConstant(name), value, effect,
3306 155 : control);
3307 : }
3308 :
3309 3284 : bool JSNativeContextSpecialization::CanTreatHoleAsUndefined(
3310 : MapHandles const& receiver_maps) {
3311 : // Check if all {receiver_maps} have one of the initial Array.prototype
3312 : // or Object.prototype objects as their prototype (in any of the current
3313 : // native contexts, as the global Array protector works isolate-wide).
3314 7022 : for (Handle<Map> map : receiver_maps) {
3315 : MapRef receiver_map(broker(), map);
3316 3979 : if (!FLAG_concurrent_inlining) receiver_map.SerializePrototype();
3317 3979 : ObjectRef receiver_prototype = receiver_map.prototype();
3318 11937 : if (!receiver_prototype.IsJSObject() ||
3319 11937 : !broker()->IsArrayOrObjectPrototype(receiver_prototype.AsJSObject())) {
3320 241 : return false;
3321 : }
3322 : }
3323 :
3324 : // Check if the array prototype chain is intact.
3325 3043 : return dependencies()->DependOnNoElementsProtector();
3326 : }
3327 :
3328 : namespace {
3329 163575 : void TryUpdateThenDropDeprecated(Isolate* isolate, MapHandles* maps) {
3330 346953 : for (auto it = maps->begin(); it != maps->end();) {
3331 366756 : if (Map::TryUpdate(isolate, *it).ToHandle(&*it)) {
3332 : DCHECK(!(*it)->is_deprecated());
3333 : ++it;
3334 : } else {
3335 : it = maps->erase(it);
3336 : }
3337 : }
3338 163575 : }
3339 : } // namespace
3340 :
3341 592240 : bool JSNativeContextSpecialization::ExtractReceiverMaps(
3342 : Node* receiver, Node* effect, FeedbackNexus const& nexus,
3343 : MapHandles* receiver_maps) {
3344 : DCHECK(receiver_maps->empty());
3345 592241 : if (nexus.IsUninitialized()) return true;
3346 :
3347 : // See if we can infer a concrete type for the {receiver}. Solely relying on
3348 : // the inference is not safe for keyed stores, because we would potentially
3349 : // miss out on transitions that need to be performed.
3350 : {
3351 : FeedbackSlotKind kind = nexus.kind();
3352 : bool use_inference =
3353 176188 : !IsKeyedStoreICKind(kind) && !IsStoreInArrayLiteralICKind(kind);
3354 176188 : if (use_inference && InferReceiverMaps(receiver, effect, receiver_maps)) {
3355 78840 : TryUpdateThenDropDeprecated(isolate(), receiver_maps);
3356 78840 : return true;
3357 : }
3358 : }
3359 :
3360 : // Try to extract some maps from the {nexus}.
3361 97348 : if (nexus.ExtractMaps(receiver_maps) != 0) {
3362 : // Try to filter impossible candidates based on inferred root map.
3363 : Handle<Map> root_map;
3364 169470 : if (InferReceiverRootMap(receiver).ToHandle(&root_map)) {
3365 : DCHECK(!root_map->is_abandoned_prototype_map());
3366 : Isolate* isolate = this->isolate();
3367 : receiver_maps->erase(
3368 : std::remove_if(receiver_maps->begin(), receiver_maps->end(),
3369 12018 : [root_map, isolate](Handle<Map> map) {
3370 12018 : return map->is_abandoned_prototype_map() ||
3371 6002 : map->FindRootMap(isolate) != *root_map;
3372 6016 : }),
3373 : receiver_maps->end());
3374 : }
3375 84735 : TryUpdateThenDropDeprecated(isolate(), receiver_maps);
3376 : return true;
3377 : }
3378 :
3379 : return false;
3380 : }
3381 :
3382 166400 : bool JSNativeContextSpecialization::InferReceiverMaps(
3383 : Node* receiver, Node* effect, MapHandles* receiver_maps) {
3384 : ZoneHandleSet<Map> maps;
3385 : NodeProperties::InferReceiverMapsResult result =
3386 166400 : NodeProperties::InferReceiverMaps(broker(), receiver, effect, &maps);
3387 166400 : if (result == NodeProperties::kReliableReceiverMaps) {
3388 61812 : for (size_t i = 0; i < maps.size(); ++i) {
3389 42238 : receiver_maps->push_back(maps[i]);
3390 : }
3391 : return true;
3392 146826 : } else if (result == NodeProperties::kUnreliableReceiverMaps) {
3393 : // For untrusted receiver maps, we can still use the information
3394 : // if the maps are stable.
3395 185312 : for (size_t i = 0; i < maps.size(); ++i) {
3396 : MapRef map(broker(), maps[i]);
3397 65992 : if (!map.is_stable()) return false;
3398 : }
3399 178540 : for (size_t i = 0; i < maps.size(); ++i) {
3400 119274 : receiver_maps->push_back(maps[i]);
3401 : }
3402 : return true;
3403 : }
3404 : return false;
3405 : }
3406 :
3407 84735 : MaybeHandle<Map> JSNativeContextSpecialization::InferReceiverRootMap(
3408 : Node* receiver) {
3409 : HeapObjectMatcher m(receiver);
3410 84735 : if (m.HasValue()) {
3411 11404 : return handle(m.Value()->map()->FindRootMap(isolate()), isolate());
3412 79033 : } else if (m.IsJSCreate()) {
3413 : base::Optional<MapRef> initial_map =
3414 8287 : NodeProperties::GetJSCreateMap(broker(), receiver);
3415 8287 : if (initial_map.has_value()) {
3416 : DCHECK_EQ(*initial_map->object(),
3417 : initial_map->object()->FindRootMap(isolate()));
3418 207 : return initial_map->object();
3419 : }
3420 : }
3421 78826 : return MaybeHandle<Map>();
3422 : }
3423 :
3424 0 : Graph* JSNativeContextSpecialization::graph() const {
3425 0 : return jsgraph()->graph();
3426 : }
3427 :
3428 0 : Isolate* JSNativeContextSpecialization::isolate() const {
3429 0 : return jsgraph()->isolate();
3430 : }
3431 :
3432 0 : Factory* JSNativeContextSpecialization::factory() const {
3433 0 : return isolate()->factory();
3434 : }
3435 :
3436 0 : CommonOperatorBuilder* JSNativeContextSpecialization::common() const {
3437 0 : return jsgraph()->common();
3438 : }
3439 :
3440 0 : JSOperatorBuilder* JSNativeContextSpecialization::javascript() const {
3441 0 : return jsgraph()->javascript();
3442 : }
3443 :
3444 0 : SimplifiedOperatorBuilder* JSNativeContextSpecialization::simplified() const {
3445 0 : return jsgraph()->simplified();
3446 : }
3447 :
3448 : #undef V8_TYPED_ARRAY_MAX_SIZE_IN_HEAP
3449 :
3450 : } // namespace compiler
3451 : } // namespace internal
3452 120216 : } // namespace v8
|