// 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.

#ifndef V8_LOOKUP_H_
#define V8_LOOKUP_H_

#include "src/factory.h"
#include "src/globals.h"
#include "src/isolate.h"
#include "src/objects.h"
#include "src/objects/descriptor-array.h"
#include "src/objects/map.h"

namespace v8 {
namespace internal {

class V8_EXPORT_PRIVATE LookupIterator final BASE_EMBEDDED {
 public:
  enum Configuration {
    // Configuration bits.
    kInterceptor = 1 << 0,
    kPrototypeChain = 1 << 1,

    // Convenience combinations of bits.
    OWN_SKIP_INTERCEPTOR = 0,
    OWN = kInterceptor,
    PROTOTYPE_CHAIN_SKIP_INTERCEPTOR = kPrototypeChain,
    PROTOTYPE_CHAIN = kPrototypeChain | kInterceptor,
    DEFAULT = PROTOTYPE_CHAIN
  };

  enum State {
    ACCESS_CHECK,
    INTEGER_INDEXED_EXOTIC,
    INTERCEPTOR,
    JSPROXY,
    NOT_FOUND,
    ACCESSOR,
    DATA,
    TRANSITION,
    // Set state_ to BEFORE_PROPERTY to ensure that the next lookup will be a
    // PROPERTY lookup.
    BEFORE_PROPERTY = INTERCEPTOR
  };

  LookupIterator(Handle<Object> receiver, Handle<Name> name,
                 Configuration configuration = DEFAULT)
      : LookupIterator(name->GetIsolate(), receiver, name, configuration) {}

  LookupIterator(Isolate* isolate, Handle<Object> receiver, Handle<Name> name,
                 Configuration configuration = DEFAULT)
      : LookupIterator(isolate, receiver, name, GetRoot(isolate, receiver),
                       configuration) {}

  LookupIterator(Handle<Object> receiver, Handle<Name> name,
                 Handle<JSReceiver> holder,
                 Configuration configuration = DEFAULT)
      : LookupIterator(name->GetIsolate(), receiver, name, holder,
                       configuration) {}

  LookupIterator(Isolate* isolate, Handle<Object> receiver, Handle<Name> name,
                 Handle<JSReceiver> holder,
                 Configuration configuration = DEFAULT)
      : configuration_(ComputeConfiguration(configuration, name)),
        interceptor_state_(InterceptorState::kUninitialized),
        property_details_(PropertyDetails::Empty()),
        isolate_(isolate),
        name_(isolate_->factory()->InternalizeName(name)),
        receiver_(receiver),
        initial_holder_(holder),
        // kMaxUInt32 isn't a valid index.
        index_(kMaxUInt32),
        number_(static_cast<uint32_t>(DescriptorArray::kNotFound)) {
#ifdef DEBUG
    uint32_t index;  // Assert that the name is not an array index.
    DCHECK(!name->AsArrayIndex(&index));
#endif  // DEBUG
    Start<false>();
  }

  LookupIterator(Isolate* isolate, Handle<Object> receiver, uint32_t index,
                 Configuration configuration = DEFAULT)
      : LookupIterator(isolate, receiver, index,
                       GetRoot(isolate, receiver, index), configuration) {}

  LookupIterator(Isolate* isolate, Handle<Object> receiver, uint32_t index,
                 Handle<JSReceiver> holder,
                 Configuration configuration = DEFAULT)
      : configuration_(configuration),
        interceptor_state_(InterceptorState::kUninitialized),
        property_details_(PropertyDetails::Empty()),
        isolate_(isolate),
        receiver_(receiver),
        initial_holder_(holder),
        index_(index),
        number_(static_cast<uint32_t>(DescriptorArray::kNotFound)) {
    // kMaxUInt32 isn't a valid index.
    DCHECK_NE(kMaxUInt32, index_);
    Start<true>();
  }

  static LookupIterator PropertyOrElement(
      Isolate* isolate, Handle<Object> receiver, Handle<Name> name,
      Configuration configuration = DEFAULT) {
    uint32_t index;
    if (name->AsArrayIndex(&index)) {
      LookupIterator it =
          LookupIterator(isolate, receiver, index, configuration);
      it.name_ = name;
      return it;
    }
    return LookupIterator(receiver, name, configuration);
  }

  static LookupIterator PropertyOrElement(
      Isolate* isolate, Handle<Object> receiver, Handle<Name> name,
      Handle<JSReceiver> holder, Configuration configuration = DEFAULT) {
    uint32_t index;
    if (name->AsArrayIndex(&index)) {
      LookupIterator it =
          LookupIterator(isolate, receiver, index, holder, configuration);
      it.name_ = name;
      return it;
    }
    return LookupIterator(receiver, name, holder, configuration);
  }

  static LookupIterator PropertyOrElement(
      Isolate* isolate, Handle<Object> receiver, Handle<Object> key,
      bool* success, Handle<JSReceiver> holder,
      Configuration configuration = DEFAULT);

