1
0
mirror of https://github.com/dart-lang/sdk synced 2024-07-08 12:06:26 +00:00

[vm/compiler] keep stack depth per block in stack IR

Rationale:
This simplifies finding the proper stack depth while
traversing the entries in the DOM tree during OSR.
Also enables asserting stack integrity on all paths
(OSR and non-OSR) more rigidly.

https://github.com/dart-lang/sdk/issues/38459
https://github.com/dart-lang/sdk/issues/38436
https://github.com/dart-lang/sdk/issues/38434

Change-Id: I3bc43def081013357e9a765e9e03fffe4c72dc6b
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/118473
Reviewed-by: Alexander Markov <alexmarkov@google.com>
Reviewed-by: Martin Kustermann <kustermann@google.com>
Commit-Queue: Aart Bik <ajcbik@google.com>
This commit is contained in:
Aart Bik 2019-09-24 21:33:01 +00:00 committed by commit-bot@chromium.org
parent acba8cf7a1
commit 78bd9f17a1
7 changed files with 2434 additions and 45 deletions

View File

@ -1029,14 +1029,15 @@ void FlowGraph::PopulateEnvironmentFromFunctionEntry(
VariableLivenessAnalysis* variable_liveness,
ZoneGrowableArray<Definition*>* inlining_parameters) {
ASSERT(!IsCompiledForOsr());
const intptr_t parameter_count = num_direct_parameters_;
const intptr_t direct_parameter_count = num_direct_parameters_;
// Check if inlining_parameters include a type argument vector parameter.
const intptr_t inlined_type_args_param =
((inlining_parameters != NULL) && function().IsGeneric()) ? 1 : 0;
ASSERT(parameter_count <= env->length());
for (intptr_t i = 0; i < parameter_count; i++) {
ASSERT(variable_count() == env->length());
ASSERT(direct_parameter_count <= env->length());
for (intptr_t i = 0; i < direct_parameter_count; i++) {
ParameterInstr* param = new (zone()) ParameterInstr(i, function_entry);
param->set_ssa_temp_index(alloc_ssa_temp_index());
AddToInitialDefinitions(function_entry, param);
@ -1097,8 +1098,7 @@ void FlowGraph::PopulateEnvironmentFromOsrEntry(
// passed as parameters. The latter mimics the incoming expression
// stack that was set up prior to triggering OSR.
const intptr_t parameter_count = osr_variable_count();
ASSERT(env->length() == (parameter_count - osr_entry->stack_depth()));
env->EnsureLength(parameter_count, constant_dead());
ASSERT(parameter_count == env->length());
for (intptr_t i = 0; i < parameter_count; i++) {
ParameterInstr* param = new (zone()) ParameterInstr(i, osr_entry);
param->set_ssa_temp_index(alloc_ssa_temp_index());
@ -1120,7 +1120,7 @@ void FlowGraph::PopulateEnvironmentFromCatchEntry(
: -1;
// Add real definitions for all locals and parameters.
ASSERT(variable_count() <= env->length());
ASSERT(variable_count() == env->length());
for (intptr_t i = 0, n = variable_count(); i < n; ++i) {
// Replace usages of the raw exception/stacktrace variables with
// [SpecialParameterInstr]s.
@ -1288,7 +1288,7 @@ void FlowGraph::RenameRecursive(
PushArgumentInstr* push_arg = current->PushArgumentAt(i);
ASSERT(push_arg->IsPushArgument());
ASSERT(reaching_defn->ssa_temp_index() != -1);
ASSERT(reaching_defn->IsPhi());
ASSERT(reaching_defn->IsPhi() || reaching_defn == constant_dead());
push_arg->ReplaceUsesWith(push_arg->InputAt(0)->definition());
push_arg->UnuseAllInputs();
push_arg->previous()->LinkTo(push_arg->next());
@ -1416,29 +1416,30 @@ void FlowGraph::RenameRecursive(
// Update expression stack and remove current instruction from the graph.
Definition* definition = current->Cast<Definition>();
if (definition->HasTemp()) {
ASSERT(result != NULL);
ASSERT(result != nullptr);
env->Add(result);
}
it.RemoveCurrentFromGraph();
}
// 3. Process dominated blocks.
BlockEntryInstr* osr_succ =
(block_entry == graph_entry() && IsCompiledForOsr())
? graph_entry()->osr_entry()->last_instruction()->SuccessorAt(0)
: nullptr;
const bool set_stack = (block_entry == graph_entry()) && IsCompiledForOsr();
for (intptr_t i = 0; i < block_entry->dominated_blocks().length(); ++i) {
BlockEntryInstr* block = block_entry->dominated_blocks()[i];
GrowableArray<Definition*> new_env(env->length());
new_env.AddArray(*env);
ASSERT(block != nullptr);
if (block == osr_succ) {
// During OSR, when visiting the successor block of the OSR entry from
// the graph entry (rather than going through the OSR entry first), we
// must adjust the environment to mimic a non-empty incoming expression
// stack to ensure temporaries refer to the right stack items.
new_env.FillWith(constant_dead(), new_env.length(),
graph_entry()->osr_entry()->stack_depth());
// During OSR, when traversing from the graph entry directly any block
// (which may be a non-entry), we must adjust the environment to mimic
// a non-empty incoming expression stack to ensure temporaries refer to
// the right stack items.
const intptr_t stack_depth = block->stack_depth();
ASSERT(stack_depth >= 0);
if (set_stack) {
ASSERT(variable_count() == new_env.length());
new_env.FillWith(constant_dead(), variable_count(), stack_depth);
} else if (!block->last_instruction()->IsTailCall()) {
// Assert environment integrity otherwise.
ASSERT((variable_count() + stack_depth) == new_env.length());
}
RenameRecursive(block, &new_env, live_phis, variable_liveness,
inlining_parameters);

View File

@ -1129,7 +1129,10 @@ GraphEntryInstr::GraphEntryInstr(const ParsedFunction& parsed_function,
GraphEntryInstr::GraphEntryInstr(const ParsedFunction& parsed_function,
intptr_t osr_id,
intptr_t deopt_id)
: BlockEntryWithInitialDefs(0, kInvalidTryIndex, deopt_id),
: BlockEntryWithInitialDefs(0,
kInvalidTryIndex,
deopt_id,
/*stack_depth*/ 0),
parsed_function_(parsed_function),
catch_entries_(),
indirect_entries_(),
@ -1656,11 +1659,11 @@ bool BlockEntryInstr::FindOsrEntryAndRelink(GraphEntryInstr* graph_entry,
// we can simply jump to the beginning of the block.
ASSERT(instr->previous() == this);
const intptr_t stack_depth = instr->AsCheckStackOverflow()->stack_depth();
ASSERT(stack_depth() == instr->AsCheckStackOverflow()->stack_depth());
auto normal_entry = graph_entry->normal_entry();
auto osr_entry = new OsrEntryInstr(graph_entry, normal_entry->block_id(),
normal_entry->try_index(),
normal_entry->deopt_id(), stack_depth);
auto osr_entry = new OsrEntryInstr(
graph_entry, normal_entry->block_id(), normal_entry->try_index(),
normal_entry->deopt_id(), stack_depth());
auto goto_join = new GotoInstr(AsJoinEntry(),
CompilerState::Current().GetNextDeoptId());

View File

@ -1384,6 +1384,10 @@ class BlockEntryInstr : public Instruction {
intptr_t offset() const { return offset_; }
void set_offset(intptr_t offset) { offset_ = offset; }
// Stack-based IR bookkeeping.
intptr_t stack_depth() const { return stack_depth_; }
void set_stack_depth(intptr_t s) { stack_depth_ = s; }
// For all instruction in this block: Remove all inputs (including in the
// environment) from their definition's use lists for all instructions.
void ClearAllInstructions();
@ -1395,12 +1399,16 @@ class BlockEntryInstr : public Instruction {
ADD_EXTRA_INFO_TO_S_EXPRESSION_SUPPORT
protected:
BlockEntryInstr(intptr_t block_id, intptr_t try_index, intptr_t deopt_id)
BlockEntryInstr(intptr_t block_id,
intptr_t try_index,
intptr_t deopt_id,
intptr_t stack_depth)
: Instruction(deopt_id),
block_id_(block_id),
try_index_(try_index),
preorder_number_(-1),
postorder_number_(-1),
stack_depth_(stack_depth),
dominator_(nullptr),
dominated_blocks_(1),
last_instruction_(NULL),
@ -1428,6 +1436,8 @@ class BlockEntryInstr : public Instruction {
intptr_t try_index_;
intptr_t preorder_number_;
intptr_t postorder_number_;
// Expected stack depth on entry (for stack-based IR only).
intptr_t stack_depth_;
// Starting and ending lifetime positions for this block. Used by
// the linear scan register allocator.
intptr_t start_pos_;
@ -1512,8 +1522,9 @@ class BlockEntryWithInitialDefs : public BlockEntryInstr {
public:
BlockEntryWithInitialDefs(intptr_t block_id,
intptr_t try_index,
intptr_t deopt_id)
: BlockEntryInstr(block_id, try_index, deopt_id) {}
intptr_t deopt_id,
intptr_t stack_depth)
: BlockEntryInstr(block_id, try_index, deopt_id, stack_depth) {}
GrowableArray<Definition*>* initial_definitions() {
return &initial_definitions_;
@ -1630,8 +1641,11 @@ class GraphEntryInstr : public BlockEntryWithInitialDefs {
class JoinEntryInstr : public BlockEntryInstr {
public:
JoinEntryInstr(intptr_t block_id, intptr_t try_index, intptr_t deopt_id)
: BlockEntryInstr(block_id, try_index, deopt_id),
JoinEntryInstr(intptr_t block_id,
intptr_t try_index,
intptr_t deopt_id,
intptr_t stack_depth = 0)
: BlockEntryInstr(block_id, try_index, deopt_id, stack_depth),
predecessors_(2), // Two is the assumed to be the common case.
phis_(NULL) {}
@ -1698,8 +1712,11 @@ class PhiIterator : public ValueObject {
class TargetEntryInstr : public BlockEntryInstr {
public:
TargetEntryInstr(intptr_t block_id, intptr_t try_index, intptr_t deopt_id)
: BlockEntryInstr(block_id, try_index, deopt_id),
TargetEntryInstr(intptr_t block_id,
intptr_t try_index,
intptr_t deopt_id,
intptr_t stack_depth = 0)
: BlockEntryInstr(block_id, try_index, deopt_id, stack_depth),
predecessor_(NULL),
edge_weight_(0.0) {}
@ -1749,7 +1766,10 @@ class FunctionEntryInstr : public BlockEntryWithInitialDefs {
intptr_t block_id,
intptr_t try_index,
intptr_t deopt_id)
: BlockEntryWithInitialDefs(block_id, try_index, deopt_id),
: BlockEntryWithInitialDefs(block_id,
try_index,
deopt_id,
/*stack_depth=*/0),
graph_entry_(graph_entry) {}
DECLARE_INSTRUCTION(FunctionEntry)
@ -1815,8 +1835,7 @@ class OsrEntryInstr : public BlockEntryWithInitialDefs {
intptr_t try_index,
intptr_t deopt_id,
intptr_t stack_depth)
: BlockEntryWithInitialDefs(block_id, try_index, deopt_id),
stack_depth_(stack_depth),
: BlockEntryWithInitialDefs(block_id, try_index, deopt_id, stack_depth),
graph_entry_(graph_entry) {}
DECLARE_INSTRUCTION(OsrEntry)
@ -1829,7 +1848,6 @@ class OsrEntryInstr : public BlockEntryWithInitialDefs {
return graph_entry_;
}
intptr_t stack_depth() const { return stack_depth_; }
GraphEntryInstr* graph_entry() const { return graph_entry_; }
PRINT_TO_SUPPORT
@ -1841,7 +1859,6 @@ class OsrEntryInstr : public BlockEntryWithInitialDefs {
graph_entry_ = predecessor->AsGraphEntry();
}
const intptr_t stack_depth_;
GraphEntryInstr* graph_entry_;
DISALLOW_COPY_AND_ASSIGN(OsrEntryInstr);
@ -1880,7 +1897,10 @@ class CatchBlockEntryInstr : public BlockEntryWithInitialDefs {
const LocalVariable* stacktrace_var,
const LocalVariable* raw_exception_var,
const LocalVariable* raw_stacktrace_var)
: BlockEntryWithInitialDefs(block_id, try_index, deopt_id),
: BlockEntryWithInitialDefs(block_id,
try_index,
deopt_id,
/*stack_depth=*/0),
graph_entry_(graph_entry),
predecessor_(NULL),
catch_handler_types_(Array::ZoneHandle(handler_types.raw())),

View File

@ -661,8 +661,8 @@ Fragment BaseFlowGraphBuilder::MakeTemp() {
}
TargetEntryInstr* BaseFlowGraphBuilder::BuildTargetEntry() {
return new (Z)
TargetEntryInstr(AllocateBlockId(), CurrentTryIndex(), GetNextDeoptId());
return new (Z) TargetEntryInstr(AllocateBlockId(), CurrentTryIndex(),
GetNextDeoptId(), GetStackDepth());
}
FunctionEntryInstr* BaseFlowGraphBuilder::BuildFunctionEntry(
@ -672,12 +672,13 @@ FunctionEntryInstr* BaseFlowGraphBuilder::BuildFunctionEntry(
}
JoinEntryInstr* BaseFlowGraphBuilder::BuildJoinEntry(intptr_t try_index) {
return new (Z) JoinEntryInstr(AllocateBlockId(), try_index, GetNextDeoptId());
return new (Z) JoinEntryInstr(AllocateBlockId(), try_index, GetNextDeoptId(),
GetStackDepth());
}
JoinEntryInstr* BaseFlowGraphBuilder::BuildJoinEntry() {
return new (Z)
JoinEntryInstr(AllocateBlockId(), CurrentTryIndex(), GetNextDeoptId());
return new (Z) JoinEntryInstr(AllocateBlockId(), CurrentTryIndex(),
GetNextDeoptId(), GetStackDepth());
}
ArgumentArray BaseFlowGraphBuilder::GetArguments(int count) {

View File

@ -2177,6 +2177,7 @@ FlowGraph* BytecodeFlowGraphBuilder::BuildGraph() {
B->stack_ = stack_state;
}
code_ = Fragment(join);
join->set_stack_depth(B->GetStackDepth());
B->SetCurrentTryIndex(join->try_index());
} else {
// Unreachable bytecode is not allowed.

View File

@ -267,8 +267,6 @@ Fragment PrologueBuilder::BuildOptionalParameterHandling(
copy_args_prologue += Drop();
for (intptr_t i = 0; param < num_params; ++param, ++i) {
JoinEntryInstr* join = BuildJoinEntry();
copy_args_prologue += IntConstant(
compiler::target::ArgumentsDescriptor::named_entry_size() /
compiler::target::kWordSize);
@ -299,6 +297,9 @@ Fragment PrologueBuilder::BuildOptionalParameterHandling(
TargetEntryInstr *supplied, *missing;
copy_args_prologue += BranchIfStrictEqual(&supplied, &missing);
// Join good/not_good.
JoinEntryInstr* join = BuildJoinEntry();
// Let's load position from arg descriptor (to see which parameter is the
// name) and move kEntrySize forward in ArgDescriptopr names array.
Fragment good(supplied);

File diff suppressed because it is too large Load Diff