121efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch// Copyright 2016 the V8 project authors. All rights reserved.
221efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch// Use of this source code is governed by a BSD-style license that can be
321efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch// found in the LICENSE file.
421efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch
521efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch#include "src/wasm/wasm-debug.h"
621efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch
721efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch#include "src/assert-scope.h"
821efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch#include "src/debug/debug.h"
921efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch#include "src/factory.h"
1021efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch#include "src/isolate.h"
1121efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch#include "src/wasm/module-decoder.h"
1221efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch#include "src/wasm/wasm-module.h"
1321efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch
1421efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdochusing namespace v8::internal;
1521efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdochusing namespace v8::internal::wasm;
1621efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch
1721efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdochnamespace {
1821efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch
1921efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdochenum {
2021efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch  kWasmDebugInfoWasmObj,
2121efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch  kWasmDebugInfoWasmBytesHash,
2221efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch  kWasmDebugInfoFunctionByteOffsets,
2321efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch  kWasmDebugInfoNumEntries
2421efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch};
2521efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch
2621efce637eb329c94f1323b6a2334a1c977e1a9dBen MurdochByteArray *GetOrCreateFunctionOffsetTable(Handle<WasmDebugInfo> debug_info) {
2721efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch  Object *offset_table = debug_info->get(kWasmDebugInfoFunctionByteOffsets);
2821efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch  Isolate *isolate = debug_info->GetIsolate();
2921efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch  if (!offset_table->IsUndefined(isolate)) return ByteArray::cast(offset_table);
3021efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch
3121efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch  FunctionOffsetsResult function_offsets;
3221efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch  {
3321efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch    DisallowHeapAllocation no_gc;
3421efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch    SeqOneByteString *wasm_bytes =
3521efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch        wasm::GetWasmBytes(debug_info->wasm_object());
3621efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch    const byte *bytes_start = wasm_bytes->GetChars();
3721efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch    const byte *bytes_end = bytes_start + wasm_bytes->length();
3821efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch    function_offsets = wasm::DecodeWasmFunctionOffsets(bytes_start, bytes_end);
3921efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch  }
4021efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch  DCHECK(function_offsets.ok());
4121efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch  size_t array_size = 2 * kIntSize * function_offsets.val.size();
4221efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch  CHECK_LE(array_size, static_cast<size_t>(kMaxInt));
4321efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch  ByteArray *arr =
4421efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch      *isolate->factory()->NewByteArray(static_cast<int>(array_size));
4521efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch  int idx = 0;
4621efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch  for (std::pair<int, int> p : function_offsets.val) {
4721efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch    arr->set_int(idx++, p.first);
4821efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch    arr->set_int(idx++, p.second);
4921efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch  }
5021efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch  DCHECK_EQ(arr->length(), idx * kIntSize);
5121efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch  debug_info->set(kWasmDebugInfoFunctionByteOffsets, arr);
5221efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch
5321efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch  return arr;
5421efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch}
5521efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch
5621efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdochstd::pair<int, int> GetFunctionOffsetAndLength(Handle<WasmDebugInfo> debug_info,
5721efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch                                               int func_index) {
5821efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch  ByteArray *arr = GetOrCreateFunctionOffsetTable(debug_info);
5921efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch  DCHECK(func_index >= 0 && func_index < arr->length() / kIntSize / 2);
6021efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch
6121efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch  int offset = arr->get_int(2 * func_index);
6221efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch  int length = arr->get_int(2 * func_index + 1);
6321efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch  // Assert that it's distinguishable from the "illegal function index" return.
6421efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch  DCHECK(offset > 0 && length > 0);
6521efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch  return {offset, length};
6621efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch}
6721efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch
6821efce637eb329c94f1323b6a2334a1c977e1a9dBen MurdochVector<const uint8_t> GetFunctionBytes(Handle<WasmDebugInfo> debug_info,
6921efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch                                       int func_index) {
7021efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch  SeqOneByteString *module_bytes =
7121efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch      wasm::GetWasmBytes(debug_info->wasm_object());
7221efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch  std::pair<int, int> offset_and_length =
7321efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch      GetFunctionOffsetAndLength(debug_info, func_index);
7421efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch  return Vector<const uint8_t>(
7521efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch      module_bytes->GetChars() + offset_and_length.first,
7621efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch      offset_and_length.second);
7721efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch}
7821efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch
7921efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch}  // namespace
8021efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch
8121efce637eb329c94f1323b6a2334a1c977e1a9dBen MurdochHandle<WasmDebugInfo> WasmDebugInfo::New(Handle<JSObject> wasm) {
8221efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch  Isolate *isolate = wasm->GetIsolate();
8321efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch  Factory *factory = isolate->factory();
8421efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch  Handle<FixedArray> arr =
8521efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch      factory->NewFixedArray(kWasmDebugInfoNumEntries, TENURED);
8621efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch  arr->set(kWasmDebugInfoWasmObj, *wasm);
8721efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch  int hash = 0;
8821efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch  Handle<SeqOneByteString> wasm_bytes(GetWasmBytes(*wasm), isolate);
8921efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch  {
9021efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch    DisallowHeapAllocation no_gc;
9121efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch    hash = StringHasher::HashSequentialString(
9221efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch        wasm_bytes->GetChars(), wasm_bytes->length(), kZeroHashSeed);
9321efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch  }
9421efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch  Handle<Object> hash_obj = factory->NewNumberFromInt(hash, TENURED);
9521efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch  arr->set(kWasmDebugInfoWasmBytesHash, *hash_obj);
9621efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch
9721efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch  return Handle<WasmDebugInfo>::cast(arr);
9821efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch}
9921efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch
10021efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdochbool WasmDebugInfo::IsDebugInfo(Object *object) {
10121efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch  if (!object->IsFixedArray()) return false;
10221efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch  FixedArray *arr = FixedArray::cast(object);
10321efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch  Isolate *isolate = arr->GetIsolate();
10421efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch  return arr->length() == kWasmDebugInfoNumEntries &&
10521efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch         IsWasmObject(arr->get(kWasmDebugInfoWasmObj)) &&
10621efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch         arr->get(kWasmDebugInfoWasmBytesHash)->IsNumber() &&
10721efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch         (arr->get(kWasmDebugInfoFunctionByteOffsets)->IsUndefined(isolate) ||
10821efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch          arr->get(kWasmDebugInfoFunctionByteOffsets)->IsByteArray());
10921efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch}
11021efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch
11121efce637eb329c94f1323b6a2334a1c977e1a9dBen MurdochWasmDebugInfo *WasmDebugInfo::cast(Object *object) {
11221efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch  DCHECK(IsDebugInfo(object));
11321efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch  return reinterpret_cast<WasmDebugInfo *>(object);
11421efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch}
11521efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch
11621efce637eb329c94f1323b6a2334a1c977e1a9dBen MurdochJSObject *WasmDebugInfo::wasm_object() {
11721efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch  return JSObject::cast(get(kWasmDebugInfoWasmObj));
11821efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch}
11921efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch
12021efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdochbool WasmDebugInfo::SetBreakPoint(int byte_offset) {
12121efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch  // TODO(clemensh): Implement this.
12221efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch  return false;
12321efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch}
12421efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch
12521efce637eb329c94f1323b6a2334a1c977e1a9dBen MurdochHandle<String> WasmDebugInfo::DisassembleFunction(
12621efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch    Handle<WasmDebugInfo> debug_info, int func_index) {
12721efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch  std::ostringstream disassembly_os;
12821efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch
12921efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch  {
13021efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch    Vector<const uint8_t> bytes_vec = GetFunctionBytes(debug_info, func_index);
13121efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch    DisallowHeapAllocation no_gc;
13221efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch
13321efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch    base::AccountingAllocator allocator;
13421efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch    bool ok = PrintAst(
13521efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch        &allocator, FunctionBodyForTesting(bytes_vec.start(), bytes_vec.end()),
13621efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch        disassembly_os, nullptr);
13721efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch    DCHECK(ok);
13821efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch    USE(ok);
13921efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch  }
14021efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch
14121efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch  // Unfortunately, we have to copy the string here.
14221efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch  std::string code_str = disassembly_os.str();
14321efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch  CHECK_LE(code_str.length(), static_cast<size_t>(kMaxInt));
14421efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch  Factory *factory = debug_info->GetIsolate()->factory();
14521efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch  Vector<const char> code_vec(code_str.data(),
14621efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch                              static_cast<int>(code_str.length()));
14721efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch  return factory->NewStringFromAscii(code_vec).ToHandleChecked();
14821efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch}
14921efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch
15021efce637eb329c94f1323b6a2334a1c977e1a9dBen MurdochHandle<FixedArray> WasmDebugInfo::GetFunctionOffsetTable(
15121efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch    Handle<WasmDebugInfo> debug_info, int func_index) {
15221efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch  class NullBuf : public std::streambuf {};
15321efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch  NullBuf null_buf;
15421efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch  std::ostream null_stream(&null_buf);
15521efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch
15621efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch  std::vector<std::tuple<uint32_t, int, int>> offset_table_vec;
15721efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch
15821efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch  {
15921efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch    Vector<const uint8_t> bytes_vec = GetFunctionBytes(debug_info, func_index);
16021efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch    DisallowHeapAllocation no_gc;
16121efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch
16221efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch    v8::base::AccountingAllocator allocator;
16321efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch    bool ok = PrintAst(
16421efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch        &allocator, FunctionBodyForTesting(bytes_vec.start(), bytes_vec.end()),
16521efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch        null_stream, &offset_table_vec);
16621efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch    DCHECK(ok);
16721efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch    USE(ok);
16821efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch  }
16921efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch
17021efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch  size_t arr_size = 3 * offset_table_vec.size();
17121efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch  CHECK_LE(arr_size, static_cast<size_t>(kMaxInt));
17221efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch  Factory *factory = debug_info->GetIsolate()->factory();
17321efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch  Handle<FixedArray> offset_table =
17421efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch      factory->NewFixedArray(static_cast<int>(arr_size), TENURED);
17521efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch
17621efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch  int idx = 0;
17721efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch  for (std::tuple<uint32_t, int, int> elem : offset_table_vec) {
17821efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch    offset_table->set(idx++, Smi::FromInt(std::get<0>(elem)));
17921efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch    offset_table->set(idx++, Smi::FromInt(std::get<1>(elem)));
18021efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch    offset_table->set(idx++, Smi::FromInt(std::get<2>(elem)));
18121efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch  }
18221efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch  DCHECK_EQ(idx, offset_table->length());
18321efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch
18421efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch  return offset_table;
18521efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch}
186