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/type-feedback-vector.h"
6
7 #include "src/code-stubs.h"
8 #include "src/ic/ic-inl.h"
9 #include "src/ic/ic-state.h"
10 #include "src/objects.h"
11 #include "src/type-feedback-vector-inl.h"
12
13 namespace v8 {
14 namespace internal {
15
16
IsPropertyNameFeedback(Object * feedback)17 static bool IsPropertyNameFeedback(Object* feedback) {
18 if (feedback->IsString()) return true;
19 if (!feedback->IsSymbol()) return false;
20 Symbol* symbol = Symbol::cast(feedback);
21 Heap* heap = symbol->GetHeap();
22 return symbol != heap->uninitialized_symbol() &&
23 symbol != heap->premonomorphic_symbol() &&
24 symbol != heap->megamorphic_symbol();
25 }
26
27
operator <<(std::ostream & os,FeedbackVectorSlotKind kind)28 std::ostream& operator<<(std::ostream& os, FeedbackVectorSlotKind kind) {
29 return os << TypeFeedbackMetadata::Kind2String(kind);
30 }
31
32
GetKind(FeedbackVectorSlot slot) const33 FeedbackVectorSlotKind TypeFeedbackMetadata::GetKind(
34 FeedbackVectorSlot slot) const {
35 int index = VectorICComputer::index(kReservedIndexCount, slot.ToInt());
36 int data = Smi::cast(get(index))->value();
37 return VectorICComputer::decode(data, slot.ToInt());
38 }
39
GetName(FeedbackVectorSlot slot) const40 String* TypeFeedbackMetadata::GetName(FeedbackVectorSlot slot) const {
41 DCHECK(SlotRequiresName(GetKind(slot)));
42 UnseededNumberDictionary* names =
43 UnseededNumberDictionary::cast(get(kNamesTableIndex));
44 int entry = names->FindEntry(GetIsolate(), slot.ToInt());
45 CHECK_NE(UnseededNumberDictionary::kNotFound, entry);
46 Object* name = names->ValueAt(entry);
47 DCHECK(name->IsString());
48 return String::cast(name);
49 }
50
SetKind(FeedbackVectorSlot slot,FeedbackVectorSlotKind kind)51 void TypeFeedbackMetadata::SetKind(FeedbackVectorSlot slot,
52 FeedbackVectorSlotKind kind) {
53 int index = VectorICComputer::index(kReservedIndexCount, slot.ToInt());
54 int data = Smi::cast(get(index))->value();
55 int new_data = VectorICComputer::encode(data, slot.ToInt(), kind);
56 set(index, Smi::FromInt(new_data));
57 }
58
59
60 template Handle<TypeFeedbackMetadata> TypeFeedbackMetadata::New(
61 Isolate* isolate, const StaticFeedbackVectorSpec* spec);
62 template Handle<TypeFeedbackMetadata> TypeFeedbackMetadata::New(
63 Isolate* isolate, const FeedbackVectorSpec* spec);
64
65
66 // static
67 template <typename Spec>
New(Isolate * isolate,const Spec * spec)68 Handle<TypeFeedbackMetadata> TypeFeedbackMetadata::New(Isolate* isolate,
69 const Spec* spec) {
70 Factory* factory = isolate->factory();
71
72 const int slot_count = spec->slots();
73 const int slot_kinds_length = VectorICComputer::word_count(slot_count);
74 const int length = slot_kinds_length + kReservedIndexCount;
75 if (length == kReservedIndexCount) {
76 return Handle<TypeFeedbackMetadata>::cast(factory->empty_fixed_array());
77 }
78 #ifdef DEBUG
79 for (int i = 0; i < slot_count;) {
80 FeedbackVectorSlotKind kind = spec->GetKind(i);
81 int entry_size = TypeFeedbackMetadata::GetSlotSize(kind);
82 for (int j = 1; j < entry_size; j++) {
83 FeedbackVectorSlotKind kind = spec->GetKind(i + j);
84 DCHECK_EQ(FeedbackVectorSlotKind::INVALID, kind);
85 }
86 i += entry_size;
87 }
88 #endif
89
90 Handle<FixedArray> array = factory->NewFixedArray(length, TENURED);
91 array->set(kSlotsCountIndex, Smi::FromInt(slot_count));
92 // Fill the bit-vector part with zeros.
93 for (int i = 0; i < slot_kinds_length; i++) {
94 array->set(kReservedIndexCount + i, Smi::kZero);
95 }
96
97 Handle<TypeFeedbackMetadata> metadata =
98 Handle<TypeFeedbackMetadata>::cast(array);
99
100 // Add names to NamesTable.
101 const int name_count = spec->name_count();
102
103 Handle<UnseededNumberDictionary> names;
104 if (name_count) {
105 names = UnseededNumberDictionary::New(isolate, name_count, TENURED);
106 }
107
108 int name_index = 0;
109 for (int i = 0; i < slot_count; i++) {
110 FeedbackVectorSlotKind kind = spec->GetKind(i);
111 metadata->SetKind(FeedbackVectorSlot(i), kind);
112 if (SlotRequiresName(kind)) {
113 Handle<String> name = spec->GetName(name_index);
114 DCHECK(!name.is_null());
115 Handle<UnseededNumberDictionary> new_names =
116 UnseededNumberDictionary::AtNumberPut(names, i, name);
117 DCHECK_EQ(*new_names, *names);
118 names = new_names;
119 name_index++;
120 }
121 }
122 DCHECK_EQ(name_count, name_index);
123 metadata->set(kNamesTableIndex,
124 name_count ? static_cast<Object*>(*names) : Smi::kZero);
125
126 // It's important that the TypeFeedbackMetadata have a COW map, since it's
127 // pointed to by both a SharedFunctionInfo and indirectly by closures through
128 // the TypeFeedbackVector. The serializer uses the COW map type to decide
129 // this object belongs in the startup snapshot and not the partial
130 // snapshot(s).
131 metadata->set_map(isolate->heap()->fixed_cow_array_map());
132
133 return metadata;
134 }
135
136
SpecDiffersFrom(const FeedbackVectorSpec * other_spec) const137 bool TypeFeedbackMetadata::SpecDiffersFrom(
138 const FeedbackVectorSpec* other_spec) const {
139 if (other_spec->slots() != slot_count()) {
140 return true;
141 }
142
143 int slots = slot_count();
144 int name_index = 0;
145 for (int i = 0; i < slots;) {
146 FeedbackVectorSlot slot(i);
147 FeedbackVectorSlotKind kind = GetKind(slot);
148 int entry_size = TypeFeedbackMetadata::GetSlotSize(kind);
149
150 if (kind != other_spec->GetKind(i)) {
151 return true;
152 }
153 if (SlotRequiresName(kind)) {
154 String* name = GetName(slot);
155 DCHECK(name != GetHeap()->empty_string());
156 String* other_name = *other_spec->GetName(name_index++);
157 if (name != other_name) {
158 return true;
159 }
160 }
161 i += entry_size;
162 }
163 return false;
164 }
165
DiffersFrom(const TypeFeedbackMetadata * other_metadata) const166 bool TypeFeedbackMetadata::DiffersFrom(
167 const TypeFeedbackMetadata* other_metadata) const {
168 if (other_metadata->slot_count() != slot_count()) {
169 return true;
170 }
171
172 int slots = slot_count();
173 for (int i = 0; i < slots;) {
174 FeedbackVectorSlot slot(i);
175 FeedbackVectorSlotKind kind = GetKind(slot);
176 int entry_size = TypeFeedbackMetadata::GetSlotSize(kind);
177 if (GetKind(slot) != other_metadata->GetKind(slot)) {
178 return true;
179 }
180 if (SlotRequiresName(kind)) {
181 if (GetName(slot) != other_metadata->GetName(slot)) {
182 return true;
183 }
184 }
185 i += entry_size;
186 }
187 return false;
188 }
189
Kind2String(FeedbackVectorSlotKind kind)190 const char* TypeFeedbackMetadata::Kind2String(FeedbackVectorSlotKind kind) {
191 switch (kind) {
192 case FeedbackVectorSlotKind::INVALID:
193 return "INVALID";
194 case FeedbackVectorSlotKind::CALL_IC:
195 return "CALL_IC";
196 case FeedbackVectorSlotKind::LOAD_IC:
197 return "LOAD_IC";
198 case FeedbackVectorSlotKind::LOAD_GLOBAL_IC:
199 return "LOAD_GLOBAL_IC";
200 case FeedbackVectorSlotKind::KEYED_LOAD_IC:
201 return "KEYED_LOAD_IC";
202 case FeedbackVectorSlotKind::STORE_IC:
203 return "STORE_IC";
204 case FeedbackVectorSlotKind::KEYED_STORE_IC:
205 return "KEYED_STORE_IC";
206 case FeedbackVectorSlotKind::INTERPRETER_BINARYOP_IC:
207 return "INTERPRETER_BINARYOP_IC";
208 case FeedbackVectorSlotKind::INTERPRETER_COMPARE_IC:
209 return "INTERPRETER_COMPARE_IC";
210 case FeedbackVectorSlotKind::GENERAL:
211 return "STUB";
212 case FeedbackVectorSlotKind::KINDS_NUMBER:
213 break;
214 }
215 UNREACHABLE();
216 return "?";
217 }
218
GetKind(FeedbackVectorSlot slot) const219 FeedbackVectorSlotKind TypeFeedbackVector::GetKind(
220 FeedbackVectorSlot slot) const {
221 DCHECK(!is_empty());
222 return metadata()->GetKind(slot);
223 }
224
GetName(FeedbackVectorSlot slot) const225 String* TypeFeedbackVector::GetName(FeedbackVectorSlot slot) const {
226 DCHECK(!is_empty());
227 return metadata()->GetName(slot);
228 }
229
230 // static
New(Isolate * isolate,Handle<TypeFeedbackMetadata> metadata)231 Handle<TypeFeedbackVector> TypeFeedbackVector::New(
232 Isolate* isolate, Handle<TypeFeedbackMetadata> metadata) {
233 Factory* factory = isolate->factory();
234
235 const int slot_count = metadata->slot_count();
236 const int length = slot_count + kReservedIndexCount;
237 if (length == kReservedIndexCount) {
238 return Handle<TypeFeedbackVector>::cast(
239 factory->empty_type_feedback_vector());
240 }
241
242 Handle<FixedArray> array = factory->NewFixedArray(length, TENURED);
243 array->set(kMetadataIndex, *metadata);
244 array->set(kInvocationCountIndex, Smi::kZero);
245
246 DisallowHeapAllocation no_gc;
247
248 // Ensure we can skip the write barrier
249 Handle<Object> uninitialized_sentinel = UninitializedSentinel(isolate);
250 DCHECK_EQ(isolate->heap()->uninitialized_symbol(), *uninitialized_sentinel);
251 for (int i = 0; i < slot_count;) {
252 FeedbackVectorSlot slot(i);
253 FeedbackVectorSlotKind kind = metadata->GetKind(slot);
254 int index = TypeFeedbackVector::GetIndex(slot);
255 int entry_size = TypeFeedbackMetadata::GetSlotSize(kind);
256
257 Object* value;
258 if (kind == FeedbackVectorSlotKind::LOAD_GLOBAL_IC) {
259 value = isolate->heap()->empty_weak_cell();
260 } else if (kind == FeedbackVectorSlotKind::INTERPRETER_COMPARE_IC ||
261 kind == FeedbackVectorSlotKind::INTERPRETER_BINARYOP_IC) {
262 value = Smi::kZero;
263 } else {
264 value = *uninitialized_sentinel;
265 }
266 array->set(index, value, SKIP_WRITE_BARRIER);
267
268 value = kind == FeedbackVectorSlotKind::CALL_IC ? Smi::kZero
269 : *uninitialized_sentinel;
270 for (int j = 1; j < entry_size; j++) {
271 array->set(index + j, value, SKIP_WRITE_BARRIER);
272 }
273 i += entry_size;
274 }
275 return Handle<TypeFeedbackVector>::cast(array);
276 }
277
278
279 // static
GetIndexFromSpec(const FeedbackVectorSpec * spec,FeedbackVectorSlot slot)280 int TypeFeedbackVector::GetIndexFromSpec(const FeedbackVectorSpec* spec,
281 FeedbackVectorSlot slot) {
282 return kReservedIndexCount + slot.ToInt();
283 }
284
285
286 // static
Copy(Isolate * isolate,Handle<TypeFeedbackVector> vector)287 Handle<TypeFeedbackVector> TypeFeedbackVector::Copy(
288 Isolate* isolate, Handle<TypeFeedbackVector> vector) {
289 Handle<TypeFeedbackVector> result;
290 result = Handle<TypeFeedbackVector>::cast(
291 isolate->factory()->CopyFixedArray(Handle<FixedArray>::cast(vector)));
292 return result;
293 }
294
295
296 // This logic is copied from
297 // StaticMarkingVisitor<StaticVisitor>::VisitCodeTarget.
ClearLogic(Isolate * isolate)298 static bool ClearLogic(Isolate* isolate) {
299 return FLAG_cleanup_code_caches_at_gc && isolate->serializer_enabled();
300 }
301
302
ClearSlotsImpl(SharedFunctionInfo * shared,bool force_clear)303 void TypeFeedbackVector::ClearSlotsImpl(SharedFunctionInfo* shared,
304 bool force_clear) {
305 Isolate* isolate = GetIsolate();
306
307 if (!force_clear && !ClearLogic(isolate)) return;
308
309 Object* uninitialized_sentinel =
310 TypeFeedbackVector::RawUninitializedSentinel(isolate);
311
312 TypeFeedbackMetadataIterator iter(metadata());
313 while (iter.HasNext()) {
314 FeedbackVectorSlot slot = iter.Next();
315 FeedbackVectorSlotKind kind = iter.kind();
316
317 Object* obj = Get(slot);
318 if (obj != uninitialized_sentinel) {
319 switch (kind) {
320 case FeedbackVectorSlotKind::CALL_IC: {
321 CallICNexus nexus(this, slot);
322 nexus.Clear(shared->code());
323 break;
324 }
325 case FeedbackVectorSlotKind::LOAD_IC: {
326 LoadICNexus nexus(this, slot);
327 nexus.Clear(shared->code());
328 break;
329 }
330 case FeedbackVectorSlotKind::LOAD_GLOBAL_IC: {
331 LoadGlobalICNexus nexus(this, slot);
332 nexus.Clear(shared->code());
333 break;
334 }
335 case FeedbackVectorSlotKind::KEYED_LOAD_IC: {
336 KeyedLoadICNexus nexus(this, slot);
337 nexus.Clear(shared->code());
338 break;
339 }
340 case FeedbackVectorSlotKind::STORE_IC: {
341 StoreICNexus nexus(this, slot);
342 nexus.Clear(shared->code());
343 break;
344 }
345 case FeedbackVectorSlotKind::KEYED_STORE_IC: {
346 KeyedStoreICNexus nexus(this, slot);
347 nexus.Clear(shared->code());
348 break;
349 }
350 case FeedbackVectorSlotKind::INTERPRETER_BINARYOP_IC:
351 case FeedbackVectorSlotKind::INTERPRETER_COMPARE_IC: {
352 DCHECK(Get(slot)->IsSmi());
353 // don't clear these smi slots.
354 // Set(slot, Smi::kZero);
355 break;
356 }
357 case FeedbackVectorSlotKind::GENERAL: {
358 if (obj->IsHeapObject()) {
359 InstanceType instance_type =
360 HeapObject::cast(obj)->map()->instance_type();
361 // AllocationSites are exempt from clearing. They don't store Maps
362 // or Code pointers which can cause memory leaks if not cleared
363 // regularly.
364 if (instance_type != ALLOCATION_SITE_TYPE) {
365 Set(slot, uninitialized_sentinel, SKIP_WRITE_BARRIER);
366 }
367 }
368 break;
369 }
370 case FeedbackVectorSlotKind::INVALID:
371 case FeedbackVectorSlotKind::KINDS_NUMBER:
372 UNREACHABLE();
373 break;
374 }
375 }
376 }
377 }
378
379
380 // static
ClearAllKeyedStoreICs(Isolate * isolate)381 void TypeFeedbackVector::ClearAllKeyedStoreICs(Isolate* isolate) {
382 SharedFunctionInfo::Iterator iterator(isolate);
383 SharedFunctionInfo* shared;
384 while ((shared = iterator.Next())) {
385 if (!shared->OptimizedCodeMapIsCleared()) {
386 FixedArray* optimized_code_map = shared->optimized_code_map();
387 int length = optimized_code_map->length();
388 for (int i = SharedFunctionInfo::kEntriesStart; i < length;
389 i += SharedFunctionInfo::kEntryLength) {
390 WeakCell* cell = WeakCell::cast(
391 optimized_code_map->get(i + SharedFunctionInfo::kLiteralsOffset));
392 if (cell->value()->IsLiteralsArray()) {
393 TypeFeedbackVector* vector =
394 LiteralsArray::cast(cell->value())->feedback_vector();
395 vector->ClearKeyedStoreICs(shared);
396 }
397 }
398 }
399 }
400 }
401
402
ClearKeyedStoreICs(SharedFunctionInfo * shared)403 void TypeFeedbackVector::ClearKeyedStoreICs(SharedFunctionInfo* shared) {
404 Isolate* isolate = GetIsolate();
405
406 Code* host = shared->code();
407 Object* uninitialized_sentinel =
408 TypeFeedbackVector::RawUninitializedSentinel(isolate);
409
410 TypeFeedbackMetadataIterator iter(metadata());
411 while (iter.HasNext()) {
412 FeedbackVectorSlot slot = iter.Next();
413 FeedbackVectorSlotKind kind = iter.kind();
414 if (kind != FeedbackVectorSlotKind::KEYED_STORE_IC) continue;
415 Object* obj = Get(slot);
416 if (obj != uninitialized_sentinel) {
417 KeyedStoreICNexus nexus(this, slot);
418 nexus.Clear(host);
419 }
420 }
421 }
422
423
424 // static
DummyVector(Isolate * isolate)425 Handle<TypeFeedbackVector> TypeFeedbackVector::DummyVector(Isolate* isolate) {
426 return isolate->factory()->dummy_vector();
427 }
428
429
EnsureArrayOfSize(int length)430 Handle<FixedArray> FeedbackNexus::EnsureArrayOfSize(int length) {
431 Isolate* isolate = GetIsolate();
432 Handle<Object> feedback = handle(GetFeedback(), isolate);
433 if (!feedback->IsFixedArray() ||
434 FixedArray::cast(*feedback)->length() != length) {
435 Handle<FixedArray> array = isolate->factory()->NewFixedArray(length);
436 SetFeedback(*array);
437 return array;
438 }
439 return Handle<FixedArray>::cast(feedback);
440 }
441
442
EnsureExtraArrayOfSize(int length)443 Handle<FixedArray> FeedbackNexus::EnsureExtraArrayOfSize(int length) {
444 Isolate* isolate = GetIsolate();
445 Handle<Object> feedback_extra = handle(GetFeedbackExtra(), isolate);
446 if (!feedback_extra->IsFixedArray() ||
447 FixedArray::cast(*feedback_extra)->length() != length) {
448 Handle<FixedArray> array = isolate->factory()->NewFixedArray(length);
449 SetFeedbackExtra(*array);
450 return array;
451 }
452 return Handle<FixedArray>::cast(feedback_extra);
453 }
454
InstallHandlers(Handle<FixedArray> array,MapHandleList * maps,List<Handle<Object>> * handlers)455 void FeedbackNexus::InstallHandlers(Handle<FixedArray> array,
456 MapHandleList* maps,
457 List<Handle<Object>>* handlers) {
458 int receiver_count = maps->length();
459 for (int current = 0; current < receiver_count; ++current) {
460 Handle<Map> map = maps->at(current);
461 Handle<WeakCell> cell = Map::WeakCellForMap(map);
462 array->set(current * 2, *cell);
463 array->set(current * 2 + 1, *handlers->at(current));
464 }
465 }
466
467
ConfigureUninitialized()468 void FeedbackNexus::ConfigureUninitialized() {
469 SetFeedback(*TypeFeedbackVector::UninitializedSentinel(GetIsolate()),
470 SKIP_WRITE_BARRIER);
471 SetFeedbackExtra(*TypeFeedbackVector::UninitializedSentinel(GetIsolate()),
472 SKIP_WRITE_BARRIER);
473 }
474
475
ConfigurePremonomorphic()476 void FeedbackNexus::ConfigurePremonomorphic() {
477 SetFeedback(*TypeFeedbackVector::PremonomorphicSentinel(GetIsolate()),
478 SKIP_WRITE_BARRIER);
479 SetFeedbackExtra(*TypeFeedbackVector::UninitializedSentinel(GetIsolate()),
480 SKIP_WRITE_BARRIER);
481 }
482
483
ConfigureMegamorphic()484 void FeedbackNexus::ConfigureMegamorphic() {
485 // Keyed ICs must use ConfigureMegamorphicKeyed.
486 DCHECK_NE(FeedbackVectorSlotKind::KEYED_LOAD_IC, vector()->GetKind(slot()));
487 DCHECK_NE(FeedbackVectorSlotKind::KEYED_STORE_IC, vector()->GetKind(slot()));
488
489 Isolate* isolate = GetIsolate();
490 SetFeedback(*TypeFeedbackVector::MegamorphicSentinel(isolate),
491 SKIP_WRITE_BARRIER);
492 SetFeedbackExtra(*TypeFeedbackVector::UninitializedSentinel(isolate),
493 SKIP_WRITE_BARRIER);
494 }
495
ConfigureMegamorphicKeyed(IcCheckType property_type)496 void KeyedLoadICNexus::ConfigureMegamorphicKeyed(IcCheckType property_type) {
497 Isolate* isolate = GetIsolate();
498 SetFeedback(*TypeFeedbackVector::MegamorphicSentinel(isolate),
499 SKIP_WRITE_BARRIER);
500 SetFeedbackExtra(Smi::FromInt(static_cast<int>(property_type)),
501 SKIP_WRITE_BARRIER);
502 }
503
ConfigureMegamorphicKeyed(IcCheckType property_type)504 void KeyedStoreICNexus::ConfigureMegamorphicKeyed(IcCheckType property_type) {
505 Isolate* isolate = GetIsolate();
506 SetFeedback(*TypeFeedbackVector::MegamorphicSentinel(isolate),
507 SKIP_WRITE_BARRIER);
508 SetFeedbackExtra(Smi::FromInt(static_cast<int>(property_type)),
509 SKIP_WRITE_BARRIER);
510 }
511
StateFromFeedback() const512 InlineCacheState LoadICNexus::StateFromFeedback() const {
513 Isolate* isolate = GetIsolate();
514 Object* feedback = GetFeedback();
515
516 if (feedback == *TypeFeedbackVector::UninitializedSentinel(isolate)) {
517 return UNINITIALIZED;
518 } else if (feedback == *TypeFeedbackVector::MegamorphicSentinel(isolate)) {
519 return MEGAMORPHIC;
520 } else if (feedback == *TypeFeedbackVector::PremonomorphicSentinel(isolate)) {
521 return PREMONOMORPHIC;
522 } else if (feedback->IsFixedArray()) {
523 // Determine state purely by our structure, don't check if the maps are
524 // cleared.
525 return POLYMORPHIC;
526 } else if (feedback->IsWeakCell()) {
527 // Don't check if the map is cleared.
528 return MONOMORPHIC;
529 }
530
531 return UNINITIALIZED;
532 }
533
StateFromFeedback() const534 InlineCacheState LoadGlobalICNexus::StateFromFeedback() const {
535 Isolate* isolate = GetIsolate();
536 Object* feedback = GetFeedback();
537
538 Object* extra = GetFeedbackExtra();
539 if (!WeakCell::cast(feedback)->cleared() ||
540 extra != *TypeFeedbackVector::UninitializedSentinel(isolate)) {
541 return MONOMORPHIC;
542 }
543 return UNINITIALIZED;
544 }
545
StateFromFeedback() const546 InlineCacheState KeyedLoadICNexus::StateFromFeedback() const {
547 Isolate* isolate = GetIsolate();
548 Object* feedback = GetFeedback();
549
550 if (feedback == *TypeFeedbackVector::UninitializedSentinel(isolate)) {
551 return UNINITIALIZED;
552 } else if (feedback == *TypeFeedbackVector::PremonomorphicSentinel(isolate)) {
553 return PREMONOMORPHIC;
554 } else if (feedback == *TypeFeedbackVector::MegamorphicSentinel(isolate)) {
555 return MEGAMORPHIC;
556 } else if (feedback->IsFixedArray()) {
557 // Determine state purely by our structure, don't check if the maps are
558 // cleared.
559 return POLYMORPHIC;
560 } else if (feedback->IsWeakCell()) {
561 // Don't check if the map is cleared.
562 return MONOMORPHIC;
563 } else if (feedback->IsName()) {
564 Object* extra = GetFeedbackExtra();
565 FixedArray* extra_array = FixedArray::cast(extra);
566 return extra_array->length() > 2 ? POLYMORPHIC : MONOMORPHIC;
567 }
568
569 return UNINITIALIZED;
570 }
571
572
StateFromFeedback() const573 InlineCacheState StoreICNexus::StateFromFeedback() const {
574 Isolate* isolate = GetIsolate();
575 Object* feedback = GetFeedback();
576
577 if (feedback == *TypeFeedbackVector::UninitializedSentinel(isolate)) {
578 return UNINITIALIZED;
579 } else if (feedback == *TypeFeedbackVector::MegamorphicSentinel(isolate)) {
580 return MEGAMORPHIC;
581 } else if (feedback == *TypeFeedbackVector::PremonomorphicSentinel(isolate)) {
582 return PREMONOMORPHIC;
583 } else if (feedback->IsFixedArray()) {
584 // Determine state purely by our structure, don't check if the maps are
585 // cleared.
586 return POLYMORPHIC;
587 } else if (feedback->IsWeakCell()) {
588 // Don't check if the map is cleared.
589 return MONOMORPHIC;
590 }
591
592 return UNINITIALIZED;
593 }
594
595
StateFromFeedback() const596 InlineCacheState KeyedStoreICNexus::StateFromFeedback() const {
597 Isolate* isolate = GetIsolate();
598 Object* feedback = GetFeedback();
599
600 if (feedback == *TypeFeedbackVector::UninitializedSentinel(isolate)) {
601 return UNINITIALIZED;
602 } else if (feedback == *TypeFeedbackVector::PremonomorphicSentinel(isolate)) {
603 return PREMONOMORPHIC;
604 } else if (feedback == *TypeFeedbackVector::MegamorphicSentinel(isolate)) {
605 return MEGAMORPHIC;
606 } else if (feedback->IsFixedArray()) {
607 // Determine state purely by our structure, don't check if the maps are
608 // cleared.
609 return POLYMORPHIC;
610 } else if (feedback->IsWeakCell()) {
611 // Don't check if the map is cleared.
612 return MONOMORPHIC;
613 } else if (feedback->IsName()) {
614 Object* extra = GetFeedbackExtra();
615 FixedArray* extra_array = FixedArray::cast(extra);
616 return extra_array->length() > 2 ? POLYMORPHIC : MONOMORPHIC;
617 }
618
619 return UNINITIALIZED;
620 }
621
622
StateFromFeedback() const623 InlineCacheState CallICNexus::StateFromFeedback() const {
624 Isolate* isolate = GetIsolate();
625 Object* feedback = GetFeedback();
626 DCHECK(GetFeedbackExtra() ==
627 *TypeFeedbackVector::UninitializedSentinel(isolate) ||
628 GetFeedbackExtra()->IsSmi());
629
630 if (feedback == *TypeFeedbackVector::MegamorphicSentinel(isolate)) {
631 return GENERIC;
632 } else if (feedback->IsAllocationSite() || feedback->IsWeakCell()) {
633 return MONOMORPHIC;
634 }
635
636 CHECK(feedback == *TypeFeedbackVector::UninitializedSentinel(isolate));
637 return UNINITIALIZED;
638 }
639
640
ExtractCallCount()641 int CallICNexus::ExtractCallCount() {
642 Object* call_count = GetFeedbackExtra();
643 CHECK(call_count->IsSmi());
644 int value = Smi::cast(call_count)->value();
645 return value;
646 }
647
ComputeCallFrequency()648 float CallICNexus::ComputeCallFrequency() {
649 double const invocation_count = vector()->invocation_count();
650 double const call_count = ExtractCallCount();
651 return static_cast<float>(call_count / invocation_count);
652 }
653
Clear(Code * host)654 void CallICNexus::Clear(Code* host) { CallIC::Clear(GetIsolate(), host, this); }
655
ConfigureUninitialized()656 void CallICNexus::ConfigureUninitialized() {
657 Isolate* isolate = GetIsolate();
658 SetFeedback(*TypeFeedbackVector::UninitializedSentinel(isolate),
659 SKIP_WRITE_BARRIER);
660 SetFeedbackExtra(Smi::kZero, SKIP_WRITE_BARRIER);
661 }
662
ConfigureMonomorphicArray()663 void CallICNexus::ConfigureMonomorphicArray() {
664 Object* feedback = GetFeedback();
665 if (!feedback->IsAllocationSite()) {
666 Handle<AllocationSite> new_site =
667 GetIsolate()->factory()->NewAllocationSite();
668 SetFeedback(*new_site);
669 }
670 SetFeedbackExtra(Smi::FromInt(1), SKIP_WRITE_BARRIER);
671 }
672
673
ConfigureMonomorphic(Handle<JSFunction> function)674 void CallICNexus::ConfigureMonomorphic(Handle<JSFunction> function) {
675 Handle<WeakCell> new_cell = GetIsolate()->factory()->NewWeakCell(function);
676 SetFeedback(*new_cell);
677 SetFeedbackExtra(Smi::FromInt(1), SKIP_WRITE_BARRIER);
678 }
679
680
ConfigureMegamorphic()681 void CallICNexus::ConfigureMegamorphic() {
682 SetFeedback(*TypeFeedbackVector::MegamorphicSentinel(GetIsolate()),
683 SKIP_WRITE_BARRIER);
684 Smi* count = Smi::cast(GetFeedbackExtra());
685 int new_count = count->value() + 1;
686 SetFeedbackExtra(Smi::FromInt(new_count), SKIP_WRITE_BARRIER);
687 }
688
ConfigureMegamorphic(int call_count)689 void CallICNexus::ConfigureMegamorphic(int call_count) {
690 SetFeedback(*TypeFeedbackVector::MegamorphicSentinel(GetIsolate()),
691 SKIP_WRITE_BARRIER);
692 SetFeedbackExtra(Smi::FromInt(call_count), SKIP_WRITE_BARRIER);
693 }
694
ConfigureMonomorphic(Handle<Map> receiver_map,Handle<Object> handler)695 void LoadICNexus::ConfigureMonomorphic(Handle<Map> receiver_map,
696 Handle<Object> handler) {
697 Handle<WeakCell> cell = Map::WeakCellForMap(receiver_map);
698 SetFeedback(*cell);
699 SetFeedbackExtra(*handler);
700 }
701
ConfigureUninitialized()702 void LoadGlobalICNexus::ConfigureUninitialized() {
703 Isolate* isolate = GetIsolate();
704 SetFeedback(isolate->heap()->empty_weak_cell(), SKIP_WRITE_BARRIER);
705 SetFeedbackExtra(*TypeFeedbackVector::UninitializedSentinel(isolate),
706 SKIP_WRITE_BARRIER);
707 }
708
ConfigurePropertyCellMode(Handle<PropertyCell> cell)709 void LoadGlobalICNexus::ConfigurePropertyCellMode(Handle<PropertyCell> cell) {
710 Isolate* isolate = GetIsolate();
711 SetFeedback(*isolate->factory()->NewWeakCell(cell));
712 SetFeedbackExtra(*TypeFeedbackVector::UninitializedSentinel(isolate),
713 SKIP_WRITE_BARRIER);
714 }
715
ConfigureHandlerMode(Handle<Code> handler)716 void LoadGlobalICNexus::ConfigureHandlerMode(Handle<Code> handler) {
717 SetFeedback(GetIsolate()->heap()->empty_weak_cell());
718 SetFeedbackExtra(*handler);
719 }
720
ConfigureMonomorphic(Handle<Name> name,Handle<Map> receiver_map,Handle<Object> handler)721 void KeyedLoadICNexus::ConfigureMonomorphic(Handle<Name> name,
722 Handle<Map> receiver_map,
723 Handle<Object> handler) {
724 Handle<WeakCell> cell = Map::WeakCellForMap(receiver_map);
725 if (name.is_null()) {
726 SetFeedback(*cell);
727 SetFeedbackExtra(*handler);
728 } else {
729 Handle<FixedArray> array = EnsureExtraArrayOfSize(2);
730 SetFeedback(*name);
731 array->set(0, *cell);
732 array->set(1, *handler);
733 }
734 }
735
ConfigureMonomorphic(Handle<Map> receiver_map,Handle<Object> handler)736 void StoreICNexus::ConfigureMonomorphic(Handle<Map> receiver_map,
737 Handle<Object> handler) {
738 Handle<WeakCell> cell = Map::WeakCellForMap(receiver_map);
739 SetFeedback(*cell);
740 SetFeedbackExtra(*handler);
741 }
742
ConfigureMonomorphic(Handle<Name> name,Handle<Map> receiver_map,Handle<Object> handler)743 void KeyedStoreICNexus::ConfigureMonomorphic(Handle<Name> name,
744 Handle<Map> receiver_map,
745 Handle<Object> handler) {
746 Handle<WeakCell> cell = Map::WeakCellForMap(receiver_map);
747 if (name.is_null()) {
748 SetFeedback(*cell);
749 SetFeedbackExtra(*handler);
750 } else {
751 Handle<FixedArray> array = EnsureExtraArrayOfSize(2);
752 SetFeedback(*name);
753 array->set(0, *cell);
754 array->set(1, *handler);
755 }
756 }
757
ConfigurePolymorphic(MapHandleList * maps,List<Handle<Object>> * handlers)758 void LoadICNexus::ConfigurePolymorphic(MapHandleList* maps,
759 List<Handle<Object>>* handlers) {
760 Isolate* isolate = GetIsolate();
761 int receiver_count = maps->length();
762 Handle<FixedArray> array = EnsureArrayOfSize(receiver_count * 2);
763 InstallHandlers(array, maps, handlers);
764 SetFeedbackExtra(*TypeFeedbackVector::UninitializedSentinel(isolate),
765 SKIP_WRITE_BARRIER);
766 }
767
ConfigurePolymorphic(Handle<Name> name,MapHandleList * maps,List<Handle<Object>> * handlers)768 void KeyedLoadICNexus::ConfigurePolymorphic(Handle<Name> name,
769 MapHandleList* maps,
770 List<Handle<Object>>* handlers) {
771 int receiver_count = maps->length();
772 DCHECK(receiver_count > 1);
773 Handle<FixedArray> array;
774 if (name.is_null()) {
775 array = EnsureArrayOfSize(receiver_count * 2);
776 SetFeedbackExtra(*TypeFeedbackVector::UninitializedSentinel(GetIsolate()),
777 SKIP_WRITE_BARRIER);
778 } else {
779 array = EnsureExtraArrayOfSize(receiver_count * 2);
780 SetFeedback(*name);
781 }
782
783 InstallHandlers(array, maps, handlers);
784 }
785
ConfigurePolymorphic(MapHandleList * maps,List<Handle<Object>> * handlers)786 void StoreICNexus::ConfigurePolymorphic(MapHandleList* maps,
787 List<Handle<Object>>* handlers) {
788 Isolate* isolate = GetIsolate();
789 int receiver_count = maps->length();
790 Handle<FixedArray> array = EnsureArrayOfSize(receiver_count * 2);
791 InstallHandlers(array, maps, handlers);
792 SetFeedbackExtra(*TypeFeedbackVector::UninitializedSentinel(isolate),
793 SKIP_WRITE_BARRIER);
794 }
795
ConfigurePolymorphic(Handle<Name> name,MapHandleList * maps,List<Handle<Object>> * handlers)796 void KeyedStoreICNexus::ConfigurePolymorphic(Handle<Name> name,
797 MapHandleList* maps,
798 List<Handle<Object>>* handlers) {
799 int receiver_count = maps->length();
800 DCHECK(receiver_count > 1);
801 Handle<FixedArray> array;
802 if (name.is_null()) {
803 array = EnsureArrayOfSize(receiver_count * 2);
804 SetFeedbackExtra(*TypeFeedbackVector::UninitializedSentinel(GetIsolate()),
805 SKIP_WRITE_BARRIER);
806 } else {
807 array = EnsureExtraArrayOfSize(receiver_count * 2);
808 SetFeedback(*name);
809 }
810
811 InstallHandlers(array, maps, handlers);
812 }
813
814
ConfigurePolymorphic(MapHandleList * maps,MapHandleList * transitioned_maps,CodeHandleList * handlers)815 void KeyedStoreICNexus::ConfigurePolymorphic(MapHandleList* maps,
816 MapHandleList* transitioned_maps,
817 CodeHandleList* handlers) {
818 int receiver_count = maps->length();
819 DCHECK(receiver_count > 1);
820 Handle<FixedArray> array = EnsureArrayOfSize(receiver_count * 3);
821 SetFeedbackExtra(*TypeFeedbackVector::UninitializedSentinel(GetIsolate()),
822 SKIP_WRITE_BARRIER);
823
824 Handle<Oddball> undefined_value = GetIsolate()->factory()->undefined_value();
825 for (int i = 0; i < receiver_count; ++i) {
826 Handle<Map> map = maps->at(i);
827 Handle<WeakCell> cell = Map::WeakCellForMap(map);
828 array->set(i * 3, *cell);
829 if (!transitioned_maps->at(i).is_null()) {
830 Handle<Map> transitioned_map = transitioned_maps->at(i);
831 cell = Map::WeakCellForMap(transitioned_map);
832 array->set((i * 3) + 1, *cell);
833 } else {
834 array->set((i * 3) + 1, *undefined_value);
835 }
836 array->set((i * 3) + 2, *handlers->at(i));
837 }
838 }
839
840 namespace {
841
GetStepSize(FixedArray * array,Isolate * isolate)842 int GetStepSize(FixedArray* array, Isolate* isolate) {
843 // The array should be of the form
844 // [map, handler, map, handler, ...]
845 // or
846 // [map, map, handler, map, map, handler, ...]
847 // where "map" is either a WeakCell or |undefined|,
848 // and "handler" is either a Code object or a Smi.
849 DCHECK(array->length() >= 2);
850 Object* second = array->get(1);
851 if (second->IsWeakCell() || second->IsUndefined(isolate)) return 3;
852 DCHECK(IC::IsHandler(second));
853 return 2;
854 }
855
856 } // namespace
857
ExtractMaps(MapHandleList * maps) const858 int FeedbackNexus::ExtractMaps(MapHandleList* maps) const {
859 Isolate* isolate = GetIsolate();
860 Object* feedback = GetFeedback();
861 bool is_named_feedback = IsPropertyNameFeedback(feedback);
862 if (feedback->IsFixedArray() || is_named_feedback) {
863 int found = 0;
864 if (is_named_feedback) {
865 feedback = GetFeedbackExtra();
866 }
867 FixedArray* array = FixedArray::cast(feedback);
868 int increment = GetStepSize(array, isolate);
869 for (int i = 0; i < array->length(); i += increment) {
870 DCHECK(array->get(i)->IsWeakCell());
871 WeakCell* cell = WeakCell::cast(array->get(i));
872 if (!cell->cleared()) {
873 Map* map = Map::cast(cell->value());
874 maps->Add(handle(map, isolate));
875 found++;
876 }
877 }
878 return found;
879 } else if (feedback->IsWeakCell()) {
880 WeakCell* cell = WeakCell::cast(feedback);
881 if (!cell->cleared()) {
882 Map* map = Map::cast(cell->value());
883 maps->Add(handle(map, isolate));
884 return 1;
885 }
886 }
887
888 return 0;
889 }
890
FindHandlerForMap(Handle<Map> map) const891 MaybeHandle<Object> FeedbackNexus::FindHandlerForMap(Handle<Map> map) const {
892 Object* feedback = GetFeedback();
893 Isolate* isolate = GetIsolate();
894 bool is_named_feedback = IsPropertyNameFeedback(feedback);
895 if (feedback->IsFixedArray() || is_named_feedback) {
896 if (is_named_feedback) {
897 feedback = GetFeedbackExtra();
898 }
899 FixedArray* array = FixedArray::cast(feedback);
900 int increment = GetStepSize(array, isolate);
901 for (int i = 0; i < array->length(); i += increment) {
902 DCHECK(array->get(i)->IsWeakCell());
903 WeakCell* cell = WeakCell::cast(array->get(i));
904 if (!cell->cleared()) {
905 Map* array_map = Map::cast(cell->value());
906 if (array_map == *map) {
907 Object* code = array->get(i + increment - 1);
908 DCHECK(IC::IsHandler(code));
909 return handle(code, isolate);
910 }
911 }
912 }
913 } else if (feedback->IsWeakCell()) {
914 WeakCell* cell = WeakCell::cast(feedback);
915 if (!cell->cleared()) {
916 Map* cell_map = Map::cast(cell->value());
917 if (cell_map == *map) {
918 Object* code = GetFeedbackExtra();
919 DCHECK(IC::IsHandler(code));
920 return handle(code, isolate);
921 }
922 }
923 }
924
925 return MaybeHandle<Code>();
926 }
927
FindHandlers(List<Handle<Object>> * code_list,int length) const928 bool FeedbackNexus::FindHandlers(List<Handle<Object>>* code_list,
929 int length) const {
930 Object* feedback = GetFeedback();
931 Isolate* isolate = GetIsolate();
932 int count = 0;
933 bool is_named_feedback = IsPropertyNameFeedback(feedback);
934 if (feedback->IsFixedArray() || is_named_feedback) {
935 if (is_named_feedback) {
936 feedback = GetFeedbackExtra();
937 }
938 FixedArray* array = FixedArray::cast(feedback);
939 int increment = GetStepSize(array, isolate);
940 for (int i = 0; i < array->length(); i += increment) {
941 DCHECK(array->get(i)->IsWeakCell());
942 WeakCell* cell = WeakCell::cast(array->get(i));
943 // Be sure to skip handlers whose maps have been cleared.
944 if (!cell->cleared()) {
945 Object* code = array->get(i + increment - 1);
946 DCHECK(IC::IsHandler(code));
947 code_list->Add(handle(code, isolate));
948 count++;
949 }
950 }
951 } else if (feedback->IsWeakCell()) {
952 WeakCell* cell = WeakCell::cast(feedback);
953 if (!cell->cleared()) {
954 Object* code = GetFeedbackExtra();
955 DCHECK(IC::IsHandler(code));
956 code_list->Add(handle(code, isolate));
957 count++;
958 }
959 }
960 return count == length;
961 }
962
963
Clear(Code * host)964 void LoadICNexus::Clear(Code* host) { LoadIC::Clear(GetIsolate(), host, this); }
965
Clear(Code * host)966 void LoadGlobalICNexus::Clear(Code* host) {
967 LoadGlobalIC::Clear(GetIsolate(), host, this);
968 }
969
Clear(Code * host)970 void KeyedLoadICNexus::Clear(Code* host) {
971 KeyedLoadIC::Clear(GetIsolate(), host, this);
972 }
973
974
FindFirstName() const975 Name* KeyedLoadICNexus::FindFirstName() const {
976 Object* feedback = GetFeedback();
977 if (IsPropertyNameFeedback(feedback)) {
978 return Name::cast(feedback);
979 }
980 return NULL;
981 }
982
983
FindFirstName() const984 Name* KeyedStoreICNexus::FindFirstName() const {
985 Object* feedback = GetFeedback();
986 if (IsPropertyNameFeedback(feedback)) {
987 return Name::cast(feedback);
988 }
989 return NULL;
990 }
991
992
Clear(Code * host)993 void StoreICNexus::Clear(Code* host) {
994 StoreIC::Clear(GetIsolate(), host, this);
995 }
996
997
Clear(Code * host)998 void KeyedStoreICNexus::Clear(Code* host) {
999 KeyedStoreIC::Clear(GetIsolate(), host, this);
1000 }
1001
1002
GetKeyedAccessStoreMode() const1003 KeyedAccessStoreMode KeyedStoreICNexus::GetKeyedAccessStoreMode() const {
1004 KeyedAccessStoreMode mode = STANDARD_STORE;
1005 MapHandleList maps;
1006 List<Handle<Object>> handlers;
1007
1008 if (GetKeyType() == PROPERTY) return mode;
1009
1010 ExtractMaps(&maps);
1011 FindHandlers(&handlers, maps.length());
1012 for (int i = 0; i < handlers.length(); i++) {
1013 // The first handler that isn't the slow handler will have the bits we need.
1014 Handle<Code> handler = Handle<Code>::cast(handlers.at(i));
1015 CodeStub::Major major_key = CodeStub::MajorKeyFromKey(handler->stub_key());
1016 uint32_t minor_key = CodeStub::MinorKeyFromKey(handler->stub_key());
1017 CHECK(major_key == CodeStub::KeyedStoreSloppyArguments ||
1018 major_key == CodeStub::StoreFastElement ||
1019 major_key == CodeStub::StoreElement ||
1020 major_key == CodeStub::ElementsTransitionAndStore ||
1021 major_key == CodeStub::NoCache);
1022 if (major_key != CodeStub::NoCache) {
1023 mode = CommonStoreModeBits::decode(minor_key);
1024 break;
1025 }
1026 }
1027
1028 return mode;
1029 }
1030
GetKeyType() const1031 IcCheckType KeyedLoadICNexus::GetKeyType() const {
1032 Object* feedback = GetFeedback();
1033 if (feedback == *TypeFeedbackVector::MegamorphicSentinel(GetIsolate())) {
1034 return static_cast<IcCheckType>(Smi::cast(GetFeedbackExtra())->value());
1035 }
1036 return IsPropertyNameFeedback(feedback) ? PROPERTY : ELEMENT;
1037 }
1038
GetKeyType() const1039 IcCheckType KeyedStoreICNexus::GetKeyType() const {
1040 Object* feedback = GetFeedback();
1041 if (feedback == *TypeFeedbackVector::MegamorphicSentinel(GetIsolate())) {
1042 return static_cast<IcCheckType>(Smi::cast(GetFeedbackExtra())->value());
1043 }
1044 return IsPropertyNameFeedback(feedback) ? PROPERTY : ELEMENT;
1045 }
1046
StateFromFeedback() const1047 InlineCacheState BinaryOpICNexus::StateFromFeedback() const {
1048 BinaryOperationHint hint = GetBinaryOperationFeedback();
1049 if (hint == BinaryOperationHint::kNone) {
1050 return UNINITIALIZED;
1051 } else if (hint == BinaryOperationHint::kAny) {
1052 return GENERIC;
1053 }
1054
1055 return MONOMORPHIC;
1056 }
1057
StateFromFeedback() const1058 InlineCacheState CompareICNexus::StateFromFeedback() const {
1059 CompareOperationHint hint = GetCompareOperationFeedback();
1060 if (hint == CompareOperationHint::kNone) {
1061 return UNINITIALIZED;
1062 } else if (hint == CompareOperationHint::kAny) {
1063 return GENERIC;
1064 }
1065
1066 return MONOMORPHIC;
1067 }
1068
GetBinaryOperationFeedback() const1069 BinaryOperationHint BinaryOpICNexus::GetBinaryOperationFeedback() const {
1070 int feedback = Smi::cast(GetFeedback())->value();
1071 return BinaryOperationHintFromFeedback(feedback);
1072 }
1073
GetCompareOperationFeedback() const1074 CompareOperationHint CompareICNexus::GetCompareOperationFeedback() const {
1075 int feedback = Smi::cast(GetFeedback())->value();
1076 return CompareOperationHintFromFeedback(feedback);
1077 }
1078
1079 } // namespace internal
1080 } // namespace v8
1081