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
12namespace v8 {
13namespace internal {
14
15
16Handle<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
28bool 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
36Handle<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
49Handle<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
86Handle<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
120Handle<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
149Code* 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
163static 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
170Handle<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
193Handle<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
221Handle<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.
244Handle<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
272Handle<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
283Handle<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
308Handle<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
316Handle<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
325Handle<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
333Handle<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
342Handle<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
352Handle<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
360Handle<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
372Handle<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
423Handle<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