// Copyright 2019 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 "test/wasm-api-tests/wasm-api-test.h"

#include "src/execution/isolate.h"
#include "src/wasm/c-api.h"
#include "src/wasm/module-decoder.h"
#include "src/wasm/wasm-engine.h"

#include <iostream>

namespace v8 {
namespace internal {
namespace wasm {

using ::wasm::Frame;
using ::wasm::Message;

namespace {

own<Trap> FailCallback(void* env, const Val args[], Val results[]) {
  Store* store = reinterpret_cast<Store*>(env);
  Message message = Message::make(std::string("callback abort"));
  return Trap::make(store, message);
}

void ExpectMessage(const char* expected, const Message& message) {
  size_t len = strlen(expected);
  EXPECT_EQ(len, message.size());
  EXPECT_EQ(0, strncmp(expected, message.get(), len));
}

}  // namespace

TEST_F(WasmCapiTest, Traps) {
  ValueType i32_type[] = {kWasmI32};
  FunctionSig sig(1, 0, i32_type);
  uint32_t callback_index = builder()->AddImport(CStrVector("callback"), &sig);
  byte code[] = {WASM_CALL_FUNCTION0(callback_index)};
  AddExportedFunction(CStrVector("callback"), code, sizeof(code), &sig);

  byte code2[] = {WASM_CALL_FUNCTION0(3)};
  AddExportedFunction(CStrVector("unreachable"), code2, sizeof(code2), &sig);
  // The first constant is a 4-byte dummy so that the {unreachable} trap
  // has a more interesting offset. This is called by code2.
  byte code3[] = {WASM_I32V_3(0), WASM_UNREACHABLE, WASM_I32V_1(1)};
  AddFunction(code3, sizeof(code3), &sig);

  own<FuncType> func_type =
      FuncType::make(ownvec<ValType>::make(),
                     ownvec<ValType>::make(ValType::make(::wasm::I32)));
  own<Func> cpp_callback = Func::make(store(), func_type.get(), FailCallback,
                                      reinterpret_cast<void*>(store()));
  Extern* imports[] = {cpp_callback.get()};
  Instantiate(imports);

  // Use internal machinery to parse the module to find the function offsets.
  // This makes the test more robust than hardcoding them.
  i::Isolate* isolate =
      reinterpret_cast<::wasm::StoreImpl*>(store())->i_isolate();
  ModuleResult result = DecodeWasmModule(
      WasmFeatures::All(), wire_bytes()->begin(), wire_bytes()->end(), false,
      ModuleOrigin::kWasmOrigin, isolate->counters(),
      isolate->metrics_recorder(), v8::metrics::Recorder::ContextId::Empty(),
      DecodingMethod::kSync, isolate->wasm_engine()->allocator());
  ASSERT_TRUE(result.ok());
  const WasmFunction* func1 = &result.value()->functions[1];
  const WasmFunction* func2 = &result.value()->functions[2];
  const WasmFunction* func3 = &result.value()->functions[3];
  const uint32_t func1_offset = func1->code.offset();
  const uint32_t func2_offset = func2->code.offset();
  const uint32_t func3_offset = func3->code.offset();

  Func* cpp_trapping_func = GetExportedFunction(0);
  own<Trap> cpp_trap = cpp_trapping_func->call();
  EXPECT_NE(nullptr, cpp_trap.get());
  ExpectMessage("Uncaught Error: callback abort", cpp_trap->message());
  own<Frame> frame = cpp_trap->origin();
  EXPECT_TRUE(frame->instance()->same(instance()));
  EXPECT_EQ(1u, frame->func_index());
  EXPECT_EQ(1u, frame->func_offset());
  EXPECT_EQ(func1_offset + frame->func_offset(), frame->module_offset());
  ownvec<Frame> trace = cpp_trap->trace();
  EXPECT_EQ(1u, trace.size());
  frame.reset(trace[0].release());
  EXPECT_TRUE(frame->instance()->same(instance()));
  EXPECT_EQ(1u, frame->func_index());
  EXPECT_EQ(1u, frame->func_offset());
  EXPECT_EQ(func1_offset + frame->func_offset(), frame->module_offset());

  Func* wasm_trapping_func = GetExportedFunction(1);
  own<Trap> wasm_trap = wasm_trapping_func->call();
  EXPECT_NE(nullptr, wasm_trap.get());
  ExpectMessage("Uncaught RuntimeError: unreachable", wasm_trap->message());
  frame = wasm_trap->origin();
  EXPECT_TRUE(frame->instance()->same(instance()));
  EXPECT_EQ(3u, frame->func_index());
  EXPECT_EQ(5u, frame->func_offset());
  EXPECT_EQ(func3_offset + frame->func_offset(), frame->module_offset());
  trace = wasm_trap->trace();
  EXPECT_EQ(2u, trace.size());

  frame.reset(trace[0].release());
  EXPECT_TRUE(frame->instance()->same(instance()));
  EXPECT_EQ(3u, frame->func_index());
  EXPECT_EQ(5u, frame->func_offset());
  EXPECT_EQ(func3_offset + frame->func_offset(), frame->module_offset());

  frame.reset(trace[1].release());
  EXPECT_TRUE(frame->instance()->same(instance()));
  EXPECT_EQ(2u, frame->func_index());
  EXPECT_EQ(1u, frame->func_offset());
  EXPECT_EQ(func2_offset + frame->func_offset(), frame->module_offset());
}

}  // namespace wasm
}  // namespace internal
}  // namespace v8
