[wasm] Clarify source of runtime information for interpreter.
This is part of the effort to consolidate the ownership of wasm instantiation/specialization parameters. This change is focused solely on the interpreter part of that effort, to verify we're not regressing performance in interpreter benchmarks. There are two aspects being addressed: - dataflow-wise, we always fetch the interpreter's memory view from the runtime objects (i.e. WasmInstanceObject/WasmCompiledModule). This is consistent with how other instance-specific information is obtained (e.g. code, indirect functions). - representation-wise, we do not reuse ModuleEnv/WasmInstance just for the memory view, because it is surprising that other instance info isn't accessed from there. Bug: Change-Id: I536fbffd8e1f142a315fa1770ba9b08319f56a8e Reviewed-on: https://chromium-review.googlesource.com/602083 Reviewed-by: Ben Titzer <titzer@chromium.org> Reviewed-by: Clemens Hammacher <clemensh@chromium.org> Commit-Queue: Mircea Trofin <mtrofin@chromium.org> Cr-Commit-Position: refs/heads/master@{#47205}
This commit is contained in:
parent
81778aaf72
commit
3f1e32b336
@ -95,10 +95,9 @@ InterpreterHandle* GetInterpreterHandle(WasmDebugInfo* debug_info);
|
||||
|
||||
class InterpreterHandle {
|
||||
MOVE_ONLY_NO_DEFAULT_CONSTRUCTOR(InterpreterHandle);
|
||||
|
||||
WasmInstance instance_;
|
||||
WasmInterpreter interpreter_;
|
||||
Isolate* isolate_;
|
||||
const WasmModule* module_;
|
||||
WasmInterpreter interpreter_;
|
||||
StepAction next_step_action_ = StepNone;
|
||||
int last_step_stack_depth_ = 0;
|
||||
std::unordered_map<Address, uint32_t> activations_;
|
||||
@ -132,50 +131,53 @@ class InterpreterHandle {
|
||||
return {frame_base, frame_limit};
|
||||
}
|
||||
|
||||
public:
|
||||
// Initialize in the right order, using helper methods to make this possible.
|
||||
// WasmInterpreter has to be allocated in place, since it is not movable.
|
||||
InterpreterHandle(Isolate* isolate, WasmDebugInfo* debug_info,
|
||||
WasmInstance* external_instance = nullptr)
|
||||
: instance_(debug_info->wasm_instance()->compiled_module()->module()),
|
||||
interpreter_(isolate, GetBytesEnv(external_instance ? external_instance
|
||||
: &instance_,
|
||||
debug_info)),
|
||||
isolate_(isolate) {
|
||||
DisallowHeapAllocation no_gc;
|
||||
|
||||
WasmInstanceObject* instance = debug_info->wasm_instance();
|
||||
|
||||
// Set memory start pointer and size.
|
||||
instance_.mem_start = nullptr;
|
||||
instance_.mem_size = 0;
|
||||
if (instance->has_memory_buffer()) {
|
||||
UpdateMemory(instance->memory_buffer());
|
||||
} else {
|
||||
DCHECK_EQ(0, instance_.module->min_mem_pages);
|
||||
}
|
||||
|
||||
// Set pointer to globals storage.
|
||||
instance_.globals_start =
|
||||
debug_info->wasm_instance()->compiled_module()->GetGlobalsStartOrNull();
|
||||
}
|
||||
|
||||
~InterpreterHandle() {
|
||||
DCHECK_EQ(0, activations_.size());
|
||||
}
|
||||
|
||||
static ModuleBytesEnv GetBytesEnv(WasmInstance* instance,
|
||||
WasmDebugInfo* debug_info) {
|
||||
static Vector<const byte> GetBytes(WasmDebugInfo* debug_info) {
|
||||
// Return raw pointer into heap. The WasmInterpreter will make its own copy
|
||||
// of this data anyway, and there is no heap allocation in-between.
|
||||
SeqOneByteString* bytes_str =
|
||||
debug_info->wasm_instance()->compiled_module()->module_bytes();
|
||||
Vector<const byte> bytes(bytes_str->GetChars(), bytes_str->length());
|
||||
return {instance->module, instance, bytes};
|
||||
return {bytes_str->GetChars(), static_cast<size_t>(bytes_str->length())};
|
||||
}
|
||||
|
||||
static uint32_t GetMemSize(WasmDebugInfo* debug_info) {
|
||||
DisallowHeapAllocation no_gc;
|
||||
WasmCompiledModule* compiled_module =
|
||||
debug_info->wasm_instance()->compiled_module();
|
||||
return compiled_module->has_embedded_mem_size()
|
||||
? compiled_module->embedded_mem_size()
|
||||
: 0;
|
||||
}
|
||||
|
||||
static byte* GetMemStart(WasmDebugInfo* debug_info) {
|
||||
DisallowHeapAllocation no_gc;
|
||||
WasmCompiledModule* compiled_module =
|
||||
debug_info->wasm_instance()->compiled_module();
|
||||
return reinterpret_cast<byte*>(compiled_module->has_embedded_mem_start()
|
||||
? compiled_module->embedded_mem_start()
|
||||
: 0);
|
||||
}
|
||||
|
||||
static byte* GetGlobalsStart(WasmDebugInfo* debug_info) {
|
||||
DisallowHeapAllocation no_gc;
|
||||
WasmCompiledModule* compiled_module =
|
||||
debug_info->wasm_instance()->compiled_module();
|
||||
return reinterpret_cast<byte*>(compiled_module->has_globals_start()
|
||||
? compiled_module->globals_start()
|
||||
: 0);
|
||||
}
|
||||
|
||||
public:
|
||||
InterpreterHandle(Isolate* isolate, WasmDebugInfo* debug_info)
|
||||
: isolate_(isolate),
|
||||
module_(debug_info->wasm_instance()->compiled_module()->module()),
|
||||
interpreter_(isolate, module_, GetBytes(debug_info),
|
||||
GetGlobalsStart(debug_info), GetMemStart(debug_info),
|
||||
GetMemSize(debug_info)) {}
|
||||
|
||||
~InterpreterHandle() { DCHECK_EQ(0, activations_.size()); }
|
||||
|
||||
WasmInterpreter* interpreter() { return &interpreter_; }
|
||||
const WasmModule* module() { return instance_.module; }
|
||||
const WasmModule* module() const { return module_; }
|
||||
|
||||
void PrepareStep(StepAction step_action) {
|
||||
next_step_action_ = step_action;
|
||||
@ -647,11 +649,10 @@ Handle<WasmDebugInfo> WasmDebugInfo::New(Handle<WasmInstanceObject> instance) {
|
||||
}
|
||||
|
||||
WasmInterpreter* WasmDebugInfo::SetupForTesting(
|
||||
Handle<WasmInstanceObject> instance_obj, WasmInstance* instance) {
|
||||
Handle<WasmInstanceObject> instance_obj) {
|
||||
Handle<WasmDebugInfo> debug_info = WasmDebugInfo::New(instance_obj);
|
||||
Isolate* isolate = instance_obj->GetIsolate();
|
||||
InterpreterHandle* cpp_handle =
|
||||
new InterpreterHandle(isolate, *debug_info, instance);
|
||||
InterpreterHandle* cpp_handle = new InterpreterHandle(isolate, *debug_info);
|
||||
Handle<Object> handle = Managed<InterpreterHandle>::New(isolate, cpp_handle);
|
||||
debug_info->set(kInterpreterHandleIndex, *handle);
|
||||
return cpp_handle->interpreter();
|
||||
|
@ -176,6 +176,27 @@ namespace wasm {
|
||||
|
||||
namespace {
|
||||
|
||||
// CachedInstanceInfo encapsulates globals and memory buffer runtime information
|
||||
// for a wasm instance. The interpreter caches that information when
|
||||
// constructed, copying it from the {WasmInstanceObject}. It expects it be
|
||||
// notified on changes to it, e.g. {GrowMemory}. We cache it because interpreter
|
||||
// perf is sensitive to accesses to this information.
|
||||
//
|
||||
// TODO(wasm): other runtime information, such as indirect function table, or
|
||||
// code table (incl. imports) is currently handled separately. Consider
|
||||
// unifying, if possible, with {ModuleEnv}.
|
||||
|
||||
struct CachedInstanceInfo {
|
||||
CachedInstanceInfo(byte* globals, byte* mem, uint32_t size)
|
||||
: globals_start(globals), mem_start(mem), mem_size(size) {}
|
||||
// We do not expect the location of the globals buffer to
|
||||
// change for an instance.
|
||||
byte* const globals_start = nullptr;
|
||||
// The memory buffer may change because of GrowMemory
|
||||
byte* mem_start = nullptr;
|
||||
uint32_t mem_size = 0;
|
||||
};
|
||||
|
||||
inline int32_t ExecuteI32DivS(int32_t a, int32_t b, TrapReason* trap) {
|
||||
if (b == 0) {
|
||||
*trap = kTrapDivByZero;
|
||||
@ -598,18 +619,29 @@ inline int64_t ExecuteI64ReinterpretF64(WasmValue a) {
|
||||
|
||||
inline int32_t ExecuteGrowMemory(uint32_t delta_pages,
|
||||
MaybeHandle<WasmInstanceObject> instance_obj,
|
||||
WasmInstance* instance) {
|
||||
DCHECK_EQ(0, instance->mem_size % WasmModule::kPageSize);
|
||||
uint32_t old_pages = instance->mem_size / WasmModule::kPageSize;
|
||||
CachedInstanceInfo* mem_info) {
|
||||
Handle<WasmInstanceObject> instance = instance_obj.ToHandleChecked();
|
||||
Isolate* isolate = instance->GetIsolate();
|
||||
int32_t ret = WasmInstanceObject::GrowMemory(isolate, instance, delta_pages);
|
||||
|
||||
Isolate* isolate = instance_obj.ToHandleChecked()->GetIsolate();
|
||||
int32_t ret = WasmInstanceObject::GrowMemory(
|
||||
isolate, instance_obj.ToHandleChecked(), delta_pages);
|
||||
// Some sanity checks.
|
||||
DCHECK_EQ(ret == -1 ? old_pages : old_pages + delta_pages,
|
||||
instance->mem_size / WasmModule::kPageSize);
|
||||
DCHECK(ret == -1 || static_cast<uint32_t>(ret) == old_pages);
|
||||
USE(old_pages);
|
||||
#ifdef DEBUG
|
||||
// Ensure the effects of GrowMemory have been observed by the interpreter.
|
||||
// See {UpdateMemory}. In all cases, we are in agreement with the runtime
|
||||
// object's view.
|
||||
uint32_t cached_size = mem_info->mem_size;
|
||||
byte* cached_start = mem_info->mem_start;
|
||||
uint32_t instance_size =
|
||||
instance->compiled_module()->has_embedded_mem_size()
|
||||
? instance->compiled_module()->embedded_mem_size()
|
||||
: 0;
|
||||
byte* instance_start =
|
||||
instance->compiled_module()->has_embedded_mem_start()
|
||||
? reinterpret_cast<byte*>(
|
||||
instance->compiled_module()->embedded_mem_start())
|
||||
: nullptr;
|
||||
CHECK_EQ(cached_size, instance_size);
|
||||
CHECK_EQ(cached_start, instance_start);
|
||||
#endif
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -1100,9 +1132,10 @@ class ThreadImpl {
|
||||
};
|
||||
|
||||
public:
|
||||
ThreadImpl(Zone* zone, CodeMap* codemap, WasmInstance* instance)
|
||||
ThreadImpl(Zone* zone, CodeMap* codemap,
|
||||
CachedInstanceInfo* cached_instance_info)
|
||||
: codemap_(codemap),
|
||||
instance_(instance),
|
||||
cached_instance_info_(cached_instance_info),
|
||||
zone_(zone),
|
||||
frames_(zone),
|
||||
activations_(zone) {}
|
||||
@ -1262,7 +1295,7 @@ class ThreadImpl {
|
||||
friend class InterpretedFrameImpl;
|
||||
|
||||
CodeMap* codemap_;
|
||||
WasmInstance* instance_;
|
||||
CachedInstanceInfo* const cached_instance_info_;
|
||||
Zone* zone_;
|
||||
WasmValue* stack_start_ = nullptr; // Start of allocated stack space.
|
||||
WasmValue* stack_limit_ = nullptr; // End of allocated stack space.
|
||||
@ -1278,9 +1311,8 @@ class ThreadImpl {
|
||||
// inspection).
|
||||
ZoneVector<Activation> activations_;
|
||||
|
||||
CodeMap* codemap() { return codemap_; }
|
||||
WasmInstance* instance() { return instance_; }
|
||||
const WasmModule* module() { return instance_->module; }
|
||||
CodeMap* codemap() const { return codemap_; }
|
||||
const WasmModule* module() const { return codemap_->module(); }
|
||||
|
||||
void DoTrap(TrapReason trap, pc_t pc) {
|
||||
state_ = WasmInterpreter::TRAPPED;
|
||||
@ -1426,11 +1458,12 @@ class ThreadImpl {
|
||||
bool ExecuteLoad(Decoder* decoder, InterpreterCode* code, pc_t pc, int& len) {
|
||||
MemoryAccessOperand<false> operand(decoder, code->at(pc), sizeof(ctype));
|
||||
uint32_t index = Pop().to<uint32_t>();
|
||||
if (!BoundsCheck<mtype>(instance()->mem_size, operand.offset, index)) {
|
||||
if (!BoundsCheck<mtype>(cached_instance_info_->mem_size, operand.offset,
|
||||
index)) {
|
||||
DoTrap(kTrapMemOutOfBounds, pc);
|
||||
return false;
|
||||
}
|
||||
byte* addr = instance()->mem_start + operand.offset + index;
|
||||
byte* addr = cached_instance_info_->mem_start + operand.offset + index;
|
||||
WasmValue result(static_cast<ctype>(ReadLittleEndianValue<mtype>(addr)));
|
||||
|
||||
Push(result);
|
||||
@ -1445,11 +1478,12 @@ class ThreadImpl {
|
||||
WasmValue val = Pop();
|
||||
|
||||
uint32_t index = Pop().to<uint32_t>();
|
||||
if (!BoundsCheck<mtype>(instance()->mem_size, operand.offset, index)) {
|
||||
if (!BoundsCheck<mtype>(cached_instance_info_->mem_size, operand.offset,
|
||||
index)) {
|
||||
DoTrap(kTrapMemOutOfBounds, pc);
|
||||
return false;
|
||||
}
|
||||
byte* addr = instance()->mem_start + operand.offset + index;
|
||||
byte* addr = cached_instance_info_->mem_start + operand.offset + index;
|
||||
WriteLittleEndianValue<mtype>(addr, static_cast<mtype>(val.to<ctype>()));
|
||||
len = 1 + operand.length;
|
||||
|
||||
@ -1744,7 +1778,7 @@ class ThreadImpl {
|
||||
case kExprGetGlobal: {
|
||||
GlobalIndexOperand<false> operand(&decoder, code->at(pc));
|
||||
const WasmGlobal* global = &module()->globals[operand.index];
|
||||
byte* ptr = instance()->globals_start + global->offset;
|
||||
byte* ptr = cached_instance_info_->globals_start + global->offset;
|
||||
WasmValue val;
|
||||
switch (global->type) {
|
||||
#define CASE_TYPE(wasm, ctype) \
|
||||
@ -1763,7 +1797,7 @@ class ThreadImpl {
|
||||
case kExprSetGlobal: {
|
||||
GlobalIndexOperand<false> operand(&decoder, code->at(pc));
|
||||
const WasmGlobal* global = &module()->globals[operand.index];
|
||||
byte* ptr = instance()->globals_start + global->offset;
|
||||
byte* ptr = cached_instance_info_->globals_start + global->offset;
|
||||
WasmValue val = Pop();
|
||||
switch (global->type) {
|
||||
#define CASE_TYPE(wasm, ctype) \
|
||||
@ -1818,19 +1852,19 @@ class ThreadImpl {
|
||||
STORE_CASE(F64StoreMem, double, double);
|
||||
#undef STORE_CASE
|
||||
|
||||
#define ASMJS_LOAD_CASE(name, ctype, mtype, defval) \
|
||||
case kExpr##name: { \
|
||||
uint32_t index = Pop().to<uint32_t>(); \
|
||||
ctype result; \
|
||||
if (!BoundsCheck<mtype>(instance()->mem_size, 0, index)) { \
|
||||
result = defval; \
|
||||
} else { \
|
||||
byte* addr = instance()->mem_start + index; \
|
||||
/* TODO(titzer): alignment for asmjs load mem? */ \
|
||||
result = static_cast<ctype>(*reinterpret_cast<mtype*>(addr)); \
|
||||
} \
|
||||
Push(WasmValue(result)); \
|
||||
break; \
|
||||
#define ASMJS_LOAD_CASE(name, ctype, mtype, defval) \
|
||||
case kExpr##name: { \
|
||||
uint32_t index = Pop().to<uint32_t>(); \
|
||||
ctype result; \
|
||||
if (!BoundsCheck<mtype>(cached_instance_info_->mem_size, 0, index)) { \
|
||||
result = defval; \
|
||||
} else { \
|
||||
byte* addr = cached_instance_info_->mem_start + index; \
|
||||
/* TODO(titzer): alignment for asmjs load mem? */ \
|
||||
result = static_cast<ctype>(*reinterpret_cast<mtype*>(addr)); \
|
||||
} \
|
||||
Push(WasmValue(result)); \
|
||||
break; \
|
||||
}
|
||||
ASMJS_LOAD_CASE(I32AsmjsLoadMem8S, int32_t, int8_t, 0);
|
||||
ASMJS_LOAD_CASE(I32AsmjsLoadMem8U, int32_t, uint8_t, 0);
|
||||
@ -1847,8 +1881,8 @@ class ThreadImpl {
|
||||
case kExpr##name: { \
|
||||
WasmValue val = Pop(); \
|
||||
uint32_t index = Pop().to<uint32_t>(); \
|
||||
if (BoundsCheck<mtype>(instance()->mem_size, 0, index)) { \
|
||||
byte* addr = instance()->mem_start + index; \
|
||||
if (BoundsCheck<mtype>(cached_instance_info_->mem_size, 0, index)) { \
|
||||
byte* addr = cached_instance_info_->mem_start + index; \
|
||||
/* TODO(titzer): alignment for asmjs store mem? */ \
|
||||
*(reinterpret_cast<mtype*>(addr)) = static_cast<mtype>(val.to<ctype>()); \
|
||||
} \
|
||||
@ -1866,13 +1900,13 @@ class ThreadImpl {
|
||||
MemoryIndexOperand<false> operand(&decoder, code->at(pc));
|
||||
uint32_t delta_pages = Pop().to<uint32_t>();
|
||||
Push(WasmValue(ExecuteGrowMemory(
|
||||
delta_pages, codemap_->maybe_instance(), instance())));
|
||||
delta_pages, codemap_->maybe_instance(), cached_instance_info_)));
|
||||
len = 1 + operand.length;
|
||||
break;
|
||||
}
|
||||
case kExprMemorySize: {
|
||||
MemoryIndexOperand<false> operand(&decoder, code->at(pc));
|
||||
Push(WasmValue(static_cast<uint32_t>(instance()->mem_size /
|
||||
Push(WasmValue(static_cast<uint32_t>(cached_instance_info_->mem_size /
|
||||
WasmModule::kPageSize)));
|
||||
len = 1 + operand.length;
|
||||
break;
|
||||
@ -2511,7 +2545,9 @@ uint32_t WasmInterpreter::Thread::ActivationFrameBase(uint32_t id) {
|
||||
//============================================================================
|
||||
class WasmInterpreterInternals : public ZoneObject {
|
||||
public:
|
||||
WasmInstance* instance_;
|
||||
// We cache the memory information of the debugged instance here, and all
|
||||
// threads (currently, one) share it and update it in case of {GrowMemory}.
|
||||
CachedInstanceInfo cached_instance_info_;
|
||||
// Create a copy of the module bytes for the interpreter, since the passed
|
||||
// pointer might be invalidated after constructing the interpreter.
|
||||
const ZoneVector<uint8_t> module_bytes_;
|
||||
@ -2519,24 +2555,29 @@ class WasmInterpreterInternals : public ZoneObject {
|
||||
ZoneVector<ThreadImpl> threads_;
|
||||
|
||||
WasmInterpreterInternals(Isolate* isolate, Zone* zone,
|
||||
const ModuleBytesEnv& env)
|
||||
: instance_(env.module_env.instance),
|
||||
module_bytes_(env.wire_bytes.start(), env.wire_bytes.end(), zone),
|
||||
codemap_(
|
||||
isolate,
|
||||
env.module_env.instance ? env.module_env.instance->module : nullptr,
|
||||
module_bytes_.data(), zone),
|
||||
const WasmModule* module,
|
||||
const ModuleWireBytes& wire_bytes,
|
||||
byte* globals_start, byte* mem_start,
|
||||
uint32_t mem_size)
|
||||
: cached_instance_info_(globals_start, mem_start, mem_size),
|
||||
module_bytes_(wire_bytes.start(), wire_bytes.end(), zone),
|
||||
codemap_(isolate, module, module_bytes_.data(), zone),
|
||||
threads_(zone) {
|
||||
threads_.emplace_back(zone, &codemap_, env.module_env.instance);
|
||||
threads_.emplace_back(zone, &codemap_, &cached_instance_info_);
|
||||
}
|
||||
};
|
||||
|
||||
//============================================================================
|
||||
// Implementation of the public interface of the interpreter.
|
||||
//============================================================================
|
||||
WasmInterpreter::WasmInterpreter(Isolate* isolate, const ModuleBytesEnv& env)
|
||||
WasmInterpreter::WasmInterpreter(Isolate* isolate, const WasmModule* module,
|
||||
const ModuleWireBytes& wire_bytes,
|
||||
byte* globals_start, byte* mem_start,
|
||||
uint32_t mem_size)
|
||||
: zone_(isolate->allocator(), ZONE_NAME),
|
||||
internals_(new (&zone_) WasmInterpreterInternals(isolate, &zone_, env)) {}
|
||||
internals_(new (&zone_) WasmInterpreterInternals(
|
||||
isolate, &zone_, module, wire_bytes, globals_start, mem_start,
|
||||
mem_size)) {}
|
||||
|
||||
WasmInterpreter::~WasmInterpreter() { internals_->~WasmInterpreterInternals(); }
|
||||
|
||||
@ -2588,22 +2629,12 @@ WasmInterpreter::Thread* WasmInterpreter::GetThread(int id) {
|
||||
return ToThread(&internals_->threads_[id]);
|
||||
}
|
||||
|
||||
size_t WasmInterpreter::GetMemorySize() {
|
||||
return internals_->instance_->mem_size;
|
||||
}
|
||||
|
||||
WasmValue WasmInterpreter::ReadMemory(size_t offset) {
|
||||
UNIMPLEMENTED();
|
||||
return WasmValue();
|
||||
}
|
||||
|
||||
void WasmInterpreter::WriteMemory(size_t offset, WasmValue val) {
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
void WasmInterpreter::UpdateMemory(byte* mem_start, uint32_t mem_size) {
|
||||
internals_->instance_->mem_start = mem_start;
|
||||
internals_->instance_->mem_size = mem_size;
|
||||
// We assume one thread. Things are likely to be more complicated than this
|
||||
// in a multi-threaded case.
|
||||
DCHECK_EQ(1, internals_->threads_.size());
|
||||
internals_->cached_instance_info_.mem_start = mem_start;
|
||||
internals_->cached_instance_info_.mem_size = mem_size;
|
||||
}
|
||||
|
||||
void WasmInterpreter::AddFunctionForTesting(const WasmFunction* function) {
|
||||
|
@ -20,7 +20,7 @@ class WasmInstanceObject;
|
||||
namespace wasm {
|
||||
|
||||
// forward declarations.
|
||||
struct ModuleBytesEnv;
|
||||
struct ModuleWireBytes;
|
||||
struct WasmFunction;
|
||||
struct WasmModule;
|
||||
class WasmInterpreterInternals;
|
||||
@ -171,7 +171,9 @@ class V8_EXPORT_PRIVATE WasmInterpreter {
|
||||
uint32_t ActivationFrameBase(uint32_t activation_id);
|
||||
};
|
||||
|
||||
WasmInterpreter(Isolate* isolate, const ModuleBytesEnv& env);
|
||||
WasmInterpreter(Isolate* isolate, const WasmModule* module,
|
||||
const ModuleWireBytes& wire_bytes, byte* globals_start,
|
||||
byte* mem_start, uint32_t mem_size);
|
||||
~WasmInterpreter();
|
||||
|
||||
//==========================================================================
|
||||
@ -197,12 +199,8 @@ class V8_EXPORT_PRIVATE WasmInterpreter {
|
||||
Thread* GetThread(int id);
|
||||
|
||||
//==========================================================================
|
||||
// Memory access.
|
||||
// Update the cached module env memory parameters after a grow memory event.
|
||||
//==========================================================================
|
||||
size_t GetMemorySize();
|
||||
WasmValue ReadMemory(size_t offset);
|
||||
void WriteMemory(size_t offset, WasmValue val);
|
||||
// Update the memory region, e.g. after external GrowMemory.
|
||||
void UpdateMemory(byte* mem_start, uint32_t mem_size);
|
||||
|
||||
//==========================================================================
|
||||
@ -222,7 +220,7 @@ class V8_EXPORT_PRIVATE WasmInterpreter {
|
||||
|
||||
private:
|
||||
Zone zone_;
|
||||
WasmInterpreterInternals* internals_;
|
||||
WasmInterpreterInternals* const internals_;
|
||||
};
|
||||
|
||||
} // namespace wasm
|
||||
|
@ -611,7 +611,7 @@ class WasmDebugInfo : public FixedArray {
|
||||
// WasmDebugInfo.
|
||||
// Use for testing only.
|
||||
V8_EXPORT_PRIVATE static wasm::WasmInterpreter* SetupForTesting(
|
||||
Handle<WasmInstanceObject>, wasm::WasmInstance*);
|
||||
Handle<WasmInstanceObject>);
|
||||
|
||||
// Set a breakpoint in the given function at the given byte offset within that
|
||||
// function. This will redirect all future calls to this function to the
|
||||
|
@ -69,9 +69,10 @@ using namespace v8::internal::wasm;
|
||||
|
||||
const uint32_t kMaxGlobalsSize = 128;
|
||||
|
||||
// A helper for module environments that adds the ability to allocate memory
|
||||
// and global variables. Contains a built-in {WasmModule} and
|
||||
// {WasmInstance}.
|
||||
// A buildable ModuleEnv. Globals are pre-set, however, memory and code may be
|
||||
// progressively added by a test. In turn, we piecemeal update the runtime
|
||||
// objects, i.e. {WasmInstanceObject}, {WasmCompiledModule} and, if necessary,
|
||||
// the interpreter.
|
||||
class TestingModule : public ModuleEnv {
|
||||
public:
|
||||
explicit TestingModule(Zone* zone, WasmExecutionMode mode = kExecuteCompiled)
|
||||
@ -89,8 +90,7 @@ class TestingModule : public ModuleEnv {
|
||||
memset(global_data, 0, sizeof(global_data));
|
||||
instance_object_ = InitInstanceObject();
|
||||
if (mode == kExecuteInterpreted) {
|
||||
interpreter_ =
|
||||
WasmDebugInfo::SetupForTesting(instance_object_, &instance_);
|
||||
interpreter_ = WasmDebugInfo::SetupForTesting(instance_object_);
|
||||
}
|
||||
}
|
||||
|
||||
@ -113,6 +113,21 @@ class TestingModule : public ModuleEnv {
|
||||
CHECK(size == 0 || instance->mem_start);
|
||||
memset(instance->mem_start, 0, size);
|
||||
instance->mem_size = size;
|
||||
Handle<WasmCompiledModule> compiled_module =
|
||||
handle(instance_object_->compiled_module());
|
||||
Factory* factory = CcTest::i_isolate()->factory();
|
||||
// It's not really necessary we recreate the Number objects,
|
||||
// if we happened to have one, but this is a reasonable inefficiencly,
|
||||
// given this is test.
|
||||
WasmCompiledModule::recreate_embedded_mem_size(compiled_module, factory,
|
||||
instance->mem_size);
|
||||
WasmCompiledModule::recreate_embedded_mem_start(
|
||||
compiled_module, factory,
|
||||
reinterpret_cast<size_t>(instance->mem_start));
|
||||
|
||||
if (interpreter_) {
|
||||
interpreter_->UpdateMemory(instance->mem_start, instance->mem_size);
|
||||
}
|
||||
return instance->mem_start;
|
||||
}
|
||||
|
||||
@ -346,6 +361,12 @@ class TestingModule : public ModuleEnv {
|
||||
std::vector<Handle<FixedArray>> empty;
|
||||
Handle<WasmCompiledModule> compiled_module = WasmCompiledModule::New(
|
||||
isolate_, shared_module_data, code_table, empty, empty);
|
||||
// This method is called when we initialize TestEnvironment. We don't
|
||||
// have a memory yet, so we won't create it here. We'll update the
|
||||
// interpreter when we get a memory. We do have globals, though.
|
||||
WasmCompiledModule::recreate_globals_start(
|
||||
compiled_module, isolate_->factory(),
|
||||
reinterpret_cast<size_t>(instance->globals_start));
|
||||
Handle<FixedArray> weak_exported = isolate_->factory()->NewFixedArray(0);
|
||||
compiled_module->set_weak_exported_functions(weak_exported);
|
||||
DCHECK(WasmCompiledModule::IsWasmCompiledModule(*compiled_module));
|
||||
|
@ -91,8 +91,7 @@ int32_t InterpretWasmModule(Isolate* isolate,
|
||||
Zone zone(isolate->allocator(), ZONE_NAME);
|
||||
v8::internal::HandleScope scope(isolate);
|
||||
|
||||
WasmInterpreter* interpreter =
|
||||
WasmDebugInfo::SetupForTesting(instance, nullptr);
|
||||
WasmInterpreter* interpreter = WasmDebugInfo::SetupForTesting(instance);
|
||||
WasmInterpreter::HeapObjectsScope heap_objects_scope(interpreter, instance);
|
||||
WasmInterpreter::Thread* thread = interpreter->GetThread(0);
|
||||
thread->Reset();
|
||||
|
Loading…
Reference in New Issue
Block a user