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