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
18namespace v8 {
19namespace internal {
20
21// -----------------------------------------------------------------------
22// StubCache implementation.
23
24
25StubCache::StubCache(Isolate* isolate)
26    : isolate_(isolate) { }
27
28
29void StubCache::Initialize() {
30  ASSERT(IsPowerOf2(kPrimaryTableSize));
31  ASSERT(IsPowerOf2(kSecondaryTableSize));
32  Clear();
33}
34
35
36Code* 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
80Handle<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
93Handle<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
106Handle<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
148Handle<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
184Handle<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
200Handle<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
231static 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
240Code* 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
253Handle<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
277Handle<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
304Handle<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.
326Handle<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
351Handle<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
374Handle<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
398void 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
413void 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
458RUNTIME_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 */
491RUNTIME_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
531static 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 */
553RUNTIME_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
574RUNTIME_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
592RUNTIME_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
605Handle<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
615Handle<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
625Handle<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
635Handle<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
645Handle<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
655Handle<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
667Handle<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
680Handle<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
696Handle<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
704void 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
717Register 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.
755Register 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
766bool 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
774Register 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
788void 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
832Handle<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
846Handle<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
859Handle<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
873Handle<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
890Handle<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
907void 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
943Handle<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
956Handle<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
969Handle<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
1026Handle<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
1050Handle<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
1074Handle<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
1087Handle<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
1103Handle<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
1128Handle<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
1160void StubCompiler::TailCallBuiltin(MacroAssembler* masm, Builtins::Name name) {
1161  Handle<Code> code(masm->isolate()->builtins()->builtin(name));
1162  GenerateTailCall(masm, code);
1163}
1164
1165
1166void 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
1183void 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
1196Handle<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
1209Handle<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
1221void 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
1256Handle<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
1313void KeyedStoreStubCompiler::GenerateStoreDictionaryElement(
1314    MacroAssembler* masm) {
1315  KeyedStoreIC::GenerateSlow(masm);
1316}
1317
1318
1319CallOptimization::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
1331CallOptimization::CallOptimization(Handle<JSFunction> function) {
1332  Initialize(function);
1333}
1334
1335
1336Handle<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
1364bool 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
1396void 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
1409void 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