root/src/stub-cache.cc

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. Initialize
  2. Set
  3. ComputeLoadNonexistent
  4. ComputeLoadField
  5. ComputeLoadCallback
  6. ComputeLoadViaGetter
  7. ComputeLoadConstant
  8. ComputeLoadInterceptor
  9. ComputeLoadNormal
  10. ComputeLoadGlobal
  11. ComputeKeyedLoadField
  12. ComputeKeyedLoadConstant
  13. ComputeKeyedLoadInterceptor
  14. ComputeKeyedLoadCallback
  15. ComputeKeyedLoadArrayLength
  16. ComputeKeyedLoadStringLength
  17. ComputeKeyedLoadFunctionPrototype
  18. ComputeStoreField
  19. ComputeKeyedLoadOrStoreElement
  20. ComputeStoreNormal
  21. ComputeStoreGlobal
  22. ComputeStoreCallback
  23. ComputeStoreViaSetter
  24. ComputeStoreInterceptor
  25. ComputeKeyedStoreField
  26. ComputeCallField
  27. ComputeCallInterceptor
  28. ComputeCallGlobal
  29. FillCache
  30. FindCallInitialize
  31. ComputeCallInitialize
  32. ComputeCallInitialize
  33. ComputeKeyedCallInitialize
  34. ComputeCallPreMonomorphic
  35. ComputeCallNormal
  36. ComputeCallArguments
  37. ComputeCallMegamorphic
  38. ComputeCallMiss
  39. ComputeCallDebugBreak
  40. ComputeCallDebugPrepareStepIn
  41. Clear
  42. CollectMatchingMaps
  43. RUNTIME_FUNCTION
  44. RUNTIME_FUNCTION
  45. RUNTIME_FUNCTION
  46. ThrowReferenceError
  47. LoadWithInterceptor
  48. RUNTIME_FUNCTION
  49. RUNTIME_FUNCTION
  50. RUNTIME_FUNCTION
  51. RUNTIME_FUNCTION
  52. CompileCallInitialize
  53. CompileCallPreMonomorphic
  54. CompileCallNormal
  55. CompileCallMegamorphic
  56. CompileCallArguments
  57. CompileCallMiss
  58. CompileCallDebugBreak
  59. CompileCallDebugPrepareStepIn
  60. GetCodeWithFlags
  61. GetCodeWithFlags
  62. LookupPostInterceptor
  63. GetCode
  64. GetCode
  65. GetCode
  66. GetCode
  67. GenerateStoreDictionaryElement
  68. cache_holder_
  69. HasCustomCallGenerator
  70. CompileCustomCall
  71. GetCode
  72. GetCode
  73. GetCode
  74. GetPrototypeDepthOfExpectedType
  75. Initialize
  76. AnalyzePossibleApiFunction

// Copyright 2012 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
//       notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
//       copyright notice, this list of conditions and the following
//       disclaimer in the documentation and/or other materials provided
//       with the distribution.
//     * Neither the name of Google Inc. nor the names of its
//       contributors may be used to endorse or promote products derived
//       from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

#include "v8.h"

#include "api.h"
#include "arguments.h"
#include "ast.h"
#include "code-stubs.h"
#include "gdb-jit.h"
#include "ic-inl.h"
#include "stub-cache.h"
#include "vm-state-inl.h"

