11cb0ef41Sopenharmony_ci// Copyright 2019 the V8 project authors. All rights reserved.
21cb0ef41Sopenharmony_ci// Use of this source code is governed by a BSD-style license that can be
31cb0ef41Sopenharmony_ci// found in the LICENSE file.
41cb0ef41Sopenharmony_ci
51cb0ef41Sopenharmony_ci#include "src/wasm/wasm-module-sourcemap.h"
61cb0ef41Sopenharmony_ci
71cb0ef41Sopenharmony_ci#include <algorithm>
81cb0ef41Sopenharmony_ci
91cb0ef41Sopenharmony_ci#include "include/v8-context.h"
101cb0ef41Sopenharmony_ci#include "include/v8-json.h"
111cb0ef41Sopenharmony_ci#include "include/v8-local-handle.h"
121cb0ef41Sopenharmony_ci#include "include/v8-object.h"
131cb0ef41Sopenharmony_ci#include "include/v8-primitive.h"
141cb0ef41Sopenharmony_ci#include "src/api/api.h"
151cb0ef41Sopenharmony_ci#include "src/base/vlq-base64.h"
161cb0ef41Sopenharmony_ci
171cb0ef41Sopenharmony_cinamespace v8 {
181cb0ef41Sopenharmony_ci
191cb0ef41Sopenharmony_ciclass String;
201cb0ef41Sopenharmony_ci
211cb0ef41Sopenharmony_cinamespace internal {
221cb0ef41Sopenharmony_cinamespace wasm {
231cb0ef41Sopenharmony_ci
241cb0ef41Sopenharmony_ciWasmModuleSourceMap::WasmModuleSourceMap(v8::Isolate* v8_isolate,
251cb0ef41Sopenharmony_ci                                         v8::Local<v8::String> src_map_str) {
261cb0ef41Sopenharmony_ci  v8::HandleScope scope(v8_isolate);
271cb0ef41Sopenharmony_ci  v8::Local<v8::Context> context = v8::Context::New(v8_isolate);
281cb0ef41Sopenharmony_ci
291cb0ef41Sopenharmony_ci  v8::Local<v8::Value> src_map_value;
301cb0ef41Sopenharmony_ci  if (!v8::JSON::Parse(context, src_map_str).ToLocal(&src_map_value)) return;
311cb0ef41Sopenharmony_ci  v8::Local<v8::Object> src_map_obj =
321cb0ef41Sopenharmony_ci      v8::Local<v8::Object>::Cast(src_map_value);
331cb0ef41Sopenharmony_ci
341cb0ef41Sopenharmony_ci  v8::Local<v8::Value> version_value, sources_value, mappings_value;
351cb0ef41Sopenharmony_ci  bool has_valid_version =
361cb0ef41Sopenharmony_ci      src_map_obj
371cb0ef41Sopenharmony_ci          ->Get(context, v8::String::NewFromUtf8Literal(v8_isolate, "version"))
381cb0ef41Sopenharmony_ci          .ToLocal(&version_value) &&
391cb0ef41Sopenharmony_ci      version_value->IsUint32();
401cb0ef41Sopenharmony_ci  uint32_t version = 0;
411cb0ef41Sopenharmony_ci  if (!has_valid_version || !version_value->Uint32Value(context).To(&version) ||
421cb0ef41Sopenharmony_ci      version != 3u)
431cb0ef41Sopenharmony_ci    return;
441cb0ef41Sopenharmony_ci
451cb0ef41Sopenharmony_ci  bool has_valid_sources =
461cb0ef41Sopenharmony_ci      src_map_obj
471cb0ef41Sopenharmony_ci          ->Get(context, v8::String::NewFromUtf8Literal(v8_isolate, "sources"))
481cb0ef41Sopenharmony_ci          .ToLocal(&sources_value) &&
491cb0ef41Sopenharmony_ci      sources_value->IsArray();
501cb0ef41Sopenharmony_ci  if (!has_valid_sources) return;
511cb0ef41Sopenharmony_ci
521cb0ef41Sopenharmony_ci  v8::Local<v8::Object> sources_arr =
531cb0ef41Sopenharmony_ci      v8::Local<v8::Object>::Cast(sources_value);
541cb0ef41Sopenharmony_ci  v8::Local<v8::Value> sources_len_value;
551cb0ef41Sopenharmony_ci  if (!sources_arr
561cb0ef41Sopenharmony_ci           ->Get(context, v8::String::NewFromUtf8Literal(v8_isolate, "length"))
571cb0ef41Sopenharmony_ci           .ToLocal(&sources_len_value))
581cb0ef41Sopenharmony_ci    return;
591cb0ef41Sopenharmony_ci  uint32_t sources_len = 0;
601cb0ef41Sopenharmony_ci  if (!sources_len_value->Uint32Value(context).To(&sources_len)) return;
611cb0ef41Sopenharmony_ci
621cb0ef41Sopenharmony_ci  for (uint32_t i = 0; i < sources_len; ++i) {
631cb0ef41Sopenharmony_ci    v8::Local<v8::Value> file_name_value;
641cb0ef41Sopenharmony_ci    if (!sources_arr->Get(context, i).ToLocal(&file_name_value) ||
651cb0ef41Sopenharmony_ci        !file_name_value->IsString())
661cb0ef41Sopenharmony_ci      return;
671cb0ef41Sopenharmony_ci    v8::Local<v8::String> file_name =
681cb0ef41Sopenharmony_ci        v8::Local<v8::String>::Cast(file_name_value);
691cb0ef41Sopenharmony_ci    auto file_name_sz = file_name->Utf8Length(v8_isolate);
701cb0ef41Sopenharmony_ci    std::unique_ptr<char[]> file_name_buf(new char[file_name_sz + 1]);
711cb0ef41Sopenharmony_ci    file_name->WriteUtf8(v8_isolate, file_name_buf.get());
721cb0ef41Sopenharmony_ci    file_name_buf.get()[file_name_sz] = '\0';
731cb0ef41Sopenharmony_ci    filenames.emplace_back(file_name_buf.get());
741cb0ef41Sopenharmony_ci  }
751cb0ef41Sopenharmony_ci
761cb0ef41Sopenharmony_ci  bool has_valid_mappings =
771cb0ef41Sopenharmony_ci      src_map_obj
781cb0ef41Sopenharmony_ci          ->Get(context, v8::String::NewFromUtf8Literal(v8_isolate, "mappings"))
791cb0ef41Sopenharmony_ci          .ToLocal(&mappings_value) &&
801cb0ef41Sopenharmony_ci      mappings_value->IsString();
811cb0ef41Sopenharmony_ci  if (!has_valid_mappings) return;
821cb0ef41Sopenharmony_ci
831cb0ef41Sopenharmony_ci  v8::Local<v8::String> mappings = v8::Local<v8::String>::Cast(mappings_value);
841cb0ef41Sopenharmony_ci  int mappings_sz = mappings->Utf8Length(v8_isolate);
851cb0ef41Sopenharmony_ci  std::unique_ptr<char[]> mappings_buf(new char[mappings_sz + 1]);
861cb0ef41Sopenharmony_ci  mappings->WriteUtf8(v8_isolate, mappings_buf.get());
871cb0ef41Sopenharmony_ci  mappings_buf.get()[mappings_sz] = '\0';
881cb0ef41Sopenharmony_ci
891cb0ef41Sopenharmony_ci  valid_ = DecodeMapping(mappings_buf.get());
901cb0ef41Sopenharmony_ci}
911cb0ef41Sopenharmony_ci
921cb0ef41Sopenharmony_cisize_t WasmModuleSourceMap::GetSourceLine(size_t wasm_offset) const {
931cb0ef41Sopenharmony_ci  std::vector<std::size_t>::const_iterator up =
941cb0ef41Sopenharmony_ci      std::upper_bound(offsets.begin(), offsets.end(), wasm_offset);
951cb0ef41Sopenharmony_ci  CHECK_NE(offsets.begin(), up);
961cb0ef41Sopenharmony_ci  size_t source_idx = up - offsets.begin() - 1;
971cb0ef41Sopenharmony_ci  return source_row[source_idx];
981cb0ef41Sopenharmony_ci}
991cb0ef41Sopenharmony_ci
1001cb0ef41Sopenharmony_cistd::string WasmModuleSourceMap::GetFilename(size_t wasm_offset) const {
1011cb0ef41Sopenharmony_ci  std::vector<size_t>::const_iterator up =
1021cb0ef41Sopenharmony_ci      std::upper_bound(offsets.begin(), offsets.end(), wasm_offset);
1031cb0ef41Sopenharmony_ci  CHECK_NE(offsets.begin(), up);
1041cb0ef41Sopenharmony_ci  size_t offset_idx = up - offsets.begin() - 1;
1051cb0ef41Sopenharmony_ci  size_t filename_idx = file_idxs[offset_idx];
1061cb0ef41Sopenharmony_ci  return filenames[filename_idx];
1071cb0ef41Sopenharmony_ci}
1081cb0ef41Sopenharmony_ci
1091cb0ef41Sopenharmony_cibool WasmModuleSourceMap::HasSource(size_t start, size_t end) const {
1101cb0ef41Sopenharmony_ci  return start <= *(offsets.end() - 1) && end > *offsets.begin();
1111cb0ef41Sopenharmony_ci}
1121cb0ef41Sopenharmony_ci
1131cb0ef41Sopenharmony_cibool WasmModuleSourceMap::HasValidEntry(size_t start, size_t addr) const {
1141cb0ef41Sopenharmony_ci  std::vector<size_t>::const_iterator up =
1151cb0ef41Sopenharmony_ci      std::upper_bound(offsets.begin(), offsets.end(), addr);
1161cb0ef41Sopenharmony_ci  if (up == offsets.begin()) return false;
1171cb0ef41Sopenharmony_ci  size_t offset_idx = up - offsets.begin() - 1;
1181cb0ef41Sopenharmony_ci  size_t entry_offset = offsets[offset_idx];
1191cb0ef41Sopenharmony_ci  if (entry_offset < start) return false;
1201cb0ef41Sopenharmony_ci  return true;
1211cb0ef41Sopenharmony_ci}
1221cb0ef41Sopenharmony_ci
1231cb0ef41Sopenharmony_cibool WasmModuleSourceMap::DecodeMapping(const std::string& s) {
1241cb0ef41Sopenharmony_ci  size_t pos = 0, gen_col = 0, file_idx = 0, ori_line = 0;
1251cb0ef41Sopenharmony_ci  int32_t qnt = 0;
1261cb0ef41Sopenharmony_ci
1271cb0ef41Sopenharmony_ci  while (pos < s.size()) {
1281cb0ef41Sopenharmony_ci    // Skip redundant commas.
1291cb0ef41Sopenharmony_ci    if (s[pos] == ',') {
1301cb0ef41Sopenharmony_ci      ++pos;
1311cb0ef41Sopenharmony_ci      continue;
1321cb0ef41Sopenharmony_ci    }
1331cb0ef41Sopenharmony_ci    if ((qnt = base::VLQBase64Decode(s.c_str(), s.size(), &pos)) ==
1341cb0ef41Sopenharmony_ci        std::numeric_limits<int32_t>::min())
1351cb0ef41Sopenharmony_ci      return false;
1361cb0ef41Sopenharmony_ci    gen_col += qnt;
1371cb0ef41Sopenharmony_ci    if ((qnt = base::VLQBase64Decode(s.c_str(), s.size(), &pos)) ==
1381cb0ef41Sopenharmony_ci        std::numeric_limits<int32_t>::min())
1391cb0ef41Sopenharmony_ci      return false;
1401cb0ef41Sopenharmony_ci    file_idx += qnt;
1411cb0ef41Sopenharmony_ci    if ((qnt = base::VLQBase64Decode(s.c_str(), s.size(), &pos)) ==
1421cb0ef41Sopenharmony_ci        std::numeric_limits<int32_t>::min())
1431cb0ef41Sopenharmony_ci      return false;
1441cb0ef41Sopenharmony_ci    ori_line += qnt;
1451cb0ef41Sopenharmony_ci    // Column number in source file is always 0 in source map generated by
1461cb0ef41Sopenharmony_ci    // Emscripten. We just decode this value without further usage of it.
1471cb0ef41Sopenharmony_ci    if ((qnt = base::VLQBase64Decode(s.c_str(), s.size(), &pos)) ==
1481cb0ef41Sopenharmony_ci        std::numeric_limits<int32_t>::min())
1491cb0ef41Sopenharmony_ci      return false;
1501cb0ef41Sopenharmony_ci
1511cb0ef41Sopenharmony_ci    if (pos < s.size() && s[pos] != ',') return false;
1521cb0ef41Sopenharmony_ci    pos++;
1531cb0ef41Sopenharmony_ci
1541cb0ef41Sopenharmony_ci    file_idxs.push_back(file_idx);
1551cb0ef41Sopenharmony_ci    source_row.push_back(ori_line);
1561cb0ef41Sopenharmony_ci    offsets.push_back(gen_col);
1571cb0ef41Sopenharmony_ci  }
1581cb0ef41Sopenharmony_ci  return true;
1591cb0ef41Sopenharmony_ci}
1601cb0ef41Sopenharmony_ci
1611cb0ef41Sopenharmony_ci}  // namespace wasm
1621cb0ef41Sopenharmony_ci}  // namespace internal
1631cb0ef41Sopenharmony_ci}  // namespace v8
164