blob: 85a171e5acbe2a1517fba5cc782a86a16dd46f03 [file] [log] [blame]
// 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
->Get(context, v8::String::NewFromUtf8Literal(v8_isolate, "version"))
.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
->Get(context, v8::String::NewFromUtf8Literal(v8_isolate, "sources"))
.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
->Get(context, v8::String::NewFromUtf8Literal(v8_isolate, "length"))
.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
->Get(context, v8::String::NewFromUtf8Literal(v8_isolate, "mappings"))
.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