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 14649110 : FeedbackSlot FeedbackVectorSpec::AddSlot(FeedbackSlotKind kind) {
19 : int slot = slots();
20 14649110 : int entries_per_slot = FeedbackMetadata::GetSlotSize(kind);
21 : append(kind);
22 39575090 : for (int i = 1; i < entries_per_slot; i++) {
23 : append(FeedbackSlotKind::kInvalid);
24 : }
25 14648978 : 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 2152194 : static bool IsPropertyNameFeedback(MaybeObject feedback) {
45 2152194 : HeapObject heap_object;
46 2152194 : if (!feedback->GetHeapObjectIfStrong(&heap_object)) return false;
47 1082159 : if (heap_object->IsString()) {
48 : DCHECK(heap_object->IsInternalizedString());
49 : return true;
50 : }
51 1051422 : if (!heap_object->IsSymbol()) return false;
52 : Symbol symbol = Symbol::cast(heap_object);
53 : ReadOnlyRoots roots = symbol->GetReadOnlyRoots();
54 37645 : return symbol != roots.uninitialized_symbol() &&
55 649870 : 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 404 : FeedbackSlotKind FeedbackMetadata::GetKind(FeedbackSlot slot) const {
64 : int index = VectorICComputer::index(0, slot.ToInt());
65 : int data = get(index);
66 43978147 : 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 51964370 : int new_data = VectorICComputer::encode(data, slot.ToInt(), kind);
73 : set(index, new_data);
74 0 : }
75 :
76 : // static
77 2111028 : Handle<FeedbackMetadata> FeedbackMetadata::New(Isolate* isolate,
78 : const FeedbackVectorSpec* spec) {
79 : Factory* factory = isolate->factory();
80 :
81 2111028 : const int slot_count = spec == nullptr ? 0 : spec->slots();
82 : const int closure_feedback_cell_count =
83 2111028 : spec == nullptr ? 0 : spec->closure_feedback_cells();
84 2111028 : if (slot_count == 0 && closure_feedback_cell_count == 0) {
85 : return factory->empty_feedback_metadata();
86 : }
87 : #ifdef DEBUG
88 : for (int i = 0; i < slot_count;) {
89 : DCHECK(spec);
90 : FeedbackSlotKind kind = spec->GetKind(FeedbackSlot(i));
91 : int entry_size = FeedbackMetadata::GetSlotSize(kind);
92 : for (int j = 1; j < entry_size; j++) {
93 : FeedbackSlotKind kind = spec->GetKind(FeedbackSlot(i + j));
94 : DCHECK_EQ(FeedbackSlotKind::kInvalid, kind);
95 : }
96 : i += entry_size;
97 : }
98 : #endif
99 :
100 : Handle<FeedbackMetadata> metadata =
101 1613500 : factory->NewFeedbackMetadata(slot_count, closure_feedback_cell_count);
102 :
103 : // Initialize the slots. The raw data section has already been pre-zeroed in
104 : // NewFeedbackMetadata.
105 53577876 : for (int i = 0; i < slot_count; i++) {
106 : DCHECK(spec);
107 : FeedbackSlot slot(i);
108 : FeedbackSlotKind kind = spec->GetKind(slot);
109 : metadata->SetKind(slot, kind);
110 : }
111 :
112 1613506 : return metadata;
113 : }
114 :
115 0 : bool FeedbackMetadata::SpecDiffersFrom(
116 : const FeedbackVectorSpec* other_spec) const {
117 0 : if (other_spec->slots() != slot_count()) {
118 : return true;
119 : }
120 :
121 : int slots = slot_count();
122 0 : for (int i = 0; i < slots;) {
123 : FeedbackSlot slot(i);
124 : FeedbackSlotKind kind = GetKind(slot);
125 0 : int entry_size = FeedbackMetadata::GetSlotSize(kind);
126 :
127 0 : if (kind != other_spec->GetKind(slot)) {
128 : return true;
129 : }
130 0 : i += entry_size;
131 : }
132 : return false;
133 : }
134 :
135 0 : const char* FeedbackMetadata::Kind2String(FeedbackSlotKind kind) {
136 0 : switch (kind) {
137 : case FeedbackSlotKind::kInvalid:
138 : return "Invalid";
139 : case FeedbackSlotKind::kCall:
140 0 : return "Call";
141 : case FeedbackSlotKind::kLoadProperty:
142 0 : return "LoadProperty";
143 : case FeedbackSlotKind::kLoadGlobalInsideTypeof:
144 0 : return "LoadGlobalInsideTypeof";
145 : case FeedbackSlotKind::kLoadGlobalNotInsideTypeof:
146 0 : return "LoadGlobalNotInsideTypeof";
147 : case FeedbackSlotKind::kLoadKeyed:
148 0 : return "LoadKeyed";
149 : case FeedbackSlotKind::kHasKeyed:
150 0 : return "HasKeyed";
151 : case FeedbackSlotKind::kStoreNamedSloppy:
152 0 : return "StoreNamedSloppy";
153 : case FeedbackSlotKind::kStoreNamedStrict:
154 0 : return "StoreNamedStrict";
155 : case FeedbackSlotKind::kStoreOwnNamed:
156 0 : return "StoreOwnNamed";
157 : case FeedbackSlotKind::kStoreGlobalSloppy:
158 0 : return "StoreGlobalSloppy";
159 : case FeedbackSlotKind::kStoreGlobalStrict:
160 0 : return "StoreGlobalStrict";
161 : case FeedbackSlotKind::kStoreKeyedSloppy:
162 0 : return "StoreKeyedSloppy";
163 : case FeedbackSlotKind::kStoreKeyedStrict:
164 0 : return "StoreKeyedStrict";
165 : case FeedbackSlotKind::kStoreInArrayLiteral:
166 0 : return "StoreInArrayLiteral";
167 : case FeedbackSlotKind::kBinaryOp:
168 0 : return "BinaryOp";
169 : case FeedbackSlotKind::kCompareOp:
170 0 : return "CompareOp";
171 : case FeedbackSlotKind::kStoreDataPropertyInLiteral:
172 0 : return "StoreDataPropertyInLiteral";
173 : case FeedbackSlotKind::kLiteral:
174 0 : return "Literal";
175 : case FeedbackSlotKind::kTypeProfile:
176 0 : return "TypeProfile";
177 : case FeedbackSlotKind::kForIn:
178 0 : return "ForIn";
179 : case FeedbackSlotKind::kInstanceOf:
180 0 : return "InstanceOf";
181 : case FeedbackSlotKind::kCloneObject:
182 0 : return "CloneObject";
183 : case FeedbackSlotKind::kKindsNumber:
184 : break;
185 : }
186 0 : UNREACHABLE();
187 : }
188 :
189 452 : bool FeedbackMetadata::HasTypeProfileSlot() const {
190 : FeedbackSlot slot =
191 : FeedbackVector::ToSlot(FeedbackVectorSpec::kTypeProfileSlotIndex);
192 872 : return slot.ToInt() < slot_count() &&
193 452 : GetKind(slot) == FeedbackSlotKind::kTypeProfile;
194 : }
195 :
196 22859226 : FeedbackSlotKind FeedbackVector::GetKind(FeedbackSlot slot) const {
197 : DCHECK(!is_empty());
198 22859226 : return metadata()->GetKind(slot);
199 : }
200 :
201 440 : FeedbackSlot FeedbackVector::GetTypeProfileSlot() const {
202 : DCHECK(metadata()->HasTypeProfileSlot());
203 : FeedbackSlot slot =
204 : FeedbackVector::ToSlot(FeedbackVectorSpec::kTypeProfileSlotIndex);
205 : DCHECK_EQ(FeedbackSlotKind::kTypeProfile, GetKind(slot));
206 440 : return slot;
207 : }
208 :
209 : // static
210 3102041 : Handle<ClosureFeedbackCellArray> ClosureFeedbackCellArray::New(
211 : Isolate* isolate, Handle<SharedFunctionInfo> shared) {
212 : Factory* factory = isolate->factory();
213 :
214 : int num_feedback_cells =
215 : shared->feedback_metadata()->closure_feedback_cell_count();
216 :
217 : Handle<ClosureFeedbackCellArray> feedback_cell_array =
218 3102041 : factory->NewClosureFeedbackCellArray(num_feedback_cells);
219 :
220 11352711 : for (int i = 0; i < num_feedback_cells; i++) {
221 : Handle<FeedbackCell> cell =
222 4125333 : factory->NewNoClosuresCell(factory->undefined_value());
223 8250666 : feedback_cell_array->set(i, *cell);
224 : }
225 3102045 : return feedback_cell_array;
226 : }
227 :
228 : // static
229 3101996 : Handle<FeedbackVector> FeedbackVector::New(
230 : Isolate* isolate, Handle<SharedFunctionInfo> shared,
231 : Handle<ClosureFeedbackCellArray> closure_feedback_cell_array) {
232 : Factory* factory = isolate->factory();
233 :
234 : const int slot_count = shared->feedback_metadata()->slot_count();
235 :
236 : Handle<FeedbackVector> vector = factory->NewFeedbackVector(
237 3101996 : shared, closure_feedback_cell_array, AllocationType::kOld);
238 :
239 : DCHECK_EQ(vector->length(), slot_count);
240 :
241 : DCHECK_EQ(vector->shared_function_info(), *shared);
242 : DCHECK_EQ(
243 : vector->optimized_code_weak_or_smi(),
244 : MaybeObject::FromSmi(Smi::FromEnum(
245 : FLAG_log_function_events ? OptimizationMarker::kLogFirstExecution
246 : : OptimizationMarker::kNone)));
247 : DCHECK_EQ(vector->invocation_count(), 0);
248 : DCHECK_EQ(vector->profiler_ticks(), 0);
249 : DCHECK_EQ(vector->deopt_count(), 0);
250 :
251 : // Ensure we can skip the write barrier
252 : Handle<Object> uninitialized_sentinel = UninitializedSentinel(isolate);
253 : DCHECK_EQ(ReadOnlyRoots(isolate).uninitialized_symbol(),
254 : *uninitialized_sentinel);
255 45063877 : for (int i = 0; i < slot_count;) {
256 : FeedbackSlot slot(i);
257 : FeedbackSlotKind kind = shared->feedback_metadata()->GetKind(slot);
258 : int index = FeedbackVector::GetIndex(slot);
259 20980929 : int entry_size = FeedbackMetadata::GetSlotSize(kind);
260 :
261 : Object extra_value = *uninitialized_sentinel;
262 20980917 : switch (kind) {
263 : case FeedbackSlotKind::kLoadGlobalInsideTypeof:
264 : case FeedbackSlotKind::kLoadGlobalNotInsideTypeof:
265 : case FeedbackSlotKind::kStoreGlobalSloppy:
266 : case FeedbackSlotKind::kStoreGlobalStrict:
267 18957919 : vector->set(index, HeapObjectReference::ClearedValue(isolate),
268 6319306 : SKIP_WRITE_BARRIER);
269 6319307 : break;
270 : case FeedbackSlotKind::kForIn:
271 : case FeedbackSlotKind::kCompareOp:
272 : case FeedbackSlotKind::kBinaryOp:
273 5554134 : vector->set(index, Smi::kZero, SKIP_WRITE_BARRIER);
274 2777068 : break;
275 : case FeedbackSlotKind::kLiteral:
276 800511 : vector->set(index, Smi::kZero, SKIP_WRITE_BARRIER);
277 400258 : break;
278 : case FeedbackSlotKind::kCall:
279 11696728 : vector->set(index, *uninitialized_sentinel, SKIP_WRITE_BARRIER);
280 : extra_value = Smi::kZero;
281 5848362 : break;
282 : case FeedbackSlotKind::kCloneObject:
283 : case FeedbackSlotKind::kLoadProperty:
284 : case FeedbackSlotKind::kLoadKeyed:
285 : case FeedbackSlotKind::kHasKeyed:
286 : case FeedbackSlotKind::kStoreNamedSloppy:
287 : case FeedbackSlotKind::kStoreNamedStrict:
288 : case FeedbackSlotKind::kStoreOwnNamed:
289 : case FeedbackSlotKind::kStoreKeyedSloppy:
290 : case FeedbackSlotKind::kStoreKeyedStrict:
291 : case FeedbackSlotKind::kStoreInArrayLiteral:
292 : case FeedbackSlotKind::kStoreDataPropertyInLiteral:
293 : case FeedbackSlotKind::kTypeProfile:
294 : case FeedbackSlotKind::kInstanceOf:
295 11271943 : vector->set(index, *uninitialized_sentinel, SKIP_WRITE_BARRIER);
296 5635965 : break;
297 :
298 : case FeedbackSlotKind::kInvalid:
299 : case FeedbackSlotKind::kKindsNumber:
300 0 : UNREACHABLE();
301 : break;
302 : }
303 56537562 : for (int j = 1; j < entry_size; j++) {
304 53334909 : vector->set(index + j, extra_value, SKIP_WRITE_BARRIER);
305 : }
306 20980944 : i += entry_size;
307 : }
308 :
309 : Handle<FeedbackVector> result = Handle<FeedbackVector>::cast(vector);
310 3102004 : if (!isolate->is_best_effort_code_coverage() ||
311 : isolate->is_collecting_type_profile()) {
312 1200 : AddToVectorsForProfilingTools(isolate, result);
313 : }
314 3102004 : return result;
315 : }
316 :
317 : // static
318 1200 : void FeedbackVector::AddToVectorsForProfilingTools(
319 : Isolate* isolate, Handle<FeedbackVector> vector) {
320 : DCHECK(!isolate->is_best_effort_code_coverage() ||
321 : isolate->is_collecting_type_profile());
322 1200 : if (!vector->shared_function_info()->IsSubjectToDebugging()) return;
323 : Handle<ArrayList> list = Handle<ArrayList>::cast(
324 : isolate->factory()->feedback_vectors_for_profiling_tools());
325 1200 : list = ArrayList::Add(isolate, list, vector);
326 1200 : isolate->SetFeedbackVectorsForProfilingTools(*list);
327 : }
328 :
329 : // static
330 23076 : void FeedbackVector::SetOptimizedCode(Handle<FeedbackVector> vector,
331 : Handle<Code> code) {
332 : DCHECK_EQ(code->kind(), Code::OPTIMIZED_FUNCTION);
333 46152 : vector->set_optimized_code_weak_or_smi(HeapObjectReference::Weak(*code));
334 23076 : }
335 :
336 0 : void FeedbackVector::ClearOptimizedCode() {
337 : DCHECK(has_optimized_code());
338 : SetOptimizationMarker(OptimizationMarker::kNone);
339 0 : }
340 :
341 769744 : void FeedbackVector::ClearOptimizationMarker() {
342 : DCHECK(!has_optimized_code());
343 : SetOptimizationMarker(OptimizationMarker::kNone);
344 769743 : }
345 :
346 499545 : void FeedbackVector::SetOptimizationMarker(OptimizationMarker marker) {
347 1271550 : set_optimized_code_weak_or_smi(MaybeObject::FromSmi(Smi::FromEnum(marker)));
348 499545 : }
349 :
350 4404804 : void FeedbackVector::EvictOptimizedCodeMarkedForDeoptimization(
351 : SharedFunctionInfo shared, const char* reason) {
352 : MaybeObject slot = optimized_code_weak_or_smi();
353 4404804 : if (slot->IsSmi()) {
354 3957619 : return;
355 : }
356 :
357 447432 : if (slot->IsCleared()) {
358 : ClearOptimizationMarker();
359 : return;
360 : }
361 :
362 447185 : Code code = Code::cast(slot->GetHeapObject());
363 447185 : if (code->marked_for_deoptimization()) {
364 2014 : if (FLAG_trace_deopt) {
365 : PrintF("[evicting optimizing code marked for deoptimization (%s) for ",
366 0 : reason);
367 0 : shared->ShortPrint();
368 0 : PrintF("]\n");
369 : }
370 2014 : if (!code->deopt_already_counted()) {
371 : increment_deopt_count();
372 1217 : code->set_deopt_already_counted(true);
373 : }
374 : ClearOptimizedCode();
375 : }
376 : }
377 :
378 52596 : bool FeedbackVector::ClearSlots(Isolate* isolate) {
379 : MaybeObject uninitialized_sentinel = MaybeObject::FromObject(
380 : FeedbackVector::RawUninitializedSentinel(isolate));
381 :
382 : bool feedback_updated = false;
383 : FeedbackMetadataIterator iter(metadata());
384 214504 : while (iter.HasNext()) {
385 80954 : FeedbackSlot slot = iter.Next();
386 :
387 : MaybeObject obj = Get(slot);
388 80954 : if (obj != uninitialized_sentinel) {
389 55810 : FeedbackNexus nexus(*this, slot);
390 55810 : feedback_updated |= nexus.Clear();
391 : }
392 : }
393 52596 : return feedback_updated;
394 : }
395 :
396 415730 : void FeedbackVector::AssertNoLegacyTypes(MaybeObject object) {
397 : #ifdef DEBUG
398 : HeapObject heap_object;
399 : if (object->GetHeapObject(&heap_object)) {
400 : // Instead of FixedArray, the Feedback and the Extra should contain
401 : // WeakFixedArrays. The only allowed FixedArray subtype is HashTable.
402 : DCHECK_IMPLIES(heap_object->IsFixedArray(), heap_object->IsHashTable());
403 : }
404 : #endif
405 415730 : }
406 :
407 224401 : Handle<WeakFixedArray> FeedbackNexus::EnsureArrayOfSize(int length) {
408 : Isolate* isolate = GetIsolate();
409 : HeapObject heap_object;
410 535730 : if (GetFeedback()->GetHeapObjectIfStrong(&heap_object) &&
411 311132 : heap_object->IsWeakFixedArray() &&
412 : WeakFixedArray::cast(heap_object)->length() == length) {
413 : return handle(WeakFixedArray::cast(heap_object), isolate);
414 : }
415 217866 : Handle<WeakFixedArray> array = isolate->factory()->NewWeakFixedArray(length);
416 : SetFeedback(*array);
417 217870 : return array;
418 : }
419 :
420 17957 : Handle<WeakFixedArray> FeedbackNexus::EnsureExtraArrayOfSize(int length) {
421 : Isolate* isolate = GetIsolate();
422 : HeapObject heap_object;
423 40237 : if (GetFeedbackExtra()->GetHeapObjectIfStrong(&heap_object) &&
424 22210 : heap_object->IsWeakFixedArray() &&
425 : WeakFixedArray::cast(heap_object)->length() == length) {
426 : return handle(WeakFixedArray::cast(heap_object), isolate);
427 : }
428 17758 : Handle<WeakFixedArray> array = isolate->factory()->NewWeakFixedArray(length);
429 17758 : SetFeedbackExtra(*array);
430 17758 : return array;
431 : }
432 :
433 45756 : void FeedbackNexus::ConfigureUninitialized() {
434 : Isolate* isolate = GetIsolate();
435 45756 : switch (kind()) {
436 : case FeedbackSlotKind::kStoreGlobalSloppy:
437 : case FeedbackSlotKind::kStoreGlobalStrict:
438 : case FeedbackSlotKind::kLoadGlobalNotInsideTypeof:
439 : case FeedbackSlotKind::kLoadGlobalInsideTypeof: {
440 16132 : SetFeedback(HeapObjectReference::ClearedValue(isolate),
441 8066 : SKIP_WRITE_BARRIER);
442 16132 : SetFeedbackExtra(*FeedbackVector::UninitializedSentinel(isolate),
443 8066 : SKIP_WRITE_BARRIER);
444 8066 : break;
445 : }
446 : case FeedbackSlotKind::kCloneObject:
447 : case FeedbackSlotKind::kCall: {
448 : SetFeedback(*FeedbackVector::UninitializedSentinel(isolate),
449 : SKIP_WRITE_BARRIER);
450 6434 : SetFeedbackExtra(Smi::kZero, SKIP_WRITE_BARRIER);
451 6434 : break;
452 : }
453 : case FeedbackSlotKind::kInstanceOf: {
454 : SetFeedback(*FeedbackVector::UninitializedSentinel(isolate),
455 : SKIP_WRITE_BARRIER);
456 0 : break;
457 : }
458 : case FeedbackSlotKind::kStoreNamedSloppy:
459 : case FeedbackSlotKind::kStoreNamedStrict:
460 : case FeedbackSlotKind::kStoreKeyedSloppy:
461 : case FeedbackSlotKind::kStoreKeyedStrict:
462 : case FeedbackSlotKind::kStoreInArrayLiteral:
463 : case FeedbackSlotKind::kStoreOwnNamed:
464 : case FeedbackSlotKind::kLoadProperty:
465 : case FeedbackSlotKind::kLoadKeyed:
466 : case FeedbackSlotKind::kHasKeyed:
467 : case FeedbackSlotKind::kStoreDataPropertyInLiteral: {
468 : SetFeedback(*FeedbackVector::UninitializedSentinel(isolate),
469 : SKIP_WRITE_BARRIER);
470 62512 : SetFeedbackExtra(*FeedbackVector::UninitializedSentinel(isolate),
471 31256 : SKIP_WRITE_BARRIER);
472 31256 : break;
473 : }
474 : default:
475 0 : UNREACHABLE();
476 : }
477 45756 : }
478 :
479 55810 : bool FeedbackNexus::Clear() {
480 : bool feedback_updated = false;
481 :
482 : switch (kind()) {
483 : case FeedbackSlotKind::kTypeProfile:
484 : // We don't clear these kinds ever.
485 : break;
486 :
487 : case FeedbackSlotKind::kCompareOp:
488 : case FeedbackSlotKind::kForIn:
489 : case FeedbackSlotKind::kBinaryOp:
490 : // We don't clear these, either.
491 : break;
492 :
493 : case FeedbackSlotKind::kLiteral:
494 : SetFeedback(Smi::kZero, SKIP_WRITE_BARRIER);
495 : feedback_updated = true;
496 13 : break;
497 :
498 : case FeedbackSlotKind::kStoreNamedSloppy:
499 : case FeedbackSlotKind::kStoreNamedStrict:
500 : case FeedbackSlotKind::kStoreKeyedSloppy:
501 : case FeedbackSlotKind::kStoreKeyedStrict:
502 : case FeedbackSlotKind::kStoreInArrayLiteral:
503 : case FeedbackSlotKind::kStoreOwnNamed:
504 : case FeedbackSlotKind::kLoadProperty:
505 : case FeedbackSlotKind::kLoadKeyed:
506 : case FeedbackSlotKind::kHasKeyed:
507 : case FeedbackSlotKind::kStoreGlobalSloppy:
508 : case FeedbackSlotKind::kStoreGlobalStrict:
509 : case FeedbackSlotKind::kLoadGlobalNotInsideTypeof:
510 : case FeedbackSlotKind::kLoadGlobalInsideTypeof:
511 : case FeedbackSlotKind::kCall:
512 : case FeedbackSlotKind::kInstanceOf:
513 : case FeedbackSlotKind::kStoreDataPropertyInLiteral:
514 : case FeedbackSlotKind::kCloneObject:
515 47770 : if (!IsCleared()) {
516 45756 : ConfigureUninitialized();
517 : feedback_updated = true;
518 : }
519 : break;
520 :
521 : case FeedbackSlotKind::kInvalid:
522 : case FeedbackSlotKind::kKindsNumber:
523 0 : UNREACHABLE();
524 : break;
525 : }
526 55810 : return feedback_updated;
527 : }
528 :
529 676238 : void FeedbackNexus::ConfigurePremonomorphic(Handle<Map> receiver_map) {
530 : SetFeedback(*FeedbackVector::PremonomorphicSentinel(GetIsolate()),
531 : SKIP_WRITE_BARRIER);
532 676241 : SetFeedbackExtra(HeapObjectReference::Weak(*receiver_map));
533 676244 : }
534 :
535 126 : bool FeedbackNexus::ConfigureMegamorphic() {
536 : DisallowHeapAllocation no_gc;
537 : Isolate* isolate = GetIsolate();
538 : MaybeObject sentinel =
539 : MaybeObject::FromObject(*FeedbackVector::MegamorphicSentinel(isolate));
540 252 : if (GetFeedback() != sentinel) {
541 126 : SetFeedback(sentinel, SKIP_WRITE_BARRIER);
542 126 : SetFeedbackExtra(HeapObjectReference::ClearedValue(isolate));
543 126 : return true;
544 : }
545 :
546 : return false;
547 : }
548 :
549 47423 : bool FeedbackNexus::ConfigureMegamorphic(IcCheckType property_type) {
550 : DisallowHeapAllocation no_gc;
551 : Isolate* isolate = GetIsolate();
552 : bool changed = false;
553 : MaybeObject sentinel =
554 : MaybeObject::FromObject(*FeedbackVector::MegamorphicSentinel(isolate));
555 94846 : if (GetFeedback() != sentinel) {
556 42994 : SetFeedback(sentinel, SKIP_WRITE_BARRIER);
557 : changed = true;
558 : }
559 :
560 47424 : Smi extra = Smi::FromInt(static_cast<int>(property_type));
561 51854 : if (changed || GetFeedbackExtra() != MaybeObject::FromSmi(extra)) {
562 42994 : SetFeedbackExtra(extra, SKIP_WRITE_BARRIER);
563 : changed = true;
564 : }
565 47424 : return changed;
566 : }
567 :
568 103743 : Map FeedbackNexus::GetFirstMap() const {
569 : MapHandles maps;
570 103743 : ExtractMaps(&maps);
571 103743 : if (maps.size() > 0) return *maps.at(0);
572 4 : return Map();
573 : }
574 :
575 12707504 : InlineCacheState FeedbackNexus::ic_state() const {
576 : Isolate* isolate = GetIsolate();
577 12707504 : MaybeObject feedback = GetFeedback();
578 :
579 12707521 : switch (kind()) {
580 : case FeedbackSlotKind::kLiteral:
581 53061 : if (feedback->IsSmi()) return UNINITIALIZED;
582 7833 : return MONOMORPHIC;
583 :
584 : case FeedbackSlotKind::kStoreGlobalSloppy:
585 : case FeedbackSlotKind::kStoreGlobalStrict:
586 : case FeedbackSlotKind::kLoadGlobalNotInsideTypeof:
587 : case FeedbackSlotKind::kLoadGlobalInsideTypeof: {
588 5921224 : if (feedback->IsSmi()) return MONOMORPHIC;
589 :
590 5921017 : if (feedback == MaybeObject::FromObject(
591 : *FeedbackVector::PremonomorphicSentinel(isolate))) {
592 : DCHECK(kind() == FeedbackSlotKind::kStoreGlobalSloppy ||
593 : kind() == FeedbackSlotKind::kStoreGlobalStrict);
594 : return PREMONOMORPHIC;
595 : }
596 :
597 : DCHECK(feedback->IsWeakOrCleared());
598 5920986 : MaybeObject extra = GetFeedbackExtra();
599 11421304 : if (!feedback->IsCleared() ||
600 : extra != MaybeObject::FromObject(
601 : *FeedbackVector::UninitializedSentinel(isolate))) {
602 : return MONOMORPHIC;
603 : }
604 5495569 : return UNINITIALIZED;
605 : }
606 :
607 : case FeedbackSlotKind::kStoreNamedSloppy:
608 : case FeedbackSlotKind::kStoreNamedStrict:
609 : case FeedbackSlotKind::kStoreKeyedSloppy:
610 : case FeedbackSlotKind::kStoreKeyedStrict:
611 : case FeedbackSlotKind::kStoreInArrayLiteral:
612 : case FeedbackSlotKind::kStoreOwnNamed:
613 : case FeedbackSlotKind::kLoadProperty:
614 : case FeedbackSlotKind::kLoadKeyed:
615 : case FeedbackSlotKind::kHasKeyed: {
616 5035826 : if (feedback == MaybeObject::FromObject(
617 : *FeedbackVector::UninitializedSentinel(isolate))) {
618 : return UNINITIALIZED;
619 : }
620 3067476 : if (feedback == MaybeObject::FromObject(
621 : *FeedbackVector::MegamorphicSentinel(isolate))) {
622 : return MEGAMORPHIC;
623 : }
624 2408251 : if (feedback == MaybeObject::FromObject(
625 : *FeedbackVector::PremonomorphicSentinel(isolate))) {
626 : return PREMONOMORPHIC;
627 : }
628 930309 : if (feedback->IsWeakOrCleared()) {
629 : // Don't check if the map is cleared.
630 : return MONOMORPHIC;
631 : }
632 : HeapObject heap_object;
633 218727 : if (feedback->GetHeapObjectIfStrong(&heap_object)) {
634 218728 : if (heap_object->IsWeakFixedArray()) {
635 : // Determine state purely by our structure, don't check if the maps
636 : // are cleared.
637 : return POLYMORPHIC;
638 : }
639 16821 : if (heap_object->IsName()) {
640 : DCHECK(IsKeyedLoadICKind(kind()) || IsKeyedStoreICKind(kind()) ||
641 : IsKeyedHasICKind(kind()));
642 33642 : Object extra = GetFeedbackExtra()->GetHeapObjectAssumeStrong();
643 : WeakFixedArray extra_array = WeakFixedArray::cast(extra);
644 16821 : return extra_array->length() > 2 ? POLYMORPHIC : MONOMORPHIC;
645 : }
646 : }
647 0 : UNREACHABLE();
648 : }
649 : case FeedbackSlotKind::kCall: {
650 : HeapObject heap_object;
651 1039828 : if (feedback == MaybeObject::FromObject(
652 : *FeedbackVector::MegamorphicSentinel(isolate))) {
653 : return GENERIC;
654 2718355 : } else if (feedback->IsWeakOrCleared() ||
655 679149 : (feedback->GetHeapObjectIfStrong(&heap_object) &&
656 : heap_object->IsAllocationSite())) {
657 : return MONOMORPHIC;
658 : }
659 :
660 677401 : CHECK_EQ(feedback, MaybeObject::FromObject(
661 : *FeedbackVector::UninitializedSentinel(isolate)));
662 : return UNINITIALIZED;
663 : }
664 : case FeedbackSlotKind::kBinaryOp: {
665 : BinaryOperationHint hint = GetBinaryOperationFeedback();
666 271009 : if (hint == BinaryOperationHint::kNone) {
667 : return UNINITIALIZED;
668 255833 : } else if (hint == BinaryOperationHint::kAny) {
669 : return GENERIC;
670 : }
671 :
672 252575 : return MONOMORPHIC;
673 : }
674 : case FeedbackSlotKind::kCompareOp: {
675 151103 : CompareOperationHint hint = GetCompareOperationFeedback();
676 151103 : if (hint == CompareOperationHint::kNone) {
677 : return UNINITIALIZED;
678 137235 : } else if (hint == CompareOperationHint::kAny) {
679 : return GENERIC;
680 : }
681 :
682 101335 : return MONOMORPHIC;
683 : }
684 : case FeedbackSlotKind::kForIn: {
685 : ForInHint hint = GetForInFeedback();
686 1378 : if (hint == ForInHint::kNone) {
687 : return UNINITIALIZED;
688 1333 : } else if (hint == ForInHint::kAny) {
689 : return GENERIC;
690 : }
691 499 : return MONOMORPHIC;
692 : }
693 : case FeedbackSlotKind::kInstanceOf: {
694 4878 : if (feedback == MaybeObject::FromObject(
695 : *FeedbackVector::UninitializedSentinel(isolate))) {
696 : return UNINITIALIZED;
697 1924 : } else if (feedback ==
698 : MaybeObject::FromObject(
699 : *FeedbackVector::MegamorphicSentinel(isolate))) {
700 : return MEGAMORPHIC;
701 : }
702 1700 : return MONOMORPHIC;
703 : }
704 : case FeedbackSlotKind::kStoreDataPropertyInLiteral: {
705 228247 : if (feedback == MaybeObject::FromObject(
706 : *FeedbackVector::UninitializedSentinel(isolate))) {
707 : return UNINITIALIZED;
708 223930 : } else if (feedback->IsWeakOrCleared()) {
709 : // Don't check if the map is cleared.
710 : return MONOMORPHIC;
711 : }
712 :
713 16341 : return MEGAMORPHIC;
714 : }
715 : case FeedbackSlotKind::kTypeProfile: {
716 0 : if (feedback == MaybeObject::FromObject(
717 : *FeedbackVector::UninitializedSentinel(isolate))) {
718 : return UNINITIALIZED;
719 : }
720 0 : return MONOMORPHIC;
721 : }
722 :
723 : case FeedbackSlotKind::kCloneObject: {
724 978 : if (feedback == MaybeObject::FromObject(
725 : *FeedbackVector::UninitializedSentinel(isolate))) {
726 : return UNINITIALIZED;
727 : }
728 280 : if (feedback == MaybeObject::FromObject(
729 : *FeedbackVector::MegamorphicSentinel(isolate))) {
730 : return MEGAMORPHIC;
731 : }
732 280 : if (feedback->IsWeakOrCleared()) {
733 : return MONOMORPHIC;
734 : }
735 :
736 : DCHECK(feedback->GetHeapObjectAssumeStrong()->IsWeakFixedArray());
737 180 : return POLYMORPHIC;
738 : }
739 :
740 : case FeedbackSlotKind::kInvalid:
741 : case FeedbackSlotKind::kKindsNumber:
742 0 : UNREACHABLE();
743 : break;
744 : }
745 : return UNINITIALIZED;
746 : }
747 :
748 5734954 : void FeedbackNexus::ConfigurePropertyCellMode(Handle<PropertyCell> cell) {
749 : DCHECK(IsGlobalICKind(kind()));
750 : Isolate* isolate = GetIsolate();
751 5734954 : SetFeedback(HeapObjectReference::Weak(*cell));
752 11469914 : SetFeedbackExtra(*FeedbackVector::UninitializedSentinel(isolate),
753 5734957 : SKIP_WRITE_BARRIER);
754 5734957 : }
755 :
756 61358 : bool FeedbackNexus::ConfigureLexicalVarMode(int script_context_index,
757 : int context_slot_index,
758 : bool immutable) {
759 : DCHECK(IsGlobalICKind(kind()));
760 : DCHECK_LE(0, script_context_index);
761 : DCHECK_LE(0, context_slot_index);
762 184074 : if (!ContextIndexBits::is_valid(script_context_index) ||
763 122717 : !SlotIndexBits::is_valid(context_slot_index) ||
764 : !ImmutabilityBit::is_valid(immutable)) {
765 : return false;
766 : }
767 61359 : int config = ContextIndexBits::encode(script_context_index) |
768 122718 : SlotIndexBits::encode(context_slot_index) |
769 61359 : ImmutabilityBit::encode(immutable);
770 :
771 : SetFeedback(Smi::From31BitPattern(config));
772 : Isolate* isolate = GetIsolate();
773 122718 : SetFeedbackExtra(*FeedbackVector::UninitializedSentinel(isolate),
774 61359 : SKIP_WRITE_BARRIER);
775 61359 : return true;
776 : }
777 :
778 44704 : void FeedbackNexus::ConfigureHandlerMode(const MaybeObjectHandle& handler) {
779 : DCHECK(IsGlobalICKind(kind()));
780 : DCHECK(IC::IsHandler(*handler));
781 44704 : SetFeedback(HeapObjectReference::ClearedValue(GetIsolate()));
782 44704 : SetFeedbackExtra(*handler);
783 44704 : }
784 :
785 450 : void FeedbackNexus::ConfigureCloneObject(Handle<Map> source_map,
786 : Handle<Map> result_map) {
787 : Isolate* isolate = GetIsolate();
788 450 : MaybeObject maybe_feedback = GetFeedback();
789 : Handle<HeapObject> feedback(maybe_feedback->IsStrongOrWeak()
790 : ? maybe_feedback->GetHeapObject()
791 : : HeapObject(),
792 450 : isolate);
793 450 : switch (ic_state()) {
794 : case UNINITIALIZED:
795 : // Cache the first map seen which meets the fast case requirements.
796 324 : SetFeedback(HeapObjectReference::Weak(*source_map));
797 324 : SetFeedbackExtra(*result_map);
798 324 : break;
799 : case MONOMORPHIC:
800 108 : if (maybe_feedback->IsCleared() || feedback.is_identical_to(source_map) ||
801 : Map::cast(*feedback)->is_deprecated()) {
802 : // Remain in MONOMORPHIC state if previous feedback has been collected.
803 0 : SetFeedback(HeapObjectReference::Weak(*source_map));
804 0 : SetFeedbackExtra(*result_map);
805 : } else {
806 : // Transition to POLYMORPHIC.
807 : Handle<WeakFixedArray> array =
808 36 : EnsureArrayOfSize(2 * kCloneObjectPolymorphicEntrySize);
809 36 : array->Set(0, maybe_feedback);
810 72 : array->Set(1, GetFeedbackExtra());
811 72 : array->Set(2, HeapObjectReference::Weak(*source_map));
812 36 : array->Set(3, MaybeObject::FromObject(*result_map));
813 36 : SetFeedbackExtra(HeapObjectReference::ClearedValue(isolate));
814 : }
815 : break;
816 : case POLYMORPHIC: {
817 : const int kMaxElements =
818 90 : FLAG_max_polymorphic_map_count * kCloneObjectPolymorphicEntrySize;
819 : Handle<WeakFixedArray> array = Handle<WeakFixedArray>::cast(feedback);
820 : int i = 0;
821 333 : for (; i < array->length(); i += kCloneObjectPolymorphicEntrySize) {
822 : MaybeObject feedback = array->Get(i);
823 252 : if (feedback->IsCleared()) break;
824 : Handle<Map> cached_map(Map::cast(feedback->GetHeapObject()), isolate);
825 486 : if (cached_map.is_identical_to(source_map) ||
826 : cached_map->is_deprecated())
827 : break;
828 : }
829 :
830 90 : if (i >= array->length()) {
831 81 : if (i == kMaxElements) {
832 : // Transition to MEGAMORPHIC.
833 : MaybeObject sentinel = MaybeObject::FromObject(
834 27 : *FeedbackVector::MegamorphicSentinel(isolate));
835 27 : SetFeedback(sentinel, SKIP_WRITE_BARRIER);
836 27 : SetFeedbackExtra(HeapObjectReference::ClearedValue(isolate));
837 : break;
838 : }
839 :
840 : // Grow polymorphic feedback array.
841 : Handle<WeakFixedArray> new_array = EnsureArrayOfSize(
842 54 : array->length() + kCloneObjectPolymorphicEntrySize);
843 594 : for (int j = 0; j < array->length(); ++j) {
844 270 : new_array->Set(j, array->Get(j));
845 : }
846 54 : array = new_array;
847 : }
848 :
849 126 : array->Set(i, HeapObjectReference::Weak(*source_map));
850 126 : array->Set(i + 1, MaybeObject::FromObject(*result_map));
851 63 : break;
852 : }
853 :
854 : default:
855 0 : UNREACHABLE();
856 : }
857 450 : }
858 :
859 509403 : int FeedbackNexus::GetCallCount() {
860 : DCHECK(IsCallICKind(kind()));
861 :
862 1018806 : Object call_count = GetFeedbackExtra()->cast<Object>();
863 509403 : CHECK(call_count->IsSmi());
864 509403 : uint32_t value = static_cast<uint32_t>(Smi::ToInt(call_count));
865 509403 : return CallCountField::decode(value);
866 : }
867 :
868 1963 : void FeedbackNexus::SetSpeculationMode(SpeculationMode mode) {
869 : DCHECK(IsCallICKind(kind()));
870 :
871 3926 : Object call_count = GetFeedbackExtra()->cast<Object>();
872 1963 : CHECK(call_count->IsSmi());
873 1963 : uint32_t count = static_cast<uint32_t>(Smi::ToInt(call_count));
874 : uint32_t value = CallCountField::encode(CallCountField::decode(count));
875 1963 : int result = static_cast<int>(value | SpeculationModeField::encode(mode));
876 1963 : SetFeedbackExtra(Smi::FromInt(result), SKIP_WRITE_BARRIER);
877 1963 : }
878 :
879 466526 : SpeculationMode FeedbackNexus::GetSpeculationMode() {
880 : DCHECK(IsCallICKind(kind()));
881 :
882 933052 : Object call_count = GetFeedbackExtra()->cast<Object>();
883 466526 : CHECK(call_count->IsSmi());
884 466526 : uint32_t value = static_cast<uint32_t>(Smi::ToInt(call_count));
885 466526 : return SpeculationModeField::decode(value);
886 : }
887 :
888 509375 : float FeedbackNexus::ComputeCallFrequency() {
889 : DCHECK(IsCallICKind(kind()));
890 :
891 509375 : double const invocation_count = vector()->invocation_count();
892 509375 : double const call_count = GetCallCount();
893 509375 : if (invocation_count == 0) {
894 : // Prevent division by 0.
895 : return 0.0f;
896 : }
897 191900 : return static_cast<float>(call_count / invocation_count);
898 : }
899 :
900 1963094 : void FeedbackNexus::ConfigureMonomorphic(Handle<Name> name,
901 : Handle<Map> receiver_map,
902 : const MaybeObjectHandle& handler) {
903 : DCHECK(handler.is_null() || IC::IsHandler(*handler));
904 1963094 : if (kind() == FeedbackSlotKind::kStoreDataPropertyInLiteral) {
905 3352 : SetFeedback(HeapObjectReference::Weak(*receiver_map));
906 3352 : SetFeedbackExtra(*name);
907 : } else {
908 1959742 : if (name.is_null()) {
909 1945843 : SetFeedback(HeapObjectReference::Weak(*receiver_map));
910 1945869 : SetFeedbackExtra(*handler);
911 : } else {
912 13899 : Handle<WeakFixedArray> array = EnsureExtraArrayOfSize(2);
913 : SetFeedback(*name);
914 27798 : array->Set(0, HeapObjectReference::Weak(*receiver_map));
915 27798 : array->Set(1, *handler);
916 : }
917 : }
918 1963118 : }
919 :
920 228370 : void FeedbackNexus::ConfigurePolymorphic(Handle<Name> name,
921 : MapHandles const& maps,
922 : MaybeObjectHandles* handlers) {
923 : DCHECK_EQ(handlers->size(), maps.size());
924 228370 : int receiver_count = static_cast<int>(maps.size());
925 : DCHECK_GT(receiver_count, 1);
926 : Handle<WeakFixedArray> array;
927 228370 : if (name.is_null()) {
928 224312 : array = EnsureArrayOfSize(receiver_count * 2);
929 448628 : SetFeedbackExtra(*FeedbackVector::UninitializedSentinel(GetIsolate()),
930 224314 : SKIP_WRITE_BARRIER);
931 : } else {
932 4058 : array = EnsureExtraArrayOfSize(receiver_count * 2);
933 : SetFeedback(*name);
934 : }
935 :
936 1382512 : for (int current = 0; current < receiver_count; ++current) {
937 1154140 : Handle<Map> map = maps[current];
938 1154140 : array->Set(current * 2, HeapObjectReference::Weak(*map));
939 : DCHECK(IC::IsHandler(*handlers->at(current)));
940 1154140 : array->Set(current * 2 + 1, *handlers->at(current));
941 : }
942 228372 : }
943 :
944 1075913 : int FeedbackNexus::ExtractMaps(MapHandles* maps) const {
945 : DCHECK(IsLoadICKind(kind()) || IsStoreICKind(kind()) ||
946 : IsKeyedLoadICKind(kind()) || IsKeyedStoreICKind(kind()) ||
947 : IsStoreOwnICKind(kind()) || IsStoreDataPropertyInLiteralKind(kind()) ||
948 : IsStoreInArrayLiteralICKind(kind()) || IsKeyedHasICKind(kind()));
949 :
950 : Isolate* isolate = GetIsolate();
951 1075913 : MaybeObject feedback = GetFeedback();
952 1075919 : bool is_named_feedback = IsPropertyNameFeedback(feedback);
953 : HeapObject heap_object;
954 1682683 : if ((feedback->GetHeapObjectIfStrong(&heap_object) &&
955 1996814 : heap_object->IsWeakFixedArray()) ||
956 : is_named_feedback) {
957 : int found = 0;
958 : WeakFixedArray array;
959 161032 : if (is_named_feedback) {
960 : array =
961 12032 : WeakFixedArray::cast(GetFeedbackExtra()->GetHeapObjectAssumeStrong());
962 : } else {
963 : array = WeakFixedArray::cast(heap_object);
964 : }
965 : const int increment = 2;
966 : HeapObject heap_object;
967 557165 : for (int i = 0; i < array->length(); i += increment) {
968 : DCHECK(array->Get(i)->IsWeakOrCleared());
969 396133 : if (array->Get(i)->GetHeapObjectIfWeak(&heap_object)) {
970 : Map map = Map::cast(heap_object);
971 654974 : maps->push_back(handle(map, isolate));
972 327487 : found++;
973 : }
974 : }
975 : return found;
976 914882 : } else if (feedback->GetHeapObjectIfWeak(&heap_object)) {
977 : Map map = Map::cast(heap_object);
978 724509 : maps->push_back(handle(map, isolate));
979 : return 1;
980 998364 : } else if (feedback->GetHeapObjectIfStrong(&heap_object) &&
981 : heap_object ==
982 : heap_object->GetReadOnlyRoots().premonomorphic_symbol()) {
983 16298 : if (GetFeedbackExtra()->GetHeapObjectIfWeak(&heap_object)) {
984 : Map map = Map::cast(heap_object);
985 14880 : maps->push_back(handle(map, isolate));
986 : return 1;
987 : }
988 : }
989 :
990 : return 0;
991 : }
992 :
993 376995 : MaybeObjectHandle FeedbackNexus::FindHandlerForMap(Handle<Map> map) const {
994 : DCHECK(IsLoadICKind(kind()) || IsStoreICKind(kind()) ||
995 : IsKeyedLoadICKind(kind()) || IsKeyedStoreICKind(kind()) ||
996 : IsStoreOwnICKind(kind()) || IsStoreDataPropertyInLiteralKind(kind()) ||
997 : IsKeyedHasICKind(kind()));
998 :
999 376995 : MaybeObject feedback = GetFeedback();
1000 : Isolate* isolate = GetIsolate();
1001 376998 : bool is_named_feedback = IsPropertyNameFeedback(feedback);
1002 : HeapObject heap_object;
1003 501733 : if ((feedback->GetHeapObjectIfStrong(&heap_object) &&
1004 631436 : heap_object->IsWeakFixedArray()) ||
1005 : is_named_feedback) {
1006 : WeakFixedArray array;
1007 124737 : if (is_named_feedback) {
1008 : array =
1009 4364 : WeakFixedArray::cast(GetFeedbackExtra()->GetHeapObjectAssumeStrong());
1010 : } else {
1011 : array = WeakFixedArray::cast(heap_object);
1012 : }
1013 : const int increment = 2;
1014 : HeapObject heap_object;
1015 433024 : for (int i = 0; i < array->length(); i += increment) {
1016 : DCHECK(array->Get(i)->IsWeakOrCleared());
1017 308849 : if (array->Get(i)->GetHeapObjectIfWeak(&heap_object)) {
1018 : Map array_map = Map::cast(heap_object);
1019 240841 : if (array_map == *map && !array->Get(i + increment - 1)->IsCleared()) {
1020 : MaybeObject handler = array->Get(i + increment - 1);
1021 : DCHECK(IC::IsHandler(handler));
1022 : return handle(handler, isolate);
1023 : }
1024 : }
1025 : }
1026 252258 : } else if (feedback->GetHeapObjectIfWeak(&heap_object)) {
1027 : Map cell_map = Map::cast(heap_object);
1028 160023 : if (cell_map == *map && !GetFeedbackExtra()->IsCleared()) {
1029 13130 : MaybeObject handler = GetFeedbackExtra();
1030 : DCHECK(IC::IsHandler(handler));
1031 : return handle(handler, isolate);
1032 : }
1033 : }
1034 :
1035 363303 : return MaybeObjectHandle();
1036 : }
1037 :
1038 511831 : bool FeedbackNexus::FindHandlers(MaybeObjectHandles* code_list,
1039 : int length) const {
1040 : DCHECK(IsLoadICKind(kind()) || IsStoreICKind(kind()) ||
1041 : IsKeyedLoadICKind(kind()) || IsKeyedStoreICKind(kind()) ||
1042 : IsStoreOwnICKind(kind()) || IsStoreDataPropertyInLiteralKind(kind()) ||
1043 : IsStoreInArrayLiteralICKind(kind()) || IsKeyedHasICKind(kind()));
1044 :
1045 511831 : MaybeObject feedback = GetFeedback();
1046 : Isolate* isolate = GetIsolate();
1047 : int count = 0;
1048 511831 : bool is_named_feedback = IsPropertyNameFeedback(feedback);
1049 : HeapObject heap_object;
1050 740993 : if ((feedback->GetHeapObjectIfStrong(&heap_object) &&
1051 882510 : heap_object->IsWeakFixedArray()) ||
1052 : is_named_feedback) {
1053 : WeakFixedArray array;
1054 146252 : if (is_named_feedback) {
1055 : array =
1056 10202 : WeakFixedArray::cast(GetFeedbackExtra()->GetHeapObjectAssumeStrong());
1057 : } else {
1058 : array = WeakFixedArray::cast(heap_object);
1059 : }
1060 : const int increment = 2;
1061 : HeapObject heap_object;
1062 527389 : for (int i = 0; i < array->length(); i += increment) {
1063 : // Be sure to skip handlers whose maps have been cleared.
1064 : DCHECK(array->Get(i)->IsWeakOrCleared());
1065 693675 : if (array->Get(i)->GetHeapObjectIfWeak(&heap_object) &&
1066 : !array->Get(i + increment - 1)->IsCleared()) {
1067 : MaybeObject handler = array->Get(i + increment - 1);
1068 : DCHECK(IC::IsHandler(handler));
1069 625053 : code_list->push_back(handle(handler, isolate));
1070 312527 : count++;
1071 : }
1072 : }
1073 365579 : } else if (feedback->GetHeapObjectIfWeak(&heap_object)) {
1074 176838 : MaybeObject extra = GetFeedbackExtra();
1075 176839 : if (!extra->IsCleared()) {
1076 : DCHECK(IC::IsHandler(extra));
1077 351706 : code_list->push_back(handle(extra, isolate));
1078 : count++;
1079 : }
1080 : }
1081 511834 : return count == length;
1082 : }
1083 :
1084 49909 : Name FeedbackNexus::GetName() const {
1085 49909 : if (IsKeyedStoreICKind(kind()) || IsKeyedLoadICKind(kind()) ||
1086 : IsKeyedHasICKind(kind())) {
1087 49909 : MaybeObject feedback = GetFeedback();
1088 49909 : if (IsPropertyNameFeedback(feedback)) {
1089 : return Name::cast(feedback->GetHeapObjectAssumeStrong());
1090 : }
1091 : }
1092 21379 : return Name();
1093 : }
1094 :
1095 45148 : KeyedAccessLoadMode FeedbackNexus::GetKeyedAccessLoadMode() const {
1096 : DCHECK(IsKeyedLoadICKind(kind()) || IsKeyedHasICKind(kind()));
1097 : MapHandles maps;
1098 : MaybeObjectHandles handlers;
1099 :
1100 45148 : if (GetKeyType() == PROPERTY) return STANDARD_LOAD;
1101 :
1102 42907 : ExtractMaps(&maps);
1103 42907 : FindHandlers(&handlers, static_cast<int>(maps.size()));
1104 60562 : for (MaybeObjectHandle const& handler : handlers) {
1105 18525 : KeyedAccessLoadMode mode = LoadHandler::GetKeyedAccessLoadMode(*handler);
1106 18525 : if (mode != STANDARD_LOAD) return mode;
1107 : }
1108 :
1109 : return STANDARD_LOAD;
1110 : }
1111 :
1112 : namespace {
1113 :
1114 : bool BuiltinHasKeyedAccessStoreMode(int builtin_index) {
1115 : DCHECK(Builtins::IsBuiltinId(builtin_index));
1116 20234 : switch (builtin_index) {
1117 : case Builtins::kKeyedStoreIC_SloppyArguments_Standard:
1118 : case Builtins::kKeyedStoreIC_SloppyArguments_GrowNoTransitionHandleCOW:
1119 : case Builtins::kKeyedStoreIC_SloppyArguments_NoTransitionIgnoreOOB:
1120 : case Builtins::kKeyedStoreIC_SloppyArguments_NoTransitionHandleCOW:
1121 : case Builtins::kStoreFastElementIC_Standard:
1122 : case Builtins::kStoreFastElementIC_GrowNoTransitionHandleCOW:
1123 : case Builtins::kStoreFastElementIC_NoTransitionIgnoreOOB:
1124 : case Builtins::kStoreFastElementIC_NoTransitionHandleCOW:
1125 : case Builtins::kStoreInArrayLiteralIC_Slow_Standard:
1126 : case Builtins::kStoreInArrayLiteralIC_Slow_GrowNoTransitionHandleCOW:
1127 : case Builtins::kStoreInArrayLiteralIC_Slow_NoTransitionIgnoreOOB:
1128 : case Builtins::kStoreInArrayLiteralIC_Slow_NoTransitionHandleCOW:
1129 : case Builtins::kKeyedStoreIC_Slow_Standard:
1130 : case Builtins::kKeyedStoreIC_Slow_GrowNoTransitionHandleCOW:
1131 : case Builtins::kKeyedStoreIC_Slow_NoTransitionIgnoreOOB:
1132 : case Builtins::kKeyedStoreIC_Slow_NoTransitionHandleCOW:
1133 : case Builtins::kElementsTransitionAndStore_Standard:
1134 : case Builtins::kElementsTransitionAndStore_GrowNoTransitionHandleCOW:
1135 : case Builtins::kElementsTransitionAndStore_NoTransitionIgnoreOOB:
1136 : case Builtins::kElementsTransitionAndStore_NoTransitionHandleCOW:
1137 : return true;
1138 : default:
1139 : return false;
1140 : }
1141 : UNREACHABLE();
1142 : }
1143 :
1144 20197 : KeyedAccessStoreMode KeyedAccessStoreModeForBuiltin(int builtin_index) {
1145 : DCHECK(BuiltinHasKeyedAccessStoreMode(builtin_index));
1146 20197 : switch (builtin_index) {
1147 : case Builtins::kKeyedStoreIC_SloppyArguments_Standard:
1148 : case Builtins::kStoreInArrayLiteralIC_Slow_Standard:
1149 : case Builtins::kKeyedStoreIC_Slow_Standard:
1150 : case Builtins::kStoreFastElementIC_Standard:
1151 : case Builtins::kElementsTransitionAndStore_Standard:
1152 : return STANDARD_STORE;
1153 : case Builtins::kKeyedStoreIC_SloppyArguments_GrowNoTransitionHandleCOW:
1154 : case Builtins::kStoreInArrayLiteralIC_Slow_GrowNoTransitionHandleCOW:
1155 : case Builtins::kKeyedStoreIC_Slow_GrowNoTransitionHandleCOW:
1156 : case Builtins::kStoreFastElementIC_GrowNoTransitionHandleCOW:
1157 : case Builtins::kElementsTransitionAndStore_GrowNoTransitionHandleCOW:
1158 4667 : return STORE_AND_GROW_NO_TRANSITION_HANDLE_COW;
1159 : case Builtins::kKeyedStoreIC_SloppyArguments_NoTransitionIgnoreOOB:
1160 : case Builtins::kStoreInArrayLiteralIC_Slow_NoTransitionIgnoreOOB:
1161 : case Builtins::kKeyedStoreIC_Slow_NoTransitionIgnoreOOB:
1162 : case Builtins::kStoreFastElementIC_NoTransitionIgnoreOOB:
1163 : case Builtins::kElementsTransitionAndStore_NoTransitionIgnoreOOB:
1164 296 : return STORE_NO_TRANSITION_IGNORE_OUT_OF_BOUNDS;
1165 : case Builtins::kKeyedStoreIC_SloppyArguments_NoTransitionHandleCOW:
1166 : case Builtins::kStoreInArrayLiteralIC_Slow_NoTransitionHandleCOW:
1167 : case Builtins::kKeyedStoreIC_Slow_NoTransitionHandleCOW:
1168 : case Builtins::kStoreFastElementIC_NoTransitionHandleCOW:
1169 : case Builtins::kElementsTransitionAndStore_NoTransitionHandleCOW:
1170 741 : return STORE_NO_TRANSITION_HANDLE_COW;
1171 : default:
1172 0 : UNREACHABLE();
1173 : }
1174 : }
1175 :
1176 : } // namespace
1177 :
1178 76603 : KeyedAccessStoreMode FeedbackNexus::GetKeyedAccessStoreMode() const {
1179 : DCHECK(IsKeyedStoreICKind(kind()) || IsStoreInArrayLiteralICKind(kind()));
1180 : KeyedAccessStoreMode mode = STANDARD_STORE;
1181 : MapHandles maps;
1182 : MaybeObjectHandles handlers;
1183 :
1184 76603 : if (GetKeyType() == PROPERTY) return mode;
1185 :
1186 75812 : ExtractMaps(&maps);
1187 75812 : FindHandlers(&handlers, static_cast<int>(maps.size()));
1188 75867 : for (const MaybeObjectHandle& maybe_code_handler : handlers) {
1189 : // The first handler that isn't the slow handler will have the bits we need.
1190 : Handle<Code> handler;
1191 20252 : if (maybe_code_handler.object()->IsStoreHandler()) {
1192 : Handle<StoreHandler> data_handler =
1193 : Handle<StoreHandler>::cast(maybe_code_handler.object());
1194 : handler = handle(Code::cast(data_handler->smi_handler()),
1195 : vector()->GetIsolate());
1196 11600 : } else if (maybe_code_handler.object()->IsSmi()) {
1197 : // Skip proxy handlers.
1198 : DCHECK_EQ(*(maybe_code_handler.object()),
1199 : *StoreHandler::StoreProxy(GetIsolate()));
1200 : continue;
1201 : } else {
1202 : // Element store without prototype chain check.
1203 : handler = Handle<Code>::cast(maybe_code_handler.object());
1204 : }
1205 :
1206 20234 : if (handler->is_builtin()) {
1207 : const int builtin_index = handler->builtin_index();
1208 20234 : if (!BuiltinHasKeyedAccessStoreMode(builtin_index)) continue;
1209 :
1210 20197 : mode = KeyedAccessStoreModeForBuiltin(builtin_index);
1211 : break;
1212 : }
1213 : }
1214 :
1215 : return mode;
1216 : }
1217 :
1218 143141 : IcCheckType FeedbackNexus::GetKeyType() const {
1219 : DCHECK(IsKeyedStoreICKind(kind()) || IsKeyedLoadICKind(kind()) ||
1220 : IsStoreInArrayLiteralICKind(kind()) || IsKeyedHasICKind(kind()));
1221 143141 : MaybeObject feedback = GetFeedback();
1222 143141 : if (feedback == MaybeObject::FromObject(
1223 : *FeedbackVector::MegamorphicSentinel(GetIsolate()))) {
1224 : return static_cast<IcCheckType>(
1225 11202 : Smi::ToInt(GetFeedbackExtra()->cast<Object>()));
1226 : }
1227 137540 : return IsPropertyNameFeedback(feedback) ? PROPERTY : ELEMENT;
1228 : }
1229 :
1230 676251 : BinaryOperationHint FeedbackNexus::GetBinaryOperationFeedback() const {
1231 : DCHECK_EQ(kind(), FeedbackSlotKind::kBinaryOp);
1232 1894520 : int feedback = GetFeedback().ToSmi().value();
1233 676251 : return BinaryOperationHintFromFeedback(feedback);
1234 : }
1235 :
1236 527087 : CompareOperationHint FeedbackNexus::GetCompareOperationFeedback() const {
1237 : DCHECK_EQ(kind(), FeedbackSlotKind::kCompareOp);
1238 1054174 : int feedback = GetFeedback().ToSmi().value();
1239 527087 : return CompareOperationHintFromFeedback(feedback);
1240 : }
1241 :
1242 2930 : ForInHint FeedbackNexus::GetForInFeedback() const {
1243 : DCHECK_EQ(kind(), FeedbackSlotKind::kForIn);
1244 8616 : int feedback = GetFeedback().ToSmi().value();
1245 2930 : return ForInHintFromFeedback(feedback);
1246 : }
1247 :
1248 2887 : MaybeHandle<JSObject> FeedbackNexus::GetConstructorFeedback() const {
1249 : DCHECK_EQ(kind(), FeedbackSlotKind::kInstanceOf);
1250 : Isolate* isolate = GetIsolate();
1251 2887 : MaybeObject feedback = GetFeedback();
1252 : HeapObject heap_object;
1253 2887 : if (feedback->GetHeapObjectIfWeak(&heap_object)) {
1254 36 : return handle(JSObject::cast(heap_object), isolate);
1255 : }
1256 2851 : return MaybeHandle<JSObject>();
1257 : }
1258 :
1259 : namespace {
1260 :
1261 64 : bool InList(Handle<ArrayList> types, Handle<String> type) {
1262 124 : for (int i = 0; i < types->Length(); i++) {
1263 : Object obj = types->Get(i);
1264 76 : if (String::cast(obj)->Equals(*type)) {
1265 : return true;
1266 : }
1267 : }
1268 : return false;
1269 : }
1270 : } // anonymous namespace
1271 :
1272 228 : void FeedbackNexus::Collect(Handle<String> type, int position) {
1273 : DCHECK(IsTypeProfileKind(kind()));
1274 : DCHECK_GE(position, 0);
1275 : Isolate* isolate = GetIsolate();
1276 :
1277 228 : MaybeObject const feedback = GetFeedback();
1278 :
1279 : // Map source position to collection of types
1280 : Handle<SimpleNumberDictionary> types;
1281 :
1282 228 : if (feedback == MaybeObject::FromObject(
1283 : *FeedbackVector::UninitializedSentinel(isolate))) {
1284 68 : types = SimpleNumberDictionary::New(isolate, 1);
1285 : } else {
1286 : types = handle(
1287 : SimpleNumberDictionary::cast(feedback->GetHeapObjectAssumeStrong()),
1288 : isolate);
1289 : }
1290 :
1291 : Handle<ArrayList> position_specific_types;
1292 :
1293 456 : int entry = types->FindEntry(isolate, position);
1294 228 : if (entry == SimpleNumberDictionary::kNotFound) {
1295 164 : position_specific_types = ArrayList::New(isolate, 1);
1296 : types = SimpleNumberDictionary::Set(
1297 : isolate, types, position,
1298 328 : ArrayList::Add(isolate, position_specific_types, type));
1299 : } else {
1300 : DCHECK(types->ValueAt(entry)->IsArrayList());
1301 : position_specific_types =
1302 64 : handle(ArrayList::cast(types->ValueAt(entry)), isolate);
1303 64 : if (!InList(position_specific_types, type)) { // Add type
1304 : types = SimpleNumberDictionary::Set(
1305 : isolate, types, position,
1306 96 : ArrayList::Add(isolate, position_specific_types, type));
1307 : }
1308 : }
1309 : SetFeedback(*types);
1310 228 : }
1311 :
1312 108 : std::vector<int> FeedbackNexus::GetSourcePositions() const {
1313 : DCHECK(IsTypeProfileKind(kind()));
1314 : std::vector<int> source_positions;
1315 : Isolate* isolate = GetIsolate();
1316 :
1317 108 : MaybeObject const feedback = GetFeedback();
1318 :
1319 108 : if (feedback == MaybeObject::FromObject(
1320 : *FeedbackVector::UninitializedSentinel(isolate))) {
1321 : return source_positions;
1322 : }
1323 :
1324 : Handle<SimpleNumberDictionary> types(
1325 : SimpleNumberDictionary::cast(feedback->GetHeapObjectAssumeStrong()),
1326 : isolate);
1327 :
1328 768 : for (int index = SimpleNumberDictionary::kElementsStartIndex;
1329 : index < types->length(); index += SimpleNumberDictionary::kEntrySize) {
1330 : int key_index = index + SimpleNumberDictionary::kEntryKeyIndex;
1331 : Object key = types->get(key_index);
1332 352 : if (key->IsSmi()) {
1333 148 : int position = Smi::cast(key)->value();
1334 148 : source_positions.push_back(position);
1335 : }
1336 : }
1337 : return source_positions;
1338 : }
1339 :
1340 148 : std::vector<Handle<String>> FeedbackNexus::GetTypesForSourcePositions(
1341 : uint32_t position) const {
1342 : DCHECK(IsTypeProfileKind(kind()));
1343 : Isolate* isolate = GetIsolate();
1344 :
1345 148 : MaybeObject const feedback = GetFeedback();
1346 : std::vector<Handle<String>> types_for_position;
1347 148 : if (feedback == MaybeObject::FromObject(
1348 : *FeedbackVector::UninitializedSentinel(isolate))) {
1349 : return types_for_position;
1350 : }
1351 :
1352 : Handle<SimpleNumberDictionary> types(
1353 : SimpleNumberDictionary::cast(feedback->GetHeapObjectAssumeStrong()),
1354 : isolate);
1355 :
1356 148 : int entry = types->FindEntry(isolate, position);
1357 148 : if (entry == SimpleNumberDictionary::kNotFound) {
1358 : return types_for_position;
1359 : }
1360 : DCHECK(types->ValueAt(entry)->IsArrayList());
1361 : Handle<ArrayList> position_specific_types =
1362 : Handle<ArrayList>(ArrayList::cast(types->ValueAt(entry)), isolate);
1363 540 : for (int i = 0; i < position_specific_types->Length(); i++) {
1364 : Object t = position_specific_types->Get(i);
1365 196 : types_for_position.push_back(Handle<String>(String::cast(t), isolate));
1366 : }
1367 :
1368 : return types_for_position;
1369 : }
1370 :
1371 : namespace {
1372 :
1373 0 : Handle<JSObject> ConvertToJSObject(Isolate* isolate,
1374 : Handle<SimpleNumberDictionary> feedback) {
1375 : Handle<JSObject> type_profile =
1376 0 : isolate->factory()->NewJSObject(isolate->object_function());
1377 :
1378 0 : for (int index = SimpleNumberDictionary::kElementsStartIndex;
1379 : index < feedback->length();
1380 : index += SimpleNumberDictionary::kEntrySize) {
1381 : int key_index = index + SimpleNumberDictionary::kEntryKeyIndex;
1382 : Object key = feedback->get(key_index);
1383 0 : if (key->IsSmi()) {
1384 0 : int value_index = index + SimpleNumberDictionary::kEntryValueIndex;
1385 :
1386 : Handle<ArrayList> position_specific_types(
1387 : ArrayList::cast(feedback->get(value_index)), isolate);
1388 :
1389 : int position = Smi::ToInt(key);
1390 0 : JSObject::AddDataElement(
1391 : type_profile, position,
1392 : isolate->factory()->NewJSArrayWithElements(
1393 : ArrayList::Elements(isolate, position_specific_types)),
1394 0 : PropertyAttributes::NONE);
1395 : }
1396 : }
1397 0 : return type_profile;
1398 : }
1399 : } // namespace
1400 :
1401 0 : JSObject FeedbackNexus::GetTypeProfile() const {
1402 : DCHECK(IsTypeProfileKind(kind()));
1403 : Isolate* isolate = GetIsolate();
1404 :
1405 0 : MaybeObject const feedback = GetFeedback();
1406 :
1407 0 : if (feedback == MaybeObject::FromObject(
1408 : *FeedbackVector::UninitializedSentinel(isolate))) {
1409 0 : return *isolate->factory()->NewJSObject(isolate->object_function());
1410 : }
1411 :
1412 0 : return *ConvertToJSObject(isolate,
1413 : handle(SimpleNumberDictionary::cast(
1414 : feedback->GetHeapObjectAssumeStrong()),
1415 : isolate));
1416 : }
1417 :
1418 212 : void FeedbackNexus::ResetTypeProfile() {
1419 : DCHECK(IsTypeProfileKind(kind()));
1420 : SetFeedback(*FeedbackVector::UninitializedSentinel(GetIsolate()));
1421 212 : }
1422 :
1423 : } // namespace internal
1424 122036 : } // namespace v8
|