  static LookupIterator PropertyOrElement(
      Isolate* isolate, Handle<Object> receiver, Handle<Object> key,
      bool* success, Configuration configuration = DEFAULT);

  static LookupIterator ForTransitionHandler(Isolate* isolate,
                                             Handle<Object> receiver,
                                             Handle<Name> name,
                                             Handle<Object> value,
                                             MaybeHandle<Object> handler,
                                             Handle<Map> transition_map);

  void Restart() {
    InterceptorState state = InterceptorState::kUninitialized;
    IsElement() ? RestartInternal<true>(state) : RestartInternal<false>(state);
  }

  Isolate* isolate() const { return isolate_; }
  State state() const { return state_; }

  Handle<Name> name() const {
    DCHECK(!IsElement());
    return name_;
  }
  Handle<Name> GetName() {
    if (name_.is_null()) {
      DCHECK(IsElement());
      name_ = factory()->Uint32ToString(index_);
    }
    return name_;
  }
  uint32_t index() const { return index_; }

  bool IsElement() const { return index_ != kMaxUInt32; }

  bool IsFound() const { return state_ != NOT_FOUND; }
  void Next();
  void NotFound() {
    has_property_ = false;
    state_ = NOT_FOUND;
  }

  Heap* heap() const { return isolate_->heap(); }
  Factory* factory() const { return isolate_->factory(); }
  Handle<Object> GetReceiver() const { return receiver_; }

  Handle<JSObject> GetStoreTarget() const {
    DCHECK(receiver_->IsJSObject());
    if (receiver_->IsJSGlobalProxy()) {
      Map* map = JSGlobalProxy::cast(*receiver_)->map();
      if (map->has_hidden_prototype()) {
        return handle(JSGlobalObject::cast(map->prototype()), isolate_);
      }
    }
    return Handle<JSObject>::cast(receiver_);
  }

  bool is_dictionary_holder() const { return !holder_->HasFastProperties(); }
  Handle<Map> transition_map() const {
    DCHECK_EQ(TRANSITION, state_);
    return Handle<Map>::cast(transition_);
  }
  Handle<PropertyCell> transition_cell() const {
    DCHECK_EQ(TRANSITION, state_);
    return Handle<PropertyCell>::cast(transition_);
  }
  template <class T>
  Handle<T> GetHolder() const {
    DCHECK(IsFound());
    return Handle<T>::cast(holder_);
  }

  bool HolderIsReceiver() const;
  bool HolderIsReceiverOrHiddenPrototype() const;

  bool check_prototype_chain() const {
    return (configuration_ & kPrototypeChain) != 0;
  }

  /* ACCESS_CHECK */
  bool HasAccess() const;

  /* PROPERTY */
  bool ExtendingNonExtensible(Handle<JSObject> receiver) {
    DCHECK(receiver.is_identical_to(GetStoreTarget()));
    return !receiver->map()->is_extensible() &&
           (IsElement() || !name_->IsPrivate());
  }
  void PrepareForDataProperty(Handle<Object> value);
  bool PrepareTransitionToDataProperty(Handle<JSObject> receiver,
                                       Handle<Object> value,
                                       PropertyAttributes attributes,
                                       Object::StoreFromKeyed store_mode);
  bool IsCacheableTransition() {
    DCHECK_EQ(TRANSITION, state_);
    return transition_->IsPropertyCell() ||
           (transition_map()->is_dictionary_map() &&
            !GetStoreTarget()->HasFastProperties()) ||
           transition_map()->GetBackPointer()->IsMap();
  }
  void ApplyTransitionToDataProperty(Handle<JSObject> receiver);
  void ReconfigureDataProperty(Handle<Object> value,
                               PropertyAttributes attributes);
  void Delete();
  void TransitionToAccessorProperty(Handle<Object> getter,
                                    Handle<Object> setter,
                                    PropertyAttributes attributes);
  void TransitionToAccessorPair(Handle<Object> pair,
                                PropertyAttributes attributes);
  PropertyDetails property_details() const {
    DCHECK(has_property_);
    return property_details_;
  }
  PropertyAttributes property_attributes() const {
    return property_details().attributes();
  }
  bool IsConfigurable() const { return property_details().IsConfigurable(); }
  bool IsReadOnly() const { return property_details().IsReadOnly(); }
  bool IsEnumerable() const { return property_details().IsEnumerable(); }
  Representation representation() const {
    return property_details().representation();
  }
  PropertyLocation location() const { return property_details().location(); }
  PropertyConstness constness() const { return property_details().constness(); }
  Handle<Map> GetFieldOwnerMap() const;
  FieldIndex GetFieldIndex() const;
  Handle<FieldType> GetFieldType() const;
  int GetFieldDescriptorIndex() const;
  int GetAccessorIndex() const;
  int GetConstantIndex() const;
  Handle<PropertyCell> GetPropertyCell() const;
  Handle<Object> GetAccessors() const;
  inline Handle<InterceptorInfo> GetInterceptor() const {
    DCHECK_EQ(INTERCEPTOR, state_);
    InterceptorInfo* result =
        IsElement() ? GetInterceptor<true>(JSObject::cast(*holder_))
                    : GetInterceptor<false>(JSObject::cast(*holder_));
    return handle(result, isolate_);
  }
  Handle<InterceptorInfo> GetInterceptorForFailedAccessCheck() const;
  Handle<Object> GetDataValue() const;
  void WriteDataValue(Handle<Object> value, bool initializing_store);
  inline void UpdateProtector() {
    if (IsElement()) return;
    // This list must be kept in sync with
    // CodeStubAssembler::HasAssociatedProtector!
    if (*name_ == heap()->is_concat_spreadable_symbol() ||
        *name_ == heap()->constructor_string() ||
        *name_ == heap()->species_symbol() ||
        *name_ == heap()->iterator_symbol()) {
      InternalUpdateProtector();
    }
  }