namespace v8 {
namespace internal {

// -----------------------------------------------------------------------
// StubCache implementation.


StubCache::StubCache(Isolate* isolate, Zone* zone)
    : isolate_(isolate) {
  ASSERT(isolate == Isolate::Current());
}


void StubCache::Initialize() {
  ASSERT(IsPowerOf2(kPrimaryTableSize));
  ASSERT(IsPowerOf2(kSecondaryTableSize));
  Clear();
}


Code* StubCache::Set(String* name, Map* map, Code* code) {
  // Get the flags from the code.
  Code::Flags flags = Code::RemoveTypeFromFlags(code->flags());

  // Validate that the name does not move on scavenge, and that we
  // can use identity checks instead of string equality checks.
  ASSERT(!heap()->InNewSpace(name));
  ASSERT(name->IsSymbol());

  // The state bits are not important to the hash function because
  // the stub cache only contains monomorphic stubs. Make sure that
  // the bits are the least significant so they will be the ones
  // masked out.
  ASSERT(Code::ExtractICStateFromFlags(flags) == MONOMORPHIC);
  STATIC_ASSERT((Code::ICStateField::kMask & 1) == 1);

  // Make sure that the code type is not included in the hash.
  ASSERT(Code::ExtractTypeFromFlags(flags) == 0);

  // Compute the primary entry.
  int primary_offset = PrimaryOffset(name, flags, map);
  Entry* primary = entry(primary_, primary_offset);
  Code* old_code = primary->value;

  // If the primary entry has useful data in it, we retire it to the
  // secondary cache before overwriting it.
  if (old_code != isolate_->builtins()->builtin(Builtins::kIllegal)) {
    Map* old_map = primary->map;
    Code::Flags old_flags = Code::RemoveTypeFromFlags(old_code->flags());
    int seed = PrimaryOffset(primary->key, old_flags, old_map);
    int secondary_offset = SecondaryOffset(primary->key, old_flags, seed);
    Entry* secondary = entry(secondary_, secondary_offset);
    *secondary = *primary;
  }

  // Update primary cache.
  primary->key = name;
  primary->value = code;
  primary->map = map;
  isolate()->counters()->megamorphic_stub_cache_updates()->Increment();
  return code;
}


Handle<Code> StubCache::ComputeLoadNonexistent(Handle<String> name,
                                               Handle<JSObject> receiver) {
  ASSERT(receiver->IsGlobalObject() || receiver->HasFastProperties());
  // If no global objects are present in the prototype chain, the load
  // nonexistent IC stub can be shared for all names for a given map
  // and we use the empty string for the map cache in that case.  If
  // there are global objects involved, we need to check global
  // property cells in the stub and therefore the stub will be
  // specific to the name.
  Handle<String> cache_name = factory()->empty_string();
  if (receiver->IsGlobalObject()) cache_name = name;
  Handle<JSObject> last = receiver;
  while (last->GetPrototype() != heap()->null_value()) {
    last = Handle<JSObject>(JSObject::cast(last->GetPrototype()));
    if (last->IsGlobalObject()) cache_name = name;
  }
  // Compile the stub that is either shared for all names or
  // name specific if there are global objects involved.
  Code::Flags flags =
      Code::ComputeMonomorphicFlags(Code::LOAD_IC, Code::NONEXISTENT);
  Handle<Object> probe(receiver->map()->FindInCodeCache(*cache_name, flags));
  if (probe->IsCode()) return Handle<Code>::cast(probe);

  LoadStubCompiler compiler(isolate_);
  Handle<Code> code =
      compiler.CompileLoadNonexistent(cache_name, receiver, last);
  PROFILE(isolate_, CodeCreateEvent(Logger::LOAD_IC_TAG, *code, *cache_name));
  GDBJIT(AddCode(GDBJITInterface::LOAD_IC, *cache_name, *code));
  JSObject::UpdateMapCodeCache(receiver, cache_name, code);
  return code;
}


Handle<Code> StubCache::ComputeLoadField(Handle<String> name,
                                         Handle<JSObject> receiver,
                                         Handle<JSObject> holder,
                                         int field_index) {
  ASSERT(IC::GetCodeCacheForObject(*receiver, *holder) == OWN_MAP);
  Code::Flags flags = Code::ComputeMonomorphicFlags(Code::LOAD_IC, Code::FIELD);
  Handle<Object> probe(receiver->map()->FindInCodeCache(*name, flags));
  if (probe->IsCode()) return Handle<Code>::cast(probe);

  LoadStubCompiler compiler(isolate_);
  Handle<Code> code =
      compiler.CompileLoadField(receiver, holder, field_index, name);
  PROFILE(isolate_, CodeCreateEvent(Logger::LOAD_IC_TAG, *code, *name));
  GDBJIT(AddCode(GDBJITInterface::LOAD_IC, *name, *code));
  JSObject::UpdateMapCodeCache(receiver, name, code);
  return code;
}


Handle<Code> StubCache::ComputeLoadCallback(Handle<String> name,
                                            Handle<JSObject> receiver,
                                            Handle<JSObject> holder,
                                            Handle<AccessorInfo> callback) {
  ASSERT(v8::ToCData<Address>(callback->getter()) != 0);
  ASSERT(IC::GetCodeCacheForObject(*receiver, *holder) == OWN_MAP);
  Code::Flags flags =
      Code::ComputeMonomorphicFlags(Code::LOAD_IC, Code::CALLBACKS);
  Handle<Object> probe(receiver->map()->FindInCodeCache(*name, flags));
  if (probe->IsCode()) return Handle<Code>::cast(probe);

  LoadStubCompiler compiler(isolate_);
  Handle<Code> code =
      compiler.CompileLoadCallback(name, receiver, holder, callback);
  PROFILE(isolate_, CodeCreateEvent(Logger::LOAD_IC_TAG, *code, *name));
  GDBJIT(AddCode(GDBJITInterface::LOAD_IC, *name, *code));
  JSObject::UpdateMapCodeCache(receiver, name, code);
  return code;
}


Handle<Code> StubCache::ComputeLoadViaGetter(Handle<String> name,
                                             Handle<JSObject> receiver,
                                             Handle<JSObject> holder,
                                             Handle<JSFunction> getter) {
  ASSERT(IC::GetCodeCacheForObject(*receiver, *holder) == OWN_MAP);
  Code::Flags flags =
      Code::ComputeMonomorphicFlags(Code::LOAD_IC, Code::CALLBACKS);
  Handle<Object> probe(receiver->map()->FindInCodeCache(*name, flags));
  if (probe->IsCode()) return Handle<Code>::cast(probe);

  LoadStubCompiler compiler(isolate_);
  Handle<Code> code =
      compiler.CompileLoadViaGetter(name, receiver, holder, getter);
  PROFILE(isolate_, CodeCreateEvent(Logger::LOAD_IC_TAG, *code, *name));
  GDBJIT(AddCode(GDBJITInterface::LOAD_IC, *name, *code));
  JSObject::UpdateMapCodeCache(receiver, name, code);
  return code;
}


Handle<Code> StubCache::ComputeLoadConstant(Handle<String> name,
                                            Handle<JSObject> receiver,
                                            Handle<JSObject> holder,
                                            Handle<JSFunction> value) {
  ASSERT(IC::GetCodeCacheForObject(*receiver, *holder) == OWN_MAP);
  Code::Flags flags =
      Code::ComputeMonomorphicFlags(Code::LOAD_IC, Code::CONSTANT_FUNCTION);
  Handle<Object> probe(receiver->map()->FindInCodeCache(*name, flags));
  if (probe->IsCode()) return Handle<Code>::cast(probe);

  LoadStubCompiler compiler(isolate_);
  Handle<Code> code =
        compiler.CompileLoadConstant(receiver, holder, value, name);
  PROFILE(isolate_, CodeCreateEvent(Logger::LOAD_IC_TAG, *code, *name));
  GDBJIT(AddCode(GDBJITInterface::LOAD_IC, *name, *code));
  JSObject::UpdateMapCodeCache(receiver, name, code);
  return code;
}


Handle<Code> StubCache::ComputeLoadInterceptor(Handle<String> name,
                                               Handle<JSObject> receiver,
                                               Handle<JSObject> holder) {
  ASSERT(IC::GetCodeCacheForObject(*receiver, *holder) == OWN_MAP);
  Code::Flags flags =
      Code::ComputeMonomorphicFlags(Code::LOAD_IC, Code::INTERCEPTOR);
  Handle<Object> probe(receiver->map()->FindInCodeCache(*name, flags));
  if (probe->IsCode()) return Handle<Code>::cast(probe);

  LoadStubCompiler compiler(isolate_);
  Handle<Code> code =
        compiler.CompileLoadInterceptor(receiver, holder, name);
  PROFILE(isolate_, CodeCreateEvent(Logger::LOAD_IC_TAG, *code, *name));
  GDBJIT(AddCode(GDBJITInterface::LOAD_IC, *name, *code));
  JSObject::UpdateMapCodeCache(receiver, name, code);
  return code;
}


Handle<Code> StubCache::ComputeLoadNormal() {
  return isolate_->builtins()->LoadIC_Normal();
}


Handle<Code> StubCache::ComputeLoadGlobal(Handle<String> name,
                                          Handle<JSObject> receiver,
                                          Handle<GlobalObject> holder,
                                          Handle<JSGlobalPropertyCell> cell,
                                          bool is_dont_delete) {
  ASSERT(IC::GetCodeCacheForObject(*receiver, *holder) == OWN_MAP);
  Code::Flags flags =
      Code::ComputeMonomorphicFlags(Code::LOAD_IC, Code::NORMAL);
  Handle<Object> probe(receiver->map()->FindInCodeCache(*name, flags));
  if (probe->IsCode()) return Handle<Code>::cast(probe);

  LoadStubCompiler compiler(isolate_);
  Handle<Code> code =
      compiler.CompileLoadGlobal(receiver, holder, cell, name, is_dont_delete);
  PROFILE(isolate_, CodeCreateEvent(Logger::LOAD_IC_TAG, *code, *name));
  GDBJIT(AddCode(GDBJITInterface::LOAD_IC, *name, *code));
  JSObject::UpdateMapCodeCache(receiver, name, code);
  return code;
}


Handle<Code> StubCache::ComputeKeyedLoadField(Handle<String> name,
                                              Handle<JSObject> receiver,
                                              Handle<JSObject> holder,
                                              int field_index) {
  ASSERT(IC::GetCodeCacheForObject(*receiver, *holder) == OWN_MAP);
  Code::Flags flags =
      Code::ComputeMonomorphicFlags(Code::KEYED_LOAD_IC, Code::FIELD);
  Handle<Object> probe(receiver->map()->FindInCodeCache(*name, flags));
  if (probe->IsCode()) return Handle<Code>::cast(probe);

  KeyedLoadStubCompiler compiler(isolate_);
  Handle<Code> code =
      compiler.CompileLoadField(name, receiver, holder, field_index);
  PROFILE(isolate_, CodeCreateEvent(Logger::KEYED_LOAD_IC_TAG, *code, *name));
  GDBJIT(AddCode(GDBJITInterface::KEYED_LOAD_IC, *name, *code));
  JSObject::UpdateMapCodeCache(receiver, name, code);
  return code;
}


Handle<Code> StubCache::ComputeKeyedLoadConstant(Handle<String> name,
                                                 Handle<JSObject> receiver,
                                                 Handle<JSObject> holder,
                                                 Handle<JSFunction> value) {
  ASSERT(IC::GetCodeCacheForObject(*receiver, *holder) == OWN_MAP);
  Code::Flags flags = Code::ComputeMonomorphicFlags(Code::KEYED_LOAD_IC,
                                                    Code::CONSTANT_FUNCTION);
  Handle<Object> probe(receiver->map()->FindInCodeCache(*name, flags));
  if (probe->IsCode()) return Handle<Code>::cast(probe);

  KeyedLoadStubCompiler compiler(isolate_);
  Handle<Code> code =
      compiler.CompileLoadConstant(name, receiver, holder, value);
  PROFILE(isolate_, CodeCreateEvent(Logger::KEYED_LOAD_IC_TAG, *code, *name));
  GDBJIT(AddCode(GDBJITInterface::KEYED_LOAD_IC, *name, *code));
  JSObject::UpdateMapCodeCache(receiver, name, code);
  return code;
}


Handle<Code> StubCache::ComputeKeyedLoadInterceptor(Handle<String> name,
                                                    Handle<JSObject> receiver,
                                                    Handle<JSObject> holder) {
  ASSERT(IC::GetCodeCacheForObject(*receiver, *holder) == OWN_MAP);
  Code::Flags flags =
      Code::ComputeMonomorphicFlags(Code::KEYED_LOAD_IC, Code::INTERCEPTOR);
  Handle<Object> probe(receiver->map()->FindInCodeCache(*name, flags));
  if (probe->IsCode()) return Handle<Code>::cast(probe);

  KeyedLoadStubCompiler compiler(isolate_);
  Handle<Code> code = compiler.CompileLoadInterceptor(receiver, holder, name);
  PROFILE(isolate_, CodeCreateEvent(Logger::KEYED_LOAD_IC_TAG, *code, *name));
  GDBJIT(AddCode(GDBJITInterface::KEYED_LOAD_IC, *name, *code));
  JSObject::UpdateMapCodeCache(receiver, name, code);
  return code;
}


Handle<Code> StubCache::ComputeKeyedLoadCallback(
    Handle<String> name,
    Handle<JSObject> receiver,
    Handle<JSObject> holder,
    Handle<AccessorInfo> callback) {
  ASSERT(IC::GetCodeCacheForObject(*receiver, *holder) == OWN_MAP);
  Code::Flags flags =
      Code::ComputeMonomorphicFlags(Code::KEYED_LOAD_IC, Code::CALLBACKS);
  Handle<Object> probe(receiver->map()->FindInCodeCache(*name, flags));
  if (probe->IsCode()) return Handle<Code>::cast(probe);

  KeyedLoadStubCompiler compiler(isolate_);
  Handle<Code> code =
      compiler.CompileLoadCallback(name, receiver, holder, callback);
  PROFILE(isolate_, CodeCreateEvent(Logger::KEYED_LOAD_IC_TAG, *code, *name));
  GDBJIT(AddCode(GDBJITInterface::KEYED_LOAD_IC, *name, *code));
  JSObject::UpdateMapCodeCache(receiver, name, code);
  return code;
}


Handle<Code> StubCache::ComputeKeyedLoadArrayLength(Handle<String> name,
                                                    Handle<JSArray> receiver) {
  Code::Flags flags =
      Code::ComputeMonomorphicFlags(Code::KEYED_LOAD_IC, Code::CALLBACKS);
  Handle<Object> probe(receiver->map()->FindInCodeCache(*name, flags));
  if (probe->IsCode()) return Handle<Code>::cast(probe);

  KeyedLoadStubCompiler compiler(isolate_);
  Handle<Code> code = compiler.CompileLoadArrayLength(name);
  PROFILE(isolate_, CodeCreateEvent(Logger::KEYED_LOAD_IC_TAG, *code, *name));
  GDBJIT(AddCode(GDBJITInterface::KEYED_LOAD_IC, *name, *code));
  JSObject::UpdateMapCodeCache(receiver, name, code);
  return code;
}


Handle<Code> StubCache::ComputeKeyedLoadStringLength(Handle<String> name,
                                                     Handle<String> receiver) {
  Code::Flags flags =
      Code::ComputeMonomorphicFlags(Code::KEYED_LOAD_IC, Code::CALLBACKS);
  Handle<Map> map(receiver->map());
  Handle<Object> probe(map->FindInCodeCache(*name, flags));
  if (probe->IsCode()) return Handle<Code>::cast(probe);

  KeyedLoadStubCompiler compiler(isolate_);
  Handle<Code> code = compiler.CompileLoadStringLength(name);
  PROFILE(isolate_, CodeCreateEvent(Logger::KEYED_LOAD_IC_TAG, *code, *name));
  GDBJIT(AddCode(GDBJITInterface::KEYED_LOAD_IC, *name, *code));
  Map::UpdateCodeCache(map, name, code);
  return code;
}


Handle<Code> StubCache::ComputeKeyedLoadFunctionPrototype(
    Handle<String> name,
    Handle<JSFunction> receiver) {
  Code::Flags flags =
      Code::ComputeMonomorphicFlags(Code::KEYED_LOAD_IC, Code::CALLBACKS);
  Handle<Object> probe(receiver->map()->FindInCodeCache(*name, flags));
  if (probe->IsCode()) return Handle<Code>::cast(probe);

  KeyedLoadStubCompiler compiler(isolate_);
  Handle<Code> code = compiler.CompileLoadFunctionPrototype(name);
  PROFILE(isolate_, CodeCreateEvent(Logger::KEYED_LOAD_IC_TAG, *code, *name));
  GDBJIT(AddCode(GDBJITInterface::KEYED_LOAD_IC, *name, *code));
  JSObject::UpdateMapCodeCache(receiver, name, code);
  return code;
}


Handle<Code> StubCache::ComputeStoreField(Handle<String> name,
                                          Handle<JSObject> receiver,
                                          int field_index,
                                          Handle<Map> transition,
                                          StrictModeFlag strict_mode) {
  Code::StubType type =
      (transition.is_null()) ? Code::FIELD : Code::MAP_TRANSITION;
  Code::Flags flags = Code::ComputeMonomorphicFlags(
      Code::STORE_IC, type, strict_mode);
  Handle<Object> probe(receiver->map()->FindInCodeCache(*name, flags));
  if (probe->IsCode()) return Handle<Code>::cast(probe);

  StoreStubCompiler compiler(isolate_, strict_mode);
  Handle<Code> code =
      compiler.CompileStoreField(receiver, field_index, transition, name);
  PROFILE(isolate_, CodeCreateEvent(Logger::STORE_IC_TAG, *code, *name));
  GDBJIT(AddCode(GDBJITInterface::STORE_IC, *name, *code));
  JSObject::UpdateMapCodeCache(receiver, name, code);
  return code;
}


Handle<Code> StubCache::ComputeKeyedLoadOrStoreElement(
    Handle<Map> receiver_map,
    KeyedIC::StubKind stub_kind,
    StrictModeFlag strict_mode) {
  KeyedAccessGrowMode grow_mode =
      KeyedIC::GetGrowModeFromStubKind(stub_kind);
  Code::ExtraICState extra_state =
      Code::ComputeExtraICState(grow_mode, strict_mode);
  Code::Flags flags =
      Code::ComputeMonomorphicFlags(
          stub_kind == KeyedIC::LOAD ? Code::KEYED_LOAD_IC
                                     : Code::KEYED_STORE_IC,
          Code::NORMAL,
          extra_state);
  Handle<String> name;
  switch (stub_kind) {
    case KeyedIC::LOAD:
      name = isolate()->factory()->KeyedLoadElementMonomorphic_symbol();
      break;
    case KeyedIC::STORE_NO_TRANSITION:
      name = isolate()->factory()->KeyedStoreElementMonomorphic_symbol();
      break;
    case KeyedIC::STORE_AND_GROW_NO_TRANSITION:
      name = isolate()->factory()->KeyedStoreAndGrowElementMonomorphic_symbol();
      break;
    default:
      UNREACHABLE();
      break;
  }
  Handle<Object> probe(receiver_map->FindInCodeCache(*name, flags));
  if (probe->IsCode()) return Handle<Code>::cast(probe);

  Handle<Code> code;
  switch (stub_kind) {
    case KeyedIC::LOAD: {
      KeyedLoadStubCompiler compiler(isolate_);
      code = compiler.CompileLoadElement(receiver_map);
      break;
    }
    case KeyedIC::STORE_AND_GROW_NO_TRANSITION: {
      KeyedStoreStubCompiler compiler(isolate_, strict_mode,
                                      ALLOW_JSARRAY_GROWTH);
      code = compiler.CompileStoreElement(receiver_map);
      break;
    }
    case KeyedIC::STORE_NO_TRANSITION: {
      KeyedStoreStubCompiler compiler(isolate_, strict_mode,
                                      DO_NOT_ALLOW_JSARRAY_GROWTH);
      code = compiler.CompileStoreElement(receiver_map);
      break;
    }
    default:
      UNREACHABLE();
      break;
  }

  ASSERT(!code.is_null());

  if (stub_kind == KeyedIC::LOAD) {
    PROFILE(isolate_, CodeCreateEvent(Logger::KEYED_LOAD_IC_TAG, *code, 0));
  } else {
    PROFILE(isolate_, CodeCreateEvent(Logger::KEYED_STORE_IC_TAG, *code, 0));
  }
  Map::UpdateCodeCache(receiver_map, name, code);
  return code;
}


Handle<Code> StubCache::ComputeStoreNormal(StrictModeFlag strict_mode) {
  return (strict_mode == kStrictMode)
      ? isolate_->builtins()->Builtins::StoreIC_Normal_Strict()
      : isolate_->builtins()->Builtins::StoreIC_Normal();
}


Handle<Code> StubCache::ComputeStoreGlobal(Handle<String> name,
                                           Handle<GlobalObject> receiver,
                                           Handle<JSGlobalPropertyCell> cell,
                                           StrictModeFlag strict_mode) {
  Code::Flags flags = Code::ComputeMonomorphicFlags(
      Code::STORE_IC, Code::NORMAL, strict_mode);
  Handle<Object> probe(receiver->map()->FindInCodeCache(*name, flags));
  if (probe->IsCode()) return Handle<Code>::cast(probe);

  StoreStubCompiler compiler(isolate_, strict_mode);
  Handle<Code> code = compiler.CompileStoreGlobal(receiver, cell, name);
  PROFILE(isolate_, CodeCreateEvent(Logger::STORE_IC_TAG, *code, *name));
  GDBJIT(AddCode(GDBJITInterface::STORE_IC, *name, *code));
  JSObject::UpdateMapCodeCache(receiver, name, code);
  return code;
}


Handle<Code> StubCache::ComputeStoreCallback(Handle<String> name,
                                             Handle<JSObject> receiver,
                                             Handle<AccessorInfo> callback,
                                             StrictModeFlag strict_mode) {
  ASSERT(v8::ToCData<Address>(callback->setter()) != 0);
  Code::Flags flags = Code::ComputeMonomorphicFlags(
      Code::STORE_IC, Code::CALLBACKS, strict_mode);
  Handle<Object> probe(receiver->map()->FindInCodeCache(*name, flags));
  if (probe->IsCode()) return Handle<Code>::cast(probe);

  StoreStubCompiler compiler(isolate_, strict_mode);
  Handle<Code> code = compiler.CompileStoreCallback(receiver, callback, name);
  PROFILE(isolate_, CodeCreateEvent(Logger::STORE_IC_TAG, *code, *name));
  GDBJIT(AddCode(GDBJITInterface::STORE_IC, *name, *code));
  JSObject::UpdateMapCodeCache(receiver, name, code);
  return code;
}


Handle<Code> StubCache::ComputeStoreViaSetter(Handle<String> name,
                                              Handle<JSObject> receiver,
                                              Handle<JSObject> holder,
                                              Handle<JSFunction> setter,
                                              StrictModeFlag strict_mode) {
  Code::Flags flags = Code::ComputeMonomorphicFlags(
      Code::STORE_IC, Code::CALLBACKS, strict_mode);
  Handle<Object> probe(receiver->map()->FindInCodeCache(*name, flags));
  if (probe->IsCode()) return Handle<Code>::cast(probe);

  StoreStubCompiler compiler(isolate_, strict_mode);
  Handle<Code> code =
      compiler.CompileStoreViaSetter(name, receiver, holder, setter);
  PROFILE(isolate_, CodeCreateEvent(Logger::STORE_IC_TAG, *code, *name));
  GDBJIT(AddCode(GDBJITInterface::STORE_IC, *name, *code));
  JSObject::UpdateMapCodeCache(receiver, name, code);
  return code;
}


Handle<Code> StubCache::ComputeStoreInterceptor(Handle<String> name,
                                                Handle<JSObject> receiver,
                                                StrictModeFlag strict_mode) {
  Code::Flags flags = Code::ComputeMonomorphicFlags(
      Code::STORE_IC, Code::INTERCEPTOR, strict_mode);
  Handle<Object> probe(receiver->map()->FindInCodeCache(*name, flags));
  if (probe->IsCode()) return Handle<Code>::cast(probe);

  StoreStubCompiler compiler(isolate_, strict_mode);
  Handle<Code> code = compiler.CompileStoreInterceptor(receiver, name);
  PROFILE(isolate_, CodeCreateEvent(Logger::STORE_IC_TAG, *code, *name));
  GDBJIT(AddCode(GDBJITInterface::STORE_IC, *name, *code));
  JSObject::UpdateMapCodeCache(receiver, name, code);
  return code;
}

Handle<Code> StubCache::ComputeKeyedStoreField(Handle<String> name,
                                               Handle<JSObject> receiver,
                                               int field_index,
                                               Handle<Map> transition,
                                               StrictModeFlag strict_mode) {
  Code::StubType type =
      (transition.is_null()) ? Code::FIELD : Code::MAP_TRANSITION;
  Code::Flags flags = Code::ComputeMonomorphicFlags(
      Code::KEYED_STORE_IC, type, strict_mode);
  Handle<Object> probe(receiver->map()->FindInCodeCache(*name, flags));
  if (probe->IsCode()) return Handle<Code>::cast(probe);

  KeyedStoreStubCompiler compiler(isolate(), strict_mode,
                                  DO_NOT_ALLOW_JSARRAY_GROWTH);
  Handle<Code> code =
      compiler.CompileStoreField(receiver, field_index, transition, name);
  PROFILE(isolate_, CodeCreateEvent(Logger::KEYED_STORE_IC_TAG, *code, *name));
  GDBJIT(AddCode(GDBJITInterface::KEYED_STORE_IC, *name, *code));
  JSObject::UpdateMapCodeCache(receiver, name, code);
  return code;
}


#define CALL_LOGGER_TAG(kind, type) \
    (kind == Code::CALL_IC ? Logger::type : Logger::KEYED_##type)

Handle<Code> StubCache::ComputeCallConstant(int argc,
                                            Code::Kind kind,
                                            Code::ExtraICState extra_state,
                                            Handle<String> name,
                                            Handle<Object> object,
                                            Handle<JSObject> holder,
                                            Handle<JSFunction> function) {
  // Compute the check type and the map.
  InlineCacheHolderFlag cache_holder =
      IC::GetCodeCacheForObject(*object, *holder);
  Handle<JSObject> map_holder(IC::GetCodeCacheHolder(*object, cache_holder));

  // Compute check type based on receiver/holder.
  CheckType check = RECEIVER_MAP_CHECK;
  if (object->IsString()) {
    check = STRING_CHECK;
  } else if (object->IsNumber()) {
    check = NUMBER_CHECK;
  } else if (object->IsBoolean()) {
    check = BOOLEAN_CHECK;
  }

  Code::Flags flags =
      Code::ComputeMonomorphicFlags(kind, Code::CONSTANT_FUNCTION, extra_state,
                                    cache_holder, argc);
  Handle<Object> probe(map_holder->map()->FindInCodeCache(*name, flags));
  if (probe->IsCode()) return Handle<Code>::cast(probe);

  CallStubCompiler compiler(isolate_, argc, kind, extra_state, cache_holder);
  Handle<Code> code =
      compiler.CompileCallConstant(object, holder, function, name, check);
  code->set_check_type(check);
  ASSERT_EQ(flags, code->flags());
  PROFILE(isolate_,
          CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_IC_TAG), *code, *name));
  GDBJIT(AddCode(GDBJITInterface::CALL_IC, *name, *code));
  JSObject::UpdateMapCodeCache(map_holder, name, code);
  return code;
}


Handle<Code> StubCache::ComputeCallField(int argc,
                                         Code::Kind kind,
                                         Code::ExtraICState extra_state,
                                         Handle<String> name,
                                         Handle<Object> object,
                                         Handle<JSObject> holder,
                                         int index) {
  // Compute the check type and the map.
  InlineCacheHolderFlag cache_holder =
      IC::GetCodeCacheForObject(*object, *holder);
  Handle<JSObject> map_holder(IC::GetCodeCacheHolder(*object, cache_holder));

  // TODO(1233596): We cannot do receiver map check for non-JS objects
  // because they may be represented as immediates without a
  // map. Instead, we check against the map in the holder.
  if (object->IsNumber() || object->IsBoolean() || object->IsString()) {
    object = holder;
  }

  Code::Flags flags =
      Code::ComputeMonomorphicFlags(kind, Code::FIELD, extra_state,
                                    cache_holder, argc);
  Handle<Object> probe(map_holder->map()->FindInCodeCache(*name, flags));
  if (probe->IsCode()) return Handle<Code>::cast(probe);

  CallStubCompiler compiler(isolate_, argc, kind, extra_state, cache_holder);
  Handle<Code> code =
      compiler.CompileCallField(Handle<JSObject>::cast(object),
                                holder, index, name);
  ASSERT_EQ(flags, code->flags());
  PROFILE(isolate_,
          CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_IC_TAG), *code, *name));
  GDBJIT(AddCode(GDBJITInterface::CALL_IC, *name, *code));
  JSObject::UpdateMapCodeCache(map_holder, name, code);
  return code;
}


