// Copyright 2014 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "src/ic/handler-compiler.h"

#include "src/field-type.h"
#include "src/ic/call-optimization.h"
#include "src/ic/ic-inl.h"
#include "src/ic/ic.h"
#include "src/isolate-inl.h"

namespace v8 {
namespace internal {

Handle<Code> PropertyHandlerCompiler::Find(Handle<Name> name,
                                           Handle<Map> stub_holder,
                                           Code::Kind kind,
                                           CacheHolderFlag cache_holder) {
  Code::Flags flags = Code::ComputeHandlerFlags(kind, cache_holder);
  Code* code = stub_holder->LookupInCodeCache(*name, flags);
  if (code == nullptr) return Handle<Code>();
  return handle(code);
}


Handle<Code> NamedLoadHandlerCompiler::ComputeLoadNonexistent(
    Handle<Name> name, Handle<Map> receiver_map) {
  Isolate* isolate = name->GetIsolate();
  if (receiver_map->prototype()->IsNull(isolate)) {
    // TODO(jkummerow/verwaest): If there is no prototype and the property
    // is nonexistent, introduce a builtin to handle this (fast properties
    // -> return undefined, dictionary properties -> do negative lookup).
    return Handle<Code>();
  }
  CacheHolderFlag flag;
  Handle<Map> stub_holder_map =
      IC::GetHandlerCacheHolder(receiver_map, false, isolate, &flag);

  // If no dictionary mode 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 dictionary
  // mode objects involved, we need to do negative lookups in the stub and
  // therefore the stub will be specific to the name.
  Handle<Name> cache_name =
      receiver_map->is_dictionary_map()
          ? name
          : Handle<Name>::cast(isolate->factory()->nonexistent_symbol());
  Handle<Map> current_map = stub_holder_map;
  Handle<JSObject> last(JSObject::cast(receiver_map->prototype()));
  while (true) {
    if (current_map->is_dictionary_map()) cache_name = name;
    if (current_map->prototype()->IsNull(isolate)) break;
    if (name->IsPrivate()) {
      // TODO(verwaest): Use nonexistent_private_symbol.
      cache_name = name;
      if (!current_map->has_hidden_prototype()) break;
    }

    last = handle(JSObject::cast(current_map->prototype()));
    current_map = handle(last->map());
  }
  // Compile the stub that is either shared for all names or
  // name specific if there are global objects involved.
  Handle<Code> handler = PropertyHandlerCompiler::Find(
      cache_name, stub_holder_map, Code::LOAD_IC, flag);
  if (!handler.is_null()) return handler;

  TRACE_HANDLER_STATS(isolate, LoadIC_LoadNonexistent);
  NamedLoadHandlerCompiler compiler(isolate, receiver_map, last, flag);
  handler = compiler.CompileLoadNonexistent(cache_name);
  Map::UpdateCodeCache(stub_holder_map, cache_name, handler);
  return handler;
}


Handle<Code> PropertyHandlerCompiler::GetCode(Code::Kind kind,
                                              Handle<Name> name) {
  Code::Flags flags = Code::ComputeHandlerFlags(kind, cache_holder());
  Handle<Code> code = GetCodeWithFlags(flags, name);
  PROFILE(isolate(), CodeCreateEvent(CodeEventListener::HANDLER_TAG,
                                     AbstractCode::cast(*code), *name));
#ifdef DEBUG
  code->VerifyEmbeddedObjects();
#endif
  return code;
}


#define __ ACCESS_MASM(masm())


Register NamedLoadHandlerCompiler::FrontendHeader(Register object_reg,
                                                  Handle<Name> name,
                                                  Label* miss,
                                                  ReturnHolder return_what) {
  PrototypeCheckType check_type = SKIP_RECEIVER;
  int function_index = map()->IsPrimitiveMap()
                           ? map()->GetConstructorFunctionIndex()
                           : Map::kNoConstructorFunctionIndex;
  if (function_index != Map::kNoConstructorFunctionIndex) {
    GenerateDirectLoadGlobalFunctionPrototype(masm(), function_index,
                                              scratch1(), miss);
    Object* function = isolate()->native_context()->get(function_index);
    Object* prototype = JSFunction::cast(function)->instance_prototype();
    Handle<Map> map(JSObject::cast(prototype)->map());
    set_map(map);
    object_reg = scratch1();
    check_type = CHECK_ALL_MAPS;
  }

  // Check that the maps starting from the prototype haven't changed.
  return CheckPrototypes(object_reg, scratch1(), scratch2(), scratch3(), name,
                         miss, check_type, return_what);
}


// Frontend for store uses the name register. It has to be restored before a
// miss.
Register NamedStoreHandlerCompiler::FrontendHeader(Register object_reg,
                                                   Handle<Name> name,
                                                   Label* miss,
                                                   ReturnHolder return_what) {
  return CheckPrototypes(object_reg, this->name(), scratch1(), scratch2(), name,
                         miss, SKIP_RECEIVER, return_what);
}


Register PropertyHandlerCompiler::Frontend(Handle<Name> name) {
  Label miss;
  if (IC::ICUseVector(kind())) {
    PushVectorAndSlot();
  }
  Register reg = FrontendHeader(receiver(), name, &miss, RETURN_HOLDER);
  FrontendFooter(name, &miss);
  // The footer consumes the vector and slot from the stack if miss occurs.
  if (IC::ICUseVector(kind())) {
    DiscardVectorAndSlot();
  }
  return reg;
}


void PropertyHandlerCompiler::NonexistentFrontendHeader(Handle<Name> name,
                                                        Label* miss,
                                                        Register scratch1,
                                                        Register scratch2) {
  Register holder_reg;
  Handle<Map> last_map;
  if (holder().is_null()) {
    holder_reg = receiver();
    last_map = map();
    // If |type| has null as its prototype, |holder()| is
    // Handle<JSObject>::null().
    DCHECK(last_map->prototype() == isolate()->heap()->null_value());
  } else {
    last_map = handle(holder()->map());
    // This condition matches the branches below.
    bool need_holder =
        last_map->is_dictionary_map() && !last_map->IsJSGlobalObjectMap();
    holder_reg =
        FrontendHeader(receiver(), name, miss,
                       need_holder ? RETURN_HOLDER : DONT_RETURN_ANYTHING);
  }

  if (last_map->is_dictionary_map()) {
    if (last_map->IsJSGlobalObjectMap()) {
      Handle<JSGlobalObject> global =
          holder().is_null()
              ? Handle<JSGlobalObject>::cast(isolate()->global_object())
              : Handle<JSGlobalObject>::cast(holder());
      GenerateCheckPropertyCell(masm(), global, name, scratch1, miss);
    } else {
      if (!name->IsUniqueName()) {
        DCHECK(name->IsString());
        name = factory()->InternalizeString(Handle<String>::cast(name));
      }
      DCHECK(holder().is_null() ||
             holder()->property_dictionary()->FindEntry(name) ==
                 NameDictionary::kNotFound);
      GenerateDictionaryNegativeLookup(masm(), miss, holder_reg, name, scratch1,
                                       scratch2);
    }
  }
}


Handle<Code> NamedLoadHandlerCompiler::CompileLoadField(Handle<Name> name,
                                                        FieldIndex field) {
  Register reg = Frontend(name);
  __ Move(receiver(), reg);
  LoadFieldStub stub(isolate(), field);
  GenerateTailCall(masm(), stub.GetCode());
  return GetCode(kind(), name);
}


Handle<Code> NamedLoadHandlerCompiler::CompileLoadConstant(Handle<Name> name,
                                                           int constant_index) {
  Register reg = Frontend(name);
  __ Move(receiver(), reg);
  LoadConstantStub stub(isolate(), constant_index);
  GenerateTailCall(masm(), stub.GetCode());
  return GetCode(kind(), name);
}


Handle<Code> NamedLoadHandlerCompiler::CompileLoadNonexistent(
    Handle<Name> name) {
  Label miss;
  if (IC::ICUseVector(kind())) {
    DCHECK(kind() == Code::LOAD_IC);
    PushVectorAndSlot();
  }
  NonexistentFrontendHeader(name, &miss, scratch2(), scratch3());
  if (IC::ICUseVector(kind())) {
    DiscardVectorAndSlot();
  }
  GenerateLoadConstant(isolate()->factory()->undefined_value());
  FrontendFooter(name, &miss);
  return GetCode(kind(), name);
}


Handle<Code> NamedLoadHandlerCompiler::CompileLoadCallback(
    Handle<Name> name, Handle<AccessorInfo> callback) {
  Register reg = Frontend(name);
  if (FLAG_runtime_call_stats) {
    TailCallBuiltin(masm(), Builtins::kLoadIC_Slow);
  } else {
    GenerateLoadCallback(reg, callback);
  }
  return GetCode(kind(), name);
}


Handle<Code> NamedLoadHandlerCompiler::CompileLoadCallback(
    Handle<Name> name, const CallOptimization& call_optimization,
    int accessor_index) {
  DCHECK(call_optimization.is_simple_api_call());
  Register holder = Frontend(name);
  if (FLAG_runtime_call_stats) {
    TailCallBuiltin(masm(), Builtins::kLoadIC_Slow);
  } else {
    GenerateApiAccessorCall(masm(), call_optimization, map(), receiver(),
                            scratch2(), false, no_reg, holder, accessor_index);
  }
  return GetCode(kind(), name);
}


void NamedLoadHandlerCompiler::InterceptorVectorSlotPush(Register holder_reg) {
  if (IC::ICUseVector(kind())) {
    if (holder_reg.is(receiver())) {
      PushVectorAndSlot();
    } else {
      DCHECK(holder_reg.is(scratch1()));
      PushVectorAndSlot(scratch2(), scratch3());
    }
  }
}


void NamedLoadHandlerCompiler::InterceptorVectorSlotPop(Register holder_reg,
                                                        PopMode mode) {
  if (IC::ICUseVector(kind())) {
    if (mode == DISCARD) {
      DiscardVectorAndSlot();
    } else {
      if (holder_reg.is(receiver())) {
        PopVectorAndSlot();
      } else {
        DCHECK(holder_reg.is(scratch1()));
        PopVectorAndSlot(scratch2(), scratch3());
      }
    }
  }
}


Handle<Code> NamedLoadHandlerCompiler::CompileLoadInterceptor(
    LookupIterator* it) {
  // So far the most popular follow ups for interceptor loads are DATA and
  // AccessorInfo, so inline only them. Other cases may be added
  // later.
  bool inline_followup = false;
  switch (it->state()) {
    case LookupIterator::TRANSITION:
      UNREACHABLE();
    case LookupIterator::ACCESS_CHECK:
    case LookupIterator::INTERCEPTOR:
    case LookupIterator::JSPROXY:
    case LookupIterator::NOT_FOUND:
    case LookupIterator::INTEGER_INDEXED_EXOTIC:
      break;
    case LookupIterator::DATA:
      inline_followup =
          it->property_details().type() == DATA && !it->is_dictionary_holder();
      break;
    case LookupIterator::ACCESSOR: {
      Handle<Object> accessors = it->GetAccessors();
      if (accessors->IsAccessorInfo()) {
        Handle<AccessorInfo> info = Handle<AccessorInfo>::cast(accessors);
        inline_followup =
            info->getter() != NULL &&
            AccessorInfo::IsCompatibleReceiverMap(isolate(), info, map());
      } else if (accessors->IsAccessorPair()) {
        Handle<JSObject> property_holder(it->GetHolder<JSObject>());
        Handle<Object> getter(Handle<AccessorPair>::cast(accessors)->getter(),
                              isolate());
        if (!(getter->IsJSFunction() || getter->IsFunctionTemplateInfo())) {
          break;
        }
        if (!property_holder->HasFastProperties()) break;
        CallOptimization call_optimization(getter);
        Handle<Map> receiver_map = map();
        inline_followup = call_optimization.is_simple_api_call() &&
                          call_optimization.IsCompatibleReceiverMap(
                              receiver_map, property_holder);
      }
    }
  }

  Label miss;
  InterceptorVectorSlotPush(receiver());
  bool lost_holder_register = false;
  auto holder_orig = holder();
  // non masking interceptors must check the entire chain, so temporarily reset
  // the holder to be that last element for the FrontendHeader call.
  if (holder()->GetNamedInterceptor()->non_masking()) {
    DCHECK(!inline_followup);
    JSObject* last = *holder();
    PrototypeIterator iter(isolate(), last);
    while (!iter.IsAtEnd()) {
      lost_holder_register = true;
      // Casting to JSObject is fine here. The LookupIterator makes sure to
      // look behind non-masking interceptors during the original lookup, and
      // we wouldn't try to compile a handler if there was a Proxy anywhere.
      last = iter.GetCurrent<JSObject>();
      iter.Advance();
    }
    auto last_handle = handle(last);
    set_holder(last_handle);
  }
  Register reg = FrontendHeader(receiver(), it->name(), &miss, RETURN_HOLDER);
  // Reset the holder so further calculations are correct.
  set_holder(holder_orig);
  if (lost_holder_register) {
    if (*it->GetReceiver() == *holder()) {
      reg = receiver();
    } else {
      // Reload lost holder register.
      auto cell = isolate()->factory()->NewWeakCell(holder());
      __ LoadWeakValue(reg, cell, &miss);
    }
  }
  FrontendFooter(it->name(), &miss);
  InterceptorVectorSlotPop(reg);
  if (inline_followup) {
    // TODO(368): Compile in the whole chain: all the interceptors in
    // prototypes and ultimate answer.
    GenerateLoadInterceptorWithFollowup(it, reg);
  } else {
    GenerateLoadInterceptor(reg);
  }
  return GetCode(kind(), it->name());
}

void NamedLoadHandlerCompiler::GenerateLoadCallback(
    Register reg, Handle<AccessorInfo> callback) {
  DCHECK(receiver().is(ApiGetterDescriptor::ReceiverRegister()));
  __ Move(ApiGetterDescriptor::HolderRegister(), reg);
  // The callback is alive if this instruction is executed,
  // so the weak cell is not cleared and points to data.
  Handle<WeakCell> cell = isolate()->factory()->NewWeakCell(callback);
  __ GetWeakValue(ApiGetterDescriptor::CallbackRegister(), cell);

  CallApiGetterStub stub(isolate());
  __ TailCallStub(&stub);
}

void NamedLoadHandlerCompiler::GenerateLoadPostInterceptor(
    LookupIterator* it, Register interceptor_reg) {
  Handle<JSObject> real_named_property_holder(it->GetHolder<JSObject>());

  Handle<Map> holder_map(holder()->map());
  set_map(holder_map);
  set_holder(real_named_property_holder);

  Label miss;
  InterceptorVectorSlotPush(interceptor_reg);
  Register reg =
      FrontendHeader(interceptor_reg, it->name(), &miss, RETURN_HOLDER);
  FrontendFooter(it->name(), &miss);
  // We discard the vector and slot now because we don't miss below this point.
  InterceptorVectorSlotPop(reg, DISCARD);

  switch (it->state()) {
    case LookupIterator::ACCESS_CHECK:
    case LookupIterator::INTERCEPTOR:
    case LookupIterator::JSPROXY:
    case LookupIterator::NOT_FOUND:
    case LookupIterator::INTEGER_INDEXED_EXOTIC:
    case LookupIterator::TRANSITION:
      UNREACHABLE();
    case LookupIterator::DATA: {
      DCHECK_EQ(DATA, it->property_details().type());
      __ Move(receiver(), reg);
      LoadFieldStub stub(isolate(), it->GetFieldIndex());
      GenerateTailCall(masm(), stub.GetCode());
      break;
    }
    case LookupIterator::ACCESSOR:
      if (it->GetAccessors()->IsAccessorInfo()) {
        Handle<AccessorInfo> info =
            Handle<AccessorInfo>::cast(it->GetAccessors());
        DCHECK_NOT_NULL(info->getter());
        GenerateLoadCallback(reg, info);
      } else {
        Handle<Object> function = handle(
            AccessorPair::cast(*it->GetAccessors())->getter(), isolate());
        CallOptimization call_optimization(function);
        GenerateApiAccessorCall(masm(), call_optimization, holder_map,
                                receiver(), scratch2(), false, no_reg, reg,
                                it->GetAccessorIndex());
      }
  }
}

Handle<Code> NamedLoadHandlerCompiler::CompileLoadViaGetter(
    Handle<Name> name, int accessor_index, int expected_arguments) {
  Register holder = Frontend(name);
  GenerateLoadViaGetter(masm(), map(), receiver(), holder, accessor_index,
                        expected_arguments, scratch2());
  return GetCode(kind(), name);
}


// TODO(verwaest): Cleanup. holder() is actually the receiver.
Handle<Code> NamedStoreHandlerCompiler::CompileStoreTransition(
    Handle<Map> transition, Handle<Name> name) {
  Label miss;

  PushVectorAndSlot();

  // Check that we are allowed to write this.
  bool is_nonexistent = holder()->map() == transition->GetBackPointer();
  if (is_nonexistent) {
    // Find the top object.
    Handle<JSObject> last;
    PrototypeIterator::WhereToEnd end =
        name->IsPrivate() ? PrototypeIterator::END_AT_NON_HIDDEN
                          : PrototypeIterator::END_AT_NULL;
    PrototypeIterator iter(isolate(), holder(), kStartAtPrototype, end);
    while (!iter.IsAtEnd()) {
      last = PrototypeIterator::GetCurrent<JSObject>(iter);
      iter.Advance();
    }
    if (!last.is_null()) set_holder(last);
    NonexistentFrontendHeader(name, &miss, scratch1(), scratch2());
  } else {
    FrontendHeader(receiver(), name, &miss, DONT_RETURN_ANYTHING);
    DCHECK(holder()->HasFastProperties());
  }

  int descriptor = transition->LastAdded();
  Handle<DescriptorArray> descriptors(transition->instance_descriptors());
  PropertyDetails details = descriptors->GetDetails(descriptor);
  Representation representation = details.representation();
  DCHECK(!representation.IsNone());

  // Stub is never generated for objects that require access checks.
  DCHECK(!transition->is_access_check_needed());

  // Call to respective StoreTransitionStub.
  bool virtual_args = StoreTransitionHelper::HasVirtualSlotArg();
  Register map_reg = StoreTransitionHelper::MapRegister();

  if (details.type() == DATA_CONSTANT) {
    DCHECK(descriptors->GetValue(descriptor)->IsJSFunction());
    Register tmp =
        virtual_args ? VectorStoreICDescriptor::VectorRegister() : map_reg;
    GenerateRestoreMap(transition, tmp, scratch2(), &miss);
    GenerateConstantCheck(tmp, descriptor, value(), scratch2(), &miss);
    if (virtual_args) {
      // This will move the map from tmp into map_reg.
      RearrangeVectorAndSlot(tmp, map_reg);
    } else {
      PopVectorAndSlot();
    }
    GenerateRestoreName(name);
    StoreTransitionStub stub(isolate());
    GenerateTailCall(masm(), stub.GetCode());

  } else {
    if (representation.IsHeapObject()) {
      GenerateFieldTypeChecks(descriptors->GetFieldType(descriptor), value(),
                              &miss);
    }
    StoreTransitionStub::StoreMode store_mode =
        Map::cast(transition->GetBackPointer())->unused_property_fields() == 0
            ? StoreTransitionStub::ExtendStorageAndStoreMapAndValue
            : StoreTransitionStub::StoreMapAndValue;

    Register tmp =
        virtual_args ? VectorStoreICDescriptor::VectorRegister() : map_reg;
    GenerateRestoreMap(transition, tmp, scratch2(), &miss);
    if (virtual_args) {
      RearrangeVectorAndSlot(tmp, map_reg);
    } else {
      PopVectorAndSlot();
    }
    GenerateRestoreName(name);
    StoreTransitionStub stub(isolate(),
                             FieldIndex::ForDescriptor(*transition, descriptor),
                             representation, store_mode);
    GenerateTailCall(masm(), stub.GetCode());
  }

  GenerateRestoreName(&miss, name);
  PopVectorAndSlot();
  TailCallBuiltin(masm(), MissBuiltin(kind()));

  return GetCode(kind(), name);
}

bool NamedStoreHandlerCompiler::RequiresFieldTypeChecks(
    FieldType* field_type) const {
  return field_type->IsClass();
}


Handle<Code> NamedStoreHandlerCompiler::CompileStoreField(LookupIterator* it) {
  Label miss;
  DCHECK(it->representation().IsHeapObject());

  FieldType* field_type = *it->GetFieldType();
  bool need_save_restore = false;
  if (RequiresFieldTypeChecks(field_type)) {
    need_save_restore = IC::ICUseVector(kind());
    if (need_save_restore) PushVectorAndSlot();
    GenerateFieldTypeChecks(field_type, value(), &miss);
    if (need_save_restore) PopVectorAndSlot();
  }

  StoreFieldStub stub(isolate(), it->GetFieldIndex(), it->representation());
  GenerateTailCall(masm(), stub.GetCode());

  __ bind(&miss);
  if (need_save_restore) PopVectorAndSlot();
  TailCallBuiltin(masm(), MissBuiltin(kind()));
  return GetCode(kind(), it->name());
}


Handle<Code> NamedStoreHandlerCompiler::CompileStoreViaSetter(
    Handle<JSObject> object, Handle<Name> name, int accessor_index,
    int expected_arguments) {
  Register holder = Frontend(name);
  GenerateStoreViaSetter(masm(), map(), receiver(), holder, accessor_index,
                         expected_arguments, scratch2());

  return GetCode(kind(), name);
}


Handle<Code> NamedStoreHandlerCompiler::CompileStoreCallback(
    Handle<JSObject> object, Handle<Name> name,
    const CallOptimization& call_optimization, int accessor_index) {
  Register holder = Frontend(name);
  if (FLAG_runtime_call_stats) {
    GenerateRestoreName(name);
    TailCallBuiltin(masm(), Builtins::kStoreIC_Slow);
  } else {
    GenerateApiAccessorCall(masm(), call_optimization, handle(object->map()),
                            receiver(), scratch2(), true, value(), holder,
                            accessor_index);
  }
  return GetCode(kind(), name);
}


#undef __

void ElementHandlerCompiler::CompileElementHandlers(
    MapHandleList* receiver_maps, CodeHandleList* handlers) {
  for (int i = 0; i < receiver_maps->length(); ++i) {
    Handle<Map> receiver_map = receiver_maps->at(i);
    Handle<Code> cached_stub;

    if (receiver_map->IsStringMap()) {
      cached_stub = LoadIndexedStringStub(isolate()).GetCode();
    } else if (receiver_map->instance_type() < FIRST_JS_RECEIVER_TYPE) {
      cached_stub = isolate()->builtins()->KeyedLoadIC_Slow();
    } else {
      bool is_js_array = receiver_map->instance_type() == JS_ARRAY_TYPE;
      ElementsKind elements_kind = receiver_map->elements_kind();

      // No need to check for an elements-free prototype chain here, the
      // generated stub code needs to check that dynamically anyway.
      bool convert_hole_to_undefined =
          (is_js_array && elements_kind == FAST_HOLEY_ELEMENTS &&
           *receiver_map == isolate()->get_initial_js_array_map(elements_kind));

      if (receiver_map->has_indexed_interceptor() &&
          !receiver_map->GetIndexedInterceptor()->getter()->IsUndefined(
              isolate()) &&
          !receiver_map->GetIndexedInterceptor()->non_masking()) {
        cached_stub = LoadIndexedInterceptorStub(isolate()).GetCode();
      } else if (IsSloppyArgumentsElements(elements_kind)) {
        cached_stub = KeyedLoadSloppyArgumentsStub(isolate()).GetCode();
      } else if (IsFastElementsKind(elements_kind) ||
                 IsFixedTypedArrayElementsKind(elements_kind)) {
        cached_stub = LoadFastElementStub(isolate(), is_js_array, elements_kind,
                                          convert_hole_to_undefined).GetCode();
      } else {
        DCHECK(elements_kind == DICTIONARY_ELEMENTS);
        cached_stub = LoadDictionaryElementStub(isolate()).GetCode();
      }
    }

    handlers->Add(cached_stub);
  }
}
}  // namespace internal
}  // namespace v8
