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