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/ic/ic-compiler.h"
6 
7 #include "src/ic/handler-compiler.h"
8 #include "src/ic/ic-inl.h"
9 #include "src/profiler/cpu-profiler.h"
10 
11 
12 namespace v8 {
13 namespace internal {
14 
15 
Find(Handle<Name> name,Handle<Map> stub_holder,Code::Kind kind,ExtraICState extra_state,CacheHolderFlag cache_holder)16 Handle<Code> PropertyICCompiler::Find(Handle<Name> name,
17                                       Handle<Map> stub_holder, Code::Kind kind,
18                                       ExtraICState extra_state,
19                                       CacheHolderFlag cache_holder) {
20   Code::Flags flags =
21       Code::ComputeMonomorphicFlags(kind, extra_state, cache_holder);
22   Object* probe = stub_holder->FindInCodeCache(*name, flags);
23   if (probe->IsCode()) return handle(Code::cast(probe));
24   return Handle<Code>::null();
25 }
26 
27 
IncludesNumberMap(MapHandleList * maps)28 bool PropertyICCompiler::IncludesNumberMap(MapHandleList* maps) {
29   for (int i = 0; i < maps->length(); ++i) {
30     if (maps->at(i)->instance_type() == HEAP_NUMBER_TYPE) return true;
31   }
32   return false;
33 }
34 
35 
ComputeKeyedLoadMonomorphicHandler(Handle<Map> receiver_map,ExtraICState extra_ic_state)36 Handle<Code> PropertyICCompiler::ComputeKeyedLoadMonomorphicHandler(
37     Handle<Map> receiver_map, ExtraICState extra_ic_state) {
38   Isolate* isolate = receiver_map->GetIsolate();
39   bool is_js_array = receiver_map->instance_type() == JS_ARRAY_TYPE;
40   ElementsKind elements_kind = receiver_map->elements_kind();
41 
42   // No need to check for an elements-free prototype chain here, the generated
43   // stub code needs to check that dynamically anyway.
44   bool convert_hole_to_undefined =
45       is_js_array && elements_kind == FAST_HOLEY_ELEMENTS &&
46       *receiver_map == isolate->get_initial_js_array_map(elements_kind) &&
47       !(is_strong(LoadICState::GetLanguageMode(extra_ic_state)));
48   Handle<Code> stub;
49   if (receiver_map->has_indexed_interceptor()) {
50     stub = LoadIndexedInterceptorStub(isolate).GetCode();
51   } else if (receiver_map->IsStringMap()) {
52     // We have a string.
53     stub = LoadIndexedStringStub(isolate).GetCode();
54   } else if (receiver_map->has_sloppy_arguments_elements()) {
55     stub = KeyedLoadSloppyArgumentsStub(isolate).GetCode();
56   } else if (receiver_map->has_fast_elements() ||
57              receiver_map->has_fixed_typed_array_elements()) {
58     stub = LoadFastElementStub(isolate, is_js_array, elements_kind,
59                                convert_hole_to_undefined).GetCode();
60   } else {
61     stub = LoadDictionaryElementStub(isolate, LoadICState(extra_ic_state))
62                .GetCode();
63   }
64   return stub;
65 }
66 
67 
ComputeKeyedStoreMonomorphicHandler(Handle<Map> receiver_map,LanguageMode language_mode,KeyedAccessStoreMode store_mode)68 Handle<Code> PropertyICCompiler::ComputeKeyedStoreMonomorphicHandler(
69     Handle<Map> receiver_map, LanguageMode language_mode,
70     KeyedAccessStoreMode store_mode) {
71   Isolate* isolate = receiver_map->GetIsolate();
72   ExtraICState extra_state =
73       KeyedStoreIC::ComputeExtraICState(language_mode, store_mode);
74 
75   DCHECK(store_mode == STANDARD_STORE ||
76          store_mode == STORE_AND_GROW_NO_TRANSITION ||
77          store_mode == STORE_NO_TRANSITION_IGNORE_OUT_OF_BOUNDS ||
78          store_mode == STORE_NO_TRANSITION_HANDLE_COW);
79 
80   PropertyICCompiler compiler(isolate, Code::KEYED_STORE_IC, extra_state);
81   Handle<Code> code =
82       compiler.CompileKeyedStoreMonomorphicHandler(receiver_map, store_mode);
83   return code;
84 }
85 
86 
FindPreMonomorphic(Isolate * isolate,Code::Kind kind,ExtraICState state)87 Code* PropertyICCompiler::FindPreMonomorphic(Isolate* isolate, Code::Kind kind,
88                                              ExtraICState state) {
89   Code::Flags flags = Code::ComputeFlags(kind, PREMONOMORPHIC, state);
90   UnseededNumberDictionary* dictionary =
91       isolate->heap()->non_monomorphic_cache();
92   int entry = dictionary->FindEntry(isolate, flags);
93   DCHECK(entry != -1);
94   Object* code = dictionary->ValueAt(entry);
95   // This might be called during the marking phase of the collector
96   // hence the unchecked cast.
97   return reinterpret_cast<Code*>(code);
98 }
99 
100 
FillCache(Isolate * isolate,Handle<Code> code)101 static void FillCache(Isolate* isolate, Handle<Code> code) {
102   Handle<UnseededNumberDictionary> dictionary = UnseededNumberDictionary::Set(
103       isolate->factory()->non_monomorphic_cache(), code->flags(), code);
104   isolate->heap()->SetRootNonMonomorphicCache(*dictionary);
105 }
106 
107 
ComputeStore(Isolate * isolate,InlineCacheState ic_state,ExtraICState extra_state)108 Handle<Code> PropertyICCompiler::ComputeStore(Isolate* isolate,
109                                               InlineCacheState ic_state,
110                                               ExtraICState extra_state) {
111   Code::Flags flags = Code::ComputeFlags(Code::STORE_IC, ic_state, extra_state);
112   Handle<UnseededNumberDictionary> cache =
113       isolate->factory()->non_monomorphic_cache();
114   int entry = cache->FindEntry(isolate, flags);
115   if (entry != -1) return Handle<Code>(Code::cast(cache->ValueAt(entry)));
116 
117   PropertyICCompiler compiler(isolate, Code::STORE_IC);
118   Handle<Code> code;
119   if (ic_state == UNINITIALIZED) {
120     code = compiler.CompileStoreInitialize(flags);
121   } else if (ic_state == PREMONOMORPHIC) {
122     code = compiler.CompileStorePreMonomorphic(flags);
123   } else if (ic_state == GENERIC) {
124     code = compiler.CompileStoreGeneric(flags);
125   } else if (ic_state == MEGAMORPHIC) {
126     code = compiler.CompileStoreMegamorphic(flags);
127   } else {
128     UNREACHABLE();
129   }
130 
131   FillCache(isolate, code);
132   return code;
133 }
134 
135 
ComputeCompareNil(Handle<Map> receiver_map,CompareNilICStub * stub)136 Handle<Code> PropertyICCompiler::ComputeCompareNil(Handle<Map> receiver_map,
137                                                    CompareNilICStub* stub) {
138   Isolate* isolate = receiver_map->GetIsolate();
139   Handle<String> name(isolate->heap()->empty_string());
140   if (!receiver_map->is_dictionary_map()) {
141     Handle<Code> cached_ic =
142         Find(name, receiver_map, Code::COMPARE_NIL_IC, stub->GetExtraICState());
143     if (!cached_ic.is_null()) return cached_ic;
144   }
145 
146   Code::FindAndReplacePattern pattern;
147   Handle<WeakCell> cell = Map::WeakCellForMap(receiver_map);
148   pattern.Add(isolate->factory()->meta_map(), cell);
149   Handle<Code> ic = stub->GetCodeCopy(pattern);
150 
151   if (!receiver_map->is_dictionary_map()) {
152     Map::UpdateCodeCache(receiver_map, name, ic);
153   }
154 
155   return ic;
156 }
157 
158 
ComputeKeyedStorePolymorphicHandlers(MapHandleList * receiver_maps,MapHandleList * transitioned_maps,CodeHandleList * handlers,KeyedAccessStoreMode store_mode,LanguageMode language_mode)159 void PropertyICCompiler::ComputeKeyedStorePolymorphicHandlers(
160     MapHandleList* receiver_maps, MapHandleList* transitioned_maps,
161     CodeHandleList* handlers, KeyedAccessStoreMode store_mode,
162     LanguageMode language_mode) {
163   Isolate* isolate = receiver_maps->at(0)->GetIsolate();
164   DCHECK(store_mode == STANDARD_STORE ||
165          store_mode == STORE_AND_GROW_NO_TRANSITION ||
166          store_mode == STORE_NO_TRANSITION_IGNORE_OUT_OF_BOUNDS ||
167          store_mode == STORE_NO_TRANSITION_HANDLE_COW);
168   ExtraICState extra_state =
169       KeyedStoreIC::ComputeExtraICState(language_mode, store_mode);
170   PropertyICCompiler compiler(isolate, Code::KEYED_STORE_IC, extra_state);
171   compiler.CompileKeyedStorePolymorphicHandlers(
172       receiver_maps, transitioned_maps, handlers, store_mode);
173 }
174 
175 
CompileLoadInitialize(Code::Flags flags)176 Handle<Code> PropertyICCompiler::CompileLoadInitialize(Code::Flags flags) {
177   LoadIC::GenerateInitialize(masm());
178   Handle<Code> code = GetCodeWithFlags(flags, "CompileLoadInitialize");
179   PROFILE(isolate(), CodeCreateEvent(Logger::LOAD_INITIALIZE_TAG, *code, 0));
180   return code;
181 }
182 
183 
CompileStoreInitialize(Code::Flags flags)184 Handle<Code> PropertyICCompiler::CompileStoreInitialize(Code::Flags flags) {
185   StoreIC::GenerateInitialize(masm());
186   Handle<Code> code = GetCodeWithFlags(flags, "CompileStoreInitialize");
187   PROFILE(isolate(), CodeCreateEvent(Logger::STORE_INITIALIZE_TAG, *code, 0));
188   return code;
189 }
190 
191 
CompileStorePreMonomorphic(Code::Flags flags)192 Handle<Code> PropertyICCompiler::CompileStorePreMonomorphic(Code::Flags flags) {
193   StoreIC::GeneratePreMonomorphic(masm());
194   Handle<Code> code = GetCodeWithFlags(flags, "CompileStorePreMonomorphic");
195   PROFILE(isolate(),
196           CodeCreateEvent(Logger::STORE_PREMONOMORPHIC_TAG, *code, 0));
197   return code;
198 }
199 
200 
CompileStoreGeneric(Code::Flags flags)201 Handle<Code> PropertyICCompiler::CompileStoreGeneric(Code::Flags flags) {
202   ExtraICState extra_state = Code::ExtractExtraICStateFromFlags(flags);
203   LanguageMode language_mode = StoreICState::GetLanguageMode(extra_state);
204   GenerateRuntimeSetProperty(masm(), language_mode);
205   Handle<Code> code = GetCodeWithFlags(flags, "CompileStoreGeneric");
206   PROFILE(isolate(), CodeCreateEvent(Logger::STORE_GENERIC_TAG, *code, 0));
207   return code;
208 }
209 
210 
CompileStoreMegamorphic(Code::Flags flags)211 Handle<Code> PropertyICCompiler::CompileStoreMegamorphic(Code::Flags flags) {
212   StoreIC::GenerateMegamorphic(masm());
213   Handle<Code> code = GetCodeWithFlags(flags, "CompileStoreMegamorphic");
214   PROFILE(isolate(), CodeCreateEvent(Logger::STORE_MEGAMORPHIC_TAG, *code, 0));
215   return code;
216 }
217 
218 
GetCode(Code::Kind kind,Code::StubType type,Handle<Name> name,InlineCacheState state)219 Handle<Code> PropertyICCompiler::GetCode(Code::Kind kind, Code::StubType type,
220                                          Handle<Name> name,
221                                          InlineCacheState state) {
222   Code::Flags flags =
223       Code::ComputeFlags(kind, state, extra_ic_state_, type, cache_holder());
224   Handle<Code> code = GetCodeWithFlags(flags, name);
225   PROFILE(isolate(), CodeCreateEvent(log_kind(code), *code, *name));
226 #ifdef DEBUG
227   code->VerifyEmbeddedObjects();
228 #endif
229   return code;
230 }
231 
232 
CompileKeyedStorePolymorphicHandlers(MapHandleList * receiver_maps,MapHandleList * transitioned_maps,CodeHandleList * handlers,KeyedAccessStoreMode store_mode)233 void PropertyICCompiler::CompileKeyedStorePolymorphicHandlers(
234     MapHandleList* receiver_maps, MapHandleList* transitioned_maps,
235     CodeHandleList* handlers, KeyedAccessStoreMode store_mode) {
236   for (int i = 0; i < receiver_maps->length(); ++i) {
237     Handle<Map> receiver_map(receiver_maps->at(i));
238     Handle<Code> cached_stub;
239     Handle<Map> transitioned_map =
240         Map::FindTransitionedMap(receiver_map, receiver_maps);
241 
242     // TODO(mvstanton): The code below is doing pessimistic elements
243     // transitions. I would like to stop doing that and rely on Allocation Site
244     // Tracking to do a better job of ensuring the data types are what they need
245     // to be. Not all the elements are in place yet, pessimistic elements
246     // transitions are still important for performance.
247     bool is_js_array = receiver_map->instance_type() == JS_ARRAY_TYPE;
248     ElementsKind elements_kind = receiver_map->elements_kind();
249     if (!transitioned_map.is_null()) {
250       cached_stub =
251           ElementsTransitionAndStoreStub(isolate(), elements_kind,
252                                          transitioned_map->elements_kind(),
253                                          is_js_array, store_mode).GetCode();
254     } else if (receiver_map->instance_type() < FIRST_JS_RECEIVER_TYPE) {
255       // TODO(mvstanton): Consider embedding store_mode in the state of the slow
256       // keyed store ic for uniformity.
257       cached_stub = isolate()->builtins()->KeyedStoreIC_Slow();
258     } else {
259       if (IsSloppyArgumentsElements(elements_kind)) {
260         cached_stub =
261             KeyedStoreSloppyArgumentsStub(isolate(), store_mode).GetCode();
262       } else if (receiver_map->has_fast_elements() ||
263                  receiver_map->has_fixed_typed_array_elements()) {
264         cached_stub = StoreFastElementStub(isolate(), is_js_array,
265                                            elements_kind, store_mode).GetCode();
266       } else {
267         cached_stub =
268             StoreElementStub(isolate(), elements_kind, store_mode).GetCode();
269       }
270     }
271     DCHECK(!cached_stub.is_null());
272     handlers->Add(cached_stub);
273     transitioned_maps->Add(transitioned_map);
274   }
275 }
276 
277 
278 #define __ ACCESS_MASM(masm())
279 
280 
CompileKeyedStoreMonomorphicHandler(Handle<Map> receiver_map,KeyedAccessStoreMode store_mode)281 Handle<Code> PropertyICCompiler::CompileKeyedStoreMonomorphicHandler(
282     Handle<Map> receiver_map, KeyedAccessStoreMode store_mode) {
283   ElementsKind elements_kind = receiver_map->elements_kind();
284   bool is_jsarray = receiver_map->instance_type() == JS_ARRAY_TYPE;
285   Handle<Code> stub;
286   if (receiver_map->has_sloppy_arguments_elements()) {
287     stub = KeyedStoreSloppyArgumentsStub(isolate(), store_mode).GetCode();
288   } else if (receiver_map->has_fast_elements() ||
289              receiver_map->has_fixed_typed_array_elements()) {
290     stub = StoreFastElementStub(isolate(), is_jsarray, elements_kind,
291                                 store_mode).GetCode();
292   } else {
293     stub = StoreElementStub(isolate(), elements_kind, store_mode).GetCode();
294   }
295   return stub;
296 }
297 
298 
CompileKeyedStoreMonomorphic(Handle<Map> receiver_map,KeyedAccessStoreMode store_mode)299 Handle<Code> PropertyICCompiler::CompileKeyedStoreMonomorphic(
300     Handle<Map> receiver_map, KeyedAccessStoreMode store_mode) {
301   Handle<Code> stub =
302       CompileKeyedStoreMonomorphicHandler(receiver_map, store_mode);
303 
304   Handle<WeakCell> cell = Map::WeakCellForMap(receiver_map);
305 
306   __ DispatchWeakMap(receiver(), scratch1(), scratch2(), cell, stub,
307                      DO_SMI_CHECK);
308 
309   TailCallBuiltin(masm(), Builtins::kKeyedStoreIC_Miss);
310 
311   return GetCode(kind(), Code::NORMAL, factory()->empty_string());
312 }
313 
314 
315 #undef __
316 }  // namespace internal
317 }  // namespace v8
318