Handle<Code> StubCache::ComputeCallInterceptor(int argc,
                                               Code::Kind kind,
                                               Code::ExtraICState extra_state,
                                               Handle<String> name,
                                               Handle<Object> object,
                                               Handle<JSObject> holder) {
  // Compute the check type and the map.
  InlineCacheHolderFlag cache_holder =
      IC::GetCodeCacheForObject(*object, *holder);
  Handle<JSObject> map_holder(IC::GetCodeCacheHolder(*object, cache_holder));

  // TODO(1233596): We cannot do receiver map check for non-JS objects
  // because they may be represented as immediates without a
  // map. Instead, we check against the map in the holder.
  if (object->IsNumber() || object->IsBoolean() || object->IsString()) {
    object = holder;
  }

  Code::Flags flags =
      Code::ComputeMonomorphicFlags(kind, Code::INTERCEPTOR, extra_state,
                                    cache_holder, argc);
  Handle<Object> probe(map_holder->map()->FindInCodeCache(*name, flags));
  if (probe->IsCode()) return Handle<Code>::cast(probe);

  CallStubCompiler compiler(isolate(), argc, kind, extra_state, cache_holder);
  Handle<Code> code =
      compiler.CompileCallInterceptor(Handle<JSObject>::cast(object),
                                      holder, name);
  ASSERT_EQ(flags, code->flags());
  PROFILE(isolate(),
          CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_IC_TAG), *code, *name));
  GDBJIT(AddCode(GDBJITInterface::CALL_IC, *name, *code));
  JSObject::UpdateMapCodeCache(map_holder, name, code);
  return code;
}


