wasm-module-sourcemap.cc 5.32 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
// 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 "src/wasm/wasm-module-sourcemap.h"

#include <algorithm>

#include "include/v8.h"
#include "src/api/api.h"
#include "src/base/vlq-base64.h"

namespace v8 {
namespace internal {
namespace wasm {

WasmModuleSourceMap::WasmModuleSourceMap(v8::Isolate* v8_isolate,
                                         v8::Local<v8::String> src_map_str) {
  v8::HandleScope scope(v8_isolate);
  v8::Local<v8::Context> context = v8::Context::New(v8_isolate);

  v8::Local<v8::Value> src_map_value;
  if (!v8::JSON::Parse(context, src_map_str).ToLocal(&src_map_value)) return;
  v8::Local<v8::Object> src_map_obj =
      v8::Local<v8::Object>::Cast(src_map_value);

  v8::Local<v8::Value> version_value, sources_value, mappings_value;
  bool has_valid_version =
      src_map_obj
30
          ->Get(context, v8::String::NewFromUtf8Literal(v8_isolate, "version"))
31 32 33 34 35 36 37 38 39
          .ToLocal(&version_value) &&
      version_value->IsUint32();
  uint32_t version = 0;
  if (!has_valid_version || !version_value->Uint32Value(context).To(&version) ||
      version != 3u)
    return;

  bool has_valid_sources =
      src_map_obj
40
          ->Get(context, v8::String::NewFromUtf8Literal(v8_isolate, "sources"))
41 42 43 44 45 46 47 48
          .ToLocal(&sources_value) &&
      sources_value->IsArray();
  if (!has_valid_sources) return;

  v8::Local<v8::Object> sources_arr =
      v8::Local<v8::Object>::Cast(sources_value);
  v8::Local<v8::Value> sources_len_value;
  if (!sources_arr
49
           ->Get(context, v8::String::NewFromUtf8Literal(v8_isolate, "length"))
50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70
           .ToLocal(&sources_len_value))
    return;
  uint32_t sources_len = 0;
  if (!sources_len_value->Uint32Value(context).To(&sources_len)) return;

  for (uint32_t i = 0; i < sources_len; ++i) {
    v8::Local<v8::Value> file_name_value;
    if (!sources_arr->Get(context, i).ToLocal(&file_name_value) ||
        !file_name_value->IsString())
      return;
    v8::Local<v8::String> file_name =
        v8::Local<v8::String>::Cast(file_name_value);
    auto file_name_sz = file_name->Utf8Length(v8_isolate);
    std::unique_ptr<char[]> file_name_buf(new char[file_name_sz + 1]);
    file_name->WriteUtf8(v8_isolate, file_name_buf.get());
    file_name_buf.get()[file_name_sz] = '\0';
    filenames.emplace_back(file_name_buf.get());
  }

  bool has_valid_mappings =
      src_map_obj
71
          ->Get(context, v8::String::NewFromUtf8Literal(v8_isolate, "mappings"))
72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156
          .ToLocal(&mappings_value) &&
      mappings_value->IsString();
  if (!has_valid_mappings) return;

  v8::Local<v8::String> mappings = v8::Local<v8::String>::Cast(mappings_value);
  int mappings_sz = mappings->Utf8Length(v8_isolate);
  std::unique_ptr<char[]> mappings_buf(new char[mappings_sz + 1]);
  mappings->WriteUtf8(v8_isolate, mappings_buf.get());
  mappings_buf.get()[mappings_sz] = '\0';

  valid_ = DecodeMapping(mappings_buf.get());
}

size_t WasmModuleSourceMap::GetSourceLine(size_t wasm_offset) const {
  std::vector<std::size_t>::const_iterator up =
      std::upper_bound(offsets.begin(), offsets.end(), wasm_offset);
  CHECK_NE(offsets.begin(), up);
  size_t source_idx = up - offsets.begin() - 1;
  return source_row[source_idx];
}

std::string WasmModuleSourceMap::GetFilename(size_t wasm_offset) const {
  std::vector<size_t>::const_iterator up =
      std::upper_bound(offsets.begin(), offsets.end(), wasm_offset);
  CHECK_NE(offsets.begin(), up);
  size_t offset_idx = up - offsets.begin() - 1;
  size_t filename_idx = file_idxs[offset_idx];
  return filenames[filename_idx];
}

bool WasmModuleSourceMap::HasSource(size_t start, size_t end) const {
  return start <= *(offsets.end() - 1) && end > *offsets.begin();
}

bool WasmModuleSourceMap::HasValidEntry(size_t start, size_t addr) const {
  std::vector<size_t>::const_iterator up =
      std::upper_bound(offsets.begin(), offsets.end(), addr);
  if (up == offsets.begin()) return false;
  size_t offset_idx = up - offsets.begin() - 1;
  size_t entry_offset = offsets[offset_idx];
  if (entry_offset < start) return false;
  return true;
}

bool WasmModuleSourceMap::DecodeMapping(const std::string& s) {
  size_t pos = 0, gen_col = 0, file_idx = 0, ori_line = 0;
  int32_t qnt = 0;

  while (pos < s.size()) {
    // Skip redundant commas.
    if (s[pos] == ',') {
      ++pos;
      continue;
    }
    if ((qnt = base::VLQBase64Decode(s.c_str(), s.size(), &pos)) ==
        std::numeric_limits<int32_t>::min())
      return false;
    gen_col += qnt;
    if ((qnt = base::VLQBase64Decode(s.c_str(), s.size(), &pos)) ==
        std::numeric_limits<int32_t>::min())
      return false;
    file_idx += qnt;
    if ((qnt = base::VLQBase64Decode(s.c_str(), s.size(), &pos)) ==
        std::numeric_limits<int32_t>::min())
      return false;
    ori_line += qnt;
    // Column number in source file is always 0 in source map generated by
    // Emscripten. We just decode this value without further usage of it.
    if ((qnt = base::VLQBase64Decode(s.c_str(), s.size(), &pos)) ==
        std::numeric_limits<int32_t>::min())
      return false;

    if (pos < s.size() && s[pos] != ',') return false;
    pos++;

    file_idxs.push_back(file_idx);
    source_row.push_back(ori_line);
    offsets.push_back(gen_col);
  }
  return true;
}

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