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
Find(Handle<Name> name,Handle<Map> stub_holder,Code::Kind kind,ExtraICState extra_state,CacheHolderFlag cache_holder)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
IncludesNumberType(TypeHandleList * types)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
CompileMonomorphic(Handle<HeapType> type,Handle<Code> handler,Handle<Name> name,IcCheckType check)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
ComputeMonomorphic(Code::Kind kind,Handle<Name> name,Handle<HeapType> type,Handle<Code> handler,ExtraICState extra_ic_state)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
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
ComputeKeyedLoadMonomorphic(Handle<Map> receiver_map)86 Handle<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
ComputeKeyedStoreMonomorphic(Handle<Map> receiver_map,StrictMode strict_mode,KeyedAccessStoreMode store_mode)120 Handle<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
FindPreMonomorphic(Isolate * isolate,Code::Kind kind,ExtraICState state)149 Code* 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
FillCache(Isolate * isolate,Handle<Code> code)163 static 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
ComputeLoad(Isolate * isolate,InlineCacheState ic_state,ExtraICState extra_state)170 Handle<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
ComputeStore(Isolate * isolate,InlineCacheState ic_state,ExtraICState extra_state)193 Handle<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
ComputeCompareNil(Handle<Map> receiver_map,CompareNilICStub * stub)221 Handle<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.
ComputeKeyedLoadPolymorphic(MapHandleList * receiver_maps)244 Handle<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
ComputePolymorphic(Code::Kind kind,TypeHandleList * types,CodeHandleList * handlers,int valid_types,Handle<Name> name,ExtraICState extra_ic_state)272 Handle<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
ComputeKeyedStorePolymorphic(MapHandleList * receiver_maps,KeyedAccessStoreMode store_mode,StrictMode strict_mode)283 Handle<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
CompileLoadInitialize(Code::Flags flags)308 Handle<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
CompileLoadPreMonomorphic(Code::Flags flags)316 Handle<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
CompileStoreInitialize(Code::Flags flags)325 Handle<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
CompileStorePreMonomorphic(Code::Flags flags)333 Handle<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
CompileStoreGeneric(Code::Flags flags)342 Handle<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
CompileStoreMegamorphic(Code::Flags flags)352 Handle<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
GetCode(Code::Kind kind,Code::StubType type,Handle<Name> name,InlineCacheState state)360 Handle<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
CompileKeyedStorePolymorphic(MapHandleList * receiver_maps,KeyedAccessStoreMode store_mode)372 Handle<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
CompileKeyedStoreMonomorphic(Handle<Map> receiver_map,KeyedAccessStoreMode store_mode)423 Handle<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