Handle<Code> StubCache::ComputeCallGlobal(int argc,
                                          Code::Kind kind,
                                          Code::ExtraICState extra_state,
                                          Handle<String> name,
                                          Handle<JSObject> receiver,
                                          Handle<GlobalObject> holder,
                                          Handle<JSGlobalPropertyCell> cell,
                                          Handle<JSFunction> function) {
  InlineCacheHolderFlag cache_holder =
      IC::GetCodeCacheForObject(*receiver, *holder);
  Handle<JSObject> map_holder(IC::GetCodeCacheHolder(*receiver, cache_holder));
  Code::Flags flags =
      Code::ComputeMonomorphicFlags(kind, Code::NORMAL, extra_state,
                                    cache_holder, argc);
  Handle<Object> probe(map_holder->map()->FindInCodeCache(*name, flags));
  if (probe->IsCode()) return Handle<Code>::cast(probe);

  CallStubCompiler compiler(isolate(), argc, kind, extra_state, cache_holder);
  Handle<Code> code =
      compiler.CompileCallGlobal(receiver, holder, cell, function, name);
  ASSERT_EQ(flags, code->flags());
  PROFILE(isolate(),
          CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_IC_TAG), *code, *name));
  GDBJIT(AddCode(GDBJITInterface::CALL_IC, *name, *code));
  JSObject::UpdateMapCodeCache(map_holder, name, code);
  return code;
}


