Commit 94b4ad93 authored by Ben L. Titzer's avatar Ben L. Titzer Committed by Commit Bot

[wasm] Introduce WasmContextCacheNodes to simplify WasmGraphBuilder interface.

This CL introduces a small struct to hold the {mem_start} and {mem_size}
node pointers that are managed in the function body decoder's SSA environment.
This struct insulates the function body decoder from further changes in
how context-specific information is represented in the compiler.

R=clemensh@chromium.org
CC=​mstarzinger@chromium.org

Bug: 
Change-Id: If17bef9fd2490ac11e4f3b3614f91333bb0b9528
Reviewed-on: https://chromium-review.googlesource.com/817282Reviewed-by: 's avatarClemens Hammacher <clemensh@chromium.org>
Commit-Queue: Ben L. Titzer <titzer@google.com>
Cr-Commit-Position: refs/heads/master@{#50004}
parent e33a911a
...@@ -122,10 +122,6 @@ Node* WasmGraphBuilder::Terminate(Node* effect, Node* control) { ...@@ -122,10 +122,6 @@ Node* WasmGraphBuilder::Terminate(Node* effect, Node* control) {
return terminate; return terminate;
} }
unsigned WasmGraphBuilder::InputCount(Node* node) {
return static_cast<unsigned>(node->InputCount());
}
bool WasmGraphBuilder::IsPhiWithMerge(Node* phi, Node* merge) { bool WasmGraphBuilder::IsPhiWithMerge(Node* phi, Node* merge) {
return phi && IrOpcode::IsPhiOpcode(phi->opcode()) && return phi && IrOpcode::IsPhiOpcode(phi->opcode()) &&
NodeProperties::GetControlInput(phi) == merge; NodeProperties::GetControlInput(phi) == merge;
...@@ -3230,28 +3226,21 @@ void WasmGraphBuilder::BuildCWasmEntry(Address wasm_context_address) { ...@@ -3230,28 +3226,21 @@ void WasmGraphBuilder::BuildCWasmEntry(Address wasm_context_address) {
} }
} }
// This function is used by WasmFullDecoder to create a node that loads the void WasmGraphBuilder::InitContextCache(WasmContextCacheNodes* context_cache) {
// {mem_start} variable from the WasmContext. It should not be used directly by
// the WasmGraphBuilder. The WasmGraphBuilder should directly use {mem_start_},
// which will always contain the correct node (stored in the SsaEnv).
Node* WasmGraphBuilder::LoadMemStart() {
DCHECK_NOT_NULL(wasm_context_); DCHECK_NOT_NULL(wasm_context_);
Node* mem_buffer = graph()->NewNode( DCHECK_NOT_NULL(*control_);
DCHECK_NOT_NULL(*effect_);
// Load the memory start.
Node* mem_start = graph()->NewNode(
jsgraph()->machine()->Load(MachineType::UintPtr()), wasm_context_, jsgraph()->machine()->Load(MachineType::UintPtr()), wasm_context_,
jsgraph()->Int32Constant( jsgraph()->Int32Constant(
static_cast<int32_t>(offsetof(WasmContext, mem_start))), static_cast<int32_t>(offsetof(WasmContext, mem_start))),
*effect_, *control_); *effect_, *control_);
*effect_ = mem_buffer; *effect_ = mem_start;
return mem_buffer;
}
// This function is used by WasmFullDecoder to create a node that loads the context_cache->mem_start = mem_start;
// {mem_size} variable from the WasmContext. It should not be used directly by
// the WasmGraphBuilder. The WasmGraphBuilder should directly use {mem_size_}, // Load the memory size.
// which will always contain the correct node (stored in the SsaEnv).
Node* WasmGraphBuilder::LoadMemSize() {
// Load mem_size from the WasmContext at runtime.
DCHECK_NOT_NULL(wasm_context_);
Node* mem_size = graph()->NewNode( Node* mem_size = graph()->NewNode(
jsgraph()->machine()->Load(MachineType::Uint32()), wasm_context_, jsgraph()->machine()->Load(MachineType::Uint32()), wasm_context_,
jsgraph()->Int32Constant( jsgraph()->Int32Constant(
...@@ -3262,7 +3251,69 @@ Node* WasmGraphBuilder::LoadMemSize() { ...@@ -3262,7 +3251,69 @@ Node* WasmGraphBuilder::LoadMemSize() {
mem_size = graph()->NewNode(jsgraph()->machine()->ChangeUint32ToUint64(), mem_size = graph()->NewNode(jsgraph()->machine()->ChangeUint32ToUint64(),
mem_size); mem_size);
} }
return mem_size;
context_cache->mem_size = mem_size;
}
void WasmGraphBuilder::PrepareContextCacheForLoop(
WasmContextCacheNodes* context_cache, Node* control) {
// Introduce phis for mem_size and mem_start.
context_cache->mem_size =
Phi(MachineRepresentation::kWord32, 1, &context_cache->mem_size, control);
context_cache->mem_start = Phi(MachineType::PointerRepresentation(), 1,
&context_cache->mem_start, control);
}
void WasmGraphBuilder::NewContextCacheMerge(WasmContextCacheNodes* to,
WasmContextCacheNodes* from,
Node* merge) {
if (to->mem_size != from->mem_size) {
Node* vals[] = {to->mem_size, from->mem_size};
to->mem_size = Phi(MachineRepresentation::kWord32, 2, vals, merge);
}
if (to->mem_start != from->mem_start) {
Node* vals[] = {to->mem_start, from->mem_start};
to->mem_start = Phi(MachineType::PointerRepresentation(), 2, vals, merge);
}
}
void WasmGraphBuilder::MergeContextCacheInto(WasmContextCacheNodes* to,
WasmContextCacheNodes* from,
Node* merge) {
to->mem_size = CreateOrMergeIntoPhi(MachineRepresentation::kWord32, merge,
to->mem_size, from->mem_size);
to->mem_start = CreateOrMergeIntoPhi(MachineType::PointerRepresentation(),
merge, to->mem_start, from->mem_start);
}
Node* WasmGraphBuilder::CreateOrMergeIntoPhi(wasm::ValueType type, Node* merge,
Node* tnode, Node* fnode) {
if (IsPhiWithMerge(tnode, merge)) {
AppendToPhi(tnode, fnode);
} else if (tnode != fnode) {
uint32_t count = merge->InputCount();
Node** vals = Buffer(count);
for (uint32_t j = 0; j < count - 1; j++) vals[j] = tnode;
vals[count - 1] = fnode;
return Phi(type, count, vals, merge);
}
return tnode;
}
Node* WasmGraphBuilder::CreateOrMergeIntoEffectPhi(Node* merge, Node* tnode,
Node* fnode) {
if (IsPhiWithMerge(tnode, merge)) {
AppendToPhi(tnode, fnode);
} else if (tnode != fnode) {
uint32_t count = merge->InputCount();
Node** effects = Buffer(count);
for (uint32_t j = 0; j < count - 1; j++) {
effects[j] = tnode;
}
effects[count - 1] = fnode;
tnode = EffectPhi(count, effects, merge);
}
return tnode;
} }
void WasmGraphBuilder::GetGlobalBaseAndOffset(MachineType mem_type, void WasmGraphBuilder::GetGlobalBaseAndOffset(MachineType mem_type,
...@@ -3299,17 +3350,20 @@ void WasmGraphBuilder::GetGlobalBaseAndOffset(MachineType mem_type, ...@@ -3299,17 +3350,20 @@ void WasmGraphBuilder::GetGlobalBaseAndOffset(MachineType mem_type,
} }
Node* WasmGraphBuilder::MemBuffer(uint32_t offset) { Node* WasmGraphBuilder::MemBuffer(uint32_t offset) {
DCHECK_NOT_NULL(*mem_start_); DCHECK_NOT_NULL(context_cache_);
if (offset == 0) return *mem_start_; Node* mem_start = context_cache_->mem_start;
return graph()->NewNode(jsgraph()->machine()->IntAdd(), *mem_start_, DCHECK_NOT_NULL(mem_start);
if (offset == 0) return mem_start;
return graph()->NewNode(jsgraph()->machine()->IntAdd(), mem_start,
jsgraph()->IntPtrConstant(offset)); jsgraph()->IntPtrConstant(offset));
} }
Node* WasmGraphBuilder::CurrentMemoryPages() { Node* WasmGraphBuilder::CurrentMemoryPages() {
// CurrentMemoryPages can not be called from asm.js. // CurrentMemoryPages can not be called from asm.js.
DCHECK_EQ(wasm::kWasmOrigin, env_->module->origin()); DCHECK_EQ(wasm::kWasmOrigin, env_->module->origin());
DCHECK_NOT_NULL(*mem_size_); DCHECK_NOT_NULL(context_cache_);
Node* mem_size = *mem_size_; Node* mem_size = context_cache_->mem_size;
DCHECK_NOT_NULL(mem_size);
if (jsgraph()->machine()->Is64()) { if (jsgraph()->machine()->Is64()) {
mem_size = graph()->NewNode(jsgraph()->machine()->TruncateInt64ToInt32(), mem_size = graph()->NewNode(jsgraph()->machine()->TruncateInt64ToInt32(),
mem_size); mem_size);
...@@ -3435,7 +3489,9 @@ void WasmGraphBuilder::BoundsCheckMem(MachineType memtype, Node* index, ...@@ -3435,7 +3489,9 @@ void WasmGraphBuilder::BoundsCheckMem(MachineType memtype, Node* index,
uint32_t offset, uint32_t offset,
wasm::WasmCodePosition position) { wasm::WasmCodePosition position) {
if (FLAG_wasm_no_bounds_checks) return; if (FLAG_wasm_no_bounds_checks) return;
DCHECK_NOT_NULL(*mem_size_); DCHECK_NOT_NULL(context_cache_);
Node* mem_size = context_cache_->mem_size;
DCHECK_NOT_NULL(mem_size);
uint32_t min_size = env_->module->initial_pages * wasm::WasmModule::kPageSize; uint32_t min_size = env_->module->initial_pages * wasm::WasmModule::kPageSize;
uint32_t max_size = uint32_t max_size =
...@@ -3460,12 +3516,11 @@ void WasmGraphBuilder::BoundsCheckMem(MachineType memtype, Node* index, ...@@ -3460,12 +3516,11 @@ void WasmGraphBuilder::BoundsCheckMem(MachineType memtype, Node* index,
Node* cond; Node* cond;
if (jsgraph()->machine()->Is32()) { if (jsgraph()->machine()->Is32()) {
cond = graph()->NewNode(jsgraph()->machine()->Uint32LessThanOrEqual(), cond = graph()->NewNode(jsgraph()->machine()->Uint32LessThanOrEqual(),
jsgraph()->Int32Constant(end_offset), *mem_size_); jsgraph()->Int32Constant(end_offset), mem_size);
} else { } else {
cond = graph()->NewNode( cond = graph()->NewNode(
jsgraph()->machine()->Uint64LessThanOrEqual(), jsgraph()->machine()->Uint64LessThanOrEqual(),
jsgraph()->Int64Constant(static_cast<int64_t>(end_offset)), jsgraph()->Int64Constant(static_cast<int64_t>(end_offset)), mem_size);
*mem_size_);
} }
TrapIfFalse(wasm::kTrapMemOutOfBounds, cond, position); TrapIfFalse(wasm::kTrapMemOutOfBounds, cond, position);
} else { } else {
...@@ -3485,11 +3540,11 @@ void WasmGraphBuilder::BoundsCheckMem(MachineType memtype, Node* index, ...@@ -3485,11 +3540,11 @@ void WasmGraphBuilder::BoundsCheckMem(MachineType memtype, Node* index,
Node* effective_size; Node* effective_size;
if (jsgraph()->machine()->Is32()) { if (jsgraph()->machine()->Is32()) {
effective_size = effective_size =
graph()->NewNode(jsgraph()->machine()->Int32Sub(), *mem_size_, graph()->NewNode(jsgraph()->machine()->Int32Sub(), mem_size,
jsgraph()->Int32Constant(end_offset - 1)); jsgraph()->Int32Constant(end_offset - 1));
} else { } else {
effective_size = graph()->NewNode( effective_size = graph()->NewNode(
jsgraph()->machine()->Int64Sub(), *mem_size_, jsgraph()->machine()->Int64Sub(), mem_size,
jsgraph()->Int64Constant(static_cast<int64_t>(end_offset - 1))); jsgraph()->Int64Constant(static_cast<int64_t>(end_offset - 1)));
} }
...@@ -3658,15 +3713,18 @@ Node* WasmGraphBuilder::StoreMem(MachineType memtype, Node* index, ...@@ -3658,15 +3713,18 @@ Node* WasmGraphBuilder::StoreMem(MachineType memtype, Node* index,
Node* WasmGraphBuilder::BuildAsmjsLoadMem(MachineType type, Node* index) { Node* WasmGraphBuilder::BuildAsmjsLoadMem(MachineType type, Node* index) {
// TODO(turbofan): fold bounds checks for constant asm.js loads. // TODO(turbofan): fold bounds checks for constant asm.js loads.
// asm.js semantics use CheckedLoad (i.e. OOB reads return 0ish). // asm.js semantics use CheckedLoad (i.e. OOB reads return 0ish).
DCHECK_NOT_NULL(*mem_size_); DCHECK_NOT_NULL(context_cache_);
DCHECK_NOT_NULL(*mem_start_); Node* mem_start = context_cache_->mem_start;
Node* mem_size = context_cache_->mem_size;
DCHECK_NOT_NULL(mem_start);
DCHECK_NOT_NULL(mem_size);
if (jsgraph()->machine()->Is64()) { if (jsgraph()->machine()->Is64()) {
index = index =
graph()->NewNode(jsgraph()->machine()->ChangeUint32ToUint64(), index); graph()->NewNode(jsgraph()->machine()->ChangeUint32ToUint64(), index);
} }
const Operator* op = jsgraph()->machine()->CheckedLoad(type); const Operator* op = jsgraph()->machine()->CheckedLoad(type);
Node* load = Node* load =
graph()->NewNode(op, *mem_start_, index, *mem_size_, *effect_, *control_); graph()->NewNode(op, mem_start, index, mem_size, *effect_, *control_);
*effect_ = load; *effect_ = load;
return load; return load;
} }
...@@ -3675,16 +3733,19 @@ Node* WasmGraphBuilder::BuildAsmjsStoreMem(MachineType type, Node* index, ...@@ -3675,16 +3733,19 @@ Node* WasmGraphBuilder::BuildAsmjsStoreMem(MachineType type, Node* index,
Node* val) { Node* val) {
// TODO(turbofan): fold bounds checks for constant asm.js stores. // TODO(turbofan): fold bounds checks for constant asm.js stores.
// asm.js semantics use CheckedStore (i.e. ignore OOB writes). // asm.js semantics use CheckedStore (i.e. ignore OOB writes).
DCHECK_NOT_NULL(*mem_size_); DCHECK_NOT_NULL(context_cache_);
DCHECK_NOT_NULL(*mem_start_); Node* mem_start = context_cache_->mem_start;
Node* mem_size = context_cache_->mem_size;
DCHECK_NOT_NULL(mem_start);
DCHECK_NOT_NULL(mem_size);
if (jsgraph()->machine()->Is64()) { if (jsgraph()->machine()->Is64()) {
index = index =
graph()->NewNode(jsgraph()->machine()->ChangeUint32ToUint64(), index); graph()->NewNode(jsgraph()->machine()->ChangeUint32ToUint64(), index);
} }
const Operator* op = const Operator* op =
jsgraph()->machine()->CheckedStore(type.representation()); jsgraph()->machine()->CheckedStore(type.representation());
Node* store = graph()->NewNode(op, *mem_start_, index, *mem_size_, val, Node* store = graph()->NewNode(op, mem_start, index, mem_size, val, *effect_,
*effect_, *control_); *control_);
*effect_ = store; *effect_ = store;
return val; return val;
} }
......
...@@ -209,6 +209,16 @@ enum CWasmEntryParameters { ...@@ -209,6 +209,16 @@ enum CWasmEntryParameters {
Handle<Code> CompileCWasmEntry(Isolate* isolate, wasm::FunctionSig* sig, Handle<Code> CompileCWasmEntry(Isolate* isolate, wasm::FunctionSig* sig,
Address wasm_context_address); Address wasm_context_address);
// Values from the {WasmContext} are cached between WASM-level function calls.
// This struct allows the SSA environment handling this cache to be defined
// and manipulated in wasm-compiler.{h,cc} instead of inside the WASM decoder.
// (Note that currently, the globals base is immutable in a context, so not
// cached here.)
struct WasmContextCacheNodes {
Node* mem_start;
Node* mem_size;
};
// Abstracts details of building TurboFan graph nodes for wasm to separate // Abstracts details of building TurboFan graph nodes for wasm to separate
// the wasm decoder from the internal details of TurboFan. // the wasm decoder from the internal details of TurboFan.
typedef ZoneVector<Node*> NodeVector; typedef ZoneVector<Node*> NodeVector;
...@@ -239,6 +249,9 @@ class WasmGraphBuilder { ...@@ -239,6 +249,9 @@ class WasmGraphBuilder {
Node* Terminate(Node* effect, Node* control); Node* Terminate(Node* effect, Node* control);
Node* Merge(unsigned count, Node** controls); Node* Merge(unsigned count, Node** controls);
Node* Phi(wasm::ValueType type, unsigned count, Node** vals, Node* control); Node* Phi(wasm::ValueType type, unsigned count, Node** vals, Node* control);
Node* CreateOrMergeIntoPhi(wasm::ValueType type, Node* merge, Node* tnode,
Node* fnode);
Node* CreateOrMergeIntoEffectPhi(Node* merge, Node* tnode, Node* fnode);
Node* EffectPhi(unsigned count, Node** effects, Node* control); Node* EffectPhi(unsigned count, Node** effects, Node* control);
Node* NumberConstant(int32_t value); Node* NumberConstant(int32_t value);
Node* Uint32Constant(uint32_t value); Node* Uint32Constant(uint32_t value);
...@@ -259,7 +272,6 @@ class WasmGraphBuilder { ...@@ -259,7 +272,6 @@ class WasmGraphBuilder {
Node* ConvertExceptionTagToRuntimeId(uint32_t tag); Node* ConvertExceptionTagToRuntimeId(uint32_t tag);
Node* GetExceptionRuntimeId(); Node* GetExceptionRuntimeId();
Node** GetExceptionValues(const wasm::WasmException* except_decl); Node** GetExceptionValues(const wasm::WasmException* except_decl);
unsigned InputCount(Node* node);
bool IsPhiWithMerge(Node* phi, Node* merge); bool IsPhiWithMerge(Node* phi, Node* merge);
bool ThrowsException(Node* node, Node** if_success, Node** if_exception); bool ThrowsException(Node* node, Node** if_success, Node** if_exception);
void AppendToMerge(Node* merge, Node* from); void AppendToMerge(Node* merge, Node* from);
...@@ -362,9 +374,18 @@ class WasmGraphBuilder { ...@@ -362,9 +374,18 @@ class WasmGraphBuilder {
void GetGlobalBaseAndOffset(MachineType mem_type, uint32_t offset, void GetGlobalBaseAndOffset(MachineType mem_type, uint32_t offset,
Node** base_node, Node** offset_node); Node** base_node, Node** offset_node);
void set_mem_size(Node** mem_size) { this->mem_size_ = mem_size; } // Utilities to manipulate sets of context cache nodes.
void InitContextCache(WasmContextCacheNodes* context_cache);
void set_mem_start(Node** mem_start) { this->mem_start_ = mem_start; } void PrepareContextCacheForLoop(WasmContextCacheNodes* context_cache,
Node* control);
void NewContextCacheMerge(WasmContextCacheNodes* to,
WasmContextCacheNodes* from, Node* merge);
void MergeContextCacheInto(WasmContextCacheNodes* to,
WasmContextCacheNodes* from, Node* merge);
void set_context_cache(WasmContextCacheNodes* context_cache) {
this->context_cache_ = context_cache;
}
wasm::FunctionSig* GetFunctionSignature() { return sig_; } wasm::FunctionSig* GetFunctionSignature() { return sig_; }
...@@ -413,8 +434,7 @@ class WasmGraphBuilder { ...@@ -413,8 +434,7 @@ class WasmGraphBuilder {
NodeVector function_table_sizes_; NodeVector function_table_sizes_;
Node** control_ = nullptr; Node** control_ = nullptr;
Node** effect_ = nullptr; Node** effect_ = nullptr;
Node** mem_size_ = nullptr; WasmContextCacheNodes* context_cache_ = nullptr;
Node** mem_start_ = nullptr;
Node* globals_start_ = nullptr; Node* globals_start_ = nullptr;
Node** cur_buffer_; Node** cur_buffer_;
size_t cur_bufsize_; size_t cur_bufsize_;
......
...@@ -716,9 +716,9 @@ class WasmDecoder : public Decoder { ...@@ -716,9 +716,9 @@ class WasmDecoder : public Decoder {
case kExprGrowMemory: case kExprGrowMemory:
case kExprCallFunction: case kExprCallFunction:
case kExprCallIndirect: case kExprCallIndirect:
// Add mem_size and mem_start to the assigned set. // Add context cache nodes to the assigned set.
assigned->Add(locals_count - 2); // mem_size // TODO(titzer): make this more clear.
assigned->Add(locals_count - 1); // mem_start assigned->Add(locals_count - 1);
length = OpcodeLength(decoder, pc); length = OpcodeLength(decoder, pc);
break; break;
case kExprEnd: case kExprEnd:
......
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment