/*
 * Copyright 2022 WebAssembly Community Group participants
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "ir/memory-utils.h"
#include "support/stdckdint.h"
#include "wasm.h"

namespace wasm::MemoryUtils {

// When flattening, do not generate a massive segment that will likely just
// OOM.
static uint64_t MaxFlatMemorySize = 4ULL * 1024 * 1024 * 1024;

bool isSubType(const Memory& a, const Memory& b) {
  return a.shared == b.shared && a.addressType == b.addressType &&
         a.initial >= b.initial && a.max <= b.max &&
         a.pageSizeLog2 == b.pageSizeLog2;
}

bool flatten(Module& wasm) {
  // If there are no memories then they are already flat, in the empty sense.
  if (wasm.memories.empty()) {
    return true;
  }
  // Flatten does not currently have support for multimemory
  if (wasm.memories.size() != 1) {
    return false;
  }
  // The presence of any instruction that cares about segment identity is a
  // problem because flattening gets rid of that (when it merges them all into
  // one big segment).
  struct Scanner : public WalkerPass<
                     PostWalker<Scanner, UnifiedExpressionVisitor<Scanner>>> {
    std::atomic<bool>& noticesSegmentIdentity;

    Scanner(std::atomic<bool>& noticesSegmentIdentity)
      : noticesSegmentIdentity(noticesSegmentIdentity) {}

    std::unique_ptr<Pass> create() override {
      return std::make_unique<Scanner>(noticesSegmentIdentity);
    }

    void visitExpression(Expression* curr) {
#define DELEGATE_ID curr->_id

#define DELEGATE_START(id) [[maybe_unused]] auto* cast = curr->cast<id>();

#define DELEGATE_GET_FIELD(id, field) cast->field

#define DELEGATE_FIELD_TYPE(id, field)
#define DELEGATE_FIELD_HEAPTYPE(id, field)
#define DELEGATE_FIELD_CHILD(id, field)
#define DELEGATE_FIELD_OPTIONAL_CHILD(id, field)
#define DELEGATE_FIELD_INT(id, field)
#define DELEGATE_FIELD_LITERAL(id, field)
#define DELEGATE_FIELD_NAME(id, field)
#define DELEGATE_FIELD_SCOPE_NAME_DEF(id, field)
#define DELEGATE_FIELD_SCOPE_NAME_USE(id, field)
#define DELEGATE_FIELD_ADDRESS(id, field)

#define DELEGATE_FIELD_NAME_KIND(id, field, kind)                              \
  if (kind == ModuleItemKind::DataSegment) {                                   \
    noticesSegmentIdentity = true;                                             \
  }

#include "wasm-delegations-fields.def"
    }
  };

  std::atomic<bool> noticesSegmentIdentity = false;
  PassRunner runner(&wasm);
  Scanner scanner(noticesSegmentIdentity);
  scanner.setPassRunner(&runner);
  scanner.run(&wasm);
  scanner.runOnModuleCode(&runner, &wasm);
  if (noticesSegmentIdentity) {
    return false;
  }

  auto& dataSegments = wasm.dataSegments;

  if (dataSegments.size() == 0) {
    return true;
  }

  std::vector<char> data;
  for (auto& segment : dataSegments) {
    if (segment->isPassive()) {
      return false;
    }
    auto* offset = segment->offset->dynCast<Const>();
    if (!offset) {
      return false;
    }
  }

  // If we have more data than can fit in memory, we will trap anyhow, and it
  // makes no sense to flatten.
  auto& memory = wasm.memories[0];
  uint64_t memoryInitialSizeBytes;
  if (std::ckd_mul(&memoryInitialSizeBytes,
                   (uint64_t)memory->initial,
                   memory->pageSize())) {
    return false;
  }

  for (auto& segment : dataSegments) {
    auto* offset = segment->offset->dynCast<Const>();
    uint64_t start = offset->value.getUnsigned();
    uint64_t size = segment->data.size();
    uint64_t end;
    if (std::ckd_add(&end, start, size)) {
      return false;
    }
    if (end > memoryInitialSizeBytes || end > MaxFlatMemorySize) {
      return false;
    }
    if (end > data.size()) {
      data.resize(end);
    }
    std::copy(segment->data.begin(), segment->data.end(), data.begin() + start);
  }
  dataSegments[0]->offset->cast<Const>()->value =
    Literal::makeFromInt32(0, wasm.memories[0]->addressType);
  dataSegments[0]->data.swap(data);
  wasm.removeDataSegments(
    [&](DataSegment* curr) { return curr->name != dataSegments[0]->name; });

  return true;
}

} // namespace wasm::MemoryUtils
