blob: e087acfcb0e71f1be9d6a75a961a10f00563c477 [file] [log] [blame]
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001// 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);
Emily Bernierd0a1eb72015-03-24 16:35:39 -040060 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 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000070
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
Ben Murdochb8a8cc12014-11-26 15:28:44 +000081 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
89Handle<Code> PropertyICCompiler::ComputeKeyedLoadMonomorphic(
90 Handle<Map> receiver_map) {
91 Isolate* isolate = receiver_map->GetIsolate();
Emily Bernierd0a1eb72015-03-24 16:35:39 -040092 DCHECK(KeyedLoadIC::GetKeyType(kNoExtraICState) == ELEMENT);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000093 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
Emily Bernierd0a1eb72015-03-24 16:35:39 -040099 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
110Handle<Code> PropertyICCompiler::ComputeKeyedLoadMonomorphicHandler(
111 Handle<Map> receiver_map) {
112 Isolate* isolate = receiver_map->GetIsolate();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000113 ElementsKind elements_kind = receiver_map->elements_kind();
114 Handle<Code> stub;
115 if (receiver_map->has_indexed_interceptor()) {
116 stub = LoadIndexedInterceptorStub(isolate).GetCode();
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400117 } else if (receiver_map->IsStringMap()) {
118 // We have a string.
119 stub = LoadIndexedStringStub(isolate).GetCode();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000120 } 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 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400131 return stub;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000132}
133
134
135Handle<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
164Code* 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
178static 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
185Handle<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
208Handle<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
236Handle<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;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400247 Handle<WeakCell> cell = Map::WeakCellForMap(receiver_map);
248 pattern.Add(isolate->factory()->meta_map(), cell);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000249 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.
260Handle<Code> PropertyICCompiler::ComputeKeyedLoadPolymorphic(
261 MapHandleList* receiver_maps) {
262 Isolate* isolate = receiver_maps->at(0)->GetIsolate();
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400263 DCHECK(KeyedLoadIC::GetKeyType(kNoExtraICState) == ELEMENT);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000264 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
289Handle<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
300Handle<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
325Handle<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
333Handle<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
342Handle<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
350Handle<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
359Handle<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
369Handle<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
377Handle<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);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000383 PROFILE(isolate(), CodeCreateEvent(log_kind(code), *code, *name));
384 return code;
385}
386
387
388Handle<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
439Handle<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
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400453 Handle<WeakCell> cell = Map::WeakCellForMap(receiver_map);
454
455 __ DispatchWeakMap(receiver(), scratch1(), scratch2(), cell, stub,
456 DO_SMI_CHECK);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000457
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