deps: upgrade v8 to 3.31.74.1
[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::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
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
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   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 = !type->Is(HeapType::String());
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(type, 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 =
102       compiler.CompileMonomorphic(HeapType::Class(receiver_map, isolate), stub,
103                                   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, StrictMode strict_mode,
137     KeyedAccessStoreMode store_mode) {
138   Isolate* isolate = receiver_map->GetIsolate();
139   ExtraICState extra_state =
140       KeyedStoreIC::ComputeExtraICState(strict_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 {
201     UNREACHABLE();
202   }
203   FillCache(isolate, code);
204   return code;
205 }
206
207
208 Handle<Code> PropertyICCompiler::ComputeStore(Isolate* isolate,
209                                               InlineCacheState ic_state,
210                                               ExtraICState extra_state) {
211   Code::Flags flags = Code::ComputeFlags(Code::STORE_IC, ic_state, extra_state);
212   Handle<UnseededNumberDictionary> cache =
213       isolate->factory()->non_monomorphic_cache();
214   int entry = cache->FindEntry(isolate, flags);
215   if (entry != -1) return Handle<Code>(Code::cast(cache->ValueAt(entry)));
216
217   PropertyICCompiler compiler(isolate, Code::STORE_IC);
218   Handle<Code> code;
219   if (ic_state == UNINITIALIZED) {
220     code = compiler.CompileStoreInitialize(flags);
221   } else if (ic_state == PREMONOMORPHIC) {
222     code = compiler.CompileStorePreMonomorphic(flags);
223   } else if (ic_state == GENERIC) {
224     code = compiler.CompileStoreGeneric(flags);
225   } else if (ic_state == MEGAMORPHIC) {
226     code = compiler.CompileStoreMegamorphic(flags);
227   } else {
228     UNREACHABLE();
229   }
230
231   FillCache(isolate, code);
232   return code;
233 }
234
235
236 Handle<Code> PropertyICCompiler::ComputeCompareNil(Handle<Map> receiver_map,
237                                                    CompareNilICStub* stub) {
238   Isolate* isolate = receiver_map->GetIsolate();
239   Handle<String> name(isolate->heap()->empty_string());
240   if (!receiver_map->is_dictionary_map()) {
241     Handle<Code> cached_ic =
242         Find(name, receiver_map, Code::COMPARE_NIL_IC, stub->GetExtraICState());
243     if (!cached_ic.is_null()) return cached_ic;
244   }
245
246   Code::FindAndReplacePattern pattern;
247   Handle<WeakCell> cell = Map::WeakCellForMap(receiver_map);
248   pattern.Add(isolate->factory()->meta_map(), cell);
249   Handle<Code> ic = stub->GetCodeCopy(pattern);
250
251   if (!receiver_map->is_dictionary_map()) {
252     Map::UpdateCodeCache(receiver_map, name, ic);
253   }
254
255   return ic;
256 }
257
258
259 // TODO(verwaest): Change this method so it takes in a TypeHandleList.
260 Handle<Code> PropertyICCompiler::ComputeKeyedLoadPolymorphic(
261     MapHandleList* receiver_maps) {
262   Isolate* isolate = receiver_maps->at(0)->GetIsolate();
263   DCHECK(KeyedLoadIC::GetKeyType(kNoExtraICState) == ELEMENT);
264   Code::Flags flags = Code::ComputeFlags(Code::KEYED_LOAD_IC, POLYMORPHIC);
265   Handle<PolymorphicCodeCache> cache =
266       isolate->factory()->polymorphic_code_cache();
267   Handle<Object> probe = cache->Lookup(receiver_maps, flags);
268   if (probe->IsCode()) return Handle<Code>::cast(probe);
269
270   TypeHandleList types(receiver_maps->length());
271   for (int i = 0; i < receiver_maps->length(); i++) {
272     types.Add(HeapType::Class(receiver_maps->at(i), isolate));
273   }
274   CodeHandleList handlers(receiver_maps->length());
275   ElementHandlerCompiler compiler(isolate);
276   compiler.CompileElementHandlers(receiver_maps, &handlers);
277   PropertyICCompiler ic_compiler(isolate, Code::KEYED_LOAD_IC);
278   Handle<Code> code = ic_compiler.CompilePolymorphic(
279       &types, &handlers, isolate->factory()->empty_string(), Code::NORMAL,
280       ELEMENT);
281
282   isolate->counters()->keyed_load_polymorphic_stubs()->Increment();
283
284   PolymorphicCodeCache::Update(cache, receiver_maps, flags, code);
285   return code;
286 }
287
288
289 Handle<Code> PropertyICCompiler::ComputePolymorphic(
290     Code::Kind kind, TypeHandleList* types, CodeHandleList* handlers,
291     int valid_types, Handle<Name> name, ExtraICState extra_ic_state) {
292   Handle<Code> handler = handlers->at(0);
293   Code::StubType type = valid_types == 1 ? handler->type() : Code::NORMAL;
294   DCHECK(kind == Code::LOAD_IC || kind == Code::STORE_IC);
295   PropertyICCompiler ic_compiler(name->GetIsolate(), kind, extra_ic_state);
296   return ic_compiler.CompilePolymorphic(types, handlers, name, type, PROPERTY);
297 }
298
299
300 Handle<Code> PropertyICCompiler::ComputeKeyedStorePolymorphic(
301     MapHandleList* receiver_maps, KeyedAccessStoreMode store_mode,
302     StrictMode strict_mode) {
303   Isolate* isolate = receiver_maps->at(0)->GetIsolate();
304   DCHECK(store_mode == STANDARD_STORE ||
305          store_mode == STORE_AND_GROW_NO_TRANSITION ||
306          store_mode == STORE_NO_TRANSITION_IGNORE_OUT_OF_BOUNDS ||
307          store_mode == STORE_NO_TRANSITION_HANDLE_COW);
308   Handle<PolymorphicCodeCache> cache =
309       isolate->factory()->polymorphic_code_cache();
310   ExtraICState extra_state =
311       KeyedStoreIC::ComputeExtraICState(strict_mode, store_mode);
312   Code::Flags flags =
313       Code::ComputeFlags(Code::KEYED_STORE_IC, POLYMORPHIC, extra_state);
314   Handle<Object> probe = cache->Lookup(receiver_maps, flags);
315   if (probe->IsCode()) return Handle<Code>::cast(probe);
316
317   PropertyICCompiler compiler(isolate, Code::KEYED_STORE_IC, extra_state);
318   Handle<Code> code =
319       compiler.CompileKeyedStorePolymorphic(receiver_maps, store_mode);
320   PolymorphicCodeCache::Update(cache, receiver_maps, flags, code);
321   return code;
322 }
323
324
325 Handle<Code> PropertyICCompiler::CompileLoadInitialize(Code::Flags flags) {
326   LoadIC::GenerateInitialize(masm());
327   Handle<Code> code = GetCodeWithFlags(flags, "CompileLoadInitialize");
328   PROFILE(isolate(), CodeCreateEvent(Logger::LOAD_INITIALIZE_TAG, *code, 0));
329   return code;
330 }
331
332
333 Handle<Code> PropertyICCompiler::CompileLoadPreMonomorphic(Code::Flags flags) {
334   LoadIC::GeneratePreMonomorphic(masm());
335   Handle<Code> code = GetCodeWithFlags(flags, "CompileLoadPreMonomorphic");
336   PROFILE(isolate(),
337           CodeCreateEvent(Logger::LOAD_PREMONOMORPHIC_TAG, *code, 0));
338   return code;
339 }
340
341
342 Handle<Code> PropertyICCompiler::CompileStoreInitialize(Code::Flags flags) {
343   StoreIC::GenerateInitialize(masm());
344   Handle<Code> code = GetCodeWithFlags(flags, "CompileStoreInitialize");
345   PROFILE(isolate(), CodeCreateEvent(Logger::STORE_INITIALIZE_TAG, *code, 0));
346   return code;
347 }
348
349
350 Handle<Code> PropertyICCompiler::CompileStorePreMonomorphic(Code::Flags flags) {
351   StoreIC::GeneratePreMonomorphic(masm());
352   Handle<Code> code = GetCodeWithFlags(flags, "CompileStorePreMonomorphic");
353   PROFILE(isolate(),
354           CodeCreateEvent(Logger::STORE_PREMONOMORPHIC_TAG, *code, 0));
355   return code;
356 }
357
358
359 Handle<Code> PropertyICCompiler::CompileStoreGeneric(Code::Flags flags) {
360   ExtraICState extra_state = Code::ExtractExtraICStateFromFlags(flags);
361   StrictMode strict_mode = StoreIC::GetStrictMode(extra_state);
362   GenerateRuntimeSetProperty(masm(), strict_mode);
363   Handle<Code> code = GetCodeWithFlags(flags, "CompileStoreGeneric");
364   PROFILE(isolate(), CodeCreateEvent(Logger::STORE_GENERIC_TAG, *code, 0));
365   return code;
366 }
367
368
369 Handle<Code> PropertyICCompiler::CompileStoreMegamorphic(Code::Flags flags) {
370   StoreIC::GenerateMegamorphic(masm());
371   Handle<Code> code = GetCodeWithFlags(flags, "CompileStoreMegamorphic");
372   PROFILE(isolate(), CodeCreateEvent(Logger::STORE_MEGAMORPHIC_TAG, *code, 0));
373   return code;
374 }
375
376
377 Handle<Code> PropertyICCompiler::GetCode(Code::Kind kind, Code::StubType type,
378                                          Handle<Name> name,
379                                          InlineCacheState state) {
380   Code::Flags flags =
381       Code::ComputeFlags(kind, state, extra_ic_state_, type, cache_holder());
382   Handle<Code> code = GetCodeWithFlags(flags, name);
383   PROFILE(isolate(), CodeCreateEvent(log_kind(code), *code, *name));
384   return code;
385 }
386
387
388 Handle<Code> PropertyICCompiler::CompileKeyedStorePolymorphic(
389     MapHandleList* receiver_maps, KeyedAccessStoreMode store_mode) {
390   // Collect MONOMORPHIC stubs for all |receiver_maps|.
391   CodeHandleList handlers(receiver_maps->length());
392   MapHandleList transitioned_maps(receiver_maps->length());
393   for (int i = 0; i < receiver_maps->length(); ++i) {
394     Handle<Map> receiver_map(receiver_maps->at(i));
395     Handle<Code> cached_stub;
396     Handle<Map> transitioned_map =
397         receiver_map->FindTransitionedMap(receiver_maps);
398
399     // TODO(mvstanton): The code below is doing pessimistic elements
400     // transitions. I would like to stop doing that and rely on Allocation Site
401     // Tracking to do a better job of ensuring the data types are what they need
402     // to be. Not all the elements are in place yet, pessimistic elements
403     // transitions are still important for performance.
404     bool is_js_array = receiver_map->instance_type() == JS_ARRAY_TYPE;
405     ElementsKind elements_kind = receiver_map->elements_kind();
406     if (!transitioned_map.is_null()) {
407       cached_stub =
408           ElementsTransitionAndStoreStub(isolate(), elements_kind,
409                                          transitioned_map->elements_kind(),
410                                          is_js_array, store_mode).GetCode();
411     } else if (receiver_map->instance_type() < FIRST_JS_RECEIVER_TYPE) {
412       cached_stub = isolate()->builtins()->KeyedStoreIC_Slow();
413     } else {
414       if (receiver_map->has_fast_elements() ||
415           receiver_map->has_external_array_elements() ||
416           receiver_map->has_fixed_typed_array_elements()) {
417         cached_stub = StoreFastElementStub(isolate(), is_js_array,
418                                            elements_kind, store_mode).GetCode();
419       } else {
420         cached_stub = StoreElementStub(isolate(), elements_kind).GetCode();
421       }
422     }
423     DCHECK(!cached_stub.is_null());
424     handlers.Add(cached_stub);
425     transitioned_maps.Add(transitioned_map);
426   }
427
428   Handle<Code> code = CompileKeyedStorePolymorphic(receiver_maps, &handlers,
429                                                    &transitioned_maps);
430   isolate()->counters()->keyed_store_polymorphic_stubs()->Increment();
431   PROFILE(isolate(), CodeCreateEvent(log_kind(code), *code, 0));
432   return code;
433 }
434
435
436 #define __ ACCESS_MASM(masm())
437
438
439 Handle<Code> PropertyICCompiler::CompileKeyedStoreMonomorphic(
440     Handle<Map> receiver_map, KeyedAccessStoreMode store_mode) {
441   ElementsKind elements_kind = receiver_map->elements_kind();
442   bool is_jsarray = receiver_map->instance_type() == JS_ARRAY_TYPE;
443   Handle<Code> stub;
444   if (receiver_map->has_fast_elements() ||
445       receiver_map->has_external_array_elements() ||
446       receiver_map->has_fixed_typed_array_elements()) {
447     stub = StoreFastElementStub(isolate(), is_jsarray, elements_kind,
448                                 store_mode).GetCode();
449   } else {
450     stub = StoreElementStub(isolate(), elements_kind).GetCode();
451   }
452
453   Handle<WeakCell> cell = Map::WeakCellForMap(receiver_map);
454
455   __ DispatchWeakMap(receiver(), scratch1(), scratch2(), cell, stub,
456                      DO_SMI_CHECK);
457
458   TailCallBuiltin(masm(), Builtins::kKeyedStoreIC_Miss);
459
460   return GetCode(kind(), Code::NORMAL, factory()->empty_string());
461 }
462
463
464 #undef __
465 }
466 }  // namespace v8::internal