• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2012 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "src/v8.h"
6 
7 #include "src/api.h"
8 #include "src/arguments.h"
9 #include "src/ast.h"
10 #include "src/code-stubs.h"
11 #include "src/cpu-profiler.h"
12 #include "src/gdb-jit.h"
13 #include "src/ic-inl.h"
14 #include "src/stub-cache.h"
15 #include "src/type-info.h"
16 #include "src/vm-state-inl.h"
17 
18 namespace v8 {
19 namespace internal {
20 
21 // -----------------------------------------------------------------------
22 // StubCache implementation.
23 
24 
StubCache(Isolate * isolate)25 StubCache::StubCache(Isolate* isolate)
26     : isolate_(isolate) { }
27 
28 
Initialize()29 void StubCache::Initialize() {
30   ASSERT(IsPowerOf2(kPrimaryTableSize));
31   ASSERT(IsPowerOf2(kSecondaryTableSize));
32   Clear();
33 }
34 
35 
Set(Name * name,Map * map,Code * code)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 
FindIC(Handle<Name> name,Handle<Map> stub_holder,Code::Kind kind,ExtraICState extra_state,InlineCacheHolderFlag cache_holder)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 
FindHandler(Handle<Name> name,Handle<Map> stub_holder,Code::Kind kind,InlineCacheHolderFlag cache_holder,Code::StubType type)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 
ComputeMonomorphicIC(Code::Kind kind,Handle<Name> name,Handle<HeapType> type,Handle<Code> handler,ExtraICState extra_ic_state)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 
ComputeLoadNonexistent(Handle<Name> name,Handle<HeapType> type)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 
ComputeKeyedLoadElement(Handle<Map> receiver_map)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 
ComputeKeyedStoreElement(Handle<Map> receiver_map,StrictMode strict_mode,KeyedAccessStoreMode store_mode)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 
FillCache(Isolate * isolate,Handle<Code> code)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 
FindPreMonomorphicIC(Code::Kind kind,ExtraICState state)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 
ComputeLoad(InlineCacheState ic_state,ExtraICState extra_state)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 
ComputeStore(InlineCacheState ic_state,ExtraICState extra_state)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 
ComputeCompareNil(Handle<Map> receiver_map,CompareNilICStub * stub)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.
ComputeLoadElementPolymorphic(MapHandleList * receiver_maps)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 
ComputePolymorphicIC(Code::Kind kind,TypeHandleList * types,CodeHandleList * handlers,int number_of_valid_types,Handle<Name> name,ExtraICState extra_ic_state)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 
ComputeStoreElementPolymorphic(MapHandleList * receiver_maps,KeyedAccessStoreMode store_mode,StrictMode strict_mode)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 
Clear()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 
CollectMatchingMaps(SmallMapList * types,Handle<Name> name,Code::Flags flags,Handle<Context> native_context,Zone * zone)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 
RUNTIME_FUNCTION(StoreCallbackProperty)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  */
RUNTIME_FUNCTION(LoadPropertyWithInterceptorOnly)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 
ThrowReferenceError(Isolate * isolate,Name * name)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 /**
550  * Loads a property with an interceptor performing post interceptor
551  * lookup if interceptor failed.
552  */
RUNTIME_FUNCTION(LoadPropertyWithInterceptor)553 RUNTIME_FUNCTION(LoadPropertyWithInterceptor) {
554   HandleScope scope(isolate);
555   ASSERT(args.length() == StubCache::kInterceptorArgsLength);
556   Handle<Name> name =
557       args.at<Name>(StubCache::kInterceptorArgsNameIndex);
558   Handle<JSObject> receiver =
559       args.at<JSObject>(StubCache::kInterceptorArgsThisIndex);
560   Handle<JSObject> holder =
561       args.at<JSObject>(StubCache::kInterceptorArgsHolderIndex);
562 
563   Handle<Object> result;
564   LookupIterator it(receiver, name, holder);
565   ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
566       isolate, result, JSObject::GetProperty(&it));
567 
568   if (it.IsFound()) return *result;
569 
570   return ThrowReferenceError(isolate, Name::cast(args[0]));
571 }
572 
573 
RUNTIME_FUNCTION(StoreInterceptorProperty)574 RUNTIME_FUNCTION(StoreInterceptorProperty) {
575   HandleScope scope(isolate);
576   ASSERT(args.length() == 3);
577   StoreIC ic(IC::NO_EXTRA_FRAME, isolate);
578   Handle<JSObject> receiver = args.at<JSObject>(0);
579   Handle<Name> name = args.at<Name>(1);
580   Handle<Object> value = args.at<Object>(2);
581   ASSERT(receiver->HasNamedInterceptor());
582   PropertyAttributes attr = NONE;
583   Handle<Object> result;
584   ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
585       isolate, result,
586       JSObject::SetPropertyWithInterceptor(
587           receiver, name, value, attr, ic.strict_mode()));
588   return *result;
589 }
590 
591 
RUNTIME_FUNCTION(KeyedLoadPropertyWithInterceptor)592 RUNTIME_FUNCTION(KeyedLoadPropertyWithInterceptor) {
593   HandleScope scope(isolate);
594   Handle<JSObject> receiver = args.at<JSObject>(0);
595   ASSERT(args.smi_at(1) >= 0);
596   uint32_t index = args.smi_at(1);
597   Handle<Object> result;
598   ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
599       isolate, result,
600       JSObject::GetElementWithInterceptor(receiver, receiver, index));
601   return *result;
602 }
603 
604 
CompileLoadInitialize(Code::Flags flags)605 Handle<Code> StubCompiler::CompileLoadInitialize(Code::Flags flags) {
606   LoadIC::GenerateInitialize(masm());
607   Handle<Code> code = GetCodeWithFlags(flags, "CompileLoadInitialize");
608   PROFILE(isolate(),
609           CodeCreateEvent(Logger::LOAD_INITIALIZE_TAG, *code, 0));
610   GDBJIT(AddCode(GDBJITInterface::LOAD_IC, *code));
611   return code;
612 }
613 
614 
CompileLoadPreMonomorphic(Code::Flags flags)615 Handle<Code> StubCompiler::CompileLoadPreMonomorphic(Code::Flags flags) {
616   LoadIC::GeneratePreMonomorphic(masm());
617   Handle<Code> code = GetCodeWithFlags(flags, "CompileLoadPreMonomorphic");
618   PROFILE(isolate(),
619           CodeCreateEvent(Logger::LOAD_PREMONOMORPHIC_TAG, *code, 0));
620   GDBJIT(AddCode(GDBJITInterface::LOAD_IC, *code));
621   return code;
622 }
623 
624 
CompileLoadMegamorphic(Code::Flags flags)625 Handle<Code> StubCompiler::CompileLoadMegamorphic(Code::Flags flags) {
626   LoadIC::GenerateMegamorphic(masm());
627   Handle<Code> code = GetCodeWithFlags(flags, "CompileLoadMegamorphic");
628   PROFILE(isolate(),
629           CodeCreateEvent(Logger::LOAD_MEGAMORPHIC_TAG, *code, 0));
630   GDBJIT(AddCode(GDBJITInterface::LOAD_IC, *code));
631   return code;
632 }
633 
634 
CompileStoreInitialize(Code::Flags flags)635 Handle<Code> StubCompiler::CompileStoreInitialize(Code::Flags flags) {
636   StoreIC::GenerateInitialize(masm());
637   Handle<Code> code = GetCodeWithFlags(flags, "CompileStoreInitialize");
638   PROFILE(isolate(),
639           CodeCreateEvent(Logger::STORE_INITIALIZE_TAG, *code, 0));
640   GDBJIT(AddCode(GDBJITInterface::STORE_IC, *code));
641   return code;
642 }
643 
644 
CompileStorePreMonomorphic(Code::Flags flags)645 Handle<Code> StubCompiler::CompileStorePreMonomorphic(Code::Flags flags) {
646   StoreIC::GeneratePreMonomorphic(masm());
647   Handle<Code> code = GetCodeWithFlags(flags, "CompileStorePreMonomorphic");
648   PROFILE(isolate(),
649           CodeCreateEvent(Logger::STORE_PREMONOMORPHIC_TAG, *code, 0));
650   GDBJIT(AddCode(GDBJITInterface::STORE_IC, *code));
651   return code;
652 }
653 
654 
CompileStoreGeneric(Code::Flags flags)655 Handle<Code> StubCompiler::CompileStoreGeneric(Code::Flags flags) {
656   ExtraICState extra_state = Code::ExtractExtraICStateFromFlags(flags);
657   StrictMode strict_mode = StoreIC::GetStrictMode(extra_state);
658   StoreIC::GenerateRuntimeSetProperty(masm(), strict_mode);
659   Handle<Code> code = GetCodeWithFlags(flags, "CompileStoreGeneric");
660   PROFILE(isolate(),
661           CodeCreateEvent(Logger::STORE_GENERIC_TAG, *code, 0));
662   GDBJIT(AddCode(GDBJITInterface::STORE_IC, *code));
663   return code;
664 }
665 
666 
CompileStoreMegamorphic(Code::Flags flags)667 Handle<Code> StubCompiler::CompileStoreMegamorphic(Code::Flags flags) {
668   StoreIC::GenerateMegamorphic(masm());
669   Handle<Code> code = GetCodeWithFlags(flags, "CompileStoreMegamorphic");
670   PROFILE(isolate(),
671           CodeCreateEvent(Logger::STORE_MEGAMORPHIC_TAG, *code, 0));
672   GDBJIT(AddCode(GDBJITInterface::STORE_IC, *code));
673   return code;
674 }
675 
676 
677 #undef CALL_LOGGER_TAG
678 
679 
GetCodeWithFlags(Code::Flags flags,const char * name)680 Handle<Code> StubCompiler::GetCodeWithFlags(Code::Flags flags,
681                                             const char* name) {
682   // Create code object in the heap.
683   CodeDesc desc;
684   masm_.GetCode(&desc);
685   Handle<Code> code = factory()->NewCode(desc, flags, masm_.CodeObject());
686   if (code->has_major_key()) {
687     code->set_major_key(CodeStub::NoCache);
688   }
689 #ifdef ENABLE_DISASSEMBLER
690   if (FLAG_print_code_stubs) code->Disassemble(name);
691 #endif
692   return code;
693 }
694 
695 
GetCodeWithFlags(Code::Flags flags,Handle<Name> name)696 Handle<Code> StubCompiler::GetCodeWithFlags(Code::Flags flags,
697                                             Handle<Name> name) {
698   return (FLAG_print_code_stubs && !name.is_null() && name->IsString())
699       ? GetCodeWithFlags(flags, Handle<String>::cast(name)->ToCString().get())
700       : GetCodeWithFlags(flags, NULL);
701 }
702 
703 
LookupPostInterceptor(Handle<JSObject> holder,Handle<Name> name,LookupResult * lookup)704 void StubCompiler::LookupPostInterceptor(Handle<JSObject> holder,
705                                          Handle<Name> name,
706                                          LookupResult* lookup) {
707   holder->LookupOwnRealNamedProperty(name, lookup);
708   if (lookup->IsFound()) return;
709   if (holder->GetPrototype()->IsNull()) return;
710   holder->GetPrototype()->Lookup(name, lookup);
711 }
712 
713 
714 #define __ ACCESS_MASM(masm())
715 
716 
HandlerFrontendHeader(Handle<HeapType> type,Register object_reg,Handle<JSObject> holder,Handle<Name> name,Label * miss)717 Register LoadStubCompiler::HandlerFrontendHeader(
718     Handle<HeapType> type,
719     Register object_reg,
720     Handle<JSObject> holder,
721     Handle<Name> name,
722     Label* miss) {
723   PrototypeCheckType check_type = CHECK_ALL_MAPS;
724   int function_index = -1;
725   if (type->Is(HeapType::String())) {
726     function_index = Context::STRING_FUNCTION_INDEX;
727   } else if (type->Is(HeapType::Symbol())) {
728     function_index = Context::SYMBOL_FUNCTION_INDEX;
729   } else if (type->Is(HeapType::Number())) {
730     function_index = Context::NUMBER_FUNCTION_INDEX;
731   } else if (type->Is(HeapType::Boolean())) {
732     function_index = Context::BOOLEAN_FUNCTION_INDEX;
733   } else {
734     check_type = SKIP_RECEIVER;
735   }
736 
737   if (check_type == CHECK_ALL_MAPS) {
738     GenerateDirectLoadGlobalFunctionPrototype(
739         masm(), function_index, scratch1(), miss);
740     Object* function = isolate()->native_context()->get(function_index);
741     Object* prototype = JSFunction::cast(function)->instance_prototype();
742     type = IC::CurrentTypeOf(handle(prototype, isolate()), isolate());
743     object_reg = scratch1();
744   }
745 
746   // Check that the maps starting from the prototype haven't changed.
747   return CheckPrototypes(
748       type, object_reg, holder, scratch1(), scratch2(), scratch3(),
749       name, miss, check_type);
750 }
751 
752 
753 // HandlerFrontend for store uses the name register. It has to be restored
754 // before a miss.
HandlerFrontendHeader(Handle<HeapType> type,Register object_reg,Handle<JSObject> holder,Handle<Name> name,Label * miss)755 Register StoreStubCompiler::HandlerFrontendHeader(
756     Handle<HeapType> type,
757     Register object_reg,
758     Handle<JSObject> holder,
759     Handle<Name> name,
760     Label* miss) {
761   return CheckPrototypes(type, object_reg, holder, this->name(),
762                          scratch1(), scratch2(), name, miss, SKIP_RECEIVER);
763 }
764 
765 
IncludesNumberType(TypeHandleList * types)766 bool BaseLoadStoreStubCompiler::IncludesNumberType(TypeHandleList* types) {
767   for (int i = 0; i < types->length(); ++i) {
768     if (types->at(i)->Is(HeapType::Number())) return true;
769   }
770   return false;
771 }
772 
773 
HandlerFrontend(Handle<HeapType> type,Register object_reg,Handle<JSObject> holder,Handle<Name> name)774 Register BaseLoadStoreStubCompiler::HandlerFrontend(Handle<HeapType> type,
775                                                     Register object_reg,
776                                                     Handle<JSObject> holder,
777                                                     Handle<Name> name) {
778   Label miss;
779 
780   Register reg = HandlerFrontendHeader(type, object_reg, holder, name, &miss);
781 
782   HandlerFrontendFooter(name, &miss);
783 
784   return reg;
785 }
786 
787 
NonexistentHandlerFrontend(Handle<HeapType> type,Handle<JSObject> last,Handle<Name> name)788 void LoadStubCompiler::NonexistentHandlerFrontend(Handle<HeapType> type,
789                                                   Handle<JSObject> last,
790                                                   Handle<Name> name) {
791   Label miss;
792 
793   Register holder;
794   Handle<Map> last_map;
795   if (last.is_null()) {
796     holder = receiver();
797     last_map = IC::TypeToMap(*type, isolate());
798     // If |type| has null as its prototype, |last| is Handle<JSObject>::null().
799     ASSERT(last_map->prototype() == isolate()->heap()->null_value());
800   } else {
801     holder = HandlerFrontendHeader(type, receiver(), last, name, &miss);
802     last_map = handle(last->map());
803   }
804 
805   if (last_map->is_dictionary_map() &&
806       !last_map->IsJSGlobalObjectMap() &&
807       !last_map->IsJSGlobalProxyMap()) {
808     if (!name->IsUniqueName()) {
809       ASSERT(name->IsString());
810       name = factory()->InternalizeString(Handle<String>::cast(name));
811     }
812     ASSERT(last.is_null() ||
813            last->property_dictionary()->FindEntry(name) ==
814                NameDictionary::kNotFound);
815     GenerateDictionaryNegativeLookup(masm(), &miss, holder, name,
816                                      scratch2(), scratch3());
817   }
818 
819   // If the last object in the prototype chain is a global object,
820   // check that the global property cell is empty.
821   if (last_map->IsJSGlobalObjectMap()) {
822     Handle<JSGlobalObject> global = last.is_null()
823         ? Handle<JSGlobalObject>::cast(type->AsConstant()->Value())
824         : Handle<JSGlobalObject>::cast(last);
825     GenerateCheckPropertyCell(masm(), global, name, scratch2(), &miss);
826   }
827 
828   HandlerFrontendFooter(name, &miss);
829 }
830 
831 
CompileLoadField(Handle<HeapType> type,Handle<JSObject> holder,Handle<Name> name,FieldIndex field,Representation representation)832 Handle<Code> LoadStubCompiler::CompileLoadField(
833     Handle<HeapType> type,
834     Handle<JSObject> holder,
835     Handle<Name> name,
836     FieldIndex field,
837     Representation representation) {
838   Register reg = HandlerFrontend(type, receiver(), holder, name);
839   GenerateLoadField(reg, holder, field, representation);
840 
841   // Return the generated code.
842   return GetCode(kind(), Code::FAST, name);
843 }
844 
845 
CompileLoadConstant(Handle<HeapType> type,Handle<JSObject> holder,Handle<Name> name,Handle<Object> value)846 Handle<Code> LoadStubCompiler::CompileLoadConstant(
847     Handle<HeapType> type,
848     Handle<JSObject> holder,
849     Handle<Name> name,
850     Handle<Object> value) {
851   HandlerFrontend(type, receiver(), holder, name);
852   GenerateLoadConstant(value);
853 
854   // Return the generated code.
855   return GetCode(kind(), Code::FAST, name);
856 }
857 
858 
CompileLoadCallback(Handle<HeapType> type,Handle<JSObject> holder,Handle<Name> name,Handle<ExecutableAccessorInfo> callback)859 Handle<Code> LoadStubCompiler::CompileLoadCallback(
860     Handle<HeapType> type,
861     Handle<JSObject> holder,
862     Handle<Name> name,
863     Handle<ExecutableAccessorInfo> callback) {
864   Register reg = CallbackHandlerFrontend(
865       type, receiver(), holder, name, callback);
866   GenerateLoadCallback(reg, callback);
867 
868   // Return the generated code.
869   return GetCode(kind(), Code::FAST, name);
870 }
871 
872 
CompileLoadCallback(Handle<HeapType> type,Handle<JSObject> holder,Handle<Name> name,const CallOptimization & call_optimization)873 Handle<Code> LoadStubCompiler::CompileLoadCallback(
874     Handle<HeapType> type,
875     Handle<JSObject> holder,
876     Handle<Name> name,
877     const CallOptimization& call_optimization) {
878   ASSERT(call_optimization.is_simple_api_call());
879   Handle<JSFunction> callback = call_optimization.constant_function();
880   CallbackHandlerFrontend(type, receiver(), holder, name, callback);
881   Handle<Map>receiver_map = IC::TypeToMap(*type, isolate());
882   GenerateFastApiCall(
883       masm(), call_optimization, receiver_map,
884       receiver(), scratch1(), false, 0, NULL);
885   // Return the generated code.
886   return GetCode(kind(), Code::FAST, name);
887 }
888 
889 
CompileLoadInterceptor(Handle<HeapType> type,Handle<JSObject> holder,Handle<Name> name)890 Handle<Code> LoadStubCompiler::CompileLoadInterceptor(
891     Handle<HeapType> type,
892     Handle<JSObject> holder,
893     Handle<Name> name) {
894   LookupResult lookup(isolate());
895   LookupPostInterceptor(holder, name, &lookup);
896 
897   Register reg = HandlerFrontend(type, receiver(), holder, name);
898   // TODO(368): Compile in the whole chain: all the interceptors in
899   // prototypes and ultimate answer.
900   GenerateLoadInterceptor(reg, type, holder, &lookup, name);
901 
902   // Return the generated code.
903   return GetCode(kind(), Code::FAST, name);
904 }
905 
906 
GenerateLoadPostInterceptor(Register interceptor_reg,Handle<JSObject> interceptor_holder,Handle<Name> name,LookupResult * lookup)907 void LoadStubCompiler::GenerateLoadPostInterceptor(
908     Register interceptor_reg,
909     Handle<JSObject> interceptor_holder,
910     Handle<Name> name,
911     LookupResult* lookup) {
912   Handle<JSObject> holder(lookup->holder());
913   if (lookup->IsField()) {
914     FieldIndex field = lookup->GetFieldIndex();
915     if (interceptor_holder.is_identical_to(holder)) {
916       GenerateLoadField(
917           interceptor_reg, holder, field, lookup->representation());
918     } else {
919       // We found FIELD property in prototype chain of interceptor's holder.
920       // Retrieve a field from field's holder.
921       Register reg = HandlerFrontend(
922           IC::CurrentTypeOf(interceptor_holder, isolate()),
923           interceptor_reg, holder, name);
924       GenerateLoadField(
925           reg, holder, field, lookup->representation());
926     }
927   } else {
928     // We found CALLBACKS property in prototype chain of interceptor's
929     // holder.
930     ASSERT(lookup->type() == CALLBACKS);
931     Handle<ExecutableAccessorInfo> callback(
932         ExecutableAccessorInfo::cast(lookup->GetCallbackObject()));
933     ASSERT(callback->getter() != NULL);
934 
935     Register reg = CallbackHandlerFrontend(
936         IC::CurrentTypeOf(interceptor_holder, isolate()),
937         interceptor_reg, holder, name, callback);
938     GenerateLoadCallback(reg, callback);
939   }
940 }
941 
942 
CompileMonomorphicIC(Handle<HeapType> type,Handle<Code> handler,Handle<Name> name)943 Handle<Code> BaseLoadStoreStubCompiler::CompileMonomorphicIC(
944     Handle<HeapType> type,
945     Handle<Code> handler,
946     Handle<Name> name) {
947   TypeHandleList types(1);
948   CodeHandleList handlers(1);
949   types.Add(type);
950   handlers.Add(handler);
951   Code::StubType stub_type = handler->type();
952   return CompilePolymorphicIC(&types, &handlers, name, stub_type, PROPERTY);
953 }
954 
955 
CompileLoadViaGetter(Handle<HeapType> type,Handle<JSObject> holder,Handle<Name> name,Handle<JSFunction> getter)956 Handle<Code> LoadStubCompiler::CompileLoadViaGetter(
957     Handle<HeapType> type,
958     Handle<JSObject> holder,
959     Handle<Name> name,
960     Handle<JSFunction> getter) {
961   HandlerFrontend(type, receiver(), holder, name);
962   GenerateLoadViaGetter(masm(), type, receiver(), getter);
963 
964   // Return the generated code.
965   return GetCode(kind(), Code::FAST, name);
966 }
967 
968 
CompileStoreTransition(Handle<JSObject> object,LookupResult * lookup,Handle<Map> transition,Handle<Name> name)969 Handle<Code> StoreStubCompiler::CompileStoreTransition(
970     Handle<JSObject> object,
971     LookupResult* lookup,
972     Handle<Map> transition,
973     Handle<Name> name) {
974   Label miss, slow;
975 
976   // Ensure no transitions to deprecated maps are followed.
977   __ CheckMapDeprecated(transition, scratch1(), &miss);
978 
979   // Check that we are allowed to write this.
980   if (object->GetPrototype()->IsJSObject()) {
981     Handle<JSObject> holder;
982     // holder == object indicates that no property was found.
983     if (lookup->holder() != *object) {
984       holder = Handle<JSObject>(lookup->holder());
985     } else {
986       // Find the top object.
987       holder = object;
988       do {
989         holder = Handle<JSObject>(JSObject::cast(holder->GetPrototype()));
990       } while (holder->GetPrototype()->IsJSObject());
991     }
992 
993     Register holder_reg = HandlerFrontendHeader(
994         IC::CurrentTypeOf(object, isolate()), receiver(), holder, name, &miss);
995 
996     // If no property was found, and the holder (the last object in the
997     // prototype chain) is in slow mode, we need to do a negative lookup on the
998     // holder.
999     if (lookup->holder() == *object) {
1000       GenerateNegativeHolderLookup(masm(), holder, holder_reg, name, &miss);
1001     }
1002   }
1003 
1004   GenerateStoreTransition(masm(),
1005                           object,
1006                           lookup,
1007                           transition,
1008                           name,
1009                           receiver(), this->name(), value(),
1010                           scratch1(), scratch2(), scratch3(),
1011                           &miss,
1012                           &slow);
1013 
1014   // Handle store cache miss.
1015   GenerateRestoreName(masm(), &miss, name);
1016   TailCallBuiltin(masm(), MissBuiltin(kind()));
1017 
1018   GenerateRestoreName(masm(), &slow, name);
1019   TailCallBuiltin(masm(), SlowBuiltin(kind()));
1020 
1021   // Return the generated code.
1022   return GetCode(kind(), Code::FAST, name);
1023 }
1024 
1025 
CompileStoreField(Handle<JSObject> object,LookupResult * lookup,Handle<Name> name)1026 Handle<Code> StoreStubCompiler::CompileStoreField(Handle<JSObject> object,
1027                                                   LookupResult* lookup,
1028                                                   Handle<Name> name) {
1029   Label miss;
1030 
1031   HandlerFrontendHeader(IC::CurrentTypeOf(object, isolate()),
1032                         receiver(), object, name, &miss);
1033 
1034   // Generate store field code.
1035   GenerateStoreField(masm(),
1036                      object,
1037                      lookup,
1038                      receiver(), this->name(), value(), scratch1(), scratch2(),
1039                      &miss);
1040 
1041   // Handle store cache miss.
1042   __ bind(&miss);
1043   TailCallBuiltin(masm(), MissBuiltin(kind()));
1044 
1045   // Return the generated code.
1046   return GetCode(kind(), Code::FAST, name);
1047 }
1048 
1049 
CompileStoreArrayLength(Handle<JSObject> object,LookupResult * lookup,Handle<Name> name)1050 Handle<Code> StoreStubCompiler::CompileStoreArrayLength(Handle<JSObject> object,
1051                                                         LookupResult* lookup,
1052                                                         Handle<Name> name) {
1053   // This accepts as a receiver anything JSArray::SetElementsLength accepts
1054   // (currently anything except for external arrays which means anything with
1055   // elements of FixedArray type).  Value must be a number, but only smis are
1056   // accepted as the most common case.
1057   Label miss;
1058 
1059   // Check that value is a smi.
1060   __ JumpIfNotSmi(value(), &miss);
1061 
1062   // Generate tail call to StoreIC_ArrayLength.
1063   GenerateStoreArrayLength();
1064 
1065   // Handle miss case.
1066   __ bind(&miss);
1067   TailCallBuiltin(masm(), MissBuiltin(kind()));
1068 
1069   // Return the generated code.
1070   return GetCode(kind(), Code::FAST, name);
1071 }
1072 
1073 
CompileStoreViaSetter(Handle<JSObject> object,Handle<JSObject> holder,Handle<Name> name,Handle<JSFunction> setter)1074 Handle<Code> StoreStubCompiler::CompileStoreViaSetter(
1075     Handle<JSObject> object,
1076     Handle<JSObject> holder,
1077     Handle<Name> name,
1078     Handle<JSFunction> setter) {
1079   Handle<HeapType> type = IC::CurrentTypeOf(object, isolate());
1080   HandlerFrontend(type, receiver(), holder, name);
1081   GenerateStoreViaSetter(masm(), type, receiver(), setter);
1082 
1083   return GetCode(kind(), Code::FAST, name);
1084 }
1085 
1086 
CompileStoreCallback(Handle<JSObject> object,Handle<JSObject> holder,Handle<Name> name,const CallOptimization & call_optimization)1087 Handle<Code> StoreStubCompiler::CompileStoreCallback(
1088     Handle<JSObject> object,
1089     Handle<JSObject> holder,
1090     Handle<Name> name,
1091     const CallOptimization& call_optimization) {
1092   HandlerFrontend(IC::CurrentTypeOf(object, isolate()),
1093                   receiver(), holder, name);
1094   Register values[] = { value() };
1095   GenerateFastApiCall(
1096       masm(), call_optimization, handle(object->map()),
1097       receiver(), scratch1(), true, 1, values);
1098   // Return the generated code.
1099   return GetCode(kind(), Code::FAST, name);
1100 }
1101 
1102 
CompileLoadElement(Handle<Map> receiver_map)1103 Handle<Code> KeyedLoadStubCompiler::CompileLoadElement(
1104     Handle<Map> receiver_map) {
1105   ElementsKind elements_kind = receiver_map->elements_kind();
1106   if (receiver_map->has_fast_elements() ||
1107       receiver_map->has_external_array_elements() ||
1108       receiver_map->has_fixed_typed_array_elements()) {
1109     Handle<Code> stub = KeyedLoadFastElementStub(
1110         isolate(),
1111         receiver_map->instance_type() == JS_ARRAY_TYPE,
1112         elements_kind).GetCode();
1113     __ DispatchMap(receiver(), scratch1(), receiver_map, stub, DO_SMI_CHECK);
1114   } else {
1115     Handle<Code> stub = FLAG_compiled_keyed_dictionary_loads
1116         ? KeyedLoadDictionaryElementStub(isolate()).GetCode()
1117         : KeyedLoadDictionaryElementPlatformStub(isolate()).GetCode();
1118     __ DispatchMap(receiver(), scratch1(), receiver_map, stub, DO_SMI_CHECK);
1119   }
1120 
1121   TailCallBuiltin(masm(), Builtins::kKeyedLoadIC_Miss);
1122 
1123   // Return the generated code.
1124   return GetICCode(kind(), Code::NORMAL, factory()->empty_string());
1125 }
1126 
1127 
CompileStoreElement(Handle<Map> receiver_map)1128 Handle<Code> KeyedStoreStubCompiler::CompileStoreElement(
1129     Handle<Map> receiver_map) {
1130   ElementsKind elements_kind = receiver_map->elements_kind();
1131   bool is_jsarray = receiver_map->instance_type() == JS_ARRAY_TYPE;
1132   Handle<Code> stub;
1133   if (receiver_map->has_fast_elements() ||
1134       receiver_map->has_external_array_elements() ||
1135       receiver_map->has_fixed_typed_array_elements()) {
1136     stub = KeyedStoreFastElementStub(
1137         isolate(),
1138         is_jsarray,
1139         elements_kind,
1140         store_mode()).GetCode();
1141   } else {
1142     stub = KeyedStoreElementStub(isolate(),
1143                                  is_jsarray,
1144                                  elements_kind,
1145                                  store_mode()).GetCode();
1146   }
1147 
1148   __ DispatchMap(receiver(), scratch1(), receiver_map, stub, DO_SMI_CHECK);
1149 
1150   TailCallBuiltin(masm(), Builtins::kKeyedStoreIC_Miss);
1151 
1152   // Return the generated code.
1153   return GetICCode(kind(), Code::NORMAL, factory()->empty_string());
1154 }
1155 
1156 
1157 #undef __
1158 
1159 
TailCallBuiltin(MacroAssembler * masm,Builtins::Name name)1160 void StubCompiler::TailCallBuiltin(MacroAssembler* masm, Builtins::Name name) {
1161   Handle<Code> code(masm->isolate()->builtins()->builtin(name));
1162   GenerateTailCall(masm, code);
1163 }
1164 
1165 
JitEvent(Handle<Name> name,Handle<Code> code)1166 void BaseLoadStoreStubCompiler::JitEvent(Handle<Name> name, Handle<Code> code) {
1167 #ifdef ENABLE_GDB_JIT_INTERFACE
1168   GDBJITInterface::CodeTag tag;
1169   if (kind_ == Code::LOAD_IC) {
1170     tag = GDBJITInterface::LOAD_IC;
1171   } else if (kind_ == Code::KEYED_LOAD_IC) {
1172     tag = GDBJITInterface::KEYED_LOAD_IC;
1173   } else if (kind_ == Code::STORE_IC) {
1174     tag = GDBJITInterface::STORE_IC;
1175   } else {
1176     tag = GDBJITInterface::KEYED_STORE_IC;
1177   }
1178   GDBJIT(AddCode(tag, *name, *code));
1179 #endif
1180 }
1181 
1182 
InitializeRegisters()1183 void BaseLoadStoreStubCompiler::InitializeRegisters() {
1184   if (kind_ == Code::LOAD_IC) {
1185     registers_ = LoadStubCompiler::registers();
1186   } else if (kind_ == Code::KEYED_LOAD_IC) {
1187     registers_ = KeyedLoadStubCompiler::registers();
1188   } else if (kind_ == Code::STORE_IC) {
1189     registers_ = StoreStubCompiler::registers();
1190   } else {
1191     registers_ = KeyedStoreStubCompiler::registers();
1192   }
1193 }
1194 
1195 
GetICCode(Code::Kind kind,Code::StubType type,Handle<Name> name,InlineCacheState state)1196 Handle<Code> BaseLoadStoreStubCompiler::GetICCode(Code::Kind kind,
1197                                                   Code::StubType type,
1198                                                   Handle<Name> name,
1199                                                   InlineCacheState state) {
1200   Code::Flags flags = Code::ComputeFlags(kind, state, extra_state(), type);
1201   Handle<Code> code = GetCodeWithFlags(flags, name);
1202   IC::RegisterWeakMapDependency(code);
1203   PROFILE(isolate(), CodeCreateEvent(log_kind(code), *code, *name));
1204   JitEvent(name, code);
1205   return code;
1206 }
1207 
1208 
GetCode(Code::Kind kind,Code::StubType type,Handle<Name> name)1209 Handle<Code> BaseLoadStoreStubCompiler::GetCode(Code::Kind kind,
1210                                                 Code::StubType type,
1211                                                 Handle<Name> name) {
1212   ASSERT_EQ(kNoExtraICState, extra_state());
1213   Code::Flags flags = Code::ComputeHandlerFlags(kind, type, cache_holder_);
1214   Handle<Code> code = GetCodeWithFlags(flags, name);
1215   PROFILE(isolate(), CodeCreateEvent(log_kind(code), *code, *name));
1216   JitEvent(name, code);
1217   return code;
1218 }
1219 
1220 
CompileElementHandlers(MapHandleList * receiver_maps,CodeHandleList * handlers)1221 void KeyedLoadStubCompiler::CompileElementHandlers(MapHandleList* receiver_maps,
1222                                                    CodeHandleList* handlers) {
1223   for (int i = 0; i < receiver_maps->length(); ++i) {
1224     Handle<Map> receiver_map = receiver_maps->at(i);
1225     Handle<Code> cached_stub;
1226 
1227     if ((receiver_map->instance_type() & kNotStringTag) == 0) {
1228       cached_stub = isolate()->builtins()->KeyedLoadIC_String();
1229     } else if (receiver_map->instance_type() < FIRST_JS_RECEIVER_TYPE) {
1230       cached_stub = isolate()->builtins()->KeyedLoadIC_Slow();
1231     } else {
1232       bool is_js_array = receiver_map->instance_type() == JS_ARRAY_TYPE;
1233       ElementsKind elements_kind = receiver_map->elements_kind();
1234 
1235       if (IsFastElementsKind(elements_kind) ||
1236           IsExternalArrayElementsKind(elements_kind) ||
1237           IsFixedTypedArrayElementsKind(elements_kind)) {
1238         cached_stub =
1239             KeyedLoadFastElementStub(isolate(),
1240                                      is_js_array,
1241                                      elements_kind).GetCode();
1242       } else if (elements_kind == SLOPPY_ARGUMENTS_ELEMENTS) {
1243         cached_stub = isolate()->builtins()->KeyedLoadIC_SloppyArguments();
1244       } else {
1245         ASSERT(elements_kind == DICTIONARY_ELEMENTS);
1246         cached_stub =
1247             KeyedLoadDictionaryElementStub(isolate()).GetCode();
1248       }
1249     }
1250 
1251     handlers->Add(cached_stub);
1252   }
1253 }
1254 
1255 
CompileStoreElementPolymorphic(MapHandleList * receiver_maps)1256 Handle<Code> KeyedStoreStubCompiler::CompileStoreElementPolymorphic(
1257     MapHandleList* receiver_maps) {
1258   // Collect MONOMORPHIC stubs for all |receiver_maps|.
1259   CodeHandleList handlers(receiver_maps->length());
1260   MapHandleList transitioned_maps(receiver_maps->length());
1261   for (int i = 0; i < receiver_maps->length(); ++i) {
1262     Handle<Map> receiver_map(receiver_maps->at(i));
1263     Handle<Code> cached_stub;
1264     Handle<Map> transitioned_map =
1265         receiver_map->FindTransitionedMap(receiver_maps);
1266 
1267     // TODO(mvstanton): The code below is doing pessimistic elements
1268     // transitions. I would like to stop doing that and rely on Allocation Site
1269     // Tracking to do a better job of ensuring the data types are what they need
1270     // to be. Not all the elements are in place yet, pessimistic elements
1271     // transitions are still important for performance.
1272     bool is_js_array = receiver_map->instance_type() == JS_ARRAY_TYPE;
1273     ElementsKind elements_kind = receiver_map->elements_kind();
1274     if (!transitioned_map.is_null()) {
1275       cached_stub = ElementsTransitionAndStoreStub(
1276           isolate(),
1277           elements_kind,
1278           transitioned_map->elements_kind(),
1279           is_js_array,
1280           store_mode()).GetCode();
1281     } else if (receiver_map->instance_type() < FIRST_JS_RECEIVER_TYPE) {
1282       cached_stub = isolate()->builtins()->KeyedStoreIC_Slow();
1283     } else {
1284       if (receiver_map->has_fast_elements() ||
1285           receiver_map->has_external_array_elements() ||
1286           receiver_map->has_fixed_typed_array_elements()) {
1287         cached_stub = KeyedStoreFastElementStub(
1288             isolate(),
1289             is_js_array,
1290             elements_kind,
1291             store_mode()).GetCode();
1292       } else {
1293         cached_stub = KeyedStoreElementStub(
1294             isolate(),
1295             is_js_array,
1296             elements_kind,
1297             store_mode()).GetCode();
1298       }
1299     }
1300     ASSERT(!cached_stub.is_null());
1301     handlers.Add(cached_stub);
1302     transitioned_maps.Add(transitioned_map);
1303   }
1304   Handle<Code> code =
1305       CompileStorePolymorphic(receiver_maps, &handlers, &transitioned_maps);
1306   isolate()->counters()->keyed_store_polymorphic_stubs()->Increment();
1307   PROFILE(isolate(),
1308           CodeCreateEvent(Logger::KEYED_STORE_POLYMORPHIC_IC_TAG, *code, 0));
1309   return code;
1310 }
1311 
1312 
GenerateStoreDictionaryElement(MacroAssembler * masm)1313 void KeyedStoreStubCompiler::GenerateStoreDictionaryElement(
1314     MacroAssembler* masm) {
1315   KeyedStoreIC::GenerateSlow(masm);
1316 }
1317 
1318 
CallOptimization(LookupResult * lookup)1319 CallOptimization::CallOptimization(LookupResult* lookup) {
1320   if (lookup->IsFound() &&
1321       lookup->IsCacheable() &&
1322       lookup->IsConstantFunction()) {
1323     // We only optimize constant function calls.
1324     Initialize(Handle<JSFunction>(lookup->GetConstantFunction()));
1325   } else {
1326     Initialize(Handle<JSFunction>::null());
1327   }
1328 }
1329 
1330 
CallOptimization(Handle<JSFunction> function)1331 CallOptimization::CallOptimization(Handle<JSFunction> function) {
1332   Initialize(function);
1333 }
1334 
1335 
LookupHolderOfExpectedType(Handle<Map> object_map,HolderLookup * holder_lookup) const1336 Handle<JSObject> CallOptimization::LookupHolderOfExpectedType(
1337     Handle<Map> object_map,
1338     HolderLookup* holder_lookup) const {
1339   ASSERT(is_simple_api_call());
1340   if (!object_map->IsJSObjectMap()) {
1341     *holder_lookup = kHolderNotFound;
1342     return Handle<JSObject>::null();
1343   }
1344   if (expected_receiver_type_.is_null() ||
1345       expected_receiver_type_->IsTemplateFor(*object_map)) {
1346     *holder_lookup = kHolderIsReceiver;
1347     return Handle<JSObject>::null();
1348   }
1349   while (true) {
1350     if (!object_map->prototype()->IsJSObject()) break;
1351     Handle<JSObject> prototype(JSObject::cast(object_map->prototype()));
1352     if (!prototype->map()->is_hidden_prototype()) break;
1353     object_map = handle(prototype->map());
1354     if (expected_receiver_type_->IsTemplateFor(*object_map)) {
1355       *holder_lookup = kHolderFound;
1356       return prototype;
1357     }
1358   }
1359   *holder_lookup = kHolderNotFound;
1360   return Handle<JSObject>::null();
1361 }
1362 
1363 
IsCompatibleReceiver(Handle<Object> receiver,Handle<JSObject> holder) const1364 bool CallOptimization::IsCompatibleReceiver(Handle<Object> receiver,
1365                                             Handle<JSObject> holder) const {
1366   ASSERT(is_simple_api_call());
1367   if (!receiver->IsJSObject()) return false;
1368   Handle<Map> map(JSObject::cast(*receiver)->map());
1369   HolderLookup holder_lookup;
1370   Handle<JSObject> api_holder =
1371       LookupHolderOfExpectedType(map, &holder_lookup);
1372   switch (holder_lookup) {
1373     case kHolderNotFound:
1374       return false;
1375     case kHolderIsReceiver:
1376       return true;
1377     case kHolderFound:
1378       if (api_holder.is_identical_to(holder)) return true;
1379       // Check if holder is in prototype chain of api_holder.
1380       {
1381         JSObject* object = *api_holder;
1382         while (true) {
1383           Object* prototype = object->map()->prototype();
1384           if (!prototype->IsJSObject()) return false;
1385           if (prototype == *holder) return true;
1386           object = JSObject::cast(prototype);
1387         }
1388       }
1389       break;
1390   }
1391   UNREACHABLE();
1392   return false;
1393 }
1394 
1395 
Initialize(Handle<JSFunction> function)1396 void CallOptimization::Initialize(Handle<JSFunction> function) {
1397   constant_function_ = Handle<JSFunction>::null();
1398   is_simple_api_call_ = false;
1399   expected_receiver_type_ = Handle<FunctionTemplateInfo>::null();
1400   api_call_info_ = Handle<CallHandlerInfo>::null();
1401 
1402   if (function.is_null() || !function->is_compiled()) return;
1403 
1404   constant_function_ = function;
1405   AnalyzePossibleApiFunction(function);
1406 }
1407 
1408 
AnalyzePossibleApiFunction(Handle<JSFunction> function)1409 void CallOptimization::AnalyzePossibleApiFunction(Handle<JSFunction> function) {
1410   if (!function->shared()->IsApiFunction()) return;
1411   Handle<FunctionTemplateInfo> info(function->shared()->get_api_func_data());
1412 
1413   // Require a C++ callback.
1414   if (info->call_code()->IsUndefined()) return;
1415   api_call_info_ =
1416       Handle<CallHandlerInfo>(CallHandlerInfo::cast(info->call_code()));
1417 
1418   // Accept signatures that either have no restrictions at all or
1419   // only have restrictions on the receiver.
1420   if (!info->signature()->IsUndefined()) {
1421     Handle<SignatureInfo> signature =
1422         Handle<SignatureInfo>(SignatureInfo::cast(info->signature()));
1423     if (!signature->args()->IsUndefined()) return;
1424     if (!signature->receiver()->IsUndefined()) {
1425       expected_receiver_type_ =
1426           Handle<FunctionTemplateInfo>(
1427               FunctionTemplateInfo::cast(signature->receiver()));
1428     }
1429   }
1430 
1431   is_simple_api_call_ = true;
1432 }
1433 
1434 
1435 } }  // namespace v8::internal
1436