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