b0be315b2b612bfd3733da6f6f0efbb236d68363
[platform/upstream/nodejs.git] / deps / v8 / src / type-feedback-vector.cc
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/v8.h"
6
7 #include "src/ic/ic.h"
8 #include "src/ic/ic-state.h"
9 #include "src/objects.h"
10 #include "src/type-feedback-vector-inl.h"
11
12 namespace v8 {
13 namespace internal {
14
15 // static
16 TypeFeedbackVector::VectorICKind TypeFeedbackVector::FromCodeKind(
17     Code::Kind kind) {
18   switch (kind) {
19     case Code::CALL_IC:
20       return KindCallIC;
21     case Code::LOAD_IC:
22       return KindLoadIC;
23     case Code::KEYED_LOAD_IC:
24       return KindKeyedLoadIC;
25     default:
26       // Shouldn't get here.
27       UNREACHABLE();
28   }
29
30   return KindUnused;
31 }
32
33
34 // static
35 Code::Kind TypeFeedbackVector::FromVectorICKind(VectorICKind kind) {
36   switch (kind) {
37     case KindCallIC:
38       return Code::CALL_IC;
39     case KindLoadIC:
40       return Code::LOAD_IC;
41     case KindKeyedLoadIC:
42       return Code::KEYED_LOAD_IC;
43     case KindUnused:
44       break;
45   }
46   // Sentinel for no information.
47   return Code::NUMBER_OF_KINDS;
48 }
49
50
51 Code::Kind TypeFeedbackVector::GetKind(FeedbackVectorICSlot slot) const {
52   if (!FLAG_vector_ics) {
53     // We only have CALL_ICs
54     return Code::CALL_IC;
55   }
56
57   int index = VectorICComputer::index(kReservedIndexCount, slot.ToInt());
58   int data = Smi::cast(get(index))->value();
59   VectorICKind b = VectorICComputer::decode(data, slot.ToInt());
60   return FromVectorICKind(b);
61 }
62
63
64 void TypeFeedbackVector::SetKind(FeedbackVectorICSlot slot, Code::Kind kind) {
65   if (!FLAG_vector_ics) {
66     // Nothing to do if we only have CALL_ICs
67     return;
68   }
69
70   VectorICKind b = FromCodeKind(kind);
71   int index = VectorICComputer::index(kReservedIndexCount, slot.ToInt());
72   int data = Smi::cast(get(index))->value();
73   int new_data = VectorICComputer::encode(data, slot.ToInt(), b);
74   set(index, Smi::FromInt(new_data));
75 }
76
77
78 // static
79 Handle<TypeFeedbackVector> TypeFeedbackVector::Allocate(
80     Isolate* isolate, const FeedbackVectorSpec& spec) {
81   const int slot_count = spec.slots();
82   const int ic_slot_count = spec.ic_slots();
83   const int index_count =
84       FLAG_vector_ics ? VectorICComputer::word_count(ic_slot_count) : 0;
85   const int length =
86       slot_count + ic_slot_count + index_count + kReservedIndexCount;
87   if (length == kReservedIndexCount) {
88     return Handle<TypeFeedbackVector>::cast(
89         isolate->factory()->empty_fixed_array());
90   }
91
92   Handle<FixedArray> array = isolate->factory()->NewFixedArray(length, TENURED);
93   if (ic_slot_count > 0) {
94     array->set(kFirstICSlotIndex,
95                Smi::FromInt(slot_count + index_count + kReservedIndexCount));
96   } else {
97     array->set(kFirstICSlotIndex, Smi::FromInt(length));
98   }
99   array->set(kWithTypesIndex, Smi::FromInt(0));
100   array->set(kGenericCountIndex, Smi::FromInt(0));
101   // Fill the indexes with zeros.
102   for (int i = 0; i < index_count; i++) {
103     array->set(kReservedIndexCount + i, Smi::FromInt(0));
104   }
105
106   // Ensure we can skip the write barrier
107   Handle<Object> uninitialized_sentinel = UninitializedSentinel(isolate);
108   DCHECK_EQ(isolate->heap()->uninitialized_symbol(), *uninitialized_sentinel);
109   for (int i = kReservedIndexCount + index_count; i < length; i++) {
110     array->set(i, *uninitialized_sentinel, SKIP_WRITE_BARRIER);
111   }
112
113   Handle<TypeFeedbackVector> vector = Handle<TypeFeedbackVector>::cast(array);
114   if (FLAG_vector_ics) {
115     for (int i = 0; i < ic_slot_count; i++) {
116       vector->SetKind(FeedbackVectorICSlot(i), spec.GetKind(i));
117     }
118   }
119   return vector;
120 }
121
122
123 // static
124 Handle<TypeFeedbackVector> TypeFeedbackVector::Copy(
125     Isolate* isolate, Handle<TypeFeedbackVector> vector) {
126   Handle<TypeFeedbackVector> result;
127   result = Handle<TypeFeedbackVector>::cast(
128       isolate->factory()->CopyFixedArray(Handle<FixedArray>::cast(vector)));
129   return result;
130 }
131
132
133 // This logic is copied from
134 // StaticMarkingVisitor<StaticVisitor>::VisitCodeTarget.
135 static bool ClearLogic(Heap* heap, int ic_age) {
136   return FLAG_cleanup_code_caches_at_gc &&
137          heap->isolate()->serializer_enabled();
138 }
139
140
141 void TypeFeedbackVector::ClearSlots(SharedFunctionInfo* shared) {
142   int slots = Slots();
143   Isolate* isolate = GetIsolate();
144   Object* uninitialized_sentinel =
145       TypeFeedbackVector::RawUninitializedSentinel(isolate->heap());
146
147   for (int i = 0; i < slots; i++) {
148     FeedbackVectorSlot slot(i);
149     Object* obj = Get(slot);
150     if (obj->IsHeapObject()) {
151       InstanceType instance_type =
152           HeapObject::cast(obj)->map()->instance_type();
153       // AllocationSites are exempt from clearing. They don't store Maps
154       // or Code pointers which can cause memory leaks if not cleared
155       // regularly.
156       if (instance_type != ALLOCATION_SITE_TYPE) {
157         Set(slot, uninitialized_sentinel, SKIP_WRITE_BARRIER);
158       }
159     }
160   }
161 }
162
163
164 void TypeFeedbackVector::ClearICSlotsImpl(SharedFunctionInfo* shared,
165                                           bool force_clear) {
166   Heap* heap = GetIsolate()->heap();
167
168   // I'm not sure yet if this ic age is the correct one.
169   int ic_age = shared->ic_age();
170
171   if (!force_clear && !ClearLogic(heap, ic_age)) return;
172
173   int slots = ICSlots();
174   Code* host = shared->code();
175   Object* uninitialized_sentinel =
176       TypeFeedbackVector::RawUninitializedSentinel(heap);
177   for (int i = 0; i < slots; i++) {
178     FeedbackVectorICSlot slot(i);
179     Object* obj = Get(slot);
180     if (obj != uninitialized_sentinel) {
181       Code::Kind kind = GetKind(slot);
182       if (kind == Code::CALL_IC) {
183         CallICNexus nexus(this, slot);
184         nexus.Clear(host);
185       } else if (kind == Code::LOAD_IC) {
186         LoadICNexus nexus(this, slot);
187         nexus.Clear(host);
188       } else if (kind == Code::KEYED_LOAD_IC) {
189         KeyedLoadICNexus nexus(this, slot);
190         nexus.Clear(host);
191       }
192     }
193   }
194 }
195
196
197 Handle<FixedArray> FeedbackNexus::EnsureArrayOfSize(int length) {
198   Isolate* isolate = GetIsolate();
199   Handle<Object> feedback = handle(GetFeedback(), isolate);
200   if (!feedback->IsFixedArray() ||
201       FixedArray::cast(*feedback)->length() != length) {
202     Handle<FixedArray> array = isolate->factory()->NewFixedArray(length);
203     SetFeedback(*array);
204     return array;
205   }
206   return Handle<FixedArray>::cast(feedback);
207 }
208
209
210 void FeedbackNexus::InstallHandlers(int start_index, MapHandleList* maps,
211                                     CodeHandleList* handlers) {
212   Isolate* isolate = GetIsolate();
213   Handle<FixedArray> array = handle(FixedArray::cast(GetFeedback()), isolate);
214   int receiver_count = maps->length();
215   for (int current = 0; current < receiver_count; ++current) {
216     Handle<Map> map = maps->at(current);
217     Handle<WeakCell> cell = Map::WeakCellForMap(map);
218     array->set(start_index + (current * 2), *cell);
219     array->set(start_index + (current * 2 + 1), *handlers->at(current));
220   }
221 }
222
223
224 InlineCacheState LoadICNexus::StateFromFeedback() const {
225   Isolate* isolate = GetIsolate();
226   Object* feedback = GetFeedback();
227   if (feedback == *vector()->UninitializedSentinel(isolate)) {
228     return UNINITIALIZED;
229   } else if (feedback == *vector()->MegamorphicSentinel(isolate)) {
230     return MEGAMORPHIC;
231   } else if (feedback == *vector()->PremonomorphicSentinel(isolate)) {
232     return PREMONOMORPHIC;
233   } else if (feedback->IsFixedArray()) {
234     // Determine state purely by our structure, don't check if the maps are
235     // cleared.
236     FixedArray* array = FixedArray::cast(feedback);
237     int length = array->length();
238     DCHECK(length >= 2);
239     return length == 2 ? MONOMORPHIC : POLYMORPHIC;
240   }
241
242   return UNINITIALIZED;
243 }
244
245
246 InlineCacheState KeyedLoadICNexus::StateFromFeedback() const {
247   Isolate* isolate = GetIsolate();
248   Object* feedback = GetFeedback();
249   if (feedback == *vector()->UninitializedSentinel(isolate)) {
250     return UNINITIALIZED;
251   } else if (feedback == *vector()->PremonomorphicSentinel(isolate)) {
252     return PREMONOMORPHIC;
253   } else if (feedback == *vector()->MegamorphicSentinel(isolate)) {
254     return MEGAMORPHIC;
255   } else if (feedback->IsFixedArray()) {
256     // Determine state purely by our structure, don't check if the maps are
257     // cleared.
258     FixedArray* array = FixedArray::cast(feedback);
259     int length = array->length();
260     DCHECK(length >= 3);
261     return length == 3 ? MONOMORPHIC : POLYMORPHIC;
262   }
263
264   return UNINITIALIZED;
265 }
266
267
268 InlineCacheState CallICNexus::StateFromFeedback() const {
269   Isolate* isolate = GetIsolate();
270   Object* feedback = GetFeedback();
271
272   if (feedback == *vector()->MegamorphicSentinel(isolate)) {
273     return GENERIC;
274   } else if (feedback->IsAllocationSite() || feedback->IsWeakCell()) {
275     return MONOMORPHIC;
276   }
277
278   CHECK(feedback == *vector()->UninitializedSentinel(isolate));
279   return UNINITIALIZED;
280 }
281
282
283 void CallICNexus::Clear(Code* host) { CallIC::Clear(GetIsolate(), host, this); }
284
285
286 void CallICNexus::ConfigureGeneric() {
287   SetFeedback(*vector()->MegamorphicSentinel(GetIsolate()), SKIP_WRITE_BARRIER);
288 }
289
290
291 void CallICNexus::ConfigureMonomorphicArray() {
292   Object* feedback = GetFeedback();
293   if (!feedback->IsAllocationSite()) {
294     Handle<AllocationSite> new_site =
295         GetIsolate()->factory()->NewAllocationSite();
296     SetFeedback(*new_site);
297   }
298 }
299
300
301 void CallICNexus::ConfigureUninitialized() {
302   SetFeedback(*vector()->UninitializedSentinel(GetIsolate()),
303               SKIP_WRITE_BARRIER);
304 }
305
306
307 void CallICNexus::ConfigureMonomorphic(Handle<JSFunction> function) {
308   Handle<WeakCell> new_cell = GetIsolate()->factory()->NewWeakCell(function);
309   SetFeedback(*new_cell);
310 }
311
312
313 void KeyedLoadICNexus::ConfigureMegamorphic() {
314   SetFeedback(*vector()->MegamorphicSentinel(GetIsolate()), SKIP_WRITE_BARRIER);
315 }
316
317
318 void LoadICNexus::ConfigureMegamorphic() {
319   SetFeedback(*vector()->MegamorphicSentinel(GetIsolate()), SKIP_WRITE_BARRIER);
320 }
321
322
323 void LoadICNexus::ConfigurePremonomorphic() {
324   SetFeedback(*vector()->PremonomorphicSentinel(GetIsolate()),
325               SKIP_WRITE_BARRIER);
326 }
327
328
329 void KeyedLoadICNexus::ConfigurePremonomorphic() {
330   SetFeedback(*vector()->PremonomorphicSentinel(GetIsolate()),
331               SKIP_WRITE_BARRIER);
332 }
333
334
335 void LoadICNexus::ConfigureMonomorphic(Handle<Map> receiver_map,
336                                        Handle<Code> handler) {
337   Handle<FixedArray> array = EnsureArrayOfSize(2);
338   Handle<WeakCell> cell = Map::WeakCellForMap(receiver_map);
339   array->set(0, *cell);
340   array->set(1, *handler);
341 }
342
343
344 void KeyedLoadICNexus::ConfigureMonomorphic(Handle<Name> name,
345                                             Handle<Map> receiver_map,
346                                             Handle<Code> handler) {
347   Handle<FixedArray> array = EnsureArrayOfSize(3);
348   if (name.is_null()) {
349     array->set(0, Smi::FromInt(0));
350   } else {
351     array->set(0, *name);
352   }
353   Handle<WeakCell> cell = Map::WeakCellForMap(receiver_map);
354   array->set(1, *cell);
355   array->set(2, *handler);
356 }
357
358
359 void LoadICNexus::ConfigurePolymorphic(MapHandleList* maps,
360                                        CodeHandleList* handlers) {
361   int receiver_count = maps->length();
362   EnsureArrayOfSize(receiver_count * 2);
363   InstallHandlers(0, maps, handlers);
364 }
365
366
367 void KeyedLoadICNexus::ConfigurePolymorphic(Handle<Name> name,
368                                             MapHandleList* maps,
369                                             CodeHandleList* handlers) {
370   int receiver_count = maps->length();
371   Handle<FixedArray> array = EnsureArrayOfSize(1 + receiver_count * 2);
372   if (name.is_null()) {
373     array->set(0, Smi::FromInt(0));
374   } else {
375     array->set(0, *name);
376   }
377   InstallHandlers(1, maps, handlers);
378 }
379
380
381 int FeedbackNexus::ExtractMaps(int start_index, MapHandleList* maps) const {
382   Isolate* isolate = GetIsolate();
383   Object* feedback = GetFeedback();
384   if (feedback->IsFixedArray()) {
385     int found = 0;
386     FixedArray* array = FixedArray::cast(feedback);
387     // The array should be of the form [<optional name>], then
388     // [map, handler, map, handler, ... ]
389     DCHECK(array->length() >= (2 + start_index));
390     for (int i = start_index; i < array->length(); i += 2) {
391       WeakCell* cell = WeakCell::cast(array->get(i));
392       if (!cell->cleared()) {
393         Map* map = Map::cast(cell->value());
394         maps->Add(handle(map, isolate));
395         found++;
396       }
397     }
398     return found;
399   }
400
401   return 0;
402 }
403
404
405 MaybeHandle<Code> FeedbackNexus::FindHandlerForMap(int start_index,
406                                                    Handle<Map> map) const {
407   Object* feedback = GetFeedback();
408   if (feedback->IsFixedArray()) {
409     FixedArray* array = FixedArray::cast(feedback);
410     for (int i = start_index; i < array->length(); i += 2) {
411       WeakCell* cell = WeakCell::cast(array->get(i));
412       if (!cell->cleared()) {
413         Map* array_map = Map::cast(cell->value());
414         if (array_map == *map) {
415           Code* code = Code::cast(array->get(i + 1));
416           DCHECK(code->kind() == Code::HANDLER);
417           return handle(code);
418         }
419       }
420     }
421   }
422
423   return MaybeHandle<Code>();
424 }
425
426
427 bool FeedbackNexus::FindHandlers(int start_index, CodeHandleList* code_list,
428                                  int length) const {
429   Object* feedback = GetFeedback();
430   int count = 0;
431   if (feedback->IsFixedArray()) {
432     FixedArray* array = FixedArray::cast(feedback);
433     // The array should be of the form [<optional name>], then
434     // [map, handler, map, handler, ... ]. Be sure to skip handlers whose maps
435     // have been cleared.
436     DCHECK(array->length() >= (2 + start_index));
437     for (int i = start_index; i < array->length(); i += 2) {
438       WeakCell* cell = WeakCell::cast(array->get(i));
439       if (!cell->cleared()) {
440         Code* code = Code::cast(array->get(i + 1));
441         DCHECK(code->kind() == Code::HANDLER);
442         code_list->Add(handle(code));
443         count++;
444       }
445     }
446   }
447   return count == length;
448 }
449
450
451 int LoadICNexus::ExtractMaps(MapHandleList* maps) const {
452   return FeedbackNexus::ExtractMaps(0, maps);
453 }
454
455
456 void LoadICNexus::Clear(Code* host) { LoadIC::Clear(GetIsolate(), host, this); }
457
458
459 void KeyedLoadICNexus::Clear(Code* host) {
460   KeyedLoadIC::Clear(GetIsolate(), host, this);
461 }
462
463
464 int KeyedLoadICNexus::ExtractMaps(MapHandleList* maps) const {
465   return FeedbackNexus::ExtractMaps(1, maps);
466 }
467
468
469 MaybeHandle<Code> LoadICNexus::FindHandlerForMap(Handle<Map> map) const {
470   return FeedbackNexus::FindHandlerForMap(0, map);
471 }
472
473
474 MaybeHandle<Code> KeyedLoadICNexus::FindHandlerForMap(Handle<Map> map) const {
475   return FeedbackNexus::FindHandlerForMap(1, map);
476 }
477
478
479 bool LoadICNexus::FindHandlers(CodeHandleList* code_list, int length) const {
480   return FeedbackNexus::FindHandlers(0, code_list, length);
481 }
482
483
484 bool KeyedLoadICNexus::FindHandlers(CodeHandleList* code_list,
485                                     int length) const {
486   return FeedbackNexus::FindHandlers(1, code_list, length);
487 }
488
489
490 Name* KeyedLoadICNexus::FindFirstName() const {
491   Object* feedback = GetFeedback();
492   if (feedback->IsFixedArray()) {
493     FixedArray* array = FixedArray::cast(feedback);
494     DCHECK(array->length() >= 3);
495     Object* name = array->get(0);
496     if (name->IsName()) return Name::cast(name);
497   }
498   return NULL;
499 }
500 }
501 }  // namespace v8::internal