  // Lookup a 'cached' private property for an accessor.
  // If not found returns false and leaves the LookupIterator unmodified.
  bool TryLookupCachedProperty();
  bool LookupCachedProperty();

 private:
  // For |ForTransitionHandler|.
  LookupIterator(Isolate* isolate, Handle<Object> receiver, Handle<Name> name,
                 Handle<Map> transition_map, PropertyDetails details,
                 bool has_property);

  void InternalUpdateProtector();

  enum class InterceptorState {
    kUninitialized,
    kSkipNonMasking,
    kProcessNonMasking
  };

  Handle<Map> GetReceiverMap() const;

  MUST_USE_RESULT inline JSReceiver* NextHolder(Map* map);

  template <bool is_element>
  V8_EXPORT_PRIVATE void Start();
  template <bool is_element>
  void NextInternal(Map* map, JSReceiver* holder);
  template <bool is_element>
  inline State LookupInHolder(Map* map, JSReceiver* holder) {
    return map->IsSpecialReceiverMap()
               ? LookupInSpecialHolder<is_element>(map, holder)
               : LookupInRegularHolder<is_element>(map, holder);
  }
  template <bool is_element>
  State LookupInRegularHolder(Map* map, JSReceiver* holder);
  template <bool is_element>
  State LookupInSpecialHolder(Map* map, JSReceiver* holder);
  template <bool is_element>
  void RestartLookupForNonMaskingInterceptors() {
    RestartInternal<is_element>(InterceptorState::kProcessNonMasking);
  }
  template <bool is_element>
  void RestartInternal(InterceptorState interceptor_state);
  Handle<Object> FetchValue() const;
  bool IsConstFieldValueEqualTo(Object* value) const;
  template <bool is_element>
  void ReloadPropertyInformation();

  template <bool is_element>
  bool SkipInterceptor(JSObject* holder);
  template <bool is_element>
  inline InterceptorInfo* GetInterceptor(JSObject* holder) const {
    return is_element ? holder->GetIndexedInterceptor()
                      : holder->GetNamedInterceptor();
  }

  bool check_interceptor() const {
    return (configuration_ & kInterceptor) != 0;
  }
  int descriptor_number() const {
    DCHECK(!IsElement());
    DCHECK(has_property_);
    DCHECK(holder_->HasFastProperties());
    return number_;
  }
  int dictionary_entry() const {
    DCHECK(!IsElement());
    DCHECK(has_property_);
    DCHECK(!holder_->HasFastProperties());
    return number_;
  }

  static Configuration ComputeConfiguration(
      Configuration configuration, Handle<Name> name) {
    return name->IsPrivate() ? OWN_SKIP_INTERCEPTOR : configuration;
  }

  static Handle<JSReceiver> GetRootForNonJSReceiver(
      Isolate* isolate, Handle<Object> receiver, uint32_t index = kMaxUInt32);
  inline static Handle<JSReceiver> GetRoot(Isolate* isolate,
                                           Handle<Object> receiver,
                                           uint32_t index = kMaxUInt32) {
    if (receiver->IsJSReceiver()) return Handle<JSReceiver>::cast(receiver);
    return GetRootForNonJSReceiver(isolate, receiver, index);
  }

  State NotFound(JSReceiver* const holder) const;

  // If configuration_ becomes mutable, update
  // HolderIsReceiverOrHiddenPrototype.
  const Configuration configuration_;
  State state_;
  bool has_property_;
  InterceptorState interceptor_state_;
  PropertyDetails property_details_;
  Isolate* const isolate_;
  Handle<Name> name_;
  Handle<Object> transition_;
  const Handle<Object> receiver_;
  Handle<JSReceiver> holder_;
  const Handle<JSReceiver> initial_holder_;
  const uint32_t index_;
  uint32_t number_;
};


}  // namespace internal
}  // namespace v8

#endif  // V8_LOOKUP_H_
