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/handler-compiler.h"
8 #include "src/ic/ic-inl.h"
9 #include "src/ic/ic-compiler.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 
IncludesNumberType(TypeHandleList * types)28 bool PropertyICCompiler::IncludesNumberType(TypeHandleList* types) {
29   for (int i = 0; i < types->length(); ++i) {
30     if (types->at(i)->Is(HeapType::Number())) return true;
31   }
32   return false;
33 }
34 
35 
CompileMonomorphic(Handle<HeapType> type,Handle<Code> handler,Handle<Name> name,IcCheckType check)36 Handle<Code> PropertyICCompiler::CompileMonomorphic(Handle<HeapType> type,
37                                                     Handle<Code> handler,
38                                                     Handle<Name> name,
39                                                     IcCheckType check) {
40   TypeHandleList types(1);
41   CodeHandleList handlers(1);
42   types.Add(type);
43   handlers.Add(handler);
44   Code::StubType stub_type = handler->type();
45   return CompilePolymorphic(&types, &handlers, name, stub_type, check);
46 }
47 
48 
ComputeMonomorphic(Code::Kind kind,Handle<Name> name,Handle<HeapType> type,Handle<Code> handler,ExtraICState extra_ic_state)49 Handle<Code> PropertyICCompiler::ComputeMonomorphic(
50     Code::Kind kind, Handle<Name> name, Handle<HeapType> type,
51     Handle<Code> handler, ExtraICState extra_ic_state) {
52   Isolate* isolate = name->GetIsolate();
53   if (handler.is_identical_to(isolate->builtins()->LoadIC_Normal()) ||
54       handler.is_identical_to(isolate->builtins()->StoreIC_Normal())) {
55     name = isolate->factory()->normal_ic_symbol();
56   }
57 
58   CacheHolderFlag flag;
59   Handle<Map> stub_holder = IC::GetICCacheHolder(*type, isolate, &flag);
60 
61   Handle<Code> ic;
62   // There are multiple string maps that all use the same prototype. That
63   // prototype cannot hold multiple handlers, one for each of the string maps,
64   // for a single name. Hence, turn off caching of the IC.
65   bool can_be_cached = !type->Is(HeapType::String());
66   if (can_be_cached) {
67     ic = Find(name, stub_holder, kind, extra_ic_state, flag);
68     if (!ic.is_null()) return ic;
69   }
70 
71 #ifdef DEBUG
72   if (kind == Code::KEYED_STORE_IC) {
73     DCHECK(STANDARD_STORE ==
74            KeyedStoreIC::GetKeyedAccessStoreMode(extra_ic_state));
75   }
76 #endif
77 
78   PropertyICCompiler ic_compiler(isolate, kind, extra_ic_state, flag);
79   ic = ic_compiler.CompileMonomorphic(type, handler, name, PROPERTY);
80 
81   if (can_be_cached) Map::UpdateCodeCache(stub_holder, name, ic);
82   return ic;
83 }
84 
85 
ComputeKeyedLoadMonomorphic(Handle<Map> receiver_map)86 Handle<Code> PropertyICCompiler::ComputeKeyedLoadMonomorphic(
87     Handle<Map> receiver_map) {
88   Isolate* isolate = receiver_map->GetIsolate();
89   Code::Flags flags = Code::ComputeMonomorphicFlags(Code::KEYED_LOAD_IC);
90   Handle<Name> name = isolate->factory()->KeyedLoadMonomorphic_string();
91 
92   Handle<Object> probe(receiver_map->FindInCodeCache(*name, flags), isolate);
93   if (probe->IsCode()) return Handle<Code>::cast(probe);
94 
95   ElementsKind elements_kind = receiver_map->elements_kind();
96   Handle<Code> stub;
97   if (receiver_map->has_indexed_interceptor()) {
98     stub = LoadIndexedInterceptorStub(isolate).GetCode();
99   } else if (receiver_map->has_sloppy_arguments_elements()) {
100     stub = KeyedLoadSloppyArgumentsStub(isolate).GetCode();
101   } else if (receiver_map->has_fast_elements() ||
102              receiver_map->has_external_array_elements() ||
103              receiver_map->has_fixed_typed_array_elements()) {
104     stub = LoadFastElementStub(isolate,
105                                receiver_map->instance_type() == JS_ARRAY_TYPE,
106                                elements_kind).GetCode();
107   } else {
108     stub = LoadDictionaryElementStub(isolate).GetCode();
109   }
110   PropertyICCompiler compiler(isolate, Code::KEYED_LOAD_IC);
111   Handle<Code> code =
112       compiler.CompileMonomorphic(HeapType::Class(receiver_map, isolate), stub,
113                                   isolate->factory()->empty_string(), ELEMENT);
114 
115   Map::UpdateCodeCache(receiver_map, name, code);
116   return code;
117 }
118 
119 
ComputeKeyedStoreMonomorphic(Handle<Map> receiver_map,StrictMode strict_mode,KeyedAccessStoreMode store_mode)120 Handle<Code> PropertyICCompiler::ComputeKeyedStoreMonomorphic(
121     Handle<Map> receiver_map, StrictMode strict_mode,
122     KeyedAccessStoreMode store_mode) {
123   Isolate* isolate = receiver_map->GetIsolate();
124   ExtraICState extra_state =
125       KeyedStoreIC::ComputeExtraICState(strict_mode, store_mode);
126   Code::Flags flags =
127       Code::ComputeMonomorphicFlags(Code::KEYED_STORE_IC, extra_state);
128 
129   DCHECK(store_mode == STANDARD_STORE ||
130          store_mode == STORE_AND_GROW_NO_TRANSITION ||
131          store_mode == STORE_NO_TRANSITION_IGNORE_OUT_OF_BOUNDS ||
132          store_mode == STORE_NO_TRANSITION_HANDLE_COW);
133 
134   Handle<String> name = isolate->factory()->KeyedStoreMonomorphic_string();
135   Handle<Object> probe(receiver_map->FindInCodeCache(*name, flags), isolate);
136   if (probe->IsCode()) return Handle<Code>::cast(probe);
137 
138   PropertyICCompiler compiler(isolate, Code::KEYED_STORE_IC, extra_state);
139   Handle<Code> code =
140       compiler.CompileKeyedStoreMonomorphic(receiver_map, store_mode);
141 
142   Map::UpdateCodeCache(receiver_map, name, code);
143   DCHECK(KeyedStoreIC::GetKeyedAccessStoreMode(code->extra_ic_state()) ==
144          store_mode);
145   return code;
146 }
147 
148 
FindPreMonomorphic(Isolate * isolate,Code::Kind kind,ExtraICState state)149 Code* PropertyICCompiler::FindPreMonomorphic(Isolate* isolate, Code::Kind kind,
150                                              ExtraICState state) {
151   Code::Flags flags = Code::ComputeFlags(kind, PREMONOMORPHIC, state);
152   UnseededNumberDictionary* dictionary =
153       isolate->heap()->non_monomorphic_cache();
154   int entry = dictionary->FindEntry(isolate, flags);
155   DCHECK(entry != -1);
156   Object* code = dictionary->ValueAt(entry);
157   // This might be called during the marking phase of the collector
158   // hence the unchecked cast.
159   return reinterpret_cast<Code*>(code);
160 }
161 
162 
FillCache(Isolate * isolate,Handle<Code> code)163 static void FillCache(Isolate* isolate, Handle<Code> code) {
164   Handle<UnseededNumberDictionary> dictionary = UnseededNumberDictionary::Set(
165       isolate->factory()->non_monomorphic_cache(), code->flags(), code);
166   isolate->heap()->public_set_non_monomorphic_cache(*dictionary);
167 }
168 
169 
ComputeLoad(Isolate * isolate,InlineCacheState ic_state,ExtraICState extra_state)170 Handle<Code> PropertyICCompiler::ComputeLoad(Isolate* isolate,
171                                              InlineCacheState ic_state,
172                                              ExtraICState extra_state) {
173   Code::Flags flags = Code::ComputeFlags(Code::LOAD_IC, ic_state, extra_state);
174   Handle<UnseededNumberDictionary> cache =
175       isolate->factory()->non_monomorphic_cache();
176   int entry = cache->FindEntry(isolate, flags);
177   if (entry != -1) return Handle<Code>(Code::cast(cache->ValueAt(entry)));
178 
179   PropertyICCompiler compiler(isolate, Code::LOAD_IC);
180   Handle<Code> code;
181   if (ic_state == UNINITIALIZED) {
182     code = compiler.CompileLoadInitialize(flags);
183   } else if (ic_state == PREMONOMORPHIC) {
184     code = compiler.CompileLoadPreMonomorphic(flags);
185   } else {
186     UNREACHABLE();
187   }
188   FillCache(isolate, code);
189   return code;
190 }
191 
192 
ComputeStore(Isolate * isolate,InlineCacheState ic_state,ExtraICState extra_state)193 Handle<Code> PropertyICCompiler::ComputeStore(Isolate* isolate,
194                                               InlineCacheState ic_state,
195                                               ExtraICState extra_state) {
196   Code::Flags flags = Code::ComputeFlags(Code::STORE_IC, ic_state, extra_state);
197   Handle<UnseededNumberDictionary> cache =
198       isolate->factory()->non_monomorphic_cache();
199   int entry = cache->FindEntry(isolate, flags);
200   if (entry != -1) return Handle<Code>(Code::cast(cache->ValueAt(entry)));
201 
202   PropertyICCompiler compiler(isolate, Code::STORE_IC);
203   Handle<Code> code;
204   if (ic_state == UNINITIALIZED) {
205     code = compiler.CompileStoreInitialize(flags);
206   } else if (ic_state == PREMONOMORPHIC) {
207     code = compiler.CompileStorePreMonomorphic(flags);
208   } else if (ic_state == GENERIC) {
209     code = compiler.CompileStoreGeneric(flags);
210   } else if (ic_state == MEGAMORPHIC) {
211     code = compiler.CompileStoreMegamorphic(flags);
212   } else {
213     UNREACHABLE();
214   }
215 
216   FillCache(isolate, code);
217   return code;
218 }
219 
220 
ComputeCompareNil(Handle<Map> receiver_map,CompareNilICStub * stub)221 Handle<Code> PropertyICCompiler::ComputeCompareNil(Handle<Map> receiver_map,
222                                                    CompareNilICStub* stub) {
223   Isolate* isolate = receiver_map->GetIsolate();
224   Handle<String> name(isolate->heap()->empty_string());
225   if (!receiver_map->is_dictionary_map()) {
226     Handle<Code> cached_ic =
227         Find(name, receiver_map, Code::COMPARE_NIL_IC, stub->GetExtraICState());
228     if (!cached_ic.is_null()) return cached_ic;
229   }
230 
231   Code::FindAndReplacePattern pattern;
232   pattern.Add(isolate->factory()->meta_map(), receiver_map);
233   Handle<Code> ic = stub->GetCodeCopy(pattern);
234 
235   if (!receiver_map->is_dictionary_map()) {
236     Map::UpdateCodeCache(receiver_map, name, ic);
237   }
238 
239   return ic;
240 }
241 
242 
243 // TODO(verwaest): Change this method so it takes in a TypeHandleList.
ComputeKeyedLoadPolymorphic(MapHandleList * receiver_maps)244 Handle<Code> PropertyICCompiler::ComputeKeyedLoadPolymorphic(
245     MapHandleList* receiver_maps) {
246   Isolate* isolate = receiver_maps->at(0)->GetIsolate();
247   Code::Flags flags = Code::ComputeFlags(Code::KEYED_LOAD_IC, POLYMORPHIC);
248   Handle<PolymorphicCodeCache> cache =
249       isolate->factory()->polymorphic_code_cache();
250   Handle<Object> probe = cache->Lookup(receiver_maps, flags);
251   if (probe->IsCode()) return Handle<Code>::cast(probe);
252 
253   TypeHandleList types(receiver_maps->length());
254   for (int i = 0; i < receiver_maps->length(); i++) {
255     types.Add(HeapType::Class(receiver_maps->at(i), isolate));
256   }
257   CodeHandleList handlers(receiver_maps->length());
258   ElementHandlerCompiler compiler(isolate);
259   compiler.CompileElementHandlers(receiver_maps, &handlers);
260   PropertyICCompiler ic_compiler(isolate, Code::KEYED_LOAD_IC);
261   Handle<Code> code = ic_compiler.CompilePolymorphic(
262       &types, &handlers, isolate->factory()->empty_string(), Code::NORMAL,
263       ELEMENT);
264 
265   isolate->counters()->keyed_load_polymorphic_stubs()->Increment();
266 
267   PolymorphicCodeCache::Update(cache, receiver_maps, flags, code);
268   return code;
269 }
270 
271 
ComputePolymorphic(Code::Kind kind,TypeHandleList * types,CodeHandleList * handlers,int valid_types,Handle<Name> name,ExtraICState extra_ic_state)272 Handle<Code> PropertyICCompiler::ComputePolymorphic(
273     Code::Kind kind, TypeHandleList* types, CodeHandleList* handlers,
274     int valid_types, Handle<Name> name, ExtraICState extra_ic_state) {
275   Handle<Code> handler = handlers->at(0);
276   Code::StubType type = valid_types == 1 ? handler->type() : Code::NORMAL;
277   DCHECK(kind == Code::LOAD_IC || kind == Code::STORE_IC);
278   PropertyICCompiler ic_compiler(name->GetIsolate(), kind, extra_ic_state);
279   return ic_compiler.CompilePolymorphic(types, handlers, name, type, PROPERTY);
280 }
281 
282 
ComputeKeyedStorePolymorphic(MapHandleList * receiver_maps,KeyedAccessStoreMode store_mode,StrictMode strict_mode)283 Handle<Code> PropertyICCompiler::ComputeKeyedStorePolymorphic(
284     MapHandleList* receiver_maps, KeyedAccessStoreMode store_mode,
285     StrictMode strict_mode) {
286   Isolate* isolate = receiver_maps->at(0)->GetIsolate();
287   DCHECK(store_mode == STANDARD_STORE ||
288          store_mode == STORE_AND_GROW_NO_TRANSITION ||
289          store_mode == STORE_NO_TRANSITION_IGNORE_OUT_OF_BOUNDS ||
290          store_mode == STORE_NO_TRANSITION_HANDLE_COW);
291   Handle<PolymorphicCodeCache> cache =
292       isolate->factory()->polymorphic_code_cache();
293   ExtraICState extra_state =
294       KeyedStoreIC::ComputeExtraICState(strict_mode, store_mode);
295   Code::Flags flags =
296       Code::ComputeFlags(Code::KEYED_STORE_IC, POLYMORPHIC, extra_state);
297   Handle<Object> probe = cache->Lookup(receiver_maps, flags);
298   if (probe->IsCode()) return Handle<Code>::cast(probe);
299 
300   PropertyICCompiler compiler(isolate, Code::KEYED_STORE_IC, extra_state);
301   Handle<Code> code =
302       compiler.CompileKeyedStorePolymorphic(receiver_maps, store_mode);
303   PolymorphicCodeCache::Update(cache, receiver_maps, flags, code);
304   return code;
305 }
306 
307 
CompileLoadInitialize(Code::Flags flags)308 Handle<Code> PropertyICCompiler::CompileLoadInitialize(Code::Flags flags) {
309   LoadIC::GenerateInitialize(masm());
310   Handle<Code> code = GetCodeWithFlags(flags, "CompileLoadInitialize");
311   PROFILE(isolate(), CodeCreateEvent(Logger::LOAD_INITIALIZE_TAG, *code, 0));
312   return code;
313 }
314 
315 
CompileLoadPreMonomorphic(Code::Flags flags)316 Handle<Code> PropertyICCompiler::CompileLoadPreMonomorphic(Code::Flags flags) {
317   LoadIC::GeneratePreMonomorphic(masm());
318   Handle<Code> code = GetCodeWithFlags(flags, "CompileLoadPreMonomorphic");
319   PROFILE(isolate(),
320           CodeCreateEvent(Logger::LOAD_PREMONOMORPHIC_TAG, *code, 0));
321   return code;
322 }
323 
324 
CompileStoreInitialize(Code::Flags flags)325 Handle<Code> PropertyICCompiler::CompileStoreInitialize(Code::Flags flags) {
326   StoreIC::GenerateInitialize(masm());
327   Handle<Code> code = GetCodeWithFlags(flags, "CompileStoreInitialize");
328   PROFILE(isolate(), CodeCreateEvent(Logger::STORE_INITIALIZE_TAG, *code, 0));
329   return code;
330 }
331 
332 
CompileStorePreMonomorphic(Code::Flags flags)333 Handle<Code> PropertyICCompiler::CompileStorePreMonomorphic(Code::Flags flags) {
334   StoreIC::GeneratePreMonomorphic(masm());
335   Handle<Code> code = GetCodeWithFlags(flags, "CompileStorePreMonomorphic");
336   PROFILE(isolate(),
337           CodeCreateEvent(Logger::STORE_PREMONOMORPHIC_TAG, *code, 0));
338   return code;
339 }
340 
341 
CompileStoreGeneric(Code::Flags flags)342 Handle<Code> PropertyICCompiler::CompileStoreGeneric(Code::Flags flags) {
343   ExtraICState extra_state = Code::ExtractExtraICStateFromFlags(flags);
344   StrictMode strict_mode = StoreIC::GetStrictMode(extra_state);
345   GenerateRuntimeSetProperty(masm(), strict_mode);
346   Handle<Code> code = GetCodeWithFlags(flags, "CompileStoreGeneric");
347   PROFILE(isolate(), CodeCreateEvent(Logger::STORE_GENERIC_TAG, *code, 0));
348   return code;
349 }
350 
351 
CompileStoreMegamorphic(Code::Flags flags)352 Handle<Code> PropertyICCompiler::CompileStoreMegamorphic(Code::Flags flags) {
353   StoreIC::GenerateMegamorphic(masm());
354   Handle<Code> code = GetCodeWithFlags(flags, "CompileStoreMegamorphic");
355   PROFILE(isolate(), CodeCreateEvent(Logger::STORE_MEGAMORPHIC_TAG, *code, 0));
356   return code;
357 }
358 
359 
GetCode(Code::Kind kind,Code::StubType type,Handle<Name> name,InlineCacheState state)360 Handle<Code> PropertyICCompiler::GetCode(Code::Kind kind, Code::StubType type,
361                                          Handle<Name> name,
362                                          InlineCacheState state) {
363   Code::Flags flags =
364       Code::ComputeFlags(kind, state, extra_ic_state_, type, cache_holder());
365   Handle<Code> code = GetCodeWithFlags(flags, name);
366   IC::RegisterWeakMapDependency(code);
367   PROFILE(isolate(), CodeCreateEvent(log_kind(code), *code, *name));
368   return code;
369 }
370 
371 
CompileKeyedStorePolymorphic(MapHandleList * receiver_maps,KeyedAccessStoreMode store_mode)372 Handle<Code> PropertyICCompiler::CompileKeyedStorePolymorphic(
373     MapHandleList* receiver_maps, KeyedAccessStoreMode store_mode) {
374   // Collect MONOMORPHIC stubs for all |receiver_maps|.
375   CodeHandleList handlers(receiver_maps->length());
376   MapHandleList transitioned_maps(receiver_maps->length());
377   for (int i = 0; i < receiver_maps->length(); ++i) {
378     Handle<Map> receiver_map(receiver_maps->at(i));
379     Handle<Code> cached_stub;
380     Handle<Map> transitioned_map =
381         receiver_map->FindTransitionedMap(receiver_maps);
382 
383     // TODO(mvstanton): The code below is doing pessimistic elements
384     // transitions. I would like to stop doing that and rely on Allocation Site
385     // Tracking to do a better job of ensuring the data types are what they need
386     // to be. Not all the elements are in place yet, pessimistic elements
387     // transitions are still important for performance.
388     bool is_js_array = receiver_map->instance_type() == JS_ARRAY_TYPE;
389     ElementsKind elements_kind = receiver_map->elements_kind();
390     if (!transitioned_map.is_null()) {
391       cached_stub =
392           ElementsTransitionAndStoreStub(isolate(), elements_kind,
393                                          transitioned_map->elements_kind(),
394                                          is_js_array, store_mode).GetCode();
395     } else if (receiver_map->instance_type() < FIRST_JS_RECEIVER_TYPE) {
396       cached_stub = isolate()->builtins()->KeyedStoreIC_Slow();
397     } else {
398       if (receiver_map->has_fast_elements() ||
399           receiver_map->has_external_array_elements() ||
400           receiver_map->has_fixed_typed_array_elements()) {
401         cached_stub = StoreFastElementStub(isolate(), is_js_array,
402                                            elements_kind, store_mode).GetCode();
403       } else {
404         cached_stub = StoreElementStub(isolate(), elements_kind).GetCode();
405       }
406     }
407     DCHECK(!cached_stub.is_null());
408     handlers.Add(cached_stub);
409     transitioned_maps.Add(transitioned_map);
410   }
411 
412   Handle<Code> code = CompileKeyedStorePolymorphic(receiver_maps, &handlers,
413                                                    &transitioned_maps);
414   isolate()->counters()->keyed_store_polymorphic_stubs()->Increment();
415   PROFILE(isolate(), CodeCreateEvent(log_kind(code), *code, 0));
416   return code;
417 }
418 
419 
420 #define __ ACCESS_MASM(masm())
421 
422 
CompileKeyedStoreMonomorphic(Handle<Map> receiver_map,KeyedAccessStoreMode store_mode)423 Handle<Code> PropertyICCompiler::CompileKeyedStoreMonomorphic(
424     Handle<Map> receiver_map, KeyedAccessStoreMode store_mode) {
425   ElementsKind elements_kind = receiver_map->elements_kind();
426   bool is_jsarray = receiver_map->instance_type() == JS_ARRAY_TYPE;
427   Handle<Code> stub;
428   if (receiver_map->has_fast_elements() ||
429       receiver_map->has_external_array_elements() ||
430       receiver_map->has_fixed_typed_array_elements()) {
431     stub = StoreFastElementStub(isolate(), is_jsarray, elements_kind,
432                                 store_mode).GetCode();
433   } else {
434     stub = StoreElementStub(isolate(), elements_kind).GetCode();
435   }
436 
437   __ DispatchMap(receiver(), scratch1(), receiver_map, stub, DO_SMI_CHECK);
438 
439   TailCallBuiltin(masm(), Builtins::kKeyedStoreIC_Miss);
440 
441   return GetCode(kind(), Code::NORMAL, factory()->empty_string());
442 }
443 
444 
445 #undef __
446 }
447 }  // namespace v8::internal
448