Upstream version 9.38.198.0
[platform/framework/web/crosswalk.git] / src / v8 / src / stub-cache.cc
1 // Copyright 2012 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/api.h"
8 #include "src/arguments.h"
9 #include "src/ast.h"
10 #include "src/code-stubs.h"
11 #include "src/cpu-profiler.h"
12 #include "src/gdb-jit.h"
13 #include "src/ic-inl.h"
14 #include "src/stub-cache.h"
15 #include "src/type-info.h"
16 #include "src/vm-state-inl.h"
17
18 namespace v8 {
19 namespace internal {
20
21 // -----------------------------------------------------------------------
22 // StubCache implementation.
23
24
25 StubCache::StubCache(Isolate* isolate)
26     : isolate_(isolate) { }
27
28
29 void StubCache::Initialize() {
30   DCHECK(IsPowerOf2(kPrimaryTableSize));
31   DCHECK(IsPowerOf2(kSecondaryTableSize));
32   Clear();
33 }
34
35
36 static Code::Flags CommonStubCacheChecks(Name* name, Map* map,
37                                          Code::Flags flags) {
38   flags = Code::RemoveTypeAndHolderFromFlags(flags);
39
40   // Validate that the name does not move on scavenge, and that we
41   // can use identity checks instead of structural equality checks.
42   DCHECK(!name->GetHeap()->InNewSpace(name));
43   DCHECK(name->IsUniqueName());
44
45   // The state bits are not important to the hash function because the stub
46   // cache only contains handlers. Make sure that the bits are the least
47   // significant so they will be the ones masked out.
48   DCHECK_EQ(Code::HANDLER, Code::ExtractKindFromFlags(flags));
49   STATIC_ASSERT((Code::ICStateField::kMask & 1) == 1);
50
51   // Make sure that the code type and cache holder are not included in the hash.
52   DCHECK(Code::ExtractTypeFromFlags(flags) == 0);
53   DCHECK(Code::ExtractCacheHolderFromFlags(flags) == 0);
54
55   return flags;
56 }
57
58
59 Code* StubCache::Set(Name* name, Map* map, Code* code) {
60   Code::Flags flags = CommonStubCacheChecks(name, map, code->flags());
61
62   // Compute the primary entry.
63   int primary_offset = PrimaryOffset(name, flags, map);
64   Entry* primary = entry(primary_, primary_offset);
65   Code* old_code = primary->value;
66
67   // If the primary entry has useful data in it, we retire it to the
68   // secondary cache before overwriting it.
69   if (old_code != isolate_->builtins()->builtin(Builtins::kIllegal)) {
70     Map* old_map = primary->map;
71     Code::Flags old_flags =
72         Code::RemoveTypeAndHolderFromFlags(old_code->flags());
73     int seed = PrimaryOffset(primary->key, old_flags, old_map);
74     int secondary_offset = SecondaryOffset(primary->key, old_flags, seed);
75     Entry* secondary = entry(secondary_, secondary_offset);
76     *secondary = *primary;
77   }
78
79   // Update primary cache.
80   primary->key = name;
81   primary->value = code;
82   primary->map = map;
83   isolate()->counters()->megamorphic_stub_cache_updates()->Increment();
84   return code;
85 }
86
87
88 Code* StubCache::Get(Name* name, Map* map, Code::Flags flags) {
89   flags = CommonStubCacheChecks(name, map, flags);
90   int primary_offset = PrimaryOffset(name, flags, map);
91   Entry* primary = entry(primary_, primary_offset);
92   if (primary->key == name && primary->map == map) {
93     return primary->value;
94   }
95   int secondary_offset = SecondaryOffset(name, flags, primary_offset);
96   Entry* secondary = entry(secondary_, secondary_offset);
97   if (secondary->key == name && secondary->map == map) {
98     return secondary->value;
99   }
100   return NULL;
101 }
102
103
104 Handle<Code> PropertyICCompiler::Find(Handle<Name> name,
105                                       Handle<Map> stub_holder, Code::Kind kind,
106                                       ExtraICState extra_state,
107                                       CacheHolderFlag cache_holder) {
108   Code::Flags flags = Code::ComputeMonomorphicFlags(
109       kind, extra_state, cache_holder);
110   Object* probe = stub_holder->FindInCodeCache(*name, flags);
111   if (probe->IsCode()) return handle(Code::cast(probe));
112   return Handle<Code>::null();
113 }
114
115
116 Handle<Code> PropertyHandlerCompiler::Find(Handle<Name> name,
117                                            Handle<Map> stub_holder,
118                                            Code::Kind kind,
119                                            CacheHolderFlag cache_holder,
120                                            Code::StubType type) {
121   Code::Flags flags = Code::ComputeHandlerFlags(kind, type, cache_holder);
122   Object* probe = stub_holder->FindInCodeCache(*name, flags);
123   if (probe->IsCode()) return handle(Code::cast(probe));
124   return Handle<Code>::null();
125 }
126
127
128 Handle<Code> PropertyICCompiler::ComputeMonomorphic(
129     Code::Kind kind, Handle<Name> name, Handle<HeapType> type,
130     Handle<Code> handler, ExtraICState extra_ic_state) {
131   Isolate* isolate = name->GetIsolate();
132   if (handler.is_identical_to(isolate->builtins()->LoadIC_Normal()) ||
133       handler.is_identical_to(isolate->builtins()->StoreIC_Normal())) {
134     name = isolate->factory()->normal_ic_symbol();
135   }
136
137   CacheHolderFlag flag;
138   Handle<Map> stub_holder = IC::GetICCacheHolder(*type, isolate, &flag);
139
140   Handle<Code> ic;
141   // There are multiple string maps that all use the same prototype. That
142   // prototype cannot hold multiple handlers, one for each of the string maps,
143   // for a single name. Hence, turn off caching of the IC.
144   bool can_be_cached = !type->Is(HeapType::String());
145   if (can_be_cached) {
146     ic = Find(name, stub_holder, kind, extra_ic_state, flag);
147     if (!ic.is_null()) return ic;
148   }
149
150 #ifdef DEBUG
151   if (kind == Code::KEYED_STORE_IC) {
152     DCHECK(STANDARD_STORE ==
153            KeyedStoreIC::GetKeyedAccessStoreMode(extra_ic_state));
154   }
155 #endif
156
157   PropertyICCompiler ic_compiler(isolate, kind, extra_ic_state, flag);
158   ic = ic_compiler.CompileMonomorphic(type, handler, name, PROPERTY);
159
160   if (can_be_cached) Map::UpdateCodeCache(stub_holder, name, ic);
161   return ic;
162 }
163
164
165 Handle<Code> NamedLoadHandlerCompiler::ComputeLoadNonexistent(
166     Handle<Name> name, Handle<HeapType> type) {
167   Isolate* isolate = name->GetIsolate();
168   Handle<Map> receiver_map = IC::TypeToMap(*type, isolate);
169   if (receiver_map->prototype()->IsNull()) {
170     // TODO(jkummerow/verwaest): If there is no prototype and the property
171     // is nonexistent, introduce a builtin to handle this (fast properties
172     // -> return undefined, dictionary properties -> do negative lookup).
173     return Handle<Code>();
174   }
175   CacheHolderFlag flag;
176   Handle<Map> stub_holder_map =
177       IC::GetHandlerCacheHolder(*type, false, isolate, &flag);
178
179   // If no dictionary mode objects are present in the prototype chain, the load
180   // nonexistent IC stub can be shared for all names for a given map and we use
181   // the empty string for the map cache in that case. If there are dictionary
182   // mode objects involved, we need to do negative lookups in the stub and
183   // therefore the stub will be specific to the name.
184   Handle<Name> cache_name =
185       receiver_map->is_dictionary_map()
186           ? name
187           : Handle<Name>::cast(isolate->factory()->nonexistent_symbol());
188   Handle<Map> current_map = stub_holder_map;
189   Handle<JSObject> last(JSObject::cast(receiver_map->prototype()));
190   while (true) {
191     if (current_map->is_dictionary_map()) cache_name = name;
192     if (current_map->prototype()->IsNull()) break;
193     last = handle(JSObject::cast(current_map->prototype()));
194     current_map = handle(last->map());
195   }
196   // Compile the stub that is either shared for all names or
197   // name specific if there are global objects involved.
198   Handle<Code> handler = PropertyHandlerCompiler::Find(
199       cache_name, stub_holder_map, Code::LOAD_IC, flag, Code::FAST);
200   if (!handler.is_null()) return handler;
201
202   NamedLoadHandlerCompiler compiler(isolate, type, last, flag);
203   handler = compiler.CompileLoadNonexistent(cache_name);
204   Map::UpdateCodeCache(stub_holder_map, cache_name, handler);
205   return handler;
206 }
207
208
209 Handle<Code> PropertyICCompiler::ComputeKeyedLoadMonomorphic(
210     Handle<Map> receiver_map) {
211   Isolate* isolate = receiver_map->GetIsolate();
212   Code::Flags flags = Code::ComputeMonomorphicFlags(Code::KEYED_LOAD_IC);
213   Handle<Name> name = isolate->factory()->KeyedLoadMonomorphic_string();
214
215   Handle<Object> probe(receiver_map->FindInCodeCache(*name, flags), isolate);
216   if (probe->IsCode()) return Handle<Code>::cast(probe);
217
218   ElementsKind elements_kind = receiver_map->elements_kind();
219   Handle<Code> stub;
220   if (receiver_map->has_fast_elements() ||
221       receiver_map->has_external_array_elements() ||
222       receiver_map->has_fixed_typed_array_elements()) {
223     stub = LoadFastElementStub(isolate,
224                                receiver_map->instance_type() == JS_ARRAY_TYPE,
225                                elements_kind).GetCode();
226   } else {
227     stub = FLAG_compiled_keyed_dictionary_loads
228                ? LoadDictionaryElementStub(isolate).GetCode()
229                : LoadDictionaryElementPlatformStub(isolate).GetCode();
230   }
231   PropertyICCompiler compiler(isolate, Code::KEYED_LOAD_IC);
232   Handle<Code> code =
233       compiler.CompileMonomorphic(HeapType::Class(receiver_map, isolate), stub,
234                                   isolate->factory()->empty_string(), ELEMENT);
235
236   Map::UpdateCodeCache(receiver_map, name, code);
237   return code;
238 }
239
240
241 Handle<Code> PropertyICCompiler::ComputeKeyedStoreMonomorphic(
242     Handle<Map> receiver_map, StrictMode strict_mode,
243     KeyedAccessStoreMode store_mode) {
244   Isolate* isolate = receiver_map->GetIsolate();
245   ExtraICState extra_state =
246       KeyedStoreIC::ComputeExtraICState(strict_mode, store_mode);
247   Code::Flags flags =
248       Code::ComputeMonomorphicFlags(Code::KEYED_STORE_IC, extra_state);
249
250   DCHECK(store_mode == STANDARD_STORE ||
251          store_mode == STORE_AND_GROW_NO_TRANSITION ||
252          store_mode == STORE_NO_TRANSITION_IGNORE_OUT_OF_BOUNDS ||
253          store_mode == STORE_NO_TRANSITION_HANDLE_COW);
254
255   Handle<String> name = isolate->factory()->KeyedStoreMonomorphic_string();
256   Handle<Object> probe(receiver_map->FindInCodeCache(*name, flags), isolate);
257   if (probe->IsCode()) return Handle<Code>::cast(probe);
258
259   PropertyICCompiler compiler(isolate, Code::KEYED_STORE_IC, extra_state);
260   Handle<Code> code =
261       compiler.CompileKeyedStoreMonomorphic(receiver_map, store_mode);
262
263   Map::UpdateCodeCache(receiver_map, name, code);
264   DCHECK(KeyedStoreIC::GetKeyedAccessStoreMode(code->extra_ic_state())
265          == store_mode);
266   return code;
267 }
268
269
270 #define CALL_LOGGER_TAG(kind, type) (Logger::KEYED_##type)
271
272 static void FillCache(Isolate* isolate, Handle<Code> code) {
273   Handle<UnseededNumberDictionary> dictionary =
274       UnseededNumberDictionary::Set(isolate->factory()->non_monomorphic_cache(),
275                                     code->flags(),
276                                     code);
277   isolate->heap()->public_set_non_monomorphic_cache(*dictionary);
278 }
279
280
281 Code* PropertyICCompiler::FindPreMonomorphic(Isolate* isolate, Code::Kind kind,
282                                              ExtraICState state) {
283   Code::Flags flags = Code::ComputeFlags(kind, PREMONOMORPHIC, state);
284   UnseededNumberDictionary* dictionary =
285       isolate->heap()->non_monomorphic_cache();
286   int entry = dictionary->FindEntry(isolate, flags);
287   DCHECK(entry != -1);
288   Object* code = dictionary->ValueAt(entry);
289   // This might be called during the marking phase of the collector
290   // hence the unchecked cast.
291   return reinterpret_cast<Code*>(code);
292 }
293
294
295 Handle<Code> PropertyICCompiler::ComputeLoad(Isolate* isolate,
296                                              InlineCacheState ic_state,
297                                              ExtraICState extra_state) {
298   Code::Flags flags = Code::ComputeFlags(Code::LOAD_IC, ic_state, extra_state);
299   Handle<UnseededNumberDictionary> cache =
300       isolate->factory()->non_monomorphic_cache();
301   int entry = cache->FindEntry(isolate, flags);
302   if (entry != -1) return Handle<Code>(Code::cast(cache->ValueAt(entry)));
303
304   PropertyICCompiler compiler(isolate, Code::LOAD_IC);
305   Handle<Code> code;
306   if (ic_state == UNINITIALIZED) {
307     code = compiler.CompileLoadInitialize(flags);
308   } else if (ic_state == PREMONOMORPHIC) {
309     code = compiler.CompileLoadPreMonomorphic(flags);
310   } else if (ic_state == MEGAMORPHIC) {
311     code = compiler.CompileLoadMegamorphic(flags);
312   } else {
313     UNREACHABLE();
314   }
315   FillCache(isolate, code);
316   return code;
317 }
318
319
320 Handle<Code> PropertyICCompiler::ComputeStore(Isolate* isolate,
321                                               InlineCacheState ic_state,
322                                               ExtraICState extra_state) {
323   Code::Flags flags = Code::ComputeFlags(Code::STORE_IC, ic_state, extra_state);
324   Handle<UnseededNumberDictionary> cache =
325       isolate->factory()->non_monomorphic_cache();
326   int entry = cache->FindEntry(isolate, flags);
327   if (entry != -1) return Handle<Code>(Code::cast(cache->ValueAt(entry)));
328
329   PropertyICCompiler compiler(isolate, Code::STORE_IC);
330   Handle<Code> code;
331   if (ic_state == UNINITIALIZED) {
332     code = compiler.CompileStoreInitialize(flags);
333   } else if (ic_state == PREMONOMORPHIC) {
334     code = compiler.CompileStorePreMonomorphic(flags);
335   } else if (ic_state == GENERIC) {
336     code = compiler.CompileStoreGeneric(flags);
337   } else if (ic_state == MEGAMORPHIC) {
338     code = compiler.CompileStoreMegamorphic(flags);
339   } else {
340     UNREACHABLE();
341   }
342
343   FillCache(isolate, code);
344   return code;
345 }
346
347
348 Handle<Code> PropertyICCompiler::ComputeCompareNil(Handle<Map> receiver_map,
349                                                    CompareNilICStub* stub) {
350   Isolate* isolate = receiver_map->GetIsolate();
351   Handle<String> name(isolate->heap()->empty_string());
352   if (!receiver_map->is_dictionary_map()) {
353     Handle<Code> cached_ic =
354         Find(name, receiver_map, Code::COMPARE_NIL_IC, stub->GetExtraICState());
355     if (!cached_ic.is_null()) return cached_ic;
356   }
357
358   Code::FindAndReplacePattern pattern;
359   pattern.Add(isolate->factory()->meta_map(), receiver_map);
360   Handle<Code> ic = stub->GetCodeCopy(pattern);
361
362   if (!receiver_map->is_dictionary_map()) {
363     Map::UpdateCodeCache(receiver_map, name, ic);
364   }
365
366   return ic;
367 }
368
369
370 // TODO(verwaest): Change this method so it takes in a TypeHandleList.
371 Handle<Code> PropertyICCompiler::ComputeKeyedLoadPolymorphic(
372     MapHandleList* receiver_maps) {
373   Isolate* isolate = receiver_maps->at(0)->GetIsolate();
374   Code::Flags flags = Code::ComputeFlags(Code::KEYED_LOAD_IC, POLYMORPHIC);
375   Handle<PolymorphicCodeCache> cache =
376       isolate->factory()->polymorphic_code_cache();
377   Handle<Object> probe = cache->Lookup(receiver_maps, flags);
378   if (probe->IsCode()) return Handle<Code>::cast(probe);
379
380   TypeHandleList types(receiver_maps->length());
381   for (int i = 0; i < receiver_maps->length(); i++) {
382     types.Add(HeapType::Class(receiver_maps->at(i), isolate));
383   }
384   CodeHandleList handlers(receiver_maps->length());
385   ElementHandlerCompiler compiler(isolate);
386   compiler.CompileElementHandlers(receiver_maps, &handlers);
387   PropertyICCompiler ic_compiler(isolate, Code::KEYED_LOAD_IC);
388   Handle<Code> code = ic_compiler.CompilePolymorphic(
389       &types, &handlers, isolate->factory()->empty_string(), Code::NORMAL,
390       ELEMENT);
391
392   isolate->counters()->keyed_load_polymorphic_stubs()->Increment();
393
394   PolymorphicCodeCache::Update(cache, receiver_maps, flags, code);
395   return code;
396 }
397
398
399 Handle<Code> PropertyICCompiler::ComputePolymorphic(
400     Code::Kind kind, TypeHandleList* types, CodeHandleList* handlers,
401     int valid_types, Handle<Name> name, ExtraICState extra_ic_state) {
402   Handle<Code> handler = handlers->at(0);
403   Code::StubType type = valid_types == 1 ? handler->type() : Code::NORMAL;
404   DCHECK(kind == Code::LOAD_IC || kind == Code::STORE_IC);
405   PropertyICCompiler ic_compiler(name->GetIsolate(), kind, extra_ic_state);
406   return ic_compiler.CompilePolymorphic(types, handlers, name, type, PROPERTY);
407 }
408
409
410 Handle<Code> PropertyICCompiler::ComputeKeyedStorePolymorphic(
411     MapHandleList* receiver_maps, KeyedAccessStoreMode store_mode,
412     StrictMode strict_mode) {
413   Isolate* isolate = receiver_maps->at(0)->GetIsolate();
414   DCHECK(store_mode == STANDARD_STORE ||
415          store_mode == STORE_AND_GROW_NO_TRANSITION ||
416          store_mode == STORE_NO_TRANSITION_IGNORE_OUT_OF_BOUNDS ||
417          store_mode == STORE_NO_TRANSITION_HANDLE_COW);
418   Handle<PolymorphicCodeCache> cache =
419       isolate->factory()->polymorphic_code_cache();
420   ExtraICState extra_state = KeyedStoreIC::ComputeExtraICState(
421       strict_mode, store_mode);
422   Code::Flags flags =
423       Code::ComputeFlags(Code::KEYED_STORE_IC, POLYMORPHIC, extra_state);
424   Handle<Object> probe = cache->Lookup(receiver_maps, flags);
425   if (probe->IsCode()) return Handle<Code>::cast(probe);
426
427   PropertyICCompiler compiler(isolate, Code::KEYED_STORE_IC, extra_state);
428   Handle<Code> code =
429       compiler.CompileKeyedStorePolymorphic(receiver_maps, store_mode);
430   PolymorphicCodeCache::Update(cache, receiver_maps, flags, code);
431   return code;
432 }
433
434
435 void StubCache::Clear() {
436   Code* empty = isolate_->builtins()->builtin(Builtins::kIllegal);
437   for (int i = 0; i < kPrimaryTableSize; i++) {
438     primary_[i].key = isolate()->heap()->empty_string();
439     primary_[i].map = NULL;
440     primary_[i].value = empty;
441   }
442   for (int j = 0; j < kSecondaryTableSize; j++) {
443     secondary_[j].key = isolate()->heap()->empty_string();
444     secondary_[j].map = NULL;
445     secondary_[j].value = empty;
446   }
447 }
448
449
450 void StubCache::CollectMatchingMaps(SmallMapList* types,
451                                     Handle<Name> name,
452                                     Code::Flags flags,
453                                     Handle<Context> native_context,
454                                     Zone* zone) {
455   for (int i = 0; i < kPrimaryTableSize; i++) {
456     if (primary_[i].key == *name) {
457       Map* map = primary_[i].map;
458       // Map can be NULL, if the stub is constant function call
459       // with a primitive receiver.
460       if (map == NULL) continue;
461
462       int offset = PrimaryOffset(*name, flags, map);
463       if (entry(primary_, offset) == &primary_[i] &&
464           !TypeFeedbackOracle::CanRetainOtherContext(map, *native_context)) {
465         types->AddMapIfMissing(Handle<Map>(map), zone);
466       }
467     }
468   }
469
470   for (int i = 0; i < kSecondaryTableSize; i++) {
471     if (secondary_[i].key == *name) {
472       Map* map = secondary_[i].map;
473       // Map can be NULL, if the stub is constant function call
474       // with a primitive receiver.
475       if (map == NULL) continue;
476
477       // Lookup in primary table and skip duplicates.
478       int primary_offset = PrimaryOffset(*name, flags, map);
479
480       // Lookup in secondary table and add matches.
481       int offset = SecondaryOffset(*name, flags, primary_offset);
482       if (entry(secondary_, offset) == &secondary_[i] &&
483           !TypeFeedbackOracle::CanRetainOtherContext(map, *native_context)) {
484         types->AddMapIfMissing(Handle<Map>(map), zone);
485       }
486     }
487   }
488 }
489
490
491 // ------------------------------------------------------------------------
492 // StubCompiler implementation.
493
494
495 RUNTIME_FUNCTION(StoreCallbackProperty) {
496   Handle<JSObject> receiver = args.at<JSObject>(0);
497   Handle<JSObject> holder = args.at<JSObject>(1);
498   Handle<ExecutableAccessorInfo> callback = args.at<ExecutableAccessorInfo>(2);
499   Handle<Name> name = args.at<Name>(3);
500   Handle<Object> value = args.at<Object>(4);
501   HandleScope scope(isolate);
502
503   DCHECK(callback->IsCompatibleReceiver(*receiver));
504
505   Address setter_address = v8::ToCData<Address>(callback->setter());
506   v8::AccessorSetterCallback fun =
507       FUNCTION_CAST<v8::AccessorSetterCallback>(setter_address);
508   DCHECK(fun != NULL);
509
510   // TODO(rossberg): Support symbols in the API.
511   if (name->IsSymbol()) return *value;
512   Handle<String> str = Handle<String>::cast(name);
513
514   LOG(isolate, ApiNamedPropertyAccess("store", *receiver, *name));
515   PropertyCallbackArguments custom_args(isolate, callback->data(), *receiver,
516                                         *holder);
517   custom_args.Call(fun, v8::Utils::ToLocal(str), v8::Utils::ToLocal(value));
518   RETURN_FAILURE_IF_SCHEDULED_EXCEPTION(isolate);
519   return *value;
520 }
521
522
523 /**
524  * Attempts to load a property with an interceptor (which must be present),
525  * but doesn't search the prototype chain.
526  *
527  * Returns |Heap::no_interceptor_result_sentinel()| if interceptor doesn't
528  * provide any value for the given name.
529  */
530 RUNTIME_FUNCTION(LoadPropertyWithInterceptorOnly) {
531   DCHECK(args.length() == NamedLoadHandlerCompiler::kInterceptorArgsLength);
532   Handle<Name> name_handle =
533       args.at<Name>(NamedLoadHandlerCompiler::kInterceptorArgsNameIndex);
534   Handle<InterceptorInfo> interceptor_info = args.at<InterceptorInfo>(
535       NamedLoadHandlerCompiler::kInterceptorArgsInfoIndex);
536
537   // TODO(rossberg): Support symbols in the API.
538   if (name_handle->IsSymbol())
539     return isolate->heap()->no_interceptor_result_sentinel();
540   Handle<String> name = Handle<String>::cast(name_handle);
541
542   Address getter_address = v8::ToCData<Address>(interceptor_info->getter());
543   v8::NamedPropertyGetterCallback getter =
544       FUNCTION_CAST<v8::NamedPropertyGetterCallback>(getter_address);
545   DCHECK(getter != NULL);
546
547   Handle<JSObject> receiver =
548       args.at<JSObject>(NamedLoadHandlerCompiler::kInterceptorArgsThisIndex);
549   Handle<JSObject> holder =
550       args.at<JSObject>(NamedLoadHandlerCompiler::kInterceptorArgsHolderIndex);
551   PropertyCallbackArguments callback_args(
552       isolate, interceptor_info->data(), *receiver, *holder);
553   {
554     // Use the interceptor getter.
555     HandleScope scope(isolate);
556     v8::Handle<v8::Value> r =
557         callback_args.Call(getter, v8::Utils::ToLocal(name));
558     RETURN_FAILURE_IF_SCHEDULED_EXCEPTION(isolate);
559     if (!r.IsEmpty()) {
560       Handle<Object> result = v8::Utils::OpenHandle(*r);
561       result->VerifyApiCallResultType();
562       return *v8::Utils::OpenHandle(*r);
563     }
564   }
565
566   return isolate->heap()->no_interceptor_result_sentinel();
567 }
568
569
570 static Object* ThrowReferenceError(Isolate* isolate, Name* name) {
571   // If the load is non-contextual, just return the undefined result.
572   // Note that both keyed and non-keyed loads may end up here.
573   HandleScope scope(isolate);
574   LoadIC ic(IC::NO_EXTRA_FRAME, isolate);
575   if (ic.contextual_mode() != CONTEXTUAL) {
576     return isolate->heap()->undefined_value();
577   }
578
579   // Throw a reference error.
580   Handle<Name> name_handle(name);
581   Handle<Object> error =
582       isolate->factory()->NewReferenceError("not_defined",
583                                             HandleVector(&name_handle, 1));
584   return isolate->Throw(*error);
585 }
586
587
588 /**
589  * Loads a property with an interceptor performing post interceptor
590  * lookup if interceptor failed.
591  */
592 RUNTIME_FUNCTION(LoadPropertyWithInterceptor) {
593   HandleScope scope(isolate);
594   DCHECK(args.length() == NamedLoadHandlerCompiler::kInterceptorArgsLength);
595   Handle<Name> name =
596       args.at<Name>(NamedLoadHandlerCompiler::kInterceptorArgsNameIndex);
597   Handle<JSObject> receiver =
598       args.at<JSObject>(NamedLoadHandlerCompiler::kInterceptorArgsThisIndex);
599   Handle<JSObject> holder =
600       args.at<JSObject>(NamedLoadHandlerCompiler::kInterceptorArgsHolderIndex);
601
602   Handle<Object> result;
603   LookupIterator it(receiver, name, holder);
604   ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
605       isolate, result, JSObject::GetProperty(&it));
606
607   if (it.IsFound()) return *result;
608
609   return ThrowReferenceError(isolate, Name::cast(args[0]));
610 }
611
612
613 RUNTIME_FUNCTION(StorePropertyWithInterceptor) {
614   HandleScope scope(isolate);
615   DCHECK(args.length() == 3);
616   StoreIC ic(IC::NO_EXTRA_FRAME, isolate);
617   Handle<JSObject> receiver = args.at<JSObject>(0);
618   Handle<Name> name = args.at<Name>(1);
619   Handle<Object> value = args.at<Object>(2);
620 #ifdef DEBUG
621   if (receiver->IsJSGlobalProxy()) {
622     PrototypeIterator iter(isolate, receiver);
623     DCHECK(iter.IsAtEnd() ||
624            Handle<JSGlobalObject>::cast(PrototypeIterator::GetCurrent(iter))
625                ->HasNamedInterceptor());
626   } else {
627     DCHECK(receiver->HasNamedInterceptor());
628   }
629 #endif
630   Handle<Object> result;
631   ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
632       isolate, result,
633       JSObject::SetProperty(receiver, name, value, ic.strict_mode()));
634   return *result;
635 }
636
637
638 RUNTIME_FUNCTION(LoadElementWithInterceptor) {
639   HandleScope scope(isolate);
640   Handle<JSObject> receiver = args.at<JSObject>(0);
641   DCHECK(args.smi_at(1) >= 0);
642   uint32_t index = args.smi_at(1);
643   Handle<Object> result;
644   ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
645       isolate, result,
646       JSObject::GetElementWithInterceptor(receiver, receiver, index));
647   return *result;
648 }
649
650
651 Handle<Code> PropertyICCompiler::CompileLoadInitialize(Code::Flags flags) {
652   LoadIC::GenerateInitialize(masm());
653   Handle<Code> code = GetCodeWithFlags(flags, "CompileLoadInitialize");
654   PROFILE(isolate(),
655           CodeCreateEvent(Logger::LOAD_INITIALIZE_TAG, *code, 0));
656   return code;
657 }
658
659
660 Handle<Code> PropertyICCompiler::CompileLoadPreMonomorphic(Code::Flags flags) {
661   LoadIC::GeneratePreMonomorphic(masm());
662   Handle<Code> code = GetCodeWithFlags(flags, "CompileLoadPreMonomorphic");
663   PROFILE(isolate(),
664           CodeCreateEvent(Logger::LOAD_PREMONOMORPHIC_TAG, *code, 0));
665   return code;
666 }
667
668
669 Handle<Code> PropertyICCompiler::CompileLoadMegamorphic(Code::Flags flags) {
670   LoadIC::GenerateMegamorphic(masm());
671   Handle<Code> code = GetCodeWithFlags(flags, "CompileLoadMegamorphic");
672   PROFILE(isolate(),
673           CodeCreateEvent(Logger::LOAD_MEGAMORPHIC_TAG, *code, 0));
674   return code;
675 }
676
677
678 Handle<Code> PropertyICCompiler::CompileStoreInitialize(Code::Flags flags) {
679   StoreIC::GenerateInitialize(masm());
680   Handle<Code> code = GetCodeWithFlags(flags, "CompileStoreInitialize");
681   PROFILE(isolate(),
682           CodeCreateEvent(Logger::STORE_INITIALIZE_TAG, *code, 0));
683   return code;
684 }
685
686
687 Handle<Code> PropertyICCompiler::CompileStorePreMonomorphic(Code::Flags flags) {
688   StoreIC::GeneratePreMonomorphic(masm());
689   Handle<Code> code = GetCodeWithFlags(flags, "CompileStorePreMonomorphic");
690   PROFILE(isolate(),
691           CodeCreateEvent(Logger::STORE_PREMONOMORPHIC_TAG, *code, 0));
692   return code;
693 }
694
695
696 Handle<Code> PropertyICCompiler::CompileStoreGeneric(Code::Flags flags) {
697   ExtraICState extra_state = Code::ExtractExtraICStateFromFlags(flags);
698   StrictMode strict_mode = StoreIC::GetStrictMode(extra_state);
699   StoreIC::GenerateRuntimeSetProperty(masm(), strict_mode);
700   Handle<Code> code = GetCodeWithFlags(flags, "CompileStoreGeneric");
701   PROFILE(isolate(),
702           CodeCreateEvent(Logger::STORE_GENERIC_TAG, *code, 0));
703   return code;
704 }
705
706
707 Handle<Code> PropertyICCompiler::CompileStoreMegamorphic(Code::Flags flags) {
708   StoreIC::GenerateMegamorphic(masm());
709   Handle<Code> code = GetCodeWithFlags(flags, "CompileStoreMegamorphic");
710   PROFILE(isolate(),
711           CodeCreateEvent(Logger::STORE_MEGAMORPHIC_TAG, *code, 0));
712   return code;
713 }
714
715
716 #undef CALL_LOGGER_TAG
717
718
719 Handle<Code> PropertyAccessCompiler::GetCodeWithFlags(Code::Flags flags,
720                                                       const char* name) {
721   // Create code object in the heap.
722   CodeDesc desc;
723   masm()->GetCode(&desc);
724   Handle<Code> code = factory()->NewCode(desc, flags, masm()->CodeObject());
725   if (code->IsCodeStubOrIC()) code->set_stub_key(CodeStub::NoCacheKey());
726 #ifdef ENABLE_DISASSEMBLER
727   if (FLAG_print_code_stubs) {
728     OFStream os(stdout);
729     code->Disassemble(name, os);
730   }
731 #endif
732   return code;
733 }
734
735
736 Handle<Code> PropertyAccessCompiler::GetCodeWithFlags(Code::Flags flags,
737                                                       Handle<Name> name) {
738   return (FLAG_print_code_stubs && !name.is_null() && name->IsString())
739       ? GetCodeWithFlags(flags, Handle<String>::cast(name)->ToCString().get())
740       : GetCodeWithFlags(flags, NULL);
741 }
742
743
744 #define __ ACCESS_MASM(masm())
745
746
747 Register NamedLoadHandlerCompiler::FrontendHeader(Register object_reg,
748                                                   Handle<Name> name,
749                                                   Label* miss) {
750   PrototypeCheckType check_type = CHECK_ALL_MAPS;
751   int function_index = -1;
752   if (type()->Is(HeapType::String())) {
753     function_index = Context::STRING_FUNCTION_INDEX;
754   } else if (type()->Is(HeapType::Symbol())) {
755     function_index = Context::SYMBOL_FUNCTION_INDEX;
756   } else if (type()->Is(HeapType::Number())) {
757     function_index = Context::NUMBER_FUNCTION_INDEX;
758   } else if (type()->Is(HeapType::Boolean())) {
759     function_index = Context::BOOLEAN_FUNCTION_INDEX;
760   } else {
761     check_type = SKIP_RECEIVER;
762   }
763
764   if (check_type == CHECK_ALL_MAPS) {
765     GenerateDirectLoadGlobalFunctionPrototype(
766         masm(), function_index, scratch1(), miss);
767     Object* function = isolate()->native_context()->get(function_index);
768     Object* prototype = JSFunction::cast(function)->instance_prototype();
769     set_type_for_object(handle(prototype, isolate()));
770     object_reg = scratch1();
771   }
772
773   // Check that the maps starting from the prototype haven't changed.
774   return CheckPrototypes(object_reg, scratch1(), scratch2(), scratch3(), name,
775                          miss, check_type);
776 }
777
778
779 // Frontend for store uses the name register. It has to be restored before a
780 // miss.
781 Register NamedStoreHandlerCompiler::FrontendHeader(Register object_reg,
782                                                    Handle<Name> name,
783                                                    Label* miss) {
784   return CheckPrototypes(object_reg, this->name(), scratch1(), scratch2(), name,
785                          miss, SKIP_RECEIVER);
786 }
787
788
789 bool PropertyICCompiler::IncludesNumberType(TypeHandleList* types) {
790   for (int i = 0; i < types->length(); ++i) {
791     if (types->at(i)->Is(HeapType::Number())) return true;
792   }
793   return false;
794 }
795
796
797 Register PropertyHandlerCompiler::Frontend(Register object_reg,
798                                            Handle<Name> name) {
799   Label miss;
800   Register reg = FrontendHeader(object_reg, name, &miss);
801   FrontendFooter(name, &miss);
802   return reg;
803 }
804
805
806 void PropertyHandlerCompiler::NonexistentFrontendHeader(Handle<Name> name,
807                                                         Label* miss,
808                                                         Register scratch1,
809                                                         Register scratch2) {
810   Register holder_reg;
811   Handle<Map> last_map;
812   if (holder().is_null()) {
813     holder_reg = receiver();
814     last_map = IC::TypeToMap(*type(), isolate());
815     // If |type| has null as its prototype, |holder()| is
816     // Handle<JSObject>::null().
817     DCHECK(last_map->prototype() == isolate()->heap()->null_value());
818   } else {
819     holder_reg = FrontendHeader(receiver(), name, miss);
820     last_map = handle(holder()->map());
821   }
822
823   if (last_map->is_dictionary_map()) {
824     if (last_map->IsJSGlobalObjectMap()) {
825       Handle<JSGlobalObject> global =
826           holder().is_null()
827               ? Handle<JSGlobalObject>::cast(type()->AsConstant()->Value())
828               : Handle<JSGlobalObject>::cast(holder());
829       GenerateCheckPropertyCell(masm(), global, name, scratch1, miss);
830     } else {
831       if (!name->IsUniqueName()) {
832         DCHECK(name->IsString());
833         name = factory()->InternalizeString(Handle<String>::cast(name));
834       }
835       DCHECK(holder().is_null() ||
836              holder()->property_dictionary()->FindEntry(name) ==
837                  NameDictionary::kNotFound);
838       GenerateDictionaryNegativeLookup(masm(), miss, holder_reg, name, scratch1,
839                                        scratch2);
840     }
841   }
842 }
843
844
845 Handle<Code> NamedLoadHandlerCompiler::CompileLoadField(Handle<Name> name,
846                                                         FieldIndex field) {
847   Register reg = Frontend(receiver(), name);
848   __ Move(receiver(), reg);
849   LoadFieldStub stub(isolate(), field);
850   GenerateTailCall(masm(), stub.GetCode());
851   return GetCode(kind(), Code::FAST, name);
852 }
853
854
855 Handle<Code> NamedLoadHandlerCompiler::CompileLoadConstant(Handle<Name> name,
856                                                            int constant_index) {
857   Register reg = Frontend(receiver(), name);
858   __ Move(receiver(), reg);
859   LoadConstantStub stub(isolate(), constant_index);
860   GenerateTailCall(masm(), stub.GetCode());
861   return GetCode(kind(), Code::FAST, name);
862 }
863
864
865 Handle<Code> NamedLoadHandlerCompiler::CompileLoadNonexistent(
866     Handle<Name> name) {
867   Label miss;
868   NonexistentFrontendHeader(name, &miss, scratch2(), scratch3());
869   GenerateLoadConstant(isolate()->factory()->undefined_value());
870   FrontendFooter(name, &miss);
871   return GetCode(kind(), Code::FAST, name);
872 }
873
874
875 Handle<Code> NamedLoadHandlerCompiler::CompileLoadCallback(
876     Handle<Name> name, Handle<ExecutableAccessorInfo> callback) {
877   Register reg = Frontend(receiver(), name);
878   GenerateLoadCallback(reg, callback);
879   return GetCode(kind(), Code::FAST, name);
880 }
881
882
883 Handle<Code> NamedLoadHandlerCompiler::CompileLoadCallback(
884     Handle<Name> name, const CallOptimization& call_optimization) {
885   DCHECK(call_optimization.is_simple_api_call());
886   Frontend(receiver(), name);
887   Handle<Map> receiver_map = IC::TypeToMap(*type(), isolate());
888   GenerateFastApiCall(
889       masm(), call_optimization, receiver_map,
890       receiver(), scratch1(), false, 0, NULL);
891   return GetCode(kind(), Code::FAST, name);
892 }
893
894
895 Handle<Code> NamedLoadHandlerCompiler::CompileLoadInterceptor(
896     Handle<Name> name) {
897   // Perform a lookup after the interceptor.
898   LookupResult lookup(isolate());
899   holder()->LookupOwnRealNamedProperty(name, &lookup);
900   if (!lookup.IsFound()) {
901     PrototypeIterator iter(holder()->GetIsolate(), holder());
902     if (!iter.IsAtEnd()) {
903       PrototypeIterator::GetCurrent(iter)->Lookup(name, &lookup);
904     }
905   }
906
907   Register reg = Frontend(receiver(), name);
908   // TODO(368): Compile in the whole chain: all the interceptors in
909   // prototypes and ultimate answer.
910   GenerateLoadInterceptor(reg, &lookup, name);
911   return GetCode(kind(), Code::FAST, name);
912 }
913
914
915 void NamedLoadHandlerCompiler::GenerateLoadPostInterceptor(
916     Register interceptor_reg, Handle<Name> name, LookupResult* lookup) {
917   Handle<JSObject> real_named_property_holder(lookup->holder());
918
919   set_type_for_object(holder());
920   set_holder(real_named_property_holder);
921   Register reg = Frontend(interceptor_reg, name);
922
923   if (lookup->IsField()) {
924     __ Move(receiver(), reg);
925     LoadFieldStub stub(isolate(), lookup->GetFieldIndex());
926     GenerateTailCall(masm(), stub.GetCode());
927   } else {
928     DCHECK(lookup->type() == CALLBACKS);
929     Handle<ExecutableAccessorInfo> callback(
930         ExecutableAccessorInfo::cast(lookup->GetCallbackObject()));
931     DCHECK(callback->getter() != NULL);
932     GenerateLoadCallback(reg, callback);
933   }
934 }
935
936
937 Handle<Code> PropertyICCompiler::CompileMonomorphic(Handle<HeapType> type,
938                                                     Handle<Code> handler,
939                                                     Handle<Name> name,
940                                                     IcCheckType check) {
941   TypeHandleList types(1);
942   CodeHandleList handlers(1);
943   types.Add(type);
944   handlers.Add(handler);
945   Code::StubType stub_type = handler->type();
946   return CompilePolymorphic(&types, &handlers, name, stub_type, check);
947 }
948
949
950 Handle<Code> NamedLoadHandlerCompiler::CompileLoadViaGetter(
951     Handle<Name> name, Handle<JSFunction> getter) {
952   Frontend(receiver(), name);
953   GenerateLoadViaGetter(masm(), type(), receiver(), getter);
954   return GetCode(kind(), Code::FAST, name);
955 }
956
957
958 // TODO(verwaest): Cleanup. holder() is actually the receiver.
959 Handle<Code> NamedStoreHandlerCompiler::CompileStoreTransition(
960     Handle<Map> transition, Handle<Name> name) {
961   Label miss, slow;
962
963   // Ensure no transitions to deprecated maps are followed.
964   __ CheckMapDeprecated(transition, scratch1(), &miss);
965
966   // Check that we are allowed to write this.
967   bool is_nonexistent = holder()->map() == transition->GetBackPointer();
968   if (is_nonexistent) {
969     // Find the top object.
970     Handle<JSObject> last;
971     PrototypeIterator iter(isolate(), holder());
972     while (!iter.IsAtEnd()) {
973       last = Handle<JSObject>::cast(PrototypeIterator::GetCurrent(iter));
974       iter.Advance();
975     }
976     if (!last.is_null()) set_holder(last);
977     NonexistentFrontendHeader(name, &miss, scratch1(), scratch2());
978   } else {
979     FrontendHeader(receiver(), name, &miss);
980     DCHECK(holder()->HasFastProperties());
981   }
982
983   GenerateStoreTransition(transition, name, receiver(), this->name(), value(),
984                           scratch1(), scratch2(), scratch3(), &miss, &slow);
985
986   GenerateRestoreName(&miss, name);
987   TailCallBuiltin(masm(), MissBuiltin(kind()));
988
989   GenerateRestoreName(&slow, name);
990   TailCallBuiltin(masm(), SlowBuiltin(kind()));
991   return GetCode(kind(), Code::FAST, name);
992 }
993
994
995 Handle<Code> NamedStoreHandlerCompiler::CompileStoreField(LookupResult* lookup,
996                                                           Handle<Name> name) {
997   Label miss;
998   GenerateStoreField(lookup, value(), &miss);
999   __ bind(&miss);
1000   TailCallBuiltin(masm(), MissBuiltin(kind()));
1001   return GetCode(kind(), Code::FAST, name);
1002 }
1003
1004
1005 Handle<Code> NamedStoreHandlerCompiler::CompileStoreViaSetter(
1006     Handle<JSObject> object, Handle<Name> name, Handle<JSFunction> setter) {
1007   Frontend(receiver(), name);
1008   GenerateStoreViaSetter(masm(), type(), receiver(), setter);
1009
1010   return GetCode(kind(), Code::FAST, name);
1011 }
1012
1013
1014 Handle<Code> NamedStoreHandlerCompiler::CompileStoreCallback(
1015     Handle<JSObject> object, Handle<Name> name,
1016     const CallOptimization& call_optimization) {
1017   Frontend(receiver(), name);
1018   Register values[] = { value() };
1019   GenerateFastApiCall(
1020       masm(), call_optimization, handle(object->map()),
1021       receiver(), scratch1(), true, 1, values);
1022   return GetCode(kind(), Code::FAST, name);
1023 }
1024
1025
1026 Handle<Code> PropertyICCompiler::CompileKeyedStoreMonomorphic(
1027     Handle<Map> receiver_map, KeyedAccessStoreMode store_mode) {
1028   ElementsKind elements_kind = receiver_map->elements_kind();
1029   bool is_jsarray = receiver_map->instance_type() == JS_ARRAY_TYPE;
1030   Handle<Code> stub;
1031   if (receiver_map->has_fast_elements() ||
1032       receiver_map->has_external_array_elements() ||
1033       receiver_map->has_fixed_typed_array_elements()) {
1034     stub = StoreFastElementStub(isolate(), is_jsarray, elements_kind,
1035                                 store_mode).GetCode();
1036   } else {
1037     stub = StoreElementStub(isolate(), is_jsarray, elements_kind, store_mode)
1038                .GetCode();
1039   }
1040
1041   __ DispatchMap(receiver(), scratch1(), receiver_map, stub, DO_SMI_CHECK);
1042
1043   TailCallBuiltin(masm(), Builtins::kKeyedStoreIC_Miss);
1044
1045   return GetCode(kind(), Code::NORMAL, factory()->empty_string());
1046 }
1047
1048
1049 #undef __
1050
1051
1052 void PropertyAccessCompiler::TailCallBuiltin(MacroAssembler* masm,
1053                                              Builtins::Name name) {
1054   Handle<Code> code(masm->isolate()->builtins()->builtin(name));
1055   GenerateTailCall(masm, code);
1056 }
1057
1058
1059 Register* PropertyAccessCompiler::GetCallingConvention(Code::Kind kind) {
1060   if (kind == Code::LOAD_IC || kind == Code::KEYED_LOAD_IC) {
1061     return load_calling_convention();
1062   }
1063   DCHECK(kind == Code::STORE_IC || kind == Code::KEYED_STORE_IC);
1064   return store_calling_convention();
1065 }
1066
1067
1068 Handle<Code> PropertyICCompiler::GetCode(Code::Kind kind, Code::StubType type,
1069                                          Handle<Name> name,
1070                                          InlineCacheState state) {
1071   Code::Flags flags =
1072       Code::ComputeFlags(kind, state, extra_ic_state_, type, cache_holder());
1073   Handle<Code> code = GetCodeWithFlags(flags, name);
1074   IC::RegisterWeakMapDependency(code);
1075   PROFILE(isolate(), CodeCreateEvent(log_kind(code), *code, *name));
1076   return code;
1077 }
1078
1079
1080 Handle<Code> PropertyHandlerCompiler::GetCode(Code::Kind kind,
1081                                               Code::StubType type,
1082                                               Handle<Name> name) {
1083   Code::Flags flags = Code::ComputeHandlerFlags(kind, type, cache_holder());
1084   Handle<Code> code = GetCodeWithFlags(flags, name);
1085   PROFILE(isolate(), CodeCreateEvent(Logger::STUB_TAG, *code, *name));
1086   return code;
1087 }
1088
1089
1090 void ElementHandlerCompiler::CompileElementHandlers(
1091     MapHandleList* receiver_maps, CodeHandleList* handlers) {
1092   for (int i = 0; i < receiver_maps->length(); ++i) {
1093     Handle<Map> receiver_map = receiver_maps->at(i);
1094     Handle<Code> cached_stub;
1095
1096     if ((receiver_map->instance_type() & kNotStringTag) == 0) {
1097       cached_stub = isolate()->builtins()->KeyedLoadIC_String();
1098     } else if (receiver_map->instance_type() < FIRST_JS_RECEIVER_TYPE) {
1099       cached_stub = isolate()->builtins()->KeyedLoadIC_Slow();
1100     } else {
1101       bool is_js_array = receiver_map->instance_type() == JS_ARRAY_TYPE;
1102       ElementsKind elements_kind = receiver_map->elements_kind();
1103
1104       if (IsFastElementsKind(elements_kind) ||
1105           IsExternalArrayElementsKind(elements_kind) ||
1106           IsFixedTypedArrayElementsKind(elements_kind)) {
1107         cached_stub = LoadFastElementStub(isolate(), is_js_array, elements_kind)
1108                           .GetCode();
1109       } else if (elements_kind == SLOPPY_ARGUMENTS_ELEMENTS) {
1110         cached_stub = isolate()->builtins()->KeyedLoadIC_SloppyArguments();
1111       } else {
1112         DCHECK(elements_kind == DICTIONARY_ELEMENTS);
1113         cached_stub = LoadDictionaryElementStub(isolate()).GetCode();
1114       }
1115     }
1116
1117     handlers->Add(cached_stub);
1118   }
1119 }
1120
1121
1122 Handle<Code> PropertyICCompiler::CompileKeyedStorePolymorphic(
1123     MapHandleList* receiver_maps, KeyedAccessStoreMode store_mode) {
1124   // Collect MONOMORPHIC stubs for all |receiver_maps|.
1125   CodeHandleList handlers(receiver_maps->length());
1126   MapHandleList transitioned_maps(receiver_maps->length());
1127   for (int i = 0; i < receiver_maps->length(); ++i) {
1128     Handle<Map> receiver_map(receiver_maps->at(i));
1129     Handle<Code> cached_stub;
1130     Handle<Map> transitioned_map =
1131         receiver_map->FindTransitionedMap(receiver_maps);
1132
1133     // TODO(mvstanton): The code below is doing pessimistic elements
1134     // transitions. I would like to stop doing that and rely on Allocation Site
1135     // Tracking to do a better job of ensuring the data types are what they need
1136     // to be. Not all the elements are in place yet, pessimistic elements
1137     // transitions are still important for performance.
1138     bool is_js_array = receiver_map->instance_type() == JS_ARRAY_TYPE;
1139     ElementsKind elements_kind = receiver_map->elements_kind();
1140     if (!transitioned_map.is_null()) {
1141       cached_stub =
1142           ElementsTransitionAndStoreStub(isolate(), elements_kind,
1143                                          transitioned_map->elements_kind(),
1144                                          is_js_array, store_mode).GetCode();
1145     } else if (receiver_map->instance_type() < FIRST_JS_RECEIVER_TYPE) {
1146       cached_stub = isolate()->builtins()->KeyedStoreIC_Slow();
1147     } else {
1148       if (receiver_map->has_fast_elements() ||
1149           receiver_map->has_external_array_elements() ||
1150           receiver_map->has_fixed_typed_array_elements()) {
1151         cached_stub = StoreFastElementStub(isolate(), is_js_array,
1152                                            elements_kind, store_mode).GetCode();
1153       } else {
1154         cached_stub = StoreElementStub(isolate(), is_js_array, elements_kind,
1155                                        store_mode).GetCode();
1156       }
1157     }
1158     DCHECK(!cached_stub.is_null());
1159     handlers.Add(cached_stub);
1160     transitioned_maps.Add(transitioned_map);
1161   }
1162
1163   Handle<Code> code = CompileKeyedStorePolymorphic(receiver_maps, &handlers,
1164                                                    &transitioned_maps);
1165   isolate()->counters()->keyed_store_polymorphic_stubs()->Increment();
1166   PROFILE(isolate(), CodeCreateEvent(log_kind(code), *code, 0));
1167   return code;
1168 }
1169
1170
1171 void ElementHandlerCompiler::GenerateStoreDictionaryElement(
1172     MacroAssembler* masm) {
1173   KeyedStoreIC::GenerateSlow(masm);
1174 }
1175
1176
1177 CallOptimization::CallOptimization(LookupResult* lookup) {
1178   if (lookup->IsFound() &&
1179       lookup->IsCacheable() &&
1180       lookup->IsConstantFunction()) {
1181     // We only optimize constant function calls.
1182     Initialize(Handle<JSFunction>(lookup->GetConstantFunction()));
1183   } else {
1184     Initialize(Handle<JSFunction>::null());
1185   }
1186 }
1187
1188
1189 CallOptimization::CallOptimization(Handle<JSFunction> function) {
1190   Initialize(function);
1191 }
1192
1193
1194 Handle<JSObject> CallOptimization::LookupHolderOfExpectedType(
1195     Handle<Map> object_map,
1196     HolderLookup* holder_lookup) const {
1197   DCHECK(is_simple_api_call());
1198   if (!object_map->IsJSObjectMap()) {
1199     *holder_lookup = kHolderNotFound;
1200     return Handle<JSObject>::null();
1201   }
1202   if (expected_receiver_type_.is_null() ||
1203       expected_receiver_type_->IsTemplateFor(*object_map)) {
1204     *holder_lookup = kHolderIsReceiver;
1205     return Handle<JSObject>::null();
1206   }
1207   while (true) {
1208     if (!object_map->prototype()->IsJSObject()) break;
1209     Handle<JSObject> prototype(JSObject::cast(object_map->prototype()));
1210     if (!prototype->map()->is_hidden_prototype()) break;
1211     object_map = handle(prototype->map());
1212     if (expected_receiver_type_->IsTemplateFor(*object_map)) {
1213       *holder_lookup = kHolderFound;
1214       return prototype;
1215     }
1216   }
1217   *holder_lookup = kHolderNotFound;
1218   return Handle<JSObject>::null();
1219 }
1220
1221
1222 bool CallOptimization::IsCompatibleReceiver(Handle<Object> receiver,
1223                                             Handle<JSObject> holder) const {
1224   DCHECK(is_simple_api_call());
1225   if (!receiver->IsJSObject()) return false;
1226   Handle<Map> map(JSObject::cast(*receiver)->map());
1227   HolderLookup holder_lookup;
1228   Handle<JSObject> api_holder =
1229       LookupHolderOfExpectedType(map, &holder_lookup);
1230   switch (holder_lookup) {
1231     case kHolderNotFound:
1232       return false;
1233     case kHolderIsReceiver:
1234       return true;
1235     case kHolderFound:
1236       if (api_holder.is_identical_to(holder)) return true;
1237       // Check if holder is in prototype chain of api_holder.
1238       {
1239         JSObject* object = *api_holder;
1240         while (true) {
1241           Object* prototype = object->map()->prototype();
1242           if (!prototype->IsJSObject()) return false;
1243           if (prototype == *holder) return true;
1244           object = JSObject::cast(prototype);
1245         }
1246       }
1247       break;
1248   }
1249   UNREACHABLE();
1250   return false;
1251 }
1252
1253
1254 void CallOptimization::Initialize(Handle<JSFunction> function) {
1255   constant_function_ = Handle<JSFunction>::null();
1256   is_simple_api_call_ = false;
1257   expected_receiver_type_ = Handle<FunctionTemplateInfo>::null();
1258   api_call_info_ = Handle<CallHandlerInfo>::null();
1259
1260   if (function.is_null() || !function->is_compiled()) return;
1261
1262   constant_function_ = function;
1263   AnalyzePossibleApiFunction(function);
1264 }
1265
1266
1267 void CallOptimization::AnalyzePossibleApiFunction(Handle<JSFunction> function) {
1268   if (!function->shared()->IsApiFunction()) return;
1269   Handle<FunctionTemplateInfo> info(function->shared()->get_api_func_data());
1270
1271   // Require a C++ callback.
1272   if (info->call_code()->IsUndefined()) return;
1273   api_call_info_ =
1274       Handle<CallHandlerInfo>(CallHandlerInfo::cast(info->call_code()));
1275
1276   // Accept signatures that either have no restrictions at all or
1277   // only have restrictions on the receiver.
1278   if (!info->signature()->IsUndefined()) {
1279     Handle<SignatureInfo> signature =
1280         Handle<SignatureInfo>(SignatureInfo::cast(info->signature()));
1281     if (!signature->args()->IsUndefined()) return;
1282     if (!signature->receiver()->IsUndefined()) {
1283       expected_receiver_type_ =
1284           Handle<FunctionTemplateInfo>(
1285               FunctionTemplateInfo::cast(signature->receiver()));
1286     }
1287   }
1288
1289   is_simple_api_call_ = true;
1290 }
1291
1292
1293 } }  // namespace v8::internal