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.
8 #include "src/ic/ic-state.h"
9 #include "src/objects.h"
10 #include "src/type-feedback-vector-inl.h"
16 TypeFeedbackVector::VectorICKind TypeFeedbackVector::FromCodeKind(
23 case Code::KEYED_LOAD_IC:
24 return KindKeyedLoadIC;
26 // Shouldn't get here.
35 Code::Kind TypeFeedbackVector::FromVectorICKind(VectorICKind kind) {
42 return Code::KEYED_LOAD_IC;
46 // Sentinel for no information.
47 return Code::NUMBER_OF_KINDS;
51 Code::Kind TypeFeedbackVector::GetKind(FeedbackVectorICSlot slot) const {
52 if (!FLAG_vector_ics) {
53 // We only have CALL_ICs
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);
64 void TypeFeedbackVector::SetKind(FeedbackVectorICSlot slot, Code::Kind kind) {
65 if (!FLAG_vector_ics) {
66 // Nothing to do if we only have CALL_ICs
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));
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;
86 slot_count + ic_slot_count + index_count + kReservedIndexCount;
87 if (length == kReservedIndexCount) {
88 return Handle<TypeFeedbackVector>::cast(
89 isolate->factory()->empty_fixed_array());
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));
97 array->set(kFirstICSlotIndex, Smi::FromInt(length));
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));
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);
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));
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)));
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();
141 void TypeFeedbackVector::ClearSlots(SharedFunctionInfo* shared) {
143 Isolate* isolate = GetIsolate();
144 Object* uninitialized_sentinel =
145 TypeFeedbackVector::RawUninitializedSentinel(isolate->heap());
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
156 if (instance_type != ALLOCATION_SITE_TYPE) {
157 Set(slot, uninitialized_sentinel, SKIP_WRITE_BARRIER);
164 void TypeFeedbackVector::ClearICSlotsImpl(SharedFunctionInfo* shared,
166 Heap* heap = GetIsolate()->heap();
168 // I'm not sure yet if this ic age is the correct one.
169 int ic_age = shared->ic_age();
171 if (!force_clear && !ClearLogic(heap, ic_age)) return;
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);
185 } else if (kind == Code::LOAD_IC) {
186 LoadICNexus nexus(this, slot);
188 } else if (kind == Code::KEYED_LOAD_IC) {
189 KeyedLoadICNexus nexus(this, slot);
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);
206 return Handle<FixedArray>::cast(feedback);
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));
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)) {
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
236 FixedArray* array = FixedArray::cast(feedback);
237 int length = array->length();
239 return length == 2 ? MONOMORPHIC : POLYMORPHIC;
242 return UNINITIALIZED;
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)) {
255 } else if (feedback->IsFixedArray()) {
256 // Determine state purely by our structure, don't check if the maps are
258 FixedArray* array = FixedArray::cast(feedback);
259 int length = array->length();
261 return length == 3 ? MONOMORPHIC : POLYMORPHIC;
264 return UNINITIALIZED;
268 InlineCacheState CallICNexus::StateFromFeedback() const {
269 Isolate* isolate = GetIsolate();
270 Object* feedback = GetFeedback();
272 if (feedback == *vector()->MegamorphicSentinel(isolate)) {
274 } else if (feedback->IsAllocationSite() || feedback->IsWeakCell()) {
278 CHECK(feedback == *vector()->UninitializedSentinel(isolate));
279 return UNINITIALIZED;
283 void CallICNexus::Clear(Code* host) { CallIC::Clear(GetIsolate(), host, this); }
286 void CallICNexus::ConfigureGeneric() {
287 SetFeedback(*vector()->MegamorphicSentinel(GetIsolate()), SKIP_WRITE_BARRIER);
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);
301 void CallICNexus::ConfigureUninitialized() {
302 SetFeedback(*vector()->UninitializedSentinel(GetIsolate()),
307 void CallICNexus::ConfigureMonomorphic(Handle<JSFunction> function) {
308 Handle<WeakCell> new_cell = GetIsolate()->factory()->NewWeakCell(function);
309 SetFeedback(*new_cell);
313 void KeyedLoadICNexus::ConfigureMegamorphic() {
314 SetFeedback(*vector()->MegamorphicSentinel(GetIsolate()), SKIP_WRITE_BARRIER);
318 void LoadICNexus::ConfigureMegamorphic() {
319 SetFeedback(*vector()->MegamorphicSentinel(GetIsolate()), SKIP_WRITE_BARRIER);
323 void LoadICNexus::ConfigurePremonomorphic() {
324 SetFeedback(*vector()->PremonomorphicSentinel(GetIsolate()),
329 void KeyedLoadICNexus::ConfigurePremonomorphic() {
330 SetFeedback(*vector()->PremonomorphicSentinel(GetIsolate()),
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);
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));
351 array->set(0, *name);
353 Handle<WeakCell> cell = Map::WeakCellForMap(receiver_map);
354 array->set(1, *cell);
355 array->set(2, *handler);
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);
367 void KeyedLoadICNexus::ConfigurePolymorphic(Handle<Name> name,
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));
375 array->set(0, *name);
377 InstallHandlers(1, maps, handlers);
381 int FeedbackNexus::ExtractMaps(int start_index, MapHandleList* maps) const {
382 Isolate* isolate = GetIsolate();
383 Object* feedback = GetFeedback();
384 if (feedback->IsFixedArray()) {
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));
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);
423 return MaybeHandle<Code>();
427 bool FeedbackNexus::FindHandlers(int start_index, CodeHandleList* code_list,
429 Object* feedback = GetFeedback();
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));
447 return count == length;
451 int LoadICNexus::ExtractMaps(MapHandleList* maps) const {
452 return FeedbackNexus::ExtractMaps(0, maps);
456 void LoadICNexus::Clear(Code* host) { LoadIC::Clear(GetIsolate(), host, this); }
459 void KeyedLoadICNexus::Clear(Code* host) {
460 KeyedLoadIC::Clear(GetIsolate(), host, this);
464 int KeyedLoadICNexus::ExtractMaps(MapHandleList* maps) const {
465 return FeedbackNexus::ExtractMaps(1, maps);
469 MaybeHandle<Code> LoadICNexus::FindHandlerForMap(Handle<Map> map) const {
470 return FeedbackNexus::FindHandlerForMap(0, map);
474 MaybeHandle<Code> KeyedLoadICNexus::FindHandlerForMap(Handle<Map> map) const {
475 return FeedbackNexus::FindHandlerForMap(1, map);
479 bool LoadICNexus::FindHandlers(CodeHandleList* code_list, int length) const {
480 return FeedbackNexus::FindHandlers(0, code_list, length);
484 bool KeyedLoadICNexus::FindHandlers(CodeHandleList* code_list,
486 return FeedbackNexus::FindHandlers(1, code_list, length);
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);
501 } // namespace v8::internal