// Copyright (c) 2018, the Dart project authors.  Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.

#include "vm/compiler/backend/slot.h"

#include "vm/compiler/backend/flow_graph_compiler.h"
#include "vm/compiler/backend/il.h"
#include "vm/compiler/compiler_state.h"
#include "vm/hash_map.h"
#include "vm/parser.h"
#include "vm/scopes.h"

namespace dart {

// Canonicalization cache for Slot objects.
//
// This cache is attached to the CompilerState to ensure that we preserve
// identity of Slot objects during each individual compilation.
class SlotCache : public ZoneAllocated {
 public:
  // Returns an instance of SlotCache for the current compilation.
  static SlotCache& Instance(Thread* thread) {
    auto result = thread->compiler_state().slot_cache();
    if (result == nullptr) {
      result = new (thread->zone()) SlotCache(thread);
      thread->compiler_state().set_slot_cache(result);
    }
    return *result;
  }

  const Slot& Canonicalize(const Slot& value) {
    auto result = fields_.LookupValue(&value);
    if (result == nullptr) {
      result = new (zone_) Slot(value);
      fields_.Insert(result);
    }
    return *result;
  }

 private:
  explicit SlotCache(Thread* thread)
      : zone_(thread->zone()), fields_(thread->zone()) {}

  Zone* const zone_;
  DirectChainedHashMap<PointerKeyValueTrait<const Slot> > fields_;
};

#define NATIVE_SLOT_NAME(C, F, id, M) Kind::k##C##_##F
#define NATIVE_TO_STR(C, F, id, M) #C "_" #F

const char* Slot::KindToCString(Kind k) {
  switch (k) {
#define NATIVE_CASE(C, U, F, id, M)                                            \
  case NATIVE_SLOT_NAME(C, F, id, M):                                          \
    return NATIVE_TO_STR(C, F, id, M);
    BOXED_NATIVE_SLOTS_LIST(NATIVE_CASE)
    UNBOXED_NATIVE_SLOTS_LIST(NATIVE_CASE)
#undef NATIVE_CASE
    case Kind::kTypeArguments:
      return "TypeArguments";
    case Kind::kCapturedVariable:
      return "CapturedVariable";
    case Kind::kDartField:
      return "DartField";
    default:
      UNREACHABLE();
      return nullptr;
  }
}

bool Slot::ParseKind(const char* str, Kind* out) {
  ASSERT(str != nullptr && out != nullptr);
#define NATIVE_CASE(C, U, F, id, M)                                            \
  if (strcmp(str, NATIVE_TO_STR(C, F, id, M)) == 0) {                          \
    *out = NATIVE_SLOT_NAME(C, F, id, M);                                      \
    return true;                                                               \
  }
  BOXED_NATIVE_SLOTS_LIST(NATIVE_CASE)
  UNBOXED_NATIVE_SLOTS_LIST(NATIVE_CASE)
#undef NATIVE_CASE
  if (strcmp(str, "TypeArguments") == 0) {
    *out = Kind::kTypeArguments;
    return true;
  }
  if (strcmp(str, "CapturedVariable") == 0) {
    *out = Kind::kCapturedVariable;
    return true;
  }
  if (strcmp(str, "DartField") == 0) {
    *out = Kind::kDartField;
    return true;
  }
  return false;
}

#undef NATIVE_TO_STR
#undef NATIVE_SLOT_NAME

static Representation CheckFit(Representation rep) {
  ASSERT(Boxing::Supports(rep));
  switch (rep) {
    case kUnboxedInt64:
    case kUnboxedInt32:
    case kUnboxedUint32:
      break;
    default:
      UNREACHABLE();
      break;
  }
  return rep;
}

static classid_t GetUnboxedNativeSlotCid(Representation rep) {
  ASSERT(Boxing::Supports(rep));
  if (Boxing::RequiresAllocation(rep)) {
    return Boxing::BoxCid(rep);
  }
#if defined(TARGET_ARCH_IS_64_BIT)
  // On 64-bit platforms, these always fit in Smis.
  if (rep == kUnboxedInt32 || rep == kUnboxedUint32) {
    return kSmiCid;
  }
#endif
  UNREACHABLE();
  return kIllegalCid;
}

const Slot& Slot::GetNativeSlot(Kind kind) {
  // There is a fixed statically known number of native slots so we cache
  // them statically.
  static const Slot fields[] = {
#define FIELD_FINAL (IsImmutableBit::encode(true))
#define FIELD_VAR (0)
#define DEFINE_BOXED_NATIVE_FIELD(ClassName, UnderlyingType, FieldName, cid,   \
                                  mutability)                                  \
  Slot(Kind::k##ClassName##_##FieldName, FIELD_##mutability, k##cid##Cid,      \
       compiler::target::ClassName::FieldName##_offset(),                      \
       #ClassName "." #FieldName, nullptr, kTagged),

      BOXED_NATIVE_SLOTS_LIST(DEFINE_BOXED_NATIVE_FIELD)

#undef DEFINE_BOXED_NATIVE_FIELD
#define DEFINE_UNBOXED_NATIVE_FIELD(ClassName, UnderlyingType, FieldName,      \
                                    representation, mutability)                \
  Slot(Kind::k##ClassName##_##FieldName, FIELD_##mutability,                   \
       GetUnboxedNativeSlotCid(kUnboxed##representation),                      \
       compiler::target::ClassName::FieldName##_offset(),                      \
       #ClassName "." #FieldName, nullptr,                                     \
       CheckFit(kUnboxed##representation)),

          UNBOXED_NATIVE_SLOTS_LIST(DEFINE_UNBOXED_NATIVE_FIELD)

#undef DEFINE_UNBOXED_NATIVE_FIELD
#undef FIELD_VAR
#undef FIELD_FINAL
  };

  ASSERT(static_cast<uint8_t>(kind) < ARRAY_SIZE(fields));
  return fields[static_cast<uint8_t>(kind)];
}

// Note: should only be called with cids of array-like classes.
const Slot& Slot::GetLengthFieldForArrayCid(intptr_t array_cid) {
  if (IsExternalTypedDataClassId(array_cid) || IsTypedDataClassId(array_cid) ||
      IsTypedDataViewClassId(array_cid)) {
    return GetNativeSlot(Kind::kTypedDataBase_length);
  }
  switch (array_cid) {
    case kGrowableObjectArrayCid:
      return GetNativeSlot(Kind::kGrowableObjectArray_length);

    case kOneByteStringCid:
    case kTwoByteStringCid:
    case kExternalOneByteStringCid:
    case kExternalTwoByteStringCid:
      return GetNativeSlot(Kind::kString_length);

    case kArrayCid:
    case kImmutableArrayCid:
      return GetNativeSlot(Kind::kArray_length);

    default:
      UNREACHABLE();
      return GetNativeSlot(Kind::kArray_length);
  }
}

const Slot& Slot::GetTypeArgumentsSlotAt(Thread* thread, intptr_t offset) {
  ASSERT(offset != Class::kNoTypeArguments);
  return SlotCache::Instance(thread).Canonicalize(Slot(
      Kind::kTypeArguments, IsImmutableBit::encode(true), kTypeArgumentsCid,
      offset, ":type_arguments", /*static_type=*/nullptr, kTagged));
}

const Slot& Slot::GetTypeArgumentsSlotFor(Thread* thread, const Class& cls) {
  return GetTypeArgumentsSlotAt(
      thread, compiler::target::Class::TypeArgumentsFieldOffset(cls));
}

const Slot& Slot::GetContextVariableSlotFor(Thread* thread,
                                            const LocalVariable& variable) {
  ASSERT(variable.is_captured());
  return SlotCache::Instance(thread).Canonicalize(
      Slot(Kind::kCapturedVariable,
           IsImmutableBit::encode(variable.is_final() && !variable.is_late()) |
               IsNullableBit::encode(true),
           kDynamicCid,
           compiler::target::Context::variable_offset(variable.index().value()),
           &variable.name(), &variable.type(), kTagged));
}

const Slot& Slot::GetTypeArgumentsIndexSlot(Thread* thread, intptr_t index) {
  const intptr_t offset =
      compiler::target::TypeArguments::type_at_offset(index);
  const Slot& slot =
      Slot(Kind::kTypeArgumentsIndex, IsImmutableBit::encode(true), kDynamicCid,
           offset, ":argument", /*static_type=*/nullptr, kTagged);
  return SlotCache::Instance(thread).Canonicalize(slot);
}

const Slot& Slot::Get(const Field& field,
                      const ParsedFunction* parsed_function) {
  Thread* thread = Thread::Current();
  Zone* zone = thread->zone();
  Representation rep = kTagged;
  intptr_t nullable_cid = kDynamicCid;
  bool is_nullable = true;

  if (field.has_pragma()) {
    const intptr_t cid = MethodRecognizer::ResultCidFromPragma(field);
    if (cid != kDynamicCid) {
      nullable_cid = cid;
      is_nullable = false;
    } else if (MethodRecognizer::HasNonNullableResultTypeFromPragma(field)) {
      is_nullable = false;
    }
  }

  AbstractType& type = AbstractType::ZoneHandle(zone, field.type());
  if (type.IsStrictlyNonNullable()) {
    is_nullable = false;
  }

  bool used_guarded_state = false;
  if (field.guarded_cid() != kIllegalCid &&
      field.guarded_cid() != kDynamicCid) {
    // Use guarded state if it is more precise then what we already have.
    if (nullable_cid == kDynamicCid) {
      nullable_cid = field.guarded_cid();
      used_guarded_state = true;
    }

    if (is_nullable && !field.is_nullable()) {
      is_nullable = false;
      used_guarded_state = true;
    }
  }

  if (field.needs_load_guard()) {
    // Should be kept in sync with LoadStaticFieldInstr::ComputeType.
    type = Type::DynamicType();
    nullable_cid = kDynamicCid;
    is_nullable = true;
    used_guarded_state = false;
  }

  if (field.is_non_nullable_integer()) {
    ASSERT(FLAG_precompiled_mode);
    is_nullable = false;
    if (FlowGraphCompiler::IsUnboxedField(field)) {
      rep = kUnboxedInt64;
    }
  }

  const Slot& slot = SlotCache::Instance(thread).Canonicalize(
      Slot(Kind::kDartField,
           IsImmutableBit::encode((field.is_final() && !field.is_late()) ||
                                  field.is_const()) |
               IsNullableBit::encode(is_nullable) |
               IsGuardedBit::encode(used_guarded_state),
           nullable_cid, compiler::target::Field::OffsetOf(field), &field,
           &type, rep));

  // If properties of this slot were based on the guarded state make sure
  // to add the field to the list of guarded fields. Note that during background
  // compilation we might have two field clones that have incompatible guarded
  // state - however both of these clones would correspond to the same slot.
  // That is why we check the is_guarded_field() property of the slot rather
  // than look at the current guarded state of the field, because current
  // guarded state of the field might be set to kDynamicCid, while it was
  // set to something more concrete when the slot was created.
  // Note that we could have created this slot during an unsuccessful inlining
  // attempt where we built and discarded the graph, in this case guarded
  // fields associated with that graph are also discarded. However the slot
  // itself stays behind in the compilation global cache. Thus we must always
  // try to add it to the list of guarded fields of the current function.
  if (slot.is_guarded_field()) {
    if (thread->isolate()->use_field_guards()) {
      ASSERT(parsed_function != nullptr);
      parsed_function->AddToGuardedFields(&slot.field());
    } else {
      // In precompiled mode we use guarded_cid field for type information
      // inferred by TFA.
      ASSERT(CompilerState::Current().is_aot());
    }
  }

  return slot;
}

CompileType Slot::ComputeCompileType() const {
  return CompileType::CreateNullable(is_nullable(), nullable_cid());
}

const AbstractType& Slot::static_type() const {
  return static_type_ != nullptr ? *static_type_ : Object::null_abstract_type();
}

const char* Slot::Name() const {
  if (IsLocalVariable()) {
    return DataAs<const String>()->ToCString();
  } else if (IsDartField()) {
    return String::Handle(field().name()).ToCString();
  } else {
    return DataAs<const char>();
  }
}

bool Slot::Equals(const Slot* other) const {
  if (kind_ != other->kind_) {
    return false;
  }

  switch (kind_) {
    case Kind::kTypeArguments:
    case Kind::kTypeArgumentsIndex:
      return (offset_in_bytes_ == other->offset_in_bytes_);

    case Kind::kCapturedVariable:
      return (offset_in_bytes_ == other->offset_in_bytes_) &&
             (flags_ == other->flags_) &&
             (DataAs<const String>()->raw() ==
              other->DataAs<const String>()->raw());

    case Kind::kDartField:
      return (offset_in_bytes_ == other->offset_in_bytes_) &&
             other->DataAs<const Field>()->Original() ==
                 DataAs<const Field>()->Original();

    default:
      UNREACHABLE();
      return false;
  }
}

intptr_t Slot::Hashcode() const {
  intptr_t result = (static_cast<int8_t>(kind_) * 63 + offset_in_bytes_) * 31;
  if (IsDartField()) {
    result += String::Handle(DataAs<const Field>()->name()).Hash();
  } else if (IsLocalVariable()) {
    result += DataAs<const String>()->Hash();
  }
  return result;
}

}  // namespace dart
