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 14595528 : FeedbackSlot FeedbackVectorSpec::AddSlot(FeedbackSlotKind kind) {
19 : int slot = slots();
20 14595528 : int entries_per_slot = FeedbackMetadata::GetSlotSize(kind);
21 : append(kind);
22 39435111 : for (int i = 1; i < entries_per_slot; i++) {
23 : append(FeedbackSlotKind::kInvalid);
24 : }
25 14595405 : 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 2128049 : static bool IsPropertyNameFeedback(MaybeObject feedback) {
45 2128049 : HeapObject heap_object;
46 2128049 : if (!feedback->GetHeapObjectIfStrong(&heap_object)) return false;
47 1067351 : if (heap_object->IsString()) {
48 : DCHECK(heap_object->IsInternalizedString());
49 : return true;
50 : }
51 1036880 : if (!heap_object->IsSymbol()) return false;
52 : Symbol symbol = Symbol::cast(heap_object);
53 : ReadOnlyRoots roots = symbol->GetReadOnlyRoots();
54 42111 : return symbol != roots.uninitialized_symbol() &&
55 640047 : 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 44251957 : 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 51805938 : int new_data = VectorICComputer::encode(data, slot.ToInt(), kind);
73 : set(index, new_data);
74 0 : }
75 :
76 : // static
77 2090711 : Handle<FeedbackMetadata> FeedbackMetadata::New(Isolate* isolate,
78 : const FeedbackVectorSpec* spec) {
79 : Factory* factory = isolate->factory();
80 :
81 2090711 : const int slot_count = spec == nullptr ? 0 : spec->slots();
82 : const int closure_feedback_cell_count =
83 2090711 : spec == nullptr ? 0 : spec->closure_feedback_cells();
84 2090711 : 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 1597425 : 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 53403365 : 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 1597427 : 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 23360074 : FeedbackSlotKind FeedbackVector::GetKind(FeedbackSlot slot) const {
197 : DCHECK(!is_empty());
198 46720153 : 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 3082537 : Handle<FeedbackVector> FeedbackVector::New(
211 : Isolate* isolate, Handle<SharedFunctionInfo> shared,
212 : Handle<FixedArray> closure_feedback_cell_array) {
213 : Factory* factory = isolate->factory();
214 :
215 : const int slot_count = shared->feedback_metadata()->slot_count();
216 :
217 : Handle<FeedbackVector> vector =
218 3082537 : factory->NewFeedbackVector(shared, AllocationType::kOld);
219 :
220 : DCHECK_EQ(vector->length(), slot_count);
221 :
222 : DCHECK_EQ(vector->shared_function_info(), *shared);
223 : DCHECK_EQ(
224 : vector->optimized_code_weak_or_smi(),
225 : MaybeObject::FromSmi(Smi::FromEnum(
226 : FLAG_log_function_events ? OptimizationMarker::kLogFirstExecution
227 : : OptimizationMarker::kNone)));
228 : DCHECK_EQ(vector->invocation_count(), 0);
229 : DCHECK_EQ(vector->profiler_ticks(), 0);
230 : DCHECK_EQ(vector->deopt_count(), 0);
231 :
232 3082539 : vector->set_closure_feedback_cell_array(*closure_feedback_cell_array);
233 :
234 : // Ensure we can skip the write barrier
235 : Handle<Object> uninitialized_sentinel = UninitializedSentinel(isolate);
236 : DCHECK_EQ(ReadOnlyRoots(isolate).uninitialized_symbol(),
237 : *uninitialized_sentinel);
238 44701938 : for (int i = 0; i < slot_count;) {
239 : FeedbackSlot slot(i);
240 : FeedbackSlotKind kind = shared->feedback_metadata()->GetKind(slot);
241 : int index = FeedbackVector::GetIndex(slot);
242 20809693 : int entry_size = FeedbackMetadata::GetSlotSize(kind);
243 :
244 : Object extra_value = *uninitialized_sentinel;
245 20809696 : switch (kind) {
246 : case FeedbackSlotKind::kLoadGlobalInsideTypeof:
247 : case FeedbackSlotKind::kLoadGlobalNotInsideTypeof:
248 : case FeedbackSlotKind::kStoreGlobalSloppy:
249 : case FeedbackSlotKind::kStoreGlobalStrict:
250 18757599 : vector->set(index, HeapObjectReference::ClearedValue(isolate),
251 6252533 : SKIP_WRITE_BARRIER);
252 6252533 : break;
253 : case FeedbackSlotKind::kForIn:
254 : case FeedbackSlotKind::kCompareOp:
255 : case FeedbackSlotKind::kBinaryOp:
256 5517335 : vector->set(index, Smi::kZero, SKIP_WRITE_BARRIER);
257 2758667 : break;
258 : case FeedbackSlotKind::kLiteral:
259 793444 : vector->set(index, Smi::kZero, SKIP_WRITE_BARRIER);
260 396722 : break;
261 : case FeedbackSlotKind::kCall:
262 11607286 : vector->set(index, *uninitialized_sentinel, SKIP_WRITE_BARRIER);
263 : extra_value = Smi::kZero;
264 5803643 : break;
265 : case FeedbackSlotKind::kCloneObject:
266 : case FeedbackSlotKind::kLoadProperty:
267 : case FeedbackSlotKind::kLoadKeyed:
268 : case FeedbackSlotKind::kHasKeyed:
269 : case FeedbackSlotKind::kStoreNamedSloppy:
270 : case FeedbackSlotKind::kStoreNamedStrict:
271 : case FeedbackSlotKind::kStoreOwnNamed:
272 : case FeedbackSlotKind::kStoreKeyedSloppy:
273 : case FeedbackSlotKind::kStoreKeyedStrict:
274 : case FeedbackSlotKind::kStoreInArrayLiteral:
275 : case FeedbackSlotKind::kStoreDataPropertyInLiteral:
276 : case FeedbackSlotKind::kTypeProfile:
277 : case FeedbackSlotKind::kInstanceOf:
278 11196283 : vector->set(index, *uninitialized_sentinel, SKIP_WRITE_BARRIER);
279 5598140 : break;
280 :
281 : case FeedbackSlotKind::kInvalid:
282 : case FeedbackSlotKind::kKindsNumber:
283 0 : UNREACHABLE();
284 : break;
285 : }
286 56068334 : for (int j = 1; j < entry_size; j++) {
287 52887949 : vector->set(index + j, extra_value, SKIP_WRITE_BARRIER);
288 : }
289 20809699 : i += entry_size;
290 : }
291 :
292 : Handle<FeedbackVector> result = Handle<FeedbackVector>::cast(vector);
293 3082546 : if (!isolate->is_best_effort_code_coverage() ||
294 : isolate->is_collecting_type_profile()) {
295 1200 : AddToVectorsForProfilingTools(isolate, result);
296 : }
297 3082546 : return result;
298 : }
299 :
300 : // static
301 3082534 : Handle<FixedArray> FeedbackVector::NewClosureFeedbackCellArray(
302 : Isolate* isolate, Handle<SharedFunctionInfo> shared) {
303 : Factory* factory = isolate->factory();
304 :
305 : int num_feedback_cells =
306 : shared->feedback_metadata()->closure_feedback_cell_count();
307 3082534 : if (num_feedback_cells == 0) {
308 : return factory->empty_fixed_array();
309 : }
310 :
311 : Handle<FixedArray> feedback_cell_array =
312 1027145 : factory->NewFixedArray(num_feedback_cells, AllocationType::kOld);
313 9185659 : for (int i = 0; i < num_feedback_cells; i++) {
314 : Handle<FeedbackCell> cell =
315 4079254 : factory->NewNoClosuresCell(factory->undefined_value());
316 8158512 : feedback_cell_array->set(i, *cell);
317 : }
318 1027151 : return feedback_cell_array;
319 : }
320 :
321 : // static
322 1200 : void FeedbackVector::AddToVectorsForProfilingTools(
323 : Isolate* isolate, Handle<FeedbackVector> vector) {
324 : DCHECK(!isolate->is_best_effort_code_coverage() ||
325 : isolate->is_collecting_type_profile());
326 1200 : if (!vector->shared_function_info()->IsSubjectToDebugging()) return;
327 : Handle<ArrayList> list = Handle<ArrayList>::cast(
328 : isolate->factory()->feedback_vectors_for_profiling_tools());
329 1200 : list = ArrayList::Add(isolate, list, vector);
330 1200 : isolate->SetFeedbackVectorsForProfilingTools(*list);
331 : }
332 :
333 : // static
334 24641 : void FeedbackVector::SetOptimizedCode(Handle<FeedbackVector> vector,
335 : Handle<Code> code) {
336 : DCHECK_EQ(code->kind(), Code::OPTIMIZED_FUNCTION);
337 49282 : vector->set_optimized_code_weak_or_smi(HeapObjectReference::Weak(*code));
338 24641 : }
339 :
340 0 : void FeedbackVector::ClearOptimizedCode() {
341 : DCHECK(has_optimized_code());
342 : SetOptimizationMarker(OptimizationMarker::kNone);
343 0 : }
344 :
345 766351 : void FeedbackVector::ClearOptimizationMarker() {
346 : DCHECK(!has_optimized_code());
347 : SetOptimizationMarker(OptimizationMarker::kNone);
348 766352 : }
349 :
350 500589 : void FeedbackVector::SetOptimizationMarker(OptimizationMarker marker) {
351 1269216 : set_optimized_code_weak_or_smi(MaybeObject::FromSmi(Smi::FromEnum(marker)));
352 500590 : }
353 :
354 4413436 : void FeedbackVector::EvictOptimizedCodeMarkedForDeoptimization(
355 : SharedFunctionInfo shared, const char* reason) {
356 : MaybeObject slot = optimized_code_weak_or_smi();
357 4413436 : if (slot->IsSmi()) {
358 3990670 : return;
359 : }
360 :
361 423030 : if (slot->IsCleared()) {
362 : ClearOptimizationMarker();
363 : return;
364 : }
365 :
366 422758 : Code code = Code::cast(slot->GetHeapObject());
367 422758 : if (code->marked_for_deoptimization()) {
368 2004 : if (FLAG_trace_deopt) {
369 : PrintF("[evicting optimizing code marked for deoptimization (%s) for ",
370 0 : reason);
371 0 : shared->ShortPrint();
372 0 : PrintF("]\n");
373 : }
374 2004 : if (!code->deopt_already_counted()) {
375 : increment_deopt_count();
376 1224 : code->set_deopt_already_counted(true);
377 : }
378 : ClearOptimizedCode();
379 : }
380 : }
381 :
382 52599 : bool FeedbackVector::ClearSlots(Isolate* isolate) {
383 : MaybeObject uninitialized_sentinel = MaybeObject::FromObject(
384 : FeedbackVector::RawUninitializedSentinel(isolate));
385 :
386 : bool feedback_updated = false;
387 52599 : FeedbackMetadataIterator iter(metadata());
388 214513 : while (iter.HasNext()) {
389 80957 : FeedbackSlot slot = iter.Next();
390 :
391 : MaybeObject obj = Get(slot);
392 80957 : if (obj != uninitialized_sentinel) {
393 : FeedbackNexus nexus(*this, slot);
394 55810 : feedback_updated |= nexus.Clear();
395 : }
396 : }
397 52599 : return feedback_updated;
398 : }
399 :
400 413684 : void FeedbackVector::AssertNoLegacyTypes(MaybeObject object) {
401 : #ifdef DEBUG
402 : HeapObject heap_object;
403 : if (object->GetHeapObject(&heap_object)) {
404 : // Instead of FixedArray, the Feedback and the Extra should contain
405 : // WeakFixedArrays. The only allowed FixedArray subtype is HashTable.
406 : DCHECK_IMPLIES(heap_object->IsFixedArray(), heap_object->IsHashTable());
407 : }
408 : #endif
409 413684 : }
410 :
411 222365 : Handle<WeakFixedArray> FeedbackNexus::EnsureArrayOfSize(int length) {
412 : Isolate* isolate = GetIsolate();
413 : HeapObject heap_object;
414 531235 : if (GetFeedback()->GetHeapObjectIfStrong(&heap_object) &&
415 308678 : heap_object->IsWeakFixedArray() &&
416 : WeakFixedArray::cast(heap_object)->length() == length) {
417 : return handle(WeakFixedArray::cast(heap_object), isolate);
418 : }
419 215967 : Handle<WeakFixedArray> array = isolate->factory()->NewWeakFixedArray(length);
420 : SetFeedback(*array);
421 215967 : return array;
422 : }
423 :
424 18011 : Handle<WeakFixedArray> FeedbackNexus::EnsureExtraArrayOfSize(int length) {
425 : Isolate* isolate = GetIsolate();
426 : HeapObject heap_object;
427 40384 : if (GetFeedbackExtra()->GetHeapObjectIfStrong(&heap_object) &&
428 22303 : heap_object->IsWeakFixedArray() &&
429 : WeakFixedArray::cast(heap_object)->length() == length) {
430 : return handle(WeakFixedArray::cast(heap_object), isolate);
431 : }
432 17758 : Handle<WeakFixedArray> array = isolate->factory()->NewWeakFixedArray(length);
433 17758 : SetFeedbackExtra(*array);
434 17758 : return array;
435 : }
436 :
437 45756 : void FeedbackNexus::ConfigureUninitialized() {
438 : Isolate* isolate = GetIsolate();
439 45756 : switch (kind()) {
440 : case FeedbackSlotKind::kStoreGlobalSloppy:
441 : case FeedbackSlotKind::kStoreGlobalStrict:
442 : case FeedbackSlotKind::kLoadGlobalNotInsideTypeof:
443 : case FeedbackSlotKind::kLoadGlobalInsideTypeof: {
444 16132 : SetFeedback(HeapObjectReference::ClearedValue(isolate),
445 8066 : SKIP_WRITE_BARRIER);
446 16132 : SetFeedbackExtra(*FeedbackVector::UninitializedSentinel(isolate),
447 8066 : SKIP_WRITE_BARRIER);
448 8066 : break;
449 : }
450 : case FeedbackSlotKind::kCloneObject:
451 : case FeedbackSlotKind::kCall: {
452 : SetFeedback(*FeedbackVector::UninitializedSentinel(isolate),
453 : SKIP_WRITE_BARRIER);
454 6434 : SetFeedbackExtra(Smi::kZero, SKIP_WRITE_BARRIER);
455 6434 : break;
456 : }
457 : case FeedbackSlotKind::kInstanceOf: {
458 : SetFeedback(*FeedbackVector::UninitializedSentinel(isolate),
459 : SKIP_WRITE_BARRIER);
460 0 : break;
461 : }
462 : case FeedbackSlotKind::kStoreNamedSloppy:
463 : case FeedbackSlotKind::kStoreNamedStrict:
464 : case FeedbackSlotKind::kStoreKeyedSloppy:
465 : case FeedbackSlotKind::kStoreKeyedStrict:
466 : case FeedbackSlotKind::kStoreInArrayLiteral:
467 : case FeedbackSlotKind::kStoreOwnNamed:
468 : case FeedbackSlotKind::kLoadProperty:
469 : case FeedbackSlotKind::kLoadKeyed:
470 : case FeedbackSlotKind::kHasKeyed:
471 : case FeedbackSlotKind::kStoreDataPropertyInLiteral: {
472 : SetFeedback(*FeedbackVector::UninitializedSentinel(isolate),
473 : SKIP_WRITE_BARRIER);
474 62512 : SetFeedbackExtra(*FeedbackVector::UninitializedSentinel(isolate),
475 31256 : SKIP_WRITE_BARRIER);
476 31256 : break;
477 : }
478 : default:
479 0 : UNREACHABLE();
480 : }
481 45756 : }
482 :
483 55810 : bool FeedbackNexus::Clear() {
484 : bool feedback_updated = false;
485 :
486 : switch (kind()) {
487 : case FeedbackSlotKind::kTypeProfile:
488 : // We don't clear these kinds ever.
489 : break;
490 :
491 : case FeedbackSlotKind::kCompareOp:
492 : case FeedbackSlotKind::kForIn:
493 : case FeedbackSlotKind::kBinaryOp:
494 : // We don't clear these, either.
495 : break;
496 :
497 : case FeedbackSlotKind::kLiteral:
498 : SetFeedback(Smi::kZero, SKIP_WRITE_BARRIER);
499 : feedback_updated = true;
500 13 : break;
501 :
502 : case FeedbackSlotKind::kStoreNamedSloppy:
503 : case FeedbackSlotKind::kStoreNamedStrict:
504 : case FeedbackSlotKind::kStoreKeyedSloppy:
505 : case FeedbackSlotKind::kStoreKeyedStrict:
506 : case FeedbackSlotKind::kStoreInArrayLiteral:
507 : case FeedbackSlotKind::kStoreOwnNamed:
508 : case FeedbackSlotKind::kLoadProperty:
509 : case FeedbackSlotKind::kLoadKeyed:
510 : case FeedbackSlotKind::kHasKeyed:
511 : case FeedbackSlotKind::kStoreGlobalSloppy:
512 : case FeedbackSlotKind::kStoreGlobalStrict:
513 : case FeedbackSlotKind::kLoadGlobalNotInsideTypeof:
514 : case FeedbackSlotKind::kLoadGlobalInsideTypeof:
515 : case FeedbackSlotKind::kCall:
516 : case FeedbackSlotKind::kInstanceOf:
517 : case FeedbackSlotKind::kStoreDataPropertyInLiteral:
518 : case FeedbackSlotKind::kCloneObject:
519 47770 : if (!IsCleared()) {
520 45756 : ConfigureUninitialized();
521 : feedback_updated = true;
522 : }
523 : break;
524 :
525 : case FeedbackSlotKind::kInvalid:
526 : case FeedbackSlotKind::kKindsNumber:
527 0 : UNREACHABLE();
528 : break;
529 : }
530 55810 : return feedback_updated;
531 : }
532 :
533 686666 : void FeedbackNexus::ConfigurePremonomorphic(Handle<Map> receiver_map) {
534 : SetFeedback(*FeedbackVector::PremonomorphicSentinel(GetIsolate()),
535 : SKIP_WRITE_BARRIER);
536 686666 : SetFeedbackExtra(HeapObjectReference::Weak(*receiver_map));
537 686667 : }
538 :
539 126 : bool FeedbackNexus::ConfigureMegamorphic() {
540 : DisallowHeapAllocation no_gc;
541 : Isolate* isolate = GetIsolate();
542 : MaybeObject sentinel =
543 : MaybeObject::FromObject(*FeedbackVector::MegamorphicSentinel(isolate));
544 252 : if (GetFeedback() != sentinel) {
545 126 : SetFeedback(sentinel, SKIP_WRITE_BARRIER);
546 126 : SetFeedbackExtra(HeapObjectReference::ClearedValue(isolate));
547 126 : return true;
548 : }
549 :
550 : return false;
551 : }
552 :
553 47827 : bool FeedbackNexus::ConfigureMegamorphic(IcCheckType property_type) {
554 : DisallowHeapAllocation no_gc;
555 : Isolate* isolate = GetIsolate();
556 : bool changed = false;
557 : MaybeObject sentinel =
558 : MaybeObject::FromObject(*FeedbackVector::MegamorphicSentinel(isolate));
559 95655 : if (GetFeedback() != sentinel) {
560 43398 : SetFeedback(sentinel, SKIP_WRITE_BARRIER);
561 : changed = true;
562 : }
563 :
564 47828 : Smi extra = Smi::FromInt(static_cast<int>(property_type));
565 52258 : if (changed || GetFeedbackExtra() != MaybeObject::FromSmi(extra)) {
566 43398 : SetFeedbackExtra(extra, SKIP_WRITE_BARRIER);
567 : changed = true;
568 : }
569 47827 : return changed;
570 : }
571 :
572 103509 : Map FeedbackNexus::GetFirstMap() const {
573 : MapHandles maps;
574 103509 : ExtractMaps(&maps);
575 103509 : if (maps.size() > 0) return *maps.at(0);
576 4 : return Map();
577 : }
578 :
579 13174959 : InlineCacheState FeedbackNexus::ic_state() const {
580 : Isolate* isolate = GetIsolate();
581 13174959 : MaybeObject feedback = GetFeedback();
582 :
583 13174968 : switch (kind()) {
584 : case FeedbackSlotKind::kLiteral:
585 52370 : if (feedback->IsSmi()) return UNINITIALIZED;
586 7591 : return MONOMORPHIC;
587 :
588 : case FeedbackSlotKind::kStoreGlobalSloppy:
589 : case FeedbackSlotKind::kStoreGlobalStrict:
590 : case FeedbackSlotKind::kLoadGlobalNotInsideTypeof:
591 : case FeedbackSlotKind::kLoadGlobalInsideTypeof: {
592 6421997 : if (feedback->IsSmi()) return MONOMORPHIC;
593 :
594 6421757 : if (feedback == MaybeObject::FromObject(
595 : *FeedbackVector::PremonomorphicSentinel(isolate))) {
596 : DCHECK(kind() == FeedbackSlotKind::kStoreGlobalSloppy ||
597 : kind() == FeedbackSlotKind::kStoreGlobalStrict);
598 : return PREMONOMORPHIC;
599 : }
600 :
601 : DCHECK(feedback->IsWeakOrCleared());
602 6421730 : MaybeObject extra = GetFeedbackExtra();
603 12424143 : if (!feedback->IsCleared() ||
604 : extra != MaybeObject::FromObject(
605 : *FeedbackVector::UninitializedSentinel(isolate))) {
606 : return MONOMORPHIC;
607 : }
608 5997680 : return UNINITIALIZED;
609 : }
610 :
611 : case FeedbackSlotKind::kStoreNamedSloppy:
612 : case FeedbackSlotKind::kStoreNamedStrict:
613 : case FeedbackSlotKind::kStoreKeyedSloppy:
614 : case FeedbackSlotKind::kStoreKeyedStrict:
615 : case FeedbackSlotKind::kStoreInArrayLiteral:
616 : case FeedbackSlotKind::kStoreOwnNamed:
617 : case FeedbackSlotKind::kLoadProperty:
618 : case FeedbackSlotKind::kLoadKeyed:
619 : case FeedbackSlotKind::kHasKeyed: {
620 5009590 : if (feedback == MaybeObject::FromObject(
621 : *FeedbackVector::UninitializedSentinel(isolate))) {
622 : return UNINITIALIZED;
623 : }
624 3055846 : if (feedback == MaybeObject::FromObject(
625 : *FeedbackVector::MegamorphicSentinel(isolate))) {
626 : return MEGAMORPHIC;
627 : }
628 2389581 : if (feedback == MaybeObject::FromObject(
629 : *FeedbackVector::PremonomorphicSentinel(isolate))) {
630 : return PREMONOMORPHIC;
631 : }
632 921286 : if (feedback->IsWeakOrCleared()) {
633 : // Don't check if the map is cleared.
634 : return MONOMORPHIC;
635 : }
636 : HeapObject heap_object;
637 218071 : if (feedback->GetHeapObjectIfStrong(&heap_object)) {
638 218071 : if (heap_object->IsWeakFixedArray()) {
639 : // Determine state purely by our structure, don't check if the maps
640 : // are cleared.
641 : return POLYMORPHIC;
642 : }
643 16923 : if (heap_object->IsName()) {
644 : DCHECK(IsKeyedLoadICKind(kind()) || IsKeyedStoreICKind(kind()) ||
645 : IsKeyedHasICKind(kind()));
646 33846 : Object extra = GetFeedbackExtra()->GetHeapObjectAssumeStrong();
647 : WeakFixedArray extra_array = WeakFixedArray::cast(extra);
648 16923 : return extra_array->length() > 2 ? POLYMORPHIC : MONOMORPHIC;
649 : }
650 : }
651 0 : UNREACHABLE();
652 : }
653 : case FeedbackSlotKind::kCall: {
654 : HeapObject heap_object;
655 1031449 : if (feedback == MaybeObject::FromObject(
656 : *FeedbackVector::MegamorphicSentinel(isolate))) {
657 : return GENERIC;
658 2700849 : } else if (feedback->IsWeakOrCleared() ||
659 678521 : (feedback->GetHeapObjectIfStrong(&heap_object) &&
660 : heap_object->IsAllocationSite())) {
661 : return MONOMORPHIC;
662 : }
663 :
664 676853 : CHECK_EQ(feedback, MaybeObject::FromObject(
665 : *FeedbackVector::UninitializedSentinel(isolate)));
666 : return UNINITIALIZED;
667 : }
668 : case FeedbackSlotKind::kBinaryOp: {
669 273233 : BinaryOperationHint hint = GetBinaryOperationFeedback();
670 273233 : if (hint == BinaryOperationHint::kNone) {
671 : return UNINITIALIZED;
672 257856 : } else if (hint == BinaryOperationHint::kAny) {
673 : return GENERIC;
674 : }
675 :
676 254516 : return MONOMORPHIC;
677 : }
678 : case FeedbackSlotKind::kCompareOp: {
679 151557 : CompareOperationHint hint = GetCompareOperationFeedback();
680 151557 : if (hint == CompareOperationHint::kNone) {
681 : return UNINITIALIZED;
682 137676 : } else if (hint == CompareOperationHint::kAny) {
683 : return GENERIC;
684 : }
685 :
686 101634 : return MONOMORPHIC;
687 : }
688 : case FeedbackSlotKind::kForIn: {
689 : ForInHint hint = GetForInFeedback();
690 1353 : if (hint == ForInHint::kNone) {
691 : return UNINITIALIZED;
692 1320 : } else if (hint == ForInHint::kAny) {
693 : return GENERIC;
694 : }
695 484 : return MONOMORPHIC;
696 : }
697 : case FeedbackSlotKind::kInstanceOf: {
698 4807 : if (feedback == MaybeObject::FromObject(
699 : *FeedbackVector::UninitializedSentinel(isolate))) {
700 : return UNINITIALIZED;
701 1890 : } else if (feedback ==
702 : MaybeObject::FromObject(
703 : *FeedbackVector::MegamorphicSentinel(isolate))) {
704 : return MEGAMORPHIC;
705 : }
706 1666 : return MONOMORPHIC;
707 : }
708 : case FeedbackSlotKind::kStoreDataPropertyInLiteral: {
709 227678 : if (feedback == MaybeObject::FromObject(
710 : *FeedbackVector::UninitializedSentinel(isolate))) {
711 : return UNINITIALIZED;
712 223476 : } else if (feedback->IsWeakOrCleared()) {
713 : // Don't check if the map is cleared.
714 : return MONOMORPHIC;
715 : }
716 :
717 16354 : return MEGAMORPHIC;
718 : }
719 : case FeedbackSlotKind::kTypeProfile: {
720 0 : if (feedback == MaybeObject::FromObject(
721 : *FeedbackVector::UninitializedSentinel(isolate))) {
722 : return UNINITIALIZED;
723 : }
724 0 : return MONOMORPHIC;
725 : }
726 :
727 : case FeedbackSlotKind::kCloneObject: {
728 959 : if (feedback == MaybeObject::FromObject(
729 : *FeedbackVector::UninitializedSentinel(isolate))) {
730 : return UNINITIALIZED;
731 : }
732 280 : if (feedback == MaybeObject::FromObject(
733 : *FeedbackVector::MegamorphicSentinel(isolate))) {
734 : return MEGAMORPHIC;
735 : }
736 280 : if (feedback->IsWeakOrCleared()) {
737 : return MONOMORPHIC;
738 : }
739 :
740 : DCHECK(feedback->GetHeapObjectAssumeStrong()->IsWeakFixedArray());
741 180 : return POLYMORPHIC;
742 : }
743 :
744 : case FeedbackSlotKind::kInvalid:
745 : case FeedbackSlotKind::kKindsNumber:
746 0 : UNREACHABLE();
747 : break;
748 : }
749 : return UNINITIALIZED;
750 : }
751 :
752 5678275 : void FeedbackNexus::ConfigurePropertyCellMode(Handle<PropertyCell> cell) {
753 : DCHECK(IsGlobalICKind(kind()));
754 : Isolate* isolate = GetIsolate();
755 5678275 : SetFeedback(HeapObjectReference::Weak(*cell));
756 11356559 : SetFeedbackExtra(*FeedbackVector::UninitializedSentinel(isolate),
757 5678280 : SKIP_WRITE_BARRIER);
758 5678279 : }
759 :
760 56686 : bool FeedbackNexus::ConfigureLexicalVarMode(int script_context_index,
761 : int context_slot_index,
762 : bool immutable) {
763 : DCHECK(IsGlobalICKind(kind()));
764 : DCHECK_LE(0, script_context_index);
765 : DCHECK_LE(0, context_slot_index);
766 170058 : if (!ContextIndexBits::is_valid(script_context_index) ||
767 113372 : !SlotIndexBits::is_valid(context_slot_index) ||
768 : !ImmutabilityBit::is_valid(immutable)) {
769 : return false;
770 : }
771 56686 : int config = ContextIndexBits::encode(script_context_index) |
772 113372 : SlotIndexBits::encode(context_slot_index) |
773 56686 : ImmutabilityBit::encode(immutable);
774 :
775 : SetFeedback(Smi::From31BitPattern(config));
776 : Isolate* isolate = GetIsolate();
777 113372 : SetFeedbackExtra(*FeedbackVector::UninitializedSentinel(isolate),
778 56686 : SKIP_WRITE_BARRIER);
779 56686 : return true;
780 : }
781 :
782 44655 : void FeedbackNexus::ConfigureHandlerMode(const MaybeObjectHandle& handler) {
783 : DCHECK(IsGlobalICKind(kind()));
784 : DCHECK(IC::IsHandler(*handler));
785 44655 : SetFeedback(HeapObjectReference::ClearedValue(GetIsolate()));
786 44655 : SetFeedbackExtra(*handler);
787 44655 : }
788 :
789 441 : void FeedbackNexus::ConfigureCloneObject(Handle<Map> source_map,
790 : Handle<Map> result_map) {
791 : Isolate* isolate = GetIsolate();
792 441 : MaybeObject maybe_feedback = GetFeedback();
793 : Handle<HeapObject> feedback(maybe_feedback->IsStrongOrWeak()
794 : ? maybe_feedback->GetHeapObject()
795 : : HeapObject(),
796 441 : isolate);
797 441 : switch (ic_state()) {
798 : case UNINITIALIZED:
799 : // Cache the first map seen which meets the fast case requirements.
800 315 : SetFeedback(HeapObjectReference::Weak(*source_map));
801 315 : SetFeedbackExtra(*result_map);
802 315 : break;
803 : case MONOMORPHIC:
804 108 : if (maybe_feedback->IsCleared() || feedback.is_identical_to(source_map) ||
805 : Map::cast(*feedback)->is_deprecated()) {
806 : // Remain in MONOMORPHIC state if previous feedback has been collected.
807 0 : SetFeedback(HeapObjectReference::Weak(*source_map));
808 0 : SetFeedbackExtra(*result_map);
809 : } else {
810 : // Transition to POLYMORPHIC.
811 : Handle<WeakFixedArray> array =
812 36 : EnsureArrayOfSize(2 * kCloneObjectPolymorphicEntrySize);
813 36 : array->Set(0, maybe_feedback);
814 72 : array->Set(1, GetFeedbackExtra());
815 72 : array->Set(2, HeapObjectReference::Weak(*source_map));
816 36 : array->Set(3, MaybeObject::FromObject(*result_map));
817 36 : SetFeedbackExtra(HeapObjectReference::ClearedValue(isolate));
818 : }
819 : break;
820 : case POLYMORPHIC: {
821 : const int kMaxElements =
822 90 : FLAG_max_polymorphic_map_count * kCloneObjectPolymorphicEntrySize;
823 : Handle<WeakFixedArray> array = Handle<WeakFixedArray>::cast(feedback);
824 : int i = 0;
825 333 : for (; i < array->length(); i += kCloneObjectPolymorphicEntrySize) {
826 : MaybeObject feedback = array->Get(i);
827 252 : if (feedback->IsCleared()) break;
828 : Handle<Map> cached_map(Map::cast(feedback->GetHeapObject()), isolate);
829 486 : if (cached_map.is_identical_to(source_map) ||
830 : cached_map->is_deprecated())
831 : break;
832 : }
833 :
834 90 : if (i >= array->length()) {
835 81 : if (i == kMaxElements) {
836 : // Transition to MEGAMORPHIC.
837 : MaybeObject sentinel = MaybeObject::FromObject(
838 27 : *FeedbackVector::MegamorphicSentinel(isolate));
839 27 : SetFeedback(sentinel, SKIP_WRITE_BARRIER);
840 27 : SetFeedbackExtra(HeapObjectReference::ClearedValue(isolate));
841 : break;
842 : }
843 :
844 : // Grow polymorphic feedback array.
845 : Handle<WeakFixedArray> new_array = EnsureArrayOfSize(
846 54 : array->length() + kCloneObjectPolymorphicEntrySize);
847 594 : for (int j = 0; j < array->length(); ++j) {
848 270 : new_array->Set(j, array->Get(j));
849 : }
850 54 : array = new_array;
851 : }
852 :
853 126 : array->Set(i, HeapObjectReference::Weak(*source_map));
854 126 : array->Set(i + 1, MaybeObject::FromObject(*result_map));
855 63 : break;
856 : }
857 :
858 : default:
859 0 : UNREACHABLE();
860 : }
861 441 : }
862 :
863 505272 : int FeedbackNexus::GetCallCount() {
864 : DCHECK(IsCallICKind(kind()));
865 :
866 1010544 : Object call_count = GetFeedbackExtra()->cast<Object>();
867 505272 : CHECK(call_count->IsSmi());
868 505272 : uint32_t value = static_cast<uint32_t>(Smi::ToInt(call_count));
869 505272 : return CallCountField::decode(value);
870 : }
871 :
872 1948 : void FeedbackNexus::SetSpeculationMode(SpeculationMode mode) {
873 : DCHECK(IsCallICKind(kind()));
874 :
875 3896 : Object call_count = GetFeedbackExtra()->cast<Object>();
876 1948 : CHECK(call_count->IsSmi());
877 1948 : uint32_t count = static_cast<uint32_t>(Smi::ToInt(call_count));
878 : uint32_t value = CallCountField::encode(CallCountField::decode(count));
879 1948 : int result = static_cast<int>(value | SpeculationModeField::encode(mode));
880 1948 : SetFeedbackExtra(Smi::FromInt(result), SKIP_WRITE_BARRIER);
881 1948 : }
882 :
883 464390 : SpeculationMode FeedbackNexus::GetSpeculationMode() {
884 : DCHECK(IsCallICKind(kind()));
885 :
886 928780 : Object call_count = GetFeedbackExtra()->cast<Object>();
887 464390 : CHECK(call_count->IsSmi());
888 464390 : uint32_t value = static_cast<uint32_t>(Smi::ToInt(call_count));
889 464390 : return SpeculationModeField::decode(value);
890 : }
891 :
892 505244 : float FeedbackNexus::ComputeCallFrequency() {
893 : DCHECK(IsCallICKind(kind()));
894 :
895 505244 : double const invocation_count = vector()->invocation_count();
896 505244 : double const call_count = GetCallCount();
897 505244 : if (invocation_count == 0) {
898 : // Prevent division by 0.
899 : return 0.0f;
900 : }
901 188602 : return static_cast<float>(call_count / invocation_count);
902 : }
903 :
904 1941665 : void FeedbackNexus::ConfigureMonomorphic(Handle<Name> name,
905 : Handle<Map> receiver_map,
906 : const MaybeObjectHandle& handler) {
907 : DCHECK(handler.is_null() || IC::IsHandler(*handler));
908 1941665 : if (kind() == FeedbackSlotKind::kStoreDataPropertyInLiteral) {
909 3257 : SetFeedback(HeapObjectReference::Weak(*receiver_map));
910 3257 : SetFeedbackExtra(*name);
911 : } else {
912 1938408 : if (name.is_null()) {
913 1924441 : SetFeedback(HeapObjectReference::Weak(*receiver_map));
914 1924449 : SetFeedbackExtra(*handler);
915 : } else {
916 13967 : Handle<WeakFixedArray> array = EnsureExtraArrayOfSize(2);
917 : SetFeedback(*name);
918 27934 : array->Set(0, HeapObjectReference::Weak(*receiver_map));
919 27934 : array->Set(1, *handler);
920 : }
921 : }
922 1941672 : }
923 :
924 226319 : void FeedbackNexus::ConfigurePolymorphic(Handle<Name> name,
925 : MapHandles const& maps,
926 : MaybeObjectHandles* handlers) {
927 : DCHECK_EQ(handlers->size(), maps.size());
928 226319 : int receiver_count = static_cast<int>(maps.size());
929 : DCHECK_GT(receiver_count, 1);
930 : Handle<WeakFixedArray> array;
931 226319 : if (name.is_null()) {
932 222275 : array = EnsureArrayOfSize(receiver_count * 2);
933 444552 : SetFeedbackExtra(*FeedbackVector::UninitializedSentinel(GetIsolate()),
934 222276 : SKIP_WRITE_BARRIER);
935 : } else {
936 4044 : array = EnsureExtraArrayOfSize(receiver_count * 2);
937 : SetFeedback(*name);
938 : }
939 :
940 1372103 : for (int current = 0; current < receiver_count; ++current) {
941 1145782 : Handle<Map> map = maps[current];
942 1145782 : array->Set(current * 2, HeapObjectReference::Weak(*map));
943 : DCHECK(IC::IsHandler(*handlers->at(current)));
944 1145779 : array->Set(current * 2 + 1, *handlers->at(current));
945 : }
946 226321 : }
947 :
948 1059681 : int FeedbackNexus::ExtractMaps(MapHandles* maps) const {
949 : DCHECK(IsLoadICKind(kind()) || IsStoreICKind(kind()) ||
950 : IsKeyedLoadICKind(kind()) || IsKeyedStoreICKind(kind()) ||
951 : IsStoreOwnICKind(kind()) || IsStoreDataPropertyInLiteralKind(kind()) ||
952 : IsStoreInArrayLiteralICKind(kind()) || IsKeyedHasICKind(kind()));
953 :
954 : Isolate* isolate = GetIsolate();
955 1059681 : MaybeObject feedback = GetFeedback();
956 1059681 : bool is_named_feedback = IsPropertyNameFeedback(feedback);
957 : HeapObject heap_object;
958 1654477 : if ((feedback->GetHeapObjectIfStrong(&heap_object) &&
959 1965182 : heap_object->IsWeakFixedArray()) ||
960 : is_named_feedback) {
961 : int found = 0;
962 : WeakFixedArray array;
963 160225 : if (is_named_feedback) {
964 : array =
965 12088 : WeakFixedArray::cast(GetFeedbackExtra()->GetHeapObjectAssumeStrong());
966 : } else {
967 : array = WeakFixedArray::cast(heap_object);
968 : }
969 : const int increment = 2;
970 : HeapObject heap_object;
971 554264 : for (int i = 0; i < array->length(); i += increment) {
972 : DCHECK(array->Get(i)->IsWeakOrCleared());
973 394039 : if (array->Get(i)->GetHeapObjectIfWeak(&heap_object)) {
974 : Map map = Map::cast(heap_object);
975 650794 : maps->push_back(handle(map, isolate));
976 325397 : found++;
977 : }
978 : }
979 : return found;
980 899456 : } else if (feedback->GetHeapObjectIfWeak(&heap_object)) {
981 : Map map = Map::cast(heap_object);
982 720907 : maps->push_back(handle(map, isolate));
983 : return 1;
984 973575 : } else if (feedback->GetHeapObjectIfStrong(&heap_object) &&
985 : heap_object ==
986 : heap_object->GetReadOnlyRoots().premonomorphic_symbol()) {
987 16190 : if (GetFeedbackExtra()->GetHeapObjectIfWeak(&heap_object)) {
988 : Map map = Map::cast(heap_object);
989 14810 : maps->push_back(handle(map, isolate));
990 : return 1;
991 : }
992 : }
993 :
994 : return 0;
995 : }
996 :
997 375536 : MaybeObjectHandle FeedbackNexus::FindHandlerForMap(Handle<Map> map) const {
998 : DCHECK(IsLoadICKind(kind()) || IsStoreICKind(kind()) ||
999 : IsKeyedLoadICKind(kind()) || IsKeyedStoreICKind(kind()) ||
1000 : IsStoreOwnICKind(kind()) || IsStoreDataPropertyInLiteralKind(kind()) ||
1001 : IsKeyedHasICKind(kind()));
1002 :
1003 375536 : MaybeObject feedback = GetFeedback();
1004 : Isolate* isolate = GetIsolate();
1005 375538 : bool is_named_feedback = IsPropertyNameFeedback(feedback);
1006 : HeapObject heap_object;
1007 501198 : if ((feedback->GetHeapObjectIfStrong(&heap_object) &&
1008 627621 : heap_object->IsWeakFixedArray()) ||
1009 : is_named_feedback) {
1010 : WeakFixedArray array;
1011 125662 : if (is_named_feedback) {
1012 : array =
1013 4420 : WeakFixedArray::cast(GetFeedbackExtra()->GetHeapObjectAssumeStrong());
1014 : } else {
1015 : array = WeakFixedArray::cast(heap_object);
1016 : }
1017 : const int increment = 2;
1018 : HeapObject heap_object;
1019 436729 : for (int i = 0; i < array->length(); i += increment) {
1020 : DCHECK(array->Get(i)->IsWeakOrCleared());
1021 311626 : if (array->Get(i)->GetHeapObjectIfWeak(&heap_object)) {
1022 : Map array_map = Map::cast(heap_object);
1023 243644 : if (array_map == *map && !array->Get(i + increment - 1)->IsCleared()) {
1024 : MaybeObject handler = array->Get(i + increment - 1);
1025 : DCHECK(IC::IsHandler(handler));
1026 : return handle(handler, isolate);
1027 : }
1028 : }
1029 : }
1030 249874 : } else if (feedback->GetHeapObjectIfWeak(&heap_object)) {
1031 : Map cell_map = Map::cast(heap_object);
1032 159864 : if (cell_map == *map && !GetFeedbackExtra()->IsCleared()) {
1033 12589 : MaybeObject handler = GetFeedbackExtra();
1034 : DCHECK(IC::IsHandler(handler));
1035 : return handle(handler, isolate);
1036 : }
1037 : }
1038 :
1039 362389 : return MaybeObjectHandle();
1040 : }
1041 :
1042 508789 : bool FeedbackNexus::FindHandlers(MaybeObjectHandles* code_list,
1043 : int length) const {
1044 : DCHECK(IsLoadICKind(kind()) || IsStoreICKind(kind()) ||
1045 : IsKeyedLoadICKind(kind()) || IsKeyedStoreICKind(kind()) ||
1046 : IsStoreOwnICKind(kind()) || IsStoreDataPropertyInLiteralKind(kind()) ||
1047 : IsStoreInArrayLiteralICKind(kind()) || IsKeyedHasICKind(kind()));
1048 :
1049 508789 : MaybeObject feedback = GetFeedback();
1050 : Isolate* isolate = GetIsolate();
1051 : int count = 0;
1052 508790 : bool is_named_feedback = IsPropertyNameFeedback(feedback);
1053 : HeapObject heap_object;
1054 737375 : if ((feedback->GetHeapObjectIfStrong(&heap_object) &&
1055 875857 : heap_object->IsWeakFixedArray()) ||
1056 : is_named_feedback) {
1057 : WeakFixedArray array;
1058 146841 : if (is_named_feedback) {
1059 : array =
1060 10240 : WeakFixedArray::cast(GetFeedbackExtra()->GetHeapObjectAssumeStrong());
1061 : } else {
1062 : array = WeakFixedArray::cast(heap_object);
1063 : }
1064 : const int increment = 2;
1065 : HeapObject heap_object;
1066 529746 : for (int i = 0; i < array->length(); i += increment) {
1067 : // Be sure to skip handlers whose maps have been cleared.
1068 : DCHECK(array->Get(i)->IsWeakOrCleared());
1069 697248 : if (array->Get(i)->GetHeapObjectIfWeak(&heap_object) &&
1070 : !array->Get(i + increment - 1)->IsCleared()) {
1071 : MaybeObject handler = array->Get(i + increment - 1);
1072 : DCHECK(IC::IsHandler(handler));
1073 628662 : code_list->push_back(handle(handler, isolate));
1074 314331 : count++;
1075 : }
1076 : }
1077 361948 : } else if (feedback->GetHeapObjectIfWeak(&heap_object)) {
1078 177103 : MaybeObject extra = GetFeedbackExtra();
1079 177104 : if (!extra->IsCleared()) {
1080 : DCHECK(IC::IsHandler(extra));
1081 352104 : code_list->push_back(handle(extra, isolate));
1082 : count++;
1083 : }
1084 : }
1085 508790 : return count == length;
1086 : }
1087 :
1088 50032 : Name FeedbackNexus::GetName() const {
1089 50032 : if (IsKeyedStoreICKind(kind()) || IsKeyedLoadICKind(kind()) ||
1090 : IsKeyedHasICKind(kind())) {
1091 50032 : MaybeObject feedback = GetFeedback();
1092 50032 : if (IsPropertyNameFeedback(feedback)) {
1093 : return Name::cast(feedback->GetHeapObjectAssumeStrong());
1094 : }
1095 : }
1096 22105 : return Name();
1097 : }
1098 :
1099 46301 : KeyedAccessLoadMode FeedbackNexus::GetKeyedAccessLoadMode() const {
1100 : DCHECK(IsKeyedLoadICKind(kind()) || IsKeyedHasICKind(kind()));
1101 : MapHandles maps;
1102 : MaybeObjectHandles handlers;
1103 :
1104 46301 : if (GetKeyType() == PROPERTY) return STANDARD_LOAD;
1105 :
1106 44042 : ExtractMaps(&maps);
1107 44042 : FindHandlers(&handlers, static_cast<int>(maps.size()));
1108 60795 : for (MaybeObjectHandle const& handler : handlers) {
1109 17648 : KeyedAccessLoadMode mode = LoadHandler::GetKeyedAccessLoadMode(*handler);
1110 17648 : if (mode != STANDARD_LOAD) return mode;
1111 : }
1112 :
1113 : return STANDARD_LOAD;
1114 : }
1115 :
1116 : namespace {
1117 :
1118 : bool BuiltinHasKeyedAccessStoreMode(int builtin_index) {
1119 : DCHECK(Builtins::IsBuiltinId(builtin_index));
1120 20188 : switch (builtin_index) {
1121 : case Builtins::kKeyedStoreIC_SloppyArguments_Standard:
1122 : case Builtins::kKeyedStoreIC_SloppyArguments_GrowNoTransitionHandleCOW:
1123 : case Builtins::kKeyedStoreIC_SloppyArguments_NoTransitionIgnoreOOB:
1124 : case Builtins::kKeyedStoreIC_SloppyArguments_NoTransitionHandleCOW:
1125 : case Builtins::kStoreFastElementIC_Standard:
1126 : case Builtins::kStoreFastElementIC_GrowNoTransitionHandleCOW:
1127 : case Builtins::kStoreFastElementIC_NoTransitionIgnoreOOB:
1128 : case Builtins::kStoreFastElementIC_NoTransitionHandleCOW:
1129 : case Builtins::kStoreInArrayLiteralIC_Slow_Standard:
1130 : case Builtins::kStoreInArrayLiteralIC_Slow_GrowNoTransitionHandleCOW:
1131 : case Builtins::kStoreInArrayLiteralIC_Slow_NoTransitionIgnoreOOB:
1132 : case Builtins::kStoreInArrayLiteralIC_Slow_NoTransitionHandleCOW:
1133 : case Builtins::kKeyedStoreIC_Slow_Standard:
1134 : case Builtins::kKeyedStoreIC_Slow_GrowNoTransitionHandleCOW:
1135 : case Builtins::kKeyedStoreIC_Slow_NoTransitionIgnoreOOB:
1136 : case Builtins::kKeyedStoreIC_Slow_NoTransitionHandleCOW:
1137 : case Builtins::kElementsTransitionAndStore_Standard:
1138 : case Builtins::kElementsTransitionAndStore_GrowNoTransitionHandleCOW:
1139 : case Builtins::kElementsTransitionAndStore_NoTransitionIgnoreOOB:
1140 : case Builtins::kElementsTransitionAndStore_NoTransitionHandleCOW:
1141 : return true;
1142 : default:
1143 : return false;
1144 : }
1145 : UNREACHABLE();
1146 : }
1147 :
1148 20179 : KeyedAccessStoreMode KeyedAccessStoreModeForBuiltin(int builtin_index) {
1149 : DCHECK(BuiltinHasKeyedAccessStoreMode(builtin_index));
1150 20179 : switch (builtin_index) {
1151 : case Builtins::kKeyedStoreIC_SloppyArguments_Standard:
1152 : case Builtins::kStoreInArrayLiteralIC_Slow_Standard:
1153 : case Builtins::kKeyedStoreIC_Slow_Standard:
1154 : case Builtins::kStoreFastElementIC_Standard:
1155 : case Builtins::kElementsTransitionAndStore_Standard:
1156 : return STANDARD_STORE;
1157 : case Builtins::kKeyedStoreIC_SloppyArguments_GrowNoTransitionHandleCOW:
1158 : case Builtins::kStoreInArrayLiteralIC_Slow_GrowNoTransitionHandleCOW:
1159 : case Builtins::kKeyedStoreIC_Slow_GrowNoTransitionHandleCOW:
1160 : case Builtins::kStoreFastElementIC_GrowNoTransitionHandleCOW:
1161 : case Builtins::kElementsTransitionAndStore_GrowNoTransitionHandleCOW:
1162 4701 : return STORE_AND_GROW_NO_TRANSITION_HANDLE_COW;
1163 : case Builtins::kKeyedStoreIC_SloppyArguments_NoTransitionIgnoreOOB:
1164 : case Builtins::kStoreInArrayLiteralIC_Slow_NoTransitionIgnoreOOB:
1165 : case Builtins::kKeyedStoreIC_Slow_NoTransitionIgnoreOOB:
1166 : case Builtins::kStoreFastElementIC_NoTransitionIgnoreOOB:
1167 : case Builtins::kElementsTransitionAndStore_NoTransitionIgnoreOOB:
1168 296 : return STORE_NO_TRANSITION_IGNORE_OUT_OF_BOUNDS;
1169 : case Builtins::kKeyedStoreIC_SloppyArguments_NoTransitionHandleCOW:
1170 : case Builtins::kStoreInArrayLiteralIC_Slow_NoTransitionHandleCOW:
1171 : case Builtins::kKeyedStoreIC_Slow_NoTransitionHandleCOW:
1172 : case Builtins::kStoreFastElementIC_NoTransitionHandleCOW:
1173 : case Builtins::kElementsTransitionAndStore_NoTransitionHandleCOW:
1174 683 : return STORE_NO_TRANSITION_HANDLE_COW;
1175 : default:
1176 0 : UNREACHABLE();
1177 : }
1178 : }
1179 :
1180 : } // namespace
1181 :
1182 73920 : KeyedAccessStoreMode FeedbackNexus::GetKeyedAccessStoreMode() const {
1183 : DCHECK(IsKeyedStoreICKind(kind()) || IsStoreInArrayLiteralICKind(kind()));
1184 : KeyedAccessStoreMode mode = STANDARD_STORE;
1185 : MapHandles maps;
1186 : MaybeObjectHandles handlers;
1187 :
1188 73920 : if (GetKeyType() == PROPERTY) return mode;
1189 :
1190 73121 : ExtractMaps(&maps);
1191 73120 : FindHandlers(&handlers, static_cast<int>(maps.size()));
1192 73148 : for (const MaybeObjectHandle& maybe_code_handler : handlers) {
1193 : // The first handler that isn't the slow handler will have the bits we need.
1194 : Handle<Code> handler;
1195 20206 : if (maybe_code_handler.object()->IsStoreHandler()) {
1196 : Handle<StoreHandler> data_handler =
1197 : Handle<StoreHandler>::cast(maybe_code_handler.object());
1198 : handler = handle(Code::cast(data_handler->smi_handler()),
1199 : vector()->GetIsolate());
1200 11702 : } else if (maybe_code_handler.object()->IsSmi()) {
1201 : // Skip proxy handlers.
1202 : DCHECK_EQ(*(maybe_code_handler.object()),
1203 : *StoreHandler::StoreProxy(GetIsolate()));
1204 : continue;
1205 : } else {
1206 : // Element store without prototype chain check.
1207 : handler = Handle<Code>::cast(maybe_code_handler.object());
1208 : }
1209 :
1210 20188 : if (handler->is_builtin()) {
1211 : const int builtin_index = handler->builtin_index();
1212 20188 : if (!BuiltinHasKeyedAccessStoreMode(builtin_index)) continue;
1213 :
1214 20179 : mode = KeyedAccessStoreModeForBuiltin(builtin_index);
1215 : break;
1216 : }
1217 : }
1218 :
1219 : return mode;
1220 : }
1221 :
1222 142330 : IcCheckType FeedbackNexus::GetKeyType() const {
1223 : DCHECK(IsKeyedStoreICKind(kind()) || IsKeyedLoadICKind(kind()) ||
1224 : IsStoreInArrayLiteralICKind(kind()) || IsKeyedHasICKind(kind()));
1225 142330 : MaybeObject feedback = GetFeedback();
1226 142332 : if (feedback == MaybeObject::FromObject(
1227 : *FeedbackVector::MegamorphicSentinel(GetIsolate()))) {
1228 : return static_cast<IcCheckType>(
1229 16632 : Smi::ToInt(GetFeedbackExtra()->cast<Object>()));
1230 : }
1231 134016 : return IsPropertyNameFeedback(feedback) ? PROPERTY : ELEMENT;
1232 : }
1233 :
1234 967534 : BinaryOperationHint FeedbackNexus::GetBinaryOperationFeedback() const {
1235 : DCHECK_EQ(kind(), FeedbackSlotKind::kBinaryOp);
1236 1935068 : int feedback = GetFeedback().ToSmi().value();
1237 967534 : return BinaryOperationHintFromFeedback(feedback);
1238 : }
1239 :
1240 526601 : CompareOperationHint FeedbackNexus::GetCompareOperationFeedback() const {
1241 : DCHECK_EQ(kind(), FeedbackSlotKind::kCompareOp);
1242 1053202 : int feedback = GetFeedback().ToSmi().value();
1243 526601 : return CompareOperationHintFromFeedback(feedback);
1244 : }
1245 :
1246 2924 : ForInHint FeedbackNexus::GetForInFeedback() const {
1247 : DCHECK_EQ(kind(), FeedbackSlotKind::kForIn);
1248 8554 : int feedback = GetFeedback().ToSmi().value();
1249 2924 : return ForInHintFromFeedback(feedback);
1250 : }
1251 :
1252 2835 : MaybeHandle<JSObject> FeedbackNexus::GetConstructorFeedback() const {
1253 : DCHECK_EQ(kind(), FeedbackSlotKind::kInstanceOf);
1254 : Isolate* isolate = GetIsolate();
1255 2835 : MaybeObject feedback = GetFeedback();
1256 : HeapObject heap_object;
1257 2835 : if (feedback->GetHeapObjectIfWeak(&heap_object)) {
1258 31 : return handle(JSObject::cast(heap_object), isolate);
1259 : }
1260 2804 : return MaybeHandle<JSObject>();
1261 : }
1262 :
1263 : namespace {
1264 :
1265 64 : bool InList(Handle<ArrayList> types, Handle<String> type) {
1266 124 : for (int i = 0; i < types->Length(); i++) {
1267 : Object obj = types->Get(i);
1268 76 : if (String::cast(obj)->Equals(*type)) {
1269 : return true;
1270 : }
1271 : }
1272 : return false;
1273 : }
1274 : } // anonymous namespace
1275 :
1276 228 : void FeedbackNexus::Collect(Handle<String> type, int position) {
1277 : DCHECK(IsTypeProfileKind(kind()));
1278 : DCHECK_GE(position, 0);
1279 : Isolate* isolate = GetIsolate();
1280 :
1281 228 : MaybeObject const feedback = GetFeedback();
1282 :
1283 : // Map source position to collection of types
1284 : Handle<SimpleNumberDictionary> types;
1285 :
1286 228 : if (feedback == MaybeObject::FromObject(
1287 : *FeedbackVector::UninitializedSentinel(isolate))) {
1288 68 : types = SimpleNumberDictionary::New(isolate, 1);
1289 : } else {
1290 : types = handle(
1291 : SimpleNumberDictionary::cast(feedback->GetHeapObjectAssumeStrong()),
1292 : isolate);
1293 : }
1294 :
1295 : Handle<ArrayList> position_specific_types;
1296 :
1297 456 : int entry = types->FindEntry(isolate, position);
1298 228 : if (entry == SimpleNumberDictionary::kNotFound) {
1299 164 : position_specific_types = ArrayList::New(isolate, 1);
1300 : types = SimpleNumberDictionary::Set(
1301 : isolate, types, position,
1302 328 : ArrayList::Add(isolate, position_specific_types, type));
1303 : } else {
1304 : DCHECK(types->ValueAt(entry)->IsArrayList());
1305 : position_specific_types =
1306 128 : handle(ArrayList::cast(types->ValueAt(entry)), isolate);
1307 64 : if (!InList(position_specific_types, type)) { // Add type
1308 : types = SimpleNumberDictionary::Set(
1309 : isolate, types, position,
1310 96 : ArrayList::Add(isolate, position_specific_types, type));
1311 : }
1312 : }
1313 : SetFeedback(*types);
1314 228 : }
1315 :
1316 108 : std::vector<int> FeedbackNexus::GetSourcePositions() const {
1317 : DCHECK(IsTypeProfileKind(kind()));
1318 : std::vector<int> source_positions;
1319 : Isolate* isolate = GetIsolate();
1320 :
1321 108 : MaybeObject const feedback = GetFeedback();
1322 :
1323 108 : if (feedback == MaybeObject::FromObject(
1324 : *FeedbackVector::UninitializedSentinel(isolate))) {
1325 : return source_positions;
1326 : }
1327 :
1328 : Handle<SimpleNumberDictionary> types(
1329 : SimpleNumberDictionary::cast(feedback->GetHeapObjectAssumeStrong()),
1330 : isolate);
1331 :
1332 768 : for (int index = SimpleNumberDictionary::kElementsStartIndex;
1333 : index < types->length(); index += SimpleNumberDictionary::kEntrySize) {
1334 : int key_index = index + SimpleNumberDictionary::kEntryKeyIndex;
1335 : Object key = types->get(key_index);
1336 352 : if (key->IsSmi()) {
1337 148 : int position = Smi::cast(key)->value();
1338 148 : source_positions.push_back(position);
1339 : }
1340 : }
1341 : return source_positions;
1342 : }
1343 :
1344 148 : std::vector<Handle<String>> FeedbackNexus::GetTypesForSourcePositions(
1345 : uint32_t position) const {
1346 : DCHECK(IsTypeProfileKind(kind()));
1347 : Isolate* isolate = GetIsolate();
1348 :
1349 148 : MaybeObject const feedback = GetFeedback();
1350 : std::vector<Handle<String>> types_for_position;
1351 148 : if (feedback == MaybeObject::FromObject(
1352 : *FeedbackVector::UninitializedSentinel(isolate))) {
1353 : return types_for_position;
1354 : }
1355 :
1356 : Handle<SimpleNumberDictionary> types(
1357 : SimpleNumberDictionary::cast(feedback->GetHeapObjectAssumeStrong()),
1358 : isolate);
1359 :
1360 148 : int entry = types->FindEntry(isolate, position);
1361 148 : if (entry == SimpleNumberDictionary::kNotFound) {
1362 : return types_for_position;
1363 : }
1364 : DCHECK(types->ValueAt(entry)->IsArrayList());
1365 : Handle<ArrayList> position_specific_types =
1366 296 : Handle<ArrayList>(ArrayList::cast(types->ValueAt(entry)), isolate);
1367 540 : for (int i = 0; i < position_specific_types->Length(); i++) {
1368 : Object t = position_specific_types->Get(i);
1369 196 : types_for_position.push_back(Handle<String>(String::cast(t), isolate));
1370 : }
1371 :
1372 : return types_for_position;
1373 : }
1374 :
1375 : namespace {
1376 :
1377 0 : Handle<JSObject> ConvertToJSObject(Isolate* isolate,
1378 : Handle<SimpleNumberDictionary> feedback) {
1379 : Handle<JSObject> type_profile =
1380 0 : isolate->factory()->NewJSObject(isolate->object_function());
1381 :
1382 0 : for (int index = SimpleNumberDictionary::kElementsStartIndex;
1383 : index < feedback->length();
1384 : index += SimpleNumberDictionary::kEntrySize) {
1385 : int key_index = index + SimpleNumberDictionary::kEntryKeyIndex;
1386 : Object key = feedback->get(key_index);
1387 0 : if (key->IsSmi()) {
1388 0 : int value_index = index + SimpleNumberDictionary::kEntryValueIndex;
1389 :
1390 : Handle<ArrayList> position_specific_types(
1391 : ArrayList::cast(feedback->get(value_index)), isolate);
1392 :
1393 : int position = Smi::ToInt(key);
1394 0 : JSObject::AddDataElement(
1395 : type_profile, position,
1396 : isolate->factory()->NewJSArrayWithElements(
1397 : ArrayList::Elements(isolate, position_specific_types)),
1398 0 : PropertyAttributes::NONE);
1399 : }
1400 : }
1401 0 : return type_profile;
1402 : }
1403 : } // namespace
1404 :
1405 0 : JSObject FeedbackNexus::GetTypeProfile() const {
1406 : DCHECK(IsTypeProfileKind(kind()));
1407 : Isolate* isolate = GetIsolate();
1408 :
1409 0 : MaybeObject const feedback = GetFeedback();
1410 :
1411 0 : if (feedback == MaybeObject::FromObject(
1412 : *FeedbackVector::UninitializedSentinel(isolate))) {
1413 0 : return *isolate->factory()->NewJSObject(isolate->object_function());
1414 : }
1415 :
1416 0 : return *ConvertToJSObject(isolate,
1417 : handle(SimpleNumberDictionary::cast(
1418 : feedback->GetHeapObjectAssumeStrong()),
1419 : isolate));
1420 : }
1421 :
1422 212 : void FeedbackNexus::ResetTypeProfile() {
1423 : DCHECK(IsTypeProfileKind(kind()));
1424 : SetFeedback(*FeedbackVector::UninitializedSentinel(GetIsolate()));
1425 212 : }
1426 :
1427 : } // namespace internal
1428 120216 : } // namespace v8
|