blob: c51d9877f1c27c4e31fcdb02316a36c1883e2c92 [file] [log] [blame]
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001// 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
Emily Bernierd0a1eb72015-03-24 16:35:39 -04007#include "src/ic/ic.h"
8#include "src/ic/ic-state.h"
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009#include "src/objects.h"
10#include "src/type-feedback-vector-inl.h"
11
12namespace v8 {
13namespace internal {
14
15// static
Emily Bernierd0a1eb72015-03-24 16:35:39 -040016TypeFeedbackVector::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
35Code::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
51Code::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
64void 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
79Handle<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
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000124Handle<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}
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400131
132
133// This logic is copied from
134// StaticMarkingVisitor<StaticVisitor>::VisitCodeTarget.
135// TODO(mvstanton): with weak handling of all vector ics, this logic should
136// actually be completely eliminated and we no longer need to clear the
137// vector ICs.
138static bool ClearLogic(Heap* heap, int ic_age, Code::Kind kind,
139 InlineCacheState state) {
140 if (FLAG_cleanup_code_caches_at_gc &&
141 (kind == Code::CALL_IC || heap->flush_monomorphic_ics() ||
142 // TODO(mvstanton): is this ic_age granular enough? it comes from
143 // the SharedFunctionInfo which may change on a different schedule
144 // than ic targets.
145 // ic_age != heap->global_ic_age() ||
146 // is_invalidated_weak_stub ||
147 heap->isolate()->serializer_enabled())) {
148 return true;
149 }
150 return false;
151}
152
153
154void TypeFeedbackVector::ClearSlots(SharedFunctionInfo* shared) {
155 int slots = Slots();
156 Isolate* isolate = GetIsolate();
157 Object* uninitialized_sentinel =
158 TypeFeedbackVector::RawUninitializedSentinel(isolate->heap());
159
160 for (int i = 0; i < slots; i++) {
161 FeedbackVectorSlot slot(i);
162 Object* obj = Get(slot);
163 if (obj->IsHeapObject()) {
164 InstanceType instance_type =
165 HeapObject::cast(obj)->map()->instance_type();
166 // AllocationSites are exempt from clearing. They don't store Maps
167 // or Code pointers which can cause memory leaks if not cleared
168 // regularly.
169 if (instance_type != ALLOCATION_SITE_TYPE) {
170 Set(slot, uninitialized_sentinel, SKIP_WRITE_BARRIER);
171 }
172 }
173 }
174
175 slots = ICSlots();
176 if (slots == 0) return;
177
178 // Now clear vector-based ICs.
179 // Try and pass the containing code (the "host").
180 Heap* heap = isolate->heap();
181 Code* host = shared->code();
182 // I'm not sure yet if this ic age is the correct one.
183 int ic_age = shared->ic_age();
184 for (int i = 0; i < slots; i++) {
185 FeedbackVectorICSlot slot(i);
186 Object* obj = Get(slot);
187 if (obj != uninitialized_sentinel) {
188 Code::Kind kind = GetKind(slot);
189 if (kind == Code::CALL_IC) {
190 CallICNexus nexus(this, slot);
191 if (ClearLogic(heap, ic_age, kind, nexus.StateFromFeedback())) {
192 nexus.Clear(host);
193 }
194 } else if (kind == Code::LOAD_IC) {
195 LoadICNexus nexus(this, slot);
196 if (ClearLogic(heap, ic_age, kind, nexus.StateFromFeedback())) {
197 nexus.Clear(host);
198 }
199 } else if (kind == Code::KEYED_LOAD_IC) {
200 KeyedLoadICNexus nexus(this, slot);
201 if (ClearLogic(heap, ic_age, kind, nexus.StateFromFeedback())) {
202 nexus.Clear(host);
203 }
204 }
205 }
206 }
207}
208
209
210Handle<FixedArray> FeedbackNexus::EnsureArrayOfSize(int length) {
211 Isolate* isolate = GetIsolate();
212 Handle<Object> feedback = handle(GetFeedback(), isolate);
213 if (!feedback->IsFixedArray() ||
214 FixedArray::cast(*feedback)->length() != length) {
215 Handle<FixedArray> array = isolate->factory()->NewFixedArray(length);
216 SetFeedback(*array);
217 return array;
218 }
219 return Handle<FixedArray>::cast(feedback);
220}
221
222
223void FeedbackNexus::InstallHandlers(int start_index, TypeHandleList* types,
224 CodeHandleList* handlers) {
225 Isolate* isolate = GetIsolate();
226 Handle<FixedArray> array = handle(FixedArray::cast(GetFeedback()), isolate);
227 int receiver_count = types->length();
228 for (int current = 0; current < receiver_count; ++current) {
229 Handle<HeapType> type = types->at(current);
230 Handle<Map> map = IC::TypeToMap(*type, isolate);
231 Handle<WeakCell> cell = Map::WeakCellForMap(map);
232 array->set(start_index + (current * 2), *cell);
233 array->set(start_index + (current * 2 + 1), *handlers->at(current));
234 }
235}
236
237
238InlineCacheState LoadICNexus::StateFromFeedback() const {
239 Isolate* isolate = GetIsolate();
240 Object* feedback = GetFeedback();
241 if (feedback == *vector()->UninitializedSentinel(isolate)) {
242 return UNINITIALIZED;
243 } else if (feedback == *vector()->MegamorphicSentinel(isolate)) {
244 return MEGAMORPHIC;
245 } else if (feedback == *vector()->PremonomorphicSentinel(isolate)) {
246 return PREMONOMORPHIC;
247 } else if (feedback->IsFixedArray()) {
248 // Determine state purely by our structure, don't check if the maps are
249 // cleared.
250 FixedArray* array = FixedArray::cast(feedback);
251 int length = array->length();
252 DCHECK(length >= 2);
253 return length == 2 ? MONOMORPHIC : POLYMORPHIC;
254 }
255
256 return UNINITIALIZED;
257}
258
259
260InlineCacheState KeyedLoadICNexus::StateFromFeedback() const {
261 Isolate* isolate = GetIsolate();
262 Object* feedback = GetFeedback();
263 if (feedback == *vector()->UninitializedSentinel(isolate)) {
264 return UNINITIALIZED;
265 } else if (feedback == *vector()->PremonomorphicSentinel(isolate)) {
266 return PREMONOMORPHIC;
267 } else if (feedback == *vector()->GenericSentinel(isolate)) {
268 return GENERIC;
269 } else if (feedback->IsFixedArray()) {
270 // Determine state purely by our structure, don't check if the maps are
271 // cleared.
272 FixedArray* array = FixedArray::cast(feedback);
273 int length = array->length();
274 DCHECK(length >= 3);
275 return length == 3 ? MONOMORPHIC : POLYMORPHIC;
276 }
277
278 return UNINITIALIZED;
279}
280
281
282InlineCacheState CallICNexus::StateFromFeedback() const {
283 Isolate* isolate = GetIsolate();
284 Object* feedback = GetFeedback();
285
286 if (feedback == *vector()->MegamorphicSentinel(isolate)) {
287 return GENERIC;
288 } else if (feedback->IsAllocationSite() || feedback->IsJSFunction()) {
289 return MONOMORPHIC;
290 }
291
292 CHECK(feedback == *vector()->UninitializedSentinel(isolate));
293 return UNINITIALIZED;
294}
295
296
297void CallICNexus::Clear(Code* host) { CallIC::Clear(GetIsolate(), host, this); }
298
299
300void CallICNexus::ConfigureGeneric() {
301 SetFeedback(*vector()->MegamorphicSentinel(GetIsolate()), SKIP_WRITE_BARRIER);
302}
303
304
305void CallICNexus::ConfigureMonomorphicArray() {
306 Object* feedback = GetFeedback();
307 if (!feedback->IsAllocationSite()) {
308 Handle<AllocationSite> new_site =
309 GetIsolate()->factory()->NewAllocationSite();
310 SetFeedback(*new_site);
311 }
312}
313
314
315void CallICNexus::ConfigureUninitialized() {
316 SetFeedback(*vector()->UninitializedSentinel(GetIsolate()),
317 SKIP_WRITE_BARRIER);
318}
319
320
321void CallICNexus::ConfigureMonomorphic(Handle<JSFunction> function) {
322 SetFeedback(*function);
323}
324
325
326void KeyedLoadICNexus::ConfigureGeneric() {
327 SetFeedback(*vector()->GenericSentinel(GetIsolate()), SKIP_WRITE_BARRIER);
328}
329
330
331void LoadICNexus::ConfigureMegamorphic() {
332 SetFeedback(*vector()->MegamorphicSentinel(GetIsolate()), SKIP_WRITE_BARRIER);
333}
334
335
336void LoadICNexus::ConfigurePremonomorphic() {
337 SetFeedback(*vector()->PremonomorphicSentinel(GetIsolate()),
338 SKIP_WRITE_BARRIER);
339}
340
341
342void KeyedLoadICNexus::ConfigurePremonomorphic() {
343 SetFeedback(*vector()->PremonomorphicSentinel(GetIsolate()),
344 SKIP_WRITE_BARRIER);
345}
346
347
348void LoadICNexus::ConfigureMonomorphic(Handle<HeapType> type,
349 Handle<Code> handler) {
350 Handle<FixedArray> array = EnsureArrayOfSize(2);
351 Handle<Map> receiver_map = IC::TypeToMap(*type, GetIsolate());
352 Handle<WeakCell> cell = Map::WeakCellForMap(receiver_map);
353 array->set(0, *cell);
354 array->set(1, *handler);
355}
356
357
358void KeyedLoadICNexus::ConfigureMonomorphic(Handle<Name> name,
359 Handle<HeapType> type,
360 Handle<Code> handler) {
361 Handle<FixedArray> array = EnsureArrayOfSize(3);
362 Handle<Map> receiver_map = IC::TypeToMap(*type, GetIsolate());
363 if (name.is_null()) {
364 array->set(0, Smi::FromInt(0));
365 } else {
366 array->set(0, *name);
367 }
368 Handle<WeakCell> cell = Map::WeakCellForMap(receiver_map);
369 array->set(1, *cell);
370 array->set(2, *handler);
371}
372
373
374void LoadICNexus::ConfigurePolymorphic(TypeHandleList* types,
375 CodeHandleList* handlers) {
376 int receiver_count = types->length();
377 EnsureArrayOfSize(receiver_count * 2);
378 InstallHandlers(0, types, handlers);
379}
380
381
382void KeyedLoadICNexus::ConfigurePolymorphic(Handle<Name> name,
383 TypeHandleList* types,
384 CodeHandleList* handlers) {
385 int receiver_count = types->length();
386 Handle<FixedArray> array = EnsureArrayOfSize(1 + receiver_count * 2);
387 if (name.is_null()) {
388 array->set(0, Smi::FromInt(0));
389 } else {
390 array->set(0, *name);
391 }
392 InstallHandlers(1, types, handlers);
393}
394
395
396int FeedbackNexus::ExtractMaps(int start_index, MapHandleList* maps) const {
397 Isolate* isolate = GetIsolate();
398 Object* feedback = GetFeedback();
399 if (feedback->IsFixedArray()) {
400 int found = 0;
401 FixedArray* array = FixedArray::cast(feedback);
402 // The array should be of the form [<optional name>], then
403 // [map, handler, map, handler, ... ]
404 DCHECK(array->length() >= (2 + start_index));
405 for (int i = start_index; i < array->length(); i += 2) {
406 WeakCell* cell = WeakCell::cast(array->get(i));
407 if (!cell->cleared()) {
408 Map* map = Map::cast(cell->value());
409 maps->Add(handle(map, isolate));
410 found++;
411 }
412 }
413 return found;
414 }
415
416 return 0;
417}
418
419
420MaybeHandle<Code> FeedbackNexus::FindHandlerForMap(int start_index,
421 Handle<Map> map) const {
422 Object* feedback = GetFeedback();
423 if (feedback->IsFixedArray()) {
424 FixedArray* array = FixedArray::cast(feedback);
425 for (int i = start_index; i < array->length(); i += 2) {
426 WeakCell* cell = WeakCell::cast(array->get(i));
427 if (!cell->cleared()) {
428 Map* array_map = Map::cast(cell->value());
429 if (array_map == *map) {
430 Code* code = Code::cast(array->get(i + 1));
431 DCHECK(code->kind() == Code::HANDLER);
432 return handle(code);
433 }
434 }
435 }
436 }
437
438 return MaybeHandle<Code>();
439}
440
441
442bool FeedbackNexus::FindHandlers(int start_index, CodeHandleList* code_list,
443 int length) const {
444 Object* feedback = GetFeedback();
445 int count = 0;
446 if (feedback->IsFixedArray()) {
447 FixedArray* array = FixedArray::cast(feedback);
448 // The array should be of the form [<optional name>], then
449 // [map, handler, map, handler, ... ]. Be sure to skip handlers whose maps
450 // have been cleared.
451 DCHECK(array->length() >= (2 + start_index));
452 for (int i = start_index; i < array->length(); i += 2) {
453 WeakCell* cell = WeakCell::cast(array->get(i));
454 if (!cell->cleared()) {
455 Code* code = Code::cast(array->get(i + 1));
456 DCHECK(code->kind() == Code::HANDLER);
457 code_list->Add(handle(code));
458 count++;
459 }
460 }
461 }
462 return count == length;
463}
464
465
466int LoadICNexus::ExtractMaps(MapHandleList* maps) const {
467 return FeedbackNexus::ExtractMaps(0, maps);
468}
469
470
471void LoadICNexus::Clear(Code* host) { LoadIC::Clear(GetIsolate(), host, this); }
472
473
474void KeyedLoadICNexus::Clear(Code* host) {
475 KeyedLoadIC::Clear(GetIsolate(), host, this);
476}
477
478
479int KeyedLoadICNexus::ExtractMaps(MapHandleList* maps) const {
480 return FeedbackNexus::ExtractMaps(1, maps);
481}
482
483
484MaybeHandle<Code> LoadICNexus::FindHandlerForMap(Handle<Map> map) const {
485 return FeedbackNexus::FindHandlerForMap(0, map);
486}
487
488
489MaybeHandle<Code> KeyedLoadICNexus::FindHandlerForMap(Handle<Map> map) const {
490 return FeedbackNexus::FindHandlerForMap(1, map);
491}
492
493
494bool LoadICNexus::FindHandlers(CodeHandleList* code_list, int length) const {
495 return FeedbackNexus::FindHandlers(0, code_list, length);
496}
497
498
499bool KeyedLoadICNexus::FindHandlers(CodeHandleList* code_list,
500 int length) const {
501 return FeedbackNexus::FindHandlers(1, code_list, length);
502}
503
504
505Name* KeyedLoadICNexus::FindFirstName() const {
506 Object* feedback = GetFeedback();
507 if (feedback->IsFixedArray()) {
508 FixedArray* array = FixedArray::cast(feedback);
509 DCHECK(array->length() >= 3);
510 Object* name = array->get(0);
511 if (name->IsName()) return Name::cast(name);
512 }
513 return NULL;
514}
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000515}
516} // namespace v8::internal