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