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

Unified Diff: src/wasm/wasm-objects.cc

Issue 2626253002: [wasm] Set and store breakpoints in wasm (Closed)
Patch Set: Remove CheckBreakPoints methods Created 3 years, 11 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
« no previous file with comments | « src/wasm/wasm-objects.h ('k') | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: src/wasm/wasm-objects.cc
diff --git a/src/wasm/wasm-objects.cc b/src/wasm/wasm-objects.cc
index 3c0139242d23b48b495e91461bfb5b7cf1220227..2f0cdce23d598b006adebbc220681724572ea46e 100644
--- a/src/wasm/wasm-objects.cc
+++ b/src/wasm/wasm-objects.cc
@@ -5,6 +5,7 @@
#include "src/wasm/wasm-objects.h"
#include "src/utils.h"
+#include "src/base/iterator.h"
#include "src/debug/debug-interface.h"
#include "src/wasm/module-decoder.h"
#include "src/wasm/wasm-module.h"
@@ -37,6 +38,15 @@ using namespace v8::internal::wasm;
return !getter(field)->IsUndefined(GetIsolate()); \
}
+#define DEFINE_OPTIONAL_GETTER0(getter, Container, name, field, type) \
+ DEFINE_GETTER0(getter, Container, name, field, type) \
+ bool Container::has_##name() { \
+ return !getter(field)->IsUndefined(GetIsolate()); \
+ }
+
+#define DEFINE_GETTER0(getter, Container, name, field, type) \
+ type* Container::name() { return type::cast(getter(field)); }
+
#define DEFINE_OBJ_GETTER(Container, name, field, type) \
DEFINE_GETTER0(GetInternalField, Container, name, field, type)
#define DEFINE_OBJ_ACCESSORS(Container, name, field, type) \
@@ -51,6 +61,8 @@ using namespace v8::internal::wasm;
DEFINE_ACCESSORS0(get, set, Container, name, field, type)
#define DEFINE_OPTIONAL_ARR_ACCESSORS(Container, name, field, type) \
DEFINE_OPTIONAL_ACCESSORS0(get, set, Container, name, field, type)
+#define DEFINE_OPTIONAL_ARR_GETTER(Container, name, field, type) \
+ DEFINE_OPTIONAL_GETTER0(get, Container, name, field, type)
namespace {
@@ -78,6 +90,130 @@ int32_t SafeInt32(Object* value) {
return static_cast<int32_t>(num->value());
}
+// An iterator that returns first the module itself, then all modules linked via
+// next, then all linked via prev.
+class CompiledModulesIterator
+ : public std::iterator<std::input_iterator_tag,
+ Handle<WasmCompiledModule>> {
+ public:
+ CompiledModulesIterator(Isolate* isolate,
+ Handle<WasmCompiledModule> start_module, bool at_end)
+ : isolate_(isolate),
+ start_module_(start_module),
+ current_(at_end ? Handle<WasmCompiledModule>::null() : start_module) {}
+
+ Handle<WasmCompiledModule> operator*() const {
+ DCHECK(!current_.is_null());
+ return current_;
+ }
+
+ void operator++() { Advance(); }
+
+ bool operator!=(const CompiledModulesIterator& other) {
+ DCHECK(start_module_.is_identical_to(other.start_module_));
+ return !current_.is_identical_to(other.current_);
+ }
+
+ private:
+ void Advance() {
+ DCHECK(!current_.is_null());
+ if (!is_backwards_) {
+ if (current_->has_weak_next_instance()) {
+ WeakCell* weak_next = current_->ptr_to_weak_next_instance();
+ if (!weak_next->cleared()) {
+ current_ =
+ handle(WasmCompiledModule::cast(weak_next->value()), isolate_);
+ return;
+ }
+ }
+ // No more modules in next-links, now try the previous-links.
+ is_backwards_ = true;
+ current_ = start_module_;
+ }
+ if (current_->has_weak_prev_instance()) {
+ WeakCell* weak_prev = current_->ptr_to_weak_prev_instance();
+ if (!weak_prev->cleared()) {
+ current_ =
+ handle(WasmCompiledModule::cast(weak_prev->value()), isolate_);
+ return;
+ }
+ }
+ current_ = Handle<WasmCompiledModule>::null();
+ }
+
+ friend class CompiledModuleInstancesIterator;
+ Isolate* isolate_;
+ Handle<WasmCompiledModule> start_module_;
+ Handle<WasmCompiledModule> current_;
+ bool is_backwards_ = false;
+};
+
+// An iterator based on the CompiledModulesIterator, but it returns all live
+// instances, not the WasmCompiledModules itself.
+class CompiledModuleInstancesIterator
+ : public std::iterator<std::input_iterator_tag,
+ Handle<WasmInstanceObject>> {
+ public:
+ CompiledModuleInstancesIterator(Isolate* isolate,
+ Handle<WasmCompiledModule> start_module,
+ bool at_end)
+ : it(isolate, start_module, at_end) {
+ while (NeedToAdvance()) ++it;
+ }
+
+ Handle<WasmInstanceObject> operator*() {
+ return handle(
+ WasmInstanceObject::cast((*it)->weak_owning_instance()->value()),
+ it.isolate_);
+ }
+
+ void operator++() {
+ do {
+ ++it;
+ } while (NeedToAdvance());
+ }
+
+ bool operator!=(const CompiledModuleInstancesIterator& other) {
+ return it != other.it;
+ }
+
+ private:
+ bool NeedToAdvance() {
+ return !it.current_.is_null() &&
+ (!it.current_->has_weak_owning_instance() ||
+ it.current_->ptr_to_weak_owning_instance()->cleared());
+ }
+ CompiledModulesIterator it;
+};
+
+v8::base::iterator_range<CompiledModuleInstancesIterator>
+iterate_compiled_module_instance_chain(
+ Isolate* isolate, Handle<WasmCompiledModule> compiled_module) {
+ return {CompiledModuleInstancesIterator(isolate, compiled_module, false),
+ CompiledModuleInstancesIterator(isolate, compiled_module, true)};
+}
+
+#ifdef DEBUG
+bool IsBreakablePosition(Handle<WasmCompiledModule> compiled_module,
+ int func_index, int offset_in_func) {
+ DisallowHeapAllocation no_gc;
+ AccountingAllocator alloc;
+ Zone tmp(&alloc, ZONE_NAME);
+ BodyLocalDecls locals(&tmp);
+ const byte* module_start = compiled_module->module_bytes()->GetChars();
+ WasmFunction& func = compiled_module->module()->functions[func_index];
+ BytecodeIterator iterator(module_start + func.code_start_offset,
+ module_start + func.code_end_offset, &locals);
+ DCHECK_LT(0, locals.encoded_size);
+ uint32_t found_position = 0;
+ for (uint32_t offset : iterator.offsets()) {
+ if (offset > static_cast<uint32_t>(offset_in_func)) break;
+ if (offset == static_cast<uint32_t>(offset_in_func)) return true;
+ }
+ return false;
+}
+#endif // DEBUG
+
} // namespace
Handle<WasmModuleObject> WasmModuleObject::New(
@@ -383,6 +519,9 @@ bool WasmSharedModuleData::IsWasmSharedModuleData(Object* object) {
if (!arr->get(kAsmJsOffsetTable)->IsUndefined(isolate) &&
!arr->get(kAsmJsOffsetTable)->IsByteArray())
return false;
+ if (!arr->get(kBreakPointInfos)->IsUndefined(isolate) &&
+ !arr->get(kBreakPointInfos)->IsFixedArray())
+ return false;
return true;
}
@@ -400,6 +539,8 @@ DEFINE_OPTIONAL_ARR_ACCESSORS(WasmSharedModuleData, module_bytes, kModuleBytes,
DEFINE_ARR_GETTER(WasmSharedModuleData, script, kScript, Script);
DEFINE_OPTIONAL_ARR_ACCESSORS(WasmSharedModuleData, asm_js_offset_table,
kAsmJsOffsetTable, ByteArray);
+DEFINE_OPTIONAL_ARR_GETTER(WasmSharedModuleData, breakpoint_infos,
+ kBreakPointInfos, FixedArray);
Handle<WasmSharedModuleData> WasmSharedModuleData::New(
Isolate* isolate, Handle<Foreign> module_wrapper,
@@ -459,6 +600,126 @@ void WasmSharedModuleData::RecreateModuleWrapper(
DCHECK(WasmSharedModuleData::IsWasmSharedModuleData(*shared));
}
+namespace {
+
+int GetBreakpointPos(Isolate* isolate, Object* break_point_info_or_undef) {
+ if (break_point_info_or_undef->IsUndefined(isolate)) return kMaxInt;
+ return BreakPointInfo::cast(break_point_info_or_undef)->source_position();
+}
+
+int FindBreakpointInfoInsertPos(Isolate* isolate,
+ Handle<FixedArray> breakpoint_infos,
+ int position) {
+ // Find insert location via binary search, taking care of undefined values on
+ // the right. Position is always greater than zero.
+ DCHECK_LT(0, position);
+
+ int left = 0; // inclusive
+ int right = breakpoint_infos->length(); // exclusive
+ while (right - left > 1) {
+ int mid = left + (right - left) / 2;
+ Object* mid_obj = breakpoint_infos->get(mid);
+ if (GetBreakpointPos(isolate, mid_obj) <= position) {
+ left = mid;
+ } else {
+ right = mid;
+ }
+ }
+
+ int left_pos = GetBreakpointPos(isolate, breakpoint_infos->get(left));
+ return left_pos < position ? left + 1 : left;
+}
+
+} // namespace
+
+void WasmSharedModuleData::AddBreakpoint(Handle<WasmSharedModuleData> shared,
+ int position,
+ Handle<Object> break_point_object) {
+ Isolate* isolate = shared->GetIsolate();
+ Handle<FixedArray> breakpoint_infos;
+ if (shared->has_breakpoint_infos()) {
+ breakpoint_infos = handle(shared->breakpoint_infos(), isolate);
+ } else {
+ breakpoint_infos = isolate->factory()->NewFixedArray(4, TENURED);
+ shared->set(kBreakPointInfos, *breakpoint_infos);
+ }
+
+ int insert_pos =
+ FindBreakpointInfoInsertPos(isolate, breakpoint_infos, position);
+
+ // If a BreakPointInfo object already exists for this position, add the new
+ // breakpoint object and return.
+ if (insert_pos < breakpoint_infos->length() &&
+ GetBreakpointPos(isolate, breakpoint_infos->get(insert_pos)) ==
+ position) {
+ Handle<BreakPointInfo> old_info(
+ BreakPointInfo::cast(breakpoint_infos->get(insert_pos)), isolate);
+ BreakPointInfo::SetBreakPoint(old_info, break_point_object);
+ return;
+ }
+
+ // Enlarge break positions array if necessary.
+ bool need_realloc = !breakpoint_infos->get(breakpoint_infos->length() - 1)
+ ->IsUndefined(isolate);
+ Handle<FixedArray> new_breakpoint_infos = breakpoint_infos;
+ if (need_realloc) {
+ new_breakpoint_infos = isolate->factory()->NewFixedArray(
+ 2 * breakpoint_infos->length(), TENURED);
+ shared->set(kBreakPointInfos, *new_breakpoint_infos);
+ // Copy over the entries [0, insert_pos).
+ for (int i = 0; i < insert_pos; ++i)
+ new_breakpoint_infos->set(i, breakpoint_infos->get(i));
+ }
+
+ // Move elements [insert_pos+1, ...] up by one.
+ for (int i = insert_pos + 1; i < breakpoint_infos->length(); ++i) {
+ Object* entry = breakpoint_infos->get(i);
+ if (entry->IsUndefined(isolate)) break;
+ new_breakpoint_infos->set(i + 1, entry);
+ }
+
+ // Generate new BreakpointInfo.
+ Handle<BreakPointInfo> breakpoint_info =
+ isolate->factory()->NewBreakPointInfo(position);
+ BreakPointInfo::SetBreakPoint(breakpoint_info, break_point_object);
+
+ // Now insert new position at insert_pos.
+ new_breakpoint_infos->set(insert_pos, *breakpoint_info);
+}
+
+void WasmSharedModuleData::SetBreakpointsOnNewInstance(
+ Handle<WasmSharedModuleData> shared, Handle<WasmInstanceObject> instance) {
+ if (!shared->has_breakpoint_infos()) return;
+ Isolate* isolate = shared->GetIsolate();
+ Handle<WasmCompiledModule> compiled_module(instance->compiled_module(),
+ isolate);
+ Handle<WasmDebugInfo> debug_info =
+ WasmInstanceObject::GetOrCreateDebugInfo(instance);
+
+ Handle<FixedArray> breakpoint_infos(shared->breakpoint_infos(), isolate);
+ // If the array exists, it should not be empty.
+ DCHECK_LT(0, breakpoint_infos->length());
+
+ for (int i = 0, e = breakpoint_infos->length(); i < e; ++i) {
+ Handle<Object> obj(breakpoint_infos->get(i), isolate);
+ if (obj->IsUndefined(isolate)) {
+ for (; i < e; ++i) {
+ DCHECK(breakpoint_infos->get(i)->IsUndefined(isolate));
+ }
+ break;
+ }
+ Handle<BreakPointInfo> breakpoint_info = Handle<BreakPointInfo>::cast(obj);
+ int position = breakpoint_info->source_position();
+
+ // Find the function for this breakpoint, and set the breakpoint.
+ int func_index = compiled_module->GetContainingFunction(position);
+ DCHECK_LE(0, func_index);
+ WasmFunction& func = compiled_module->module()->functions[func_index];
+ int offset_in_func = position - func.code_start_offset;
+ WasmDebugInfo::SetBreakpoint(debug_info, func_index, offset_in_func);
+ }
+}
+
Handle<WasmCompiledModule> WasmCompiledModule::New(
Isolate* isolate, Handle<WasmSharedModuleData> shared) {
Handle<FixedArray> ret =
@@ -832,6 +1093,37 @@ bool WasmCompiledModule::GetPossibleBreakpoints(
return true;
}
+bool WasmCompiledModule::SetBreakPoint(
+ Handle<WasmCompiledModule> compiled_module, int* position,
+ Handle<Object> break_point_object) {
+ Isolate* isolate = compiled_module->GetIsolate();
+
+ // Find the function for this breakpoint.
+ int func_index = compiled_module->GetContainingFunction(*position);
+ if (func_index < 0) return false;
+ WasmFunction& func = compiled_module->module()->functions[func_index];
+ int offset_in_func = *position - func.code_start_offset;
+
+ // According to the current design, we should only be called with valid
+ // breakable positions.
+ DCHECK(IsBreakablePosition(compiled_module, func_index, offset_in_func));
+
+ // Insert new break point into break_positions of shared module data.
+ WasmSharedModuleData::AddBreakpoint(compiled_module->shared(), *position,
+ break_point_object);
+
+ // Iterate over all instances of this module and tell them to set this new
+ // breakpoint.
+ for (Handle<WasmInstanceObject> instance :
+ iterate_compiled_module_instance_chain(isolate, compiled_module)) {
+ Handle<WasmDebugInfo> debug_info =
+ WasmInstanceObject::GetOrCreateDebugInfo(instance);
+ WasmDebugInfo::SetBreakpoint(debug_info, func_index, offset_in_func);
+ }
+
+ return true;
+}
+
Handle<WasmInstanceWrapper> WasmInstanceWrapper::New(
Isolate* isolate, Handle<WasmInstanceObject> instance) {
Handle<FixedArray> array =
« no previous file with comments | « src/wasm/wasm-objects.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698