static void FillCache(Isolate* isolate, Handle<Code> code) {
  Handle<UnseededNumberDictionary> dictionary =
      UnseededNumberDictionary::Set(isolate->factory()->non_monomorphic_cache(),
                                    code->flags(),
                                    code);
  isolate->heap()->public_set_non_monomorphic_cache(*dictionary);
}


Code* StubCache::FindCallInitialize(int argc,
                                    RelocInfo::Mode mode,
                                    Code::Kind kind) {
  Code::ExtraICState extra_state =
      CallICBase::StringStubState::encode(DEFAULT_STRING_STUB) |
      CallICBase::Contextual::encode(mode == RelocInfo::CODE_TARGET_CONTEXT);
  Code::Flags flags =
      Code::ComputeFlags(kind, UNINITIALIZED, extra_state, Code::NORMAL, argc);

  // Use raw_unchecked... so we don't get assert failures during GC.
  UnseededNumberDictionary* dictionary =
      isolate()->heap()->raw_unchecked_non_monomorphic_cache();
  int entry = dictionary->FindEntry(isolate(), flags);
  ASSERT(entry != -1);
  Object* code = dictionary->ValueAt(entry);
  // This might be called during the marking phase of the collector
  // hence the unchecked cast.
  return reinterpret_cast<Code*>(code);
}


Handle<Code> StubCache::ComputeCallInitialize(int argc,
                                              RelocInfo::Mode mode,
                                              Code::Kind kind) {
  Code::ExtraICState extra_state =
      CallICBase::StringStubState::encode(DEFAULT_STRING_STUB) |
      CallICBase::Contextual::encode(mode == RelocInfo::CODE_TARGET_CONTEXT);
  Code::Flags flags =
      Code::ComputeFlags(kind, UNINITIALIZED, extra_state, Code::NORMAL, argc);
  Handle<UnseededNumberDictionary> cache =
      isolate_->factory()->non_monomorphic_cache();
  int entry = cache->FindEntry(isolate_, flags);
  if (entry != -1) return Handle<Code>(Code::cast(cache->ValueAt(entry)));

  StubCompiler compiler(isolate_);
  Handle<Code> code = compiler.CompileCallInitialize(flags);
  FillCache(isolate_, code);
  return code;
}


Handle<Code> StubCache::ComputeCallInitialize(int argc, RelocInfo::Mode mode) {
  return ComputeCallInitialize(argc, mode, Code::CALL_IC);
}


Handle<Code> StubCache::ComputeKeyedCallInitialize(int argc) {
  return ComputeCallInitialize(argc, RelocInfo::CODE_TARGET,
                               Code::KEYED_CALL_IC);
}


Handle<Code> StubCache::ComputeCallPreMonomorphic(
    int argc,
    Code::Kind kind,
    Code::ExtraICState extra_state) {
  Code::Flags flags =
      Code::ComputeFlags(kind, PREMONOMORPHIC, extra_state, Code::NORMAL, argc);
  Handle<UnseededNumberDictionary> cache =
      isolate_->factory()->non_monomorphic_cache();
  int entry = cache->FindEntry(isolate_, flags);
  if (entry != -1) return Handle<Code>(Code::cast(cache->ValueAt(entry)));

  StubCompiler compiler(isolate_);
  Handle<Code> code = compiler.CompileCallPreMonomorphic(flags);
  FillCache(isolate_, code);
  return code;
}


Handle<Code> StubCache::ComputeCallNormal(int argc,
                                          Code::Kind kind,
                                          Code::ExtraICState extra_state) {
  Code::Flags flags =
      Code::ComputeFlags(kind, MONOMORPHIC, extra_state, Code::NORMAL, argc);
  Handle<UnseededNumberDictionary> cache =
      isolate_->factory()->non_monomorphic_cache();
  int entry = cache->FindEntry(isolate_, flags);
  if (entry != -1) return Handle<Code>(Code::cast(cache->ValueAt(entry)));

  StubCompiler compiler(isolate_);
  Handle<Code> code = compiler.CompileCallNormal(flags);
  FillCache(isolate_, code);
  return code;
}


Handle<Code> StubCache::ComputeCallArguments(int argc, Code::Kind kind) {
  ASSERT(kind == Code::KEYED_CALL_IC);
  Code::Flags flags =
      Code::ComputeFlags(kind, MEGAMORPHIC, Code::kNoExtraICState,
                         Code::NORMAL, argc);
  Handle<UnseededNumberDictionary> cache =
      isolate_->factory()->non_monomorphic_cache();
  int entry = cache->FindEntry(isolate_, flags);
  if (entry != -1) return Handle<Code>(Code::cast(cache->ValueAt(entry)));

  StubCompiler compiler(isolate_);
  Handle<Code> code = compiler.CompileCallArguments(flags);
  FillCache(isolate_, code);
  return code;
}


Handle<Code> StubCache::ComputeCallMegamorphic(
    int argc,
    Code::Kind kind,
    Code::ExtraICState extra_state) {
  Code::Flags flags =
      Code::ComputeFlags(kind, MEGAMORPHIC, extra_state,
                         Code::NORMAL, argc);
  Handle<UnseededNumberDictionary> cache =
      isolate_->factory()->non_monomorphic_cache();
  int entry = cache->FindEntry(isolate_, flags);
  if (entry != -1) return Handle<Code>(Code::cast(cache->ValueAt(entry)));

  StubCompiler compiler(isolate_);
  Handle<Code> code = compiler.CompileCallMegamorphic(flags);
  FillCache(isolate_, code);
  return code;
}


Handle<Code> StubCache::ComputeCallMiss(int argc,
                                        Code::Kind kind,
                                        Code::ExtraICState extra_state) {
  // MONOMORPHIC_PROTOTYPE_FAILURE state is used to make sure that miss stubs
  // and monomorphic stubs are not mixed up together in the stub cache.
  Code::Flags flags =
      Code::ComputeFlags(kind, MONOMORPHIC_PROTOTYPE_FAILURE, extra_state,
                         Code::NORMAL, argc, OWN_MAP);
  Handle<UnseededNumberDictionary> cache =
      isolate_->factory()->non_monomorphic_cache();
  int entry = cache->FindEntry(isolate_, flags);
  if (entry != -1) return Handle<Code>(Code::cast(cache->ValueAt(entry)));

  StubCompiler compiler(isolate_);
  Handle<Code> code = compiler.CompileCallMiss(flags);
  FillCache(isolate_, code);
  return code;
}


#ifdef ENABLE_DEBUGGER_SUPPORT
Handle<Code> StubCache::ComputeCallDebugBreak(int argc,
                                              Code::Kind kind) {
  // Extra IC state is irrelevant for debug break ICs. They jump to
  // the actual call ic to carry out the work.
  Code::Flags flags =
      Code::ComputeFlags(kind, DEBUG_BREAK, Code::kNoExtraICState,
                         Code::NORMAL, argc);
  Handle<UnseededNumberDictionary> cache =
      isolate_->factory()->non_monomorphic_cache();
  int entry = cache->FindEntry(isolate_, flags);
  if (entry != -1) return Handle<Code>(Code::cast(cache->ValueAt(entry)));

  StubCompiler compiler(isolate_);
  Handle<Code> code = compiler.CompileCallDebugBreak(flags);
  FillCache(isolate_, code);
  return code;
}


Handle<Code> StubCache::ComputeCallDebugPrepareStepIn(int argc,
                                                      Code::Kind kind) {
  // Extra IC state is irrelevant for debug break ICs. They jump to
  // the actual call ic to carry out the work.
  Code::Flags flags =
      Code::ComputeFlags(kind, DEBUG_PREPARE_STEP_IN, Code::kNoExtraICState,
                         Code::NORMAL, argc);
  Handle<UnseededNumberDictionary> cache =
      isolate_->factory()->non_monomorphic_cache();
  int entry = cache->FindEntry(isolate_, flags);
  if (entry != -1) return Handle<Code>(Code::cast(cache->ValueAt(entry)));

  StubCompiler compiler(isolate_);
  Handle<Code> code = compiler.CompileCallDebugPrepareStepIn(flags);
  FillCache(isolate_, code);
  return code;
}
#endif


void StubCache::Clear() {
  Code* empty = isolate_->builtins()->builtin(Builtins::kIllegal);
  for (int i = 0; i < kPrimaryTableSize; i++) {
    primary_[i].key = heap()->empty_string();
    primary_[i].value = empty;
  }
  for (int j = 0; j < kSecondaryTableSize; j++) {
    secondary_[j].key = heap()->empty_string();
    secondary_[j].value = empty;
  }
}


