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