[wasm] Use WasmContext in the WasmInterpreter.

With the introduction of the WasmContext, compiled code is no longer
specialized to the memory start and size (or recently, globals_start).
This CL uses the same WasmContext between the interpreter and compiled
code, removing the need for UpdateMemory() and cached instance info.

R=clemensh@chromium.org

Bug: 
Change-Id: I0bd52352c9b6f3029246e94e239dc29f635e7920
Reviewed-on: https://chromium-review.googlesource.com/712734
Commit-Queue: Ben Titzer <titzer@chromium.org>
Reviewed-by: Clemens Hammacher <clemensh@chromium.org>
Cr-Commit-Position: refs/heads/master@{#48584}
This commit is contained in:
Ben L. Titzer 2017-10-16 11:45:56 +02:00 committed by Commit Bot
parent 089dd7d244
commit 5820041884
6 changed files with 42 additions and 114 deletions

View File

@ -136,28 +136,12 @@ class InterpreterHandle {
return {bytes_str->GetChars(), static_cast<size_t>(bytes_str->length())};
}
static uint32_t GetMemSize(WasmDebugInfo* debug_info) {
DisallowHeapAllocation no_gc;
return debug_info->wasm_instance()->wasm_context()->get()->mem_size;
}
static byte* GetMemStart(WasmDebugInfo* debug_info) {
DisallowHeapAllocation no_gc;
return debug_info->wasm_instance()->wasm_context()->get()->mem_start;
}
static byte* GetGlobalsStart(WasmDebugInfo* debug_info) {
DisallowHeapAllocation no_gc;
return debug_info->wasm_instance()->wasm_context()->get()->globals_start;
}
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)) {}
debug_info->wasm_instance()->wasm_context()->get()) {}
~InterpreterHandle() { DCHECK_EQ(0, activations_.size()); }
@ -422,13 +406,6 @@ class InterpreterHandle {
return interpreter()->GetThread(0)->NumInterpretedCalls();
}
void UpdateMemory(JSArrayBuffer* new_memory) {
byte* mem_start = reinterpret_cast<byte*>(new_memory->backing_store());
uint32_t mem_size;
CHECK(new_memory->byte_length()->ToUint32(&mem_size));
interpreter()->UpdateMemory(mem_start, mem_size);
}
Handle<JSObject> GetGlobalScopeObject(wasm::InterpretedFrame* frame,
Handle<WasmDebugInfo> debug_info) {
Isolate* isolate = debug_info->GetIsolate();
@ -744,12 +721,6 @@ uint64_t WasmDebugInfo::NumInterpretedCalls() {
return handle ? handle->NumInterpretedCalls() : 0;
}
void WasmDebugInfo::UpdateMemory(JSArrayBuffer* new_memory) {
auto* interp_handle = GetInterpreterHandleOrNull(this);
if (!interp_handle) return;
interp_handle->UpdateMemory(new_memory);
}
// static
Handle<JSObject> WasmDebugInfo::GetScopeDetails(
Handle<WasmDebugInfo> debug_info, Address frame_pointer, int frame_index) {

View File

@ -618,21 +618,6 @@ inline int64_t ExecuteI64ReinterpretF64(WasmValue a) {
return a.to_unchecked<int64_t>();
}
inline int32_t ExecuteGrowMemory(uint32_t delta_pages,
MaybeHandle<WasmInstanceObject> instance_obj,
CachedInstanceInfo* mem_info) {
Handle<WasmInstanceObject> instance = instance_obj.ToHandleChecked();
Isolate* isolate = instance->GetIsolate();
int32_t ret = WasmInstanceObject::GrowMemory(isolate, instance, delta_pages);
// 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.
DCHECK_EQ(mem_info->mem_size, instance->wasm_context()->get()->mem_size);
DCHECK_EQ(mem_info->mem_start, instance->wasm_context()->get()->mem_start);
return ret;
}
enum InternalOpcode {
#define DECL_INTERNAL_ENUM(name, value) kInternal##name = value,
FOREACH_INTERNAL_OPCODE(DECL_INTERNAL_ENUM)
@ -1130,10 +1115,9 @@ class ThreadImpl {
};
public:
ThreadImpl(Zone* zone, CodeMap* codemap,
CachedInstanceInfo* cached_instance_info)
ThreadImpl(Zone* zone, CodeMap* codemap, WasmContext* wasm_context)
: codemap_(codemap),
cached_instance_info_(cached_instance_info),
wasm_context_(wasm_context),
zone_(zone),
frames_(zone),
activations_(zone) {}
@ -1293,7 +1277,7 @@ class ThreadImpl {
friend class InterpretedFrameImpl;
CodeMap* codemap_;
CachedInstanceInfo* const cached_instance_info_;
WasmContext* wasm_context_;
Zone* zone_;
WasmValue* stack_start_ = nullptr; // Start of allocated stack space.
WasmValue* stack_limit_ = nullptr; // End of allocated stack space.
@ -1457,12 +1441,11 @@ class ThreadImpl {
MachineRepresentation rep) {
MemoryAccessOperand<false> operand(decoder, code->at(pc), sizeof(ctype));
uint32_t index = Pop().to<uint32_t>();
if (!BoundsCheck<mtype>(cached_instance_info_->mem_size, operand.offset,
index)) {
if (!BoundsCheck<mtype>(wasm_context_->mem_size, operand.offset, index)) {
DoTrap(kTrapMemOutOfBounds, pc);
return false;
}
byte* addr = cached_instance_info_->mem_start + operand.offset + index;
byte* addr = wasm_context_->mem_start + operand.offset + index;
WasmValue result(static_cast<ctype>(ReadLittleEndianValue<mtype>(addr)));
Push(result);
@ -1472,7 +1455,7 @@ class ThreadImpl {
tracing::TraceMemoryOperation(
tracing::kWasmInterpreted, false, rep, operand.offset + index,
code->function->func_index, static_cast<int>(pc),
cached_instance_info_->mem_start);
wasm_context_->mem_start);
}
return true;
@ -1485,12 +1468,11 @@ class ThreadImpl {
WasmValue val = Pop();
uint32_t index = Pop().to<uint32_t>();
if (!BoundsCheck<mtype>(cached_instance_info_->mem_size, operand.offset,
index)) {
if (!BoundsCheck<mtype>(wasm_context_->mem_size, operand.offset, index)) {
DoTrap(kTrapMemOutOfBounds, pc);
return false;
}
byte* addr = cached_instance_info_->mem_start + operand.offset + index;
byte* addr = wasm_context_->mem_start + operand.offset + index;
WriteLittleEndianValue<mtype>(addr, static_cast<mtype>(val.to<ctype>()));
len = 1 + operand.length;
@ -1504,7 +1486,7 @@ class ThreadImpl {
tracing::TraceMemoryOperation(
tracing::kWasmInterpreted, true, rep, operand.offset + index,
code->function->func_index, static_cast<int>(pc),
cached_instance_info_->mem_start);
wasm_context_->mem_start);
}
return true;
@ -1793,7 +1775,7 @@ class ThreadImpl {
case kExprGetGlobal: {
GlobalIndexOperand<false> operand(&decoder, code->at(pc));
const WasmGlobal* global = &module()->globals[operand.index];
byte* ptr = cached_instance_info_->globals_start + global->offset;
byte* ptr = wasm_context_->globals_start + global->offset;
WasmValue val;
switch (global->type) {
#define CASE_TYPE(wasm, ctype) \
@ -1812,7 +1794,7 @@ class ThreadImpl {
case kExprSetGlobal: {
GlobalIndexOperand<false> operand(&decoder, code->at(pc));
const WasmGlobal* global = &module()->globals[operand.index];
byte* ptr = cached_instance_info_->globals_start + global->offset;
byte* ptr = wasm_context_->globals_start + global->offset;
WasmValue val = Pop();
switch (global->type) {
#define CASE_TYPE(wasm, ctype) \
@ -1871,19 +1853,19 @@ class ThreadImpl {
STORE_CASE(F64StoreMem, double, double, kFloat64);
#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>(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; \
#define ASMJS_LOAD_CASE(name, ctype, mtype, defval) \
case kExpr##name: { \
uint32_t index = Pop().to<uint32_t>(); \
ctype result; \
if (!BoundsCheck<mtype>(wasm_context_->mem_size, 0, index)) { \
result = defval; \
} else { \
byte* addr = wasm_context_->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);
@ -1900,8 +1882,8 @@ class ThreadImpl {
case kExpr##name: { \
WasmValue val = Pop(); \
uint32_t index = Pop().to<uint32_t>(); \
if (BoundsCheck<mtype>(cached_instance_info_->mem_size, 0, index)) { \
byte* addr = cached_instance_info_->mem_start + index; \
if (BoundsCheck<mtype>(wasm_context_->mem_size, 0, index)) { \
byte* addr = wasm_context_->mem_start + index; \
/* TODO(titzer): alignment for asmjs store mem? */ \
*(reinterpret_cast<mtype*>(addr)) = static_cast<mtype>(val.to<ctype>()); \
} \
@ -1918,14 +1900,19 @@ class ThreadImpl {
case kExprGrowMemory: {
MemoryIndexOperand<false> operand(&decoder, code->at(pc));
uint32_t delta_pages = Pop().to<uint32_t>();
Push(WasmValue(ExecuteGrowMemory(
delta_pages, codemap_->maybe_instance(), cached_instance_info_)));
Handle<WasmInstanceObject> instance =
codemap()->maybe_instance().ToHandleChecked();
DCHECK_EQ(wasm_context_, instance->wasm_context()->get());
Isolate* isolate = instance->GetIsolate();
int32_t result =
WasmInstanceObject::GrowMemory(isolate, instance, delta_pages);
Push(WasmValue(result));
len = 1 + operand.length;
break;
}
case kExprMemorySize: {
MemoryIndexOperand<false> operand(&decoder, code->at(pc));
Push(WasmValue(static_cast<uint32_t>(cached_instance_info_->mem_size /
Push(WasmValue(static_cast<uint32_t>(wasm_context_->mem_size /
WasmModule::kPageSize)));
len = 1 + operand.length;
break;
@ -2569,9 +2556,6 @@ uint32_t WasmInterpreter::Thread::ActivationFrameBase(uint32_t id) {
//============================================================================
class WasmInterpreterInternals : public ZoneObject {
public:
// 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_;
@ -2581,13 +2565,11 @@ class WasmInterpreterInternals : public ZoneObject {
WasmInterpreterInternals(Isolate* isolate, Zone* 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),
WasmContext* wasm_context)
: module_bytes_(wire_bytes.start(), wire_bytes.end(), zone),
codemap_(isolate, module, module_bytes_.data(), zone),
threads_(zone) {
threads_.emplace_back(zone, &codemap_, &cached_instance_info_);
threads_.emplace_back(zone, &codemap_, wasm_context);
}
};
@ -2596,12 +2578,10 @@ class WasmInterpreterInternals : public ZoneObject {
//============================================================================
WasmInterpreter::WasmInterpreter(Isolate* isolate, const WasmModule* module,
const ModuleWireBytes& wire_bytes,
byte* globals_start, byte* mem_start,
uint32_t mem_size)
WasmContext* wasm_context)
: zone_(isolate->allocator(), ZONE_NAME),
internals_(new (&zone_) WasmInterpreterInternals(
isolate, &zone_, module, wire_bytes, globals_start, mem_start,
mem_size)) {}
isolate, &zone_, module, wire_bytes, wasm_context)) {}
WasmInterpreter::~WasmInterpreter() { internals_->~WasmInterpreterInternals(); }
@ -2653,14 +2633,6 @@ WasmInterpreter::Thread* WasmInterpreter::GetThread(int id) {
return ToThread(&internals_->threads_[id]);
}
void WasmInterpreter::UpdateMemory(byte* mem_start, uint32_t 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) {
internals_->codemap_.AddFunction(function, nullptr, nullptr);
}

View File

@ -16,6 +16,7 @@ class AccountingAllocator;
namespace internal {
class WasmInstanceObject;
struct WasmContext;
namespace wasm {
@ -172,8 +173,7 @@ class V8_EXPORT_PRIVATE WasmInterpreter {
};
WasmInterpreter(Isolate* isolate, const WasmModule* module,
const ModuleWireBytes& wire_bytes, byte* globals_start,
byte* mem_start, uint32_t mem_size);
const ModuleWireBytes& wire_bytes, WasmContext* wasm_context);
~WasmInterpreter();
//==========================================================================
@ -198,11 +198,6 @@ class V8_EXPORT_PRIVATE WasmInterpreter {
int GetThreadCount();
Thread* GetThread(int id);
//==========================================================================
// Update the cached module env memory parameters after a grow memory event.
//==========================================================================
void UpdateMemory(byte* mem_start, uint32_t mem_size);
//==========================================================================
// Testing functionality.
//==========================================================================

View File

@ -368,9 +368,6 @@ Handle<JSArrayBuffer> GrowMemoryBuffer(Isolate* isolate,
void SetInstanceMemory(Isolate* isolate, Handle<WasmInstanceObject> instance,
Handle<JSArrayBuffer> buffer) {
instance->set_memory_buffer(*buffer);
if (instance->has_debug_info()) {
instance->debug_info()->UpdateMemory(*buffer);
}
auto wasm_context = instance->wasm_context()->get();
wasm_context->mem_start = reinterpret_cast<byte*>(buffer->backing_store());
wasm_context->mem_size = buffer->byte_length()->Number();

View File

@ -632,10 +632,6 @@ class WasmDebugInfo : public FixedArray {
// Returns the number of calls / function frames executed in the interpreter.
uint64_t NumInterpretedCalls();
// Update the memory view of the interpreter after executing GrowMemory in
// compiled code.
void UpdateMemory(JSArrayBuffer* new_memory);
// Get scope details for a specific interpreted frame.
// This returns a JSArray of length two: One entry for the global scope, one
// for the local scope. Both elements are JSArrays of size

View File

@ -53,9 +53,6 @@ byte* TestingModuleBuilder::AddMemory(uint32_t size) {
CHECK(size == 0 || mem_start_);
memset(mem_start_, 0, size);
if (interpreter_) {
interpreter_->UpdateMemory(mem_start_, mem_size_);
}
// Create the WasmMemoryObject.
Handle<WasmMemoryObject> memory_object = WasmMemoryObject::New(
isolate_, new_buffer,