mirror of
https://github.com/dart-lang/sdk
synced 2024-10-14 15:47:08 +00:00
[vm/compiler] Rename PushArgument to MoveArgument
This is follow up to65f4a733bb
, which switched optimized code to use fixed frame for outgoing arguments. Change Kernel to IL translation to handle null-checks in invocations differently: this code used to duplicate receiver on the stack to accomodate for PushArgument in unoptimized code, but PushArgument has not been inserted sincef4e61eacfd
, which means duplication of the receiver is no longer necessary. TEST=ci Cq-Include-Trybots: luci.dart.try:vm-kernel-precomp-linux-debug-x64-try,vm-kernel-precomp-dwarf-linux-product-x64-try,vm-kernel-precomp-linux-release-simarm-try,vm-kernel-precomp-linux-release-x64-try,vm-kernel-precomp-nnbd-linux-debug-simarm_x64-try,vm-kernel-precomp-nnbd-linux-release-simarm64-try Change-Id: I6c1f1e8c354f9ea92424b6602b83b9e9ebce8b69 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/284184 Commit-Queue: Slava Egorov <vegorov@google.com> Reviewed-by: Martin Kustermann <kustermann@google.com>
This commit is contained in:
parent
354e8068a4
commit
93e73bf93a
|
@ -35,14 +35,14 @@ void matchIL$test(FlowGraph graph) {
|
|||
'bar' << match.Parameter(index: 3),
|
||||
'baz' << match.Parameter(index: 4),
|
||||
match.CheckStackOverflow(),
|
||||
match.PushArgument('x'),
|
||||
match.MoveArgument('x'),
|
||||
match.StaticCall(),
|
||||
match.PushArgument('y'),
|
||||
match.MoveArgument('y'),
|
||||
match.StaticCall(),
|
||||
'baz_boxed' << match.BoxInt64('baz'),
|
||||
match.PushArgument('foo'),
|
||||
match.MoveArgument('foo'),
|
||||
match.StaticCall(),
|
||||
match.PushArgument('baz_boxed'),
|
||||
match.MoveArgument('baz_boxed'),
|
||||
match.StaticCall(),
|
||||
match.Return(),
|
||||
]),
|
||||
|
|
|
@ -103,42 +103,42 @@ void matchIL$test(FlowGraph graph) {
|
|||
'obj2' << match.Parameter(index: 5),
|
||||
match.CheckStackOverflow(),
|
||||
|
||||
match.PushArgument('x'),
|
||||
match.PushArgument('z'),
|
||||
match.MoveArgument('x'),
|
||||
match.MoveArgument('z'),
|
||||
'r1' << match.StaticCall(),
|
||||
'r1_0' << match.ExtractNthOutput('r1', index: 0),
|
||||
'r1_1' << match.ExtractNthOutput('r1', index: 1),
|
||||
match.PushArgument('r1_0'),
|
||||
match.MoveArgument('r1_0'),
|
||||
match.StaticCall(),
|
||||
match.PushArgument('r1_1'),
|
||||
match.MoveArgument('r1_1'),
|
||||
match.StaticCall(),
|
||||
|
||||
match.PushArgument('foo'),
|
||||
match.PushArgument('bar'),
|
||||
match.MoveArgument('foo'),
|
||||
match.MoveArgument('bar'),
|
||||
'r2' << match.StaticCall(),
|
||||
'r2_bar' << match.ExtractNthOutput('r2', index: 0),
|
||||
'r2_foo' << match.ExtractNthOutput('r2', index: 1),
|
||||
match.PushArgument('r2_foo'),
|
||||
match.MoveArgument('r2_foo'),
|
||||
match.StaticCall(),
|
||||
match.PushArgument('r2_bar'),
|
||||
match.MoveArgument('r2_bar'),
|
||||
match.StaticCall(),
|
||||
|
||||
match.PushArgument('obj1'),
|
||||
match.MoveArgument('obj1'),
|
||||
'r3' << match.StaticCall(),
|
||||
'r3_0' << match.ExtractNthOutput('r3', index: 0),
|
||||
'r3_y' << match.ExtractNthOutput('r3', index: 1),
|
||||
match.PushArgument('r3_0'),
|
||||
match.MoveArgument('r3_0'),
|
||||
match.StaticCall(),
|
||||
match.PushArgument('r3_y'),
|
||||
match.MoveArgument('r3_y'),
|
||||
match.StaticCall(),
|
||||
|
||||
'obj2_cid' << match.LoadClassId('obj2'),
|
||||
match.PushArgument('obj2'),
|
||||
match.MoveArgument('obj2'),
|
||||
'r4' << match.DispatchTableCall('obj2_cid'),
|
||||
'r4_0' << match.ExtractNthOutput('r4', index: 0),
|
||||
'r4_y' << match.ExtractNthOutput('r4', index: 1),
|
||||
'r4_boxed' << match.AllocateSmallRecord('r4_0', 'r4_y'),
|
||||
match.PushArgument('r4_boxed'),
|
||||
match.MoveArgument('r4_boxed'),
|
||||
match.StaticCall(),
|
||||
|
||||
match.Return(),
|
||||
|
|
|
@ -432,8 +432,8 @@ void ConstantPropagator::VisitNativeParameter(NativeParameterInstr* instr) {
|
|||
SetValue(instr, non_constant_);
|
||||
}
|
||||
|
||||
void ConstantPropagator::VisitPushArgument(PushArgumentInstr* instr) {
|
||||
UNREACHABLE();
|
||||
void ConstantPropagator::VisitMoveArgument(MoveArgumentInstr* instr) {
|
||||
UNREACHABLE(); // Inserted right before register allocation.
|
||||
}
|
||||
|
||||
void ConstantPropagator::VisitAssertAssignable(AssertAssignableInstr* instr) {
|
||||
|
@ -1753,7 +1753,6 @@ bool ConstantPropagator::TransformDefinition(Definition* defn) {
|
|||
// Replace constant-valued instructions without observable side
|
||||
// effects. Do this for smis and old objects only to avoid having to
|
||||
// copy other objects into the heap's old generation.
|
||||
ASSERT((defn == nullptr) || !defn->IsPushArgument());
|
||||
if ((defn != nullptr) && IsConstant(defn->constant_value()) &&
|
||||
(defn->constant_value().IsSmi() || defn->constant_value().IsOld()) &&
|
||||
!defn->IsConstant() && !defn->IsStoreIndexed() && !defn->IsStoreField() &&
|
||||
|
@ -1770,7 +1769,7 @@ bool ConstantPropagator::TransformDefinition(Definition* defn) {
|
|||
ASSERT(!constant_value_.IsNull());
|
||||
}
|
||||
if (auto call = defn->AsStaticCall()) {
|
||||
ASSERT(!call->HasPushArguments());
|
||||
ASSERT(!call->HasMoveArguments());
|
||||
}
|
||||
Definition* replacement =
|
||||
graph_->TryCreateConstantReplacementFor(defn, constant_value_);
|
||||
|
|
|
@ -158,7 +158,7 @@ void FlowGraph::ReplaceCurrentInstruction(ForwardInstructionIterator* iterator,
|
|||
}
|
||||
}
|
||||
if (current->ArgumentCount() != 0) {
|
||||
ASSERT(!current->HasPushArguments());
|
||||
ASSERT(!current->HasMoveArguments());
|
||||
}
|
||||
iterator->RemoveCurrentFromGraph();
|
||||
}
|
||||
|
@ -1558,7 +1558,7 @@ void FlowGraph::RenameRecursive(
|
|||
break;
|
||||
}
|
||||
|
||||
case Instruction::kPushArgument:
|
||||
case Instruction::kMoveArgument:
|
||||
UNREACHABLE();
|
||||
break;
|
||||
|
||||
|
@ -1628,7 +1628,7 @@ void FlowGraph::RenameRecursive(
|
|||
// Rename input operand.
|
||||
Definition* input = (*env)[i];
|
||||
ASSERT(input != nullptr);
|
||||
ASSERT(!input->IsPushArgument());
|
||||
ASSERT(!input->IsMoveArgument());
|
||||
Value* use = new (zone()) Value(input);
|
||||
phi->SetInputAt(pred_index, use);
|
||||
}
|
||||
|
@ -2414,7 +2414,7 @@ void FlowGraph::WidenSmiToInt32() {
|
|||
if (use_defn == NULL) {
|
||||
// We assume that tagging before returning or pushing argument costs
|
||||
// very little compared to the cost of the return/call itself.
|
||||
ASSERT(!instr->IsPushArgument());
|
||||
ASSERT(!instr->IsMoveArgument());
|
||||
if (!instr->IsReturn() &&
|
||||
(use->use_index() >= instr->ArgumentCount())) {
|
||||
gain--;
|
||||
|
@ -2998,7 +2998,7 @@ PhiInstr* FlowGraph::AddPhi(JoinEntryInstr* join,
|
|||
return phi;
|
||||
}
|
||||
|
||||
void FlowGraph::InsertPushArguments() {
|
||||
void FlowGraph::InsertMoveArguments() {
|
||||
intptr_t max_argument_slot_count = 0;
|
||||
for (BlockIterator block_it = reverse_postorder_iterator(); !block_it.Done();
|
||||
block_it.Advance()) {
|
||||
|
@ -3010,37 +3010,37 @@ void FlowGraph::InsertPushArguments() {
|
|||
if (arg_count == 0) {
|
||||
continue;
|
||||
}
|
||||
PushArgumentsArray* arguments =
|
||||
new (Z) PushArgumentsArray(zone(), arg_count);
|
||||
MoveArgumentsArray* arguments =
|
||||
new (Z) MoveArgumentsArray(zone(), arg_count);
|
||||
arguments->EnsureLength(arg_count, nullptr);
|
||||
|
||||
intptr_t top_of_stack_relative_index = 0;
|
||||
intptr_t sp_relative_index = 0;
|
||||
for (intptr_t i = arg_count - 1; i >= 0; --i) {
|
||||
Value* arg = instruction->ArgumentValueAt(i);
|
||||
const auto rep = instruction->RequiredInputRepresentation(i);
|
||||
(*arguments)[i] = new (Z) PushArgumentInstr(
|
||||
arg->CopyWithType(Z), rep, top_of_stack_relative_index);
|
||||
(*arguments)[i] = new (Z)
|
||||
MoveArgumentInstr(arg->CopyWithType(Z), rep, sp_relative_index);
|
||||
|
||||
static_assert(compiler::target::kIntSpillFactor ==
|
||||
compiler::target::kDoubleSpillFactor,
|
||||
"double and int are expected to be of the same size");
|
||||
RELEASE_ASSERT(rep == kTagged || rep == kUnboxedDouble ||
|
||||
rep == kUnboxedInt64);
|
||||
top_of_stack_relative_index +=
|
||||
sp_relative_index +=
|
||||
(rep == kTagged) ? 1 : compiler::target::kIntSpillFactor;
|
||||
}
|
||||
max_argument_slot_count =
|
||||
Utils::Maximum(max_argument_slot_count, top_of_stack_relative_index);
|
||||
Utils::Maximum(max_argument_slot_count, sp_relative_index);
|
||||
|
||||
for (auto push_arg : *arguments) {
|
||||
// Insert all PushArgument instructions immediately before call.
|
||||
// PushArgumentInstr::EmitNativeCode may generate more efficient
|
||||
// code for subsequent PushArgument instructions (ARM, ARM64).
|
||||
InsertBefore(instruction, push_arg, /*env=*/nullptr, kEffect);
|
||||
for (auto move_arg : *arguments) {
|
||||
// Insert all MoveArgument instructions immediately before call.
|
||||
// MoveArgumentInstr::EmitNativeCode may generate more efficient
|
||||
// code for subsequent MoveArgument instructions (ARM, ARM64).
|
||||
InsertBefore(instruction, move_arg, /*env=*/nullptr, kEffect);
|
||||
}
|
||||
instruction->ReplaceInputsWithPushArguments(arguments);
|
||||
instruction->ReplaceInputsWithMoveArguments(arguments);
|
||||
if (instruction->env() != nullptr) {
|
||||
instruction->RepairPushArgsInEnvironment();
|
||||
instruction->RepairArgumentUsesInEnvironment();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -382,11 +382,11 @@ class FlowGraph : public ZoneAllocated {
|
|||
// Remove the redefinition instructions inserted to inhibit code motion.
|
||||
void RemoveRedefinitions(bool keep_checks = false);
|
||||
|
||||
// Insert PushArgument instructions and remove explicit def-use
|
||||
// Insert MoveArgument instructions and remove explicit def-use
|
||||
// relations between calls and their arguments.
|
||||
//
|
||||
// Compute the maximum number of arguments.
|
||||
void InsertPushArguments();
|
||||
void InsertMoveArguments();
|
||||
|
||||
// Copy deoptimization target from one instruction to another if we still
|
||||
// have to keep deoptimization environment at gotos for LICM purposes.
|
||||
|
|
|
@ -140,10 +140,10 @@ static void AssertArgumentsInEnv(FlowGraph* flow_graph, Definition* call) {
|
|||
ASSERT1((arg_count + after_args_input_count) <= env_count, call);
|
||||
const intptr_t env_base = env_count - arg_count - after_args_input_count;
|
||||
for (intptr_t i = 0; i < arg_count; i++) {
|
||||
if (call->HasPushArguments()) {
|
||||
if (call->HasMoveArguments()) {
|
||||
ASSERT1(call->ArgumentAt(i) == env->ValueAt(env_base + i)
|
||||
->definition()
|
||||
->AsPushArgument()
|
||||
->AsMoveArgument()
|
||||
->value()
|
||||
->definition(),
|
||||
call);
|
||||
|
|
|
@ -95,16 +95,16 @@ compiler::LRState ComputeInnerLRState(const FlowGraph& flow_graph) {
|
|||
}
|
||||
#endif
|
||||
|
||||
// Assign locations to incoming arguments, i.e., values pushed above spill slots
|
||||
// with PushArgument. Recursively allocates from outermost to innermost
|
||||
// environment.
|
||||
void CompilerDeoptInfo::AllocateIncomingParametersRecursive(Environment* env) {
|
||||
// Assign locations to outgoing arguments. Note that MoveArgument
|
||||
// can only occur in the innermost environment because we insert
|
||||
// them immediately before the call instruction and right before
|
||||
// register allocation.
|
||||
void CompilerDeoptInfo::AllocateOutgoingArguments(Environment* env) {
|
||||
if (env == NULL) return;
|
||||
AllocateIncomingParametersRecursive(env->outer());
|
||||
for (Environment::ShallowIterator it(env); !it.Done(); it.Advance()) {
|
||||
if (it.CurrentLocation().IsInvalid()) {
|
||||
if (auto push_arg = it.CurrentValue()->definition()->AsPushArgument()) {
|
||||
it.SetCurrentLocation(push_arg->locs()->out(0));
|
||||
if (auto move_arg = it.CurrentValue()->definition()->AsMoveArgument()) {
|
||||
it.SetCurrentLocation(move_arg->locs()->out(0));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -592,8 +592,7 @@ static bool IsPusher(Instruction* instr) {
|
|||
static bool IsPopper(Instruction* instr) {
|
||||
// TODO(ajcbik): even allow deopt targets by making environment aware?
|
||||
if (!instr->CanBecomeDeoptimizationTarget()) {
|
||||
return !instr->IsPushArgument() && instr->ArgumentCount() == 0 &&
|
||||
instr->InputCount() > 0;
|
||||
return instr->ArgumentCount() == 0 && instr->InputCount() > 0;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
@ -1040,21 +1039,21 @@ void FlowGraphCompiler::RecordSafepoint(LocationSummary* locs,
|
|||
RELEASE_ASSERT(args_count == 0 || is_optimizing());
|
||||
|
||||
for (intptr_t i = 0; i < args_count; i++) {
|
||||
const auto push_arg =
|
||||
instr->ArgumentValueAt(i)->instruction()->AsPushArgument();
|
||||
const auto rep = push_arg->representation();
|
||||
const auto move_arg =
|
||||
instr->ArgumentValueAt(i)->instruction()->AsMoveArgument();
|
||||
const auto rep = move_arg->representation();
|
||||
|
||||
ASSERT(rep == kTagged || rep == kUnboxedInt64 || rep == kUnboxedDouble);
|
||||
static_assert(compiler::target::kIntSpillFactor ==
|
||||
compiler::target::kDoubleSpillFactor,
|
||||
"int and double are of the same size");
|
||||
const bool is_tagged = push_arg->representation() == kTagged;
|
||||
const bool is_tagged = move_arg->representation() == kTagged;
|
||||
const intptr_t num_bits =
|
||||
is_tagged ? 1 : compiler::target::kIntSpillFactor;
|
||||
|
||||
// Note: bits are reversed so higher bit corresponds to lower word.
|
||||
const intptr_t last_arg_bit =
|
||||
(spill_area_size - 1) - push_arg->top_of_stack_relative_index();
|
||||
(spill_area_size - 1) - move_arg->sp_relative_index();
|
||||
bitmap.SetRange(last_arg_bit - (num_bits - 1), last_arg_bit, is_tagged);
|
||||
}
|
||||
ASSERT(slow_path_argument_count == 0 || !using_shared_stub);
|
||||
|
@ -1731,7 +1730,7 @@ void FlowGraphCompiler::AllocateRegistersLocally(Instruction* instr) {
|
|||
}
|
||||
|
||||
// Allocate all unallocated input locations.
|
||||
RELEASE_ASSERT(!instr->IsPushArgument());
|
||||
ASSERT(!instr->IsMoveArgument());
|
||||
Register fpu_unboxing_temp = kNoRegister;
|
||||
for (intptr_t i = locs->input_count() - 1; i >= 0; i--) {
|
||||
Location loc = locs->in(i);
|
||||
|
@ -3292,10 +3291,6 @@ void FlowGraphCompiler::FrameStateUpdateWith(Instruction* instr) {
|
|||
ASSERT(!is_optimizing());
|
||||
|
||||
switch (instr->tag()) {
|
||||
case Instruction::kPushArgument:
|
||||
// Do nothing.
|
||||
break;
|
||||
|
||||
case Instruction::kDropTemps:
|
||||
FrameStatePop(instr->locs()->input_count() +
|
||||
instr->AsDropTemps()->num_temps());
|
||||
|
|
|
@ -199,7 +199,7 @@ class CompilerDeoptInfo : public ZoneAllocated {
|
|||
private:
|
||||
void EmitMaterializations(Environment* env, DeoptInfoBuilder* builder);
|
||||
|
||||
void AllocateIncomingParametersRecursive(Environment* env);
|
||||
void AllocateOutgoingArguments(Environment* env);
|
||||
|
||||
intptr_t pc_offset_;
|
||||
const intptr_t deopt_id_;
|
||||
|
|
|
@ -98,7 +98,7 @@ TypedDataPtr CompilerDeoptInfo::CreateDeoptInfo(FlowGraphCompiler* compiler,
|
|||
return TypedData::null();
|
||||
}
|
||||
|
||||
AllocateIncomingParametersRecursive(deopt_env_);
|
||||
AllocateOutgoingArguments(deopt_env_);
|
||||
|
||||
intptr_t slot_ix = 0;
|
||||
Environment* current = deopt_env_;
|
||||
|
|
|
@ -92,7 +92,7 @@ TypedDataPtr CompilerDeoptInfo::CreateDeoptInfo(FlowGraphCompiler* compiler,
|
|||
return TypedData::null();
|
||||
}
|
||||
|
||||
AllocateIncomingParametersRecursive(deopt_env_);
|
||||
AllocateOutgoingArguments(deopt_env_);
|
||||
|
||||
intptr_t slot_ix = 0;
|
||||
Environment* current = deopt_env_;
|
||||
|
|
|
@ -70,7 +70,7 @@ TypedDataPtr CompilerDeoptInfo::CreateDeoptInfo(FlowGraphCompiler* compiler,
|
|||
return TypedData::null();
|
||||
}
|
||||
|
||||
AllocateIncomingParametersRecursive(deopt_env_);
|
||||
AllocateOutgoingArguments(deopt_env_);
|
||||
|
||||
intptr_t slot_ix = 0;
|
||||
Environment* current = deopt_env_;
|
||||
|
|
|
@ -79,7 +79,7 @@ TypedDataPtr CompilerDeoptInfo::CreateDeoptInfo(FlowGraphCompiler* compiler,
|
|||
return TypedData::null();
|
||||
}
|
||||
|
||||
AllocateIncomingParametersRecursive(deopt_env_);
|
||||
AllocateOutgoingArguments(deopt_env_);
|
||||
|
||||
intptr_t slot_ix = 0;
|
||||
Environment* current = deopt_env_;
|
||||
|
|
|
@ -93,7 +93,7 @@ TypedDataPtr CompilerDeoptInfo::CreateDeoptInfo(FlowGraphCompiler* compiler,
|
|||
return TypedData::null();
|
||||
}
|
||||
|
||||
AllocateIncomingParametersRecursive(deopt_env_);
|
||||
AllocateOutgoingArguments(deopt_env_);
|
||||
|
||||
intptr_t slot_ix = 0;
|
||||
Environment* current = deopt_env_;
|
||||
|
|
|
@ -1475,18 +1475,18 @@ void Instruction::UnuseAllInputs() {
|
|||
}
|
||||
}
|
||||
|
||||
void Instruction::RepairPushArgsInEnvironment() const {
|
||||
void Instruction::RepairArgumentUsesInEnvironment() const {
|
||||
// Some calls (e.g. closure calls) have more inputs than actual arguments.
|
||||
// Those extra inputs will be consumed from the stack before the call.
|
||||
const intptr_t after_args_input_count = env()->LazyDeoptPruneCount();
|
||||
PushArgumentsArray* push_arguments = GetPushArguments();
|
||||
ASSERT(push_arguments != nullptr);
|
||||
MoveArgumentsArray* move_arguments = GetMoveArguments();
|
||||
ASSERT(move_arguments != nullptr);
|
||||
const intptr_t arg_count = ArgumentCount();
|
||||
ASSERT((arg_count + after_args_input_count) <= env()->Length());
|
||||
const intptr_t env_base =
|
||||
env()->Length() - arg_count - after_args_input_count;
|
||||
for (intptr_t i = 0; i < arg_count; ++i) {
|
||||
env()->ValueAt(env_base + i)->BindToEnvironment(push_arguments->At(i));
|
||||
env()->ValueAt(env_base + i)->BindToEnvironment(move_arguments->At(i));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -419,7 +419,7 @@ struct InstrAttrs {
|
|||
M(MemoryCopy, kNoGC) \
|
||||
M(TailCall, kNoGC) \
|
||||
M(ParallelMove, kNoGC) \
|
||||
M(PushArgument, kNoGC) \
|
||||
M(MoveArgument, kNoGC) \
|
||||
M(Return, kNoGC) \
|
||||
M(NativeReturn, kNoGC) \
|
||||
M(Throw, kNoGC) \
|
||||
|
@ -860,7 +860,7 @@ class BinaryFeedback : public ZoneAllocated {
|
|||
};
|
||||
|
||||
typedef GrowableArray<Value*> InputsArray;
|
||||
typedef ZoneGrowableArray<PushArgumentInstr*> PushArgumentsArray;
|
||||
typedef ZoneGrowableArray<MoveArgumentInstr*> MoveArgumentsArray;
|
||||
|
||||
template <typename Trait>
|
||||
class InstructionIndexedPropertyIterable {
|
||||
|
@ -1003,24 +1003,25 @@ class Instruction : public ZoneAllocated {
|
|||
inline Value* ArgumentValueAt(intptr_t index) const;
|
||||
inline Definition* ArgumentAt(intptr_t index) const;
|
||||
|
||||
// Sets array of PushArgument instructions.
|
||||
virtual void SetPushArguments(PushArgumentsArray* push_arguments) {
|
||||
// Sets array of MoveArgument instructions.
|
||||
virtual void SetMoveArguments(MoveArgumentsArray* move_arguments) {
|
||||
UNREACHABLE();
|
||||
}
|
||||
// Returns array of PushArgument instructions
|
||||
virtual PushArgumentsArray* GetPushArguments() const {
|
||||
// Returns array of MoveArgument instructions
|
||||
virtual MoveArgumentsArray* GetMoveArguments() const {
|
||||
UNREACHABLE();
|
||||
return nullptr;
|
||||
}
|
||||
// Replace inputs with separate PushArgument instructions detached from call.
|
||||
virtual void ReplaceInputsWithPushArguments(
|
||||
PushArgumentsArray* push_arguments) {
|
||||
// Replace inputs with separate MoveArgument instructions detached from call.
|
||||
virtual void ReplaceInputsWithMoveArguments(
|
||||
MoveArgumentsArray* move_arguments) {
|
||||
UNREACHABLE();
|
||||
}
|
||||
bool HasPushArguments() const { return GetPushArguments() != nullptr; }
|
||||
bool HasMoveArguments() const { return GetMoveArguments() != nullptr; }
|
||||
|
||||
// Repairs trailing PushArgs in environment.
|
||||
void RepairPushArgsInEnvironment() const;
|
||||
// Replaces direct uses of arguments with uses of corresponding MoveArgument
|
||||
// instructions.
|
||||
void RepairArgumentUsesInEnvironment() const;
|
||||
|
||||
// Returns true, if this instruction can deoptimize with its current inputs.
|
||||
// This property can change if we add or remove redefinitions that constrain
|
||||
|
@ -3163,21 +3164,20 @@ class TailCallInstr : public TemplateInstruction<1, Throws, Pure> {
|
|||
DISALLOW_COPY_AND_ASSIGN(TailCallInstr);
|
||||
};
|
||||
|
||||
class PushArgumentInstr : public TemplateDefinition<1, NoThrow> {
|
||||
// Move the given argument value into the place where callee expects it.
|
||||
// Currently all outgoing arguments are located in [SP+idx]
|
||||
class MoveArgumentInstr : public TemplateDefinition<1, NoThrow> {
|
||||
public:
|
||||
explicit PushArgumentInstr(Value* value,
|
||||
explicit MoveArgumentInstr(Value* value,
|
||||
Representation representation,
|
||||
intptr_t top_of_stack_relative_index)
|
||||
: representation_(representation),
|
||||
top_of_stack_relative_index_(top_of_stack_relative_index) {
|
||||
intptr_t sp_relative_index)
|
||||
: representation_(representation), sp_relative_index_(sp_relative_index) {
|
||||
SetInputAt(0, value);
|
||||
}
|
||||
|
||||
DECLARE_INSTRUCTION(PushArgument)
|
||||
DECLARE_INSTRUCTION(MoveArgument)
|
||||
|
||||
intptr_t top_of_stack_relative_index() const {
|
||||
return top_of_stack_relative_index_;
|
||||
}
|
||||
intptr_t sp_relative_index() const { return sp_relative_index_; }
|
||||
|
||||
virtual CompileType ComputeType() const;
|
||||
|
||||
|
@ -3188,7 +3188,7 @@ class PushArgumentInstr : public TemplateDefinition<1, NoThrow> {
|
|||
virtual bool HasUnknownSideEffects() const { return false; }
|
||||
|
||||
virtual TokenPosition token_pos() const {
|
||||
return TokenPosition::kPushArgument;
|
||||
return TokenPosition::kMoveArgument;
|
||||
}
|
||||
|
||||
virtual Representation representation() const { return representation_; }
|
||||
|
@ -3202,20 +3202,20 @@ class PushArgumentInstr : public TemplateDefinition<1, NoThrow> {
|
|||
|
||||
#define FIELD_LIST(F) \
|
||||
F(const Representation, representation_) \
|
||||
F(const intptr_t, top_of_stack_relative_index_)
|
||||
F(const intptr_t, sp_relative_index_)
|
||||
|
||||
DECLARE_INSTRUCTION_SERIALIZABLE_FIELDS(PushArgumentInstr,
|
||||
DECLARE_INSTRUCTION_SERIALIZABLE_FIELDS(MoveArgumentInstr,
|
||||
TemplateDefinition,
|
||||
FIELD_LIST)
|
||||
#undef FIELD_LIST
|
||||
|
||||
private:
|
||||
DISALLOW_COPY_AND_ASSIGN(PushArgumentInstr);
|
||||
DISALLOW_COPY_AND_ASSIGN(MoveArgumentInstr);
|
||||
};
|
||||
|
||||
inline Value* Instruction::ArgumentValueAt(intptr_t index) const {
|
||||
PushArgumentsArray* push_arguments = GetPushArguments();
|
||||
return push_arguments != nullptr ? (*push_arguments)[index]->value()
|
||||
MoveArgumentsArray* move_arguments = GetMoveArguments();
|
||||
return move_arguments != nullptr ? (*move_arguments)[index]->value()
|
||||
: InputAt(index);
|
||||
}
|
||||
|
||||
|
@ -3691,11 +3691,11 @@ class BranchInstr : public Instruction {
|
|||
virtual intptr_t ArgumentCount() const {
|
||||
return comparison()->ArgumentCount();
|
||||
}
|
||||
virtual void SetPushArguments(PushArgumentsArray* push_arguments) {
|
||||
comparison()->SetPushArguments(push_arguments);
|
||||
virtual void SetMoveArguments(MoveArgumentsArray* move_arguments) {
|
||||
comparison()->SetMoveArguments(move_arguments);
|
||||
}
|
||||
virtual PushArgumentsArray* GetPushArguments() const {
|
||||
return comparison()->GetPushArguments();
|
||||
virtual MoveArgumentsArray* GetMoveArguments() const {
|
||||
return comparison()->GetMoveArguments();
|
||||
}
|
||||
|
||||
intptr_t InputCount() const { return comparison()->InputCount(); }
|
||||
|
@ -4331,23 +4331,23 @@ class TemplateDartCall : public VariadicDefinition {
|
|||
// ArgumentCount() includes the type argument vector if any.
|
||||
// Caution: Must override Instruction::ArgumentCount().
|
||||
intptr_t ArgumentCount() const {
|
||||
return push_arguments_ != nullptr ? push_arguments_->length()
|
||||
return move_arguments_ != nullptr ? move_arguments_->length()
|
||||
: InputCount() - kExtraInputs;
|
||||
}
|
||||
virtual intptr_t ArgumentsSize() const { return ArgumentCount(); }
|
||||
|
||||
virtual void SetPushArguments(PushArgumentsArray* push_arguments) {
|
||||
ASSERT(push_arguments_ == nullptr);
|
||||
push_arguments_ = push_arguments;
|
||||
virtual void SetMoveArguments(MoveArgumentsArray* move_arguments) {
|
||||
ASSERT(move_arguments_ == nullptr);
|
||||
move_arguments_ = move_arguments;
|
||||
}
|
||||
virtual PushArgumentsArray* GetPushArguments() const {
|
||||
return push_arguments_;
|
||||
virtual MoveArgumentsArray* GetMoveArguments() const {
|
||||
return move_arguments_;
|
||||
}
|
||||
virtual void ReplaceInputsWithPushArguments(
|
||||
PushArgumentsArray* push_arguments) {
|
||||
ASSERT(push_arguments_ == nullptr);
|
||||
ASSERT(push_arguments->length() == ArgumentCount());
|
||||
SetPushArguments(push_arguments);
|
||||
virtual void ReplaceInputsWithMoveArguments(
|
||||
MoveArgumentsArray* move_arguments) {
|
||||
ASSERT(move_arguments_ == nullptr);
|
||||
ASSERT(move_arguments->length() == ArgumentCount());
|
||||
SetMoveArguments(move_arguments);
|
||||
ASSERT(InputCount() == ArgumentCount() + kExtraInputs);
|
||||
const intptr_t extra_inputs_base = InputCount() - kExtraInputs;
|
||||
for (intptr_t i = 0, n = ArgumentCount(); i < n; ++i) {
|
||||
|
@ -4379,7 +4379,7 @@ class TemplateDartCall : public VariadicDefinition {
|
|||
DECLARE_EXTRA_SERIALIZATION
|
||||
|
||||
private:
|
||||
PushArgumentsArray* push_arguments_ = nullptr;
|
||||
MoveArgumentsArray* move_arguments_ = nullptr;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(TemplateDartCall);
|
||||
};
|
||||
|
@ -4666,7 +4666,7 @@ class PolymorphicInstanceCallInstr : public InstanceCallBaseInstr {
|
|||
InstanceCallBaseInstr* call,
|
||||
const CallTargets& targets,
|
||||
bool complete) {
|
||||
ASSERT(!call->HasPushArguments());
|
||||
ASSERT(!call->HasMoveArguments());
|
||||
InputsArray args(zone, call->ArgumentCount());
|
||||
for (intptr_t i = 0, n = call->ArgumentCount(); i < n; ++i) {
|
||||
args.Add(call->ArgumentValueAt(i)->CopyWithType(zone));
|
||||
|
@ -5244,7 +5244,7 @@ class StaticCallInstr : public TemplateDartCall<0> {
|
|||
const C* call,
|
||||
const Function& target,
|
||||
intptr_t call_count) {
|
||||
ASSERT(!call->HasPushArguments());
|
||||
ASSERT(!call->HasMoveArguments());
|
||||
InputsArray args(zone, call->ArgumentCount());
|
||||
for (intptr_t i = 0; i < call->ArgumentCount(); i++) {
|
||||
args.Add(call->ArgumentValueAt(i)->CopyWithType());
|
||||
|
@ -10833,7 +10833,7 @@ class Environment : public ZoneAllocated {
|
|||
intptr_t CountArgsPushed() {
|
||||
intptr_t count = 0;
|
||||
for (Environment::DeepIterator it(this); !it.Done(); it.Advance()) {
|
||||
if (it.CurrentValue()->definition()->IsPushArgument()) {
|
||||
if (it.CurrentValue()->definition()->IsMoveArgument()) {
|
||||
count++;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -319,7 +319,7 @@ void MemoryCopyInstr::EmitComputeStartPointer(FlowGraphCompiler* compiler,
|
|||
}
|
||||
}
|
||||
|
||||
LocationSummary* PushArgumentInstr::MakeLocationSummary(Zone* zone,
|
||||
LocationSummary* MoveArgumentInstr::MakeLocationSummary(Zone* zone,
|
||||
bool opt) const {
|
||||
const intptr_t kNumInputs = 1;
|
||||
const intptr_t kNumTemps = 0;
|
||||
|
@ -336,9 +336,9 @@ LocationSummary* PushArgumentInstr::MakeLocationSummary(Zone* zone,
|
|||
return locs;
|
||||
}
|
||||
|
||||
// Buffers registers to use STMDB in order to push
|
||||
// Buffers registers to use STMDB in order to store
|
||||
// multiple registers at once.
|
||||
class ArgumentsPusher : public ValueObject {
|
||||
class ArgumentsMover : public ValueObject {
|
||||
public:
|
||||
// Flush all buffered registers.
|
||||
void Flush(FlowGraphCompiler* compiler) {
|
||||
|
@ -393,13 +393,13 @@ class ArgumentsPusher : public ValueObject {
|
|||
|
||||
// Return a register which can be used to hold a value of an argument.
|
||||
Register FindFreeRegister(FlowGraphCompiler* compiler,
|
||||
Instruction* push_arg) {
|
||||
Instruction* move_arg) {
|
||||
// Dart calling conventions do not have callee-save registers,
|
||||
// so arguments pushing can clobber all allocatable registers
|
||||
// except registers used in arguments which were not pushed yet,
|
||||
// as well as ParallelMove and inputs of a call instruction.
|
||||
intptr_t busy = kReservedCpuRegisters;
|
||||
for (Instruction* instr = push_arg;; instr = instr->next()) {
|
||||
for (Instruction* instr = move_arg;; instr = instr->next()) {
|
||||
ASSERT(instr != nullptr);
|
||||
if (ParallelMoveInstr* parallel_move = instr->AsParallelMove()) {
|
||||
for (intptr_t i = 0, n = parallel_move->NumMoves(); i < n; ++i) {
|
||||
|
@ -412,7 +412,7 @@ class ArgumentsPusher : public ValueObject {
|
|||
}
|
||||
}
|
||||
} else {
|
||||
ASSERT(instr->IsPushArgument() || (instr->ArgumentCount() > 0));
|
||||
ASSERT(instr->IsMoveArgument() || (instr->ArgumentCount() > 0));
|
||||
for (intptr_t i = 0, n = instr->locs()->input_count(); i < n; ++i) {
|
||||
const auto in_loc = instr->locs()->in(i);
|
||||
if (in_loc.IsRegister()) {
|
||||
|
@ -463,32 +463,31 @@ class ArgumentsPusher : public ValueObject {
|
|||
}
|
||||
};
|
||||
|
||||
void PushArgumentInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
||||
void MoveArgumentInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
||||
ASSERT(compiler->is_optimizing());
|
||||
if (previous()->IsPushArgument()) {
|
||||
// Already generated by the first PushArgument in the chain.
|
||||
if (previous()->IsMoveArgument()) {
|
||||
// Already generated by the first MoveArgument in the chain.
|
||||
return;
|
||||
}
|
||||
|
||||
ArgumentsPusher pusher;
|
||||
for (PushArgumentInstr* push_arg = this; push_arg != nullptr;
|
||||
push_arg = push_arg->next()->AsPushArgument()) {
|
||||
const Location value = push_arg->locs()->in(0);
|
||||
ArgumentsMover pusher;
|
||||
for (MoveArgumentInstr* move_arg = this; move_arg != nullptr;
|
||||
move_arg = move_arg->next()->AsMoveArgument()) {
|
||||
const Location value = move_arg->locs()->in(0);
|
||||
if (value.IsRegister()) {
|
||||
pusher.MoveRegister(compiler, push_arg->top_of_stack_relative_index(),
|
||||
value.reg());
|
||||
pusher.MoveRegister(compiler, move_arg->sp_relative_index(), value.reg());
|
||||
} else if (value.IsPairLocation()) {
|
||||
pusher.MoveRegister(compiler, push_arg->top_of_stack_relative_index() + 1,
|
||||
pusher.MoveRegister(compiler, move_arg->sp_relative_index() + 1,
|
||||
value.AsPairLocation()->At(1).reg());
|
||||
pusher.MoveRegister(compiler, push_arg->top_of_stack_relative_index(),
|
||||
pusher.MoveRegister(compiler, move_arg->sp_relative_index(),
|
||||
value.AsPairLocation()->At(0).reg());
|
||||
} else if (value.IsFpuRegister()) {
|
||||
pusher.Flush(compiler);
|
||||
__ StoreDToOffset(EvenDRegisterOf(value.fpu_reg()), SP,
|
||||
push_arg->top_of_stack_relative_index() *
|
||||
compiler::target::kWordSize);
|
||||
__ StoreDToOffset(
|
||||
EvenDRegisterOf(value.fpu_reg()), SP,
|
||||
move_arg->sp_relative_index() * compiler::target::kWordSize);
|
||||
} else {
|
||||
const Register reg = pusher.FindFreeRegister(compiler, push_arg);
|
||||
const Register reg = pusher.FindFreeRegister(compiler, move_arg);
|
||||
ASSERT(reg != kNoRegister);
|
||||
if (value.IsConstant()) {
|
||||
__ LoadObject(reg, value.constant());
|
||||
|
@ -497,8 +496,7 @@ void PushArgumentInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
|||
const intptr_t value_offset = value.ToStackSlotOffset();
|
||||
__ LoadFromOffset(reg, value.base_reg(), value_offset);
|
||||
}
|
||||
pusher.MoveRegister(compiler, push_arg->top_of_stack_relative_index(),
|
||||
reg);
|
||||
pusher.MoveRegister(compiler, move_arg->sp_relative_index(), reg);
|
||||
}
|
||||
}
|
||||
pusher.Flush(compiler);
|
||||
|
|
|
@ -336,7 +336,7 @@ void MemoryCopyInstr::EmitComputeStartPointer(FlowGraphCompiler* compiler,
|
|||
}
|
||||
}
|
||||
|
||||
LocationSummary* PushArgumentInstr::MakeLocationSummary(Zone* zone,
|
||||
LocationSummary* MoveArgumentInstr::MakeLocationSummary(Zone* zone,
|
||||
bool opt) const {
|
||||
const intptr_t kNumInputs = 1;
|
||||
const intptr_t kNumTemps = 0;
|
||||
|
@ -356,9 +356,9 @@ LocationSummary* PushArgumentInstr::MakeLocationSummary(Zone* zone,
|
|||
return locs;
|
||||
}
|
||||
|
||||
// Buffers registers in order to use STP to push
|
||||
// Buffers registers in order to use STP to move
|
||||
// two registers at once.
|
||||
class ArgumentsPusher : public ValueObject {
|
||||
class ArgumentsMover : public ValueObject {
|
||||
public:
|
||||
// Flush all buffered registers.
|
||||
void Flush(FlowGraphCompiler* compiler) {
|
||||
|
@ -404,18 +404,18 @@ class ArgumentsPusher : public ValueObject {
|
|||
Register pending_register_ = kNoRegister;
|
||||
};
|
||||
|
||||
void PushArgumentInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
||||
void MoveArgumentInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
||||
ASSERT(compiler->is_optimizing());
|
||||
|
||||
if (previous()->IsPushArgument()) {
|
||||
// Already generated by the first PushArgument in the chain.
|
||||
if (previous()->IsMoveArgument()) {
|
||||
// Already generated by the first MoveArgument in the chain.
|
||||
return;
|
||||
}
|
||||
|
||||
ArgumentsPusher pusher;
|
||||
for (PushArgumentInstr* push_arg = this; push_arg != nullptr;
|
||||
push_arg = push_arg->next()->AsPushArgument()) {
|
||||
const Location value = push_arg->locs()->in(0);
|
||||
ArgumentsMover pusher;
|
||||
for (MoveArgumentInstr* move_arg = this; move_arg != nullptr;
|
||||
move_arg = move_arg->next()->AsMoveArgument()) {
|
||||
const Location value = move_arg->locs()->in(0);
|
||||
Register reg = kNoRegister;
|
||||
if (value.IsRegister()) {
|
||||
reg = value.reg();
|
||||
|
@ -423,7 +423,7 @@ void PushArgumentInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
|||
if (value.constant_instruction()->HasZeroRepresentation()) {
|
||||
reg = ZR;
|
||||
} else {
|
||||
ASSERT(push_arg->representation() == kTagged);
|
||||
ASSERT(move_arg->representation() == kTagged);
|
||||
const Object& constant = value.constant();
|
||||
if (constant.IsNull()) {
|
||||
reg = NULL_REG;
|
||||
|
@ -435,7 +435,7 @@ void PushArgumentInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
|||
} else if (value.IsFpuRegister()) {
|
||||
pusher.Flush(compiler);
|
||||
__ StoreDToOffset(value.fpu_reg(), SP,
|
||||
push_arg->top_of_stack_relative_index() * kWordSize);
|
||||
move_arg->sp_relative_index() * kWordSize);
|
||||
continue;
|
||||
} else {
|
||||
ASSERT(value.IsStackSlot());
|
||||
|
@ -443,7 +443,7 @@ void PushArgumentInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
|||
reg = pusher.GetFreeTempRegister(compiler);
|
||||
__ LoadFromOffset(reg, value.base_reg(), value_offset);
|
||||
}
|
||||
pusher.MoveRegister(compiler, push_arg->top_of_stack_relative_index(), reg);
|
||||
pusher.MoveRegister(compiler, move_arg->sp_relative_index(), reg);
|
||||
}
|
||||
pusher.Flush(compiler);
|
||||
}
|
||||
|
|
|
@ -251,7 +251,7 @@ void MemoryCopyInstr::EmitComputeStartPointer(FlowGraphCompiler* compiler,
|
|||
__ leal(array_reg, compiler::Address(array_reg, start_reg, scale, offset));
|
||||
}
|
||||
|
||||
LocationSummary* PushArgumentInstr::MakeLocationSummary(Zone* zone,
|
||||
LocationSummary* MoveArgumentInstr::MakeLocationSummary(Zone* zone,
|
||||
bool opt) const {
|
||||
const intptr_t kNumInputs = 1;
|
||||
const intptr_t kNumTemps = 0;
|
||||
|
@ -262,11 +262,11 @@ LocationSummary* PushArgumentInstr::MakeLocationSummary(Zone* zone,
|
|||
return locs;
|
||||
}
|
||||
|
||||
void PushArgumentInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
||||
void MoveArgumentInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
||||
ASSERT(compiler->is_optimizing());
|
||||
|
||||
Location value = locs()->in(0);
|
||||
const compiler::Address dst(ESP, top_of_stack_relative_index() * kWordSize);
|
||||
const compiler::Address dst(ESP, sp_relative_index() * kWordSize);
|
||||
if (value.IsConstant()) {
|
||||
__ StoreToOffset(value.constant(), dst);
|
||||
} else {
|
||||
|
|
|
@ -155,7 +155,7 @@ class IlTestPrinter : public AllStatic {
|
|||
}
|
||||
writer->CloseArray();
|
||||
} else if (instr->ArgumentCount() != 0 &&
|
||||
instr->GetPushArguments() != nullptr) {
|
||||
instr->GetMoveArguments() != nullptr) {
|
||||
writer->OpenArray("i");
|
||||
for (intptr_t i = 0; i < instr->ArgumentCount(); i++) {
|
||||
writer->PrintValue(
|
||||
|
@ -1431,9 +1431,9 @@ void SuspendInstr::PrintOperandsTo(BaseTextBuffer* f) const {
|
|||
f->AddString(")");
|
||||
}
|
||||
|
||||
void PushArgumentInstr::PrintOperandsTo(BaseTextBuffer* f) const {
|
||||
void MoveArgumentInstr::PrintOperandsTo(BaseTextBuffer* f) const {
|
||||
value()->PrintTo(f);
|
||||
f->Printf(", SP+%" Pd "", top_of_stack_relative_index());
|
||||
f->Printf(", SP+%" Pd "", sp_relative_index());
|
||||
}
|
||||
|
||||
void GotoInstr::PrintTo(BaseTextBuffer* f) const {
|
||||
|
@ -1487,7 +1487,7 @@ void Environment::PrintTo(BaseTextBuffer* f) const {
|
|||
int arg_count = 0;
|
||||
for (intptr_t i = 0; i < values_.length(); ++i) {
|
||||
if (i > 0) f->AddString(", ");
|
||||
if (values_[i]->definition()->IsPushArgument()) {
|
||||
if (values_[i]->definition()->IsMoveArgument()) {
|
||||
f->Printf("a%d", arg_count++);
|
||||
} else {
|
||||
values_[i]->PrintTo(f);
|
||||
|
|
|
@ -376,7 +376,7 @@ void MemoryCopyInstr::EmitComputeStartPointer(FlowGraphCompiler* compiler,
|
|||
}
|
||||
}
|
||||
|
||||
LocationSummary* PushArgumentInstr::MakeLocationSummary(Zone* zone,
|
||||
LocationSummary* MoveArgumentInstr::MakeLocationSummary(Zone* zone,
|
||||
bool opt) const {
|
||||
const intptr_t kNumInputs = 1;
|
||||
const intptr_t kNumTemps = 0;
|
||||
|
@ -401,12 +401,11 @@ LocationSummary* PushArgumentInstr::MakeLocationSummary(Zone* zone,
|
|||
return locs;
|
||||
}
|
||||
|
||||
void PushArgumentInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
||||
void MoveArgumentInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
||||
ASSERT(compiler->is_optimizing());
|
||||
|
||||
const Location value = locs()->in(0);
|
||||
const intptr_t offset =
|
||||
top_of_stack_relative_index() * compiler::target::kWordSize;
|
||||
const intptr_t offset = sp_relative_index() * compiler::target::kWordSize;
|
||||
if (value.IsRegister()) {
|
||||
__ StoreToOffset(value.reg(), SP, offset);
|
||||
#if XLEN == 32
|
||||
|
|
|
@ -556,12 +556,12 @@ void FlowGraphSerializer::WriteRefTrait<Definition*>::WriteRef(
|
|||
FlowGraphSerializer* s,
|
||||
Definition* x) {
|
||||
if (!x->HasSSATemp()) {
|
||||
if (auto* push_arg = x->AsPushArgument()) {
|
||||
// Environments of the calls can reference PushArgument instructions
|
||||
if (auto* move_arg = x->AsMoveArgument()) {
|
||||
// Environments of the calls can reference MoveArgument instructions
|
||||
// and they don't have SSA temps.
|
||||
// Write a reference to the original definition.
|
||||
// When reading it is restored using RepairPushArgsInEnvironment.
|
||||
x = push_arg->value()->definition();
|
||||
// When reading it is restored using RepairArgumentUsesInEnvironment.
|
||||
x = move_arg->value()->definition();
|
||||
} else {
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
@ -2338,21 +2338,21 @@ void SpecialParameterInstr::ReadExtra(FlowGraphDeserializer* d) {
|
|||
template <intptr_t kExtraInputs>
|
||||
void TemplateDartCall<kExtraInputs>::WriteExtra(FlowGraphSerializer* s) {
|
||||
VariadicDefinition::WriteExtra(s);
|
||||
if (push_arguments_ == nullptr) {
|
||||
if (move_arguments_ == nullptr) {
|
||||
s->Write<intptr_t>(-1);
|
||||
} else {
|
||||
s->Write<intptr_t>(push_arguments_->length());
|
||||
s->Write<intptr_t>(move_arguments_->length());
|
||||
#if defined(DEBUG)
|
||||
// Verify that PushArgument instructions are inserted immediately
|
||||
// Verify that MoveArgument instructions are inserted immediately
|
||||
// before this instruction. ReadExtra below relies on
|
||||
// that when restoring push_arguments_.
|
||||
// that when restoring move_arguments_.
|
||||
Instruction* instr = this;
|
||||
for (intptr_t i = push_arguments_->length() - 1; i >= 0; --i) {
|
||||
for (intptr_t i = move_arguments_->length() - 1; i >= 0; --i) {
|
||||
do {
|
||||
instr = instr->previous();
|
||||
ASSERT(instr != nullptr);
|
||||
} while (!instr->IsPushArgument());
|
||||
ASSERT(instr == (*push_arguments_)[i]);
|
||||
} while (!instr->IsMoveArgument());
|
||||
ASSERT(instr == (*move_arguments_)[i]);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
@ -2361,21 +2361,21 @@ void TemplateDartCall<kExtraInputs>::WriteExtra(FlowGraphSerializer* s) {
|
|||
template <intptr_t kExtraInputs>
|
||||
void TemplateDartCall<kExtraInputs>::ReadExtra(FlowGraphDeserializer* d) {
|
||||
VariadicDefinition::ReadExtra(d);
|
||||
const intptr_t num_push_args = d->Read<intptr_t>();
|
||||
if (num_push_args >= 0) {
|
||||
push_arguments_ =
|
||||
new (d->zone()) PushArgumentsArray(d->zone(), num_push_args);
|
||||
push_arguments_->EnsureLength(num_push_args, nullptr);
|
||||
const intptr_t num_move_args = d->Read<intptr_t>();
|
||||
if (num_move_args >= 0) {
|
||||
move_arguments_ =
|
||||
new (d->zone()) MoveArgumentsArray(d->zone(), num_move_args);
|
||||
move_arguments_->EnsureLength(num_move_args, nullptr);
|
||||
Instruction* instr = this;
|
||||
for (int i = num_push_args - 1; i >= 0; --i) {
|
||||
for (int i = num_move_args - 1; i >= 0; --i) {
|
||||
do {
|
||||
instr = instr->previous();
|
||||
ASSERT(instr != nullptr);
|
||||
} while (!instr->IsPushArgument());
|
||||
(*push_arguments_)[i] = instr->AsPushArgument();
|
||||
} while (!instr->IsMoveArgument());
|
||||
(*move_arguments_)[i] = instr->AsMoveArgument();
|
||||
}
|
||||
if (env() != nullptr) {
|
||||
RepairPushArgsInEnvironment();
|
||||
RepairArgumentUsesInEnvironment();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -336,7 +336,7 @@ void MemoryCopyInstr::EmitComputeStartPointer(FlowGraphCompiler* compiler,
|
|||
__ leaq(array_reg, compiler::Address(array_reg, start_reg, scale, offset));
|
||||
}
|
||||
|
||||
LocationSummary* PushArgumentInstr::MakeLocationSummary(Zone* zone,
|
||||
LocationSummary* MoveArgumentInstr::MakeLocationSummary(Zone* zone,
|
||||
bool opt) const {
|
||||
const intptr_t kNumInputs = 1;
|
||||
const intptr_t kNumTemps = 0;
|
||||
|
@ -352,11 +352,11 @@ LocationSummary* PushArgumentInstr::MakeLocationSummary(Zone* zone,
|
|||
return locs;
|
||||
}
|
||||
|
||||
void PushArgumentInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
||||
void MoveArgumentInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
||||
ASSERT(compiler->is_optimizing());
|
||||
|
||||
const Location value = locs()->in(0);
|
||||
const compiler::Address dst(RSP, top_of_stack_relative_index() * kWordSize);
|
||||
const compiler::Address dst(RSP, sp_relative_index() * kWordSize);
|
||||
if (value.IsRegister()) {
|
||||
__ movq(dst, value.reg());
|
||||
} else if (value.IsConstant()) {
|
||||
|
|
|
@ -197,14 +197,15 @@ class GraphInfoCollector : public ValueObject {
|
|||
continue;
|
||||
}
|
||||
++instruction_count_;
|
||||
// Count inputs of certain instructions as if separate PushArgument
|
||||
// Count inputs of certain instructions as if separate MoveArgument
|
||||
// instructions are used for inputs. This is done in order to
|
||||
// preserve inlining behavior and avoid code size growth after
|
||||
// PushArgument instructions are eliminated.
|
||||
// MoveArgument insertion was moved to the end of the
|
||||
// compilation pipeline.
|
||||
if (current->IsAllocateObject()) {
|
||||
instruction_count_ += current->InputCount();
|
||||
} else if (current->ArgumentCount() > 0) {
|
||||
ASSERT(!current->HasPushArguments());
|
||||
ASSERT(!current->HasMoveArguments());
|
||||
instruction_count_ += current->ArgumentCount();
|
||||
}
|
||||
if (current->IsInstanceCall() || current->IsStaticCall() ||
|
||||
|
@ -465,7 +466,7 @@ class CallSites : public ValueObject {
|
|||
}
|
||||
// For instructions with arguments we don't expect push arguments to
|
||||
// be inserted yet.
|
||||
ASSERT(defn->ArgumentCount() == 0 || !defn->HasPushArguments());
|
||||
ASSERT(defn->ArgumentCount() == 0 || !defn->HasMoveArguments());
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -1730,7 +1731,7 @@ class CallSiteInliner : public ValueObject {
|
|||
ReplaceParameterStubs(zone(), caller_graph_, call_data, NULL);
|
||||
exit_collector->ReplaceCall(callee_function_entry);
|
||||
|
||||
ASSERT(!call_data->call->HasPushArguments());
|
||||
ASSERT(!call_data->call->HasMoveArguments());
|
||||
}
|
||||
|
||||
static intptr_t CountConstants(const GrowableArray<Value*>& arguments) {
|
||||
|
@ -2411,7 +2412,7 @@ TargetEntryInstr* PolymorphicInliner::BuildDecisionGraph() {
|
|||
}
|
||||
}
|
||||
|
||||
ASSERT(!call_->HasPushArguments());
|
||||
ASSERT(!call_->HasMoveArguments());
|
||||
|
||||
// Handle any non-inlined variants.
|
||||
if (!non_inlined_variants_->is_empty()) {
|
||||
|
@ -3628,7 +3629,7 @@ bool FlowGraphInliner::TryReplaceInstanceCallWithInline(
|
|||
flow_graph->AddExactnessGuard(call, receiver_cid);
|
||||
}
|
||||
|
||||
ASSERT(!call->HasPushArguments());
|
||||
ASSERT(!call->HasMoveArguments());
|
||||
|
||||
// Replace all uses of this definition with the result.
|
||||
if (call->HasUses()) {
|
||||
|
@ -3678,7 +3679,7 @@ bool FlowGraphInliner::TryReplaceStaticCallWithInline(
|
|||
ASSERT((last != nullptr && result != nullptr) ||
|
||||
(call->function().recognized_kind() ==
|
||||
MethodRecognizer::kObjectConstructor));
|
||||
ASSERT(!call->HasPushArguments());
|
||||
ASSERT(!call->HasMoveArguments());
|
||||
// Replace all uses of this definition with the result.
|
||||
if (call->HasUses()) {
|
||||
ASSERT(result->HasSSATemp());
|
||||
|
|
|
@ -214,7 +214,7 @@ void SSALivenessAnalysis::ComputeInitialSets() {
|
|||
// MaterializeObject instruction is not in the graph.
|
||||
// Treat its inputs as part of the environment.
|
||||
DeepLiveness(defn->AsMaterializeObject(), live_in);
|
||||
} else if (!defn->IsPushArgument() && !defn->IsConstant()) {
|
||||
} else if (!defn->IsMoveArgument() && !defn->IsConstant()) {
|
||||
live_in->Add(defn->vreg(0));
|
||||
if (defn->HasPairRepresentation()) {
|
||||
live_in->Add(defn->vreg(1));
|
||||
|
@ -1058,7 +1058,7 @@ void FlowGraphAllocator::ProcessEnvironmentUses(BlockEntryInstr* block,
|
|||
continue;
|
||||
}
|
||||
|
||||
if (def->IsPushArgument()) {
|
||||
if (def->IsMoveArgument()) {
|
||||
// Frame size is unknown until after allocation.
|
||||
locations[i] = Location::NoLocation();
|
||||
continue;
|
||||
|
@ -3293,19 +3293,19 @@ void FlowGraphAllocator::AllocateOutgoingArguments() {
|
|||
|
||||
for (auto block : flow_graph_.reverse_postorder()) {
|
||||
for (auto instr : block->instructions()) {
|
||||
if (auto push = instr->AsPushArgument()) {
|
||||
if (auto move_arg = instr->AsMoveArgument()) {
|
||||
Location loc;
|
||||
|
||||
const intptr_t spill_index =
|
||||
(total_spill_slot_count - 1) - push->top_of_stack_relative_index();
|
||||
(total_spill_slot_count - 1) - move_arg->sp_relative_index();
|
||||
const intptr_t slot_index =
|
||||
compiler::target::frame_layout.FrameSlotForVariableIndex(
|
||||
-spill_index);
|
||||
|
||||
push->locs()->set_out(0,
|
||||
(push->representation() == kUnboxedDouble)
|
||||
? Location::DoubleStackSlot(slot_index, FPREG)
|
||||
: Location::StackSlot(slot_index, FPREG));
|
||||
move_arg->locs()->set_out(
|
||||
0, (move_arg->representation() == kUnboxedDouble)
|
||||
? Location::DoubleStackSlot(slot_index, FPREG)
|
||||
: Location::StackSlot(slot_index, FPREG));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4425,7 +4425,7 @@ void DeadCodeElimination::EliminateDeadCode(FlowGraph* flow_graph) {
|
|||
BlockEntryInstr* block = block_it.Current();
|
||||
for (ForwardInstructionIterator it(block); !it.Done(); it.Advance()) {
|
||||
Instruction* current = it.Current();
|
||||
ASSERT(!current->IsPushArgument());
|
||||
ASSERT(!current->IsMoveArgument());
|
||||
// TODO(alexmarkov): take control dependencies into account and
|
||||
// eliminate dead branches/conditions.
|
||||
if (!CanEliminateInstruction(current, block)) {
|
||||
|
@ -4462,7 +4462,7 @@ void DeadCodeElimination::EliminateDeadCode(FlowGraph* flow_graph) {
|
|||
for (Environment::DeepIterator it(current->env()); !it.Done();
|
||||
it.Advance()) {
|
||||
Definition* input = it.CurrentValue()->definition();
|
||||
ASSERT(!input->IsPushArgument());
|
||||
ASSERT(!input->IsMoveArgument());
|
||||
if (input->HasSSATemp() && !live.Contains(input->ssa_temp_index())) {
|
||||
worklist.Add(input);
|
||||
live.Add(input->ssa_temp_index());
|
||||
|
@ -4488,8 +4488,8 @@ void DeadCodeElimination::EliminateDeadCode(FlowGraph* flow_graph) {
|
|||
if (!CanEliminateInstruction(current, block)) {
|
||||
continue;
|
||||
}
|
||||
ASSERT(!current->IsPushArgument());
|
||||
ASSERT((current->ArgumentCount() == 0) || !current->HasPushArguments());
|
||||
ASSERT(!current->IsMoveArgument());
|
||||
ASSERT((current->ArgumentCount() == 0) || !current->HasMoveArguments());
|
||||
if (Definition* def = current->AsDefinition()) {
|
||||
if (def->HasSSATemp() && live.Contains(def->ssa_temp_index())) {
|
||||
continue;
|
||||
|
|
|
@ -249,9 +249,9 @@ static void TestAliasingViaRedefinition(
|
|||
// v0 <- AllocateObject(class K)
|
||||
// v1 <- LoadField(v0, K.field)
|
||||
// v2 <- make_redefinition(v0)
|
||||
// PushArgument(v1)
|
||||
// MoveArgument(v1)
|
||||
// #if make_it_escape
|
||||
// PushArgument(v2)
|
||||
// MoveArgument(v2)
|
||||
// #endif
|
||||
// v3 <- StaticCall(blackhole, v1, v2)
|
||||
// v4 <- LoadField(v2, K.field)
|
||||
|
@ -418,13 +418,13 @@ static void TestAliasingViaStore(
|
|||
// #endif
|
||||
// v1 <- LoadField(v0, K.field)
|
||||
// v2 <- REDEFINITION(v5)
|
||||
// PushArgument(v1)
|
||||
// MoveArgument(v1)
|
||||
// #if make_it_escape
|
||||
// v6 <- LoadField(v2, K.field)
|
||||
// PushArgument(v6)
|
||||
// MoveArgument(v6)
|
||||
// #elif make_host_escape
|
||||
// StoreField(v2 . K.field = v0)
|
||||
// PushArgument(v5)
|
||||
// MoveArgument(v5)
|
||||
// #endif
|
||||
// v3 <- StaticCall(blackhole, v1, v6)
|
||||
// v4 <- LoadField(v0, K.field)
|
||||
|
@ -1213,7 +1213,7 @@ main() {
|
|||
48: v335 <- Box(v15) T{_Double}
|
||||
49: ParallelMove rdx <- rcx, rax <- rax
|
||||
50: StoreIndexed(v17, v39, v335)
|
||||
52: PushArgument(v17)
|
||||
52: MoveArgument(v17)
|
||||
54: v40 <- StaticCall:44( _interpolate@0150898<0> v17,
|
||||
recognized_kind = StringBaseInterpolate) T{String?}
|
||||
56: Return:48(v40)
|
||||
|
@ -1256,7 +1256,7 @@ main() {
|
|||
kMatchAndMoveStoreIndexed,
|
||||
kMatchAndMoveBox,
|
||||
kMatchAndMoveStoreIndexed,
|
||||
kMatchAndMovePushArgument,
|
||||
kMatchAndMoveMoveArgument,
|
||||
{kMatchAndMoveStaticCall, &string_interpolate},
|
||||
kMatchReturn,
|
||||
}));
|
||||
|
@ -1329,7 +1329,7 @@ main() {
|
|||
28: StoreIndexed(v11, v28, v29, NoStoreBarrier)
|
||||
29: ParallelMove rcx <- S-3
|
||||
30: StoreIndexed(v11, v30, v9, NoStoreBarrier)
|
||||
32: PushArgument(v11)
|
||||
32: MoveArgument(v11)
|
||||
34: v31 <- StaticCall:20( _interpolate@0150898<0> v11, recognized_kind = StringBaseInterpolate) T{String}
|
||||
35: ParallelMove rax <- rax
|
||||
36: Return:24(v31)
|
||||
|
@ -1353,7 +1353,7 @@ main() {
|
|||
kMatchAndMoveStoreIndexed,
|
||||
kMatchAndMoveStoreIndexed,
|
||||
kMatchAndMoveStoreIndexed,
|
||||
kMatchAndMovePushArgument,
|
||||
kMatchAndMoveMoveArgument,
|
||||
kMatchAndMoveStaticCall,
|
||||
kMatchReturn,
|
||||
}));
|
||||
|
|
|
@ -1288,7 +1288,7 @@ CompileType ParameterInstr::ComputeType() const {
|
|||
return CompileType::Dynamic();
|
||||
}
|
||||
|
||||
CompileType PushArgumentInstr::ComputeType() const {
|
||||
CompileType MoveArgumentInstr::ComputeType() const {
|
||||
return CompileType::Dynamic();
|
||||
}
|
||||
|
||||
|
|
|
@ -564,12 +564,12 @@ ISOLATE_UNIT_TEST_CASE(TypePropagator_NonNullableLoadStaticField) {
|
|||
RELEASE_ASSERT(cursor.TryMatch({
|
||||
kMoveGlob,
|
||||
{kMatchAndMoveLoadStaticField, &load},
|
||||
kMatchAndMovePushArgument,
|
||||
kMatchAndMoveMoveArgument,
|
||||
kMatchAndMoveStaticCall,
|
||||
kMatchAndMoveUnboxInt64,
|
||||
kMatchAndMoveBinaryInt64Op,
|
||||
kMatchAndMoveBoxInt64,
|
||||
kMatchAndMovePushArgument,
|
||||
kMatchAndMoveMoveArgument,
|
||||
kMatchAndMoveStaticCall,
|
||||
kMatchReturn,
|
||||
}));
|
||||
|
@ -736,10 +736,10 @@ ISOLATE_UNIT_TEST_CASE(TypePropagator_RecordFieldAccess) {
|
|||
{kMatchAndMoveLoadField, &load1},
|
||||
kMatchAndMoveCheckSmi,
|
||||
kMatchAndMoveBinarySmiOp,
|
||||
kMatchAndMovePushArgument,
|
||||
kMatchAndMoveMoveArgument,
|
||||
kMatchAndMoveStaticCall,
|
||||
{kMatchAndMoveLoadField, &load2},
|
||||
kMatchAndMovePushArgument,
|
||||
kMatchAndMoveMoveArgument,
|
||||
kMatchAndMoveStaticCall,
|
||||
kMatchReturn,
|
||||
}));
|
||||
|
|
|
@ -207,7 +207,7 @@ void CallSpecializer::SpecializePolymorphicInstanceCall(
|
|||
void CallSpecializer::ReplaceCallWithResult(Definition* call,
|
||||
Instruction* replacement,
|
||||
Definition* result) {
|
||||
ASSERT(!call->HasPushArguments());
|
||||
ASSERT(!call->HasMoveArguments());
|
||||
if (result == nullptr) {
|
||||
ASSERT(replacement->IsDefinition());
|
||||
call->ReplaceWith(replacement->AsDefinition(), current_iterator());
|
||||
|
@ -1268,7 +1268,7 @@ void CallSpecializer::ReplaceWithInstanceOf(InstanceCallInstr* call) {
|
|||
// One result only.
|
||||
AddReceiverCheck(call);
|
||||
ConstantInstr* bool_const = flow_graph()->GetConstant(as_bool);
|
||||
ASSERT(!call->HasPushArguments());
|
||||
ASSERT(!call->HasMoveArguments());
|
||||
call->ReplaceUsesWith(bool_const);
|
||||
ASSERT(current_iterator()->Current() == call);
|
||||
current_iterator()->RemoveCurrentFromGraph();
|
||||
|
|
|
@ -546,7 +546,7 @@ COMPILER_PASS(AllocationSinking_DetachMaterializations, {
|
|||
});
|
||||
|
||||
COMPILER_PASS(AllocateRegisters, {
|
||||
flow_graph->InsertPushArguments();
|
||||
flow_graph->InsertMoveArguments();
|
||||
// Ensure loop hierarchy has been computed.
|
||||
flow_graph->GetLoopHierarchy();
|
||||
// Perform register allocation on the SSA graph.
|
||||
|
|
|
@ -1087,8 +1087,7 @@ Fragment BaseFlowGraphBuilder::DebugStepCheck(TokenPosition position) {
|
|||
|
||||
Fragment BaseFlowGraphBuilder::CheckNull(TokenPosition position,
|
||||
LocalVariable* receiver,
|
||||
const String& function_name,
|
||||
bool clear_the_temp /* = true */) {
|
||||
const String& function_name) {
|
||||
Fragment instructions = LoadLocal(receiver);
|
||||
|
||||
CheckNullInstr* check_null = new (Z) CheckNullInstr(
|
||||
|
@ -1099,14 +1098,6 @@ Fragment BaseFlowGraphBuilder::CheckNull(TokenPosition position,
|
|||
// Does not use the redefinition, no `Push(check_null)`.
|
||||
instructions <<= check_null;
|
||||
|
||||
if (clear_the_temp) {
|
||||
// Null out receiver to make sure it is not saved into the frame before
|
||||
// doing the call.
|
||||
instructions += NullConstant();
|
||||
instructions += StoreLocal(TokenPosition::kNoSource, receiver);
|
||||
instructions += Drop();
|
||||
}
|
||||
|
||||
return instructions;
|
||||
}
|
||||
|
||||
|
|
|
@ -385,13 +385,11 @@ class BaseFlowGraphBuilder {
|
|||
// Loads 'receiver' and checks it for null. Throws NoSuchMethod if it is null.
|
||||
// 'function_name' is a selector which is being called (reported in
|
||||
// NoSuchMethod message).
|
||||
// Sets 'receiver' to 'null' after the check if 'clear_the_temp'.
|
||||
// Note that this does _not_ use the result of the CheckNullInstr, so it does
|
||||
// not create a data dependency and might break with code motion.
|
||||
Fragment CheckNull(TokenPosition position,
|
||||
LocalVariable* receiver,
|
||||
const String& function_name,
|
||||
bool clear_the_temp = true);
|
||||
const String& function_name);
|
||||
|
||||
// Pops the top of the stack, checks it for null, and pushes the result on
|
||||
// the stack to create a data dependency.
|
||||
|
@ -423,7 +421,7 @@ class BaseFlowGraphBuilder {
|
|||
// Builds closure call with given number of arguments. Target closure
|
||||
// (in bare instructions mode) or closure function (otherwise) is taken from
|
||||
// top of the stack.
|
||||
// PushArgument instructions should be already added for arguments.
|
||||
// MoveArgument instructions should be already added for arguments.
|
||||
Fragment ClosureCall(TokenPosition position,
|
||||
intptr_t type_args_len,
|
||||
intptr_t argument_count,
|
||||
|
|
|
@ -1522,13 +1522,10 @@ Fragment StreamingFlowGraphBuilder::RedefinitionWithType(
|
|||
return flow_graph_builder_->RedefinitionWithType(type);
|
||||
}
|
||||
|
||||
Fragment StreamingFlowGraphBuilder::CheckNull(
|
||||
TokenPosition position,
|
||||
LocalVariable* receiver,
|
||||
const String& function_name,
|
||||
bool clear_the_temp /* = true */) {
|
||||
return flow_graph_builder_->CheckNull(position, receiver, function_name,
|
||||
clear_the_temp);
|
||||
Fragment StreamingFlowGraphBuilder::CheckNull(TokenPosition position,
|
||||
LocalVariable* receiver,
|
||||
const String& function_name) {
|
||||
return flow_graph_builder_->CheckNull(position, receiver, function_name);
|
||||
}
|
||||
|
||||
Fragment StreamingFlowGraphBuilder::StaticCall(TokenPosition position,
|
||||
|
@ -2171,14 +2168,6 @@ Fragment StreamingFlowGraphBuilder::BuildInstanceGet(TokenPosition* p) {
|
|||
inferred_type_metadata_helper_.GetInferredType(offset);
|
||||
|
||||
Fragment instructions = BuildExpression(); // read receiver.
|
||||
|
||||
LocalVariable* receiver = nullptr;
|
||||
if (direct_call.check_receiver_for_null_) {
|
||||
// Duplicate receiver for CheckNull before it is consumed by PushArgument.
|
||||
receiver = MakeTemporary();
|
||||
instructions += LoadLocal(receiver);
|
||||
}
|
||||
|
||||
const String& getter_name = ReadNameAsGetterName(); // read name.
|
||||
SkipDartType(); // read result_type.
|
||||
const NameIndex itarget_name =
|
||||
|
@ -2189,6 +2178,7 @@ Fragment StreamingFlowGraphBuilder::BuildInstanceGet(TokenPosition* p) {
|
|||
ASSERT(getter_name.ptr() == interface_target.name());
|
||||
|
||||
if (direct_call.check_receiver_for_null_) {
|
||||
auto receiver = MakeTemporary();
|
||||
instructions += CheckNull(position, receiver, getter_name);
|
||||
}
|
||||
|
||||
|
@ -2206,10 +2196,6 @@ Fragment StreamingFlowGraphBuilder::BuildInstanceGet(TokenPosition* p) {
|
|||
Function::null_function(), &result_type);
|
||||
}
|
||||
|
||||
if (direct_call.check_receiver_for_null_) {
|
||||
instructions += DropTempsPreserveTop(1); // Drop receiver, preserve result.
|
||||
}
|
||||
|
||||
return instructions;
|
||||
}
|
||||
|
||||
|
@ -2225,20 +2211,7 @@ Fragment StreamingFlowGraphBuilder::BuildDynamicGet(TokenPosition* p) {
|
|||
inferred_type_metadata_helper_.GetInferredType(offset);
|
||||
|
||||
Fragment instructions = BuildExpression(); // read receiver.
|
||||
|
||||
LocalVariable* receiver = nullptr;
|
||||
if (direct_call.check_receiver_for_null_) {
|
||||
// Duplicate receiver for CheckNull before it is consumed by PushArgument.
|
||||
receiver = MakeTemporary();
|
||||
instructions += LoadLocal(receiver);
|
||||
}
|
||||
|
||||
const String& getter_name = ReadNameAsGetterName(); // read name.
|
||||
|
||||
if (direct_call.check_receiver_for_null_) {
|
||||
instructions += CheckNull(position, receiver, getter_name);
|
||||
}
|
||||
|
||||
const auto& mangled_name = String::ZoneHandle(
|
||||
Z, Function::CreateDynamicInvocationForwarderName(getter_name));
|
||||
const Function* direct_call_target = &direct_call.target_;
|
||||
|
@ -2247,6 +2220,11 @@ Fragment StreamingFlowGraphBuilder::BuildDynamicGet(TokenPosition* p) {
|
|||
direct_call.target_.GetDynamicInvocationForwarder(mangled_name));
|
||||
}
|
||||
|
||||
if (direct_call.check_receiver_for_null_) {
|
||||
auto receiver = MakeTemporary();
|
||||
instructions += CheckNull(position, receiver, getter_name);
|
||||
}
|
||||
|
||||
if (!direct_call_target->IsNull()) {
|
||||
ASSERT(CompilerState::Current().is_aot());
|
||||
instructions +=
|
||||
|
@ -2261,10 +2239,6 @@ Fragment StreamingFlowGraphBuilder::BuildDynamicGet(TokenPosition* p) {
|
|||
Function::null_function(), &result_type);
|
||||
}
|
||||
|
||||
if (direct_call.check_receiver_for_null_) {
|
||||
instructions += DropTempsPreserveTop(1); // Drop receiver, preserve result.
|
||||
}
|
||||
|
||||
return instructions;
|
||||
}
|
||||
|
||||
|
@ -2280,14 +2254,6 @@ Fragment StreamingFlowGraphBuilder::BuildInstanceTearOff(TokenPosition* p) {
|
|||
inferred_type_metadata_helper_.GetInferredType(offset);
|
||||
|
||||
Fragment instructions = BuildExpression(); // read receiver.
|
||||
|
||||
LocalVariable* receiver = nullptr;
|
||||
if (direct_call.check_receiver_for_null_) {
|
||||
// Duplicate receiver for CheckNull before it is consumed by PushArgument.
|
||||
receiver = MakeTemporary();
|
||||
instructions += LoadLocal(receiver);
|
||||
}
|
||||
|
||||
const String& getter_name = ReadNameAsGetterName(); // read name.
|
||||
SkipDartType(); // read result_type.
|
||||
const NameIndex itarget_name =
|
||||
|
@ -2297,6 +2263,7 @@ Fragment StreamingFlowGraphBuilder::BuildInstanceTearOff(TokenPosition* p) {
|
|||
Z, H.LookupMethodByMember(itarget_name, H.DartMethodName(itarget_name)));
|
||||
|
||||
if (direct_call.check_receiver_for_null_) {
|
||||
const auto receiver = MakeTemporary();
|
||||
instructions += CheckNull(position, receiver, getter_name);
|
||||
}
|
||||
|
||||
|
@ -2314,10 +2281,6 @@ Fragment StreamingFlowGraphBuilder::BuildInstanceTearOff(TokenPosition* p) {
|
|||
tearoff_interface_target, &result_type);
|
||||
}
|
||||
|
||||
if (direct_call.check_receiver_for_null_) {
|
||||
instructions += DropTempsPreserveTop(1); // Drop receiver, preserve result.
|
||||
}
|
||||
|
||||
return instructions;
|
||||
}
|
||||
|
||||
|
@ -2333,14 +2296,8 @@ Fragment StreamingFlowGraphBuilder::BuildFunctionTearOff(TokenPosition* p) {
|
|||
|
||||
Fragment instructions = BuildExpression(); // read receiver.
|
||||
|
||||
LocalVariable* receiver = nullptr;
|
||||
if (direct_call.check_receiver_for_null_) {
|
||||
// Duplicate receiver for CheckNull before it is consumed by PushArgument.
|
||||
receiver = MakeTemporary();
|
||||
instructions += LoadLocal(receiver);
|
||||
}
|
||||
|
||||
if (direct_call.check_receiver_for_null_) {
|
||||
const auto receiver = MakeTemporary();
|
||||
instructions += CheckNull(position, receiver, Symbols::GetCall());
|
||||
}
|
||||
|
||||
|
@ -2358,10 +2315,6 @@ Fragment StreamingFlowGraphBuilder::BuildFunctionTearOff(TokenPosition* p) {
|
|||
Function::null_function(), &result_type);
|
||||
}
|
||||
|
||||
if (direct_call.check_receiver_for_null_) {
|
||||
instructions += DropTempsPreserveTop(1); // Drop receiver, preserve result.
|
||||
}
|
||||
|
||||
return instructions;
|
||||
}
|
||||
|
||||
|
@ -2399,9 +2352,7 @@ Fragment StreamingFlowGraphBuilder::BuildInstanceSet(TokenPosition* p) {
|
|||
|
||||
LocalVariable* receiver = nullptr;
|
||||
if (direct_call.check_receiver_for_null_) {
|
||||
// Duplicate receiver for CheckNull before it is consumed by PushArgument.
|
||||
receiver = MakeTemporary();
|
||||
instructions += LoadLocal(receiver);
|
||||
}
|
||||
|
||||
const String& setter_name = ReadNameAsSetterName(); // read name.
|
||||
|
@ -2442,10 +2393,6 @@ Fragment StreamingFlowGraphBuilder::BuildInstanceSet(TokenPosition* p) {
|
|||
|
||||
instructions += Drop(); // Drop result of the setter invocation.
|
||||
|
||||
if (direct_call.check_receiver_for_null_) {
|
||||
instructions += Drop(); // Drop receiver.
|
||||
}
|
||||
|
||||
return instructions;
|
||||
}
|
||||
|
||||
|
@ -2471,9 +2418,7 @@ Fragment StreamingFlowGraphBuilder::BuildDynamicSet(TokenPosition* p) {
|
|||
|
||||
LocalVariable* receiver = nullptr;
|
||||
if (direct_call.check_receiver_for_null_) {
|
||||
// Duplicate receiver for CheckNull before it is consumed by PushArgument.
|
||||
receiver = MakeTemporary();
|
||||
instructions += LoadLocal(receiver);
|
||||
}
|
||||
|
||||
const String& setter_name = ReadNameAsSetterName(); // read name.
|
||||
|
@ -2514,10 +2459,6 @@ Fragment StreamingFlowGraphBuilder::BuildDynamicSet(TokenPosition* p) {
|
|||
|
||||
instructions += Drop(); // Drop result of the setter invocation.
|
||||
|
||||
if (direct_call.check_receiver_for_null_) {
|
||||
instructions += Drop(); // Drop receiver.
|
||||
}
|
||||
|
||||
return instructions;
|
||||
}
|
||||
|
||||
|
@ -2929,17 +2870,7 @@ Fragment StreamingFlowGraphBuilder::BuildMethodInvocation(TokenPosition* p,
|
|||
|
||||
LocalVariable* receiver_temp = nullptr;
|
||||
if (direct_call.check_receiver_for_null_) {
|
||||
// Duplicate receiver for CheckNull before it is consumed by PushArgument.
|
||||
receiver_temp = MakeTemporary();
|
||||
if (type_arguments_temp != nullptr) {
|
||||
// If call has type arguments then push them before pushing the receiver.
|
||||
// The stack will contain:
|
||||
//
|
||||
// [type_arguments_temp][receiver_temp][type_arguments][receiver] ...
|
||||
//
|
||||
instructions += LoadLocal(type_arguments_temp);
|
||||
}
|
||||
instructions += LoadLocal(receiver_temp);
|
||||
}
|
||||
|
||||
intptr_t argument_count;
|
||||
|
@ -2978,8 +2909,7 @@ Fragment StreamingFlowGraphBuilder::BuildMethodInvocation(TokenPosition* p,
|
|||
}
|
||||
|
||||
if (direct_call.check_receiver_for_null_) {
|
||||
instructions += CheckNull(position, receiver_temp, name,
|
||||
/*clear_temp=*/true);
|
||||
instructions += CheckNull(position, receiver_temp, name);
|
||||
}
|
||||
|
||||
const String* mangled_name = &name;
|
||||
|
@ -3016,14 +2946,6 @@ Fragment StreamingFlowGraphBuilder::BuildMethodInvocation(TokenPosition* p,
|
|||
result_type.ReceiverNotInt(), is_call_on_this);
|
||||
}
|
||||
|
||||
// Drop temporaries preserving result on the top of the stack.
|
||||
ASSERT((receiver_temp != nullptr) || (type_arguments_temp == nullptr));
|
||||
if (receiver_temp != nullptr) {
|
||||
const intptr_t num_temps = (receiver_temp != nullptr ? 1 : 0) +
|
||||
(type_arguments_temp != nullptr ? 1 : 0);
|
||||
instructions += DropTempsPreserveTop(num_temps);
|
||||
}
|
||||
|
||||
// Later optimization passes assume that result of a x.[]=(...) call is not
|
||||
// used. We must guarantee this invariant because violation will lead to an
|
||||
// illegal IL once we replace x.[]=(...) with a sequence that does not
|
||||
|
@ -3137,8 +3059,7 @@ Fragment StreamingFlowGraphBuilder::BuildFunctionInvocation(TokenPosition* p) {
|
|||
SkipDartType(); // read function_type.
|
||||
|
||||
if (is_unchecked_closure_call) {
|
||||
instructions += CheckNull(position, receiver_temp, Symbols::call(),
|
||||
/*clear_temp=*/false);
|
||||
instructions += CheckNull(position, receiver_temp, Symbols::call());
|
||||
// Lookup the function in the closure.
|
||||
instructions += LoadLocal(receiver_temp);
|
||||
if (!FLAG_precompiled_mode) {
|
||||
|
@ -3563,8 +3484,7 @@ Fragment StreamingFlowGraphBuilder::BuildNullCheck(TokenPosition* p) {
|
|||
TokenPosition operand_position = TokenPosition::kNoSource;
|
||||
Fragment instructions = BuildExpression(&operand_position);
|
||||
LocalVariable* expr_temp = MakeTemporary();
|
||||
instructions += CheckNull(position, expr_temp, String::null_string(),
|
||||
/* clear_the_temp = */ false);
|
||||
instructions += CheckNull(position, expr_temp, String::null_string());
|
||||
|
||||
return instructions;
|
||||
}
|
||||
|
|
|
@ -164,8 +164,7 @@ class StreamingFlowGraphBuilder : public KernelReaderHelper {
|
|||
Fragment RedefinitionWithType(const AbstractType& type);
|
||||
Fragment CheckNull(TokenPosition position,
|
||||
LocalVariable* receiver,
|
||||
const String& function_name,
|
||||
bool clear_the_temp = true);
|
||||
const String& function_name);
|
||||
Fragment StaticCall(TokenPosition position,
|
||||
const Function& target,
|
||||
intptr_t argument_count,
|
||||
|
|
|
@ -46,7 +46,7 @@ namespace dart {
|
|||
V(ParallelMove, -3) \
|
||||
V(TempMove, -4) \
|
||||
V(Constant, -5) \
|
||||
V(PushArgument, -6) \
|
||||
V(MoveArgument, -6) \
|
||||
V(ControlFlow, -7) \
|
||||
V(Context, -8) \
|
||||
V(MethodExtractor, -9) \
|
||||
|
|
Loading…
Reference in a new issue