void StubCache::CollectMatchingMaps(SmallMapList* types,
                                    String* name,
                                    Code::Flags flags,
                                    Handle<Context> global_context,
                                    Zone* zone) {
  for (int i = 0; i < kPrimaryTableSize; i++) {
    if (primary_[i].key == name) {
      Map* map = primary_[i].value->FindFirstMap();
      // Map can be NULL, if the stub is constant function call
      // with a primitive receiver.
      if (map == NULL) continue;

      int offset = PrimaryOffset(name, flags, map);
      if (entry(primary_, offset) == &primary_[i] &&
          !TypeFeedbackOracle::CanRetainOtherContext(map, *global_context)) {
        types->Add(Handle<Map>(map), zone);
      }
    }
  }

  for (int i = 0; i < kSecondaryTableSize; i++) {
    if (secondary_[i].key == name) {
      Map* map = secondary_[i].value->FindFirstMap();
      // Map can be NULL, if the stub is constant function call
      // with a primitive receiver.
      if (map == NULL) continue;

      // Lookup in primary table and skip duplicates.
      int primary_offset = PrimaryOffset(name, flags, map);
      Entry* primary_entry = entry(primary_, primary_offset);
      if (primary_entry->key == name) {
        Map* primary_map = primary_entry->value->FindFirstMap();
        if (map == primary_map) continue;
      }

      // Lookup in secondary table and add matches.
      int offset = SecondaryOffset(name, flags, primary_offset);
      if (entry(secondary_, offset) == &secondary_[i] &&
          !TypeFeedbackOracle::CanRetainOtherContext(map, *global_context)) {
        types->Add(Handle<Map>(map), zone);
      }
    }
  }
}


// ------------------------------------------------------------------------
// StubCompiler implementation.


RUNTIME_FUNCTION(MaybeObject*, LoadCallbackProperty) {
  ASSERT(args[0]->IsJSObject());
  ASSERT(args[1]->IsJSObject());
  ASSERT(args[3]->IsSmi());
  AccessorInfo* callback = AccessorInfo::cast(args[4]);
  Address getter_address = v8::ToCData<Address>(callback->getter());
  v8::AccessorGetter fun = FUNCTION_CAST<v8::AccessorGetter>(getter_address);
  ASSERT(fun != NULL);
  ASSERT(callback->IsCompatibleReceiver(args[0]));
  v8::AccessorInfo info(&args[0]);
  HandleScope scope(isolate);
  v8::Handle<v8::Value> result;
  {
    // Leaving JavaScript.
    VMState state(isolate, EXTERNAL);
    ExternalCallbackScope call_scope(isolate, getter_address);
    result = fun(v8::Utils::ToLocal(args.at<String>(5)), info);
  }
  RETURN_IF_SCHEDULED_EXCEPTION(isolate);
  if (result.IsEmpty()) return HEAP->undefined_value();
  return *v8::Utils::OpenHandle(*result);
}


RUNTIME_FUNCTION(MaybeObject*, StoreCallbackProperty) {
  JSObject* recv = JSObject::cast(args[0]);
  AccessorInfo* callback = AccessorInfo::cast(args[1]);
  Address setter_address = v8::ToCData<Address>(callback->setter());
  v8::AccessorSetter fun = FUNCTION_CAST<v8::AccessorSetter>(setter_address);
  ASSERT(fun != NULL);
  ASSERT(callback->IsCompatibleReceiver(recv));
  Handle<String> name = args.at<String>(2);
  Handle<Object> value = args.at<Object>(3);
  HandleScope scope(isolate);
  LOG(isolate, ApiNamedPropertyAccess("store", recv, *name));
  CustomArguments custom_args(isolate, callback->data(), recv, recv);
  v8::AccessorInfo info(custom_args.end());
  {
    // Leaving JavaScript.
    VMState state(isolate, EXTERNAL);
    ExternalCallbackScope call_scope(isolate, setter_address);
    fun(v8::Utils::ToLocal(name), v8::Utils::ToLocal(value), info);
  }
  RETURN_IF_SCHEDULED_EXCEPTION(isolate);
  return *value;
}


static const int kAccessorInfoOffsetInInterceptorArgs = 2;


/**
 * Attempts to load a property with an interceptor (which must be present),
 * but doesn't search the prototype chain.
 *
 * Returns |Heap::no_interceptor_result_sentinel()| if interceptor doesn't
 * provide any value for the given name.
 */
RUNTIME_FUNCTION(MaybeObject*, LoadPropertyWithInterceptorOnly) {
  Handle<String> name_handle = args.at<String>(0);
  Handle<InterceptorInfo> interceptor_info = args.at<InterceptorInfo>(1);
  ASSERT(kAccessorInfoOffsetInInterceptorArgs == 2);
  ASSERT(args[2]->IsJSObject());  // Receiver.
  ASSERT(args[3]->IsJSObject());  // Holder.
  ASSERT(args[5]->IsSmi());  // Isolate.
  ASSERT(args.length() == 6);

  Address getter_address = v8::ToCData<Address>(interceptor_info->getter());
  v8::NamedPropertyGetter getter =
      FUNCTION_CAST<v8::NamedPropertyGetter>(getter_address);
  ASSERT(getter != NULL);

  {
    // Use the interceptor getter.
    v8::AccessorInfo info(args.arguments() -
                          kAccessorInfoOffsetInInterceptorArgs);
    HandleScope scope(isolate);
    v8::Handle<v8::Value> r;
    {
      // Leaving JavaScript.
      VMState state(isolate, EXTERNAL);
      r = getter(v8::Utils::ToLocal(name_handle), info);
    }
    RETURN_IF_SCHEDULED_EXCEPTION(isolate);
    if (!r.IsEmpty()) {
      return *v8::Utils::OpenHandle(*r);
    }
  }

  return isolate->heap()->no_interceptor_result_sentinel();
}


static MaybeObject* ThrowReferenceError(String* name) {
  // If the load is non-contextual, just return the undefined result.
  // Note that both keyed and non-keyed loads may end up here, so we
  // can't use either LoadIC or KeyedLoadIC constructors.
  IC ic(IC::NO_EXTRA_FRAME, Isolate::Current());
  ASSERT(ic.target()->is_load_stub() || ic.target()->is_keyed_load_stub());
  if (!ic.SlowIsContextual()) return HEAP->undefined_value();

  // Throw a reference error.
  HandleScope scope;
  Handle<String> name_handle(name);
  Handle<Object> error =
      FACTORY->NewReferenceError("not_defined",
                                  HandleVector(&name_handle, 1));
  return Isolate::Current()->Throw(*error);
}


static MaybeObject* LoadWithInterceptor(Arguments* args,
                                        PropertyAttributes* attrs) {
  Handle<String> name_handle = args->at<String>(0);
  Handle<InterceptorInfo> interceptor_info = args->at<InterceptorInfo>(1);
  ASSERT(kAccessorInfoOffsetInInterceptorArgs == 2);
  Handle<JSObject> receiver_handle = args->at<JSObject>(2);
  Handle<JSObject> holder_handle = args->at<JSObject>(3);
  ASSERT(args->length() == 6);

  Isolate* isolate = receiver_handle->GetIsolate();

  Address getter_address = v8::ToCData<Address>(interceptor_info->getter());
  v8::NamedPropertyGetter getter =
      FUNCTION_CAST<v8::NamedPropertyGetter>(getter_address);
  ASSERT(getter != NULL);

  {
    // Use the interceptor getter.
    v8::AccessorInfo info(args->arguments() -
                          kAccessorInfoOffsetInInterceptorArgs);
    HandleScope scope(isolate);
    v8::Handle<v8::Value> r;
    {
      // Leaving JavaScript.
      VMState state(isolate, EXTERNAL);
      r = getter(v8::Utils::ToLocal(name_handle), info);
    }
    RETURN_IF_SCHEDULED_EXCEPTION(isolate);
    if (!r.IsEmpty()) {
      *attrs = NONE;
      return *v8::Utils::OpenHandle(*r);
    }
  }

  MaybeObject* result = holder_handle->GetPropertyPostInterceptor(
      *receiver_handle,
      *name_handle,
      attrs);
  RETURN_IF_SCHEDULED_EXCEPTION(isolate);
  return result;
}


/**
 * Loads a property with an interceptor performing post interceptor
 * lookup if interceptor failed.
 */
RUNTIME_FUNCTION(MaybeObject*, LoadPropertyWithInterceptorForLoad) {
  PropertyAttributes attr = NONE;
  Object* result;
  { MaybeObject* maybe_result = LoadWithInterceptor(&args, &attr);
    if (!maybe_result->ToObject(&result)) return maybe_result;
  }

  // If the property is present, return it.
  if (attr != ABSENT) return result;
  return ThrowReferenceError(String::cast(args[0]));
}


