Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(349)

Side by Side Diff: src/wasm/wasm-debug.cc

Issue 2493823003: [wasm] Allocate a single script per wasm module (Closed)
Patch Set: rebase Created 4 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « src/wasm/module-decoder.cc ('k') | src/wasm/wasm-module.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2016 the V8 project authors. All rights reserved. 1 // Copyright 2016 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "src/assert-scope.h" 5 #include "src/assert-scope.h"
6 #include "src/debug/debug.h" 6 #include "src/debug/debug.h"
7 #include "src/factory.h" 7 #include "src/factory.h"
8 #include "src/isolate.h" 8 #include "src/isolate.h"
9 #include "src/wasm/module-decoder.h" 9 #include "src/wasm/module-decoder.h"
10 #include "src/wasm/wasm-module.h" 10 #include "src/wasm/wasm-module.h"
11 #include "src/wasm/wasm-objects.h" 11 #include "src/wasm/wasm-objects.h"
12 12
13 using namespace v8::internal; 13 using namespace v8::internal;
14 using namespace v8::internal::wasm; 14 using namespace v8::internal::wasm;
15 15
16 namespace { 16 namespace {
17 17
18 enum { 18 enum {
19 kWasmDebugInfoWasmObj, 19 kWasmDebugInfoWasmObj,
20 kWasmDebugInfoWasmBytesHash, 20 kWasmDebugInfoWasmBytesHash,
21 kWasmDebugInfoFunctionByteOffsets,
22 kWasmDebugInfoFunctionScripts,
23 kWasmDebugInfoAsmJsOffsets, 21 kWasmDebugInfoAsmJsOffsets,
24 kWasmDebugInfoNumEntries 22 kWasmDebugInfoNumEntries
25 }; 23 };
26 24
27 ByteArray *GetOrCreateFunctionOffsetTable(Handle<WasmDebugInfo> debug_info) { 25 // TODO(clemensh): Move asm.js offset tables to the compiled module.
28 Object *offset_table = debug_info->get(kWasmDebugInfoFunctionByteOffsets); 26 FixedArray *GetAsmJsOffsetTables(Handle<WasmDebugInfo> debug_info,
29 Isolate *isolate = debug_info->GetIsolate(); 27 Isolate *isolate) {
30 if (!offset_table->IsUndefined(isolate)) return ByteArray::cast(offset_table);
31
32 FunctionOffsetsResult function_offsets;
33 {
34 Handle<JSObject> wasm_instance(debug_info->wasm_instance(), isolate);
35 uint32_t num_imported_functions =
36 static_cast<uint32_t>(wasm::GetNumImportedFunctions(wasm_instance));
37 Handle<SeqOneByteString> wasm_bytes = wasm::GetWasmBytes(wasm_instance);
38 DisallowHeapAllocation no_gc;
39 const byte *bytes_start = wasm_bytes->GetChars();
40 const byte *bytes_end = bytes_start + wasm_bytes->length();
41 function_offsets = wasm::DecodeWasmFunctionOffsets(bytes_start, bytes_end,
42 num_imported_functions);
43 }
44 DCHECK(function_offsets.ok());
45 size_t array_size = 2 * kIntSize * function_offsets.val.size();
46 CHECK_LE(array_size, static_cast<size_t>(kMaxInt));
47 ByteArray *arr =
48 *isolate->factory()->NewByteArray(static_cast<int>(array_size));
49 int idx = 0;
50 for (std::pair<int, int> p : function_offsets.val) {
51 arr->set_int(idx++, p.first);
52 arr->set_int(idx++, p.second);
53 }
54 DCHECK_EQ(arr->length(), idx * kIntSize);
55 debug_info->set(kWasmDebugInfoFunctionByteOffsets, arr);
56
57 return arr;
58 }
59
60 std::pair<int, int> GetFunctionOffsetAndLength(Handle<WasmDebugInfo> debug_info,
61 int func_index) {
62 ByteArray *arr = GetOrCreateFunctionOffsetTable(debug_info);
63 DCHECK(func_index >= 0 && func_index < arr->length() / kIntSize / 2);
64
65 int offset = arr->get_int(2 * func_index);
66 int length = arr->get_int(2 * func_index + 1);
67 // Assert that it's distinguishable from the "illegal function index" return.
68 DCHECK(offset > 0 && length > 0);
69 return {offset, length};
70 }
71
72 Vector<const uint8_t> GetFunctionBytes(Handle<WasmDebugInfo> debug_info,
73 int func_index) {
74 Handle<JSObject> wasm_instance(debug_info->wasm_instance());
75 Handle<SeqOneByteString> module_bytes = wasm::GetWasmBytes(wasm_instance);
76 std::pair<int, int> offset_and_length =
77 GetFunctionOffsetAndLength(debug_info, func_index);
78 return Vector<const uint8_t>(
79 module_bytes->GetChars() + offset_and_length.first,
80 offset_and_length.second);
81 }
82
83 FixedArray *GetOffsetTables(Handle<WasmDebugInfo> debug_info,
84 Isolate *isolate) {
85 Object *offset_tables = debug_info->get(kWasmDebugInfoAsmJsOffsets); 28 Object *offset_tables = debug_info->get(kWasmDebugInfoAsmJsOffsets);
86 if (!offset_tables->IsUndefined(isolate)) { 29 if (!offset_tables->IsUndefined(isolate)) {
87 return FixedArray::cast(offset_tables); 30 return FixedArray::cast(offset_tables);
88 } 31 }
89 32
33 Handle<JSObject> wasm_instance(debug_info->wasm_instance(), isolate);
34 Handle<WasmCompiledModule> compiled_module(GetCompiledModule(*wasm_instance),
35 isolate);
36 DCHECK(compiled_module->has_asm_js_offset_tables());
37
90 AsmJsOffsetsResult asm_offsets; 38 AsmJsOffsetsResult asm_offsets;
91 { 39 {
92 Handle<JSObject> wasm_instance(debug_info->wasm_instance(), isolate);
93 Handle<WasmCompiledModule> compiled_module =
94 handle(GetCompiledModule(*wasm_instance), isolate);
95 DCHECK(compiled_module->has_asm_js_offset_tables());
96 Handle<ByteArray> asm_offset_tables = 40 Handle<ByteArray> asm_offset_tables =
97 compiled_module->asm_js_offset_tables(); 41 compiled_module->asm_js_offset_tables();
98 uint32_t num_imported_functions =
99 static_cast<uint32_t>(wasm::GetNumImportedFunctions(wasm_instance));
100 DisallowHeapAllocation no_gc; 42 DisallowHeapAllocation no_gc;
101 const byte *bytes_start = asm_offset_tables->GetDataStartAddress(); 43 const byte *bytes_start = asm_offset_tables->GetDataStartAddress();
102 const byte *bytes_end = bytes_start + asm_offset_tables->length(); 44 const byte *bytes_end = bytes_start + asm_offset_tables->length();
103 asm_offsets = wasm::DecodeAsmJsOffsets(bytes_start, bytes_end, 45 asm_offsets = wasm::DecodeAsmJsOffsets(bytes_start, bytes_end);
104 num_imported_functions);
105 } 46 }
106 // Wasm bytes must be valid and must contain asm.js offset table. 47 // Wasm bytes must be valid and must contain asm.js offset table.
107 DCHECK(asm_offsets.ok()); 48 DCHECK(asm_offsets.ok());
108 DCHECK_GE(static_cast<size_t>(kMaxInt), asm_offsets.val.size()); 49 DCHECK_GE(static_cast<size_t>(kMaxInt), asm_offsets.val.size());
109 int num_functions = static_cast<int>(asm_offsets.val.size()); 50 int num_functions = static_cast<int>(asm_offsets.val.size());
110 DCHECK_EQ(wasm::GetNumberOfFunctions(handle(debug_info->wasm_instance())), 51 DCHECK_EQ(
111 num_functions); 52 wasm::GetNumberOfFunctions(handle(debug_info->wasm_instance())),
53 static_cast<int>(num_functions +
54 compiled_module->module()->num_imported_functions));
112 Handle<FixedArray> all_tables = 55 Handle<FixedArray> all_tables =
113 isolate->factory()->NewFixedArray(num_functions); 56 isolate->factory()->NewFixedArray(num_functions);
114 debug_info->set(kWasmDebugInfoAsmJsOffsets, *all_tables); 57 debug_info->set(kWasmDebugInfoAsmJsOffsets, *all_tables);
115 for (int func = 0; func < num_functions; ++func) { 58 for (int func = 0; func < num_functions; ++func) {
116 std::vector<std::pair<int, int>> &func_asm_offsets = asm_offsets.val[func]; 59 std::vector<std::pair<int, int>> &func_asm_offsets = asm_offsets.val[func];
117 if (func_asm_offsets.empty()) continue; 60 if (func_asm_offsets.empty()) continue;
118 size_t array_size = 2 * kIntSize * func_asm_offsets.size(); 61 size_t array_size = 2 * kIntSize * func_asm_offsets.size();
119 CHECK_LE(array_size, static_cast<size_t>(kMaxInt)); 62 CHECK_LE(array_size, static_cast<size_t>(kMaxInt));
120 ByteArray *arr = 63 ByteArray *arr =
121 *isolate->factory()->NewByteArray(static_cast<int>(array_size)); 64 *isolate->factory()->NewByteArray(static_cast<int>(array_size));
(...skipping 26 matching lines...) Expand all
148 } 91 }
149 Handle<Object> hash_obj = factory->NewNumberFromInt(hash, TENURED); 92 Handle<Object> hash_obj = factory->NewNumberFromInt(hash, TENURED);
150 arr->set(kWasmDebugInfoWasmBytesHash, *hash_obj); 93 arr->set(kWasmDebugInfoWasmBytesHash, *hash_obj);
151 94
152 return Handle<WasmDebugInfo>::cast(arr); 95 return Handle<WasmDebugInfo>::cast(arr);
153 } 96 }
154 97
155 bool WasmDebugInfo::IsDebugInfo(Object *object) { 98 bool WasmDebugInfo::IsDebugInfo(Object *object) {
156 if (!object->IsFixedArray()) return false; 99 if (!object->IsFixedArray()) return false;
157 FixedArray *arr = FixedArray::cast(object); 100 FixedArray *arr = FixedArray::cast(object);
158 Isolate *isolate = arr->GetIsolate();
159 return arr->length() == kWasmDebugInfoNumEntries && 101 return arr->length() == kWasmDebugInfoNumEntries &&
160 IsWasmInstance(arr->get(kWasmDebugInfoWasmObj)) && 102 IsWasmInstance(arr->get(kWasmDebugInfoWasmObj)) &&
161 arr->get(kWasmDebugInfoWasmBytesHash)->IsNumber() && 103 arr->get(kWasmDebugInfoWasmBytesHash)->IsNumber();
162 (arr->get(kWasmDebugInfoFunctionByteOffsets)->IsUndefined(isolate) ||
163 arr->get(kWasmDebugInfoFunctionByteOffsets)->IsByteArray()) &&
164 (arr->get(kWasmDebugInfoFunctionScripts)->IsUndefined(isolate) ||
165 arr->get(kWasmDebugInfoFunctionScripts)->IsFixedArray());
166 } 104 }
167 105
168 WasmDebugInfo *WasmDebugInfo::cast(Object *object) { 106 WasmDebugInfo *WasmDebugInfo::cast(Object *object) {
169 DCHECK(IsDebugInfo(object)); 107 DCHECK(IsDebugInfo(object));
170 return reinterpret_cast<WasmDebugInfo *>(object); 108 return reinterpret_cast<WasmDebugInfo *>(object);
171 } 109 }
172 110
173 JSObject *WasmDebugInfo::wasm_instance() { 111 JSObject *WasmDebugInfo::wasm_instance() {
174 return JSObject::cast(get(kWasmDebugInfoWasmObj)); 112 return JSObject::cast(get(kWasmDebugInfoWasmObj));
175 } 113 }
176 114
177 Script *WasmDebugInfo::GetFunctionScript(Handle<WasmDebugInfo> debug_info,
178 int func_index) {
179 Isolate *isolate = debug_info->GetIsolate();
180 Object *scripts_obj = debug_info->get(kWasmDebugInfoFunctionScripts);
181 Handle<FixedArray> scripts;
182 if (scripts_obj->IsUndefined(isolate)) {
183 Handle<JSObject> wasm_instance(debug_info->wasm_instance(), isolate);
184 int num_functions = wasm::GetNumberOfFunctions(wasm_instance);
185 scripts = isolate->factory()->NewFixedArray(num_functions, TENURED);
186 debug_info->set(kWasmDebugInfoFunctionScripts, *scripts);
187 } else {
188 scripts = handle(FixedArray::cast(scripts_obj), isolate);
189 }
190
191 DCHECK(func_index >= 0 && func_index < scripts->length());
192 Object *script_or_undef = scripts->get(func_index);
193 if (!script_or_undef->IsUndefined(isolate)) {
194 return Script::cast(script_or_undef);
195 }
196
197 Handle<Script> script =
198 isolate->factory()->NewScript(isolate->factory()->empty_string());
199 scripts->set(func_index, *script);
200
201 script->set_type(Script::TYPE_WASM);
202 script->set_wasm_instance(debug_info->wasm_instance());
203 script->set_wasm_function_index(func_index);
204
205 int hash = 0;
206 debug_info->get(kWasmDebugInfoWasmBytesHash)->ToInt32(&hash);
207 char buffer[32];
208 SNPrintF(ArrayVector(buffer), "wasm://%08x/%d", hash, func_index);
209 Handle<String> source_url =
210 isolate->factory()->NewStringFromAsciiChecked(buffer, TENURED);
211 script->set_source_url(*source_url);
212
213 int func_bytes_len =
214 GetFunctionOffsetAndLength(debug_info, func_index).second;
215 Handle<FixedArray> line_ends = isolate->factory()->NewFixedArray(1, TENURED);
216 line_ends->set(0, Smi::FromInt(func_bytes_len));
217 line_ends->set_map(isolate->heap()->fixed_cow_array_map());
218 script->set_line_ends(*line_ends);
219
220 // TODO(clemensh): Register with the debugger. Note that we cannot call into
221 // JS at this point since this function is called from within stack trace
222 // collection (which means we cannot call Debug::OnAfterCompile in its
223 // current form). See crbug.com/641065.
224 if (false) isolate->debug()->OnAfterCompile(script);
225
226 return *script;
227 }
228
229 Handle<String> WasmDebugInfo::DisassembleFunction(
230 Handle<WasmDebugInfo> debug_info, int func_index) {
231 std::ostringstream disassembly_os;
232
233 {
234 Vector<const uint8_t> bytes_vec = GetFunctionBytes(debug_info, func_index);
235 DisallowHeapAllocation no_gc;
236
237 AccountingAllocator allocator;
238 bool ok = PrintAst(
239 &allocator, FunctionBodyForTesting(bytes_vec.start(), bytes_vec.end()),
240 disassembly_os, nullptr);
241 DCHECK(ok);
242 USE(ok);
243 }
244
245 // Unfortunately, we have to copy the string here.
246 std::string code_str = disassembly_os.str();
247 CHECK_LE(code_str.length(), static_cast<size_t>(kMaxInt));
248 Factory *factory = debug_info->GetIsolate()->factory();
249 Vector<const char> code_vec(code_str.data(),
250 static_cast<int>(code_str.length()));
251 return factory->NewStringFromAscii(code_vec).ToHandleChecked();
252 }
253
254 Handle<FixedArray> WasmDebugInfo::GetFunctionOffsetTable(
255 Handle<WasmDebugInfo> debug_info, int func_index) {
256 class NullBuf : public std::streambuf {};
257 NullBuf null_buf;
258 std::ostream null_stream(&null_buf);
259
260 std::vector<std::tuple<uint32_t, int, int>> offset_table_vec;
261
262 {
263 Vector<const uint8_t> bytes_vec = GetFunctionBytes(debug_info, func_index);
264 DisallowHeapAllocation no_gc;
265
266 AccountingAllocator allocator;
267 bool ok = PrintAst(
268 &allocator, FunctionBodyForTesting(bytes_vec.start(), bytes_vec.end()),
269 null_stream, &offset_table_vec);
270 DCHECK(ok);
271 USE(ok);
272 }
273
274 size_t arr_size = 3 * offset_table_vec.size();
275 CHECK_LE(arr_size, static_cast<size_t>(kMaxInt));
276 Factory *factory = debug_info->GetIsolate()->factory();
277 Handle<FixedArray> offset_table =
278 factory->NewFixedArray(static_cast<int>(arr_size), TENURED);
279
280 int idx = 0;
281 for (std::tuple<uint32_t, int, int> elem : offset_table_vec) {
282 offset_table->set(idx++, Smi::FromInt(std::get<0>(elem)));
283 offset_table->set(idx++, Smi::FromInt(std::get<1>(elem)));
284 offset_table->set(idx++, Smi::FromInt(std::get<2>(elem)));
285 }
286 DCHECK_EQ(idx, offset_table->length());
287
288 return offset_table;
289 }
290
291 int WasmDebugInfo::GetAsmJsSourcePosition(Handle<WasmDebugInfo> debug_info, 115 int WasmDebugInfo::GetAsmJsSourcePosition(Handle<WasmDebugInfo> debug_info,
292 int func_index, int byte_offset) { 116 int func_index, int byte_offset) {
293 Isolate *isolate = debug_info->GetIsolate(); 117 Isolate *isolate = debug_info->GetIsolate();
294 FixedArray *offset_tables = GetOffsetTables(debug_info, isolate); 118 Handle<JSObject> instance(debug_info->wasm_instance(), isolate);
119 FixedArray *offset_tables = GetAsmJsOffsetTables(debug_info, isolate);
295 120
121 WasmCompiledModule *compiled_module = wasm::GetCompiledModule(*instance);
122 int num_imported_functions =
123 compiled_module->module()->num_imported_functions;
124 DCHECK_LE(num_imported_functions, func_index);
125 func_index -= num_imported_functions;
296 DCHECK_LT(func_index, offset_tables->length()); 126 DCHECK_LT(func_index, offset_tables->length());
297 ByteArray *offset_table = ByteArray::cast(offset_tables->get(func_index)); 127 ByteArray *offset_table = ByteArray::cast(offset_tables->get(func_index));
298 128
299 // Binary search for the current byte offset. 129 // Binary search for the current byte offset.
300 int left = 0; // inclusive 130 int left = 0; // inclusive
301 int right = offset_table->length() / kIntSize / 2; // exclusive 131 int right = offset_table->length() / kIntSize / 2; // exclusive
302 DCHECK_LT(left, right); 132 DCHECK_LT(left, right);
303 while (right - left > 1) { 133 while (right - left > 1) {
304 int mid = left + (right - left) / 2; 134 int mid = left + (right - left) / 2;
305 if (offset_table->get_int(2 * mid) <= byte_offset) { 135 if (offset_table->get_int(2 * mid) <= byte_offset) {
306 left = mid; 136 left = mid;
307 } else { 137 } else {
308 right = mid; 138 right = mid;
309 } 139 }
310 } 140 }
311 // There should be an entry for each position that could show up on the stack 141 // There should be an entry for each position that could show up on the stack
312 // trace: 142 // trace:
313 DCHECK_EQ(byte_offset, offset_table->get_int(2 * left)); 143 DCHECK_EQ(byte_offset, offset_table->get_int(2 * left));
314 return offset_table->get_int(2 * left + 1); 144 return offset_table->get_int(2 * left + 1);
315 } 145 }
OLDNEW
« no previous file with comments | « src/wasm/module-decoder.cc ('k') | src/wasm/wasm-module.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698