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