RUNTIME_FUNCTION(MaybeObject*, LoadPropertyWithInterceptorForCall) {
  PropertyAttributes attr;
  MaybeObject* result = LoadWithInterceptor(&args, &attr);
  RETURN_IF_SCHEDULED_EXCEPTION(isolate);
  // This is call IC. In this case, we simply return the undefined result which
  // will lead to an exception when trying to invoke the result as a
  // function.
  return result;
}


RUNTIME_FUNCTION(MaybeObject*, StoreInterceptorProperty) {
  ASSERT(args.length() == 4);
  JSObject* recv = JSObject::cast(args[0]);
  String* name = String::cast(args[1]);
  Object* value = args[2];
  ASSERT(args.smi_at(3) == kStrictMode || args.smi_at(3) == kNonStrictMode);
  StrictModeFlag strict_mode = static_cast<StrictModeFlag>(args.smi_at(3));
  ASSERT(recv->HasNamedInterceptor());
  PropertyAttributes attr = NONE;
  MaybeObject* result = recv->SetPropertyWithInterceptor(
      name, value, attr, strict_mode);
  return result;
}


RUNTIME_FUNCTION(MaybeObject*, KeyedLoadPropertyWithInterceptor) {
  JSObject* receiver = JSObject::cast(args[0]);
  ASSERT(args.smi_at(1) >= 0);
  uint32_t index = args.smi_at(1);
  return receiver->GetElementWithInterceptor(receiver, index);
}


Handle<Code> StubCompiler::CompileCallInitialize(Code::Flags flags) {
  int argc = Code::ExtractArgumentsCountFromFlags(flags);
  Code::Kind kind = Code::ExtractKindFromFlags(flags);
  Code::ExtraICState extra_state = Code::ExtractExtraICStateFromFlags(flags);
  if (kind == Code::CALL_IC) {
    CallIC::GenerateInitialize(masm(), argc, extra_state);
  } else {
    KeyedCallIC::GenerateInitialize(masm(), argc);
  }
  Handle<Code> code = GetCodeWithFlags(flags, "CompileCallInitialize");
  isolate()->counters()->call_initialize_stubs()->Increment();
  PROFILE(isolate(),
          CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_INITIALIZE_TAG),
                          *code, code->arguments_count()));
  GDBJIT(AddCode(GDBJITInterface::CALL_INITIALIZE, *code));
  return code;
}


Handle<Code> StubCompiler::CompileCallPreMonomorphic(Code::Flags flags) {
  int argc = Code::ExtractArgumentsCountFromFlags(flags);
  // The code of the PreMonomorphic stub is the same as the code
  // of the Initialized stub.  They just differ on the code object flags.
  Code::Kind kind = Code::ExtractKindFromFlags(flags);
  Code::ExtraICState extra_state = Code::ExtractExtraICStateFromFlags(flags);
  if (kind == Code::CALL_IC) {
    CallIC::GenerateInitialize(masm(), argc, extra_state);
  } else {
    KeyedCallIC::GenerateInitialize(masm(), argc);
  }
  Handle<Code> code = GetCodeWithFlags(flags, "CompileCallPreMonomorphic");
  isolate()->counters()->call_premonomorphic_stubs()->Increment();
  PROFILE(isolate(),
          CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_PRE_MONOMORPHIC_TAG),
                          *code, code->arguments_count()));
  GDBJIT(AddCode(GDBJITInterface::CALL_PRE_MONOMORPHIC, *code));
  return code;
}


Handle<Code> StubCompiler::CompileCallNormal(Code::Flags flags) {
  int argc = Code::ExtractArgumentsCountFromFlags(flags);
  Code::Kind kind = Code::ExtractKindFromFlags(flags);
  if (kind == Code::CALL_IC) {
    // Call normal is always with a explict receiver.
    ASSERT(!CallIC::Contextual::decode(
        Code::ExtractExtraICStateFromFlags(flags)));
    CallIC::GenerateNormal(masm(), argc);
  } else {
    KeyedCallIC::GenerateNormal(masm(), argc);
  }
  Handle<Code> code = GetCodeWithFlags(flags, "CompileCallNormal");
  isolate()->counters()->call_normal_stubs()->Increment();
  PROFILE(isolate(),
          CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_NORMAL_TAG),
                          *code, code->arguments_count()));
  GDBJIT(AddCode(GDBJITInterface::CALL_NORMAL, *code));
  return code;
}


Handle<Code> StubCompiler::CompileCallMegamorphic(Code::Flags flags) {
  int argc = Code::ExtractArgumentsCountFromFlags(flags);
  Code::Kind kind = Code::ExtractKindFromFlags(flags);
  Code::ExtraICState extra_state = Code::ExtractExtraICStateFromFlags(flags);
  if (kind == Code::CALL_IC) {
    CallIC::GenerateMegamorphic(masm(), argc, extra_state);
  } else {
    KeyedCallIC::GenerateMegamorphic(masm(), argc);
  }
  Handle<Code> code = GetCodeWithFlags(flags, "CompileCallMegamorphic");
  isolate()->counters()->call_megamorphic_stubs()->Increment();
  PROFILE(isolate(),
          CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_MEGAMORPHIC_TAG),
                          *code, code->arguments_count()));
  GDBJIT(AddCode(GDBJITInterface::CALL_MEGAMORPHIC, *code));
  return code;
}


Handle<Code> StubCompiler::CompileCallArguments(Code::Flags flags) {
  int argc = Code::ExtractArgumentsCountFromFlags(flags);
  KeyedCallIC::GenerateNonStrictArguments(masm(), argc);
  Handle<Code> code = GetCodeWithFlags(flags, "CompileCallArguments");
  PROFILE(isolate(),
          CodeCreateEvent(CALL_LOGGER_TAG(Code::ExtractKindFromFlags(flags),
                                          CALL_MEGAMORPHIC_TAG),
                          *code, code->arguments_count()));
  GDBJIT(AddCode(GDBJITInterface::CALL_MEGAMORPHIC, *code));
  return code;
}


Handle<Code> StubCompiler::CompileCallMiss(Code::Flags flags) {
  int argc = Code::ExtractArgumentsCountFromFlags(flags);
  Code::Kind kind = Code::ExtractKindFromFlags(flags);
  Code::ExtraICState extra_state = Code::ExtractExtraICStateFromFlags(flags);
  if (kind == Code::CALL_IC) {
    CallIC::GenerateMiss(masm(), argc, extra_state);
  } else {
    KeyedCallIC::GenerateMiss(masm(), argc);
  }
  Handle<Code> code = GetCodeWithFlags(flags, "CompileCallMiss");
  isolate()->counters()->call_megamorphic_stubs()->Increment();
  PROFILE(isolate(),
          CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_MISS_TAG),
                          *code, code->arguments_count()));
  GDBJIT(AddCode(GDBJITInterface::CALL_MISS, *code));
  return code;
}


#ifdef ENABLE_DEBUGGER_SUPPORT
Handle<Code> StubCompiler::CompileCallDebugBreak(Code::Flags flags) {
  Debug::GenerateCallICDebugBreak(masm());
  Handle<Code> code = GetCodeWithFlags(flags, "CompileCallDebugBreak");
  PROFILE(isolate(),
          CodeCreateEvent(CALL_LOGGER_TAG(Code::ExtractKindFromFlags(flags),
                                          CALL_DEBUG_BREAK_TAG),
                          *code, code->arguments_count()));
  return code;
}


Handle<Code> StubCompiler::CompileCallDebugPrepareStepIn(Code::Flags flags) {
  // Use the same code for the the step in preparations as we do for the
  // miss case.
  int argc = Code::ExtractArgumentsCountFromFlags(flags);
  Code::Kind kind = Code::ExtractKindFromFlags(flags);
  if (kind == Code::CALL_IC) {
    // For the debugger extra ic state is irrelevant.
    CallIC::GenerateMiss(masm(), argc, Code::kNoExtraICState);
  } else {
    KeyedCallIC::GenerateMiss(masm(), argc);
  }
  Handle<Code> code = GetCodeWithFlags(flags, "CompileCallDebugPrepareStepIn");
  PROFILE(isolate(),
          CodeCreateEvent(
              CALL_LOGGER_TAG(kind, CALL_DEBUG_PREPARE_STEP_IN_TAG),
              *code,
              code->arguments_count()));
  return code;
}
#endif  // ENABLE_DEBUGGER_SUPPORT

#undef CALL_LOGGER_TAG


Handle<Code> StubCompiler::GetCodeWithFlags(Code::Flags flags,
                                            const char* name) {
  // Create code object in the heap.
  CodeDesc desc;
  masm_.GetCode(&desc);
  Handle<Code> code = factory()->NewCode(desc, flags, masm_.CodeObject());
#ifdef ENABLE_DISASSEMBLER
  if (FLAG_print_code_stubs) code->Disassemble(name);
#endif
  return code;
}


