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

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

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

Powered by Google App Engine
This is Rietveld 408576698