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.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 return feedback->IsString() ||
19 (feedback->IsSymbol() && !Symbol::cast(feedback)->is_private());
20 }
21
22
operator <<(std::ostream & os,FeedbackVectorSlotKind kind)23 std::ostream& operator<<(std::ostream& os, FeedbackVectorSlotKind kind) {
24 return os << TypeFeedbackMetadata::Kind2String(kind);
25 }
26
27
GetKind(FeedbackVectorSlot slot) const28 FeedbackVectorSlotKind TypeFeedbackMetadata::GetKind(
29 FeedbackVectorSlot slot) const {
30 int index = VectorICComputer::index(kReservedIndexCount, slot.ToInt());
31 int data = Smi::cast(get(index))->value();
32 return VectorICComputer::decode(data, slot.ToInt());
33 }
34
35
SetKind(FeedbackVectorSlot slot,FeedbackVectorSlotKind kind)36 void TypeFeedbackMetadata::SetKind(FeedbackVectorSlot slot,
37 FeedbackVectorSlotKind kind) {
38 int index = VectorICComputer::index(kReservedIndexCount, slot.ToInt());
39 int data = Smi::cast(get(index))->value();
40 int new_data = VectorICComputer::encode(data, slot.ToInt(), kind);
41 set(index, Smi::FromInt(new_data));
42 }
43
44
45 template Handle<TypeFeedbackMetadata> TypeFeedbackMetadata::New(
46 Isolate* isolate, const StaticFeedbackVectorSpec* spec);
47 template Handle<TypeFeedbackMetadata> TypeFeedbackMetadata::New(
48 Isolate* isolate, const FeedbackVectorSpec* spec);
49
50
51 // static
52 template <typename Spec>
New(Isolate * isolate,const Spec * spec)53 Handle<TypeFeedbackMetadata> TypeFeedbackMetadata::New(Isolate* isolate,
54 const Spec* spec) {
55 const int slot_count = spec->slots();
56 const int slot_kinds_length = VectorICComputer::word_count(slot_count);
57 const int length = slot_kinds_length + kReservedIndexCount;
58 if (length == kReservedIndexCount) {
59 return Handle<TypeFeedbackMetadata>::cast(
60 isolate->factory()->empty_fixed_array());
61 }
62 #ifdef DEBUG
63 for (int i = 0; i < slot_count;) {
64 FeedbackVectorSlotKind kind = spec->GetKind(i);
65 int entry_size = TypeFeedbackMetadata::GetSlotSize(kind);
66 for (int j = 1; j < entry_size; j++) {
67 FeedbackVectorSlotKind kind = spec->GetKind(i + j);
68 DCHECK_EQ(FeedbackVectorSlotKind::INVALID, kind);
69 }
70 i += entry_size;
71 }
72 #endif
73
74 Handle<FixedArray> array = isolate->factory()->NewFixedArray(length, TENURED);
75 array->set(kSlotsCountIndex, Smi::FromInt(slot_count));
76 // Fill the bit-vector part with zeros.
77 for (int i = 0; i < slot_kinds_length; i++) {
78 array->set(kReservedIndexCount + i, Smi::FromInt(0));
79 }
80
81 Handle<TypeFeedbackMetadata> metadata =
82 Handle<TypeFeedbackMetadata>::cast(array);
83 for (int i = 0; i < slot_count; i++) {
84 metadata->SetKind(FeedbackVectorSlot(i), spec->GetKind(i));
85 }
86 return metadata;
87 }
88
89
SpecDiffersFrom(const FeedbackVectorSpec * other_spec) const90 bool TypeFeedbackMetadata::SpecDiffersFrom(
91 const FeedbackVectorSpec* other_spec) const {
92 if (other_spec->slots() != slot_count()) {
93 return true;
94 }
95
96 int slots = slot_count();
97 for (int i = 0; i < slots; i++) {
98 if (GetKind(FeedbackVectorSlot(i)) != other_spec->GetKind(i)) {
99 return true;
100 }
101 }
102 return false;
103 }
104
105
Kind2String(FeedbackVectorSlotKind kind)106 const char* TypeFeedbackMetadata::Kind2String(FeedbackVectorSlotKind kind) {
107 switch (kind) {
108 case FeedbackVectorSlotKind::INVALID:
109 return "INVALID";
110 case FeedbackVectorSlotKind::CALL_IC:
111 return "CALL_IC";
112 case FeedbackVectorSlotKind::LOAD_IC:
113 return "LOAD_IC";
114 case FeedbackVectorSlotKind::KEYED_LOAD_IC:
115 return "KEYED_LOAD_IC";
116 case FeedbackVectorSlotKind::STORE_IC:
117 return "STORE_IC";
118 case FeedbackVectorSlotKind::KEYED_STORE_IC:
119 return "KEYED_STORE_IC";
120 case FeedbackVectorSlotKind::GENERAL:
121 return "STUB";
122 case FeedbackVectorSlotKind::KINDS_NUMBER:
123 break;
124 }
125 UNREACHABLE();
126 return "?";
127 }
128
129
130 // static
New(Isolate * isolate,Handle<TypeFeedbackMetadata> metadata)131 Handle<TypeFeedbackVector> TypeFeedbackVector::New(
132 Isolate* isolate, Handle<TypeFeedbackMetadata> metadata) {
133 Factory* factory = isolate->factory();
134
135 const int slot_count = metadata->slot_count();
136 const int length = slot_count + kReservedIndexCount;
137 if (length == kReservedIndexCount) {
138 return Handle<TypeFeedbackVector>::cast(factory->empty_fixed_array());
139 }
140
141 Handle<FixedArray> array = factory->NewFixedArray(length, TENURED);
142 array->set(kMetadataIndex, *metadata);
143
144 // Ensure we can skip the write barrier
145 Handle<Object> uninitialized_sentinel = UninitializedSentinel(isolate);
146 DCHECK_EQ(*factory->uninitialized_symbol(), *uninitialized_sentinel);
147 for (int i = kReservedIndexCount; i < length; i++) {
148 array->set(i, *uninitialized_sentinel, SKIP_WRITE_BARRIER);
149 }
150
151 return Handle<TypeFeedbackVector>::cast(array);
152 }
153
154
155 // static
GetIndexFromSpec(const FeedbackVectorSpec * spec,FeedbackVectorSlot slot)156 int TypeFeedbackVector::GetIndexFromSpec(const FeedbackVectorSpec* spec,
157 FeedbackVectorSlot slot) {
158 return kReservedIndexCount + slot.ToInt();
159 }
160
161
162 // static
Copy(Isolate * isolate,Handle<TypeFeedbackVector> vector)163 Handle<TypeFeedbackVector> TypeFeedbackVector::Copy(
164 Isolate* isolate, Handle<TypeFeedbackVector> vector) {
165 Handle<TypeFeedbackVector> result;
166 result = Handle<TypeFeedbackVector>::cast(
167 isolate->factory()->CopyFixedArray(Handle<FixedArray>::cast(vector)));
168 return result;
169 }
170
171
172 // This logic is copied from
173 // StaticMarkingVisitor<StaticVisitor>::VisitCodeTarget.
ClearLogic(Isolate * isolate)174 static bool ClearLogic(Isolate* isolate) {
175 return FLAG_cleanup_code_caches_at_gc && isolate->serializer_enabled();
176 }
177
178
ClearSlotsImpl(SharedFunctionInfo * shared,bool force_clear)179 void TypeFeedbackVector::ClearSlotsImpl(SharedFunctionInfo* shared,
180 bool force_clear) {
181 Isolate* isolate = GetIsolate();
182
183 if (!force_clear && !ClearLogic(isolate)) return;
184
185 Object* uninitialized_sentinel =
186 TypeFeedbackVector::RawUninitializedSentinel(isolate);
187
188 TypeFeedbackMetadataIterator iter(metadata());
189 while (iter.HasNext()) {
190 FeedbackVectorSlot slot = iter.Next();
191 FeedbackVectorSlotKind kind = iter.kind();
192
193 Object* obj = Get(slot);
194 if (obj != uninitialized_sentinel) {
195 switch (kind) {
196 case FeedbackVectorSlotKind::CALL_IC: {
197 CallICNexus nexus(this, slot);
198 nexus.Clear(shared->code());
199 break;
200 }
201 case FeedbackVectorSlotKind::LOAD_IC: {
202 LoadICNexus nexus(this, slot);
203 nexus.Clear(shared->code());
204 break;
205 }
206 case FeedbackVectorSlotKind::KEYED_LOAD_IC: {
207 KeyedLoadICNexus nexus(this, slot);
208 nexus.Clear(shared->code());
209 break;
210 }
211 case FeedbackVectorSlotKind::STORE_IC: {
212 StoreICNexus nexus(this, slot);
213 nexus.Clear(shared->code());
214 break;
215 }
216 case FeedbackVectorSlotKind::KEYED_STORE_IC: {
217 KeyedStoreICNexus nexus(this, slot);
218 nexus.Clear(shared->code());
219 break;
220 }
221 case FeedbackVectorSlotKind::GENERAL: {
222 if (obj->IsHeapObject()) {
223 InstanceType instance_type =
224 HeapObject::cast(obj)->map()->instance_type();
225 // AllocationSites are exempt from clearing. They don't store Maps
226 // or Code pointers which can cause memory leaks if not cleared
227 // regularly.
228 if (instance_type != ALLOCATION_SITE_TYPE) {
229 Set(slot, uninitialized_sentinel, SKIP_WRITE_BARRIER);
230 }
231 }
232 break;
233 }
234 case FeedbackVectorSlotKind::INVALID:
235 case FeedbackVectorSlotKind::KINDS_NUMBER:
236 UNREACHABLE();
237 break;
238 }
239 }
240 }
241 }
242
243
244 // static
ClearAllKeyedStoreICs(Isolate * isolate)245 void TypeFeedbackVector::ClearAllKeyedStoreICs(Isolate* isolate) {
246 SharedFunctionInfo::Iterator iterator(isolate);
247 SharedFunctionInfo* shared;
248 while ((shared = iterator.Next())) {
249 TypeFeedbackVector* vector = shared->feedback_vector();
250 vector->ClearKeyedStoreICs(shared);
251 }
252 }
253
254
ClearKeyedStoreICs(SharedFunctionInfo * shared)255 void TypeFeedbackVector::ClearKeyedStoreICs(SharedFunctionInfo* shared) {
256 Isolate* isolate = GetIsolate();
257
258 Code* host = shared->code();
259 Object* uninitialized_sentinel =
260 TypeFeedbackVector::RawUninitializedSentinel(isolate);
261
262 TypeFeedbackMetadataIterator iter(metadata());
263 while (iter.HasNext()) {
264 FeedbackVectorSlot slot = iter.Next();
265 FeedbackVectorSlotKind kind = iter.kind();
266 if (kind != FeedbackVectorSlotKind::KEYED_STORE_IC) continue;
267 Object* obj = Get(slot);
268 if (obj != uninitialized_sentinel) {
269 KeyedStoreICNexus nexus(this, slot);
270 nexus.Clear(host);
271 }
272 }
273 }
274
275
276 // static
DummyVector(Isolate * isolate)277 Handle<TypeFeedbackVector> TypeFeedbackVector::DummyVector(Isolate* isolate) {
278 return isolate->factory()->dummy_vector();
279 }
280
281
EnsureArrayOfSize(int length)282 Handle<FixedArray> FeedbackNexus::EnsureArrayOfSize(int length) {
283 Isolate* isolate = GetIsolate();
284 Handle<Object> feedback = handle(GetFeedback(), isolate);
285 if (!feedback->IsFixedArray() ||
286 FixedArray::cast(*feedback)->length() != length) {
287 Handle<FixedArray> array = isolate->factory()->NewFixedArray(length);
288 SetFeedback(*array);
289 return array;
290 }
291 return Handle<FixedArray>::cast(feedback);
292 }
293
294
EnsureExtraArrayOfSize(int length)295 Handle<FixedArray> FeedbackNexus::EnsureExtraArrayOfSize(int length) {
296 Isolate* isolate = GetIsolate();
297 Handle<Object> feedback_extra = handle(GetFeedbackExtra(), isolate);
298 if (!feedback_extra->IsFixedArray() ||
299 FixedArray::cast(*feedback_extra)->length() != length) {
300 Handle<FixedArray> array = isolate->factory()->NewFixedArray(length);
301 SetFeedbackExtra(*array);
302 return array;
303 }
304 return Handle<FixedArray>::cast(feedback_extra);
305 }
306
307
InstallHandlers(Handle<FixedArray> array,MapHandleList * maps,CodeHandleList * handlers)308 void FeedbackNexus::InstallHandlers(Handle<FixedArray> array,
309 MapHandleList* maps,
310 CodeHandleList* handlers) {
311 int receiver_count = maps->length();
312 for (int current = 0; current < receiver_count; ++current) {
313 Handle<Map> map = maps->at(current);
314 Handle<WeakCell> cell = Map::WeakCellForMap(map);
315 array->set(current * 2, *cell);
316 array->set(current * 2 + 1, *handlers->at(current));
317 }
318 }
319
320
ConfigureUninitialized()321 void FeedbackNexus::ConfigureUninitialized() {
322 SetFeedback(*TypeFeedbackVector::UninitializedSentinel(GetIsolate()),
323 SKIP_WRITE_BARRIER);
324 SetFeedbackExtra(*TypeFeedbackVector::UninitializedSentinel(GetIsolate()),
325 SKIP_WRITE_BARRIER);
326 }
327
328
ConfigurePremonomorphic()329 void FeedbackNexus::ConfigurePremonomorphic() {
330 SetFeedback(*TypeFeedbackVector::PremonomorphicSentinel(GetIsolate()),
331 SKIP_WRITE_BARRIER);
332 SetFeedbackExtra(*TypeFeedbackVector::UninitializedSentinel(GetIsolate()),
333 SKIP_WRITE_BARRIER);
334 }
335
336
ConfigureMegamorphic()337 void FeedbackNexus::ConfigureMegamorphic() {
338 Isolate* isolate = GetIsolate();
339 SetFeedback(*TypeFeedbackVector::MegamorphicSentinel(isolate),
340 SKIP_WRITE_BARRIER);
341 SetFeedbackExtra(*TypeFeedbackVector::UninitializedSentinel(isolate),
342 SKIP_WRITE_BARRIER);
343 }
344
345
StateFromFeedback() const346 InlineCacheState LoadICNexus::StateFromFeedback() const {
347 Isolate* isolate = GetIsolate();
348 Object* feedback = GetFeedback();
349
350 if (feedback == *TypeFeedbackVector::UninitializedSentinel(isolate)) {
351 return UNINITIALIZED;
352 } else if (feedback == *TypeFeedbackVector::MegamorphicSentinel(isolate)) {
353 return MEGAMORPHIC;
354 } else if (feedback == *TypeFeedbackVector::PremonomorphicSentinel(isolate)) {
355 return PREMONOMORPHIC;
356 } else if (feedback->IsFixedArray()) {
357 // Determine state purely by our structure, don't check if the maps are
358 // cleared.
359 return POLYMORPHIC;
360 } else if (feedback->IsWeakCell()) {
361 // Don't check if the map is cleared.
362 return MONOMORPHIC;
363 }
364
365 return UNINITIALIZED;
366 }
367
368
StateFromFeedback() const369 InlineCacheState KeyedLoadICNexus::StateFromFeedback() const {
370 Isolate* isolate = GetIsolate();
371 Object* feedback = GetFeedback();
372
373 if (feedback == *TypeFeedbackVector::UninitializedSentinel(isolate)) {
374 return UNINITIALIZED;
375 } else if (feedback == *TypeFeedbackVector::PremonomorphicSentinel(isolate)) {
376 return PREMONOMORPHIC;
377 } else if (feedback == *TypeFeedbackVector::MegamorphicSentinel(isolate)) {
378 return MEGAMORPHIC;
379 } else if (feedback->IsFixedArray()) {
380 // Determine state purely by our structure, don't check if the maps are
381 // cleared.
382 return POLYMORPHIC;
383 } else if (feedback->IsWeakCell()) {
384 // Don't check if the map is cleared.
385 return MONOMORPHIC;
386 } else if (feedback->IsName()) {
387 Object* extra = GetFeedbackExtra();
388 FixedArray* extra_array = FixedArray::cast(extra);
389 return extra_array->length() > 2 ? POLYMORPHIC : MONOMORPHIC;
390 }
391
392 return UNINITIALIZED;
393 }
394
395
StateFromFeedback() const396 InlineCacheState StoreICNexus::StateFromFeedback() const {
397 Isolate* isolate = GetIsolate();
398 Object* feedback = GetFeedback();
399
400 if (feedback == *TypeFeedbackVector::UninitializedSentinel(isolate)) {
401 return UNINITIALIZED;
402 } else if (feedback == *TypeFeedbackVector::MegamorphicSentinel(isolate)) {
403 return MEGAMORPHIC;
404 } else if (feedback == *TypeFeedbackVector::PremonomorphicSentinel(isolate)) {
405 return PREMONOMORPHIC;
406 } else if (feedback->IsFixedArray()) {
407 // Determine state purely by our structure, don't check if the maps are
408 // cleared.
409 return POLYMORPHIC;
410 } else if (feedback->IsWeakCell()) {
411 // Don't check if the map is cleared.
412 return MONOMORPHIC;
413 }
414
415 return UNINITIALIZED;
416 }
417
418
StateFromFeedback() const419 InlineCacheState KeyedStoreICNexus::StateFromFeedback() const {
420 Isolate* isolate = GetIsolate();
421 Object* feedback = GetFeedback();
422
423 if (feedback == *TypeFeedbackVector::UninitializedSentinel(isolate)) {
424 return UNINITIALIZED;
425 } else if (feedback == *TypeFeedbackVector::PremonomorphicSentinel(isolate)) {
426 return PREMONOMORPHIC;
427 } else if (feedback == *TypeFeedbackVector::MegamorphicSentinel(isolate)) {
428 return MEGAMORPHIC;
429 } else if (feedback->IsFixedArray()) {
430 // Determine state purely by our structure, don't check if the maps are
431 // cleared.
432 return POLYMORPHIC;
433 } else if (feedback->IsWeakCell()) {
434 // Don't check if the map is cleared.
435 return MONOMORPHIC;
436 } else if (feedback->IsName()) {
437 Object* extra = GetFeedbackExtra();
438 FixedArray* extra_array = FixedArray::cast(extra);
439 return extra_array->length() > 2 ? POLYMORPHIC : MONOMORPHIC;
440 }
441
442 return UNINITIALIZED;
443 }
444
445
StateFromFeedback() const446 InlineCacheState CallICNexus::StateFromFeedback() const {
447 Isolate* isolate = GetIsolate();
448 Object* feedback = GetFeedback();
449 DCHECK(GetFeedbackExtra() ==
450 *TypeFeedbackVector::UninitializedSentinel(isolate) ||
451 GetFeedbackExtra()->IsSmi());
452
453 if (feedback == *TypeFeedbackVector::MegamorphicSentinel(isolate)) {
454 return GENERIC;
455 } else if (feedback->IsAllocationSite() || feedback->IsWeakCell()) {
456 return MONOMORPHIC;
457 }
458
459 CHECK(feedback == *TypeFeedbackVector::UninitializedSentinel(isolate));
460 return UNINITIALIZED;
461 }
462
463
ExtractCallCount()464 int CallICNexus::ExtractCallCount() {
465 Object* call_count = GetFeedbackExtra();
466 if (call_count->IsSmi()) {
467 int value = Smi::cast(call_count)->value() / 2;
468 return value;
469 }
470 return -1;
471 }
472
473
Clear(Code * host)474 void CallICNexus::Clear(Code* host) { CallIC::Clear(GetIsolate(), host, this); }
475
476
ConfigureMonomorphicArray()477 void CallICNexus::ConfigureMonomorphicArray() {
478 Object* feedback = GetFeedback();
479 if (!feedback->IsAllocationSite()) {
480 Handle<AllocationSite> new_site =
481 GetIsolate()->factory()->NewAllocationSite();
482 SetFeedback(*new_site);
483 }
484 SetFeedbackExtra(Smi::FromInt(kCallCountIncrement), SKIP_WRITE_BARRIER);
485 }
486
487
ConfigureMonomorphic(Handle<JSFunction> function)488 void CallICNexus::ConfigureMonomorphic(Handle<JSFunction> function) {
489 Handle<WeakCell> new_cell = GetIsolate()->factory()->NewWeakCell(function);
490 SetFeedback(*new_cell);
491 SetFeedbackExtra(Smi::FromInt(kCallCountIncrement), SKIP_WRITE_BARRIER);
492 }
493
494
ConfigureMegamorphic()495 void CallICNexus::ConfigureMegamorphic() {
496 FeedbackNexus::ConfigureMegamorphic();
497 }
498
499
ConfigureMegamorphic(int call_count)500 void CallICNexus::ConfigureMegamorphic(int call_count) {
501 SetFeedback(*TypeFeedbackVector::MegamorphicSentinel(GetIsolate()),
502 SKIP_WRITE_BARRIER);
503 SetFeedbackExtra(Smi::FromInt(call_count * kCallCountIncrement),
504 SKIP_WRITE_BARRIER);
505 }
506
507
ConfigureMonomorphic(Handle<Map> receiver_map,Handle<Code> handler)508 void LoadICNexus::ConfigureMonomorphic(Handle<Map> receiver_map,
509 Handle<Code> handler) {
510 Handle<WeakCell> cell = Map::WeakCellForMap(receiver_map);
511 SetFeedback(*cell);
512 SetFeedbackExtra(*handler);
513 }
514
515
ConfigureMonomorphic(Handle<Name> name,Handle<Map> receiver_map,Handle<Code> handler)516 void KeyedLoadICNexus::ConfigureMonomorphic(Handle<Name> name,
517 Handle<Map> receiver_map,
518 Handle<Code> handler) {
519 Handle<WeakCell> cell = Map::WeakCellForMap(receiver_map);
520 if (name.is_null()) {
521 SetFeedback(*cell);
522 SetFeedbackExtra(*handler);
523 } else {
524 Handle<FixedArray> array = EnsureExtraArrayOfSize(2);
525 SetFeedback(*name);
526 array->set(0, *cell);
527 array->set(1, *handler);
528 }
529 }
530
531
ConfigureMonomorphic(Handle<Map> receiver_map,Handle<Code> handler)532 void StoreICNexus::ConfigureMonomorphic(Handle<Map> receiver_map,
533 Handle<Code> handler) {
534 Handle<WeakCell> cell = Map::WeakCellForMap(receiver_map);
535 SetFeedback(*cell);
536 SetFeedbackExtra(*handler);
537 }
538
539
ConfigureMonomorphic(Handle<Name> name,Handle<Map> receiver_map,Handle<Code> handler)540 void KeyedStoreICNexus::ConfigureMonomorphic(Handle<Name> name,
541 Handle<Map> receiver_map,
542 Handle<Code> handler) {
543 Handle<WeakCell> cell = Map::WeakCellForMap(receiver_map);
544 if (name.is_null()) {
545 SetFeedback(*cell);
546 SetFeedbackExtra(*handler);
547 } else {
548 Handle<FixedArray> array = EnsureExtraArrayOfSize(2);
549 SetFeedback(*name);
550 array->set(0, *cell);
551 array->set(1, *handler);
552 }
553 }
554
555
ConfigurePolymorphic(MapHandleList * maps,CodeHandleList * handlers)556 void LoadICNexus::ConfigurePolymorphic(MapHandleList* maps,
557 CodeHandleList* handlers) {
558 Isolate* isolate = GetIsolate();
559 int receiver_count = maps->length();
560 Handle<FixedArray> array = EnsureArrayOfSize(receiver_count * 2);
561 InstallHandlers(array, maps, handlers);
562 SetFeedbackExtra(*TypeFeedbackVector::UninitializedSentinel(isolate),
563 SKIP_WRITE_BARRIER);
564 }
565
566
ConfigurePolymorphic(Handle<Name> name,MapHandleList * maps,CodeHandleList * handlers)567 void KeyedLoadICNexus::ConfigurePolymorphic(Handle<Name> name,
568 MapHandleList* maps,
569 CodeHandleList* handlers) {
570 int receiver_count = maps->length();
571 DCHECK(receiver_count > 1);
572 Handle<FixedArray> array;
573 if (name.is_null()) {
574 array = EnsureArrayOfSize(receiver_count * 2);
575 SetFeedbackExtra(*TypeFeedbackVector::UninitializedSentinel(GetIsolate()),
576 SKIP_WRITE_BARRIER);
577 } else {
578 array = EnsureExtraArrayOfSize(receiver_count * 2);
579 SetFeedback(*name);
580 }
581
582 InstallHandlers(array, maps, handlers);
583 }
584
585
ConfigurePolymorphic(MapHandleList * maps,CodeHandleList * handlers)586 void StoreICNexus::ConfigurePolymorphic(MapHandleList* maps,
587 CodeHandleList* handlers) {
588 Isolate* isolate = GetIsolate();
589 int receiver_count = maps->length();
590 Handle<FixedArray> array = EnsureArrayOfSize(receiver_count * 2);
591 InstallHandlers(array, maps, handlers);
592 SetFeedbackExtra(*TypeFeedbackVector::UninitializedSentinel(isolate),
593 SKIP_WRITE_BARRIER);
594 }
595
596
ConfigurePolymorphic(Handle<Name> name,MapHandleList * maps,CodeHandleList * handlers)597 void KeyedStoreICNexus::ConfigurePolymorphic(Handle<Name> name,
598 MapHandleList* maps,
599 CodeHandleList* handlers) {
600 int receiver_count = maps->length();
601 DCHECK(receiver_count > 1);
602 Handle<FixedArray> array;
603 if (name.is_null()) {
604 array = EnsureArrayOfSize(receiver_count * 2);
605 SetFeedbackExtra(*TypeFeedbackVector::UninitializedSentinel(GetIsolate()),
606 SKIP_WRITE_BARRIER);
607 } else {
608 array = EnsureExtraArrayOfSize(receiver_count * 2);
609 SetFeedback(*name);
610 }
611
612 InstallHandlers(array, maps, handlers);
613 }
614
615
ConfigurePolymorphic(MapHandleList * maps,MapHandleList * transitioned_maps,CodeHandleList * handlers)616 void KeyedStoreICNexus::ConfigurePolymorphic(MapHandleList* maps,
617 MapHandleList* transitioned_maps,
618 CodeHandleList* handlers) {
619 int receiver_count = maps->length();
620 DCHECK(receiver_count > 1);
621 Handle<FixedArray> array = EnsureArrayOfSize(receiver_count * 3);
622 SetFeedbackExtra(*TypeFeedbackVector::UninitializedSentinel(GetIsolate()),
623 SKIP_WRITE_BARRIER);
624
625 Handle<Oddball> undefined_value = GetIsolate()->factory()->undefined_value();
626 for (int i = 0; i < receiver_count; ++i) {
627 Handle<Map> map = maps->at(i);
628 Handle<WeakCell> cell = Map::WeakCellForMap(map);
629 array->set(i * 3, *cell);
630 if (!transitioned_maps->at(i).is_null()) {
631 Handle<Map> transitioned_map = transitioned_maps->at(i);
632 cell = Map::WeakCellForMap(transitioned_map);
633 array->set((i * 3) + 1, *cell);
634 } else {
635 array->set((i * 3) + 1, *undefined_value);
636 }
637 array->set((i * 3) + 2, *handlers->at(i));
638 }
639 }
640
641
ExtractMaps(MapHandleList * maps) const642 int FeedbackNexus::ExtractMaps(MapHandleList* maps) const {
643 Isolate* isolate = GetIsolate();
644 Object* feedback = GetFeedback();
645 bool is_named_feedback = IsPropertyNameFeedback(feedback);
646 if (feedback->IsFixedArray() || is_named_feedback) {
647 int found = 0;
648 if (is_named_feedback) {
649 feedback = GetFeedbackExtra();
650 }
651 FixedArray* array = FixedArray::cast(feedback);
652 // The array should be of the form
653 // [map, handler, map, handler, ...]
654 // or
655 // [map, map, handler, map, map, handler, ...]
656 DCHECK(array->length() >= 2);
657 int increment = array->get(1)->IsCode() ? 2 : 3;
658 for (int i = 0; i < array->length(); i += increment) {
659 DCHECK(array->get(i)->IsWeakCell());
660 WeakCell* cell = WeakCell::cast(array->get(i));
661 if (!cell->cleared()) {
662 Map* map = Map::cast(cell->value());
663 maps->Add(handle(map, isolate));
664 found++;
665 }
666 }
667 return found;
668 } else if (feedback->IsWeakCell()) {
669 WeakCell* cell = WeakCell::cast(feedback);
670 if (!cell->cleared()) {
671 Map* map = Map::cast(cell->value());
672 maps->Add(handle(map, isolate));
673 return 1;
674 }
675 }
676
677 return 0;
678 }
679
680
FindHandlerForMap(Handle<Map> map) const681 MaybeHandle<Code> FeedbackNexus::FindHandlerForMap(Handle<Map> map) const {
682 Object* feedback = GetFeedback();
683 bool is_named_feedback = IsPropertyNameFeedback(feedback);
684 if (feedback->IsFixedArray() || is_named_feedback) {
685 if (is_named_feedback) {
686 feedback = GetFeedbackExtra();
687 }
688 FixedArray* array = FixedArray::cast(feedback);
689 DCHECK(array->length() >= 2);
690 int increment = array->get(1)->IsCode() ? 2 : 3;
691 for (int i = 0; i < array->length(); i += increment) {
692 DCHECK(array->get(i)->IsWeakCell());
693 WeakCell* cell = WeakCell::cast(array->get(i));
694 if (!cell->cleared()) {
695 Map* array_map = Map::cast(cell->value());
696 if (array_map == *map) {
697 Code* code = Code::cast(array->get(i + increment - 1));
698 DCHECK(code->kind() == Code::HANDLER);
699 return handle(code);
700 }
701 }
702 }
703 } else if (feedback->IsWeakCell()) {
704 WeakCell* cell = WeakCell::cast(feedback);
705 if (!cell->cleared()) {
706 Map* cell_map = Map::cast(cell->value());
707 if (cell_map == *map) {
708 Code* code = Code::cast(GetFeedbackExtra());
709 DCHECK(code->kind() == Code::HANDLER);
710 return handle(code);
711 }
712 }
713 }
714
715 return MaybeHandle<Code>();
716 }
717
718
FindHandlers(CodeHandleList * code_list,int length) const719 bool FeedbackNexus::FindHandlers(CodeHandleList* code_list, int length) const {
720 Object* feedback = GetFeedback();
721 int count = 0;
722 bool is_named_feedback = IsPropertyNameFeedback(feedback);
723 if (feedback->IsFixedArray() || is_named_feedback) {
724 if (is_named_feedback) {
725 feedback = GetFeedbackExtra();
726 }
727 FixedArray* array = FixedArray::cast(feedback);
728 // The array should be of the form
729 // [map, handler, map, handler, ...]
730 // or
731 // [map, map, handler, map, map, handler, ...]
732 // Be sure to skip handlers whose maps have been cleared.
733 DCHECK(array->length() >= 2);
734 int increment = array->get(1)->IsCode() ? 2 : 3;
735 for (int i = 0; i < array->length(); i += increment) {
736 DCHECK(array->get(i)->IsWeakCell());
737 WeakCell* cell = WeakCell::cast(array->get(i));
738 if (!cell->cleared()) {
739 Code* code = Code::cast(array->get(i + increment - 1));
740 DCHECK(code->kind() == Code::HANDLER);
741 code_list->Add(handle(code));
742 count++;
743 }
744 }
745 } else if (feedback->IsWeakCell()) {
746 WeakCell* cell = WeakCell::cast(feedback);
747 if (!cell->cleared()) {
748 Code* code = Code::cast(GetFeedbackExtra());
749 DCHECK(code->kind() == Code::HANDLER);
750 code_list->Add(handle(code));
751 count++;
752 }
753 }
754 return count == length;
755 }
756
757
Clear(Code * host)758 void LoadICNexus::Clear(Code* host) { LoadIC::Clear(GetIsolate(), host, this); }
759
760
Clear(Code * host)761 void KeyedLoadICNexus::Clear(Code* host) {
762 KeyedLoadIC::Clear(GetIsolate(), host, this);
763 }
764
765
FindFirstName() const766 Name* KeyedLoadICNexus::FindFirstName() const {
767 Object* feedback = GetFeedback();
768 if (IsPropertyNameFeedback(feedback)) {
769 return Name::cast(feedback);
770 }
771 return NULL;
772 }
773
774
FindFirstName() const775 Name* KeyedStoreICNexus::FindFirstName() const {
776 Object* feedback = GetFeedback();
777 if (IsPropertyNameFeedback(feedback)) {
778 return Name::cast(feedback);
779 }
780 return NULL;
781 }
782
783
Clear(Code * host)784 void StoreICNexus::Clear(Code* host) {
785 StoreIC::Clear(GetIsolate(), host, this);
786 }
787
788
Clear(Code * host)789 void KeyedStoreICNexus::Clear(Code* host) {
790 KeyedStoreIC::Clear(GetIsolate(), host, this);
791 }
792
793
GetKeyedAccessStoreMode() const794 KeyedAccessStoreMode KeyedStoreICNexus::GetKeyedAccessStoreMode() const {
795 KeyedAccessStoreMode mode = STANDARD_STORE;
796 MapHandleList maps;
797 CodeHandleList handlers;
798
799 if (GetKeyType() == PROPERTY) return mode;
800
801 ExtractMaps(&maps);
802 FindHandlers(&handlers, maps.length());
803 for (int i = 0; i < handlers.length(); i++) {
804 // The first handler that isn't the slow handler will have the bits we need.
805 Handle<Code> handler = handlers.at(i);
806 CodeStub::Major major_key = CodeStub::MajorKeyFromKey(handler->stub_key());
807 uint32_t minor_key = CodeStub::MinorKeyFromKey(handler->stub_key());
808 CHECK(major_key == CodeStub::KeyedStoreSloppyArguments ||
809 major_key == CodeStub::StoreFastElement ||
810 major_key == CodeStub::StoreElement ||
811 major_key == CodeStub::ElementsTransitionAndStore ||
812 major_key == CodeStub::NoCache);
813 if (major_key != CodeStub::NoCache) {
814 mode = CommonStoreModeBits::decode(minor_key);
815 break;
816 }
817 }
818
819 return mode;
820 }
821
822
GetKeyType() const823 IcCheckType KeyedStoreICNexus::GetKeyType() const {
824 // The structure of the vector slots tells us the type.
825 return GetFeedback()->IsName() ? PROPERTY : ELEMENT;
826 }
827 } // namespace internal
828 } // namespace v8
829