Handle<Code> StubCompiler::GetCodeWithFlags(Code::Flags flags,
                                            Handle<String> name) {
  return (FLAG_print_code_stubs && !name.is_null())
      ? GetCodeWithFlags(flags, *name->ToCString())
      : GetCodeWithFlags(flags, reinterpret_cast<char*>(NULL));
}


void StubCompiler::LookupPostInterceptor(Handle<JSObject> holder,
                                         Handle<String> name,
                                         LookupResult* lookup) {
  holder->LocalLookupRealNamedProperty(*name, lookup);
  if (lookup->IsFound()) return;
  if (holder->GetPrototype()->IsNull()) return;
  holder->GetPrototype()->Lookup(*name, lookup);
}


Handle<Code> LoadStubCompiler::GetCode(Code::StubType type,
                                       Handle<String> name) {
  Code::Flags flags = Code::ComputeMonomorphicFlags(Code::LOAD_IC, type);
  Handle<Code> code = GetCodeWithFlags(flags, name);
  PROFILE(isolate(), CodeCreateEvent(Logger::LOAD_IC_TAG, *code, *name));
  GDBJIT(AddCode(GDBJITInterface::LOAD_IC, *name, *code));
  return code;
}


Handle<Code> KeyedLoadStubCompiler::GetCode(Code::StubType type,
                                            Handle<String> name,
                                            InlineCacheState state) {
  Code::Flags flags = Code::ComputeFlags(
      Code::KEYED_LOAD_IC, state, Code::kNoExtraICState, type);
  Handle<Code> code = GetCodeWithFlags(flags, name);
  PROFILE(isolate(), CodeCreateEvent(Logger::KEYED_LOAD_IC_TAG, *code, *name));
  GDBJIT(AddCode(GDBJITInterface::LOAD_IC, *name, *code));
  return code;
}


Handle<Code> StoreStubCompiler::GetCode(Code::StubType type,
                                        Handle<String> name) {
  Code::Flags flags =
      Code::ComputeMonomorphicFlags(Code::STORE_IC, type, strict_mode_);
  Handle<Code> code = GetCodeWithFlags(flags, name);
  PROFILE(isolate(), CodeCreateEvent(Logger::STORE_IC_TAG, *code, *name));
  GDBJIT(AddCode(GDBJITInterface::STORE_IC, *name, *code));
  return code;
}


Handle<Code> KeyedStoreStubCompiler::GetCode(Code::StubType type,
                                             Handle<String> name,
                                             InlineCacheState state) {
  Code::ExtraICState extra_state =
      Code::ComputeExtraICState(grow_mode_, strict_mode_);
  Code::Flags flags =
      Code::ComputeFlags(Code::KEYED_STORE_IC, state, extra_state, type);
  Handle<Code> code = GetCodeWithFlags(flags, name);
  PROFILE(isolate(), CodeCreateEvent(Logger::KEYED_STORE_IC_TAG, *code, *name));
  GDBJIT(AddCode(GDBJITInterface::KEYED_STORE_IC, *name, *code));
  return code;
}


void KeyedStoreStubCompiler::GenerateStoreDictionaryElement(
    MacroAssembler* masm) {
  KeyedStoreIC::GenerateSlow(masm);
}


CallStubCompiler::CallStubCompiler(Isolate* isolate,
                                   int argc,
                                   Code::Kind kind,
                                   Code::ExtraICState extra_state,
                                   InlineCacheHolderFlag cache_holder)
    : StubCompiler(isolate),
      arguments_(argc),
      kind_(kind),
      extra_state_(extra_state),
      cache_holder_(cache_holder) {
}


bool CallStubCompiler::HasCustomCallGenerator(Handle<JSFunction> function) {
  if (function->shared()->HasBuiltinFunctionId()) {
    BuiltinFunctionId id = function->shared()->builtin_function_id();
#define CALL_GENERATOR_CASE(name) if (id == k##name) return true;
    CUSTOM_CALL_IC_GENERATORS(CALL_GENERATOR_CASE)
#undef CALL_GENERATOR_CASE
  }

  CallOptimization optimization(function);
  return optimization.is_simple_api_call();
}


Handle<Code> CallStubCompiler::CompileCustomCall(
    Handle<Object> object,
    Handle<JSObject> holder,
    Handle<JSGlobalPropertyCell> cell,
    Handle<JSFunction> function,
    Handle<String> fname) {
  ASSERT(HasCustomCallGenerator(function));

  if (function->shared()->HasBuiltinFunctionId()) {
    BuiltinFunctionId id = function->shared()->builtin_function_id();
#define CALL_GENERATOR_CASE(name)                               \
    if (id == k##name) {                                        \
      return CallStubCompiler::Compile##name##Call(object,      \
                                                   holder,      \
                                                   cell,        \
                                                   function,    \
                                                   fname);      \
    }
    CUSTOM_CALL_IC_GENERATORS(CALL_GENERATOR_CASE)
#undef CALL_GENERATOR_CASE
  }
  CallOptimization optimization(function);
  ASSERT(optimization.is_simple_api_call());
  return CompileFastApiCall(optimization,
                            object,
                            holder,
                            cell,
                            function,
                            fname);
}


Handle<Code> CallStubCompiler::GetCode(Code::StubType type,
                                       Handle<String> name) {
  int argc = arguments_.immediate();
  Code::Flags flags = Code::ComputeMonomorphicFlags(kind_,
                                                    type,
                                                    extra_state_,
                                                    cache_holder_,
                                                    argc);
  return GetCodeWithFlags(flags, name);
}


Handle<Code> CallStubCompiler::GetCode(Handle<JSFunction> function) {
  Handle<String> function_name;
  if (function->shared()->name()->IsString()) {
    function_name = Handle<String>(String::cast(function->shared()->name()));
  }
  return GetCode(Code::CONSTANT_FUNCTION, function_name);
}


Handle<Code> ConstructStubCompiler::GetCode() {
  Code::Flags flags = Code::ComputeFlags(Code::STUB);
  Handle<Code> code = GetCodeWithFlags(flags, "ConstructStub");
  PROFILE(isolate(), CodeCreateEvent(Logger::STUB_TAG, *code, "ConstructStub"));
  GDBJIT(AddCode(GDBJITInterface::STUB, "ConstructStub", *code));
  return code;
}


CallOptimization::CallOptimization(LookupResult* lookup) {
  if (lookup->IsFound() &&
      lookup->IsCacheable() &&
      lookup->type() == CONSTANT_FUNCTION) {
    // We only optimize constant function calls.
    Initialize(Handle<JSFunction>(lookup->GetConstantFunction()));
  } else {
    Initialize(Handle<JSFunction>::null());
  }
}

CallOptimization::CallOptimization(Handle<JSFunction> function) {
  Initialize(function);
}


int CallOptimization::GetPrototypeDepthOfExpectedType(
    Handle<JSObject> object,
    Handle<JSObject> holder) const {
  ASSERT(is_simple_api_call());
  if (expected_receiver_type_.is_null()) return 0;
  int depth = 0;
  while (!object.is_identical_to(holder)) {
    if (object->IsInstanceOf(*expected_receiver_type_)) return depth;
    object = Handle<JSObject>(JSObject::cast(object->GetPrototype()));
    ++depth;
  }
  if (holder->IsInstanceOf(*expected_receiver_type_)) return depth;
  return kInvalidProtoDepth;
}


void CallOptimization::Initialize(Handle<JSFunction> function) {
  constant_function_ = Handle<JSFunction>::null();
  is_simple_api_call_ = false;
  expected_receiver_type_ = Handle<FunctionTemplateInfo>::null();
  api_call_info_ = Handle<CallHandlerInfo>::null();

  if (function.is_null() || !function->is_compiled()) return;

  constant_function_ = function;
  AnalyzePossibleApiFunction(function);
}


void CallOptimization::AnalyzePossibleApiFunction(Handle<JSFunction> function) {
  if (!function->shared()->IsApiFunction()) return;
  Handle<FunctionTemplateInfo> info(function->shared()->get_api_func_data());

  // Require a C++ callback.
  if (info->call_code()->IsUndefined()) return;
  api_call_info_ =
      Handle<CallHandlerInfo>(CallHandlerInfo::cast(info->call_code()));

  // Accept signatures that either have no restrictions at all or
  // only have restrictions on the receiver.
  if (!info->signature()->IsUndefined()) {
    Handle<SignatureInfo> signature =
        Handle<SignatureInfo>(SignatureInfo::cast(info->signature()));
    if (!signature->args()->IsUndefined()) return;
    if (!signature->receiver()->IsUndefined()) {
      expected_receiver_type_ =
          Handle<FunctionTemplateInfo>(
              FunctionTemplateInfo::cast(signature->receiver()));
    }
  }

  is_simple_api_call_ = true;
}


} }  // namespace v8::internal

/* [<][>][^][v][top][bottom][index][help] */