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