• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2019 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "src/wasm/wasm-module-sourcemap.h"
6 
7 #include <algorithm>
8 
9 #include "include/v8.h"
10 #include "src/api/api.h"
11 #include "src/base/vlq-base64.h"
12 
13 namespace v8 {
14 namespace internal {
15 namespace wasm {
16 
WasmModuleSourceMap(v8::Isolate * v8_isolate,v8::Local<v8::String> src_map_str)17 WasmModuleSourceMap::WasmModuleSourceMap(v8::Isolate* v8_isolate,
18                                          v8::Local<v8::String> src_map_str) {
19   v8::HandleScope scope(v8_isolate);
20   v8::Local<v8::Context> context = v8::Context::New(v8_isolate);
21 
22   v8::Local<v8::Value> src_map_value;
23   if (!v8::JSON::Parse(context, src_map_str).ToLocal(&src_map_value)) return;
24   v8::Local<v8::Object> src_map_obj =
25       v8::Local<v8::Object>::Cast(src_map_value);
26 
27   v8::Local<v8::Value> version_value, sources_value, mappings_value;
28   bool has_valid_version =
29       src_map_obj
30           ->Get(context, v8::String::NewFromUtf8Literal(v8_isolate, "version"))
31           .ToLocal(&version_value) &&
32       version_value->IsUint32();
33   uint32_t version = 0;
34   if (!has_valid_version || !version_value->Uint32Value(context).To(&version) ||
35       version != 3u)
36     return;
37 
38   bool has_valid_sources =
39       src_map_obj
40           ->Get(context, v8::String::NewFromUtf8Literal(v8_isolate, "sources"))
41           .ToLocal(&sources_value) &&
42       sources_value->IsArray();
43   if (!has_valid_sources) return;
44 
45   v8::Local<v8::Object> sources_arr =
46       v8::Local<v8::Object>::Cast(sources_value);
47   v8::Local<v8::Value> sources_len_value;
48   if (!sources_arr
49            ->Get(context, v8::String::NewFromUtf8Literal(v8_isolate, "length"))
50            .ToLocal(&sources_len_value))
51     return;
52   uint32_t sources_len = 0;
53   if (!sources_len_value->Uint32Value(context).To(&sources_len)) return;
54 
55   for (uint32_t i = 0; i < sources_len; ++i) {
56     v8::Local<v8::Value> file_name_value;
57     if (!sources_arr->Get(context, i).ToLocal(&file_name_value) ||
58         !file_name_value->IsString())
59       return;
60     v8::Local<v8::String> file_name =
61         v8::Local<v8::String>::Cast(file_name_value);
62     auto file_name_sz = file_name->Utf8Length(v8_isolate);
63     std::unique_ptr<char[]> file_name_buf(new char[file_name_sz + 1]);
64     file_name->WriteUtf8(v8_isolate, file_name_buf.get());
65     file_name_buf.get()[file_name_sz] = '\0';
66     filenames.emplace_back(file_name_buf.get());
67   }
68 
69   bool has_valid_mappings =
70       src_map_obj
71           ->Get(context, v8::String::NewFromUtf8Literal(v8_isolate, "mappings"))
72           .ToLocal(&mappings_value) &&
73       mappings_value->IsString();
74   if (!has_valid_mappings) return;
75 
76   v8::Local<v8::String> mappings = v8::Local<v8::String>::Cast(mappings_value);
77   int mappings_sz = mappings->Utf8Length(v8_isolate);
78   std::unique_ptr<char[]> mappings_buf(new char[mappings_sz + 1]);
79   mappings->WriteUtf8(v8_isolate, mappings_buf.get());
80   mappings_buf.get()[mappings_sz] = '\0';
81 
82   valid_ = DecodeMapping(mappings_buf.get());
83 }
84 
GetSourceLine(size_t wasm_offset) const85 size_t WasmModuleSourceMap::GetSourceLine(size_t wasm_offset) const {
86   std::vector<std::size_t>::const_iterator up =
87       std::upper_bound(offsets.begin(), offsets.end(), wasm_offset);
88   CHECK_NE(offsets.begin(), up);
89   size_t source_idx = up - offsets.begin() - 1;
90   return source_row[source_idx];
91 }
92 
GetFilename(size_t wasm_offset) const93 std::string WasmModuleSourceMap::GetFilename(size_t wasm_offset) const {
94   std::vector<size_t>::const_iterator up =
95       std::upper_bound(offsets.begin(), offsets.end(), wasm_offset);
96   CHECK_NE(offsets.begin(), up);
97   size_t offset_idx = up - offsets.begin() - 1;
98   size_t filename_idx = file_idxs[offset_idx];
99   return filenames[filename_idx];
100 }
101 
HasSource(size_t start,size_t end) const102 bool WasmModuleSourceMap::HasSource(size_t start, size_t end) const {
103   return start <= *(offsets.end() - 1) && end > *offsets.begin();
104 }
105 
HasValidEntry(size_t start,size_t addr) const106 bool WasmModuleSourceMap::HasValidEntry(size_t start, size_t addr) const {
107   std::vector<size_t>::const_iterator up =
108       std::upper_bound(offsets.begin(), offsets.end(), addr);
109   if (up == offsets.begin()) return false;
110   size_t offset_idx = up - offsets.begin() - 1;
111   size_t entry_offset = offsets[offset_idx];
112   if (entry_offset < start) return false;
113   return true;
114 }
115 
DecodeMapping(const std::string & s)116 bool WasmModuleSourceMap::DecodeMapping(const std::string& s) {
117   size_t pos = 0, gen_col = 0, file_idx = 0, ori_line = 0;
118   int32_t qnt = 0;
119 
120   while (pos < s.size()) {
121     // Skip redundant commas.
122     if (s[pos] == ',') {
123       ++pos;
124       continue;
125     }
126     if ((qnt = base::VLQBase64Decode(s.c_str(), s.size(), &pos)) ==
127         std::numeric_limits<int32_t>::min())
128       return false;
129     gen_col += qnt;
130     if ((qnt = base::VLQBase64Decode(s.c_str(), s.size(), &pos)) ==
131         std::numeric_limits<int32_t>::min())
132       return false;
133     file_idx += qnt;
134     if ((qnt = base::VLQBase64Decode(s.c_str(), s.size(), &pos)) ==
135         std::numeric_limits<int32_t>::min())
136       return false;
137     ori_line += qnt;
138     // Column number in source file is always 0 in source map generated by
139     // Emscripten. We just decode this value without further usage of it.
140     if ((qnt = base::VLQBase64Decode(s.c_str(), s.size(), &pos)) ==
141         std::numeric_limits<int32_t>::min())
142       return false;
143 
144     if (pos < s.size() && s[pos] != ',') return false;
145     pos++;
146 
147     file_idxs.push_back(file_idx);
148     source_row.push_back(ori_line);
149     offsets.push_back(gen_col);
150   }
151   return true;
152 }
153 
154 }  // namespace wasm
155 }  // namespace internal
156 }  // namespace v8
157