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

Unified 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 side-by-side diff with in-line comments
Download patch
Index: src/wasm/wasm-debug.cc
diff --git a/src/wasm/wasm-debug.cc b/src/wasm/wasm-debug.cc
new file mode 100644
index 0000000000000000000000000000000000000000..65e313ba26dc1ac23739ceb72dd3dbb4841dff0f
--- /dev/null
+++ b/src/wasm/wasm-debug.cc
@@ -0,0 +1,234 @@
+// Copyright 2016 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "src/wasm/wasm-debug.h"
+
+#include "src/assert-scope.h"
+#include "src/debug/debug.h"
+#include "src/factory.h"
+#include "src/isolate.h"
+#include "src/wasm/module-decoder.h"
+#include "src/wasm/wasm-module.h"
+
+using namespace v8::internal;
+using namespace v8::internal::wasm;
+
+namespace {
+
+enum {
+ kWasmDebugInfoWasmObj,
+ kWasmDebugInfoWasmBytesHash,
+ kWasmDebugInfoFunctionOffsets,
+ kWasmDebugInfoNumInternalFields
+};
+
+ByteArray *GetOrCreateFunctionOffsetTable(WasmDebugInfo *debug_info) {
+ Object *offset_table =
+ debug_info->GetInternalField(kWasmDebugInfoFunctionOffsets);
+ if (!offset_table->IsUndefined()) return ByteArray::cast(offset_table);
+
+ FunctionOffsetsResult function_offsets;
+ {
+ DisallowHeapAllocation no_gc;
+ SeqOneByteString *wasm_bytes =
+ wasm::GetWasmBytes(debug_info->wasm_object());
+ const byte *bytes_start = wasm_bytes->GetChars();
+ const byte *bytes_end = bytes_start + wasm_bytes->length();
+ function_offsets = wasm::DecodeWasmFunctionOffsets(bytes_start, bytes_end);
+ }
+ DCHECK(function_offsets.ok());
+ Isolate *isolate = debug_info->GetIsolate();
+ size_t array_size =
+ 2 * sizeof(int) * static_cast<int>(function_offsets.val.size());
+ CHECK_LE(array_size, std::numeric_limits<int>::max());
+ ByteArray *arr =
+ *isolate->factory()->NewByteArray(static_cast<int>(array_size));
+ int idx = 0;
+ for (std::pair<int, int> p : function_offsets.val) {
+ arr->set_int(idx++, p.first);
+ arr->set_int(idx++, p.second);
+ }
+ DCHECK_EQ(arr->length(), idx * sizeof(int));
+ debug_info->SetInternalField(kWasmDebugInfoFunctionOffsets, arr);
+
+ return arr;
+}
+
+} // namespace
+
+Handle<WasmDebugInfo> WasmDebugInfo::New(Handle<JSObject> wasm) {
+ Isolate *isolate = wasm->GetIsolate();
+ Factory *factory = isolate->factory();
+ Handle<Map> map = factory->NewMap(
+ JS_OBJECT_TYPE,
+ JSObject::kHeaderSize + kWasmDebugInfoNumInternalFields * kPointerSize);
+ Handle<JSObject> info = factory->NewJSObjectFromMap(map, TENURED);
+ info->SetInternalField(kWasmDebugInfoWasmObj, *wasm);
+ int hash = 0;
+ Handle<SeqOneByteString> wasm_bytes(GetWasmBytes(*wasm), isolate);
+ {
+ DisallowHeapAllocation no_gc;
+ hash = StringHasher::HashSequentialString(wasm_bytes->GetChars(),
+ wasm_bytes->length(), 0);
+ }
+ info->SetInternalField(kWasmDebugInfoWasmBytesHash,
+ *factory->NewNumberFromInt(hash, TENURED));
+
+ // TODO(clemensh): Register the wasm module at the debugger
+
+ return Handle<WasmDebugInfo>::cast(info);
+}
+
+bool WasmDebugInfo::IsDebugInfo(Object *object) {
+ if (!object->IsJSObject()) return false;
+ JSObject *obj = JSObject::cast(object);
+ return obj->GetInternalFieldCount() == kWasmDebugInfoNumInternalFields &&
+ IsWasmObject(obj->GetInternalField(kWasmDebugInfoWasmObj)) &&
+ obj->GetInternalField(kWasmDebugInfoWasmBytesHash)->IsNumber() &&
+ (obj->GetInternalField(kWasmDebugInfoFunctionOffsets)->IsUndefined() ||
+ obj->GetInternalField(kWasmDebugInfoFunctionOffsets)->IsByteArray());
+}
+
+WasmDebugInfo *WasmDebugInfo::cast(Object *object) {
+ DCHECK(IsDebugInfo(object));
+ return static_cast<WasmDebugInfo *>(object);
+}
+
+JSObject *WasmDebugInfo::wasm_object() {
+ return JSObject::cast(GetInternalField(kWasmDebugInfoWasmObj));
+}
+
+bool WasmDebugInfo::SetBreakPoint(int byte_offset) { return false; }
+
+std::pair<int, int> WasmDebugInfo::GetFunctionOffsetAndLength(int func_index) {
+ ByteArray *arr = GetOrCreateFunctionOffsetTable(this);
+
+ if (func_index < 0 || func_index >= arr->length() / sizeof(int) / 2) {
+ return {0, 0};
+ }
+ int offset = arr->get_int(2 * func_index);
+ int length = arr->get_int(2 * func_index + 1);
+ // Assert that it's distinguishable from the "illegal function index" return.
+ DCHECK(offset > 0 && length > 0);
+ return {offset, length};
+}
+
+Handle<Object> wasm::GetFunctionOffsetTable(Isolate *isolate,
+ Handle<String> module_bytes) {
+ FunctionOffsetsResult function_offsets;
+ {
+ DisallowHeapAllocation no_gc;
+ DCHECK(module_bytes->IsSeqOneByteString());
+ Vector<const uint8_t> bytes_vec =
+ module_bytes->GetFlatContent().ToOneByteVector();
+ function_offsets =
+ wasm::DecodeWasmFunctionOffsets(bytes_vec.start(), bytes_vec.end());
+ }
+ if (!function_offsets.ok()) return isolate->factory()->undefined_value();
+
+ size_t array_size = 2 * function_offsets.val.size();
+ CHECK_LE(array_size, std::numeric_limits<int>::max());
+ Handle<FixedArray> arr =
+ isolate->factory()->NewFixedArray(static_cast<int>(array_size));
+ int idx = 0;
+ for (std::pair<int, int> p : function_offsets.val) {
+ arr->set(idx++, Smi::FromInt(p.first));
+ arr->set(idx++, Smi::FromInt(p.second));
+ }
+ DCHECK_EQ(arr->length(), idx);
+ return isolate->factory()->NewJSArrayWithElements(arr);
+}
+
+Handle<Object> wasm::DisassembleFunction(Isolate *isolate,
+ Handle<String> function_bytes,
+ bool get_code, bool get_table) {
+ struct NullBuf : public std::streambuf {};
+ struct LineCountingStream : public std::streambuf {
+ std::streambuf *buf;
+ uint32_t line_nr = 0;
+ uint32_t col_nr = 0;
+
+ explicit LineCountingStream(std::streambuf *buf) : buf(buf) {}
+ inline void nextChar(int_type c) {
+ ++col_nr;
+ if (c == '\n') ++line_nr, col_nr = 0;
+ }
+ int_type overflow(int_type c) override {
+ if (c != EOF) {
+ nextChar(c);
+ buf->sputc(c);
+ }
+ return c;
+ }
+ std::streamsize xsputn(const char *s, std::streamsize n) override {
+ for (const char *p = s, *e = s + n; p != e; ++p) nextChar(*p);
+ buf->sputn(s, n);
+ return n;
+ }
+ };
+
+ // The result will be put here.
+ std::stringbuf code_buf;
+ std::vector<uint32_t> offset_table;
+
+ // If get_code is set, use ostringstream. If get_table is set, use
+ // LineCountingStream. Both can be combined.
+ NullBuf nullbuf;
+ std::streambuf *selected_streambuf =
+ get_code ? &code_buf : static_cast<std::streambuf *>(&nullbuf);
+ LineCountingStream line_counting_stream(selected_streambuf);
+ std::ostream line_counting_ostream(&line_counting_stream);
+ std::function<void(int)> instruction_callback;
+ if (get_table) {
+ instruction_callback = [&](uint32_t offset) {
+ offset_table.push_back(offset);
+ offset_table.push_back(line_counting_stream.line_nr);
+ offset_table.push_back(line_counting_stream.col_nr);
+ };
+ selected_streambuf = &line_counting_stream;
+ }
+
+ {
+ DisallowHeapAllocation no_gc;
+ DCHECK(function_bytes->IsSeqOneByteString());
+ Vector<const uint8_t> bytes_vec =
+ function_bytes->GetFlatContent().ToOneByteVector();
+
+ base::AccountingAllocator allocator;
+ std::ostream os(selected_streambuf);
+ if (!PrintAst(&allocator,
+ FunctionBody::ForTesting(bytes_vec.start(), bytes_vec.end()),
+ os, instruction_callback)) {
+ return isolate->factory()->undefined_value();
+ }
+ }
+
+ Handle<FixedArray> return_arr = isolate->factory()->NewFixedArray(2);
+
+ if (get_code) {
+ // Unfortunately, we have to copy the string here.
+ std::string code_str = code_buf.str();
+ CHECK_LE(code_str.length(), std::numeric_limits<int>::max());
+ return_arr->set(
+ 0, *isolate->factory()
+ ->NewStringFromAscii(Vector<const char>(
+ code_str.data(), static_cast<int>(code_str.length())))
+ .ToHandleChecked());
+ }
+
+ if (get_table) {
+ DCHECK_LE(offset_table.size(), std::numeric_limits<int>::max());
+ Handle<FixedArray> offset_arr = isolate->factory()->NewFixedArray(
+ static_cast<int>(offset_table.size()));
+ int idx = 0;
+ for (uint32_t elem : offset_table) {
+ offset_arr->set(idx++, Smi::FromInt(elem));
+ }
+ DCHECK(idx % 3 == 0);
+ DCHECK_EQ(idx, offset_arr->length());
+ return_arr->set(1, *isolate->factory()->NewJSArrayWithElements(offset_arr));
+ }
+
+ return isolate->factory()->NewJSArrayWithElements(return_arr);
+}
« 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