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.
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"
17 Handle<Code> PropertyICCompiler::Find(Handle<Name> name,
18 Handle<Map> stub_holder, Code::Kind kind,
19 ExtraICState extra_state,
20 CacheHolderFlag cache_holder) {
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();
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;
37 Handle<Code> PropertyICCompiler::CompileMonomorphic(Handle<Map> map,
41 MapHandleList maps(1);
42 CodeHandleList handlers(1);
44 handlers.Add(handler);
45 Code::StubType stub_type = handler->type();
46 return CompilePolymorphic(&maps, &handlers, name, stub_type, check);
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();
60 Handle<Map> stub_holder = IC::GetICCacheHolder(map, isolate, &flag);
61 if (kind == Code::KEYED_STORE_IC) {
62 // Always set the "property" bit.
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,
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;
78 ic = Find(name, stub_holder, kind, extra_ic_state, flag);
79 if (!ic.is_null()) return ic;
82 PropertyICCompiler ic_compiler(isolate, kind, extra_ic_state, flag);
83 ic = ic_compiler.CompileMonomorphic(map, handler, name, PROPERTY);
85 if (can_be_cached) Map::UpdateCodeCache(stub_holder, name, ic);
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();
97 Handle<Object> probe(receiver_map->FindInCodeCache(*name, flags), isolate);
98 if (probe->IsCode()) return Handle<Code>::cast(probe);
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);
105 Map::UpdateCodeCache(receiver_map, name, code);
110 Handle<Code> PropertyICCompiler::ComputeKeyedLoadMonomorphicHandler(
111 Handle<Map> receiver_map) {
112 Isolate* isolate = receiver_map->GetIsolate();
113 ElementsKind elements_kind = receiver_map->elements_kind();
115 if (receiver_map->has_indexed_interceptor()) {
116 stub = LoadIndexedInterceptorStub(isolate).GetCode();
117 } else if (receiver_map->IsStringMap()) {
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();
129 stub = LoadDictionaryElementStub(isolate).GetCode();
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);
142 Code::ComputeMonomorphicFlags(Code::KEYED_STORE_IC, extra_state);
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);
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);
153 PropertyICCompiler compiler(isolate, Code::KEYED_STORE_IC, extra_state);
155 compiler.CompileKeyedStoreMonomorphic(receiver_map, store_mode);
157 Map::UpdateCodeCache(receiver_map, name, code);
158 DCHECK(KeyedStoreIC::GetKeyedAccessStoreMode(code->extra_ic_state()) ==
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);
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);
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);
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)));
194 PropertyICCompiler compiler(isolate, Code::LOAD_IC);
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);
205 FillCache(isolate, code);
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)));
219 PropertyICCompiler compiler(isolate, Code::STORE_IC);
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);
233 FillCache(isolate, code);
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;
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);
253 if (!receiver_map->is_dictionary_map()) {
254 Map::UpdateCodeCache(receiver_map, name, ic);
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);
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);
279 isolate->counters()->keyed_load_polymorphic_stubs()->Increment();
281 PolymorphicCodeCache::Update(cache, receiver_maps, flags, code);
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);
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);
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);
314 PropertyICCompiler compiler(isolate, Code::KEYED_STORE_IC, extra_state);
316 compiler.CompileKeyedStorePolymorphic(receiver_maps, store_mode);
317 PolymorphicCodeCache::Update(cache, receiver_maps, flags, code);
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));
330 Handle<Code> PropertyICCompiler::CompileLoadPreMonomorphic(Code::Flags flags) {
331 LoadIC::GeneratePreMonomorphic(masm());
332 Handle<Code> code = GetCodeWithFlags(flags, "CompileLoadPreMonomorphic");
334 CodeCreateEvent(Logger::LOAD_PREMONOMORPHIC_TAG, *code, 0));
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));
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));
355 Handle<Code> PropertyICCompiler::CompileStorePreMonomorphic(Code::Flags flags) {
356 StoreIC::GeneratePreMonomorphic(masm());
357 Handle<Code> code = GetCodeWithFlags(flags, "CompileStorePreMonomorphic");
359 CodeCreateEvent(Logger::STORE_PREMONOMORPHIC_TAG, *code, 0));
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));
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));
382 Handle<Code> PropertyICCompiler::GetCode(Code::Kind kind, Code::StubType type,
384 InlineCacheState state) {
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));
390 code->VerifyEmbeddedObjects();
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);
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()) {
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();
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();
428 cached_stub = StoreElementStub(isolate(), elements_kind).GetCode();
431 DCHECK(!cached_stub.is_null());
432 handlers.Add(cached_stub);
433 transitioned_maps.Add(transitioned_map);
436 Handle<Code> code = CompileKeyedStorePolymorphic(receiver_maps, &handlers,
438 isolate()->counters()->keyed_store_polymorphic_stubs()->Increment();
439 PROFILE(isolate(), CodeCreateEvent(log_kind(code), *code, 0));
444 #define __ ACCESS_MASM(masm())
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;
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();
458 stub = StoreElementStub(isolate(), elements_kind).GetCode();
461 Handle<WeakCell> cell = Map::WeakCellForMap(receiver_map);
463 __ DispatchWeakMap(receiver(), scratch1(), scratch2(), cell, stub,
466 TailCallBuiltin(masm(), Builtins::kKeyedStoreIC_Miss);
468 return GetCode(kind(), Code::NORMAL, factory()->empty_string());
474 } // namespace v8::internal