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/ic-inl.h"
8 : #include "src/objects.h"
9 : #include "src/objects/data-handler-inl.h"
10 : #include "src/objects/hash-table-inl.h"
11 : #include "src/objects/map-inl.h"
12 : #include "src/objects/object-macros.h"
13 :
14 : namespace v8 {
15 : namespace internal {
16 :
17 15207108 : FeedbackSlot FeedbackVectorSpec::AddSlot(FeedbackSlotKind kind) {
18 : int slot = slots();
19 15207108 : int entries_per_slot = FeedbackMetadata::GetSlotSize(kind);
20 : append(kind);
21 25442422 : for (int i = 1; i < entries_per_slot; i++) {
22 : append(FeedbackSlotKind::kInvalid);
23 : }
24 15207063 : return FeedbackSlot(slot);
25 : }
26 :
27 85 : FeedbackSlot FeedbackVectorSpec::AddTypeProfileSlot() {
28 85 : FeedbackSlot slot = AddSlot(FeedbackSlotKind::kTypeProfile);
29 85 : CHECK_EQ(FeedbackVectorSpec::kTypeProfileSlotIndex,
30 : FeedbackVector::GetIndex(slot));
31 85 : return slot;
32 : }
33 :
34 0 : bool FeedbackVectorSpec::HasTypeProfileSlot() const {
35 : FeedbackSlot slot =
36 : FeedbackVector::ToSlot(FeedbackVectorSpec::kTypeProfileSlotIndex);
37 0 : if (slots() <= slot.ToInt()) {
38 : return false;
39 : }
40 0 : return GetKind(slot) == FeedbackSlotKind::kTypeProfile;
41 : }
42 :
43 2033640 : static bool IsPropertyNameFeedback(MaybeObject feedback) {
44 2033640 : HeapObject heap_object;
45 2033640 : if (!feedback->GetHeapObjectIfStrong(&heap_object)) return false;
46 1026618 : if (heap_object->IsString()) {
47 : DCHECK(heap_object->IsInternalizedString());
48 : return true;
49 : }
50 999403 : if (!heap_object->IsSymbol()) return false;
51 568825 : Symbol symbol = Symbol::cast(heap_object);
52 568825 : ReadOnlyRoots roots = symbol->GetReadOnlyRoots();
53 43966 : return symbol != roots.uninitialized_symbol() &&
54 604464 : symbol != roots.premonomorphic_symbol() &&
55 : symbol != roots.megamorphic_symbol();
56 : }
57 :
58 0 : std::ostream& operator<<(std::ostream& os, FeedbackSlotKind kind) {
59 0 : return os << FeedbackMetadata::Kind2String(kind);
60 : }
61 :
62 409 : FeedbackSlotKind FeedbackMetadata::GetKind(FeedbackSlot slot) const {
63 : int index = VectorICComputer::index(0, slot.ToInt());
64 : int data = get(index);
65 42496590 : return VectorICComputer::decode(data, slot.ToInt());
66 : }
67 :
68 0 : void FeedbackMetadata::SetKind(FeedbackSlot slot, FeedbackSlotKind kind) {
69 : int index = VectorICComputer::index(0, slot.ToInt());
70 : int data = get(index);
71 48180930 : int new_data = VectorICComputer::encode(data, slot.ToInt(), kind);
72 : set(index, new_data);
73 0 : }
74 :
75 : // static
76 2104253 : Handle<FeedbackMetadata> FeedbackMetadata::New(Isolate* isolate,
77 : const FeedbackVectorSpec* spec) {
78 : Factory* factory = isolate->factory();
79 :
80 2104253 : const int slot_count = spec == nullptr ? 0 : spec->slots();
81 2104253 : if (slot_count == 0) {
82 : return factory->empty_feedback_metadata();
83 : }
84 : #ifdef DEBUG
85 : for (int i = 0; i < slot_count;) {
86 : DCHECK(spec);
87 : FeedbackSlotKind kind = spec->GetKind(FeedbackSlot(i));
88 : int entry_size = FeedbackMetadata::GetSlotSize(kind);
89 : for (int j = 1; j < entry_size; j++) {
90 : FeedbackSlotKind kind = spec->GetKind(FeedbackSlot(i + j));
91 : DCHECK_EQ(FeedbackSlotKind::kInvalid, kind);
92 : }
93 : i += entry_size;
94 : }
95 : #endif
96 :
97 1613454 : Handle<FeedbackMetadata> metadata = factory->NewFeedbackMetadata(slot_count);
98 :
99 : // Initialize the slots. The raw data section has already been pre-zeroed in
100 : // NewFeedbackMetadata.
101 25703931 : for (int i = 0; i < slot_count; i++) {
102 : DCHECK(spec);
103 : FeedbackSlot slot(i);
104 : FeedbackSlotKind kind = spec->GetKind(slot);
105 : metadata->SetKind(slot, kind);
106 : }
107 :
108 1613471 : return metadata;
109 : }
110 :
111 0 : bool FeedbackMetadata::SpecDiffersFrom(
112 : const FeedbackVectorSpec* other_spec) const {
113 0 : if (other_spec->slots() != slot_count()) {
114 : return true;
115 : }
116 :
117 : int slots = slot_count();
118 0 : for (int i = 0; i < slots;) {
119 : FeedbackSlot slot(i);
120 : FeedbackSlotKind kind = GetKind(slot);
121 0 : int entry_size = FeedbackMetadata::GetSlotSize(kind);
122 :
123 0 : if (kind != other_spec->GetKind(slot)) {
124 : return true;
125 : }
126 0 : i += entry_size;
127 : }
128 : return false;
129 : }
130 :
131 0 : const char* FeedbackMetadata::Kind2String(FeedbackSlotKind kind) {
132 0 : switch (kind) {
133 : case FeedbackSlotKind::kInvalid:
134 : return "Invalid";
135 : case FeedbackSlotKind::kCall:
136 0 : return "Call";
137 : case FeedbackSlotKind::kLoadProperty:
138 0 : return "LoadProperty";
139 : case FeedbackSlotKind::kLoadGlobalInsideTypeof:
140 0 : return "LoadGlobalInsideTypeof";
141 : case FeedbackSlotKind::kLoadGlobalNotInsideTypeof:
142 0 : return "LoadGlobalNotInsideTypeof";
143 : case FeedbackSlotKind::kLoadKeyed:
144 0 : return "LoadKeyed";
145 : case FeedbackSlotKind::kStoreNamedSloppy:
146 0 : return "StoreNamedSloppy";
147 : case FeedbackSlotKind::kStoreNamedStrict:
148 0 : return "StoreNamedStrict";
149 : case FeedbackSlotKind::kStoreOwnNamed:
150 0 : return "StoreOwnNamed";
151 : case FeedbackSlotKind::kStoreGlobalSloppy:
152 0 : return "StoreGlobalSloppy";
153 : case FeedbackSlotKind::kStoreGlobalStrict:
154 0 : return "StoreGlobalStrict";
155 : case FeedbackSlotKind::kStoreKeyedSloppy:
156 0 : return "StoreKeyedSloppy";
157 : case FeedbackSlotKind::kStoreKeyedStrict:
158 0 : return "StoreKeyedStrict";
159 : case FeedbackSlotKind::kStoreInArrayLiteral:
160 0 : return "StoreInArrayLiteral";
161 : case FeedbackSlotKind::kBinaryOp:
162 0 : return "BinaryOp";
163 : case FeedbackSlotKind::kCompareOp:
164 0 : return "CompareOp";
165 : case FeedbackSlotKind::kStoreDataPropertyInLiteral:
166 0 : return "StoreDataPropertyInLiteral";
167 : case FeedbackSlotKind::kCreateClosure:
168 0 : return "kCreateClosure";
169 : case FeedbackSlotKind::kLiteral:
170 0 : return "Literal";
171 : case FeedbackSlotKind::kTypeProfile:
172 0 : return "TypeProfile";
173 : case FeedbackSlotKind::kForIn:
174 0 : return "ForIn";
175 : case FeedbackSlotKind::kInstanceOf:
176 0 : return "InstanceOf";
177 : case FeedbackSlotKind::kCloneObject:
178 0 : return "CloneObject";
179 : case FeedbackSlotKind::kKindsNumber:
180 : break;
181 : }
182 0 : UNREACHABLE();
183 : }
184 :
185 565 : bool FeedbackMetadata::HasTypeProfileSlot() const {
186 : FeedbackSlot slot =
187 : FeedbackVector::ToSlot(FeedbackVectorSpec::kTypeProfileSlotIndex);
188 1090 : return slot.ToInt() < slot_count() &&
189 565 : GetKind(slot) == FeedbackSlotKind::kTypeProfile;
190 : }
191 :
192 20950702 : FeedbackSlotKind FeedbackVector::GetKind(FeedbackSlot slot) const {
193 : DCHECK(!is_empty());
194 20950731 : return metadata()->GetKind(slot);
195 : }
196 :
197 550 : FeedbackSlot FeedbackVector::GetTypeProfileSlot() const {
198 : DCHECK(metadata()->HasTypeProfileSlot());
199 : FeedbackSlot slot =
200 : FeedbackVector::ToSlot(FeedbackVectorSpec::kTypeProfileSlotIndex);
201 : DCHECK_EQ(FeedbackSlotKind::kTypeProfile, GetKind(slot));
202 550 : return slot;
203 : }
204 :
205 : // static
206 3073888 : Handle<FeedbackVector> FeedbackVector::New(Isolate* isolate,
207 : Handle<SharedFunctionInfo> shared) {
208 : Factory* factory = isolate->factory();
209 :
210 6147784 : const int slot_count = shared->feedback_metadata()->slot_count();
211 :
212 3073893 : Handle<FeedbackVector> vector = factory->NewFeedbackVector(shared, TENURED);
213 :
214 : DCHECK_EQ(vector->length(), slot_count);
215 :
216 : DCHECK_EQ(vector->shared_function_info(), *shared);
217 : DCHECK_EQ(
218 : vector->optimized_code_weak_or_smi(),
219 : MaybeObject::FromSmi(Smi::FromEnum(
220 : FLAG_log_function_events ? OptimizationMarker::kLogFirstExecution
221 : : OptimizationMarker::kNone)));
222 : DCHECK_EQ(vector->invocation_count(), 0);
223 : DCHECK_EQ(vector->profiler_ticks(), 0);
224 : DCHECK_EQ(vector->deopt_count(), 0);
225 :
226 : // Ensure we can skip the write barrier
227 : Handle<Object> uninitialized_sentinel = UninitializedSentinel(isolate);
228 : DCHECK_EQ(ReadOnlyRoots(isolate).uninitialized_symbol(),
229 : *uninitialized_sentinel);
230 : Handle<Oddball> undefined_value = factory->undefined_value();
231 27611231 : for (int i = 0; i < slot_count;) {
232 : FeedbackSlot slot(i);
233 42926928 : FeedbackSlotKind kind = shared->feedback_metadata()->GetKind(slot);
234 : int index = FeedbackVector::GetIndex(slot);
235 21463473 : int entry_size = FeedbackMetadata::GetSlotSize(kind);
236 :
237 : Object extra_value = *uninitialized_sentinel;
238 21463464 : switch (kind) {
239 : case FeedbackSlotKind::kLoadGlobalInsideTypeof:
240 : case FeedbackSlotKind::kLoadGlobalNotInsideTypeof:
241 : case FeedbackSlotKind::kStoreGlobalSloppy:
242 : case FeedbackSlotKind::kStoreGlobalStrict:
243 : vector->set(index, HeapObjectReference::ClearedValue(isolate),
244 12423327 : SKIP_WRITE_BARRIER);
245 6211673 : break;
246 : case FeedbackSlotKind::kForIn:
247 : case FeedbackSlotKind::kCompareOp:
248 : case FeedbackSlotKind::kBinaryOp:
249 5234478 : vector->set(index, Smi::kZero, SKIP_WRITE_BARRIER);
250 2617240 : break;
251 : case FeedbackSlotKind::kCreateClosure: {
252 3939867 : Handle<FeedbackCell> cell = factory->NewNoClosuresCell(undefined_value);
253 7879728 : vector->set(index, *cell);
254 : break;
255 : }
256 : case FeedbackSlotKind::kLiteral:
257 811168 : vector->set(index, Smi::kZero, SKIP_WRITE_BARRIER);
258 405588 : break;
259 : case FeedbackSlotKind::kCall:
260 11508532 : vector->set(index, *uninitialized_sentinel, SKIP_WRITE_BARRIER);
261 : extra_value = Smi::kZero;
262 5754266 : break;
263 : case FeedbackSlotKind::kCloneObject:
264 : case FeedbackSlotKind::kLoadProperty:
265 : case FeedbackSlotKind::kLoadKeyed:
266 : case FeedbackSlotKind::kStoreNamedSloppy:
267 : case FeedbackSlotKind::kStoreNamedStrict:
268 : case FeedbackSlotKind::kStoreOwnNamed:
269 : case FeedbackSlotKind::kStoreKeyedSloppy:
270 : case FeedbackSlotKind::kStoreKeyedStrict:
271 : case FeedbackSlotKind::kStoreInArrayLiteral:
272 : case FeedbackSlotKind::kStoreDataPropertyInLiteral:
273 : case FeedbackSlotKind::kTypeProfile:
274 : case FeedbackSlotKind::kInstanceOf:
275 5069746 : vector->set(index, *uninitialized_sentinel, SKIP_WRITE_BARRIER);
276 2534876 : break;
277 :
278 : case FeedbackSlotKind::kInvalid:
279 : case FeedbackSlotKind::kKindsNumber:
280 0 : UNREACHABLE();
281 : break;
282 : }
283 35941007 : for (int j = 1; j < entry_size; j++) {
284 43432521 : vector->set(index + j, extra_value, SKIP_WRITE_BARRIER);
285 : }
286 21463501 : i += entry_size;
287 : }
288 :
289 3073897 : Handle<FeedbackVector> result = Handle<FeedbackVector>::cast(vector);
290 6146450 : if (!isolate->is_best_effort_code_coverage() ||
291 : isolate->is_collecting_type_profile()) {
292 1429 : AddToVectorsForProfilingTools(isolate, result);
293 : }
294 3073897 : return result;
295 : }
296 :
297 : // static
298 1429 : void FeedbackVector::AddToVectorsForProfilingTools(
299 : Isolate* isolate, Handle<FeedbackVector> vector) {
300 : DCHECK(!isolate->is_best_effort_code_coverage() ||
301 : isolate->is_collecting_type_profile());
302 1429 : if (!vector->shared_function_info()->IsSubjectToDebugging()) return;
303 : Handle<ArrayList> list = Handle<ArrayList>::cast(
304 1429 : isolate->factory()->feedback_vectors_for_profiling_tools());
305 1429 : list = ArrayList::Add(isolate, list, vector);
306 1429 : isolate->SetFeedbackVectorsForProfilingTools(*list);
307 : }
308 :
309 : // static
310 23085 : void FeedbackVector::SetOptimizedCode(Handle<FeedbackVector> vector,
311 : Handle<Code> code) {
312 : DCHECK_EQ(code->kind(), Code::OPTIMIZED_FUNCTION);
313 46170 : vector->set_optimized_code_weak_or_smi(HeapObjectReference::Weak(*code));
314 23085 : }
315 :
316 0 : void FeedbackVector::ClearOptimizedCode() {
317 : DCHECK(has_optimized_code());
318 : SetOptimizationMarker(OptimizationMarker::kNone);
319 0 : }
320 :
321 754440 : void FeedbackVector::ClearOptimizationMarker() {
322 : DCHECK(!has_optimized_code());
323 : SetOptimizationMarker(OptimizationMarker::kNone);
324 754439 : }
325 :
326 497015 : void FeedbackVector::SetOptimizationMarker(OptimizationMarker marker) {
327 1253774 : set_optimized_code_weak_or_smi(MaybeObject::FromSmi(Smi::FromEnum(marker)));
328 497015 : }
329 :
330 4399729 : void FeedbackVector::EvictOptimizedCodeMarkedForDeoptimization(
331 : SharedFunctionInfo shared, const char* reason) {
332 4399729 : MaybeObject slot = optimized_code_weak_or_smi();
333 4399729 : if (slot->IsSmi()) {
334 3940380 : return;
335 : }
336 :
337 459560 : if (slot->IsCleared()) {
338 : ClearOptimizationMarker();
339 : return;
340 : }
341 :
342 918687 : Code code = Code::cast(slot->GetHeapObject());
343 459344 : if (code->marked_for_deoptimization()) {
344 2102 : if (FLAG_trace_deopt) {
345 : PrintF("[evicting optimizing code marked for deoptimization (%s) for ",
346 0 : reason);
347 0 : shared->ShortPrint();
348 0 : PrintF("]\n");
349 : }
350 2102 : if (!code->deopt_already_counted()) {
351 : increment_deopt_count();
352 1289 : code->set_deopt_already_counted(true);
353 : }
354 : ClearOptimizedCode();
355 : }
356 : }
357 :
358 52533 : bool FeedbackVector::ClearSlots(Isolate* isolate) {
359 : MaybeObject uninitialized_sentinel = MaybeObject::FromObject(
360 52533 : FeedbackVector::RawUninitializedSentinel(isolate));
361 :
362 : bool feedback_updated = false;
363 : FeedbackMetadataIterator iter(metadata());
364 133576 : while (iter.HasNext()) {
365 81043 : FeedbackSlot slot = iter.Next();
366 :
367 : MaybeObject obj = Get(slot);
368 81043 : if (obj != uninitialized_sentinel) {
369 : FeedbackNexus nexus(*this, slot);
370 55764 : feedback_updated |= nexus.Clear();
371 : }
372 : }
373 52533 : return feedback_updated;
374 : }
375 :
376 26116 : void FeedbackVector::AssertNoLegacyTypes(MaybeObject object) {
377 : #ifdef DEBUG
378 : HeapObject heap_object;
379 : if (object->GetHeapObject(&heap_object)) {
380 : // Instead of FixedArray, the Feedback and the Extra should contain
381 : // WeakFixedArrays. The only allowed FixedArray subtype is HashTable.
382 : DCHECK_IMPLIES(heap_object->IsFixedArray(), heap_object->IsHashTable());
383 : }
384 : #endif
385 26116 : }
386 :
387 228270 : Handle<WeakFixedArray> FeedbackNexus::EnsureArrayOfSize(int length) {
388 228270 : Isolate* isolate = GetIsolate();
389 228276 : HeapObject heap_object;
390 541787 : if (GetFeedback()->GetHeapObjectIfStrong(&heap_object) &&
391 313326 : heap_object->IsWeakFixedArray() &&
392 : WeakFixedArray::cast(heap_object)->length() == length) {
393 : return handle(WeakFixedArray::cast(heap_object), isolate);
394 : }
395 222008 : Handle<WeakFixedArray> array = isolate->factory()->NewWeakFixedArray(length);
396 : SetFeedback(*array);
397 222008 : return array;
398 : }
399 :
400 16830 : Handle<WeakFixedArray> FeedbackNexus::EnsureExtraArrayOfSize(int length) {
401 16830 : Isolate* isolate = GetIsolate();
402 16830 : HeapObject heap_object;
403 37525 : if (GetFeedbackExtra()->GetHeapObjectIfStrong(&heap_object) &&
404 20686 : heap_object->IsWeakFixedArray() &&
405 : WeakFixedArray::cast(heap_object)->length() == length) {
406 : return handle(WeakFixedArray::cast(heap_object), isolate);
407 : }
408 16604 : Handle<WeakFixedArray> array = isolate->factory()->NewWeakFixedArray(length);
409 16604 : SetFeedbackExtra(*array);
410 16604 : return array;
411 : }
412 :
413 90128 : void FeedbackNexus::ConfigureUninitialized() {
414 45064 : Isolate* isolate = GetIsolate();
415 45064 : switch (kind()) {
416 : case FeedbackSlotKind::kStoreGlobalSloppy:
417 : case FeedbackSlotKind::kStoreGlobalStrict:
418 : case FeedbackSlotKind::kLoadGlobalNotInsideTypeof:
419 : case FeedbackSlotKind::kLoadGlobalInsideTypeof: {
420 : SetFeedback(HeapObjectReference::ClearedValue(isolate),
421 7553 : SKIP_WRITE_BARRIER);
422 : SetFeedbackExtra(*FeedbackVector::UninitializedSentinel(isolate),
423 7553 : SKIP_WRITE_BARRIER);
424 7553 : break;
425 : }
426 : case FeedbackSlotKind::kCloneObject:
427 : case FeedbackSlotKind::kCall: {
428 : SetFeedback(*FeedbackVector::UninitializedSentinel(isolate),
429 : SKIP_WRITE_BARRIER);
430 6477 : SetFeedbackExtra(Smi::kZero, SKIP_WRITE_BARRIER);
431 6477 : break;
432 : }
433 : case FeedbackSlotKind::kInstanceOf: {
434 : SetFeedback(*FeedbackVector::UninitializedSentinel(isolate),
435 : SKIP_WRITE_BARRIER);
436 0 : break;
437 : }
438 : case FeedbackSlotKind::kStoreNamedSloppy:
439 : case FeedbackSlotKind::kStoreNamedStrict:
440 : case FeedbackSlotKind::kStoreKeyedSloppy:
441 : case FeedbackSlotKind::kStoreKeyedStrict:
442 : case FeedbackSlotKind::kStoreInArrayLiteral:
443 : case FeedbackSlotKind::kStoreOwnNamed:
444 : case FeedbackSlotKind::kLoadProperty:
445 : case FeedbackSlotKind::kLoadKeyed:
446 : case FeedbackSlotKind::kStoreDataPropertyInLiteral: {
447 : SetFeedback(*FeedbackVector::UninitializedSentinel(isolate),
448 : SKIP_WRITE_BARRIER);
449 : SetFeedbackExtra(*FeedbackVector::UninitializedSentinel(isolate),
450 31034 : SKIP_WRITE_BARRIER);
451 31034 : break;
452 : }
453 : default:
454 0 : UNREACHABLE();
455 : }
456 45064 : }
457 :
458 55764 : bool FeedbackNexus::Clear() {
459 : bool feedback_updated = false;
460 :
461 : switch (kind()) {
462 : case FeedbackSlotKind::kCreateClosure:
463 : case FeedbackSlotKind::kTypeProfile:
464 : // We don't clear these kinds ever.
465 : break;
466 :
467 : case FeedbackSlotKind::kCompareOp:
468 : case FeedbackSlotKind::kForIn:
469 : case FeedbackSlotKind::kBinaryOp:
470 : // We don't clear these, either.
471 : break;
472 :
473 : case FeedbackSlotKind::kLiteral:
474 : SetFeedback(Smi::kZero, SKIP_WRITE_BARRIER);
475 : feedback_updated = true;
476 13 : break;
477 :
478 : case FeedbackSlotKind::kStoreNamedSloppy:
479 : case FeedbackSlotKind::kStoreNamedStrict:
480 : case FeedbackSlotKind::kStoreKeyedSloppy:
481 : case FeedbackSlotKind::kStoreKeyedStrict:
482 : case FeedbackSlotKind::kStoreInArrayLiteral:
483 : case FeedbackSlotKind::kStoreOwnNamed:
484 : case FeedbackSlotKind::kLoadProperty:
485 : case FeedbackSlotKind::kLoadKeyed:
486 : case FeedbackSlotKind::kStoreGlobalSloppy:
487 : case FeedbackSlotKind::kStoreGlobalStrict:
488 : case FeedbackSlotKind::kLoadGlobalNotInsideTypeof:
489 : case FeedbackSlotKind::kLoadGlobalInsideTypeof:
490 : case FeedbackSlotKind::kCall:
491 : case FeedbackSlotKind::kInstanceOf:
492 : case FeedbackSlotKind::kStoreDataPropertyInLiteral:
493 : case FeedbackSlotKind::kCloneObject:
494 47600 : if (!IsCleared()) {
495 45064 : ConfigureUninitialized();
496 : feedback_updated = true;
497 : }
498 : break;
499 :
500 : case FeedbackSlotKind::kInvalid:
501 : case FeedbackSlotKind::kKindsNumber:
502 0 : UNREACHABLE();
503 : break;
504 : }
505 55764 : return feedback_updated;
506 : }
507 :
508 558252 : void FeedbackNexus::ConfigurePremonomorphic(Handle<Map> receiver_map) {
509 558252 : SetFeedback(*FeedbackVector::PremonomorphicSentinel(GetIsolate()),
510 : SKIP_WRITE_BARRIER);
511 558265 : SetFeedbackExtra(HeapObjectReference::Weak(*receiver_map));
512 558273 : }
513 :
514 126 : bool FeedbackNexus::ConfigureMegamorphic() {
515 : DisallowHeapAllocation no_gc;
516 126 : Isolate* isolate = GetIsolate();
517 : MaybeObject sentinel =
518 : MaybeObject::FromObject(*FeedbackVector::MegamorphicSentinel(isolate));
519 252 : if (GetFeedback() != sentinel) {
520 126 : SetFeedback(sentinel, SKIP_WRITE_BARRIER);
521 126 : SetFeedbackExtra(HeapObjectReference::ClearedValue(isolate));
522 126 : return true;
523 : }
524 :
525 : return false;
526 : }
527 :
528 47038 : bool FeedbackNexus::ConfigureMegamorphic(IcCheckType property_type) {
529 : DisallowHeapAllocation no_gc;
530 47038 : Isolate* isolate = GetIsolate();
531 : bool changed = false;
532 : MaybeObject sentinel =
533 : MaybeObject::FromObject(*FeedbackVector::MegamorphicSentinel(isolate));
534 94078 : if (GetFeedback() != sentinel) {
535 42960 : SetFeedback(sentinel, SKIP_WRITE_BARRIER);
536 : changed = true;
537 : }
538 :
539 47039 : Smi extra = Smi::FromInt(static_cast<int>(property_type));
540 51118 : if (changed || GetFeedbackExtra() != MaybeObject::FromSmi(extra)) {
541 42960 : SetFeedbackExtra(extra, SKIP_WRITE_BARRIER);
542 : changed = true;
543 : }
544 47039 : return changed;
545 : }
546 :
547 114806 : Map FeedbackNexus::FindFirstMap() const {
548 : MapHandles maps;
549 114806 : ExtractMaps(&maps);
550 229612 : if (maps.size() > 0) return *maps.at(0);
551 4 : return Map();
552 : }
553 :
554 22164451 : InlineCacheState FeedbackNexus::StateFromFeedback() const {
555 11082224 : Isolate* isolate = GetIsolate();
556 11082220 : MaybeObject feedback = GetFeedback();
557 :
558 11082227 : switch (kind()) {
559 : case FeedbackSlotKind::kCreateClosure:
560 : return MONOMORPHIC;
561 :
562 : case FeedbackSlotKind::kLiteral:
563 50985 : if (feedback->IsSmi()) return UNINITIALIZED;
564 7900 : return MONOMORPHIC;
565 :
566 : case FeedbackSlotKind::kStoreGlobalSloppy:
567 : case FeedbackSlotKind::kStoreGlobalStrict:
568 : case FeedbackSlotKind::kLoadGlobalNotInsideTypeof:
569 : case FeedbackSlotKind::kLoadGlobalInsideTypeof: {
570 4969352 : if (feedback->IsSmi()) return MONOMORPHIC;
571 :
572 : DCHECK(feedback->IsWeakOrCleared());
573 4968998 : MaybeObject extra = GetFeedbackExtra();
574 9720199 : if (!feedback->IsCleared() ||
575 : extra != MaybeObject::FromObject(
576 : *FeedbackVector::UninitializedSentinel(isolate))) {
577 : return MONOMORPHIC;
578 : }
579 4746527 : return UNINITIALIZED;
580 : }
581 :
582 : case FeedbackSlotKind::kStoreNamedSloppy:
583 : case FeedbackSlotKind::kStoreNamedStrict:
584 : case FeedbackSlotKind::kStoreKeyedSloppy:
585 : case FeedbackSlotKind::kStoreKeyedStrict:
586 : case FeedbackSlotKind::kStoreInArrayLiteral:
587 : case FeedbackSlotKind::kStoreOwnNamed:
588 : case FeedbackSlotKind::kLoadProperty:
589 : case FeedbackSlotKind::kLoadKeyed: {
590 4466698 : if (feedback == MaybeObject::FromObject(
591 : *FeedbackVector::UninitializedSentinel(isolate))) {
592 : return UNINITIALIZED;
593 : }
594 2720669 : if (feedback == MaybeObject::FromObject(
595 : *FeedbackVector::MegamorphicSentinel(isolate))) {
596 : return MEGAMORPHIC;
597 : }
598 2051287 : if (feedback == MaybeObject::FromObject(
599 : *FeedbackVector::PremonomorphicSentinel(isolate))) {
600 : return PREMONOMORPHIC;
601 : }
602 912925 : if (feedback->IsWeakOrCleared()) {
603 : // Don't check if the map is cleared.
604 : return MONOMORPHIC;
605 : }
606 218093 : HeapObject heap_object;
607 218093 : if (feedback->GetHeapObjectIfStrong(&heap_object)) {
608 218093 : if (heap_object->IsWeakFixedArray()) {
609 : // Determine state purely by our structure, don't check if the maps
610 : // are cleared.
611 : return POLYMORPHIC;
612 : }
613 15834 : if (heap_object->IsName()) {
614 : DCHECK(IsKeyedLoadICKind(kind()) || IsKeyedStoreICKind(kind()));
615 15834 : Object extra = GetFeedbackExtra()->GetHeapObjectAssumeStrong();
616 : WeakFixedArray extra_array = WeakFixedArray::cast(extra);
617 15834 : return extra_array->length() > 2 ? POLYMORPHIC : MONOMORPHIC;
618 : }
619 : }
620 0 : UNREACHABLE();
621 : }
622 : case FeedbackSlotKind::kCall: {
623 904232 : HeapObject heap_object;
624 904231 : if (feedback == MaybeObject::FromObject(
625 : *FeedbackVector::MegamorphicSentinel(isolate))) {
626 : return GENERIC;
627 2307984 : } else if (feedback->IsWeakOrCleared() ||
628 1084747 : (feedback->GetHeapObjectIfStrong(&heap_object) &&
629 : heap_object->IsAllocationSite())) {
630 : return MONOMORPHIC;
631 : }
632 :
633 1081077 : CHECK_EQ(feedback, MaybeObject::FromObject(
634 : *FeedbackVector::UninitializedSentinel(isolate)));
635 : return UNINITIALIZED;
636 : }
637 : case FeedbackSlotKind::kBinaryOp: {
638 274881 : BinaryOperationHint hint = GetBinaryOperationFeedback();
639 274881 : if (hint == BinaryOperationHint::kNone) {
640 : return UNINITIALIZED;
641 259043 : } else if (hint == BinaryOperationHint::kAny) {
642 : return GENERIC;
643 : }
644 :
645 255702 : return MONOMORPHIC;
646 : }
647 : case FeedbackSlotKind::kCompareOp: {
648 154246 : CompareOperationHint hint = GetCompareOperationFeedback();
649 154246 : if (hint == CompareOperationHint::kNone) {
650 : return UNINITIALIZED;
651 140090 : } else if (hint == CompareOperationHint::kAny) {
652 : return GENERIC;
653 : }
654 :
655 104190 : return MONOMORPHIC;
656 : }
657 : case FeedbackSlotKind::kForIn: {
658 1388 : ForInHint hint = GetForInFeedback();
659 1388 : if (hint == ForInHint::kNone) {
660 : return UNINITIALIZED;
661 1363 : } else if (hint == ForInHint::kAny) {
662 : return GENERIC;
663 : }
664 507 : return MONOMORPHIC;
665 : }
666 : case FeedbackSlotKind::kInstanceOf: {
667 4726 : if (feedback == MaybeObject::FromObject(
668 : *FeedbackVector::UninitializedSentinel(isolate))) {
669 : return UNINITIALIZED;
670 1784 : } else if (feedback ==
671 : MaybeObject::FromObject(
672 : *FeedbackVector::MegamorphicSentinel(isolate))) {
673 : return MEGAMORPHIC;
674 : }
675 1567 : return MONOMORPHIC;
676 : }
677 : case FeedbackSlotKind::kStoreDataPropertyInLiteral: {
678 254847 : if (feedback == MaybeObject::FromObject(
679 : *FeedbackVector::UninitializedSentinel(isolate))) {
680 : return UNINITIALIZED;
681 250590 : } else if (feedback->IsWeakOrCleared()) {
682 : // Don't check if the map is cleared.
683 : return MONOMORPHIC;
684 : }
685 :
686 20864 : return MEGAMORPHIC;
687 : }
688 : case FeedbackSlotKind::kTypeProfile: {
689 0 : if (feedback == MaybeObject::FromObject(
690 : *FeedbackVector::UninitializedSentinel(isolate))) {
691 : return UNINITIALIZED;
692 : }
693 0 : return MONOMORPHIC;
694 : }
695 :
696 : case FeedbackSlotKind::kCloneObject: {
697 849 : if (feedback == MaybeObject::FromObject(
698 : *FeedbackVector::UninitializedSentinel(isolate))) {
699 : return UNINITIALIZED;
700 : }
701 208 : if (feedback == MaybeObject::FromObject(
702 : *FeedbackVector::MegamorphicSentinel(isolate))) {
703 : return MEGAMORPHIC;
704 : }
705 208 : if (feedback->IsWeakOrCleared()) {
706 : return MONOMORPHIC;
707 : }
708 :
709 : DCHECK(feedback->GetHeapObjectAssumeStrong()->IsWeakFixedArray());
710 126 : return POLYMORPHIC;
711 : }
712 :
713 : case FeedbackSlotKind::kInvalid:
714 : case FeedbackSlotKind::kKindsNumber:
715 0 : UNREACHABLE();
716 : break;
717 : }
718 0 : return UNINITIALIZED;
719 : }
720 :
721 5354111 : void FeedbackNexus::ConfigurePropertyCellMode(Handle<PropertyCell> cell) {
722 : DCHECK(IsGlobalICKind(kind()));
723 5354111 : Isolate* isolate = GetIsolate();
724 5354114 : SetFeedback(HeapObjectReference::Weak(*cell));
725 : SetFeedbackExtra(*FeedbackVector::UninitializedSentinel(isolate),
726 5354119 : SKIP_WRITE_BARRIER);
727 5354119 : }
728 :
729 74370 : bool FeedbackNexus::ConfigureLexicalVarMode(int script_context_index,
730 : int context_slot_index) {
731 : DCHECK(IsGlobalICKind(kind()));
732 : DCHECK_LE(0, script_context_index);
733 : DCHECK_LE(0, context_slot_index);
734 223111 : if (!ContextIndexBits::is_valid(script_context_index) ||
735 74371 : !SlotIndexBits::is_valid(context_slot_index)) {
736 : return false;
737 : }
738 74373 : int config = ContextIndexBits::encode(script_context_index) |
739 148746 : SlotIndexBits::encode(context_slot_index);
740 :
741 : SetFeedback(Smi::FromInt(config));
742 74372 : Isolate* isolate = GetIsolate();
743 : SetFeedbackExtra(*FeedbackVector::UninitializedSentinel(isolate),
744 74374 : SKIP_WRITE_BARRIER);
745 74374 : return true;
746 : }
747 :
748 44756 : void FeedbackNexus::ConfigureHandlerMode(const MaybeObjectHandle& handler) {
749 : DCHECK(IsGlobalICKind(kind()));
750 : DCHECK(IC::IsHandler(*handler));
751 89512 : SetFeedback(HeapObjectReference::ClearedValue(GetIsolate()));
752 44756 : SetFeedbackExtra(*handler);
753 44756 : }
754 :
755 387 : void FeedbackNexus::ConfigureCloneObject(Handle<Map> source_map,
756 : Handle<Map> result_map) {
757 387 : Isolate* isolate = GetIsolate();
758 387 : MaybeObject maybe_feedback = GetFeedback();
759 : Handle<HeapObject> feedback(maybe_feedback->IsStrongOrWeak()
760 : ? maybe_feedback->GetHeapObject()
761 : : HeapObject(),
762 387 : isolate);
763 387 : switch (ic_state()) {
764 : case UNINITIALIZED:
765 : // Cache the first map seen which meets the fast case requirements.
766 297 : SetFeedback(HeapObjectReference::Weak(*source_map));
767 297 : SetFeedbackExtra(*result_map);
768 297 : break;
769 : case MONOMORPHIC:
770 108 : if (maybe_feedback->IsCleared() || feedback.is_identical_to(source_map) ||
771 54 : Map::cast(*feedback)->is_deprecated()) {
772 : // Remain in MONOMORPHIC state if previous feedback has been collected.
773 0 : SetFeedback(HeapObjectReference::Weak(*source_map));
774 0 : SetFeedbackExtra(*result_map);
775 : } else {
776 : // Transition to POLYMORPHIC.
777 : Handle<WeakFixedArray> array =
778 27 : EnsureArrayOfSize(2 * kCloneObjectPolymorphicEntrySize);
779 27 : array->Set(0, maybe_feedback);
780 54 : array->Set(1, GetFeedbackExtra());
781 54 : array->Set(2, HeapObjectReference::Weak(*source_map));
782 27 : array->Set(3, MaybeObject::FromObject(*result_map));
783 27 : SetFeedbackExtra(HeapObjectReference::ClearedValue(isolate));
784 : }
785 : break;
786 : case POLYMORPHIC: {
787 : static constexpr int kMaxElements =
788 : IC::kMaxPolymorphicMapCount * kCloneObjectPolymorphicEntrySize;
789 63 : Handle<WeakFixedArray> array = Handle<WeakFixedArray>::cast(feedback);
790 : int i = 0;
791 450 : for (; i < array->length(); i += kCloneObjectPolymorphicEntrySize) {
792 171 : MaybeObject feedback = array->Get(i);
793 171 : if (feedback->IsCleared()) break;
794 324 : Handle<Map> cached_map(Map::cast(feedback->GetHeapObject()), isolate);
795 486 : if (cached_map.is_identical_to(source_map) ||
796 486 : cached_map->is_deprecated())
797 : break;
798 : }
799 :
800 63 : if (i >= array->length()) {
801 54 : if (i == kMaxElements) {
802 : // Transition to MEGAMORPHIC.
803 : MaybeObject sentinel = MaybeObject::FromObject(
804 18 : *FeedbackVector::MegamorphicSentinel(isolate));
805 18 : SetFeedback(sentinel, SKIP_WRITE_BARRIER);
806 18 : SetFeedbackExtra(HeapObjectReference::ClearedValue(isolate));
807 : break;
808 : }
809 :
810 : // Grow polymorphic feedback array.
811 : Handle<WeakFixedArray> new_array = EnsureArrayOfSize(
812 36 : array->length() + kCloneObjectPolymorphicEntrySize);
813 432 : for (int j = 0; j < array->length(); ++j) {
814 360 : new_array->Set(j, array->Get(j));
815 : }
816 36 : array = new_array;
817 : }
818 :
819 90 : array->Set(i, HeapObjectReference::Weak(*source_map));
820 90 : array->Set(i + 1, MaybeObject::FromObject(*result_map));
821 45 : break;
822 : }
823 :
824 : default:
825 0 : UNREACHABLE();
826 : }
827 387 : }
828 :
829 495242 : int FeedbackNexus::GetCallCount() {
830 : DCHECK(IsCallICKind(kind()));
831 :
832 495242 : Object call_count = GetFeedbackExtra()->cast<Object>();
833 495243 : CHECK(call_count->IsSmi());
834 495243 : uint32_t value = static_cast<uint32_t>(Smi::ToInt(call_count));
835 495243 : return CallCountField::decode(value);
836 : }
837 :
838 2004 : void FeedbackNexus::SetSpeculationMode(SpeculationMode mode) {
839 : DCHECK(IsCallICKind(kind()));
840 :
841 2004 : Object call_count = GetFeedbackExtra()->cast<Object>();
842 2004 : CHECK(call_count->IsSmi());
843 2004 : uint32_t count = static_cast<uint32_t>(Smi::ToInt(call_count));
844 : uint32_t value = CallCountField::encode(CallCountField::decode(count));
845 2004 : int result = static_cast<int>(value | SpeculationModeField::encode(mode));
846 2004 : SetFeedbackExtra(Smi::FromInt(result), SKIP_WRITE_BARRIER);
847 2004 : }
848 :
849 455240 : SpeculationMode FeedbackNexus::GetSpeculationMode() {
850 : DCHECK(IsCallICKind(kind()));
851 :
852 455240 : Object call_count = GetFeedbackExtra()->cast<Object>();
853 455241 : CHECK(call_count->IsSmi());
854 455241 : uint32_t value = static_cast<uint32_t>(Smi::ToInt(call_count));
855 455241 : return SpeculationModeField::decode(value);
856 : }
857 :
858 495214 : float FeedbackNexus::ComputeCallFrequency() {
859 : DCHECK(IsCallICKind(kind()));
860 :
861 990428 : double const invocation_count = vector()->invocation_count();
862 495214 : double const call_count = GetCallCount();
863 495215 : if (invocation_count == 0) {
864 : // Prevent division by 0.
865 : return 0.0f;
866 : }
867 193564 : return static_cast<float>(call_count / invocation_count);
868 : }
869 :
870 1571899 : void FeedbackNexus::ConfigureMonomorphic(Handle<Name> name,
871 : Handle<Map> receiver_map,
872 1571899 : const MaybeObjectHandle& handler) {
873 : DCHECK(handler.is_null() || IC::IsHandler(*handler));
874 1571899 : if (kind() == FeedbackSlotKind::kStoreDataPropertyInLiteral) {
875 3310 : SetFeedback(HeapObjectReference::Weak(*receiver_map));
876 3310 : SetFeedbackExtra(*name);
877 : } else {
878 1568589 : if (name.is_null()) {
879 1555400 : SetFeedback(HeapObjectReference::Weak(*receiver_map));
880 1555414 : SetFeedbackExtra(*handler);
881 : } else {
882 13194 : Handle<WeakFixedArray> array = EnsureExtraArrayOfSize(2);
883 : SetFeedback(*name);
884 26388 : array->Set(0, HeapObjectReference::Weak(*receiver_map));
885 26388 : array->Set(1, *handler);
886 : }
887 : }
888 1571918 : }
889 :
890 231845 : void FeedbackNexus::ConfigurePolymorphic(Handle<Name> name,
891 814343 : MapHandles const& maps,
892 : MaybeObjectHandles* handlers) {
893 : DCHECK_EQ(handlers->size(), maps.size());
894 231845 : int receiver_count = static_cast<int>(maps.size());
895 : DCHECK_GT(receiver_count, 1);
896 : Handle<WeakFixedArray> array;
897 231845 : if (name.is_null()) {
898 228209 : array = EnsureArrayOfSize(receiver_count * 2);
899 228216 : SetFeedbackExtra(*FeedbackVector::UninitializedSentinel(GetIsolate()),
900 228218 : SKIP_WRITE_BARRIER);
901 : } else {
902 3636 : array = EnsureExtraArrayOfSize(receiver_count * 2);
903 : SetFeedback(*name);
904 : }
905 :
906 814353 : for (int current = 0; current < receiver_count; ++current) {
907 1164996 : Handle<Map> map = maps[current];
908 1165001 : array->Set(current * 2, HeapObjectReference::Weak(*map));
909 : DCHECK(IC::IsHandler(*handlers->at(current)));
910 1165007 : array->Set(current * 2 + 1, *handlers->at(current));
911 : }
912 231855 : }
913 :
914 1033341 : int FeedbackNexus::ExtractMaps(MapHandles* maps) const {
915 : DCHECK(IsLoadICKind(kind()) || IsStoreICKind(kind()) ||
916 : IsKeyedLoadICKind(kind()) || IsKeyedStoreICKind(kind()) ||
917 : IsStoreOwnICKind(kind()) || IsStoreDataPropertyInLiteralKind(kind()) ||
918 : IsStoreInArrayLiteralICKind(kind()));
919 :
920 1033341 : Isolate* isolate = GetIsolate();
921 1033346 : MaybeObject feedback = GetFeedback();
922 1033348 : bool is_named_feedback = IsPropertyNameFeedback(feedback);
923 1033349 : HeapObject heap_object;
924 2640688 : if ((feedback->GetHeapObjectIfStrong(&heap_object) &&
925 1912377 : heap_object->IsWeakFixedArray()) ||
926 : is_named_feedback) {
927 : int found = 0;
928 159632 : WeakFixedArray array;
929 159632 : if (is_named_feedback) {
930 : array =
931 10654 : WeakFixedArray::cast(GetFeedbackExtra()->GetHeapObjectAssumeStrong());
932 : } else {
933 154306 : array = WeakFixedArray::cast(heap_object);
934 : }
935 : const int increment = 2;
936 159634 : HeapObject heap_object;
937 1105740 : for (int i = 0; i < array->length(); i += increment) {
938 : DCHECK(array->Get(i)->IsWeakOrCleared());
939 393233 : if (array->Get(i)->GetHeapObjectIfWeak(&heap_object)) {
940 : Map map = Map::cast(heap_object);
941 647302 : maps->push_back(handle(map, isolate));
942 323652 : found++;
943 : }
944 : }
945 : return found;
946 873711 : } else if (feedback->GetHeapObjectIfWeak(&heap_object)) {
947 : Map map = Map::cast(heap_object);
948 779317 : maps->push_back(handle(map, isolate));
949 : return 1;
950 1452161 : } else if (feedback->GetHeapObjectIfStrong(&heap_object) &&
951 : heap_object ==
952 1312771 : heap_object->GetReadOnlyRoots().premonomorphic_symbol()) {
953 8174 : if (GetFeedbackExtra()->GetHeapObjectIfWeak(&heap_object)) {
954 : Map map = Map::cast(heap_object);
955 14824 : maps->push_back(handle(map, isolate));
956 : return 1;
957 : }
958 : }
959 :
960 : return 0;
961 : }
962 :
963 351035 : MaybeObjectHandle FeedbackNexus::FindHandlerForMap(Handle<Map> map) const {
964 : DCHECK(IsLoadICKind(kind()) || IsStoreICKind(kind()) ||
965 : IsKeyedLoadICKind(kind()) || IsKeyedStoreICKind(kind()) ||
966 : IsStoreOwnICKind(kind()) || IsStoreDataPropertyInLiteralKind(kind()));
967 :
968 351035 : MaybeObject feedback = GetFeedback();
969 351039 : Isolate* isolate = GetIsolate();
970 351039 : bool is_named_feedback = IsPropertyNameFeedback(feedback);
971 351038 : HeapObject heap_object;
972 827132 : if ((feedback->GetHeapObjectIfStrong(&heap_object) &&
973 578771 : heap_object->IsWeakFixedArray()) ||
974 : is_named_feedback) {
975 125055 : WeakFixedArray array;
976 125055 : if (is_named_feedback) {
977 : array =
978 3496 : WeakFixedArray::cast(GetFeedbackExtra()->GetHeapObjectAssumeStrong());
979 : } else {
980 123305 : array = WeakFixedArray::cast(heap_object);
981 : }
982 : const int increment = 2;
983 125053 : HeapObject heap_object;
984 870555 : for (int i = 0; i < array->length(); i += increment) {
985 : DCHECK(array->Get(i)->IsWeakOrCleared());
986 310755 : if (array->Get(i)->GetHeapObjectIfWeak(&heap_object)) {
987 : Map array_map = Map::cast(heap_object);
988 241886 : if (array_map == *map && !array->Get(i + increment - 1)->IsCleared()) {
989 531 : MaybeObject handler = array->Get(i + increment - 1);
990 : DCHECK(IC::IsHandler(handler));
991 : return handle(handler, isolate);
992 : }
993 : }
994 : }
995 225984 : } else if (feedback->GetHeapObjectIfWeak(&heap_object)) {
996 : Map cell_map = Map::cast(heap_object);
997 170182 : if (cell_map == *map && !GetFeedbackExtra()->IsCleared()) {
998 13274 : MaybeObject handler = GetFeedbackExtra();
999 : DCHECK(IC::IsHandler(handler));
1000 : return handle(handler, isolate);
1001 : }
1002 : }
1003 :
1004 337233 : return MaybeObjectHandle();
1005 : }
1006 :
1007 476323 : bool FeedbackNexus::FindHandlers(MaybeObjectHandles* code_list,
1008 : int length) const {
1009 : DCHECK(IsLoadICKind(kind()) || IsStoreICKind(kind()) ||
1010 : IsKeyedLoadICKind(kind()) || IsKeyedStoreICKind(kind()) ||
1011 : IsStoreOwnICKind(kind()) || IsStoreDataPropertyInLiteralKind(kind()) ||
1012 : IsStoreInArrayLiteralICKind(kind()));
1013 :
1014 476323 : MaybeObject feedback = GetFeedback();
1015 476335 : Isolate* isolate = GetIsolate();
1016 : int count = 0;
1017 476338 : bool is_named_feedback = IsPropertyNameFeedback(feedback);
1018 476338 : HeapObject heap_object;
1019 1172478 : if ((feedback->GetHeapObjectIfStrong(&heap_object) &&
1020 810971 : heap_object->IsWeakFixedArray()) ||
1021 : is_named_feedback) {
1022 146318 : WeakFixedArray array;
1023 146318 : if (is_named_feedback) {
1024 : array =
1025 9247 : WeakFixedArray::cast(GetFeedbackExtra()->GetHeapObjectAssumeStrong());
1026 : } else {
1027 141689 : array = WeakFixedArray::cast(heap_object);
1028 : }
1029 : const int increment = 2;
1030 146314 : HeapObject heap_object;
1031 1057286 : for (int i = 0; i < array->length(); i += increment) {
1032 : // Be sure to skip handlers whose maps have been cleared.
1033 : DCHECK(array->Get(i)->IsWeakOrCleared());
1034 1077482 : if (array->Get(i)->GetHeapObjectIfWeak(&heap_object) &&
1035 695158 : !array->Get(i + increment - 1)->IsCleared()) {
1036 312799 : MaybeObject handler = array->Get(i + increment - 1);
1037 : DCHECK(IC::IsHandler(handler));
1038 625603 : code_list->push_back(handle(handler, isolate));
1039 312802 : count++;
1040 : }
1041 : }
1042 330017 : } else if (feedback->GetHeapObjectIfWeak(&heap_object)) {
1043 187182 : MaybeObject extra = GetFeedbackExtra();
1044 187183 : if (!extra->IsCleared()) {
1045 : DCHECK(IC::IsHandler(extra));
1046 373152 : code_list->push_back(handle(extra, isolate));
1047 : count++;
1048 : }
1049 : }
1050 476336 : return count == length;
1051 : }
1052 :
1053 48332 : Name FeedbackNexus::FindFirstName() const {
1054 48332 : if (IsKeyedStoreICKind(kind()) || IsKeyedLoadICKind(kind())) {
1055 48332 : MaybeObject feedback = GetFeedback();
1056 48332 : if (IsPropertyNameFeedback(feedback)) {
1057 52866 : return Name::cast(feedback->GetHeapObjectAssumeStrong());
1058 : }
1059 : }
1060 21899 : return Name();
1061 : }
1062 :
1063 45167 : KeyedAccessLoadMode FeedbackNexus::GetKeyedAccessLoadMode() const {
1064 : DCHECK(IsKeyedLoadICKind(kind()));
1065 : MapHandles maps;
1066 : MaybeObjectHandles handlers;
1067 :
1068 45167 : if (GetKeyType() == PROPERTY) return STANDARD_LOAD;
1069 :
1070 43319 : ExtractMaps(&maps);
1071 86638 : FindHandlers(&handlers, static_cast<int>(maps.size()));
1072 103266 : for (MaybeObjectHandle const& handler : handlers) {
1073 17484 : KeyedAccessLoadMode mode = LoadHandler::GetKeyedAccessLoadMode(*handler);
1074 17484 : if (mode != STANDARD_LOAD) return mode;
1075 : }
1076 :
1077 : return STANDARD_LOAD;
1078 : }
1079 :
1080 : namespace {
1081 :
1082 : bool BuiltinHasKeyedAccessStoreMode(int builtin_index) {
1083 : DCHECK(Builtins::IsBuiltinId(builtin_index));
1084 20308 : switch (builtin_index) {
1085 : case Builtins::kKeyedStoreIC_SloppyArguments_Standard:
1086 : case Builtins::kKeyedStoreIC_SloppyArguments_GrowNoTransitionHandleCOW:
1087 : case Builtins::kKeyedStoreIC_SloppyArguments_NoTransitionIgnoreOOB:
1088 : case Builtins::kKeyedStoreIC_SloppyArguments_NoTransitionHandleCOW:
1089 : case Builtins::kStoreFastElementIC_Standard:
1090 : case Builtins::kStoreFastElementIC_GrowNoTransitionHandleCOW:
1091 : case Builtins::kStoreFastElementIC_NoTransitionIgnoreOOB:
1092 : case Builtins::kStoreFastElementIC_NoTransitionHandleCOW:
1093 : case Builtins::kStoreInArrayLiteralIC_Slow_Standard:
1094 : case Builtins::kStoreInArrayLiteralIC_Slow_GrowNoTransitionHandleCOW:
1095 : case Builtins::kStoreInArrayLiteralIC_Slow_NoTransitionIgnoreOOB:
1096 : case Builtins::kStoreInArrayLiteralIC_Slow_NoTransitionHandleCOW:
1097 : case Builtins::kKeyedStoreIC_Slow_Standard:
1098 : case Builtins::kKeyedStoreIC_Slow_GrowNoTransitionHandleCOW:
1099 : case Builtins::kKeyedStoreIC_Slow_NoTransitionIgnoreOOB:
1100 : case Builtins::kKeyedStoreIC_Slow_NoTransitionHandleCOW:
1101 : case Builtins::kElementsTransitionAndStore_Standard:
1102 : case Builtins::kElementsTransitionAndStore_GrowNoTransitionHandleCOW:
1103 : case Builtins::kElementsTransitionAndStore_NoTransitionIgnoreOOB:
1104 : case Builtins::kElementsTransitionAndStore_NoTransitionHandleCOW:
1105 : return true;
1106 : default:
1107 : return false;
1108 : }
1109 : UNREACHABLE();
1110 : }
1111 :
1112 20299 : KeyedAccessStoreMode KeyedAccessStoreModeForBuiltin(int builtin_index) {
1113 : DCHECK(BuiltinHasKeyedAccessStoreMode(builtin_index));
1114 20299 : switch (builtin_index) {
1115 : case Builtins::kKeyedStoreIC_SloppyArguments_Standard:
1116 : case Builtins::kStoreInArrayLiteralIC_Slow_Standard:
1117 : case Builtins::kKeyedStoreIC_Slow_Standard:
1118 : case Builtins::kStoreFastElementIC_Standard:
1119 : case Builtins::kElementsTransitionAndStore_Standard:
1120 : return STANDARD_STORE;
1121 : case Builtins::kKeyedStoreIC_SloppyArguments_GrowNoTransitionHandleCOW:
1122 : case Builtins::kStoreInArrayLiteralIC_Slow_GrowNoTransitionHandleCOW:
1123 : case Builtins::kKeyedStoreIC_Slow_GrowNoTransitionHandleCOW:
1124 : case Builtins::kStoreFastElementIC_GrowNoTransitionHandleCOW:
1125 : case Builtins::kElementsTransitionAndStore_GrowNoTransitionHandleCOW:
1126 4711 : return STORE_AND_GROW_NO_TRANSITION_HANDLE_COW;
1127 : case Builtins::kKeyedStoreIC_SloppyArguments_NoTransitionIgnoreOOB:
1128 : case Builtins::kStoreInArrayLiteralIC_Slow_NoTransitionIgnoreOOB:
1129 : case Builtins::kKeyedStoreIC_Slow_NoTransitionIgnoreOOB:
1130 : case Builtins::kStoreFastElementIC_NoTransitionIgnoreOOB:
1131 : case Builtins::kElementsTransitionAndStore_NoTransitionIgnoreOOB:
1132 296 : return STORE_NO_TRANSITION_IGNORE_OUT_OF_BOUNDS;
1133 : case Builtins::kKeyedStoreIC_SloppyArguments_NoTransitionHandleCOW:
1134 : case Builtins::kStoreInArrayLiteralIC_Slow_NoTransitionHandleCOW:
1135 : case Builtins::kKeyedStoreIC_Slow_NoTransitionHandleCOW:
1136 : case Builtins::kStoreFastElementIC_NoTransitionHandleCOW:
1137 : case Builtins::kElementsTransitionAndStore_NoTransitionHandleCOW:
1138 696 : return STORE_NO_TRANSITION_HANDLE_COW;
1139 : default:
1140 0 : UNREACHABLE();
1141 : }
1142 : }
1143 :
1144 : } // namespace
1145 :
1146 66435 : KeyedAccessStoreMode FeedbackNexus::GetKeyedAccessStoreMode() const {
1147 : DCHECK(IsKeyedStoreICKind(kind()) || IsStoreInArrayLiteralICKind(kind()));
1148 : KeyedAccessStoreMode mode = STANDARD_STORE;
1149 : MapHandles maps;
1150 : MaybeObjectHandles handlers;
1151 :
1152 66435 : if (GetKeyType() == PROPERTY) return mode;
1153 :
1154 65603 : ExtractMaps(&maps);
1155 131208 : FindHandlers(&handlers, static_cast<int>(maps.size()));
1156 131232 : for (const MaybeObjectHandle& maybe_code_handler : handlers) {
1157 : // The first handler that isn't the slow handler will have the bits we need.
1158 : Handle<Code> handler;
1159 60981 : if (maybe_code_handler.object()->IsStoreHandler()) {
1160 : Handle<StoreHandler> data_handler =
1161 8648 : Handle<StoreHandler>::cast(maybe_code_handler.object());
1162 17296 : handler = handle(Code::cast(data_handler->smi_handler()),
1163 25944 : vector()->GetIsolate());
1164 35037 : } else if (maybe_code_handler.object()->IsSmi()) {
1165 : // Skip proxy handlers.
1166 : DCHECK_EQ(*(maybe_code_handler.object()),
1167 : *StoreHandler::StoreProxy(GetIsolate()));
1168 : continue;
1169 : } else {
1170 : // Element store without prototype chain check.
1171 11660 : handler = Handle<Code>::cast(maybe_code_handler.object());
1172 : }
1173 :
1174 20308 : if (handler->is_builtin()) {
1175 : const int builtin_index = handler->builtin_index();
1176 20308 : if (!BuiltinHasKeyedAccessStoreMode(builtin_index)) continue;
1177 :
1178 20299 : mode = KeyedAccessStoreModeForBuiltin(builtin_index);
1179 : break;
1180 : }
1181 : }
1182 :
1183 65602 : return mode;
1184 : }
1185 :
1186 133474 : IcCheckType FeedbackNexus::GetKeyType() const {
1187 : DCHECK(IsKeyedStoreICKind(kind()) || IsKeyedLoadICKind(kind()) ||
1188 : IsStoreInArrayLiteralICKind(kind()));
1189 133474 : MaybeObject feedback = GetFeedback();
1190 133476 : if (feedback == MaybeObject::FromObject(
1191 133474 : *FeedbackVector::MegamorphicSentinel(GetIsolate()))) {
1192 : return static_cast<IcCheckType>(
1193 8888 : Smi::ToInt(GetFeedbackExtra()->cast<Object>()));
1194 : }
1195 124588 : return IsPropertyNameFeedback(feedback) ? PROPERTY : ELEMENT;
1196 : }
1197 :
1198 948150 : BinaryOperationHint FeedbackNexus::GetBinaryOperationFeedback() const {
1199 : DCHECK_EQ(kind(), FeedbackSlotKind::kBinaryOp);
1200 1896301 : int feedback = GetFeedback().ToSmi().value();
1201 948151 : return BinaryOperationHintFromFeedback(feedback);
1202 : }
1203 :
1204 527494 : CompareOperationHint FeedbackNexus::GetCompareOperationFeedback() const {
1205 : DCHECK_EQ(kind(), FeedbackSlotKind::kCompareOp);
1206 1054988 : int feedback = GetFeedback().ToSmi().value();
1207 527494 : return CompareOperationHintFromFeedback(feedback);
1208 : }
1209 :
1210 4356 : ForInHint FeedbackNexus::GetForInFeedback() const {
1211 : DCHECK_EQ(kind(), FeedbackSlotKind::kForIn);
1212 8712 : int feedback = GetFeedback().ToSmi().value();
1213 4356 : return ForInHintFromFeedback(feedback);
1214 : }
1215 :
1216 420653 : Handle<FeedbackCell> FeedbackNexus::GetFeedbackCell() const {
1217 : DCHECK_EQ(FeedbackSlotKind::kCreateClosure, kind());
1218 : return handle(FeedbackCell::cast(GetFeedback()->cast<Object>()),
1219 1261961 : vector()->GetIsolate());
1220 : }
1221 :
1222 1994 : MaybeHandle<JSObject> FeedbackNexus::GetConstructorFeedback() const {
1223 : DCHECK_EQ(kind(), FeedbackSlotKind::kInstanceOf);
1224 1994 : Isolate* isolate = GetIsolate();
1225 1994 : MaybeObject feedback = GetFeedback();
1226 1994 : HeapObject heap_object;
1227 1994 : if (feedback->GetHeapObjectIfWeak(&heap_object)) {
1228 128 : return handle(JSObject::cast(heap_object), isolate);
1229 : }
1230 1866 : return MaybeHandle<JSObject>();
1231 : }
1232 :
1233 : namespace {
1234 :
1235 80 : bool InList(Handle<ArrayList> types, Handle<String> type) {
1236 310 : for (int i = 0; i < types->Length(); i++) {
1237 95 : Object obj = types->Get(i);
1238 95 : if (String::cast(obj)->Equals(*type)) {
1239 20 : return true;
1240 : }
1241 : }
1242 : return false;
1243 : }
1244 : } // anonymous namespace
1245 :
1246 285 : void FeedbackNexus::Collect(Handle<String> type, int position) {
1247 : DCHECK(IsTypeProfileKind(kind()));
1248 : DCHECK_GE(position, 0);
1249 285 : Isolate* isolate = GetIsolate();
1250 :
1251 285 : MaybeObject const feedback = GetFeedback();
1252 :
1253 : // Map source position to collection of types
1254 : Handle<SimpleNumberDictionary> types;
1255 :
1256 285 : if (feedback == MaybeObject::FromObject(
1257 : *FeedbackVector::UninitializedSentinel(isolate))) {
1258 85 : types = SimpleNumberDictionary::New(isolate, 1);
1259 : } else {
1260 : types = handle(
1261 : SimpleNumberDictionary::cast(feedback->GetHeapObjectAssumeStrong()),
1262 400 : isolate);
1263 : }
1264 :
1265 : Handle<ArrayList> position_specific_types;
1266 :
1267 570 : int entry = types->FindEntry(isolate, position);
1268 285 : if (entry == SimpleNumberDictionary::kNotFound) {
1269 205 : position_specific_types = ArrayList::New(isolate, 1);
1270 : types = SimpleNumberDictionary::Set(
1271 : isolate, types, position,
1272 410 : ArrayList::Add(isolate, position_specific_types, type));
1273 : } else {
1274 : DCHECK(types->ValueAt(entry)->IsArrayList());
1275 : position_specific_types =
1276 160 : handle(ArrayList::cast(types->ValueAt(entry)), isolate);
1277 80 : if (!InList(position_specific_types, type)) { // Add type
1278 : types = SimpleNumberDictionary::Set(
1279 : isolate, types, position,
1280 120 : ArrayList::Add(isolate, position_specific_types, type));
1281 : }
1282 : }
1283 : SetFeedback(*types);
1284 285 : }
1285 :
1286 135 : std::vector<int> FeedbackNexus::GetSourcePositions() const {
1287 : DCHECK(IsTypeProfileKind(kind()));
1288 : std::vector<int> source_positions;
1289 135 : Isolate* isolate = GetIsolate();
1290 :
1291 135 : MaybeObject const feedback = GetFeedback();
1292 :
1293 135 : if (feedback == MaybeObject::FromObject(
1294 : *FeedbackVector::UninitializedSentinel(isolate))) {
1295 : return source_positions;
1296 : }
1297 :
1298 : Handle<SimpleNumberDictionary> types(
1299 : SimpleNumberDictionary::cast(feedback->GetHeapObjectAssumeStrong()),
1300 160 : isolate);
1301 :
1302 1040 : for (int index = SimpleNumberDictionary::kElementsStartIndex;
1303 : index < types->length(); index += SimpleNumberDictionary::kEntrySize) {
1304 : int key_index = index + SimpleNumberDictionary::kEntryKeyIndex;
1305 440 : Object key = types->get(key_index);
1306 440 : if (key->IsSmi()) {
1307 185 : int position = Smi::cast(key)->value();
1308 185 : source_positions.push_back(position);
1309 : }
1310 : }
1311 : return source_positions;
1312 : }
1313 :
1314 185 : std::vector<Handle<String>> FeedbackNexus::GetTypesForSourcePositions(
1315 : uint32_t position) const {
1316 : DCHECK(IsTypeProfileKind(kind()));
1317 185 : Isolate* isolate = GetIsolate();
1318 :
1319 185 : MaybeObject const feedback = GetFeedback();
1320 : std::vector<Handle<String>> types_for_position;
1321 185 : if (feedback == MaybeObject::FromObject(
1322 : *FeedbackVector::UninitializedSentinel(isolate))) {
1323 : return types_for_position;
1324 : }
1325 :
1326 : Handle<SimpleNumberDictionary> types(
1327 : SimpleNumberDictionary::cast(feedback->GetHeapObjectAssumeStrong()),
1328 370 : isolate);
1329 :
1330 185 : int entry = types->FindEntry(isolate, position);
1331 185 : if (entry == SimpleNumberDictionary::kNotFound) {
1332 : return types_for_position;
1333 : }
1334 : DCHECK(types->ValueAt(entry)->IsArrayList());
1335 : Handle<ArrayList> position_specific_types =
1336 370 : Handle<ArrayList>(ArrayList::cast(types->ValueAt(entry)), isolate);
1337 860 : for (int i = 0; i < position_specific_types->Length(); i++) {
1338 245 : Object t = position_specific_types->Get(i);
1339 245 : types_for_position.push_back(Handle<String>(String::cast(t), isolate));
1340 : }
1341 :
1342 : return types_for_position;
1343 : }
1344 :
1345 : namespace {
1346 :
1347 0 : Handle<JSObject> ConvertToJSObject(Isolate* isolate,
1348 : Handle<SimpleNumberDictionary> feedback) {
1349 : Handle<JSObject> type_profile =
1350 0 : isolate->factory()->NewJSObject(isolate->object_function());
1351 :
1352 0 : for (int index = SimpleNumberDictionary::kElementsStartIndex;
1353 : index < feedback->length();
1354 : index += SimpleNumberDictionary::kEntrySize) {
1355 : int key_index = index + SimpleNumberDictionary::kEntryKeyIndex;
1356 0 : Object key = feedback->get(key_index);
1357 0 : if (key->IsSmi()) {
1358 0 : int value_index = index + SimpleNumberDictionary::kEntryValueIndex;
1359 :
1360 : Handle<ArrayList> position_specific_types(
1361 : ArrayList::cast(feedback->get(value_index)), isolate);
1362 :
1363 0 : int position = Smi::ToInt(key);
1364 : JSObject::AddDataElement(
1365 : type_profile, position,
1366 : isolate->factory()->NewJSArrayWithElements(
1367 : ArrayList::Elements(isolate, position_specific_types)),
1368 0 : PropertyAttributes::NONE);
1369 : }
1370 : }
1371 0 : return type_profile;
1372 : }
1373 : } // namespace
1374 :
1375 0 : JSObject FeedbackNexus::GetTypeProfile() const {
1376 : DCHECK(IsTypeProfileKind(kind()));
1377 0 : Isolate* isolate = GetIsolate();
1378 :
1379 0 : MaybeObject const feedback = GetFeedback();
1380 :
1381 0 : if (feedback == MaybeObject::FromObject(
1382 : *FeedbackVector::UninitializedSentinel(isolate))) {
1383 0 : return *isolate->factory()->NewJSObject(isolate->object_function());
1384 : }
1385 :
1386 : return *ConvertToJSObject(isolate,
1387 : handle(SimpleNumberDictionary::cast(
1388 : feedback->GetHeapObjectAssumeStrong()),
1389 0 : isolate));
1390 : }
1391 :
1392 265 : void FeedbackNexus::ResetTypeProfile() {
1393 : DCHECK(IsTypeProfileKind(kind()));
1394 265 : SetFeedback(*FeedbackVector::UninitializedSentinel(GetIsolate()));
1395 265 : }
1396 :
1397 : } // namespace internal
1398 183867 : } // namespace v8
|