Line data Source code
1 : // Copyright 2014 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/feedback-vector.h"
6 : #include "src/feedback-vector-inl.h"
7 : #include "src/ic/handler-configuration-inl.h"
8 : #include "src/ic/ic-inl.h"
9 : #include "src/objects.h"
10 : #include "src/objects/data-handler-inl.h"
11 : #include "src/objects/hash-table-inl.h"
12 : #include "src/objects/map-inl.h"
13 : #include "src/objects/object-macros.h"
14 :
15 : namespace v8 {
16 : namespace internal {
17 :
18 17256639 : FeedbackSlot FeedbackVectorSpec::AddSlot(FeedbackSlotKind kind) {
19 : int slot = slots();
20 17256639 : int entries_per_slot = FeedbackMetadata::GetSlotSize(kind);
21 : append(kind);
22 29481244 : for (int i = 1; i < entries_per_slot; i++) {
23 : append(FeedbackSlotKind::kInvalid);
24 : }
25 17256484 : return FeedbackSlot(slot);
26 : }
27 :
28 68 : FeedbackSlot FeedbackVectorSpec::AddTypeProfileSlot() {
29 68 : FeedbackSlot slot = AddSlot(FeedbackSlotKind::kTypeProfile);
30 68 : CHECK_EQ(FeedbackVectorSpec::kTypeProfileSlotIndex,
31 : FeedbackVector::GetIndex(slot));
32 68 : return slot;
33 : }
34 :
35 0 : bool FeedbackVectorSpec::HasTypeProfileSlot() const {
36 : FeedbackSlot slot =
37 : FeedbackVector::ToSlot(FeedbackVectorSpec::kTypeProfileSlotIndex);
38 0 : if (slots() <= slot.ToInt()) {
39 : return false;
40 : }
41 0 : return GetKind(slot) == FeedbackSlotKind::kTypeProfile;
42 : }
43 :
44 1984913 : static bool IsPropertyNameFeedback(MaybeObject feedback) {
45 1984913 : HeapObject heap_object;
46 1984913 : if (!feedback->GetHeapObjectIfStrong(&heap_object)) return false;
47 1014231 : if (heap_object->IsString()) {
48 : DCHECK(heap_object->IsInternalizedString());
49 : return true;
50 : }
51 987804 : if (!heap_object->IsSymbol()) return false;
52 558009 : Symbol symbol = Symbol::cast(heap_object);
53 558009 : ReadOnlyRoots roots = symbol->GetReadOnlyRoots();
54 36668 : return symbol != roots.uninitialized_symbol() &&
55 586330 : symbol != roots.premonomorphic_symbol() &&
56 : symbol != roots.megamorphic_symbol();
57 : }
58 :
59 0 : std::ostream& operator<<(std::ostream& os, FeedbackSlotKind kind) {
60 0 : return os << FeedbackMetadata::Kind2String(kind);
61 : }
62 :
63 451 : FeedbackSlotKind FeedbackMetadata::GetKind(FeedbackSlot slot) const {
64 : int index = VectorICComputer::index(0, slot.ToInt());
65 : int data = get(index);
66 47845319 : return VectorICComputer::decode(data, slot.ToInt());
67 : }
68 :
69 0 : void FeedbackMetadata::SetKind(FeedbackSlot slot, FeedbackSlotKind kind) {
70 : int index = VectorICComputer::index(0, slot.ToInt());
71 : int data = get(index);
72 56146086 : int new_data = VectorICComputer::encode(data, slot.ToInt(), kind);
73 : set(index, new_data);
74 0 : }
75 :
76 : // static
77 2081398 : Handle<FeedbackMetadata> FeedbackMetadata::New(Isolate* isolate,
78 : const FeedbackVectorSpec* spec) {
79 : Factory* factory = isolate->factory();
80 :
81 2081398 : const int slot_count = spec == nullptr ? 0 : spec->slots();
82 2081398 : if (slot_count == 0) {
83 : return factory->empty_feedback_metadata();
84 : }
85 : #ifdef DEBUG
86 : for (int i = 0; i < slot_count;) {
87 : DCHECK(spec);
88 : FeedbackSlotKind kind = spec->GetKind(FeedbackSlot(i));
89 : int entry_size = FeedbackMetadata::GetSlotSize(kind);
90 : for (int j = 1; j < entry_size; j++) {
91 : FeedbackSlotKind kind = spec->GetKind(FeedbackSlot(i + j));
92 : DCHECK_EQ(FeedbackSlotKind::kInvalid, kind);
93 : }
94 : i += entry_size;
95 : }
96 : #endif
97 :
98 1588374 : Handle<FeedbackMetadata> metadata = factory->NewFeedbackMetadata(slot_count);
99 :
100 : // Initialize the slots. The raw data section has already been pre-zeroed in
101 : // NewFeedbackMetadata.
102 29661420 : for (int i = 0; i < slot_count; i++) {
103 : DCHECK(spec);
104 : FeedbackSlot slot(i);
105 : FeedbackSlotKind kind = spec->GetKind(slot);
106 : metadata->SetKind(slot, kind);
107 : }
108 :
109 1588380 : return metadata;
110 : }
111 :
112 0 : bool FeedbackMetadata::SpecDiffersFrom(
113 : const FeedbackVectorSpec* other_spec) const {
114 0 : if (other_spec->slots() != slot_count()) {
115 : return true;
116 : }
117 :
118 : int slots = slot_count();
119 0 : for (int i = 0; i < slots;) {
120 : FeedbackSlot slot(i);
121 : FeedbackSlotKind kind = GetKind(slot);
122 0 : int entry_size = FeedbackMetadata::GetSlotSize(kind);
123 :
124 0 : if (kind != other_spec->GetKind(slot)) {
125 : return true;
126 : }
127 0 : i += entry_size;
128 : }
129 : return false;
130 : }
131 :
132 0 : const char* FeedbackMetadata::Kind2String(FeedbackSlotKind kind) {
133 0 : switch (kind) {
134 : case FeedbackSlotKind::kInvalid:
135 : return "Invalid";
136 : case FeedbackSlotKind::kCall:
137 0 : return "Call";
138 : case FeedbackSlotKind::kLoadProperty:
139 0 : return "LoadProperty";
140 : case FeedbackSlotKind::kLoadGlobalInsideTypeof:
141 0 : return "LoadGlobalInsideTypeof";
142 : case FeedbackSlotKind::kLoadGlobalNotInsideTypeof:
143 0 : return "LoadGlobalNotInsideTypeof";
144 : case FeedbackSlotKind::kLoadKeyed:
145 0 : return "LoadKeyed";
146 : case FeedbackSlotKind::kStoreNamedSloppy:
147 0 : return "StoreNamedSloppy";
148 : case FeedbackSlotKind::kStoreNamedStrict:
149 0 : return "StoreNamedStrict";
150 : case FeedbackSlotKind::kStoreOwnNamed:
151 0 : return "StoreOwnNamed";
152 : case FeedbackSlotKind::kStoreGlobalSloppy:
153 0 : return "StoreGlobalSloppy";
154 : case FeedbackSlotKind::kStoreGlobalStrict:
155 0 : return "StoreGlobalStrict";
156 : case FeedbackSlotKind::kStoreKeyedSloppy:
157 0 : return "StoreKeyedSloppy";
158 : case FeedbackSlotKind::kStoreKeyedStrict:
159 0 : return "StoreKeyedStrict";
160 : case FeedbackSlotKind::kStoreInArrayLiteral:
161 0 : return "StoreInArrayLiteral";
162 : case FeedbackSlotKind::kBinaryOp:
163 0 : return "BinaryOp";
164 : case FeedbackSlotKind::kCompareOp:
165 0 : return "CompareOp";
166 : case FeedbackSlotKind::kStoreDataPropertyInLiteral:
167 0 : return "StoreDataPropertyInLiteral";
168 : case FeedbackSlotKind::kCreateClosure:
169 0 : return "kCreateClosure";
170 : case FeedbackSlotKind::kLiteral:
171 0 : return "Literal";
172 : case FeedbackSlotKind::kTypeProfile:
173 0 : return "TypeProfile";
174 : case FeedbackSlotKind::kForIn:
175 0 : return "ForIn";
176 : case FeedbackSlotKind::kInstanceOf:
177 0 : return "InstanceOf";
178 : case FeedbackSlotKind::kCloneObject:
179 0 : return "CloneObject";
180 : case FeedbackSlotKind::kKindsNumber:
181 : break;
182 : }
183 0 : UNREACHABLE();
184 : }
185 :
186 452 : bool FeedbackMetadata::HasTypeProfileSlot() const {
187 : FeedbackSlot slot =
188 : FeedbackVector::ToSlot(FeedbackVectorSpec::kTypeProfileSlotIndex);
189 872 : return slot.ToInt() < slot_count() &&
190 452 : GetKind(slot) == FeedbackSlotKind::kTypeProfile;
191 : }
192 :
193 23299545 : FeedbackSlotKind FeedbackVector::GetKind(FeedbackSlot slot) const {
194 : DCHECK(!is_empty());
195 23299552 : return metadata()->GetKind(slot);
196 : }
197 :
198 440 : FeedbackSlot FeedbackVector::GetTypeProfileSlot() const {
199 : DCHECK(metadata()->HasTypeProfileSlot());
200 : FeedbackSlot slot =
201 : FeedbackVector::ToSlot(FeedbackVectorSpec::kTypeProfileSlotIndex);
202 : DCHECK_EQ(FeedbackSlotKind::kTypeProfile, GetKind(slot));
203 440 : return slot;
204 : }
205 :
206 : // static
207 3062179 : Handle<FeedbackVector> FeedbackVector::New(Isolate* isolate,
208 : Handle<SharedFunctionInfo> shared) {
209 : Factory* factory = isolate->factory();
210 :
211 6124362 : const int slot_count = shared->feedback_metadata()->slot_count();
212 :
213 3062181 : Handle<FeedbackVector> vector = factory->NewFeedbackVector(shared, TENURED);
214 :
215 : DCHECK_EQ(vector->length(), slot_count);
216 :
217 : DCHECK_EQ(vector->shared_function_info(), *shared);
218 : DCHECK_EQ(
219 : vector->optimized_code_weak_or_smi(),
220 : MaybeObject::FromSmi(Smi::FromEnum(
221 : FLAG_log_function_events ? OptimizationMarker::kLogFirstExecution
222 : : OptimizationMarker::kNone)));
223 : DCHECK_EQ(vector->invocation_count(), 0);
224 : DCHECK_EQ(vector->profiler_ticks(), 0);
225 : DCHECK_EQ(vector->deopt_count(), 0);
226 :
227 : // Ensure we can skip the write barrier
228 : Handle<Object> uninitialized_sentinel = UninitializedSentinel(isolate);
229 : DCHECK_EQ(ReadOnlyRoots(isolate).uninitialized_symbol(),
230 : *uninitialized_sentinel);
231 : Handle<Oddball> undefined_value = factory->undefined_value();
232 30588160 : for (int i = 0; i < slot_count;) {
233 : FeedbackSlot slot(i);
234 48927590 : FeedbackSlotKind kind = shared->feedback_metadata()->GetKind(slot);
235 : int index = FeedbackVector::GetIndex(slot);
236 24463799 : int entry_size = FeedbackMetadata::GetSlotSize(kind);
237 :
238 : Object extra_value = *uninitialized_sentinel;
239 24463800 : switch (kind) {
240 : case FeedbackSlotKind::kLoadGlobalInsideTypeof:
241 : case FeedbackSlotKind::kLoadGlobalNotInsideTypeof:
242 : case FeedbackSlotKind::kStoreGlobalSloppy:
243 : case FeedbackSlotKind::kStoreGlobalStrict:
244 : vector->set(index, HeapObjectReference::ClearedValue(isolate),
245 12368202 : SKIP_WRITE_BARRIER);
246 6184101 : break;
247 : case FeedbackSlotKind::kForIn:
248 : case FeedbackSlotKind::kCompareOp:
249 : case FeedbackSlotKind::kBinaryOp:
250 5392688 : vector->set(index, Smi::kZero, SKIP_WRITE_BARRIER);
251 2696344 : break;
252 : case FeedbackSlotKind::kCreateClosure: {
253 4026398 : Handle<FeedbackCell> cell = factory->NewNoClosuresCell(undefined_value);
254 8052790 : vector->set(index, *cell);
255 : break;
256 : }
257 : case FeedbackSlotKind::kLiteral:
258 776130 : vector->set(index, Smi::kZero, SKIP_WRITE_BARRIER);
259 388065 : break;
260 : case FeedbackSlotKind::kCall:
261 11491165 : vector->set(index, *uninitialized_sentinel, SKIP_WRITE_BARRIER);
262 : extra_value = Smi::kZero;
263 5745582 : break;
264 : case FeedbackSlotKind::kCloneObject:
265 : case FeedbackSlotKind::kLoadProperty:
266 : case FeedbackSlotKind::kLoadKeyed:
267 : case FeedbackSlotKind::kStoreNamedSloppy:
268 : case FeedbackSlotKind::kStoreNamedStrict:
269 : case FeedbackSlotKind::kStoreOwnNamed:
270 : case FeedbackSlotKind::kStoreKeyedSloppy:
271 : case FeedbackSlotKind::kStoreKeyedStrict:
272 : case FeedbackSlotKind::kStoreInArrayLiteral:
273 : case FeedbackSlotKind::kStoreDataPropertyInLiteral:
274 : case FeedbackSlotKind::kTypeProfile:
275 : case FeedbackSlotKind::kInstanceOf:
276 10846668 : vector->set(index, *uninitialized_sentinel, SKIP_WRITE_BARRIER);
277 5423334 : break;
278 :
279 : case FeedbackSlotKind::kInvalid:
280 : case FeedbackSlotKind::kKindsNumber:
281 0 : UNREACHABLE();
282 : break;
283 : }
284 41792512 : for (int j = 1; j < entry_size; j++) {
285 51986119 : vector->set(index + j, extra_value, SKIP_WRITE_BARRIER);
286 : }
287 24463804 : i += entry_size;
288 : }
289 :
290 3062184 : Handle<FeedbackVector> result = Handle<FeedbackVector>::cast(vector);
291 6123244 : if (!isolate->is_best_effort_code_coverage() ||
292 : isolate->is_collecting_type_profile()) {
293 1192 : AddToVectorsForProfilingTools(isolate, result);
294 : }
295 3062184 : return result;
296 : }
297 :
298 : // static
299 1192 : void FeedbackVector::AddToVectorsForProfilingTools(
300 : Isolate* isolate, Handle<FeedbackVector> vector) {
301 : DCHECK(!isolate->is_best_effort_code_coverage() ||
302 : isolate->is_collecting_type_profile());
303 1192 : if (!vector->shared_function_info()->IsSubjectToDebugging()) return;
304 : Handle<ArrayList> list = Handle<ArrayList>::cast(
305 1192 : isolate->factory()->feedback_vectors_for_profiling_tools());
306 1192 : list = ArrayList::Add(isolate, list, vector);
307 1192 : isolate->SetFeedbackVectorsForProfilingTools(*list);
308 : }
309 :
310 : // static
311 22993 : void FeedbackVector::SetOptimizedCode(Handle<FeedbackVector> vector,
312 : Handle<Code> code) {
313 : DCHECK_EQ(code->kind(), Code::OPTIMIZED_FUNCTION);
314 45986 : vector->set_optimized_code_weak_or_smi(HeapObjectReference::Weak(*code));
315 22993 : }
316 :
317 0 : void FeedbackVector::ClearOptimizedCode() {
318 : DCHECK(has_optimized_code());
319 : SetOptimizationMarker(OptimizationMarker::kNone);
320 0 : }
321 :
322 754277 : void FeedbackVector::ClearOptimizationMarker() {
323 : DCHECK(!has_optimized_code());
324 : SetOptimizationMarker(OptimizationMarker::kNone);
325 754277 : }
326 :
327 492048 : void FeedbackVector::SetOptimizationMarker(OptimizationMarker marker) {
328 1248573 : set_optimized_code_weak_or_smi(MaybeObject::FromSmi(Smi::FromEnum(marker)));
329 492048 : }
330 :
331 4392397 : void FeedbackVector::EvictOptimizedCodeMarkedForDeoptimization(
332 : SharedFunctionInfo shared, const char* reason) {
333 4392397 : MaybeObject slot = optimized_code_weak_or_smi();
334 4392397 : if (slot->IsSmi()) {
335 3949759 : return;
336 : }
337 :
338 442901 : if (slot->IsCleared()) {
339 : ClearOptimizationMarker();
340 : return;
341 : }
342 :
343 885276 : Code code = Code::cast(slot->GetHeapObject());
344 442638 : if (code->marked_for_deoptimization()) {
345 1985 : if (FLAG_trace_deopt) {
346 : PrintF("[evicting optimizing code marked for deoptimization (%s) for ",
347 0 : reason);
348 0 : shared->ShortPrint();
349 0 : PrintF("]\n");
350 : }
351 1985 : if (!code->deopt_already_counted()) {
352 : increment_deopt_count();
353 1218 : code->set_deopt_already_counted(true);
354 : }
355 : ClearOptimizedCode();
356 : }
357 : }
358 :
359 52330 : bool FeedbackVector::ClearSlots(Isolate* isolate) {
360 : MaybeObject uninitialized_sentinel = MaybeObject::FromObject(
361 52330 : FeedbackVector::RawUninitializedSentinel(isolate));
362 :
363 : bool feedback_updated = false;
364 : FeedbackMetadataIterator iter(metadata());
365 132976 : while (iter.HasNext()) {
366 80646 : FeedbackSlot slot = iter.Next();
367 :
368 : MaybeObject obj = Get(slot);
369 80646 : if (obj != uninitialized_sentinel) {
370 : FeedbackNexus nexus(*this, slot);
371 55515 : feedback_updated |= nexus.Clear();
372 : }
373 : }
374 52330 : return feedback_updated;
375 : }
376 :
377 411050 : void FeedbackVector::AssertNoLegacyTypes(MaybeObject object) {
378 : #ifdef DEBUG
379 : HeapObject heap_object;
380 : if (object->GetHeapObject(&heap_object)) {
381 : // Instead of FixedArray, the Feedback and the Extra should contain
382 : // WeakFixedArrays. The only allowed FixedArray subtype is HashTable.
383 : DCHECK_IMPLIES(heap_object->IsFixedArray(), heap_object->IsHashTable());
384 : }
385 : #endif
386 411050 : }
387 :
388 224704 : Handle<WeakFixedArray> FeedbackNexus::EnsureArrayOfSize(int length) {
389 224704 : Isolate* isolate = GetIsolate();
390 224707 : HeapObject heap_object;
391 534326 : if (GetFeedback()->GetHeapObjectIfStrong(&heap_object) &&
392 309431 : heap_object->IsWeakFixedArray() &&
393 : WeakFixedArray::cast(heap_object)->length() == length) {
394 : return handle(WeakFixedArray::cast(heap_object), isolate);
395 : }
396 218252 : Handle<WeakFixedArray> array = isolate->factory()->NewWeakFixedArray(length);
397 : SetFeedback(*array);
398 218254 : return array;
399 : }
400 :
401 16559 : Handle<WeakFixedArray> FeedbackNexus::EnsureExtraArrayOfSize(int length) {
402 16559 : Isolate* isolate = GetIsolate();
403 16559 : HeapObject heap_object;
404 36909 : if (GetFeedbackExtra()->GetHeapObjectIfStrong(&heap_object) &&
405 20336 : heap_object->IsWeakFixedArray() &&
406 : WeakFixedArray::cast(heap_object)->length() == length) {
407 : return handle(WeakFixedArray::cast(heap_object), isolate);
408 : }
409 16340 : Handle<WeakFixedArray> array = isolate->factory()->NewWeakFixedArray(length);
410 16340 : SetFeedbackExtra(*array);
411 16340 : return array;
412 : }
413 :
414 90754 : void FeedbackNexus::ConfigureUninitialized() {
415 45377 : Isolate* isolate = GetIsolate();
416 45377 : switch (kind()) {
417 : case FeedbackSlotKind::kStoreGlobalSloppy:
418 : case FeedbackSlotKind::kStoreGlobalStrict:
419 : case FeedbackSlotKind::kLoadGlobalNotInsideTypeof:
420 : case FeedbackSlotKind::kLoadGlobalInsideTypeof: {
421 : SetFeedback(HeapObjectReference::ClearedValue(isolate),
422 8066 : SKIP_WRITE_BARRIER);
423 : SetFeedbackExtra(*FeedbackVector::UninitializedSentinel(isolate),
424 8066 : SKIP_WRITE_BARRIER);
425 8066 : break;
426 : }
427 : case FeedbackSlotKind::kCloneObject:
428 : case FeedbackSlotKind::kCall: {
429 : SetFeedback(*FeedbackVector::UninitializedSentinel(isolate),
430 : SKIP_WRITE_BARRIER);
431 6428 : SetFeedbackExtra(Smi::kZero, SKIP_WRITE_BARRIER);
432 6428 : break;
433 : }
434 : case FeedbackSlotKind::kInstanceOf: {
435 : SetFeedback(*FeedbackVector::UninitializedSentinel(isolate),
436 : SKIP_WRITE_BARRIER);
437 0 : break;
438 : }
439 : case FeedbackSlotKind::kStoreNamedSloppy:
440 : case FeedbackSlotKind::kStoreNamedStrict:
441 : case FeedbackSlotKind::kStoreKeyedSloppy:
442 : case FeedbackSlotKind::kStoreKeyedStrict:
443 : case FeedbackSlotKind::kStoreInArrayLiteral:
444 : case FeedbackSlotKind::kStoreOwnNamed:
445 : case FeedbackSlotKind::kLoadProperty:
446 : case FeedbackSlotKind::kLoadKeyed:
447 : case FeedbackSlotKind::kStoreDataPropertyInLiteral: {
448 : SetFeedback(*FeedbackVector::UninitializedSentinel(isolate),
449 : SKIP_WRITE_BARRIER);
450 : SetFeedbackExtra(*FeedbackVector::UninitializedSentinel(isolate),
451 30883 : SKIP_WRITE_BARRIER);
452 30883 : break;
453 : }
454 : default:
455 0 : UNREACHABLE();
456 : }
457 45377 : }
458 :
459 55515 : bool FeedbackNexus::Clear() {
460 : bool feedback_updated = false;
461 :
462 : switch (kind()) {
463 : case FeedbackSlotKind::kCreateClosure:
464 : case FeedbackSlotKind::kTypeProfile:
465 : // We don't clear these kinds ever.
466 : break;
467 :
468 : case FeedbackSlotKind::kCompareOp:
469 : case FeedbackSlotKind::kForIn:
470 : case FeedbackSlotKind::kBinaryOp:
471 : // We don't clear these, either.
472 : break;
473 :
474 : case FeedbackSlotKind::kLiteral:
475 : SetFeedback(Smi::kZero, SKIP_WRITE_BARRIER);
476 : feedback_updated = true;
477 13 : break;
478 :
479 : case FeedbackSlotKind::kStoreNamedSloppy:
480 : case FeedbackSlotKind::kStoreNamedStrict:
481 : case FeedbackSlotKind::kStoreKeyedSloppy:
482 : case FeedbackSlotKind::kStoreKeyedStrict:
483 : case FeedbackSlotKind::kStoreInArrayLiteral:
484 : case FeedbackSlotKind::kStoreOwnNamed:
485 : case FeedbackSlotKind::kLoadProperty:
486 : case FeedbackSlotKind::kLoadKeyed:
487 : case FeedbackSlotKind::kStoreGlobalSloppy:
488 : case FeedbackSlotKind::kStoreGlobalStrict:
489 : case FeedbackSlotKind::kLoadGlobalNotInsideTypeof:
490 : case FeedbackSlotKind::kLoadGlobalInsideTypeof:
491 : case FeedbackSlotKind::kCall:
492 : case FeedbackSlotKind::kInstanceOf:
493 : case FeedbackSlotKind::kStoreDataPropertyInLiteral:
494 : case FeedbackSlotKind::kCloneObject:
495 47391 : if (!IsCleared()) {
496 45377 : ConfigureUninitialized();
497 : feedback_updated = true;
498 : }
499 : break;
500 :
501 : case FeedbackSlotKind::kInvalid:
502 : case FeedbackSlotKind::kKindsNumber:
503 0 : UNREACHABLE();
504 : break;
505 : }
506 55515 : return feedback_updated;
507 : }
508 :
509 645123 : void FeedbackNexus::ConfigurePremonomorphic(Handle<Map> receiver_map) {
510 645123 : SetFeedback(*FeedbackVector::PremonomorphicSentinel(GetIsolate()),
511 : SKIP_WRITE_BARRIER);
512 645124 : SetFeedbackExtra(HeapObjectReference::Weak(*receiver_map));
513 645128 : }
514 :
515 126 : bool FeedbackNexus::ConfigureMegamorphic() {
516 : DisallowHeapAllocation no_gc;
517 126 : Isolate* isolate = GetIsolate();
518 : MaybeObject sentinel =
519 : MaybeObject::FromObject(*FeedbackVector::MegamorphicSentinel(isolate));
520 252 : if (GetFeedback() != sentinel) {
521 126 : SetFeedback(sentinel, SKIP_WRITE_BARRIER);
522 126 : SetFeedbackExtra(HeapObjectReference::ClearedValue(isolate));
523 126 : return true;
524 : }
525 :
526 : return false;
527 : }
528 :
529 45174 : bool FeedbackNexus::ConfigureMegamorphic(IcCheckType property_type) {
530 : DisallowHeapAllocation no_gc;
531 45174 : Isolate* isolate = GetIsolate();
532 : bool changed = false;
533 : MaybeObject sentinel =
534 : MaybeObject::FromObject(*FeedbackVector::MegamorphicSentinel(isolate));
535 90348 : if (GetFeedback() != sentinel) {
536 41491 : SetFeedback(sentinel, SKIP_WRITE_BARRIER);
537 : changed = true;
538 : }
539 :
540 45174 : Smi extra = Smi::FromInt(static_cast<int>(property_type));
541 48857 : if (changed || GetFeedbackExtra() != MaybeObject::FromSmi(extra)) {
542 41491 : SetFeedbackExtra(extra, SKIP_WRITE_BARRIER);
543 : changed = true;
544 : }
545 45174 : return changed;
546 : }
547 :
548 103754 : Map FeedbackNexus::GetFirstMap() const {
549 : MapHandles maps;
550 103754 : ExtractMaps(&maps);
551 207508 : if (maps.size() > 0) return *maps.at(0);
552 4 : return Map();
553 : }
554 :
555 25906334 : InlineCacheState FeedbackNexus::ic_state() const {
556 12953163 : Isolate* isolate = GetIsolate();
557 12953160 : MaybeObject feedback = GetFeedback();
558 :
559 12953171 : switch (kind()) {
560 : case FeedbackSlotKind::kCreateClosure:
561 : return MONOMORPHIC;
562 :
563 : case FeedbackSlotKind::kLiteral:
564 51333 : if (feedback->IsSmi()) return UNINITIALIZED;
565 7633 : return MONOMORPHIC;
566 :
567 : case FeedbackSlotKind::kStoreGlobalSloppy:
568 : case FeedbackSlotKind::kStoreGlobalStrict:
569 : case FeedbackSlotKind::kLoadGlobalNotInsideTypeof:
570 : case FeedbackSlotKind::kLoadGlobalInsideTypeof: {
571 6431608 : if (feedback->IsSmi()) return MONOMORPHIC;
572 :
573 6431318 : if (feedback == MaybeObject::FromObject(
574 : *FeedbackVector::PremonomorphicSentinel(isolate))) {
575 : DCHECK(kind() == FeedbackSlotKind::kStoreGlobalSloppy ||
576 : kind() == FeedbackSlotKind::kStoreGlobalStrict);
577 : return PREMONOMORPHIC;
578 : }
579 :
580 : DCHECK(feedback->IsWeakOrCleared());
581 6431287 : MaybeObject extra = GetFeedbackExtra();
582 12446627 : if (!feedback->IsCleared() ||
583 : extra != MaybeObject::FromObject(
584 : *FeedbackVector::UninitializedSentinel(isolate))) {
585 : return MONOMORPHIC;
586 : }
587 6010637 : return UNINITIALIZED;
588 : }
589 :
590 : case FeedbackSlotKind::kStoreNamedSloppy:
591 : case FeedbackSlotKind::kStoreNamedStrict:
592 : case FeedbackSlotKind::kStoreKeyedSloppy:
593 : case FeedbackSlotKind::kStoreKeyedStrict:
594 : case FeedbackSlotKind::kStoreInArrayLiteral:
595 : case FeedbackSlotKind::kStoreOwnNamed:
596 : case FeedbackSlotKind::kLoadProperty:
597 : case FeedbackSlotKind::kLoadKeyed: {
598 4780204 : if (feedback == MaybeObject::FromObject(
599 : *FeedbackVector::UninitializedSentinel(isolate))) {
600 : return UNINITIALIZED;
601 : }
602 2947330 : if (feedback == MaybeObject::FromObject(
603 : *FeedbackVector::MegamorphicSentinel(isolate))) {
604 : return MEGAMORPHIC;
605 : }
606 2286626 : if (feedback == MaybeObject::FromObject(
607 : *FeedbackVector::PremonomorphicSentinel(isolate))) {
608 : return PREMONOMORPHIC;
609 : }
610 900322 : if (feedback->IsWeakOrCleared()) {
611 : // Don't check if the map is cleared.
612 : return MONOMORPHIC;
613 : }
614 219864 : HeapObject heap_object;
615 219864 : if (feedback->GetHeapObjectIfStrong(&heap_object)) {
616 219864 : if (heap_object->IsWeakFixedArray()) {
617 : // Determine state purely by our structure, don't check if the maps
618 : // are cleared.
619 : return POLYMORPHIC;
620 : }
621 15504 : if (heap_object->IsName()) {
622 : DCHECK(IsKeyedLoadICKind(kind()) || IsKeyedStoreICKind(kind()));
623 15504 : Object extra = GetFeedbackExtra()->GetHeapObjectAssumeStrong();
624 : WeakFixedArray extra_array = WeakFixedArray::cast(extra);
625 15504 : return extra_array->length() > 2 ? POLYMORPHIC : MONOMORPHIC;
626 : }
627 : }
628 0 : UNREACHABLE();
629 : }
630 : case FeedbackSlotKind::kCall: {
631 1027778 : HeapObject heap_object;
632 1027778 : if (feedback == MaybeObject::FromObject(
633 : *FeedbackVector::MegamorphicSentinel(isolate))) {
634 : return GENERIC;
635 2681325 : } else if (feedback->IsWeakOrCleared() ||
636 1334282 : (feedback->GetHeapObjectIfStrong(&heap_object) &&
637 : heap_object->IsAllocationSite())) {
638 : return MONOMORPHIC;
639 : }
640 :
641 1330784 : CHECK_EQ(feedback, MaybeObject::FromObject(
642 : *FeedbackVector::UninitializedSentinel(isolate)));
643 : return UNINITIALIZED;
644 : }
645 : case FeedbackSlotKind::kBinaryOp: {
646 273857 : BinaryOperationHint hint = GetBinaryOperationFeedback();
647 273857 : if (hint == BinaryOperationHint::kNone) {
648 : return UNINITIALIZED;
649 258659 : } else if (hint == BinaryOperationHint::kAny) {
650 : return GENERIC;
651 : }
652 :
653 255341 : return MONOMORPHIC;
654 : }
655 : case FeedbackSlotKind::kCompareOp: {
656 153013 : CompareOperationHint hint = GetCompareOperationFeedback();
657 153013 : if (hint == CompareOperationHint::kNone) {
658 : return UNINITIALIZED;
659 139027 : } else if (hint == CompareOperationHint::kAny) {
660 : return GENERIC;
661 : }
662 :
663 102756 : return MONOMORPHIC;
664 : }
665 : case FeedbackSlotKind::kForIn: {
666 1380 : ForInHint hint = GetForInFeedback();
667 1380 : if (hint == ForInHint::kNone) {
668 : return UNINITIALIZED;
669 1347 : } else if (hint == ForInHint::kAny) {
670 : return GENERIC;
671 : }
672 483 : return MONOMORPHIC;
673 : }
674 : case FeedbackSlotKind::kInstanceOf: {
675 4885 : if (feedback == MaybeObject::FromObject(
676 : *FeedbackVector::UninitializedSentinel(isolate))) {
677 : return UNINITIALIZED;
678 2030 : } else if (feedback ==
679 : MaybeObject::FromObject(
680 : *FeedbackVector::MegamorphicSentinel(isolate))) {
681 : return MEGAMORPHIC;
682 : }
683 1809 : return MONOMORPHIC;
684 : }
685 : case FeedbackSlotKind::kStoreDataPropertyInLiteral: {
686 228167 : if (feedback == MaybeObject::FromObject(
687 : *FeedbackVector::UninitializedSentinel(isolate))) {
688 : return UNINITIALIZED;
689 223965 : } else if (feedback->IsWeakOrCleared()) {
690 : // Don't check if the map is cleared.
691 : return MONOMORPHIC;
692 : }
693 :
694 16354 : return MEGAMORPHIC;
695 : }
696 : case FeedbackSlotKind::kTypeProfile: {
697 0 : if (feedback == MaybeObject::FromObject(
698 : *FeedbackVector::UninitializedSentinel(isolate))) {
699 : return UNINITIALIZED;
700 : }
701 0 : return MONOMORPHIC;
702 : }
703 :
704 : case FeedbackSlotKind::kCloneObject: {
705 940 : if (feedback == MaybeObject::FromObject(
706 : *FeedbackVector::UninitializedSentinel(isolate))) {
707 : return UNINITIALIZED;
708 : }
709 280 : if (feedback == MaybeObject::FromObject(
710 : *FeedbackVector::MegamorphicSentinel(isolate))) {
711 : return MEGAMORPHIC;
712 : }
713 280 : if (feedback->IsWeakOrCleared()) {
714 : return MONOMORPHIC;
715 : }
716 :
717 : DCHECK(feedback->GetHeapObjectAssumeStrong()->IsWeakFixedArray());
718 180 : return POLYMORPHIC;
719 : }
720 :
721 : case FeedbackSlotKind::kInvalid:
722 : case FeedbackSlotKind::kKindsNumber:
723 0 : UNREACHABLE();
724 : break;
725 : }
726 0 : return UNINITIALIZED;
727 : }
728 :
729 5620887 : void FeedbackNexus::ConfigurePropertyCellMode(Handle<PropertyCell> cell) {
730 : DCHECK(IsGlobalICKind(kind()));
731 5620887 : Isolate* isolate = GetIsolate();
732 5620893 : SetFeedback(HeapObjectReference::Weak(*cell));
733 : SetFeedbackExtra(*FeedbackVector::UninitializedSentinel(isolate),
734 5620896 : SKIP_WRITE_BARRIER);
735 5620896 : }
736 :
737 55393 : bool FeedbackNexus::ConfigureLexicalVarMode(int script_context_index,
738 : int context_slot_index,
739 : bool immutable) {
740 : DCHECK(IsGlobalICKind(kind()));
741 : DCHECK_LE(0, script_context_index);
742 : DCHECK_LE(0, context_slot_index);
743 166179 : if (!ContextIndexBits::is_valid(script_context_index) ||
744 110787 : !SlotIndexBits::is_valid(context_slot_index) ||
745 : !ImmutabilityBit::is_valid(immutable)) {
746 : return false;
747 : }
748 55394 : int config = ContextIndexBits::encode(script_context_index) |
749 110788 : SlotIndexBits::encode(context_slot_index) |
750 55394 : ImmutabilityBit::encode(immutable);
751 :
752 : SetFeedback(Smi::From31BitPattern(config));
753 55393 : Isolate* isolate = GetIsolate();
754 : SetFeedbackExtra(*FeedbackVector::UninitializedSentinel(isolate),
755 55394 : SKIP_WRITE_BARRIER);
756 55392 : return true;
757 : }
758 :
759 44550 : void FeedbackNexus::ConfigureHandlerMode(const MaybeObjectHandle& handler) {
760 : DCHECK(IsGlobalICKind(kind()));
761 : DCHECK(IC::IsHandler(*handler));
762 89100 : SetFeedback(HeapObjectReference::ClearedValue(GetIsolate()));
763 44550 : SetFeedbackExtra(*handler);
764 44550 : }
765 :
766 432 : void FeedbackNexus::ConfigureCloneObject(Handle<Map> source_map,
767 : Handle<Map> result_map) {
768 432 : Isolate* isolate = GetIsolate();
769 432 : MaybeObject maybe_feedback = GetFeedback();
770 : Handle<HeapObject> feedback(maybe_feedback->IsStrongOrWeak()
771 : ? maybe_feedback->GetHeapObject()
772 : : HeapObject(),
773 432 : isolate);
774 432 : switch (ic_state()) {
775 : case UNINITIALIZED:
776 : // Cache the first map seen which meets the fast case requirements.
777 306 : SetFeedback(HeapObjectReference::Weak(*source_map));
778 306 : SetFeedbackExtra(*result_map);
779 306 : break;
780 : case MONOMORPHIC:
781 144 : if (maybe_feedback->IsCleared() || feedback.is_identical_to(source_map) ||
782 72 : Map::cast(*feedback)->is_deprecated()) {
783 : // Remain in MONOMORPHIC state if previous feedback has been collected.
784 0 : SetFeedback(HeapObjectReference::Weak(*source_map));
785 0 : SetFeedbackExtra(*result_map);
786 : } else {
787 : // Transition to POLYMORPHIC.
788 : Handle<WeakFixedArray> array =
789 36 : EnsureArrayOfSize(2 * kCloneObjectPolymorphicEntrySize);
790 36 : array->Set(0, maybe_feedback);
791 72 : array->Set(1, GetFeedbackExtra());
792 72 : array->Set(2, HeapObjectReference::Weak(*source_map));
793 36 : array->Set(3, MaybeObject::FromObject(*result_map));
794 36 : SetFeedbackExtra(HeapObjectReference::ClearedValue(isolate));
795 : }
796 : break;
797 : case POLYMORPHIC: {
798 : const int kMaxElements =
799 90 : FLAG_max_polymorphic_map_count * kCloneObjectPolymorphicEntrySize;
800 90 : Handle<WeakFixedArray> array = Handle<WeakFixedArray>::cast(feedback);
801 : int i = 0;
802 666 : for (; i < array->length(); i += kCloneObjectPolymorphicEntrySize) {
803 252 : MaybeObject feedback = array->Get(i);
804 252 : if (feedback->IsCleared()) break;
805 486 : Handle<Map> cached_map(Map::cast(feedback->GetHeapObject()), isolate);
806 729 : if (cached_map.is_identical_to(source_map) ||
807 729 : cached_map->is_deprecated())
808 : break;
809 : }
810 :
811 90 : if (i >= array->length()) {
812 81 : if (i == kMaxElements) {
813 : // Transition to MEGAMORPHIC.
814 : MaybeObject sentinel = MaybeObject::FromObject(
815 27 : *FeedbackVector::MegamorphicSentinel(isolate));
816 27 : SetFeedback(sentinel, SKIP_WRITE_BARRIER);
817 27 : SetFeedbackExtra(HeapObjectReference::ClearedValue(isolate));
818 : break;
819 : }
820 :
821 : // Grow polymorphic feedback array.
822 : Handle<WeakFixedArray> new_array = EnsureArrayOfSize(
823 54 : array->length() + kCloneObjectPolymorphicEntrySize);
824 648 : for (int j = 0; j < array->length(); ++j) {
825 540 : new_array->Set(j, array->Get(j));
826 : }
827 54 : array = new_array;
828 : }
829 :
830 126 : array->Set(i, HeapObjectReference::Weak(*source_map));
831 126 : array->Set(i + 1, MaybeObject::FromObject(*result_map));
832 63 : break;
833 : }
834 :
835 : default:
836 0 : UNREACHABLE();
837 : }
838 432 : }
839 :
840 502175 : int FeedbackNexus::GetCallCount() {
841 : DCHECK(IsCallICKind(kind()));
842 :
843 1004350 : Object call_count = GetFeedbackExtra()->cast<Object>();
844 502175 : CHECK(call_count->IsSmi());
845 502175 : uint32_t value = static_cast<uint32_t>(Smi::ToInt(call_count));
846 502175 : return CallCountField::decode(value);
847 : }
848 :
849 1891 : void FeedbackNexus::SetSpeculationMode(SpeculationMode mode) {
850 : DCHECK(IsCallICKind(kind()));
851 :
852 3782 : Object call_count = GetFeedbackExtra()->cast<Object>();
853 1891 : CHECK(call_count->IsSmi());
854 1891 : uint32_t count = static_cast<uint32_t>(Smi::ToInt(call_count));
855 : uint32_t value = CallCountField::encode(CallCountField::decode(count));
856 1891 : int result = static_cast<int>(value | SpeculationModeField::encode(mode));
857 1891 : SetFeedbackExtra(Smi::FromInt(result), SKIP_WRITE_BARRIER);
858 1891 : }
859 :
860 462069 : SpeculationMode FeedbackNexus::GetSpeculationMode() {
861 : DCHECK(IsCallICKind(kind()));
862 :
863 924138 : Object call_count = GetFeedbackExtra()->cast<Object>();
864 462069 : CHECK(call_count->IsSmi());
865 462069 : uint32_t value = static_cast<uint32_t>(Smi::ToInt(call_count));
866 462069 : return SpeculationModeField::decode(value);
867 : }
868 :
869 502147 : float FeedbackNexus::ComputeCallFrequency() {
870 : DCHECK(IsCallICKind(kind()));
871 :
872 1004294 : double const invocation_count = vector()->invocation_count();
873 502147 : double const call_count = GetCallCount();
874 502147 : if (invocation_count == 0) {
875 : // Prevent division by 0.
876 : return 0.0f;
877 : }
878 191433 : return static_cast<float>(call_count / invocation_count);
879 : }
880 :
881 1805926 : void FeedbackNexus::ConfigureMonomorphic(Handle<Name> name,
882 : Handle<Map> receiver_map,
883 1805926 : const MaybeObjectHandle& handler) {
884 : DCHECK(handler.is_null() || IC::IsHandler(*handler));
885 1805926 : if (kind() == FeedbackSlotKind::kStoreDataPropertyInLiteral) {
886 3257 : SetFeedback(HeapObjectReference::Weak(*receiver_map));
887 3257 : SetFeedbackExtra(*name);
888 : } else {
889 1802669 : if (name.is_null()) {
890 1789679 : SetFeedback(HeapObjectReference::Weak(*receiver_map));
891 1789678 : SetFeedbackExtra(*handler);
892 : } else {
893 12996 : Handle<WeakFixedArray> array = EnsureExtraArrayOfSize(2);
894 : SetFeedback(*name);
895 25992 : array->Set(0, HeapObjectReference::Weak(*receiver_map));
896 25992 : array->Set(1, *handler);
897 : }
898 : }
899 1805944 : }
900 :
901 228177 : void FeedbackNexus::ConfigurePolymorphic(Handle<Name> name,
902 802648 : MapHandles const& maps,
903 : MaybeObjectHandles* handlers) {
904 : DCHECK_EQ(handlers->size(), maps.size());
905 228177 : int receiver_count = static_cast<int>(maps.size());
906 : DCHECK_GT(receiver_count, 1);
907 : Handle<WeakFixedArray> array;
908 228177 : if (name.is_null()) {
909 224614 : array = EnsureArrayOfSize(receiver_count * 2);
910 224617 : SetFeedbackExtra(*FeedbackVector::UninitializedSentinel(GetIsolate()),
911 224617 : SKIP_WRITE_BARRIER);
912 : } else {
913 3563 : array = EnsureExtraArrayOfSize(receiver_count * 2);
914 : SetFeedback(*name);
915 : }
916 :
917 802652 : for (int current = 0; current < receiver_count; ++current) {
918 1148942 : Handle<Map> map = maps[current];
919 1148944 : array->Set(current * 2, HeapObjectReference::Weak(*map));
920 : DCHECK(IC::IsHandler(*handlers->at(current)));
921 1148946 : array->Set(current * 2 + 1, *handlers->at(current));
922 : }
923 228181 : }
924 :
925 1002031 : int FeedbackNexus::ExtractMaps(MapHandles* maps) const {
926 : DCHECK(IsLoadICKind(kind()) || IsStoreICKind(kind()) ||
927 : IsKeyedLoadICKind(kind()) || IsKeyedStoreICKind(kind()) ||
928 : IsStoreOwnICKind(kind()) || IsStoreDataPropertyInLiteralKind(kind()) ||
929 : IsStoreInArrayLiteralICKind(kind()));
930 :
931 1002031 : Isolate* isolate = GetIsolate();
932 1002034 : MaybeObject feedback = GetFeedback();
933 1002035 : bool is_named_feedback = IsPropertyNameFeedback(feedback);
934 1002036 : HeapObject heap_object;
935 2566987 : if ((feedback->GetHeapObjectIfStrong(&heap_object) &&
936 1849757 : heap_object->IsWeakFixedArray()) ||
937 : is_named_feedback) {
938 : int found = 0;
939 159540 : WeakFixedArray array;
940 159540 : if (is_named_feedback) {
941 : array =
942 10454 : WeakFixedArray::cast(GetFeedbackExtra()->GetHeapObjectAssumeStrong());
943 : } else {
944 154313 : array = WeakFixedArray::cast(heap_object);
945 : }
946 : const int increment = 2;
947 159540 : HeapObject heap_object;
948 1104616 : for (int i = 0; i < array->length(); i += increment) {
949 : DCHECK(array->Get(i)->IsWeakOrCleared());
950 392768 : if (array->Get(i)->GetHeapObjectIfWeak(&heap_object)) {
951 : Map map = Map::cast(heap_object);
952 646524 : maps->push_back(handle(map, isolate));
953 323262 : found++;
954 : }
955 : }
956 : return found;
957 842495 : } else if (feedback->GetHeapObjectIfWeak(&heap_object)) {
958 : Map map = Map::cast(heap_object);
959 741582 : maps->push_back(handle(map, isolate));
960 : return 1;
961 1415111 : } else if (feedback->GetHeapObjectIfStrong(&heap_object) &&
962 : heap_object ==
963 1278457 : heap_object->GetReadOnlyRoots().premonomorphic_symbol()) {
964 8204 : if (GetFeedbackExtra()->GetHeapObjectIfWeak(&heap_object)) {
965 : Map map = Map::cast(heap_object);
966 15056 : maps->push_back(handle(map, isolate));
967 : return 1;
968 : }
969 : }
970 :
971 : return 0;
972 : }
973 :
974 342425 : MaybeObjectHandle FeedbackNexus::FindHandlerForMap(Handle<Map> map) const {
975 : DCHECK(IsLoadICKind(kind()) || IsStoreICKind(kind()) ||
976 : IsKeyedLoadICKind(kind()) || IsKeyedStoreICKind(kind()) ||
977 : IsStoreOwnICKind(kind()) || IsStoreDataPropertyInLiteralKind(kind()));
978 :
979 342425 : MaybeObject feedback = GetFeedback();
980 342426 : Isolate* isolate = GetIsolate();
981 342427 : bool is_named_feedback = IsPropertyNameFeedback(feedback);
982 342425 : HeapObject heap_object;
983 808969 : if ((feedback->GetHeapObjectIfStrong(&heap_object) &&
984 562404 : heap_object->IsWeakFixedArray()) ||
985 : is_named_feedback) {
986 124119 : WeakFixedArray array;
987 124119 : if (is_named_feedback) {
988 : array =
989 3346 : WeakFixedArray::cast(GetFeedbackExtra()->GetHeapObjectAssumeStrong());
990 : } else {
991 122446 : array = WeakFixedArray::cast(heap_object);
992 : }
993 : const int increment = 2;
994 124119 : HeapObject heap_object;
995 864022 : for (int i = 0; i < array->length(); i += increment) {
996 : DCHECK(array->Get(i)->IsWeakOrCleared());
997 308406 : if (array->Get(i)->GetHeapObjectIfWeak(&heap_object)) {
998 : Map array_map = Map::cast(heap_object);
999 239762 : if (array_map == *map && !array->Get(i + increment - 1)->IsCleared()) {
1000 514 : MaybeObject handler = array->Get(i + increment - 1);
1001 : DCHECK(IC::IsHandler(handler));
1002 : return handle(handler, isolate);
1003 : }
1004 : }
1005 : }
1006 218306 : } else if (feedback->GetHeapObjectIfWeak(&heap_object)) {
1007 : Map cell_map = Map::cast(heap_object);
1008 163350 : if (cell_map == *map && !GetFeedbackExtra()->IsCleared()) {
1009 12521 : MaybeObject handler = GetFeedbackExtra();
1010 : DCHECK(IC::IsHandler(handler));
1011 : return handle(handler, isolate);
1012 : }
1013 : }
1014 :
1015 329391 : return MaybeObjectHandle();
1016 : }
1017 :
1018 467175 : bool FeedbackNexus::FindHandlers(MaybeObjectHandles* code_list,
1019 : int length) const {
1020 : DCHECK(IsLoadICKind(kind()) || IsStoreICKind(kind()) ||
1021 : IsKeyedLoadICKind(kind()) || IsKeyedStoreICKind(kind()) ||
1022 : IsStoreOwnICKind(kind()) || IsStoreDataPropertyInLiteralKind(kind()) ||
1023 : IsStoreInArrayLiteralICKind(kind()));
1024 :
1025 467175 : MaybeObject feedback = GetFeedback();
1026 467176 : Isolate* isolate = GetIsolate();
1027 : int count = 0;
1028 467176 : bool is_named_feedback = IsPropertyNameFeedback(feedback);
1029 467176 : HeapObject heap_object;
1030 1152891 : if ((feedback->GetHeapObjectIfStrong(&heap_object) &&
1031 793343 : heap_object->IsWeakFixedArray()) ||
1032 : is_named_feedback) {
1033 145539 : WeakFixedArray array;
1034 145539 : if (is_named_feedback) {
1035 : array =
1036 9064 : WeakFixedArray::cast(GetFeedbackExtra()->GetHeapObjectAssumeStrong());
1037 : } else {
1038 141006 : array = WeakFixedArray::cast(heap_object);
1039 : }
1040 : const int increment = 2;
1041 145538 : HeapObject heap_object;
1042 1051490 : for (int i = 0; i < array->length(); i += increment) {
1043 : // Be sure to skip handlers whose maps have been cleared.
1044 : DCHECK(array->Get(i)->IsWeakOrCleared());
1045 1071344 : if (array->Get(i)->GetHeapObjectIfWeak(&heap_object) &&
1046 691138 : !array->Get(i + increment - 1)->IsCleared()) {
1047 310923 : MaybeObject handler = array->Get(i + increment - 1);
1048 : DCHECK(IC::IsHandler(handler));
1049 621846 : code_list->push_back(handle(handler, isolate));
1050 310923 : count++;
1051 : }
1052 : }
1053 321636 : } else if (feedback->GetHeapObjectIfWeak(&heap_object)) {
1054 180914 : MaybeObject extra = GetFeedbackExtra();
1055 180916 : if (!extra->IsCleared()) {
1056 : DCHECK(IC::IsHandler(extra));
1057 360712 : code_list->push_back(handle(extra, isolate));
1058 : count++;
1059 : }
1060 : }
1061 467176 : return count == length;
1062 : }
1063 :
1064 46788 : Name FeedbackNexus::GetName() const {
1065 46788 : if (IsKeyedStoreICKind(kind()) || IsKeyedLoadICKind(kind())) {
1066 46788 : MaybeObject feedback = GetFeedback();
1067 46788 : if (IsPropertyNameFeedback(feedback)) {
1068 51670 : return Name::cast(feedback->GetHeapObjectAssumeStrong());
1069 : }
1070 : }
1071 20953 : return Name();
1072 : }
1073 :
1074 43845 : KeyedAccessLoadMode FeedbackNexus::GetKeyedAccessLoadMode() const {
1075 : DCHECK(IsKeyedLoadICKind(kind()));
1076 : MapHandles maps;
1077 : MaybeObjectHandles handlers;
1078 :
1079 43845 : if (GetKeyType() == PROPERTY) return STANDARD_LOAD;
1080 :
1081 42061 : ExtractMaps(&maps);
1082 84122 : FindHandlers(&handlers, static_cast<int>(maps.size()));
1083 101626 : for (MaybeObjectHandle const& handler : handlers) {
1084 18324 : KeyedAccessLoadMode mode = LoadHandler::GetKeyedAccessLoadMode(*handler);
1085 18324 : if (mode != STANDARD_LOAD) return mode;
1086 : }
1087 :
1088 : return STANDARD_LOAD;
1089 : }
1090 :
1091 : namespace {
1092 :
1093 : bool BuiltinHasKeyedAccessStoreMode(int builtin_index) {
1094 : DCHECK(Builtins::IsBuiltinId(builtin_index));
1095 19770 : switch (builtin_index) {
1096 : case Builtins::kKeyedStoreIC_SloppyArguments_Standard:
1097 : case Builtins::kKeyedStoreIC_SloppyArguments_GrowNoTransitionHandleCOW:
1098 : case Builtins::kKeyedStoreIC_SloppyArguments_NoTransitionIgnoreOOB:
1099 : case Builtins::kKeyedStoreIC_SloppyArguments_NoTransitionHandleCOW:
1100 : case Builtins::kStoreFastElementIC_Standard:
1101 : case Builtins::kStoreFastElementIC_GrowNoTransitionHandleCOW:
1102 : case Builtins::kStoreFastElementIC_NoTransitionIgnoreOOB:
1103 : case Builtins::kStoreFastElementIC_NoTransitionHandleCOW:
1104 : case Builtins::kStoreInArrayLiteralIC_Slow_Standard:
1105 : case Builtins::kStoreInArrayLiteralIC_Slow_GrowNoTransitionHandleCOW:
1106 : case Builtins::kStoreInArrayLiteralIC_Slow_NoTransitionIgnoreOOB:
1107 : case Builtins::kStoreInArrayLiteralIC_Slow_NoTransitionHandleCOW:
1108 : case Builtins::kKeyedStoreIC_Slow_Standard:
1109 : case Builtins::kKeyedStoreIC_Slow_GrowNoTransitionHandleCOW:
1110 : case Builtins::kKeyedStoreIC_Slow_NoTransitionIgnoreOOB:
1111 : case Builtins::kKeyedStoreIC_Slow_NoTransitionHandleCOW:
1112 : case Builtins::kElementsTransitionAndStore_Standard:
1113 : case Builtins::kElementsTransitionAndStore_GrowNoTransitionHandleCOW:
1114 : case Builtins::kElementsTransitionAndStore_NoTransitionIgnoreOOB:
1115 : case Builtins::kElementsTransitionAndStore_NoTransitionHandleCOW:
1116 : return true;
1117 : default:
1118 : return false;
1119 : }
1120 : UNREACHABLE();
1121 : }
1122 :
1123 19761 : KeyedAccessStoreMode KeyedAccessStoreModeForBuiltin(int builtin_index) {
1124 : DCHECK(BuiltinHasKeyedAccessStoreMode(builtin_index));
1125 19761 : switch (builtin_index) {
1126 : case Builtins::kKeyedStoreIC_SloppyArguments_Standard:
1127 : case Builtins::kStoreInArrayLiteralIC_Slow_Standard:
1128 : case Builtins::kKeyedStoreIC_Slow_Standard:
1129 : case Builtins::kStoreFastElementIC_Standard:
1130 : case Builtins::kElementsTransitionAndStore_Standard:
1131 : return STANDARD_STORE;
1132 : case Builtins::kKeyedStoreIC_SloppyArguments_GrowNoTransitionHandleCOW:
1133 : case Builtins::kStoreInArrayLiteralIC_Slow_GrowNoTransitionHandleCOW:
1134 : case Builtins::kKeyedStoreIC_Slow_GrowNoTransitionHandleCOW:
1135 : case Builtins::kStoreFastElementIC_GrowNoTransitionHandleCOW:
1136 : case Builtins::kElementsTransitionAndStore_GrowNoTransitionHandleCOW:
1137 4634 : return STORE_AND_GROW_NO_TRANSITION_HANDLE_COW;
1138 : case Builtins::kKeyedStoreIC_SloppyArguments_NoTransitionIgnoreOOB:
1139 : case Builtins::kStoreInArrayLiteralIC_Slow_NoTransitionIgnoreOOB:
1140 : case Builtins::kKeyedStoreIC_Slow_NoTransitionIgnoreOOB:
1141 : case Builtins::kStoreFastElementIC_NoTransitionIgnoreOOB:
1142 : case Builtins::kElementsTransitionAndStore_NoTransitionIgnoreOOB:
1143 296 : return STORE_NO_TRANSITION_IGNORE_OUT_OF_BOUNDS;
1144 : case Builtins::kKeyedStoreIC_SloppyArguments_NoTransitionHandleCOW:
1145 : case Builtins::kStoreInArrayLiteralIC_Slow_NoTransitionHandleCOW:
1146 : case Builtins::kKeyedStoreIC_Slow_NoTransitionHandleCOW:
1147 : case Builtins::kStoreFastElementIC_NoTransitionHandleCOW:
1148 : case Builtins::kElementsTransitionAndStore_NoTransitionHandleCOW:
1149 682 : return STORE_NO_TRANSITION_HANDLE_COW;
1150 : default:
1151 0 : UNREACHABLE();
1152 : }
1153 : }
1154 :
1155 : } // namespace
1156 :
1157 66981 : KeyedAccessStoreMode FeedbackNexus::GetKeyedAccessStoreMode() const {
1158 : DCHECK(IsKeyedStoreICKind(kind()) || IsStoreInArrayLiteralICKind(kind()));
1159 : KeyedAccessStoreMode mode = STANDARD_STORE;
1160 : MapHandles maps;
1161 : MaybeObjectHandles handlers;
1162 :
1163 66981 : if (GetKeyType() == PROPERTY) return mode;
1164 :
1165 66173 : ExtractMaps(&maps);
1166 132346 : FindHandlers(&handlers, static_cast<int>(maps.size()));
1167 132373 : for (const MaybeObjectHandle& maybe_code_handler : handlers) {
1168 : // The first handler that isn't the slow handler will have the bits we need.
1169 : Handle<Code> handler;
1170 59364 : if (maybe_code_handler.object()->IsStoreHandler()) {
1171 : Handle<StoreHandler> data_handler =
1172 8409 : Handle<StoreHandler>::cast(maybe_code_handler.object());
1173 : handler = handle(Code::cast(data_handler->smi_handler()),
1174 16818 : vector()->GetIsolate());
1175 34137 : } else if (maybe_code_handler.object()->IsSmi()) {
1176 : // Skip proxy handlers.
1177 : DCHECK_EQ(*(maybe_code_handler.object()),
1178 : *StoreHandler::StoreProxy(GetIsolate()));
1179 : continue;
1180 : } else {
1181 : // Element store without prototype chain check.
1182 11361 : handler = Handle<Code>::cast(maybe_code_handler.object());
1183 : }
1184 :
1185 19770 : if (handler->is_builtin()) {
1186 : const int builtin_index = handler->builtin_index();
1187 19770 : if (!BuiltinHasKeyedAccessStoreMode(builtin_index)) continue;
1188 :
1189 19761 : mode = KeyedAccessStoreModeForBuiltin(builtin_index);
1190 : break;
1191 : }
1192 : }
1193 :
1194 66173 : return mode;
1195 : }
1196 :
1197 131791 : IcCheckType FeedbackNexus::GetKeyType() const {
1198 : DCHECK(IsKeyedStoreICKind(kind()) || IsKeyedLoadICKind(kind()) ||
1199 : IsStoreInArrayLiteralICKind(kind()));
1200 131791 : MaybeObject feedback = GetFeedback();
1201 131791 : if (feedback == MaybeObject::FromObject(
1202 131791 : *FeedbackVector::MegamorphicSentinel(GetIsolate()))) {
1203 : return static_cast<IcCheckType>(
1204 10602 : Smi::ToInt(GetFeedbackExtra()->cast<Object>()));
1205 : }
1206 126490 : return IsPropertyNameFeedback(feedback) ? PROPERTY : ELEMENT;
1207 : }
1208 :
1209 958179 : BinaryOperationHint FeedbackNexus::GetBinaryOperationFeedback() const {
1210 : DCHECK_EQ(kind(), FeedbackSlotKind::kBinaryOp);
1211 1916358 : int feedback = GetFeedback().ToSmi().value();
1212 958179 : return BinaryOperationHintFromFeedback(feedback);
1213 : }
1214 :
1215 526883 : CompareOperationHint FeedbackNexus::GetCompareOperationFeedback() const {
1216 : DCHECK_EQ(kind(), FeedbackSlotKind::kCompareOp);
1217 1053766 : int feedback = GetFeedback().ToSmi().value();
1218 526883 : return CompareOperationHintFromFeedback(feedback);
1219 : }
1220 :
1221 4328 : ForInHint FeedbackNexus::GetForInFeedback() const {
1222 : DCHECK_EQ(kind(), FeedbackSlotKind::kForIn);
1223 8656 : int feedback = GetFeedback().ToSmi().value();
1224 4328 : return ForInHintFromFeedback(feedback);
1225 : }
1226 :
1227 436954 : Handle<FeedbackCell> FeedbackNexus::GetFeedbackCell() const {
1228 : DCHECK_EQ(FeedbackSlotKind::kCreateClosure, kind());
1229 : return handle(FeedbackCell::cast(GetFeedback()->cast<Object>()),
1230 1310863 : vector()->GetIsolate());
1231 : }
1232 :
1233 2748 : MaybeHandle<JSObject> FeedbackNexus::GetConstructorFeedback() const {
1234 : DCHECK_EQ(kind(), FeedbackSlotKind::kInstanceOf);
1235 2748 : Isolate* isolate = GetIsolate();
1236 2748 : MaybeObject feedback = GetFeedback();
1237 2748 : HeapObject heap_object;
1238 2748 : if (feedback->GetHeapObjectIfWeak(&heap_object)) {
1239 33 : return handle(JSObject::cast(heap_object), isolate);
1240 : }
1241 2715 : return MaybeHandle<JSObject>();
1242 : }
1243 :
1244 : namespace {
1245 :
1246 64 : bool InList(Handle<ArrayList> types, Handle<String> type) {
1247 248 : for (int i = 0; i < types->Length(); i++) {
1248 76 : Object obj = types->Get(i);
1249 76 : if (String::cast(obj)->Equals(*type)) {
1250 16 : return true;
1251 : }
1252 : }
1253 : return false;
1254 : }
1255 : } // anonymous namespace
1256 :
1257 228 : void FeedbackNexus::Collect(Handle<String> type, int position) {
1258 : DCHECK(IsTypeProfileKind(kind()));
1259 : DCHECK_GE(position, 0);
1260 228 : Isolate* isolate = GetIsolate();
1261 :
1262 228 : MaybeObject const feedback = GetFeedback();
1263 :
1264 : // Map source position to collection of types
1265 : Handle<SimpleNumberDictionary> types;
1266 :
1267 228 : if (feedback == MaybeObject::FromObject(
1268 : *FeedbackVector::UninitializedSentinel(isolate))) {
1269 68 : types = SimpleNumberDictionary::New(isolate, 1);
1270 : } else {
1271 : types = handle(
1272 : SimpleNumberDictionary::cast(feedback->GetHeapObjectAssumeStrong()),
1273 320 : isolate);
1274 : }
1275 :
1276 : Handle<ArrayList> position_specific_types;
1277 :
1278 456 : int entry = types->FindEntry(isolate, position);
1279 228 : if (entry == SimpleNumberDictionary::kNotFound) {
1280 164 : position_specific_types = ArrayList::New(isolate, 1);
1281 : types = SimpleNumberDictionary::Set(
1282 : isolate, types, position,
1283 328 : ArrayList::Add(isolate, position_specific_types, type));
1284 : } else {
1285 : DCHECK(types->ValueAt(entry)->IsArrayList());
1286 : position_specific_types =
1287 128 : handle(ArrayList::cast(types->ValueAt(entry)), isolate);
1288 64 : if (!InList(position_specific_types, type)) { // Add type
1289 : types = SimpleNumberDictionary::Set(
1290 : isolate, types, position,
1291 96 : ArrayList::Add(isolate, position_specific_types, type));
1292 : }
1293 : }
1294 : SetFeedback(*types);
1295 228 : }
1296 :
1297 108 : std::vector<int> FeedbackNexus::GetSourcePositions() const {
1298 : DCHECK(IsTypeProfileKind(kind()));
1299 : std::vector<int> source_positions;
1300 108 : Isolate* isolate = GetIsolate();
1301 :
1302 108 : MaybeObject const feedback = GetFeedback();
1303 :
1304 108 : if (feedback == MaybeObject::FromObject(
1305 : *FeedbackVector::UninitializedSentinel(isolate))) {
1306 : return source_positions;
1307 : }
1308 :
1309 : Handle<SimpleNumberDictionary> types(
1310 : SimpleNumberDictionary::cast(feedback->GetHeapObjectAssumeStrong()),
1311 128 : isolate);
1312 :
1313 832 : for (int index = SimpleNumberDictionary::kElementsStartIndex;
1314 : index < types->length(); index += SimpleNumberDictionary::kEntrySize) {
1315 : int key_index = index + SimpleNumberDictionary::kEntryKeyIndex;
1316 352 : Object key = types->get(key_index);
1317 352 : if (key->IsSmi()) {
1318 148 : int position = Smi::cast(key)->value();
1319 148 : source_positions.push_back(position);
1320 : }
1321 : }
1322 : return source_positions;
1323 : }
1324 :
1325 148 : std::vector<Handle<String>> FeedbackNexus::GetTypesForSourcePositions(
1326 : uint32_t position) const {
1327 : DCHECK(IsTypeProfileKind(kind()));
1328 148 : Isolate* isolate = GetIsolate();
1329 :
1330 148 : MaybeObject const feedback = GetFeedback();
1331 : std::vector<Handle<String>> types_for_position;
1332 148 : if (feedback == MaybeObject::FromObject(
1333 : *FeedbackVector::UninitializedSentinel(isolate))) {
1334 : return types_for_position;
1335 : }
1336 :
1337 : Handle<SimpleNumberDictionary> types(
1338 : SimpleNumberDictionary::cast(feedback->GetHeapObjectAssumeStrong()),
1339 296 : isolate);
1340 :
1341 148 : int entry = types->FindEntry(isolate, position);
1342 148 : if (entry == SimpleNumberDictionary::kNotFound) {
1343 : return types_for_position;
1344 : }
1345 : DCHECK(types->ValueAt(entry)->IsArrayList());
1346 : Handle<ArrayList> position_specific_types =
1347 296 : Handle<ArrayList>(ArrayList::cast(types->ValueAt(entry)), isolate);
1348 688 : for (int i = 0; i < position_specific_types->Length(); i++) {
1349 196 : Object t = position_specific_types->Get(i);
1350 196 : types_for_position.push_back(Handle<String>(String::cast(t), isolate));
1351 : }
1352 :
1353 : return types_for_position;
1354 : }
1355 :
1356 : namespace {
1357 :
1358 0 : Handle<JSObject> ConvertToJSObject(Isolate* isolate,
1359 : Handle<SimpleNumberDictionary> feedback) {
1360 : Handle<JSObject> type_profile =
1361 0 : isolate->factory()->NewJSObject(isolate->object_function());
1362 :
1363 0 : for (int index = SimpleNumberDictionary::kElementsStartIndex;
1364 : index < feedback->length();
1365 : index += SimpleNumberDictionary::kEntrySize) {
1366 : int key_index = index + SimpleNumberDictionary::kEntryKeyIndex;
1367 0 : Object key = feedback->get(key_index);
1368 0 : if (key->IsSmi()) {
1369 0 : int value_index = index + SimpleNumberDictionary::kEntryValueIndex;
1370 :
1371 : Handle<ArrayList> position_specific_types(
1372 : ArrayList::cast(feedback->get(value_index)), isolate);
1373 :
1374 0 : int position = Smi::ToInt(key);
1375 : JSObject::AddDataElement(
1376 : type_profile, position,
1377 : isolate->factory()->NewJSArrayWithElements(
1378 : ArrayList::Elements(isolate, position_specific_types)),
1379 0 : PropertyAttributes::NONE);
1380 : }
1381 : }
1382 0 : return type_profile;
1383 : }
1384 : } // namespace
1385 :
1386 0 : JSObject FeedbackNexus::GetTypeProfile() const {
1387 : DCHECK(IsTypeProfileKind(kind()));
1388 0 : Isolate* isolate = GetIsolate();
1389 :
1390 0 : MaybeObject const feedback = GetFeedback();
1391 :
1392 0 : if (feedback == MaybeObject::FromObject(
1393 : *FeedbackVector::UninitializedSentinel(isolate))) {
1394 0 : return *isolate->factory()->NewJSObject(isolate->object_function());
1395 : }
1396 :
1397 : return *ConvertToJSObject(isolate,
1398 : handle(SimpleNumberDictionary::cast(
1399 : feedback->GetHeapObjectAssumeStrong()),
1400 0 : isolate));
1401 : }
1402 :
1403 212 : void FeedbackNexus::ResetTypeProfile() {
1404 : DCHECK(IsTypeProfileKind(kind()));
1405 212 : SetFeedback(*FeedbackVector::UninitializedSentinel(GetIsolate()));
1406 212 : }
1407 :
1408 : } // namespace internal
1409 178779 : } // namespace v8
|