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

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

Issue 2050953003: [wasm] Split off debug info from wasm object (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@decode-function-offsets-table
Patch Set: Created 4 years, 6 months 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
(Empty)
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
3 // found in the LICENSE file.
4
5 #include "src/wasm/wasm-debug.h"
6
7 #include "src/assert-scope.h"
8 #include "src/debug/debug.h"
9 #include "src/factory.h"
10 #include "src/isolate.h"
11 #include "src/wasm/module-decoder.h"
12 #include "src/wasm/wasm-module.h"
13
14 using namespace v8::internal;
15 using namespace v8::internal::wasm;
16
17 namespace {
18
19 enum {
20 kWasmDebugInfoWasmObj,
21 kWasmDebugInfoWasmBytesHash,
22 kWasmDebugInfoFunctionOffsets,
23 kWasmDebugInfoNumInternalFields
24 };
25
26 ByteArray *GetOrCreateFunctionOffsetTable(WasmDebugInfo *debug_info) {
27 Object *offset_table =
28 debug_info->GetInternalField(kWasmDebugInfoFunctionOffsets);
29 if (!offset_table->IsUndefined()) return ByteArray::cast(offset_table);
30
31 FunctionOffsetsResult function_offsets;
32 {
33 DisallowHeapAllocation no_gc;
34 SeqOneByteString *wasm_bytes =
35 wasm::GetWasmBytes(debug_info->wasm_object());
36 const byte *bytes_start = wasm_bytes->GetChars();
37 const byte *bytes_end = bytes_start + wasm_bytes->length();
38 function_offsets = wasm::DecodeWasmFunctionOffsets(bytes_start, bytes_end);
39 }
40 DCHECK(function_offsets.ok());
41 Isolate *isolate = debug_info->GetIsolate();
42 size_t array_size =
43 2 * sizeof(int) * static_cast<int>(function_offsets.val.size());
44 CHECK_LE(array_size, std::numeric_limits<int>::max());
45 ByteArray *arr =
46 *isolate->factory()->NewByteArray(static_cast<int>(array_size));
47 int idx = 0;
48 for (std::pair<int, int> p : function_offsets.val) {
49 arr->set_int(idx++, p.first);
50 arr->set_int(idx++, p.second);
51 }
52 DCHECK_EQ(arr->length(), idx * sizeof(int));
53 debug_info->SetInternalField(kWasmDebugInfoFunctionOffsets, arr);
54
55 return arr;
56 }
57
58 } // namespace
59
60 Handle<WasmDebugInfo> WasmDebugInfo::New(Handle<JSObject> wasm) {
61 Isolate *isolate = wasm->GetIsolate();
62 Factory *factory = isolate->factory();
63 Handle<Map> map = factory->NewMap(
64 JS_OBJECT_TYPE,
65 JSObject::kHeaderSize + kWasmDebugInfoNumInternalFields * kPointerSize);
66 Handle<JSObject> info = factory->NewJSObjectFromMap(map, TENURED);
67 info->SetInternalField(kWasmDebugInfoWasmObj, *wasm);
68 int hash = 0;
69 Handle<SeqOneByteString> wasm_bytes(GetWasmBytes(*wasm), isolate);
70 {
71 DisallowHeapAllocation no_gc;
72 hash = StringHasher::HashSequentialString(wasm_bytes->GetChars(),
73 wasm_bytes->length(), 0);
74 }
75 info->SetInternalField(kWasmDebugInfoWasmBytesHash,
76 *factory->NewNumberFromInt(hash, TENURED));
77
78 // TODO(clemensh): Register the wasm module at the debugger
79
80 return Handle<WasmDebugInfo>::cast(info);
81 }
82
83 bool WasmDebugInfo::IsDebugInfo(Object *object) {
84 if (!object->IsJSObject()) return false;
85 JSObject *obj = JSObject::cast(object);
86 return obj->GetInternalFieldCount() == kWasmDebugInfoNumInternalFields &&
87 IsWasmObject(obj->GetInternalField(kWasmDebugInfoWasmObj)) &&
88 obj->GetInternalField(kWasmDebugInfoWasmBytesHash)->IsNumber() &&
89 (obj->GetInternalField(kWasmDebugInfoFunctionOffsets)->IsUndefined() ||
90 obj->GetInternalField(kWasmDebugInfoFunctionOffsets)->IsByteArray());
91 }
92
93 WasmDebugInfo *WasmDebugInfo::cast(Object *object) {
94 DCHECK(IsDebugInfo(object));
95 return static_cast<WasmDebugInfo *>(object);
96 }
97
98 JSObject *WasmDebugInfo::wasm_object() {
99 return JSObject::cast(GetInternalField(kWasmDebugInfoWasmObj));
100 }
101
102 bool WasmDebugInfo::SetBreakPoint(int byte_offset) { return false; }
103
104 std::pair<int, int> WasmDebugInfo::GetFunctionOffsetAndLength(int func_index) {
105 ByteArray *arr = GetOrCreateFunctionOffsetTable(this);
106
107 if (func_index < 0 || func_index >= arr->length() / sizeof(int) / 2) {
108 return {0, 0};
109 }
110 int offset = arr->get_int(2 * func_index);
111 int length = arr->get_int(2 * func_index + 1);
112 // Assert that it's distinguishable from the "illegal function index" return.
113 DCHECK(offset > 0 && length > 0);
114 return {offset, length};
115 }
116
117 Handle<Object> wasm::GetFunctionOffsetTable(Isolate *isolate,
118 Handle<String> module_bytes) {
119 FunctionOffsetsResult function_offsets;
120 {
121 DisallowHeapAllocation no_gc;
122 DCHECK(module_bytes->IsSeqOneByteString());
123 Vector<const uint8_t> bytes_vec =
124 module_bytes->GetFlatContent().ToOneByteVector();
125 function_offsets =
126 wasm::DecodeWasmFunctionOffsets(bytes_vec.start(), bytes_vec.end());
127 }
128 if (!function_offsets.ok()) return isolate->factory()->undefined_value();
129
130 size_t array_size = 2 * function_offsets.val.size();
131 CHECK_LE(array_size, std::numeric_limits<int>::max());
132 Handle<FixedArray> arr =
133 isolate->factory()->NewFixedArray(static_cast<int>(array_size));
134 int idx = 0;
135 for (std::pair<int, int> p : function_offsets.val) {
136 arr->set(idx++, Smi::FromInt(p.first));
137 arr->set(idx++, Smi::FromInt(p.second));
138 }
139 DCHECK_EQ(arr->length(), idx);
140 return isolate->factory()->NewJSArrayWithElements(arr);
141 }
142
143 Handle<Object> wasm::DisassembleFunction(Isolate *isolate,
144 Handle<String> function_bytes,
145 bool get_code, bool get_table) {
146 struct NullBuf : public std::streambuf {};
147 struct LineCountingStream : public std::streambuf {
148 std::streambuf *buf;
149 uint32_t line_nr = 0;
150 uint32_t col_nr = 0;
151
152 explicit LineCountingStream(std::streambuf *buf) : buf(buf) {}
153 inline void nextChar(int_type c) {
154 ++col_nr;
155 if (c == '\n') ++line_nr, col_nr = 0;
156 }
157 int_type overflow(int_type c) override {
158 if (c != EOF) {
159 nextChar(c);
160 buf->sputc(c);
161 }
162 return c;
163 }
164 std::streamsize xsputn(const char *s, std::streamsize n) override {
165 for (const char *p = s, *e = s + n; p != e; ++p) nextChar(*p);
166 buf->sputn(s, n);
167 return n;
168 }
169 };
170
171 // The result will be put here.
172 std::stringbuf code_buf;
173 std::vector<uint32_t> offset_table;
174
175 // If get_code is set, use ostringstream. If get_table is set, use
176 // LineCountingStream. Both can be combined.
177 NullBuf nullbuf;
178 std::streambuf *selected_streambuf =
179 get_code ? &code_buf : static_cast<std::streambuf *>(&nullbuf);
180 LineCountingStream line_counting_stream(selected_streambuf);
181 std::ostream line_counting_ostream(&line_counting_stream);
182 std::function<void(int)> instruction_callback;
183 if (get_table) {
184 instruction_callback = [&](uint32_t offset) {
185 offset_table.push_back(offset);
186 offset_table.push_back(line_counting_stream.line_nr);
187 offset_table.push_back(line_counting_stream.col_nr);
188 };
189 selected_streambuf = &line_counting_stream;
190 }
191
192 {
193 DisallowHeapAllocation no_gc;
194 DCHECK(function_bytes->IsSeqOneByteString());
195 Vector<const uint8_t> bytes_vec =
196 function_bytes->GetFlatContent().ToOneByteVector();
197
198 base::AccountingAllocator allocator;
199 std::ostream os(selected_streambuf);
200 if (!PrintAst(&allocator,
201 FunctionBody::ForTesting(bytes_vec.start(), bytes_vec.end()),
202 os, instruction_callback)) {
203 return isolate->factory()->undefined_value();
204 }
205 }
206
207 Handle<FixedArray> return_arr = isolate->factory()->NewFixedArray(2);
208
209 if (get_code) {
210 // Unfortunately, we have to copy the string here.
211 std::string code_str = code_buf.str();
212 CHECK_LE(code_str.length(), std::numeric_limits<int>::max());
213 return_arr->set(
214 0, *isolate->factory()
215 ->NewStringFromAscii(Vector<const char>(
216 code_str.data(), static_cast<int>(code_str.length())))
217 .ToHandleChecked());
218 }
219
220 if (get_table) {
221 DCHECK_LE(offset_table.size(), std::numeric_limits<int>::max());
222 Handle<FixedArray> offset_arr = isolate->factory()->NewFixedArray(
223 static_cast<int>(offset_table.size()));
224 int idx = 0;
225 for (uint32_t elem : offset_table) {
226 offset_arr->set(idx++, Smi::FromInt(elem));
227 }
228 DCHECK(idx % 3 == 0);
229 DCHECK_EQ(idx, offset_arr->length());
230 return_arr->set(1, *isolate->factory()->NewJSArrayWithElements(offset_arr));
231 }
232
233 return isolate->factory()->NewJSArrayWithElements(return_arr);
234 }
OLDNEW
« src/wasm/wasm-debug.h ('K') | « src/wasm/wasm-debug.h ('k') | src/wasm/wasm-module.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698