mirror of
https://github.com/dart-lang/sdk
synced 2024-09-05 08:24:39 +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:
parent
acba8cf7a1
commit
78bd9f17a1
|
@ -1029,14 +1029,15 @@ void FlowGraph::PopulateEnvironmentFromFunctionEntry(
|
||||||
VariableLivenessAnalysis* variable_liveness,
|
VariableLivenessAnalysis* variable_liveness,
|
||||||
ZoneGrowableArray<Definition*>* inlining_parameters) {
|
ZoneGrowableArray<Definition*>* inlining_parameters) {
|
||||||
ASSERT(!IsCompiledForOsr());
|
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.
|
// Check if inlining_parameters include a type argument vector parameter.
|
||||||
const intptr_t inlined_type_args_param =
|
const intptr_t inlined_type_args_param =
|
||||||
((inlining_parameters != NULL) && function().IsGeneric()) ? 1 : 0;
|
((inlining_parameters != NULL) && function().IsGeneric()) ? 1 : 0;
|
||||||
|
|
||||||
ASSERT(parameter_count <= env->length());
|
ASSERT(variable_count() == env->length());
|
||||||
for (intptr_t i = 0; i < parameter_count; i++) {
|
ASSERT(direct_parameter_count <= env->length());
|
||||||
|
for (intptr_t i = 0; i < direct_parameter_count; i++) {
|
||||||
ParameterInstr* param = new (zone()) ParameterInstr(i, function_entry);
|
ParameterInstr* param = new (zone()) ParameterInstr(i, function_entry);
|
||||||
param->set_ssa_temp_index(alloc_ssa_temp_index());
|
param->set_ssa_temp_index(alloc_ssa_temp_index());
|
||||||
AddToInitialDefinitions(function_entry, param);
|
AddToInitialDefinitions(function_entry, param);
|
||||||
|
@ -1097,8 +1098,7 @@ void FlowGraph::PopulateEnvironmentFromOsrEntry(
|
||||||
// passed as parameters. The latter mimics the incoming expression
|
// passed as parameters. The latter mimics the incoming expression
|
||||||
// stack that was set up prior to triggering OSR.
|
// stack that was set up prior to triggering OSR.
|
||||||
const intptr_t parameter_count = osr_variable_count();
|
const intptr_t parameter_count = osr_variable_count();
|
||||||
ASSERT(env->length() == (parameter_count - osr_entry->stack_depth()));
|
ASSERT(parameter_count == env->length());
|
||||||
env->EnsureLength(parameter_count, constant_dead());
|
|
||||||
for (intptr_t i = 0; i < parameter_count; i++) {
|
for (intptr_t i = 0; i < parameter_count; i++) {
|
||||||
ParameterInstr* param = new (zone()) ParameterInstr(i, osr_entry);
|
ParameterInstr* param = new (zone()) ParameterInstr(i, osr_entry);
|
||||||
param->set_ssa_temp_index(alloc_ssa_temp_index());
|
param->set_ssa_temp_index(alloc_ssa_temp_index());
|
||||||
|
@ -1120,7 +1120,7 @@ void FlowGraph::PopulateEnvironmentFromCatchEntry(
|
||||||
: -1;
|
: -1;
|
||||||
|
|
||||||
// Add real definitions for all locals and parameters.
|
// 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) {
|
for (intptr_t i = 0, n = variable_count(); i < n; ++i) {
|
||||||
// Replace usages of the raw exception/stacktrace variables with
|
// Replace usages of the raw exception/stacktrace variables with
|
||||||
// [SpecialParameterInstr]s.
|
// [SpecialParameterInstr]s.
|
||||||
|
@ -1288,7 +1288,7 @@ void FlowGraph::RenameRecursive(
|
||||||
PushArgumentInstr* push_arg = current->PushArgumentAt(i);
|
PushArgumentInstr* push_arg = current->PushArgumentAt(i);
|
||||||
ASSERT(push_arg->IsPushArgument());
|
ASSERT(push_arg->IsPushArgument());
|
||||||
ASSERT(reaching_defn->ssa_temp_index() != -1);
|
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->ReplaceUsesWith(push_arg->InputAt(0)->definition());
|
||||||
push_arg->UnuseAllInputs();
|
push_arg->UnuseAllInputs();
|
||||||
push_arg->previous()->LinkTo(push_arg->next());
|
push_arg->previous()->LinkTo(push_arg->next());
|
||||||
|
@ -1416,29 +1416,30 @@ void FlowGraph::RenameRecursive(
|
||||||
// Update expression stack and remove current instruction from the graph.
|
// Update expression stack and remove current instruction from the graph.
|
||||||
Definition* definition = current->Cast<Definition>();
|
Definition* definition = current->Cast<Definition>();
|
||||||
if (definition->HasTemp()) {
|
if (definition->HasTemp()) {
|
||||||
ASSERT(result != NULL);
|
ASSERT(result != nullptr);
|
||||||
env->Add(result);
|
env->Add(result);
|
||||||
}
|
}
|
||||||
it.RemoveCurrentFromGraph();
|
it.RemoveCurrentFromGraph();
|
||||||
}
|
}
|
||||||
|
|
||||||
// 3. Process dominated blocks.
|
// 3. Process dominated blocks.
|
||||||
BlockEntryInstr* osr_succ =
|
const bool set_stack = (block_entry == graph_entry()) && IsCompiledForOsr();
|
||||||
(block_entry == graph_entry() && IsCompiledForOsr())
|
|
||||||
? graph_entry()->osr_entry()->last_instruction()->SuccessorAt(0)
|
|
||||||
: nullptr;
|
|
||||||
for (intptr_t i = 0; i < block_entry->dominated_blocks().length(); ++i) {
|
for (intptr_t i = 0; i < block_entry->dominated_blocks().length(); ++i) {
|
||||||
BlockEntryInstr* block = block_entry->dominated_blocks()[i];
|
BlockEntryInstr* block = block_entry->dominated_blocks()[i];
|
||||||
GrowableArray<Definition*> new_env(env->length());
|
GrowableArray<Definition*> new_env(env->length());
|
||||||
new_env.AddArray(*env);
|
new_env.AddArray(*env);
|
||||||
ASSERT(block != nullptr);
|
// During OSR, when traversing from the graph entry directly any block
|
||||||
if (block == osr_succ) {
|
// (which may be a non-entry), we must adjust the environment to mimic
|
||||||
// During OSR, when visiting the successor block of the OSR entry from
|
// a non-empty incoming expression stack to ensure temporaries refer to
|
||||||
// the graph entry (rather than going through the OSR entry first), we
|
// the right stack items.
|
||||||
// must adjust the environment to mimic a non-empty incoming expression
|
const intptr_t stack_depth = block->stack_depth();
|
||||||
// stack to ensure temporaries refer to the right stack items.
|
ASSERT(stack_depth >= 0);
|
||||||
new_env.FillWith(constant_dead(), new_env.length(),
|
if (set_stack) {
|
||||||
graph_entry()->osr_entry()->stack_depth());
|
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,
|
RenameRecursive(block, &new_env, live_phis, variable_liveness,
|
||||||
inlining_parameters);
|
inlining_parameters);
|
||||||
|
|
|
@ -1129,7 +1129,10 @@ GraphEntryInstr::GraphEntryInstr(const ParsedFunction& parsed_function,
|
||||||
GraphEntryInstr::GraphEntryInstr(const ParsedFunction& parsed_function,
|
GraphEntryInstr::GraphEntryInstr(const ParsedFunction& parsed_function,
|
||||||
intptr_t osr_id,
|
intptr_t osr_id,
|
||||||
intptr_t deopt_id)
|
intptr_t deopt_id)
|
||||||
: BlockEntryWithInitialDefs(0, kInvalidTryIndex, deopt_id),
|
: BlockEntryWithInitialDefs(0,
|
||||||
|
kInvalidTryIndex,
|
||||||
|
deopt_id,
|
||||||
|
/*stack_depth*/ 0),
|
||||||
parsed_function_(parsed_function),
|
parsed_function_(parsed_function),
|
||||||
catch_entries_(),
|
catch_entries_(),
|
||||||
indirect_entries_(),
|
indirect_entries_(),
|
||||||
|
@ -1656,11 +1659,11 @@ bool BlockEntryInstr::FindOsrEntryAndRelink(GraphEntryInstr* graph_entry,
|
||||||
// we can simply jump to the beginning of the block.
|
// we can simply jump to the beginning of the block.
|
||||||
ASSERT(instr->previous() == this);
|
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 normal_entry = graph_entry->normal_entry();
|
||||||
auto osr_entry = new OsrEntryInstr(graph_entry, normal_entry->block_id(),
|
auto osr_entry = new OsrEntryInstr(
|
||||||
normal_entry->try_index(),
|
graph_entry, normal_entry->block_id(), normal_entry->try_index(),
|
||||||
normal_entry->deopt_id(), stack_depth);
|
normal_entry->deopt_id(), stack_depth());
|
||||||
|
|
||||||
auto goto_join = new GotoInstr(AsJoinEntry(),
|
auto goto_join = new GotoInstr(AsJoinEntry(),
|
||||||
CompilerState::Current().GetNextDeoptId());
|
CompilerState::Current().GetNextDeoptId());
|
||||||
|
|
|
@ -1384,6 +1384,10 @@ class BlockEntryInstr : public Instruction {
|
||||||
intptr_t offset() const { return offset_; }
|
intptr_t offset() const { return offset_; }
|
||||||
void set_offset(intptr_t offset) { offset_ = 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
|
// For all instruction in this block: Remove all inputs (including in the
|
||||||
// environment) from their definition's use lists for all instructions.
|
// environment) from their definition's use lists for all instructions.
|
||||||
void ClearAllInstructions();
|
void ClearAllInstructions();
|
||||||
|
@ -1395,12 +1399,16 @@ class BlockEntryInstr : public Instruction {
|
||||||
ADD_EXTRA_INFO_TO_S_EXPRESSION_SUPPORT
|
ADD_EXTRA_INFO_TO_S_EXPRESSION_SUPPORT
|
||||||
|
|
||||||
protected:
|
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),
|
: Instruction(deopt_id),
|
||||||
block_id_(block_id),
|
block_id_(block_id),
|
||||||
try_index_(try_index),
|
try_index_(try_index),
|
||||||
preorder_number_(-1),
|
preorder_number_(-1),
|
||||||
postorder_number_(-1),
|
postorder_number_(-1),
|
||||||
|
stack_depth_(stack_depth),
|
||||||
dominator_(nullptr),
|
dominator_(nullptr),
|
||||||
dominated_blocks_(1),
|
dominated_blocks_(1),
|
||||||
last_instruction_(NULL),
|
last_instruction_(NULL),
|
||||||
|
@ -1428,6 +1436,8 @@ class BlockEntryInstr : public Instruction {
|
||||||
intptr_t try_index_;
|
intptr_t try_index_;
|
||||||
intptr_t preorder_number_;
|
intptr_t preorder_number_;
|
||||||
intptr_t postorder_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
|
// Starting and ending lifetime positions for this block. Used by
|
||||||
// the linear scan register allocator.
|
// the linear scan register allocator.
|
||||||
intptr_t start_pos_;
|
intptr_t start_pos_;
|
||||||
|
@ -1512,8 +1522,9 @@ class BlockEntryWithInitialDefs : public BlockEntryInstr {
|
||||||
public:
|
public:
|
||||||
BlockEntryWithInitialDefs(intptr_t block_id,
|
BlockEntryWithInitialDefs(intptr_t block_id,
|
||||||
intptr_t try_index,
|
intptr_t try_index,
|
||||||
intptr_t deopt_id)
|
intptr_t deopt_id,
|
||||||
: BlockEntryInstr(block_id, try_index, deopt_id) {}
|
intptr_t stack_depth)
|
||||||
|
: BlockEntryInstr(block_id, try_index, deopt_id, stack_depth) {}
|
||||||
|
|
||||||
GrowableArray<Definition*>* initial_definitions() {
|
GrowableArray<Definition*>* initial_definitions() {
|
||||||
return &initial_definitions_;
|
return &initial_definitions_;
|
||||||
|
@ -1630,8 +1641,11 @@ class GraphEntryInstr : public BlockEntryWithInitialDefs {
|
||||||
|
|
||||||
class JoinEntryInstr : public BlockEntryInstr {
|
class JoinEntryInstr : public BlockEntryInstr {
|
||||||
public:
|
public:
|
||||||
JoinEntryInstr(intptr_t block_id, intptr_t try_index, intptr_t deopt_id)
|
JoinEntryInstr(intptr_t block_id,
|
||||||
: BlockEntryInstr(block_id, try_index, deopt_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.
|
predecessors_(2), // Two is the assumed to be the common case.
|
||||||
phis_(NULL) {}
|
phis_(NULL) {}
|
||||||
|
|
||||||
|
@ -1698,8 +1712,11 @@ class PhiIterator : public ValueObject {
|
||||||
|
|
||||||
class TargetEntryInstr : public BlockEntryInstr {
|
class TargetEntryInstr : public BlockEntryInstr {
|
||||||
public:
|
public:
|
||||||
TargetEntryInstr(intptr_t block_id, intptr_t try_index, intptr_t deopt_id)
|
TargetEntryInstr(intptr_t block_id,
|
||||||
: BlockEntryInstr(block_id, try_index, deopt_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),
|
predecessor_(NULL),
|
||||||
edge_weight_(0.0) {}
|
edge_weight_(0.0) {}
|
||||||
|
|
||||||
|
@ -1749,7 +1766,10 @@ class FunctionEntryInstr : public BlockEntryWithInitialDefs {
|
||||||
intptr_t block_id,
|
intptr_t block_id,
|
||||||
intptr_t try_index,
|
intptr_t try_index,
|
||||||
intptr_t deopt_id)
|
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) {}
|
graph_entry_(graph_entry) {}
|
||||||
|
|
||||||
DECLARE_INSTRUCTION(FunctionEntry)
|
DECLARE_INSTRUCTION(FunctionEntry)
|
||||||
|
@ -1815,8 +1835,7 @@ class OsrEntryInstr : public BlockEntryWithInitialDefs {
|
||||||
intptr_t try_index,
|
intptr_t try_index,
|
||||||
intptr_t deopt_id,
|
intptr_t deopt_id,
|
||||||
intptr_t stack_depth)
|
intptr_t stack_depth)
|
||||||
: BlockEntryWithInitialDefs(block_id, try_index, deopt_id),
|
: BlockEntryWithInitialDefs(block_id, try_index, deopt_id, stack_depth),
|
||||||
stack_depth_(stack_depth),
|
|
||||||
graph_entry_(graph_entry) {}
|
graph_entry_(graph_entry) {}
|
||||||
|
|
||||||
DECLARE_INSTRUCTION(OsrEntry)
|
DECLARE_INSTRUCTION(OsrEntry)
|
||||||
|
@ -1829,7 +1848,6 @@ class OsrEntryInstr : public BlockEntryWithInitialDefs {
|
||||||
return graph_entry_;
|
return graph_entry_;
|
||||||
}
|
}
|
||||||
|
|
||||||
intptr_t stack_depth() const { return stack_depth_; }
|
|
||||||
GraphEntryInstr* graph_entry() const { return graph_entry_; }
|
GraphEntryInstr* graph_entry() const { return graph_entry_; }
|
||||||
|
|
||||||
PRINT_TO_SUPPORT
|
PRINT_TO_SUPPORT
|
||||||
|
@ -1841,7 +1859,6 @@ class OsrEntryInstr : public BlockEntryWithInitialDefs {
|
||||||
graph_entry_ = predecessor->AsGraphEntry();
|
graph_entry_ = predecessor->AsGraphEntry();
|
||||||
}
|
}
|
||||||
|
|
||||||
const intptr_t stack_depth_;
|
|
||||||
GraphEntryInstr* graph_entry_;
|
GraphEntryInstr* graph_entry_;
|
||||||
|
|
||||||
DISALLOW_COPY_AND_ASSIGN(OsrEntryInstr);
|
DISALLOW_COPY_AND_ASSIGN(OsrEntryInstr);
|
||||||
|
@ -1880,7 +1897,10 @@ class CatchBlockEntryInstr : public BlockEntryWithInitialDefs {
|
||||||
const LocalVariable* stacktrace_var,
|
const LocalVariable* stacktrace_var,
|
||||||
const LocalVariable* raw_exception_var,
|
const LocalVariable* raw_exception_var,
|
||||||
const LocalVariable* raw_stacktrace_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),
|
graph_entry_(graph_entry),
|
||||||
predecessor_(NULL),
|
predecessor_(NULL),
|
||||||
catch_handler_types_(Array::ZoneHandle(handler_types.raw())),
|
catch_handler_types_(Array::ZoneHandle(handler_types.raw())),
|
||||||
|
|
|
@ -661,8 +661,8 @@ Fragment BaseFlowGraphBuilder::MakeTemp() {
|
||||||
}
|
}
|
||||||
|
|
||||||
TargetEntryInstr* BaseFlowGraphBuilder::BuildTargetEntry() {
|
TargetEntryInstr* BaseFlowGraphBuilder::BuildTargetEntry() {
|
||||||
return new (Z)
|
return new (Z) TargetEntryInstr(AllocateBlockId(), CurrentTryIndex(),
|
||||||
TargetEntryInstr(AllocateBlockId(), CurrentTryIndex(), GetNextDeoptId());
|
GetNextDeoptId(), GetStackDepth());
|
||||||
}
|
}
|
||||||
|
|
||||||
FunctionEntryInstr* BaseFlowGraphBuilder::BuildFunctionEntry(
|
FunctionEntryInstr* BaseFlowGraphBuilder::BuildFunctionEntry(
|
||||||
|
@ -672,12 +672,13 @@ FunctionEntryInstr* BaseFlowGraphBuilder::BuildFunctionEntry(
|
||||||
}
|
}
|
||||||
|
|
||||||
JoinEntryInstr* BaseFlowGraphBuilder::BuildJoinEntry(intptr_t try_index) {
|
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() {
|
JoinEntryInstr* BaseFlowGraphBuilder::BuildJoinEntry() {
|
||||||
return new (Z)
|
return new (Z) JoinEntryInstr(AllocateBlockId(), CurrentTryIndex(),
|
||||||
JoinEntryInstr(AllocateBlockId(), CurrentTryIndex(), GetNextDeoptId());
|
GetNextDeoptId(), GetStackDepth());
|
||||||
}
|
}
|
||||||
|
|
||||||
ArgumentArray BaseFlowGraphBuilder::GetArguments(int count) {
|
ArgumentArray BaseFlowGraphBuilder::GetArguments(int count) {
|
||||||
|
|
|
@ -2177,6 +2177,7 @@ FlowGraph* BytecodeFlowGraphBuilder::BuildGraph() {
|
||||||
B->stack_ = stack_state;
|
B->stack_ = stack_state;
|
||||||
}
|
}
|
||||||
code_ = Fragment(join);
|
code_ = Fragment(join);
|
||||||
|
join->set_stack_depth(B->GetStackDepth());
|
||||||
B->SetCurrentTryIndex(join->try_index());
|
B->SetCurrentTryIndex(join->try_index());
|
||||||
} else {
|
} else {
|
||||||
// Unreachable bytecode is not allowed.
|
// Unreachable bytecode is not allowed.
|
||||||
|
|
|
@ -267,8 +267,6 @@ Fragment PrologueBuilder::BuildOptionalParameterHandling(
|
||||||
copy_args_prologue += Drop();
|
copy_args_prologue += Drop();
|
||||||
|
|
||||||
for (intptr_t i = 0; param < num_params; ++param, ++i) {
|
for (intptr_t i = 0; param < num_params; ++param, ++i) {
|
||||||
JoinEntryInstr* join = BuildJoinEntry();
|
|
||||||
|
|
||||||
copy_args_prologue += IntConstant(
|
copy_args_prologue += IntConstant(
|
||||||
compiler::target::ArgumentsDescriptor::named_entry_size() /
|
compiler::target::ArgumentsDescriptor::named_entry_size() /
|
||||||
compiler::target::kWordSize);
|
compiler::target::kWordSize);
|
||||||
|
@ -299,6 +297,9 @@ Fragment PrologueBuilder::BuildOptionalParameterHandling(
|
||||||
TargetEntryInstr *supplied, *missing;
|
TargetEntryInstr *supplied, *missing;
|
||||||
copy_args_prologue += BranchIfStrictEqual(&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
|
// Let's load position from arg descriptor (to see which parameter is the
|
||||||
// name) and move kEntrySize forward in ArgDescriptopr names array.
|
// name) and move kEntrySize forward in ArgDescriptopr names array.
|
||||||
Fragment good(supplied);
|
Fragment good(supplied);
|
||||||
|
|
2362
tests/language_2/vm/regression_38436.dart
Normal file
2362
tests/language_2/vm/regression_38436.dart
Normal file
File diff suppressed because it is too large
Load diff
Loading…
Reference in a new issue