// Copyright (c) 2013, 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.

#ifndef RUNTIME_VM_HEAP_WEAK_TABLE_H_
#define RUNTIME_VM_HEAP_WEAK_TABLE_H_

#include "vm/globals.h"

#include "platform/assert.h"
#include "vm/lockers.h"
#include "vm/raw_object.h"

namespace dart {

class WeakTable {
 public:
  static constexpr intptr_t kNoValue = 0;

  WeakTable() : WeakTable(kMinSize) {}
  explicit WeakTable(intptr_t size) : used_(0), count_(0) {
    ASSERT(size >= 0);
    ASSERT(Utils::IsPowerOfTwo(kMinSize));
    if (size < kMinSize) {
      size = kMinSize;
    }
    // Get a max size that avoids overflows.
    const intptr_t kMaxSize =
        (kIntptrOne << (kBitsPerWord - 2)) / (kEntrySize * kWordSize);
    ASSERT(Utils::IsPowerOfTwo(kMaxSize));
    if (size > kMaxSize) {
      size = kMaxSize;
    }
    size_ = size;
    ASSERT(Utils::IsPowerOfTwo(size_));
    data_ = reinterpret_cast<intptr_t*>(malloc(size_ * kEntrySize * kWordSize));
    for (intptr_t i = 0; i < size_; i++) {
      data_[ObjectIndex(i)] = kNoEntry;
      data_[ValueIndex(i)] = kNoValue;
    }
  }

  ~WeakTable() { free(data_); }

  static WeakTable* NewFrom(WeakTable* original) {
    return new WeakTable(SizeFor(original->count(), original->size()));
  }

  intptr_t size() const { return size_; }
  intptr_t used() const { return used_; }
  intptr_t count() const { return count_; }

  // The following methods can be called concurrently and are guarded by a lock.

  intptr_t GetValue(ObjectPtr key) {
    MutexLocker ml(&mutex_);
    return GetValueExclusive(key);
  }

  void SetValue(ObjectPtr key, intptr_t val) {
    MutexLocker ml(&mutex_);
    return SetValueExclusive(key, val);
  }

  intptr_t SetValueIfNonExistent(ObjectPtr key, intptr_t val) {
    MutexLocker ml(&mutex_);
    const auto old_value = GetValueExclusive(key);
    if (old_value == kNoValue) {
      SetValueExclusive(key, val);
      return val;
    }
    return old_value;
  }

  // The following "exclusive" methods must only be called from call sites
  // which are known to have exclusive access to the weak table.
  //
  // This is mostly limited to GC related code (e.g. scavenger, marker, ...)

  bool IsValidEntryAtExclusive(intptr_t i) const {
    ASSERT((ValueAtExclusive(i) == 0 &&
            (data_[ObjectIndex(i)] == kNoEntry ||
             data_[ObjectIndex(i)] == kDeletedEntry)) ||
           (ValueAtExclusive(i) != 0 && data_[ObjectIndex(i)] != kNoEntry &&
            data_[ObjectIndex(i)] != kDeletedEntry));
    return (data_[ValueIndex(i)] != 0);
  }

  void InvalidateAtExclusive(intptr_t i) {
    ASSERT(IsValidEntryAtExclusive(i));
    SetValueAt(i, 0);
  }

  ObjectPtr ObjectAtExclusive(intptr_t i) const {
    ASSERT(i >= 0);
    ASSERT(i < size());
    return static_cast<ObjectPtr>(data_[ObjectIndex(i)]);
  }

  intptr_t ValueAtExclusive(intptr_t i) const {
    ASSERT(i >= 0);
    ASSERT(i < size());
    return data_[ValueIndex(i)];
  }

  void SetValueExclusive(ObjectPtr key, intptr_t val);

  intptr_t GetValueExclusive(ObjectPtr key) const {
    intptr_t mask = size() - 1;
    intptr_t idx = Hash(key) & mask;
    ObjectPtr obj = ObjectAtExclusive(idx);
    while (obj != static_cast<ObjectPtr>(kNoEntry)) {
      if (obj == key) {
        return ValueAtExclusive(idx);
      }
      idx = (idx + 1) & mask;
      obj = ObjectAtExclusive(idx);
    }
    ASSERT(ValueAtExclusive(idx) == 0);
    return kNoValue;
  }

  // Removes and returns the value associated with |key|. Returns 0 if there is
  // no value associated with |key|.
  intptr_t RemoveValueExclusive(ObjectPtr key) {
    intptr_t mask = size() - 1;
    intptr_t idx = Hash(key) & mask;
    ObjectPtr obj = ObjectAtExclusive(idx);
    while (obj != static_cast<ObjectPtr>(kNoEntry)) {
      if (obj == key) {
        intptr_t result = ValueAtExclusive(idx);
        InvalidateAtExclusive(idx);
        return result;
      }
      idx = (idx + 1) & mask;
      obj = ObjectAtExclusive(idx);
    }
    ASSERT(ValueAtExclusive(idx) == 0);
    return kNoValue;
  }

  void Forward(ObjectPointerVisitor* visitor);

  void Reset();

 private:
  enum {
    kObjectOffset = 0,
    kValueOffset,
    kEntrySize,
  };

  static const intptr_t kNoEntry = 1;       // Not a valid OOP.
  static const intptr_t kDeletedEntry = 3;  // Not a valid OOP.
  static const intptr_t kMinSize = 8;

  static intptr_t SizeFor(intptr_t count, intptr_t size);
  static intptr_t LimitFor(intptr_t size) {
    // Maintain a maximum of 75% fill rate.
    return 3 * (size / 4);
  }
  intptr_t limit() const { return LimitFor(size()); }

  intptr_t index(intptr_t i) const { return i * kEntrySize; }

  void set_used(intptr_t val) {
    ASSERT(val <= limit());
    used_ = val;
  }

  void set_count(intptr_t val) {
    ASSERT(val <= limit());
    ASSERT(val <= used());
    count_ = val;
  }

  intptr_t ObjectIndex(intptr_t i) const { return index(i) + kObjectOffset; }

  intptr_t ValueIndex(intptr_t i) const { return index(i) + kValueOffset; }

  ObjectPtr* ObjectPointerAt(intptr_t i) const {
    ASSERT(i >= 0);
    ASSERT(i < size());
    return reinterpret_cast<ObjectPtr*>(&data_[ObjectIndex(i)]);
  }

  void SetObjectAt(intptr_t i, ObjectPtr key) {
    ASSERT(i >= 0);
    ASSERT(i < size());
    data_[ObjectIndex(i)] = static_cast<intptr_t>(key);
  }

  void SetValueAt(intptr_t i, intptr_t val) {
    ASSERT(i >= 0);
    ASSERT(i < size());
    // Setting a value of 0 is equivalent to invalidating the entry.
    if (val == 0) {
      data_[ObjectIndex(i)] = kDeletedEntry;
      set_count(count() - 1);
    }
    data_[ValueIndex(i)] = val;
  }

  void Rehash();

  static uword Hash(ObjectPtr key) { return static_cast<uword>(key) * 92821; }

  Mutex mutex_;

  // data_ contains size_ tuples of key/value.
  intptr_t* data_;
  // size_ keeps the number of entries in data_. used_ maintains the number of
  // non-NULL entries and will trigger rehashing if needed. count_ stores the
  // number valid entries, and will determine the size_ after rehashing.
  intptr_t size_;
  intptr_t used_;
  intptr_t count_;

  DISALLOW_COPY_AND_ASSIGN(WeakTable);
};

}  // namespace dart

#endif  // RUNTIME_VM_HEAP_WEAK_TABLE_H_
