[wasm] Set and store breakpoints in wasm
Store breakpoint positions in the WasmSharedModuleData in order to set them on new instantiations. Also redirect them to all live instances at the time the breakpoint is set. Inside the WasmDebugInfo, we store the BreakPointInfo objects to find hit breakpoints. R=titzer@chromium.org, yangguo@chromium.org BUG=v8:5822 Review-Url: https://codereview.chromium.org/2626253002 Cr-Commit-Position: refs/heads/master@{#42443}
This commit is contained in:
parent
7634b0eb13
commit
2f3de27e11
@ -29,6 +29,7 @@
|
||||
#include "src/messages.h"
|
||||
#include "src/snapshot/natives.h"
|
||||
#include "src/wasm/wasm-module.h"
|
||||
#include "src/wasm/wasm-objects.h"
|
||||
|
||||
#include "include/v8-debug.h"
|
||||
|
||||
@ -516,30 +517,18 @@ void Debug::Break(JavaScriptFrame* frame) {
|
||||
// Postpone interrupt during breakpoint processing.
|
||||
PostponeInterruptsScope postpone(isolate_);
|
||||
|
||||
// Return if we fail to retrieve debug info for javascript frames.
|
||||
if (frame->is_java_script()) {
|
||||
JavaScriptFrame* js_frame = JavaScriptFrame::cast(frame);
|
||||
|
||||
// Get the debug info (create it if it does not exist).
|
||||
Handle<JSFunction> function(js_frame->function());
|
||||
Handle<SharedFunctionInfo> shared(function->shared());
|
||||
if (!EnsureDebugInfo(shared, function)) return;
|
||||
}
|
||||
// Return if we fail to retrieve debug info.
|
||||
Handle<JSFunction> function(frame->function());
|
||||
Handle<SharedFunctionInfo> shared(function->shared());
|
||||
if (!EnsureDebugInfo(shared, function)) return;
|
||||
|
||||
BreakLocation location = BreakLocation::FromFrame(frame);
|
||||
|
||||
// Find actual break points, if any, and trigger debug break event.
|
||||
MaybeHandle<FixedArray> break_points_hit;
|
||||
if (!break_points_active()) {
|
||||
// Don't try to find hit breakpoints.
|
||||
} else if (frame->is_wasm_interpreter_entry()) {
|
||||
// TODO(clemensh): Find hit breakpoints for wasm.
|
||||
UNIMPLEMENTED();
|
||||
} else {
|
||||
if (break_points_active()) {
|
||||
// Get the debug info, which must exist if we reach here.
|
||||
Handle<DebugInfo> debug_info(
|
||||
JavaScriptFrame::cast(frame)->function()->shared()->GetDebugInfo(),
|
||||
isolate_);
|
||||
Handle<DebugInfo> debug_info(shared->GetDebugInfo(), isolate_);
|
||||
|
||||
break_points_hit = CheckBreakPoints(debug_info, &location);
|
||||
}
|
||||
@ -722,9 +711,12 @@ bool Debug::SetBreakPointForScript(Handle<Script> script,
|
||||
int* source_position,
|
||||
BreakPositionAlignment alignment) {
|
||||
if (script->type() == Script::TYPE_WASM) {
|
||||
// TODO(clemensh): set breakpoint for wasm.
|
||||
return false;
|
||||
Handle<WasmCompiledModule> compiled_module(
|
||||
WasmCompiledModule::cast(script->wasm_compiled_module()), isolate_);
|
||||
return WasmCompiledModule::SetBreakPoint(compiled_module, source_position,
|
||||
break_point_object);
|
||||
}
|
||||
|
||||
HandleScope scope(isolate_);
|
||||
|
||||
// Obtain shared function info for the function.
|
||||
|
@ -2478,6 +2478,13 @@ Handle<DebugInfo> Factory::NewDebugInfo(Handle<SharedFunctionInfo> shared) {
|
||||
return debug_info;
|
||||
}
|
||||
|
||||
Handle<BreakPointInfo> Factory::NewBreakPointInfo(int source_position) {
|
||||
Handle<BreakPointInfo> new_break_point_info =
|
||||
Handle<BreakPointInfo>::cast(NewStruct(BREAK_POINT_INFO_TYPE));
|
||||
new_break_point_info->set_source_position(source_position);
|
||||
new_break_point_info->set_break_point_objects(*undefined_value());
|
||||
return new_break_point_info;
|
||||
}
|
||||
|
||||
Handle<JSObject> Factory::NewArgumentsObject(Handle<JSFunction> callee,
|
||||
int length) {
|
||||
|
@ -326,6 +326,8 @@ class V8_EXPORT_PRIVATE Factory final {
|
||||
|
||||
Handle<Script> NewScript(Handle<String> source);
|
||||
|
||||
Handle<BreakPointInfo> NewBreakPointInfo(int source_position);
|
||||
|
||||
// Foreign objects are pretenured when allocated by the bootstrapper.
|
||||
Handle<Foreign> NewForeign(Address addr,
|
||||
PretenureFlag pretenure = NOT_TENURED);
|
||||
|
@ -18599,11 +18599,8 @@ void DebugInfo::SetBreakPoint(Handle<DebugInfo> debug_info, int source_position,
|
||||
DCHECK(index != kNoBreakPointInfo);
|
||||
|
||||
// Allocate new BreakPointInfo object and set the break point.
|
||||
Handle<BreakPointInfo> new_break_point_info = Handle<BreakPointInfo>::cast(
|
||||
isolate->factory()->NewStruct(BREAK_POINT_INFO_TYPE));
|
||||
new_break_point_info->set_source_position(source_position);
|
||||
new_break_point_info->set_break_point_objects(
|
||||
isolate->heap()->undefined_value());
|
||||
Handle<BreakPointInfo> new_break_point_info =
|
||||
isolate->factory()->NewBreakPointInfo(source_position);
|
||||
BreakPointInfo::SetBreakPoint(new_break_point_info, break_point_object);
|
||||
debug_info->break_points()->set(index, *new_break_point_info);
|
||||
}
|
||||
|
@ -1430,6 +1430,13 @@ class WasmInstanceBuilder {
|
||||
v8::WeakCallbackType::kFinalizer);
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Set all breakpoints that were set on the shared module.
|
||||
//--------------------------------------------------------------------------
|
||||
WasmSharedModuleData::SetBreakpointsOnNewInstance(
|
||||
compiled_module_->shared(), instance);
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Run the start function if one was specified.
|
||||
//--------------------------------------------------------------------------
|
||||
|
@ -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 =
|
||||
|
@ -5,6 +5,7 @@
|
||||
#ifndef V8_WASM_OBJECTS_H_
|
||||
#define V8_WASM_OBJECTS_H_
|
||||
|
||||
#include "src/debug/debug.h"
|
||||
#include "src/debug/interface-types.h"
|
||||
#include "src/objects-inl.h"
|
||||
#include "src/trap-handler/trap-handler.h"
|
||||
@ -36,6 +37,10 @@ class WasmInstanceWrapper;
|
||||
bool has_##name(); \
|
||||
DECLARE_ACCESSORS(name, type)
|
||||
|
||||
#define DECLARE_OPTIONAL_GETTER(name, type) \
|
||||
bool has_##name(); \
|
||||
DECLARE_GETTER(name, type)
|
||||
|
||||
// Representation of a WebAssembly.Module JavaScript-level object.
|
||||
class WasmModuleObject : public JSObject {
|
||||
public:
|
||||
@ -158,6 +163,7 @@ class WasmSharedModuleData : public FixedArray {
|
||||
kModuleBytes,
|
||||
kScript,
|
||||
kAsmJsOffsetTable,
|
||||
kBreakPointInfos,
|
||||
kFieldCount
|
||||
};
|
||||
|
||||
@ -168,6 +174,7 @@ class WasmSharedModuleData : public FixedArray {
|
||||
DECLARE_OPTIONAL_ACCESSORS(module_bytes, SeqOneByteString);
|
||||
DECLARE_GETTER(script, Script);
|
||||
DECLARE_OPTIONAL_ACCESSORS(asm_js_offset_table, ByteArray);
|
||||
DECLARE_OPTIONAL_GETTER(breakpoint_infos, FixedArray);
|
||||
|
||||
static Handle<WasmSharedModuleData> New(
|
||||
Isolate* isolate, Handle<Foreign> module_wrapper,
|
||||
@ -179,6 +186,12 @@ class WasmSharedModuleData : public FixedArray {
|
||||
|
||||
// Recreate the ModuleWrapper from the module bytes after deserialization.
|
||||
static void RecreateModuleWrapper(Isolate*, Handle<WasmSharedModuleData>);
|
||||
|
||||
static void AddBreakpoint(Handle<WasmSharedModuleData>, int position,
|
||||
Handle<Object> break_point_object);
|
||||
|
||||
static void SetBreakpointsOnNewInstance(Handle<WasmSharedModuleData>,
|
||||
Handle<WasmInstanceObject>);
|
||||
};
|
||||
|
||||
class WasmCompiledModule : public FixedArray {
|
||||
@ -374,6 +387,15 @@ class WasmCompiledModule : public FixedArray {
|
||||
const debug::Location& end,
|
||||
std::vector<debug::Location>* locations);
|
||||
|
||||
// Set a breakpoint on the given byte position inside the given module.
|
||||
// This will affect all live and future instances of the module.
|
||||
// The passed position might be modified to point to the next breakable
|
||||
// location inside the same function.
|
||||
// If it points outside a function, or behind the last breakable location,
|
||||
// this function returns false and does not set any breakpoint.
|
||||
static bool SetBreakPoint(Handle<WasmCompiledModule>, int* position,
|
||||
Handle<Object> break_point_object);
|
||||
|
||||
private:
|
||||
void InitId();
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user