From f4e61eacfd626792e4d45d75f120217b39132fa2 Mon Sep 17 00:00:00 2001 From: Alexander Markov Date: Thu, 9 Jan 2020 01:37:27 +0000 Subject: [PATCH] [vm/compiler] Remove PushArgument instructions from IL up to AllocateRegisters PushArgument instructions are removed from IL while it is constructed and optimized. Before allocating registers, PushArgument instructions are inserted immediately before call instructions. On ARM/ARM64 subsequent PushArgument instructions are generated using store multiple (STM) / store pair (STP) instructions which reduces size. Flutter gallery in release mode after this CL and https://dart-review.googlesource.com/c/sdk/+/129324: arm: instructions size -1.4%, total size -0.83% arm64: instructions size -1.43%, total size -0.83% Closes https://github.com/dart-lang/sdk/issues/39788 Closes https://github.com/dart-lang/sdk/issues/38354 Change-Id: I61493c72306c3ade4d9850e0dfc17e7e943a14c4 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/128481 Commit-Queue: Alexander Markov Reviewed-by: Martin Kustermann --- .../vm/compiler/aot/aot_call_specializer.cc | 88 ++--- .../compiler/backend/constant_propagator.cc | 36 +- runtime/vm/compiler/backend/flow_graph.cc | 113 +++--- runtime/vm/compiler/backend/flow_graph.h | 4 + .../vm/compiler/backend/flow_graph_checker.cc | 39 +- runtime/vm/compiler/backend/il.cc | 18 +- runtime/vm/compiler/backend/il.h | 130 +++++-- runtime/vm/compiler/backend/il_arm.cc | 145 ++++++-- runtime/vm/compiler/backend/il_arm64.cc | 88 +++-- .../vm/compiler/backend/il_deserializer.cc | 146 ++------ runtime/vm/compiler/backend/il_deserializer.h | 30 +- runtime/vm/compiler/backend/il_ia32.cc | 13 +- runtime/vm/compiler/backend/il_printer.cc | 2 +- runtime/vm/compiler/backend/il_serializer.cc | 60 ++- runtime/vm/compiler/backend/il_x64.cc | 13 +- runtime/vm/compiler/backend/inliner.cc | 44 +-- .../backend/redundancy_elimination.cc | 42 +-- .../backend/redundancy_elimination_test.cc | 34 +- .../compiler/backend/type_propagator_test.cc | 2 +- runtime/vm/compiler/call_specializer.cc | 13 +- runtime/vm/compiler/compiler_pass.cc | 1 + .../frontend/base_flow_graph_builder.cc | 40 +- .../frontend/base_flow_graph_builder.h | 7 +- .../frontend/bytecode_flow_graph_builder.cc | 40 +- .../frontend/bytecode_flow_graph_builder.h | 1 - .../frontend/kernel_binary_flowgraph.cc | 126 ++----- .../frontend/kernel_binary_flowgraph.h | 9 +- runtime/vm/compiler/frontend/kernel_to_il.cc | 82 +--- runtime/vm/regexp_assembler_ir.cc | 350 ++++++++---------- runtime/vm/regexp_assembler_ir.h | 45 +-- 30 files changed, 743 insertions(+), 1018 deletions(-) diff --git a/runtime/vm/compiler/aot/aot_call_specializer.cc b/runtime/vm/compiler/aot/aot_call_specializer.cc index 82f82591d45..3e62efe5ba1 100644 --- a/runtime/vm/compiler/aot/aot_call_specializer.cc +++ b/runtime/vm/compiler/aot/aot_call_specializer.cc @@ -195,16 +195,9 @@ bool AotCallSpecializer::TryReplaceWithHaveSameRuntimeType( cls.LookupStaticFunctionAllowPrivate(Symbols::HaveSameRuntimeType())); ASSERT(!have_same_runtime_type.IsNull()); - ZoneGrowableArray* args = - new (Z) ZoneGrowableArray(2); - PushArgumentInstr* arg1 = - new (Z) PushArgumentInstr(new (Z) Value(left->ArgumentAt(0))); - InsertBefore(call, arg1, nullptr, FlowGraph::kEffect); - args->Add(arg1); - PushArgumentInstr* arg2 = - new (Z) PushArgumentInstr(new (Z) Value(right->ArgumentAt(0))); - InsertBefore(call, arg2, nullptr, FlowGraph::kEffect); - args->Add(arg2); + InputsArray* args = new (Z) InputsArray(Z, 2); + args->Add(left->ArgumentValueAt(0)->CopyWithType(Z)); + args->Add(right->ArgumentValueAt(0)->CopyWithType(Z)); const intptr_t kTypeArgsLen = 0; StaticCallInstr* static_call = new (Z) StaticCallInstr( call->token_pos(), have_same_runtime_type, kTypeArgsLen, @@ -212,7 +205,13 @@ bool AotCallSpecializer::TryReplaceWithHaveSameRuntimeType( args, call->deopt_id(), call->CallCount(), ICData::kOptimized); static_call->SetResultType(Z, CompileType::FromCid(kBoolCid)); ReplaceCall(call, static_call); - static_call->RepairPushArgsInEnvironment(); + // ReplaceCall moved environment from 'call' to 'static_call'. + // Update arguments of 'static_call' in the environment. + Environment* env = static_call->env(); + env->ValueAt(env->Length() - 2) + ->BindToEnvironment(static_call->ArgumentAt(0)); + env->ValueAt(env->Length() - 1) + ->BindToEnvironment(static_call->ArgumentAt(1)); return true; } @@ -389,18 +388,17 @@ bool AotCallSpecializer::TryOptimizeStaticCallUsingStaticTypes( cid == kDoubleCid) { // Sometimes TFA de-virtualizes instance calls to static calls. In such // cases the VM might have a looser type on the receiver, so we explicitly - // tighten it (this is safe since it was proven that te receiver is either + // tighten it (this is safe since it was proven that the receiver is either // null or will end up with that target). const intptr_t receiver_index = instr->FirstArgIndex(); const intptr_t argument_count = instr->ArgumentCountWithoutTypeArgs(); if (argument_count >= 1) { - auto push_receiver = instr->PushArgumentAt(receiver_index); - auto receiver_value = push_receiver->value(); + auto receiver_value = instr->ArgumentValueAt(receiver_index); auto receiver = receiver_value->definition(); auto type = BuildStrengthenedReceiverType(receiver_value, cid); if (!type.IsNone()) { - auto redefinition = flow_graph()->EnsureRedefinition( - push_receiver->previous(), receiver, type); + auto redefinition = + flow_graph()->EnsureRedefinition(instr->previous(), receiver, type); if (redefinition != nullptr) { RefineUseTypes(redefinition); } @@ -1116,9 +1114,8 @@ bool AotCallSpecializer::TryExpandCallThroughGetter(const Class& receiver_class, const intptr_t receiver_idx = call->type_args_len() > 0 ? 1 : 0; - PushArgumentsArray* get_arguments = new (Z) PushArgumentsArray(1); - get_arguments->Add(new (Z) PushArgumentInstr( - call->ArgumentValueAt(receiver_idx)->CopyWithType(Z))); + InputsArray* get_arguments = new (Z) InputsArray(Z, 1); + get_arguments->Add(call->ArgumentValueAt(receiver_idx)->CopyWithType(Z)); InstanceCallInstr* invoke_get = new (Z) InstanceCallInstr( call->token_pos(), getter_name, Token::kGET, get_arguments, /*type_args_len=*/0, @@ -1129,16 +1126,13 @@ bool AotCallSpecializer::TryExpandCallThroughGetter(const Class& receiver_class, // Arguments to the .call() are the same as arguments to the // original call (including type arguments), but receiver // is replaced with the result of the get. - PushArgumentsArray* call_arguments = - new (Z) PushArgumentsArray(call->ArgumentCount()); + InputsArray* call_arguments = new (Z) InputsArray(Z, call->ArgumentCount()); if (call->type_args_len() > 0) { - call_arguments->Add( - new (Z) PushArgumentInstr(call->ArgumentValueAt(0)->CopyWithType(Z))); + call_arguments->Add(call->ArgumentValueAt(0)->CopyWithType(Z)); } - call_arguments->Add(new (Z) PushArgumentInstr(new (Z) Value(invoke_get))); + call_arguments->Add(new (Z) Value(invoke_get)); for (intptr_t i = receiver_idx + 1; i < call->ArgumentCount(); i++) { - call_arguments->Add( - new (Z) PushArgumentInstr(call->ArgumentValueAt(i)->CopyWithType(Z))); + call_arguments->Add(call->ArgumentValueAt(i)->CopyWithType(Z)); } InstanceCallInstr* invoke_call = new (Z) InstanceCallInstr( @@ -1147,30 +1141,25 @@ bool AotCallSpecializer::TryExpandCallThroughGetter(const Class& receiver_class, /*checked_argument_count=*/1, thread()->compiler_state().GetNextDeoptId()); - // Insert all new instructions, except .call() invocation into the - // graph. + // Create environment and insert 'invoke_get'. Environment* get_env = call->env()->DeepCopy(Z, call->env()->Length() - call->ArgumentCount()); for (intptr_t i = 0, n = invoke_get->ArgumentCount(); i < n; i++) { - PushArgumentInstr* push = invoke_get->PushArgumentAt(i); - InsertBefore(call, push, nullptr, FlowGraph::kEffect); - get_env->PushValue(new (Z) Value(push)); // add PushArg to getter's env + get_env->PushValue(new (Z) Value(invoke_get->ArgumentAt(i))); } InsertBefore(call, invoke_get, get_env, FlowGraph::kValue); - for (intptr_t i = 0, n = invoke_call->ArgumentCount(); i < n; i++) { - InsertBefore(call, invoke_call->PushArgumentAt(i), nullptr, - FlowGraph::kEffect); - } - // Replace original PushArguments in the graph (mainly env uses). - ASSERT(call->ArgumentCount() == invoke_call->ArgumentCount()); - for (intptr_t i = 0, n = call->ArgumentCount(); i < n; i++) { - call->PushArgumentAt(i)->ReplaceUsesWith(invoke_call->PushArgumentAt(i)); - call->PushArgumentAt(i)->RemoveFromGraph(); - } // Replace original call with .call(...) invocation. call->ReplaceWith(invoke_call, current_iterator()); + // ReplaceWith moved environment from 'call' to 'invoke_call'. + // Update receiver argument in the environment. + Environment* invoke_env = invoke_call->env(); + invoke_env + ->ValueAt(invoke_env->Length() - invoke_call->ArgumentCount() + + receiver_idx) + ->BindToEnvironment(invoke_get); + // AOT compiler expects all calls to have an ICData. EnsureICData(Z, flow_graph()->function(), invoke_get); EnsureICData(Z, flow_graph()->function(), invoke_call); @@ -1243,17 +1232,10 @@ bool AotCallSpecializer::TryReplaceInstanceOfWithRangeCheck( ConstantInstr* upper_cid = flow_graph()->GetConstant(Smi::Handle(Z, Smi::New(upper_limit))); - ZoneGrowableArray* args = - new (Z) ZoneGrowableArray(3); - PushArgumentInstr* arg = new (Z) PushArgumentInstr(new (Z) Value(left_cid)); - InsertBefore(call, arg, NULL, FlowGraph::kEffect); - args->Add(arg); - arg = new (Z) PushArgumentInstr(new (Z) Value(lower_cid)); - InsertBefore(call, arg, NULL, FlowGraph::kEffect); - args->Add(arg); - arg = new (Z) PushArgumentInstr(new (Z) Value(upper_cid)); - InsertBefore(call, arg, NULL, FlowGraph::kEffect); - args->Add(arg); + InputsArray* args = new (Z) InputsArray(Z, 3); + args->Add(new (Z) Value(left_cid)); + args->Add(new (Z) Value(lower_cid)); + args->Add(new (Z) Value(upper_cid)); const Library& dart_internal = Library::Handle(Z, Library::InternalLibrary()); const String& target_name = Symbols::_classRangeCheck(); @@ -1271,7 +1253,7 @@ bool AotCallSpecializer::TryReplaceInstanceOfWithRangeCheck( Environment* copy = call->env()->DeepCopy(Z, call->env()->Length() - call->ArgumentCount()); for (intptr_t i = 0; i < args->length(); ++i) { - copy->PushValue(new (Z) Value((*args)[i])); // add PushArg to env + copy->PushValue(new (Z) Value(new_call->ArgumentAt(i))); } call->RemoveEnvironment(); ReplaceCall(call, new_call); diff --git a/runtime/vm/compiler/backend/constant_propagator.cc b/runtime/vm/compiler/backend/constant_propagator.cc index cf618d83d29..3592d567733 100644 --- a/runtime/vm/compiler/backend/constant_propagator.cc +++ b/runtime/vm/compiler/backend/constant_propagator.cc @@ -379,22 +379,7 @@ void ConstantPropagator::VisitNativeParameter(NativeParameterInstr* instr) { } void ConstantPropagator::VisitPushArgument(PushArgumentInstr* instr) { - if (SetValue(instr, instr->value()->definition()->constant_value())) { - // The worklist implementation breaks down around push arguments, - // since these instructions do not have a direct use-link to the - // corresponding call. This is remedied by visiting all calls in - // the enviroment use list each time a push argument changes its - // value. Currently, this only needs to be done for static calls - // (the only calls involved in constant propagation). - // TODO(ajcbik): calls with multiple arguments may be revisited - // several times; a direct use-link would be better - for (Value* use = instr->env_use_list(); use != nullptr; - use = use->next_use()) { - if (use->instruction()->IsStaticCall()) { - use->instruction()->Accept(this); - } - } - } + UNREACHABLE(); } void ConstantPropagator::VisitAssertAssignable(AssertAssignableInstr* instr) { @@ -1438,15 +1423,6 @@ void ConstantPropagator::EliminateRedundantBranches() { } } -static void RemovePushArguments(StaticCallInstr* call) { - for (intptr_t i = 0; i < call->ArgumentCount(); ++i) { - PushArgumentInstr* push = call->PushArgumentAt(i); - ASSERT(push->input_use_list() == nullptr); // no direct uses - push->ReplaceUsesWith(push->value()->definition()); // cleanup env uses - push->RemoveFromGraph(); - } -} - void ConstantPropagator::Transform() { // We will recompute dominators, block ordering, block ids, block last // instructions, previous pointers, predecessors, etc. after eliminating @@ -1521,11 +1497,11 @@ void ConstantPropagator::Transform() { // Replace constant-valued instructions without observable side // effects. Do this for smis only to avoid having to copy other // objects into the heap's old generation. - if ((defn != NULL) && IsConstant(defn->constant_value()) && + ASSERT((defn == nullptr) || !defn->IsPushArgument()); + if ((defn != nullptr) && IsConstant(defn->constant_value()) && (defn->constant_value().IsSmi() || defn->constant_value().IsOld()) && - !defn->IsConstant() && !defn->IsPushArgument() && - !defn->IsStoreIndexed() && !defn->IsStoreInstanceField() && - !defn->IsStoreStaticField()) { + !defn->IsConstant() && !defn->IsStoreIndexed() && + !defn->IsStoreInstanceField() && !defn->IsStoreStaticField()) { if (FLAG_trace_constant_propagation && graph_->should_print()) { THR_Print("Constant v%" Pd " = %s\n", defn->ssa_temp_index(), defn->constant_value().ToCString()); @@ -1538,7 +1514,7 @@ void ConstantPropagator::Transform() { ASSERT(!value.IsNull() && (error_str == nullptr)); } if (auto call = defn->AsStaticCall()) { - RemovePushArguments(call); + ASSERT(!call->HasPushArguments()); } ConstantInstr* constant = graph_->GetConstant(value); defn->ReplaceUsesWith(constant); diff --git a/runtime/vm/compiler/backend/flow_graph.cc b/runtime/vm/compiler/backend/flow_graph.cc index 9f49f446e87..ef9fa480c9f 100644 --- a/runtime/vm/compiler/backend/flow_graph.cc +++ b/runtime/vm/compiler/backend/flow_graph.cc @@ -90,16 +90,7 @@ void FlowGraph::ReplaceCurrentInstruction(ForwardInstructionIterator* iterator, } } if (current->ArgumentCount() != 0) { - // Replacing a call instruction with something else. Must remove - // superfluous push arguments. - for (intptr_t i = 0; i < current->ArgumentCount(); ++i) { - PushArgumentInstr* push = current->PushArgumentAt(i); - if (replacement == NULL || i >= replacement->ArgumentCount() || - replacement->PushArgumentAt(i) != push) { - push->ReplaceUsesWith(push->value()->definition()); - push->RemoveFromGraph(); - } - } + ASSERT(!current->HasPushArguments()); } iterator->RemoveCurrentFromGraph(); } @@ -1156,8 +1147,10 @@ void FlowGraph::AttachEnvironment(Instruction* instr, Environment* deopt_env = Environment::From(zone(), *env, num_direct_parameters_, parsed_function_); if (instr->IsClosureCall()) { + // Trim extra input of ClosureCall instruction. deopt_env = - deopt_env->DeepCopy(zone(), deopt_env->Length() - instr->InputCount()); + deopt_env->DeepCopy(zone(), deopt_env->Length() - instr->InputCount() + + instr->ArgumentCount()); } instr->SetEnvironment(deopt_env); for (Environment::DeepIterator it(deopt_env); !it.Done(); it.Advance()) { @@ -1249,7 +1242,9 @@ void FlowGraph::RenameRecursive( // generate the constant rather than going through a synthetic phi. if (input_defn->IsConstant() && reaching_defn->IsPhi()) { ASSERT(env->length() < osr_variable_count()); - reaching_defn = GetConstant(input_defn->AsConstant()->value()); + auto constant = GetConstant(input_defn->AsConstant()->value()); + current->ReplaceInEnvironment(reaching_defn, constant); + reaching_defn = constant; } } else { // Note: constants can only be replaced with other constants. @@ -1266,52 +1261,8 @@ void FlowGraph::RenameRecursive( input_defn->AddInputUse(v); } - // 2b. Handle arguments. Usually this just consists of popping - // all consumed parameters from the expression stack. However, - // during OSR with a non-empty stack, PushArguments may have - // been lost (since the defining value resides in the now - // removed original entry). - Instruction* insert_at = current; // keeps push arguments in order - for (intptr_t i = current->ArgumentCount() - 1; i >= 0; --i) { - // Update expression stack. - ASSERT(env->length() > variable_count()); - Definition* reaching_defn = env->RemoveLast(); - if (reaching_defn->IsPushArgument()) { - insert_at = reaching_defn; - } else { - // We lost the PushArgument! This situation can only happen - // during OSR with a non-empty stack: replace the argument - // with the incoming parameter that mimics the stack slot. - ASSERT(IsCompiledForOsr()); - PushArgumentInstr* push_arg = current->PushArgumentAt(i); - ASSERT(reaching_defn->ssa_temp_index() != -1); - 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()); - push_arg->set_previous(nullptr); - push_arg->set_next(nullptr); - push_arg->value()->set_definition(reaching_defn); - InsertBefore(insert_at, push_arg, nullptr, FlowGraph::kEffect); - insert_at = push_arg; - // Since reaching_defn was not the expected PushArgument, we must - // change all its environment uses from the insertion point onward - // to the newly created PushArgument. This ensures that the stack - // depth computations (based on environment presence of PushArguments) - // is done correctly. - for (Value::Iterator it(reaching_defn->env_use_list()); !it.Done(); - it.Advance()) { - Instruction* instruction = it.Current()->instruction(); - if (instruction->IsDominatedBy(push_arg)) { - instruction->ReplaceInEnvironment(reaching_defn, push_arg); - } - } - } - } - - // 2c. Handle LoadLocal/StoreLocal/MakeTemp/DropTemps/Constant and - // PushArgument specially. Other definitions are just pushed - // to the environment directly. + // 2b. Handle LoadLocal/StoreLocal/MakeTemp/DropTemps/Constant specially. + // Other definitions are just pushed to the environment directly. Definition* result = NULL; switch (current->tag()) { case Instruction::kLoadLocal: { @@ -1400,8 +1351,8 @@ void FlowGraph::RenameRecursive( } case Instruction::kPushArgument: - env->Add(current->Cast()); - continue; + UNREACHABLE(); + break; case Instruction::kCheckStackOverflow: // Assert environment integrity at checkpoints. @@ -1469,12 +1420,7 @@ void FlowGraph::RenameRecursive( // Rename input operand. Definition* input = (*env)[i]; ASSERT(input != nullptr); - if (input->IsPushArgument()) { - // A push argument left on expression stack - // requires the variable name in SSA phis. - ASSERT(IsCompiledForOsr()); - input = input->InputAt(0)->definition(); - } + ASSERT(!input->IsPushArgument()); Value* use = new (zone()) Value(input); phi->SetInputAt(pred_index, use); } @@ -2078,7 +2024,9 @@ 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. - if (!instr->IsReturn() && !instr->IsPushArgument()) { + ASSERT(!instr->IsPushArgument()); + if (!instr->IsReturn() && + (use->use_index() >= instr->ArgumentCount())) { gain--; if (FLAG_support_il_printer && FLAG_trace_smi_widening) { THR_Print("v [%" Pd "] (u) %s\n", gain, @@ -2618,6 +2566,37 @@ PhiInstr* FlowGraph::AddPhi(JoinEntryInstr* join, return phi; } +void FlowGraph::InsertPushArguments() { + for (BlockIterator block_it = reverse_postorder_iterator(); !block_it.Done(); + block_it.Advance()) { + thread()->CheckForSafepoint(); + for (ForwardInstructionIterator instr_it(block_it.Current()); + !instr_it.Done(); instr_it.Advance()) { + Instruction* instruction = instr_it.Current(); + const intptr_t arg_count = instruction->ArgumentCount(); + if (arg_count == 0) { + continue; + } + PushArgumentsArray* arguments = + new (Z) PushArgumentsArray(zone(), arg_count); + for (intptr_t i = 0; i < arg_count; ++i) { + Value* arg = instruction->ArgumentValueAt(i); + PushArgumentInstr* push_arg = + new (Z) PushArgumentInstr(arg->CopyWithType(Z)); + arguments->Add(push_arg); + // 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); + } + instruction->ReplaceInputsWithPushArguments(arguments); + if (instruction->env() != nullptr) { + instruction->RepairPushArgsInEnvironment(); + } + } + } +} + } // namespace dart #endif // !defined(DART_PRECOMPILED_RUNTIME) diff --git a/runtime/vm/compiler/backend/flow_graph.h b/runtime/vm/compiler/backend/flow_graph.h index 3622a5c4fbe..b6ff5310f72 100644 --- a/runtime/vm/compiler/backend/flow_graph.h +++ b/runtime/vm/compiler/backend/flow_graph.h @@ -289,6 +289,10 @@ 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 + // relations between calls and their arguments. + void InsertPushArguments(); + // Copy deoptimization target from one instruction to another if we still // have to keep deoptimization environment at gotos for LICM purposes. void CopyDeoptTarget(Instruction* to, Instruction* from) { diff --git a/runtime/vm/compiler/backend/flow_graph_checker.cc b/runtime/vm/compiler/backend/flow_graph_checker.cc index c861c5d3cf9..5d7c523d3c2 100644 --- a/runtime/vm/compiler/backend/flow_graph_checker.cc +++ b/runtime/vm/compiler/backend/flow_graph_checker.cc @@ -106,8 +106,8 @@ static bool IsControlFlow(Instruction* instruction) { instruction->IsStop() || instruction->IsTailCall(); } -// Asserts push arguments appear in environment at the right place. -static void AssertPushArgsInEnv(FlowGraph* flow_graph, Definition* call) { +// Asserts that arguments appear in environment at the right place. +static void AssertArgumentsInEnv(FlowGraph* flow_graph, Definition* call) { Environment* env = call->env(); if (env == nullptr) { // Environments can be removed by EliminateEnvironments pass and @@ -116,14 +116,35 @@ static void AssertPushArgsInEnv(FlowGraph* flow_graph, Definition* call) { // TODO(dartbug.com/38577): cleanup regexp pipeline too.... } else { // Otherwise, the trailing environment entries must - // correspond directly with the PushArguments. + // correspond directly with the arguments. const intptr_t env_count = env->Length(); const intptr_t arg_count = call->ArgumentCount(); ASSERT(arg_count <= env_count); const intptr_t env_base = env_count - arg_count; for (intptr_t i = 0; i < arg_count; i++) { - ASSERT(call->PushArgumentAt(i) == - env->ValueAt(env_base + i)->definition()); + if (call->HasPushArguments()) { + ASSERT(call->ArgumentAt(i) == env->ValueAt(env_base + i) + ->definition() + ->AsPushArgument() + ->value() + ->definition()); + } else { + // Redefintion instructions and boxing/unboxing are inserted + // without updating environment uses (FlowGraph::RenameDominatedUses, + // FlowGraph::InsertConversionsFor). + // Also, constants may belong to different blocks (e.g. function entry + // and graph entry). + Definition* arg_def = + call->ArgumentAt(i)->OriginalDefinitionIgnoreBoxingAndConstraints(); + Definition* env_def = + env->ValueAt(env_base + i) + ->definition() + ->OriginalDefinitionIgnoreBoxingAndConstraints(); + ASSERT((arg_def == env_def) || + (arg_def->IsConstant() && env_def->IsConstant() && + arg_def->AsConstant()->value().raw() == + env_def->AsConstant()->value().raw())); + } } } } @@ -419,15 +440,15 @@ void FlowGraphChecker::VisitRedefinition(RedefinitionInstr* def) { } void FlowGraphChecker::VisitClosureCall(ClosureCallInstr* call) { - AssertPushArgsInEnv(flow_graph_, call); + AssertArgumentsInEnv(flow_graph_, call); } void FlowGraphChecker::VisitStaticCall(StaticCallInstr* call) { - AssertPushArgsInEnv(flow_graph_, call); + AssertArgumentsInEnv(flow_graph_, call); } void FlowGraphChecker::VisitInstanceCall(InstanceCallInstr* call) { - AssertPushArgsInEnv(flow_graph_, call); + AssertArgumentsInEnv(flow_graph_, call); // Force-optimized functions may not have instance calls inside them because // we do not reset ICData for these. ASSERT(!flow_graph_->function().ForceOptimize()); @@ -435,7 +456,7 @@ void FlowGraphChecker::VisitInstanceCall(InstanceCallInstr* call) { void FlowGraphChecker::VisitPolymorphicInstanceCall( PolymorphicInstanceCallInstr* call) { - AssertPushArgsInEnv(flow_graph_, call); + AssertArgumentsInEnv(flow_graph_, call); // Force-optimized functions may not have instance calls inside them because // we do not reset ICData for these. ASSERT(!flow_graph_->function().ForceOptimize()); diff --git a/runtime/vm/compiler/backend/il.cc b/runtime/vm/compiler/backend/il.cc index 88e6c49196c..6bdb4d399fd 100644 --- a/runtime/vm/compiler/backend/il.cc +++ b/runtime/vm/compiler/backend/il.cc @@ -534,7 +534,8 @@ Definition* Definition::OriginalDefinitionIgnoreBoxingAndConstraints() { Definition* def = this; while (true) { Definition* orig; - if (def->IsConstraint() || def->IsBox() || def->IsUnbox()) { + if (def->IsConstraint() || def->IsBox() || def->IsUnbox() || + def->IsIntConverter()) { orig = def->InputAt(0)->definition(); } else { orig = def->OriginalDefinition(); @@ -1484,11 +1485,13 @@ void Instruction::UnuseAllInputs() { } void Instruction::RepairPushArgsInEnvironment() const { + PushArgumentsArray* push_arguments = GetPushArguments(); + ASSERT(push_arguments != nullptr); const intptr_t arg_count = ArgumentCount(); ASSERT(arg_count <= env()->Length()); const intptr_t env_base = env()->Length() - arg_count; for (intptr_t i = 0; i < arg_count; ++i) { - env()->ValueAt(env_base + i)->BindToEnvironment(PushArgumentAt(i)); + env()->ValueAt(env_base + i)->BindToEnvironment(push_arguments->At(i)); } } @@ -4459,6 +4462,12 @@ intptr_t PolymorphicInstanceCallInstr::CallCount() const { return targets().AggregateCallCount(); } +LocationSummary* PolymorphicInstanceCallInstr::MakeLocationSummary( + Zone* zone, + bool optimizing) const { + return MakeCallSummary(zone); +} + void PolymorphicInstanceCallInstr::EmitNativeCode(FlowGraphCompiler* compiler) { ArgumentsInfo args_info(type_args_len(), ArgumentCount(), argument_names()); compiler->EmitPolymorphicInstanceCall(targets_, *instance_call(), args_info, @@ -5335,6 +5344,11 @@ intptr_t TruncDivModInstr::OutputIndexOf(Token::Kind token) { } } +LocationSummary* NativeCallInstr::MakeLocationSummary(Zone* zone, + bool optimizing) const { + return MakeCallSummary(zone); +} + void NativeCallInstr::SetupNative() { if (link_lazily()) { // Resolution will happen during NativeEntry::LinkNativeCall. diff --git a/runtime/vm/compiler/backend/il.h b/runtime/vm/compiler/backend/il.h index 3e1ad4cc5f3..9d4e713a699 100644 --- a/runtime/vm/compiler/backend/il.h +++ b/runtime/vm/compiler/backend/il.h @@ -751,6 +751,9 @@ class BinaryFeedback : public ZoneAllocated { friend class Cids; }; +typedef ZoneGrowableArray InputsArray; +typedef ZoneGrowableArray PushArgumentsArray; + class Instruction : public ZoneAllocated { public: #define DECLARE_TAG(type, attrs) k##type, @@ -809,13 +812,25 @@ class Instruction : public ZoneAllocated { // Call instructions override this function and return the number of // pushed arguments. virtual intptr_t ArgumentCount() const { return 0; } - virtual PushArgumentInstr* PushArgumentAt(intptr_t index) const { - UNREACHABLE(); - return NULL; - } 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) { + UNREACHABLE(); + } + // Returns array of PushArgument instructions + virtual PushArgumentsArray* GetPushArguments() const { + UNREACHABLE(); + return nullptr; + } + // Replace inputs with separate PushArgument instructions detached from call. + virtual void ReplaceInputsWithPushArguments( + PushArgumentsArray* push_arguments) { + UNREACHABLE(); + } + bool HasPushArguments() const { return GetPushArguments() != nullptr; } + // Repairs trailing PushArgs in environment. void RepairPushArgsInEnvironment() const; @@ -2686,7 +2701,9 @@ class PushArgumentInstr : public TemplateDefinition<1, NoThrow> { }; inline Value* Instruction::ArgumentValueAt(intptr_t index) const { - return PushArgumentAt(index)->value(); + PushArgumentsArray* push_arguments = GetPushArguments(); + return push_arguments != nullptr ? (*push_arguments)[index]->value() + : InputAt(index); } inline Definition* Instruction::ArgumentAt(intptr_t index) const { @@ -2772,8 +2789,6 @@ class NativeReturnInstr : public ReturnInstr { DISALLOW_COPY_AND_ASSIGN(NativeReturnInstr); }; -typedef ZoneGrowableArray PushArgumentsArray; - class ThrowInstr : public TemplateInstruction<1, Throws> { public: explicit ThrowInstr(TokenPosition token_pos, @@ -3088,8 +3103,11 @@ class BranchInstr : public Instruction { virtual intptr_t ArgumentCount() const { return comparison()->ArgumentCount(); } - virtual PushArgumentInstr* PushArgumentAt(intptr_t index) const { - return comparison()->PushArgumentAt(index); + virtual void SetPushArguments(PushArgumentsArray* push_arguments) { + comparison()->SetPushArguments(push_arguments); + } + virtual PushArgumentsArray* GetPushArguments() const { + return comparison()->GetPushArguments(); } intptr_t InputCount() const { return comparison()->InputCount(); } @@ -3561,20 +3579,24 @@ struct ArgumentsInfo { const Array& argument_names; }; -template -class TemplateDartCall : public TemplateDefinition { +template +class TemplateDartCall : public Definition { public: TemplateDartCall(intptr_t deopt_id, intptr_t type_args_len, const Array& argument_names, - PushArgumentsArray* arguments, + InputsArray* inputs, TokenPosition token_pos) - : TemplateDefinition(deopt_id), + : Definition(deopt_id), type_args_len_(type_args_len), argument_names_(argument_names), - arguments_(arguments), + inputs_(inputs), token_pos_(token_pos) { ASSERT(argument_names.IsZoneHandle() || argument_names.InVMIsolateHeap()); + ASSERT(inputs_->length() >= kExtraInputs); + for (intptr_t i = 0, n = inputs_->length(); i < n; ++i) { + SetInputAt(i, (*inputs_)[i]); + } } RawString* Selector() { @@ -3587,16 +3609,43 @@ class TemplateDartCall : public TemplateDefinition { } } + virtual bool MayThrow() const { return true; } + + virtual intptr_t InputCount() const { return inputs_->length(); } + virtual Value* InputAt(intptr_t i) const { return inputs_->At(i); } + intptr_t FirstArgIndex() const { return type_args_len_ > 0 ? 1 : 0; } Value* Receiver() const { return this->ArgumentValueAt(FirstArgIndex()); } intptr_t ArgumentCountWithoutTypeArgs() const { - return arguments_->length() - FirstArgIndex(); + return ArgumentCount() - FirstArgIndex(); } // ArgumentCount() includes the type argument vector if any. // Caution: Must override Instruction::ArgumentCount(). - virtual intptr_t ArgumentCount() const { return arguments_->length(); } - virtual PushArgumentInstr* PushArgumentAt(intptr_t index) const { - return (*arguments_)[index]; + virtual intptr_t ArgumentCount() const { + return push_arguments_ != nullptr ? push_arguments_->length() + : inputs_->length() - kExtraInputs; + } + virtual void SetPushArguments(PushArgumentsArray* push_arguments) { + ASSERT(push_arguments_ == nullptr); + push_arguments_ = push_arguments; + } + virtual PushArgumentsArray* GetPushArguments() const { + return push_arguments_; + } + virtual void ReplaceInputsWithPushArguments( + PushArgumentsArray* push_arguments) { + ASSERT(push_arguments_ == nullptr); + ASSERT(push_arguments->length() == ArgumentCount()); + SetPushArguments(push_arguments); + ASSERT(inputs_->length() == ArgumentCount() + kExtraInputs); + const intptr_t extra_inputs_base = inputs_->length() - kExtraInputs; + for (intptr_t i = 0, n = ArgumentCount(); i < n; ++i) { + InputAt(i)->RemoveFromUseList(); + } + for (intptr_t i = 0; i < kExtraInputs; ++i) { + SetInputAt(i, InputAt(extra_inputs_base + i)); + } + inputs_->TruncateTo(kExtraInputs); } intptr_t type_args_len() const { return type_args_len_; } const Array& argument_names() const { return argument_names_; } @@ -3609,9 +3658,14 @@ class TemplateDartCall : public TemplateDefinition { ADD_EXTRA_INFO_TO_S_EXPRESSION_SUPPORT private: + virtual void RawSetInputAt(intptr_t i, Value* value) { + (*inputs_)[i] = value; + } + intptr_t type_args_len_; const Array& argument_names_; - PushArgumentsArray* arguments_; + InputsArray* inputs_; + PushArgumentsArray* push_arguments_ = nullptr; TokenPosition token_pos_; DISALLOW_COPY_AND_ASSIGN(TemplateDartCall); @@ -3619,8 +3673,7 @@ class TemplateDartCall : public TemplateDefinition { class ClosureCallInstr : public TemplateDartCall<1> { public: - ClosureCallInstr(Value* function, - PushArgumentsArray* arguments, + ClosureCallInstr(InputsArray* inputs, intptr_t type_args_len, const Array& argument_names, TokenPosition token_pos, @@ -3629,12 +3682,9 @@ class ClosureCallInstr : public TemplateDartCall<1> { : TemplateDartCall(deopt_id, type_args_len, argument_names, - arguments, + inputs, token_pos), - entry_kind_(entry_kind) { - ASSERT(!arguments->is_empty()); - SetInputAt(0, function); - } + entry_kind_(entry_kind) {} DECLARE_INSTRUCTION(ClosureCall) @@ -3662,7 +3712,7 @@ class InstanceCallInstr : public TemplateDartCall<0> { TokenPosition token_pos, const String& function_name, Token::Kind token_kind, - PushArgumentsArray* arguments, + InputsArray* arguments, intptr_t type_args_len, const Array& argument_names, intptr_t checked_argument_count, @@ -3699,7 +3749,7 @@ class InstanceCallInstr : public TemplateDartCall<0> { TokenPosition token_pos, const String& function_name, Token::Kind token_kind, - PushArgumentsArray* arguments, + InputsArray* arguments, intptr_t type_args_len, const Array& argument_names, intptr_t checked_argument_count, @@ -3896,7 +3946,7 @@ class PolymorphicInstanceCallInstr : public TemplateDartCall<0> { private: PolymorphicInstanceCallInstr(InstanceCallInstr* instance_call, - PushArgumentsArray* arguments, + InputsArray* arguments, const CallTargets& targets, bool complete) : TemplateDartCall<0>(instance_call->deopt_id(), @@ -3918,10 +3968,11 @@ class PolymorphicInstanceCallInstr : public TemplateDartCall<0> { InstanceCallInstr* call_for_attributes, const CallTargets& targets, bool complete) { - PushArgumentsArray* args = new (zone) - PushArgumentsArray(zone, call_for_arguments->ArgumentCount()); + ASSERT(!call_for_arguments->HasPushArguments()); + InputsArray* args = + new (zone) InputsArray(zone, call_for_arguments->ArgumentCount()); for (intptr_t i = 0, n = call_for_arguments->ArgumentCount(); i < n; ++i) { - args->Add(call_for_arguments->PushArgumentAt(i)); + args->Add(call_for_arguments->ArgumentValueAt(i)->CopyWithType(zone)); } return new (zone) PolymorphicInstanceCallInstr(call_for_attributes, args, targets, complete); @@ -4232,7 +4283,7 @@ class StaticCallInstr : public TemplateDartCall<0> { const Function& function, intptr_t type_args_len, const Array& argument_names, - PushArgumentsArray* arguments, + InputsArray* arguments, const ZoneGrowableArray& ic_data_array, intptr_t deopt_id, ICData::RebindRule rebind_rule) @@ -4257,7 +4308,7 @@ class StaticCallInstr : public TemplateDartCall<0> { const Function& function, intptr_t type_args_len, const Array& argument_names, - PushArgumentsArray* arguments, + InputsArray* arguments, intptr_t deopt_id, intptr_t call_count, ICData::RebindRule rebind_rule) @@ -4284,10 +4335,10 @@ class StaticCallInstr : public TemplateDartCall<0> { const C* call, const Function& target, intptr_t call_count) { - PushArgumentsArray* args = - new (zone) PushArgumentsArray(call->ArgumentCount()); + ASSERT(!call->HasPushArguments()); + InputsArray* args = new (zone) InputsArray(zone, call->ArgumentCount()); for (intptr_t i = 0; i < call->ArgumentCount(); i++) { - args->Add(call->PushArgumentAt(i)); + args->Add(call->ArgumentValueAt(i)->CopyWithType()); } StaticCallInstr* new_call = new (zone) StaticCallInstr(call->token_pos(), target, call->type_args_len(), @@ -4296,6 +4347,9 @@ class StaticCallInstr : public TemplateDartCall<0> { if (call->result_type() != NULL) { new_call->result_type_ = call->result_type(); } + if (call->has_inlining_id()) { + new_call->set_inlining_id(call->inlining_id()); + } new_call->set_entry_kind(call->entry_kind()); return new_call; } @@ -4553,7 +4607,7 @@ class NativeCallInstr : public TemplateDartCall<0> { const Function* function, bool link_lazily, TokenPosition position, - PushArgumentsArray* args) + InputsArray* args) : TemplateDartCall(DeoptId::kNone, 0, Array::null_array(), diff --git a/runtime/vm/compiler/backend/il_arm.cc b/runtime/vm/compiler/backend/il_arm.cc index c2349e7faa0..b0efd4ef6dd 100644 --- a/runtime/vm/compiler/backend/il_arm.cc +++ b/runtime/vm/compiler/backend/il_arm.cc @@ -85,21 +85,133 @@ LocationSummary* PushArgumentInstr::MakeLocationSummary(Zone* zone, return locs; } +// Buffers registers to use STMDB in order to push +// multiple registers at once. +class ArgumentsPusher : public ValueObject { + public: + ArgumentsPusher() {} + + // Flush all buffered registers. + void Flush(FlowGraphCompiler* compiler) { + if (pending_regs_ != 0) { + if (is_single_register_) { + __ Push(lowest_register_); + } else { + __ PushList(pending_regs_); + } + pending_regs_ = 0; + lowest_register_ = kNoRegister; + is_single_register_ = false; + } + } + + // Buffer given register. May push previously buffered registers if needed. + void PushRegister(FlowGraphCompiler* compiler, Register reg) { + if (pending_regs_ != 0) { + ASSERT(lowest_register_ != kNoRegister); + // STMDB pushes higher registers first, so we can only buffer + // lower registers. + if (reg < lowest_register_) { + pending_regs_ |= (1 << reg); + lowest_register_ = reg; + is_single_register_ = false; + return; + } + Flush(compiler); + } + pending_regs_ = (1 << reg); + lowest_register_ = reg; + is_single_register_ = true; + } + + // Return a register which can be used to hold a value of an argument. + Register FindFreeRegister(FlowGraphCompiler* compiler, + Instruction* push_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()) { + ASSERT(instr != nullptr); + if (ParallelMoveInstr* parallel_move = instr->AsParallelMove()) { + for (intptr_t i = 0, n = parallel_move->NumMoves(); i < n; ++i) { + if (parallel_move->MoveOperandsAt(i)->src().IsRegister()) { + busy |= (1 << parallel_move->MoveOperandsAt(i)->src().reg()); + } + } + } else { + ASSERT(instr->IsPushArgument() || (instr->ArgumentCount() > 0)); + for (intptr_t i = 0, n = instr->locs()->input_count(); i < n; ++i) { + if (instr->locs()->in(i).IsRegister()) { + busy |= (1 << instr->locs()->in(i).reg()); + } + } + if (instr->ArgumentCount() > 0) { + break; + } + } + } + if (pending_regs_ != 0) { + // Find the highest available register which can be pushed along with + // pending registers. + Register reg = HighestAvailableRegister(busy, lowest_register_); + if (reg != kNoRegister) { + return reg; + } + Flush(compiler); + } + // At this point there are no pending buffered registers. + // Use LR as it's the highest free register, it is not allocatable and + // it is clobbered by the call. + static_assert(((1 << LR) & kDartAvailableCpuRegs) == 0, + "LR should not be allocatable"); + return LR; + } + + private: + RegList pending_regs_ = 0; + Register lowest_register_ = kNoRegister; + bool is_single_register_ = false; + + Register HighestAvailableRegister(intptr_t busy, Register upper_bound) { + for (intptr_t i = upper_bound - 1; i >= 0; --i) { + if ((busy & (1 << i)) == 0) { + return static_cast(i); + } + } + return kNoRegister; + } +}; + void PushArgumentInstr::EmitNativeCode(FlowGraphCompiler* compiler) { // In SSA mode, we need an explicit push. Nothing to do in non-SSA mode - // where PushArgument is handled by BindInstr::EmitNativeCode. + // where arguments are pushed by their definitions. if (compiler->is_optimizing()) { - Location value = locs()->in(0); - if (value.IsRegister()) { - __ Push(value.reg()); - } else if (value.IsConstant()) { - __ PushObject(value.constant()); - } else { - ASSERT(value.IsStackSlot()); - const intptr_t value_offset = value.ToStackSlotOffset(); - __ LoadFromOffset(kWord, IP, value.base_reg(), value_offset); - __ Push(IP); + if (previous()->IsPushArgument()) { + // Already generated. + 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); + if (value.IsRegister()) { + pusher.PushRegister(compiler, value.reg()); + } else { + const Register reg = pusher.FindFreeRegister(compiler, push_arg); + ASSERT(reg != kNoRegister); + if (value.IsConstant()) { + __ LoadObject(reg, value.constant()); + } else { + ASSERT(value.IsStackSlot()); + const intptr_t value_offset = value.ToStackSlotOffset(); + __ LoadFromOffset(kWord, reg, value.base_reg(), value_offset); + } + pusher.PushRegister(compiler, reg); + } + } + pusher.Flush(compiler); } } @@ -934,11 +1046,6 @@ Condition RelationalOpInstr::EmitComparisonCode(FlowGraphCompiler* compiler, } } -LocationSummary* NativeCallInstr::MakeLocationSummary(Zone* zone, - bool opt) const { - return MakeCallSummary(zone); -} - void NativeCallInstr::EmitNativeCode(FlowGraphCompiler* compiler) { SetupNative(); const Register result = locs()->out(0).reg(); @@ -6107,12 +6214,6 @@ void TruncDivModInstr::EmitNativeCode(FlowGraphCompiler* compiler) { __ Bind(&done); } -LocationSummary* PolymorphicInstanceCallInstr::MakeLocationSummary( - Zone* zone, - bool opt) const { - return MakeCallSummary(zone); -} - LocationSummary* BranchInstr::MakeLocationSummary(Zone* zone, bool opt) const { comparison()->InitializeLocationSummary(zone, opt); // Branches don't produce a result. diff --git a/runtime/vm/compiler/backend/il_arm64.cc b/runtime/vm/compiler/backend/il_arm64.cc index 9de63c379d1..2f5a6e99c5c 100644 --- a/runtime/vm/compiler/backend/il_arm64.cc +++ b/runtime/vm/compiler/backend/il_arm64.cc @@ -83,21 +83,76 @@ LocationSummary* PushArgumentInstr::MakeLocationSummary(Zone* zone, return locs; } +// Buffers registers in order to use STP to push +// two registers at once. +class ArgumentsPusher : public ValueObject { + public: + ArgumentsPusher() {} + + // Flush all buffered registers. + void Flush(FlowGraphCompiler* compiler) { + if (pending_register_ != kNoRegister) { + __ Push(pending_register_); + pending_register_ = kNoRegister; + } + } + + // Buffer given register. May push buffered registers if needed. + void PushRegister(FlowGraphCompiler* compiler, Register reg) { + if (pending_register_ != kNoRegister) { + __ PushPair(reg, pending_register_); + pending_register_ = kNoRegister; + return; + } + pending_register_ = reg; + } + + // Returns free temp register to hold argument value. + Register GetFreeTempRegister() { + // While pushing arguments only Push, PushPair, LoadObject and + // LoadFromOffset are used. They do not clobber TMP or LR. + static_assert(((1 << LR) & kDartAvailableCpuRegs) == 0, + "LR should not be allocatable"); + static_assert(((1 << TMP) & kDartAvailableCpuRegs) == 0, + "TMP should not be allocatable"); + return (pending_register_ == TMP) ? LR : TMP; + } + + private: + Register pending_register_ = kNoRegister; +}; + void PushArgumentInstr::EmitNativeCode(FlowGraphCompiler* compiler) { // In SSA mode, we need an explicit push. Nothing to do in non-SSA mode - // where PushArgument is handled by BindInstr::EmitNativeCode. + // where arguments are pushed by their definitions. if (compiler->is_optimizing()) { - Location value = locs()->in(0); - if (value.IsRegister()) { - __ Push(value.reg()); - } else if (value.IsConstant()) { - __ PushObject(value.constant()); - } else { - ASSERT(value.IsStackSlot()); - const intptr_t value_offset = value.ToStackSlotOffset(); - __ LoadFromOffset(TMP, value.base_reg(), value_offset); - __ Push(TMP); + if (previous()->IsPushArgument()) { + // Already generated. + 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); + Register reg = kNoRegister; + if (value.IsRegister()) { + reg = value.reg(); + } else if (value.IsConstant()) { + if (compiler::IsSameObject(compiler::NullObject(), value.constant())) { + reg = NULL_REG; + } else { + reg = pusher.GetFreeTempRegister(); + __ LoadObject(reg, value.constant()); + } + } else { + ASSERT(value.IsStackSlot()); + const intptr_t value_offset = value.ToStackSlotOffset(); + reg = pusher.GetFreeTempRegister(); + __ LoadFromOffset(reg, value.base_reg(), value_offset); + } + pusher.PushRegister(compiler, reg); + } + pusher.Flush(compiler); } } @@ -814,11 +869,6 @@ Condition RelationalOpInstr::EmitComparisonCode(FlowGraphCompiler* compiler, } } -LocationSummary* NativeCallInstr::MakeLocationSummary(Zone* zone, - bool opt) const { - return MakeCallSummary(zone); -} - void NativeCallInstr::EmitNativeCode(FlowGraphCompiler* compiler) { SetupNative(); const Register result = locs()->out(0).reg(); @@ -5094,12 +5144,6 @@ void TruncDivModInstr::EmitNativeCode(FlowGraphCompiler* compiler) { __ Bind(&done); } -LocationSummary* PolymorphicInstanceCallInstr::MakeLocationSummary( - Zone* zone, - bool opt) const { - return MakeCallSummary(zone); -} - LocationSummary* BranchInstr::MakeLocationSummary(Zone* zone, bool opt) const { comparison()->InitializeLocationSummary(zone, opt); // Branches don't produce a result. diff --git a/runtime/vm/compiler/backend/il_deserializer.cc b/runtime/vm/compiler/backend/il_deserializer.cc index c84332dad86..6251bf8a179 100644 --- a/runtime/vm/compiler/backend/il_deserializer.cc +++ b/runtime/vm/compiler/backend/il_deserializer.cc @@ -294,16 +294,6 @@ FlowGraph* FlowGraphDeserializer::ParseFlowGraph() { pos++; } - // The graph entry doesn't push any arguments onto the stack. Adding a - // pushed_stack_map_ entry for it allows us to unify how function entries - // are handled vs. other types of blocks with regards to incoming pushed - // argument stacks. - // - // We add this entry now so that ParseEnvironment can assume that there's - // always a current pushed_stack_map_ for current_block_. - auto const empty_stack = new (zone()) PushStack(zone(), 0); - pushed_stack_map_.Insert(0, empty_stack); - // The deopt environment for the graph entry may use entries from the // constant pool, so that must be parsed first. if (auto const env_sexp = CheckList(root->ExtraLookupValue("env"))) { @@ -500,24 +490,9 @@ bool FlowGraphDeserializer::ParseBlocks(SExpList* list, auto const block_sexp = block_sexp_map.LookupValue(block_id); ASSERT(block_sexp != nullptr); - // Copy the pushed argument stack of the predecessor to begin the stack for - // this block. This is safe due to the worklist algorithm, since one - // predecessor has already been added when this block is first reached. - // - // For JoinEntry blocks, since the worklist algorithm is a depth-first - // search, we may not see all possible predecessors before the JoinEntry - // is parsed. To ensure consistency between predecessor stacks, we check - // the consistency in ParseBlockContents when updating predecessor - // information. current_block_ = block_map_.LookupValue(block_id); ASSERT(current_block_ != nullptr); ASSERT(current_block_->PredecessorCount() > 0); - auto const pred_id = current_block_->PredecessorAt(0)->block_id(); - auto const pred_stack = pushed_stack_map_.LookupValue(pred_id); - ASSERT(pred_stack != nullptr); - auto const new_stack = new (zone()) PushStack(zone(), pred_stack->length()); - new_stack->AddArray(*pred_stack); - pushed_stack_map_.Insert(block_id, new_stack); if (!ParseBlockContents(block_sexp, worklist)) return false; @@ -663,9 +638,6 @@ intptr_t FlowGraphDeserializer::SkipPhis(SExpList* list) { bool FlowGraphDeserializer::ParseBlockContents(SExpList* list, BlockWorklist* worklist) { ASSERT(current_block_ != nullptr); - auto const curr_stack = - pushed_stack_map_.LookupValue(current_block_->block_id()); - ASSERT(curr_stack != nullptr); // Parse any Phi definitions now before parsing the block environment. if (current_block_->IsJoinEntry()) { @@ -699,9 +671,6 @@ bool FlowGraphDeserializer::ParseBlockContents(SExpList* list, if (last_inst->SuccessorCount() > 0) { for (intptr_t i = last_inst->SuccessorCount() - 1; i >= 0; i--) { auto const succ_block = last_inst->SuccessorAt(i); - // Check and make sure the stack we have is consistent with stacks - // from other predecessors. - if (!AreStacksConsistent(list, curr_stack, succ_block)) return false; succ_block->AddPredecessor(current_block_); worklist->Add(succ_block->block_id()); } @@ -787,6 +756,7 @@ Instruction* FlowGraphDeserializer::ParseInstruction(SExpList* list) { // Parse the environment before handling the instruction, as we may have // references to PushArguments and parsing the instruction may pop // PushArguments off the stack. + // TODO(alexmarkov): revise as it may not be needed anymore. Environment* env = nullptr; if (auto const env_sexp = CheckList(list->ExtraLookupValue("env"))) { env = ParseEnvironment(env_sexp); @@ -1056,8 +1026,9 @@ InstanceCallInstr* FlowGraphDeserializer::DeserializeInstanceCall( SExpList* sexp, const InstrInfo& info) { auto& interface_target = Function::ZoneHandle(zone()); - if (!ParseDartValue(Retrieve(sexp, 1), &interface_target)) return nullptr; - + if (!ParseDartValue(Retrieve(sexp, "interface_target"), &interface_target)) { + return nullptr; + } auto& function_name = String::ZoneHandle(zone()); // If we have an explicit function_name value, then use that value. Otherwise, // if we have an non-null interface_target, use its name. @@ -1086,7 +1057,7 @@ InstanceCallInstr* FlowGraphDeserializer::DeserializeInstanceCall( } auto const inst = new (zone()) InstanceCallInstr( - info.token_pos, function_name, token_kind, call_info.arguments, + info.token_pos, function_name, token_kind, call_info.inputs, call_info.type_args_len, call_info.argument_names, checked_arg_count, info.deopt_id, interface_target); @@ -1129,7 +1100,7 @@ NativeCallInstr* FlowGraphDeserializer::DeserializeNativeCall( SExpList* sexp, const InstrInfo& info) { auto& function = Function::ZoneHandle(zone()); - if (!ParseDartValue(Retrieve(sexp, 1), &function)) return nullptr; + if (!ParseDartValue(Retrieve(sexp, "function"), &function)) return nullptr; if (!function.IsFunction()) { StoreError(sexp->At(1), "expected a Function value"); return nullptr; @@ -1149,7 +1120,7 @@ NativeCallInstr* FlowGraphDeserializer::DeserializeNativeCall( if (!ParseCallInfo(sexp, &call_info)) return nullptr; return new (zone()) NativeCallInstr(&name, &function, link_lazily, - info.token_pos, call_info.arguments); + info.token_pos, call_info.inputs); } ParameterInstr* FlowGraphDeserializer::DeserializeParameter( @@ -1162,18 +1133,6 @@ ParameterInstr* FlowGraphDeserializer::DeserializeParameter( return nullptr; } -PushArgumentInstr* FlowGraphDeserializer::DeserializePushArgument( - SExpList* sexp, - const InstrInfo& info) { - auto const val = ParseValue(Retrieve(sexp, 1)); - if (val == nullptr) return nullptr; - auto const push = new (zone()) PushArgumentInstr(val); - auto const stack = pushed_stack_map_.LookupValue(current_block_->block_id()); - ASSERT(stack != nullptr); - stack->Add(push); - return push; -} - ReturnInstr* FlowGraphDeserializer::DeserializeReturn(SExpList* list, const InstrInfo& info) { Value* val = ParseValue(Retrieve(list, 1)); @@ -1200,7 +1159,8 @@ StaticCallInstr* FlowGraphDeserializer::DeserializeStaticCall( SExpList* sexp, const InstrInfo& info) { auto& function = Function::ZoneHandle(zone()); - auto const function_sexp = CheckTaggedList(Retrieve(sexp, 1), "Function"); + auto const function_sexp = + CheckTaggedList(Retrieve(sexp, "function"), "Function"); if (!ParseFunction(function_sexp, &function)) return nullptr; CallInfo call_info(zone()); @@ -1223,8 +1183,8 @@ StaticCallInstr* FlowGraphDeserializer::DeserializeStaticCall( auto const inst = new (zone()) StaticCallInstr(info.token_pos, function, call_info.type_args_len, - call_info.argument_names, call_info.arguments, - info.deopt_id, call_count, rebind_rule); + call_info.argument_names, call_info.inputs, info.deopt_id, + call_count, rebind_rule); if (call_info.result_type != nullptr) { inst->SetResultType(zone(), *call_info.result_type); @@ -1298,7 +1258,9 @@ ThrowInstr* FlowGraphDeserializer::DeserializeThrow(SExpList* sexp, return new (zone()) ThrowInstr(info.token_pos, info.deopt_id, exception); } -bool FlowGraphDeserializer::ParseCallInfo(SExpList* call, CallInfo* out) { +bool FlowGraphDeserializer::ParseCallInfo(SExpList* call, + CallInfo* out, + intptr_t num_extra_inputs) { ASSERT(out != nullptr); if (auto const len_sexp = @@ -1336,8 +1298,14 @@ bool FlowGraphDeserializer::ParseCallInfo(SExpList* call, CallInfo* out) { // Type arguments are wrapped in a TypeArguments array, so no matter how // many there are, they are contained in a single pushed argument. auto const all_args_len = (out->type_args_len > 0 ? 1 : 0) + out->args_len; - out->arguments = FetchPushedArguments(call, all_args_len); - if (out->arguments == nullptr) return false; + + const intptr_t num_inputs = all_args_len + num_extra_inputs; + out->inputs = new (zone()) InputsArray(zone(), num_inputs); + for (intptr_t i = 0; i < num_inputs; ++i) { + auto const input = ParseValue(Retrieve(call, 1 + i)); + if (input == nullptr) return false; + out->inputs->Add(input); + } return true; } @@ -1435,24 +1403,11 @@ Environment* FlowGraphDeserializer::ParseEnvironment(SExpList* list) { auto const env = new (zone()) Environment(list->Length(), fixed_param_count, *parsed_function_, outer_env); - auto const stack = pushed_stack_map_.LookupValue(current_block_->block_id()); - ASSERT(stack != nullptr); for (intptr_t i = 0; i < list->Length(); i++) { auto const elem_sexp = Retrieve(list, i); if (elem_sexp == nullptr) return nullptr; auto val = ParseValue(elem_sexp, /*allow_pending=*/false); - if (val == nullptr) { - intptr_t index; - if (!ParseSymbolAsPrefixedInt(CheckSymbol(elem_sexp), 'a', &index)) { - StoreError(elem_sexp, "expected value or reference to pushed argument"); - return nullptr; - } - if (index >= stack->length()) { - StoreError(elem_sexp, "out of range index for pushed argument"); - return nullptr; - } - val = new (zone()) Value(stack->At(index)); - } + if (val == nullptr) return nullptr; env->PushValue(val); } @@ -2434,24 +2389,6 @@ bool FlowGraphDeserializer::FixPendingValues(intptr_t index, Definition* def) { return true; } -PushArgumentsArray* FlowGraphDeserializer::FetchPushedArguments(SExpList* list, - intptr_t len) { - auto const stack = pushed_stack_map_.LookupValue(current_block_->block_id()); - ASSERT(stack != nullptr); - auto const stack_len = stack->length(); - if (len > stack_len) { - StoreError(list, "expected %" Pd " pushed arguments, only %" Pd " on stack", - len, stack_len); - return nullptr; - } - auto const arr = new (zone()) PushArgumentsArray(zone(), len); - for (intptr_t i = 0; i < len; i++) { - arr->Add(stack->At(stack_len - len + i)); - } - stack->TruncateTo(stack_len - len); - return arr; -} - BlockEntryInstr* FlowGraphDeserializer::FetchBlock(SExpSymbol* sym) { if (sym == nullptr) return nullptr; intptr_t block_id; @@ -2464,43 +2401,6 @@ BlockEntryInstr* FlowGraphDeserializer::FetchBlock(SExpSymbol* sym) { return entry; } -bool FlowGraphDeserializer::AreStacksConsistent(SExpList* list, - PushStack* curr_stack, - BlockEntryInstr* succ_block) { - auto const curr_stack_len = curr_stack->length(); - for (intptr_t i = 0, n = succ_block->SuccessorCount(); i < n; i++) { - auto const pred_block = succ_block->PredecessorAt(i); - auto const pred_stack = - pushed_stack_map_.LookupValue(pred_block->block_id()); - ASSERT(pred_stack != nullptr); - if (pred_stack->length() != curr_stack_len) { - StoreError(list->At(1), - "current pushed stack has %" Pd - " elements, " - "other pushed stack for B%" Pd " has %" Pd "", - curr_stack_len, pred_block->block_id(), pred_stack->length()); - return false; - } - for (intptr_t i = 0; i < curr_stack_len; i++) { - // Leftover pushed arguments on the stack should come from dominating - // nodes, so they should be the same PushedArgumentInstr no matter the - // predecessor. - if (pred_stack->At(i) != curr_stack->At(i)) { - auto const pred_def = pred_stack->At(i)->value()->definition(); - auto const curr_def = curr_stack->At(i)->value()->definition(); - StoreError(list->At(1), - "current pushed stack has v%" Pd " at position %" Pd - ", " - "other pushed stack for B%" Pd " has v%" Pd "", - curr_def->ssa_temp_index(), i, pred_block->block_id(), - pred_def->ssa_temp_index()); - return false; - } - } - } - return true; -} - #define BASE_CHECK_DEF(name, type) \ SExp##name* FlowGraphDeserializer::Check##name(SExpression* sexp) { \ if (sexp == nullptr) return nullptr; \ diff --git a/runtime/vm/compiler/backend/il_deserializer.h b/runtime/vm/compiler/backend/il_deserializer.h index 08e6103240f..9e8d40b8c44 100644 --- a/runtime/vm/compiler/backend/il_deserializer.h +++ b/runtime/vm/compiler/backend/il_deserializer.h @@ -48,7 +48,6 @@ class FlowGraphDeserializer : ValueObject { root_sexp_(ASSERT_NOTNULL(root)), parsed_function_(pf), block_map_(zone), - pushed_stack_map_(zone), definition_map_(zone), values_map_(zone), recursive_types_map_(zone), @@ -103,7 +102,6 @@ class FlowGraphDeserializer : ValueObject { M(LoadField) \ M(NativeCall) \ M(Parameter) \ - M(PushArgument) \ M(Return) \ M(SpecialParameter) \ M(StaticCall) \ @@ -139,7 +137,6 @@ class FlowGraphDeserializer : ValueObject { bool ParseConstantPool(SExpList* pool); bool ParseEntries(SExpList* list); - using PushStack = ZoneGrowableArray; using BlockWorklist = GrowableArray; // Starts parsing the contents of [list], where the blocks begin at position @@ -231,14 +228,16 @@ class FlowGraphDeserializer : ValueObject { Array& argument_names; intptr_t type_args_len = 0; intptr_t args_len = 0; - PushArgumentsArray* arguments = nullptr; + InputsArray* inputs = nullptr; CompileType* result_type = nullptr; Code::EntryKind entry_kind = Code::EntryKind::kNormal; }; // Helper function for parsing call instructions that returns a structure // of information common to all calls. - bool ParseCallInfo(SExpList* call, CallInfo* out); + bool ParseCallInfo(SExpList* call, + CallInfo* out, + intptr_t num_extra_inputs = 0); // Parses [sexp] as a value form, that is, either the binding name for // a definition as a symbol or the form (value { ... }). @@ -314,25 +313,10 @@ class FlowGraphDeserializer : ValueObject { // Helper function for rebinding values pending on this definition. bool FixPendingValues(intptr_t index, Definition* def); - // Creates a PushArgumentsArray of size [len] from [pushed_stack_] if there - // are enough and pops the fetched arguments from the stack. - // - // The [sexp] argument should be the serialized form of the instruction that - // needs the pushed arguments and is only used for error reporting. - PushArgumentsArray* FetchPushedArguments(SExpList* sexp, intptr_t len); - // Retrieves the block corresponding to the given block ID symbol from // [block_map_]. Assumes all blocks have had their header parsed. BlockEntryInstr* FetchBlock(SExpSymbol* sym); - // Checks that the pushed argument stacks for all predecessors of [succ_block] - // are the same as [curr_stack]. This check ensures that we can choose an - // arbitrary predecessor's pushed argument stack when parsing [succ_block]'s - // contents. [list] is used for error reporting. - bool AreStacksConsistent(SExpList* list, - PushStack* curr_stack, - BlockEntryInstr* succ_block); - // Utility functions for checking the shape of an S-expression. // If these functions return nullptr for a non-null argument, they have the // side effect of setting the stored error message. @@ -370,12 +354,6 @@ class FlowGraphDeserializer : ValueObject { // available via [flow_graph_]. IntMap block_map_; - // Map from block IDs to pushed argument stacks. Used for PushArgument - // instructions, environment parsing, and calls during block parsing. Also - // used to check that the final pushed argument stacks for predecessor blocks - // are consistent when parsing a JoinEntry. - IntMap pushed_stack_map_; - // Map from variable indexes to definitions. IntMap definition_map_; diff --git a/runtime/vm/compiler/backend/il_ia32.cc b/runtime/vm/compiler/backend/il_ia32.cc index 05d18eb6bb8..10f1149a768 100644 --- a/runtime/vm/compiler/backend/il_ia32.cc +++ b/runtime/vm/compiler/backend/il_ia32.cc @@ -82,7 +82,7 @@ LocationSummary* PushArgumentInstr::MakeLocationSummary(Zone* zone, void PushArgumentInstr::EmitNativeCode(FlowGraphCompiler* compiler) { // In SSA mode, we need an explicit push. Nothing to do in non-SSA mode - // where PushArgument is handled by BindInstr::EmitNativeCode. + // where arguments are pushed by their definitions. if (compiler->is_optimizing()) { Location value = locs()->in(0); if (value.IsRegister()) { @@ -885,11 +885,6 @@ Condition RelationalOpInstr::EmitComparisonCode(FlowGraphCompiler* compiler, } } -LocationSummary* NativeCallInstr::MakeLocationSummary(Zone* zone, - bool opt) const { - return MakeCallSummary(zone); -} - void NativeCallInstr::EmitNativeCode(FlowGraphCompiler* compiler) { SetupNative(); Register result = locs()->out(0).reg(); @@ -5354,12 +5349,6 @@ void TruncDivModInstr::EmitNativeCode(FlowGraphCompiler* compiler) { __ SmiTag(EDX); } -LocationSummary* PolymorphicInstanceCallInstr::MakeLocationSummary( - Zone* zone, - bool opt) const { - return MakeCallSummary(zone); -} - LocationSummary* BranchInstr::MakeLocationSummary(Zone* zone, bool opt) const { comparison()->InitializeLocationSummary(zone, opt); // Branches don't produce a result. diff --git a/runtime/vm/compiler/backend/il_printer.cc b/runtime/vm/compiler/backend/il_printer.cc index 04a116f1814..d039bf37506 100644 --- a/runtime/vm/compiler/backend/il_printer.cc +++ b/runtime/vm/compiler/backend/il_printer.cc @@ -489,7 +489,7 @@ void AssertBooleanInstr::PrintOperandsTo(BufferFormatter* f) const { void ClosureCallInstr::PrintOperandsTo(BufferFormatter* f) const { f->Print(" function="); - InputAt(0)->PrintTo(f); + InputAt(InputCount() - 1)->PrintTo(f); f->Print("<%" Pd ">", type_args_len()); for (intptr_t i = 0; i < ArgumentCount(); ++i) { f->Print(", "); diff --git a/runtime/vm/compiler/backend/il_serializer.cc b/runtime/vm/compiler/backend/il_serializer.cc index 7ff875c3b04..e1032a2f19d 100644 --- a/runtime/vm/compiler/backend/il_serializer.cc +++ b/runtime/vm/compiler/backend/il_serializer.cc @@ -880,7 +880,7 @@ void FlowGraphSerializer::AddDefinitionExtraInfoToSExp(const Definition* def, SExpression* Definition::ToSExpression(FlowGraphSerializer* s) const { // If we don't have a temp index, then this is a Definition that has no - // usable result, like PushArgumentInstr. + // usable result. const bool binds_name = HasSSATemp() || HasTemp(); // Don't serialize non-binding definitions as definitions unless we either // have Definition-specific extra info or we're in verbose mode. @@ -1126,14 +1126,15 @@ void TailCallInstr::AddOperandsToSExpression(SExpList* sexp, void NativeCallInstr::AddOperandsToSExpression(SExpList* sexp, FlowGraphSerializer* s) const { - if (auto const func = s->DartValueToSExp(function())) { - sexp->Add(func); - } + Instruction::AddOperandsToSExpression(sexp, s); } void NativeCallInstr::AddExtraInfoToSExpression(SExpList* sexp, FlowGraphSerializer* s) const { TemplateDartCall<0>::AddExtraInfoToSExpression(sexp, s); + if (auto const func = s->DartValueToSExp(function())) { + sexp->AddExtra("function", func); + } if (!native_name().IsNull()) { s->AddExtraString(sexp, "name", native_name().ToCString()); } @@ -1142,8 +1143,8 @@ void NativeCallInstr::AddExtraInfoToSExpression(SExpList* sexp, } } -template -void TemplateDartCall::AddExtraInfoToSExpression( +template +void TemplateDartCall::AddExtraInfoToSExpression( SExpList* sexp, FlowGraphSerializer* s) const { Instruction::AddExtraInfoToSExpression(sexp, s); @@ -1162,6 +1163,8 @@ void TemplateDartCall::AddExtraInfoToSExpression( } sexp->AddExtra("arg_names", arg_names_sexp); } + + ASSERT(!HasPushArguments()); } void ClosureCallInstr::AddExtraInfoToSExpression(SExpList* sexp, @@ -1173,15 +1176,17 @@ void ClosureCallInstr::AddExtraInfoToSExpression(SExpList* sexp, void StaticCallInstr::AddOperandsToSExpression(SExpList* sexp, FlowGraphSerializer* s) const { - if (auto const func = s->DartValueToSExp(function())) { - sexp->Add(func); - } + Instruction::AddOperandsToSExpression(sexp, s); } void StaticCallInstr::AddExtraInfoToSExpression(SExpList* sexp, FlowGraphSerializer* s) const { TemplateDartCall<0>::AddExtraInfoToSExpression(sexp, s); + if (auto const func = s->DartValueToSExp(function())) { + sexp->AddExtra("function", func); + } + if (HasICData()) { sexp->AddExtra("ic_data", s->ICDataToSExp(ic_data())); } else if (CallCount() > 0 || FLAG_verbose_flow_graph_serialization) { @@ -1208,9 +1213,7 @@ void StaticCallInstr::AddExtraInfoToSExpression(SExpList* sexp, void InstanceCallInstr::AddOperandsToSExpression(SExpList* sexp, FlowGraphSerializer* s) const { - if (auto const target = s->DartValueToSExp(interface_target())) { - sexp->Add(target); - } + Instruction::AddOperandsToSExpression(sexp, s); } void InstanceCallInstr::AddExtraInfoToSExpression( @@ -1218,6 +1221,10 @@ void InstanceCallInstr::AddExtraInfoToSExpression( FlowGraphSerializer* s) const { TemplateDartCall<0>::AddExtraInfoToSExpression(sexp, s); + if (auto const target = s->DartValueToSExp(interface_target())) { + sexp->AddExtra("interface_target", target); + } + if (HasICData()) { sexp->AddExtra("ic_data", s->ICDataToSExp(ic_data())); } @@ -1254,13 +1261,16 @@ void InstanceCallInstr::AddExtraInfoToSExpression( void PolymorphicInstanceCallInstr::AddOperandsToSExpression( SExpList* sexp, FlowGraphSerializer* s) const { - sexp->Add(instance_call()->ToSExpression(s)); + Instruction::AddOperandsToSExpression(sexp, s); } void PolymorphicInstanceCallInstr::AddExtraInfoToSExpression( SExpList* sexp, FlowGraphSerializer* s) const { - Instruction::AddExtraInfoToSExpression(sexp, s); + TemplateDartCall<0>::AddExtraInfoToSExpression(sexp, s); + // TODO(alexmarkov): figure out how to serialize information from + // inner InstanceCall + // sexp->AddExtra("instance_call", instance_call()->ToSExpression(s)); if (targets().length() > 0 || FLAG_verbose_flow_graph_serialization) { auto elem_list = new (s->zone()) SExpList(s->zone()); for (intptr_t i = 0; i < targets().length(); i++) { @@ -1449,29 +1459,11 @@ void CompileType::AddExtraInfoToSExpression(SExpList* sexp, } } -// TODO(@sstrickl): find a better way, store stack index? -static intptr_t CountArgs(Environment* env) { - if (env != nullptr) { - intptr_t arg_count = CountArgs(env->outer()); - for (intptr_t i = 0, n = env->Length(); i < n; ++i) { - if (env->ValueAt(i)->definition()->IsPushArgument()) { - arg_count++; - } - } - return arg_count; - } - return 0; -} - SExpression* Environment::ToSExpression(FlowGraphSerializer* s) const { auto sexp = new (s->zone()) SExpList(s->zone()); - intptr_t arg_count = CountArgs(outer_); for (intptr_t i = 0; i < values_.length(); ++i) { - if (values_[i]->definition()->IsPushArgument()) { - s->AddSymbol(sexp, OS::SCreate(s->zone(), "a%" Pd "", arg_count++)); - } else { - sexp->Add(values_[i]->ToSExpression(s)); - } + ASSERT(!values_[i]->definition()->IsPushArgument()); + sexp->Add(values_[i]->ToSExpression(s)); // TODO(sstrickl): This currently assumes that there are no locations in the // environment (e.g. before register allocation). If we ever want to print // out environments on steps after AllocateRegisters, we'll need to handle diff --git a/runtime/vm/compiler/backend/il_x64.cc b/runtime/vm/compiler/backend/il_x64.cc index 1e514229833..43e04ddee3c 100644 --- a/runtime/vm/compiler/backend/il_x64.cc +++ b/runtime/vm/compiler/backend/il_x64.cc @@ -82,7 +82,7 @@ LocationSummary* PushArgumentInstr::MakeLocationSummary(Zone* zone, void PushArgumentInstr::EmitNativeCode(FlowGraphCompiler* compiler) { // In SSA mode, we need an explicit push. Nothing to do in non-SSA mode - // where PushArgument is handled by BindInstr::EmitNativeCode. + // where arguments are pushed by their definitions. if (compiler->is_optimizing()) { Location value = locs()->in(0); if (value.IsRegister()) { @@ -888,11 +888,6 @@ Condition RelationalOpInstr::EmitComparisonCode(FlowGraphCompiler* compiler, } } -LocationSummary* NativeCallInstr::MakeLocationSummary(Zone* zone, - bool opt) const { - return MakeCallSummary(zone); -} - void NativeCallInstr::EmitNativeCode(FlowGraphCompiler* compiler) { SetupNative(); Register result = locs()->out(0).reg(); @@ -5459,12 +5454,6 @@ void TruncDivModInstr::EmitNativeCode(FlowGraphCompiler* compiler) { // in-range arguments, cannot create out-of-range result. } -LocationSummary* PolymorphicInstanceCallInstr::MakeLocationSummary( - Zone* zone, - bool opt) const { - return MakeCallSummary(zone); -} - LocationSummary* BranchInstr::MakeLocationSummary(Zone* zone, bool opt) const { comparison()->InitializeLocationSummary(zone, opt); // Branches don't produce a result. diff --git a/runtime/vm/compiler/backend/inliner.cc b/runtime/vm/compiler/backend/inliner.cc index 928b09f4b22..91c189642c7 100644 --- a/runtime/vm/compiler/backend/inliner.cc +++ b/runtime/vm/compiler/backend/inliner.cc @@ -203,6 +203,9 @@ class GraphInfoCollector : public ValueObject { // PushArgument instructions are eliminated. if (current->IsAllocateObject()) { instruction_count_ += current->InputCount(); + } else if (current->ArgumentCount() > 0) { + ASSERT(!current->HasPushArguments()); + instruction_count_ += current->ArgumentCount(); } if (current->IsInstanceCall() || current->IsStaticCall() || current->IsClosureCall()) { @@ -1360,13 +1363,7 @@ class CallSiteInliner : public ValueObject { ReplaceParameterStubs(zone(), caller_graph_, call_data, NULL); - // Remove push arguments of the call. - Definition* call = call_data->call; - for (intptr_t i = 0; i < call->ArgumentCount(); ++i) { - PushArgumentInstr* push = call->PushArgumentAt(i); - push->ReplaceUsesWith(push->value()->definition()); - push->RemoveFromGraph(); - } + ASSERT(!call_data->call->HasPushArguments()); } static intptr_t CountConstants(const GrowableArray& arguments) { @@ -2054,16 +2051,10 @@ TargetEntryInstr* PolymorphicInliner::BuildDecisionGraph() { } } + ASSERT(!call_->HasPushArguments()); + // Handle any non-inlined variants. if (!non_inlined_variants_->is_empty()) { - // Move push arguments of the call. - for (intptr_t i = 0; i < call_->ArgumentCount(); ++i) { - PushArgumentInstr* push = call_->PushArgumentAt(i); - push->ReplaceUsesWith(push->value()->definition()); - push->previous()->LinkTo(push->next()); - cursor->LinkTo(push); - cursor = push; - } PolymorphicInstanceCallInstr* fallback_call = PolymorphicInstanceCallInstr::FromCall(Z, call_, *non_inlined_variants_, call_->complete()); @@ -2077,16 +2068,8 @@ TargetEntryInstr* PolymorphicInliner::BuildDecisionGraph() { fallback_call); AppendInstruction(AppendInstruction(cursor, fallback_call), fallback_return); - fallback_call->RepairPushArgsInEnvironment(); exit_collector_->AddExit(fallback_return); cursor = nullptr; - } else { - // Remove push arguments of the call. - for (intptr_t i = 0; i < call_->ArgumentCount(); ++i) { - PushArgumentInstr* push = call_->PushArgumentAt(i); - push->ReplaceUsesWith(push->value()->definition()); - push->RemoveFromGraph(); - } } return entry; } @@ -3365,12 +3348,8 @@ bool FlowGraphInliner::TryReplaceInstanceCallWithInline( flow_graph->AddExactnessGuard(call, receiver_cid); } - // Remove the original push arguments. - for (intptr_t i = 0; i < call->ArgumentCount(); ++i) { - PushArgumentInstr* push = call->PushArgumentAt(i); - push->ReplaceUsesWith(push->value()->definition()); - push->RemoveFromGraph(); - } + ASSERT(!call->HasPushArguments()); + // Replace all uses of this definition with the result. if (call->HasUses()) { ASSERT(result != nullptr && result->HasSSATemp()); @@ -3419,12 +3398,7 @@ bool FlowGraphInliner::TryReplaceStaticCallWithInline( ASSERT((last != nullptr && result != nullptr) || (call->function().recognized_kind() == MethodRecognizer::kObjectConstructor)); - // Remove the original push arguments. - for (intptr_t i = 0; i < call->ArgumentCount(); ++i) { - PushArgumentInstr* push = call->PushArgumentAt(i); - push->ReplaceUsesWith(push->value()->definition()); - push->RemoveFromGraph(); - } + ASSERT(!call->HasPushArguments()); // Replace all uses of this definition with the result. if (call->HasUses()) { ASSERT(result->HasSSATemp()); diff --git a/runtime/vm/compiler/backend/redundancy_elimination.cc b/runtime/vm/compiler/backend/redundancy_elimination.cc index 7754486878d..1f008233f9e 100644 --- a/runtime/vm/compiler/backend/redundancy_elimination.cc +++ b/runtime/vm/compiler/backend/redundancy_elimination.cc @@ -1045,8 +1045,7 @@ class AliasedSet : public ZoneAllocated { for (Value* use = defn->input_use_list(); use != NULL; use = use->next_use()) { Instruction* instr = use->instruction(); - if (instr->IsPushArgument() || instr->IsCheckedSmiOp() || - instr->IsCheckedSmiComparison() || + if (instr->HasUnknownSideEffects() || (instr->IsStoreIndexed() && (use->use_index() == StoreIndexedInstr::kValuePos)) || instr->IsStoreStaticField() || instr->IsPhi()) { @@ -2831,9 +2830,7 @@ void AllocationSinking::EliminateAllocation(Definition* alloc) { alloc->RemoveFromGraph(); if (alloc->ArgumentCount() > 0) { ASSERT(alloc->ArgumentCount() == 1); - for (intptr_t i = 0; i < alloc->ArgumentCount(); ++i) { - alloc->PushArgumentAt(i)->RemoveFromGraph(); - } + ASSERT(!alloc->HasPushArguments()); } } @@ -3703,6 +3700,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()); // TODO(alexmarkov): take control dependencies into account and // eliminate dead branches/conditions. if (!CanEliminateInstruction(current, block)) { @@ -3739,9 +3737,7 @@ void DeadCodeElimination::EliminateDeadCode(FlowGraph* flow_graph) { for (Environment::DeepIterator it(current->env()); !it.Done(); it.Advance()) { Definition* input = it.CurrentValue()->definition(); - if (PushArgumentInstr* push_argument = input->AsPushArgument()) { - input = push_argument->value()->definition(); - } + ASSERT(!input->IsPushArgument()); if (input->HasSSATemp() && !live.Contains(input->ssa_temp_index())) { worklist.Add(input); live.Add(input->ssa_temp_index()); @@ -3768,39 +3764,13 @@ void DeadCodeElimination::EliminateDeadCode(FlowGraph* flow_graph) { if (!CanEliminateInstruction(current, block)) { continue; } - // Remove push arguments that correspond to non-live definitions. For - // example, if a call is removed but some of its PushArguments are also - // have environmental uses in other instructions, then those PushArguments - // linger in the graph. However, currently we only run DCE after the - // EliminateEnvironments pass, so we are guaranteed those PushArguments - // now have no uses. - // - // TODO(dartbug.com/39767): A better solution is to be able to remove - // these push arguments as soon as they go dead (i.e., during environment - // elimination) To do this, we'd need a way to go from PushArguments to - // the call in which they appear as an argument (if any), but we don't - // currently have that, so this fix papers over that for now. - if (auto const push_arg = current->AsPushArgument()) { - auto const def = push_arg->value()->definition(); - ASSERT(def->HasSSATemp()); - if (live.Contains(def->ssa_temp_index())) { - continue; - } - } + ASSERT(!current->IsPushArgument()); + ASSERT((current->ArgumentCount() == 0) || !current->HasPushArguments()); if (Definition* def = current->AsDefinition()) { if (def->HasSSATemp() && live.Contains(def->ssa_temp_index())) { continue; } } - // Remove PushArgument instructions corresponding to 'current'. - for (intptr_t i = 0, n = current->ArgumentCount(); i < n; ++i) { - PushArgumentInstr* push_arg = current->PushArgumentAt(i); - // If the definition referenced by a push argument to dead code is also - // dead, then we may have already removed it. - if (push_arg->previous() == nullptr) continue; - push_arg->ReplaceUsesWith(push_arg->value()->definition()); - push_arg->RemoveFromGraph(); - } current->UnuseAllInputs(); it.RemoveCurrentFromGraph(); } diff --git a/runtime/vm/compiler/backend/redundancy_elimination_test.cc b/runtime/vm/compiler/backend/redundancy_elimination_test.cc index 97edbe958c6..63916ddc33f 100644 --- a/runtime/vm/compiler/backend/redundancy_elimination_test.cc +++ b/runtime/vm/compiler/backend/redundancy_elimination_test.cc @@ -291,7 +291,7 @@ static void TestAliasingViaRedefinition( auto b1 = H.flow_graph()->graph_entry()->normal_entry(); AllocateObjectInstr* v0; LoadFieldInstr* v1; - PushArgumentInstr* push_v1; + StaticCallInstr* call; LoadFieldInstr* v4; ReturnInstr* ret; @@ -303,15 +303,12 @@ static void TestAliasingViaRedefinition( v1 = builder.AddDefinition( new LoadFieldInstr(new Value(v0), slot, TokenPosition::kNoSource)); auto v2 = builder.AddDefinition(make_redefinition(&S, H.flow_graph(), v0)); - auto args = new PushArgumentsArray(2); - push_v1 = builder.AddInstruction(new PushArgumentInstr(new Value(v1))); - args->Add(push_v1); + auto args = new InputsArray(2); + args->Add(new Value(v1)); if (make_it_escape) { - auto push_v2 = - builder.AddInstruction(new PushArgumentInstr(new Value(v2))); - args->Add(push_v2); + args->Add(new Value(v2)); } - builder.AddInstruction(new StaticCallInstr( + call = builder.AddInstruction(new StaticCallInstr( TokenPosition::kNoSource, blackhole, 0, Array::empty_array(), args, S.GetNextDeoptId(), 0, ICData::RebindRule::kStatic)); v4 = builder.AddDefinition( @@ -332,8 +329,7 @@ static void TestAliasingViaRedefinition( // v1 should have been removed from the graph and replaced with constant_null. EXPECT_PROPERTY(v1, it.next() == nullptr && it.previous() == nullptr); - EXPECT_PROPERTY(push_v1, - it.value()->definition() == H.flow_graph()->constant_null()); + EXPECT_PROPERTY(call, it.ArgumentAt(0) == H.flow_graph()->constant_null()); if (make_it_escape) { // v4 however should not be removed from the graph, because v0 escapes into @@ -467,7 +463,7 @@ static void TestAliasingViaStore( AllocateObjectInstr* v0; AllocateObjectInstr* v5; LoadFieldInstr* v1; - PushArgumentInstr* push_v1; + StaticCallInstr* call; LoadFieldInstr* v4; ReturnInstr* ret; @@ -486,22 +482,19 @@ static void TestAliasingViaStore( v1 = builder.AddDefinition( new LoadFieldInstr(new Value(v0), slot, TokenPosition::kNoSource)); auto v2 = builder.AddDefinition(make_redefinition(&S, H.flow_graph(), v5)); - push_v1 = builder.AddInstruction(new PushArgumentInstr(new Value(v1))); - auto args = new PushArgumentsArray(2); - args->Add(push_v1); + auto args = new InputsArray(2); + args->Add(new Value(v1)); if (make_it_escape) { auto v6 = builder.AddDefinition( new LoadFieldInstr(new Value(v2), slot, TokenPosition::kNoSource)); - auto push_v6 = - builder.AddInstruction(new PushArgumentInstr(new Value(v6))); - args->Add(push_v6); + args->Add(new Value(v6)); } else if (make_host_escape) { builder.AddInstruction(new StoreInstanceFieldInstr( slot, new Value(v2), new Value(v0), kEmitStoreBarrier, TokenPosition::kNoSource)); - args->Add(builder.AddInstruction(new PushArgumentInstr(new Value(v5)))); + args->Add(new Value(v5)); } - builder.AddInstruction(new StaticCallInstr( + call = builder.AddInstruction(new StaticCallInstr( TokenPosition::kNoSource, blackhole, 0, Array::empty_array(), args, S.GetNextDeoptId(), 0, ICData::RebindRule::kStatic)); v4 = builder.AddDefinition( @@ -528,8 +521,7 @@ static void TestAliasingViaStore( // v1 should have been removed from the graph and replaced with constant_null. EXPECT_PROPERTY(v1, it.next() == nullptr && it.previous() == nullptr); - EXPECT_PROPERTY(push_v1, - it.value()->definition() == H.flow_graph()->constant_null()); + EXPECT_PROPERTY(call, it.ArgumentAt(0) == H.flow_graph()->constant_null()); if (make_it_escape || make_host_escape) { // v4 however should not be removed from the graph, because v0 escapes into diff --git a/runtime/vm/compiler/backend/type_propagator_test.cc b/runtime/vm/compiler/backend/type_propagator_test.cc index 77272f1c3bf..02a82c8ba02 100644 --- a/runtime/vm/compiler/backend/type_propagator_test.cc +++ b/runtime/vm/compiler/backend/type_propagator_test.cc @@ -230,7 +230,7 @@ ISOLATE_UNIT_TEST_CASE(TypePropagator_Refinement) { new StaticCallInstr(TokenPosition::kNoSource, target_func, /*type_args_len=*/0, /*argument_names=*/Array::empty_array(), - new PushArgumentsArray(0), S.GetNextDeoptId(), + new InputsArray(0), S.GetNextDeoptId(), /*call_count=*/0, ICData::RebindRule::kStatic)); builder.AddInstruction(new GotoInstr(b4, S.GetNextDeoptId())); } diff --git a/runtime/vm/compiler/call_specializer.cc b/runtime/vm/compiler/call_specializer.cc index 9e438387f45..7535d0e222e 100644 --- a/runtime/vm/compiler/call_specializer.cc +++ b/runtime/vm/compiler/call_specializer.cc @@ -208,12 +208,7 @@ void CallSpecializer::SpecializePolymorphicInstanceCall( void CallSpecializer::ReplaceCallWithResult(Definition* call, Instruction* replacement, Definition* result) { - // Remove the original push arguments. - for (intptr_t i = 0; i < call->ArgumentCount(); ++i) { - PushArgumentInstr* push = call->PushArgumentAt(i); - push->ReplaceUsesWith(push->value()->definition()); - push->RemoveFromGraph(); - } + ASSERT(!call->HasPushArguments()); if (result == nullptr) { ASSERT(replacement->IsDefinition()); call->ReplaceWith(replacement->AsDefinition(), current_iterator()); @@ -1304,11 +1299,7 @@ void CallSpecializer::ReplaceWithInstanceOf(InstanceCallInstr* call) { // One result only. AddReceiverCheck(call); ConstantInstr* bool_const = flow_graph()->GetConstant(as_bool); - for (intptr_t i = 0; i < call->ArgumentCount(); ++i) { - PushArgumentInstr* push = call->PushArgumentAt(i); - push->ReplaceUsesWith(push->value()->definition()); - push->RemoveFromGraph(); - } + ASSERT(!call->HasPushArguments()); call->ReplaceUsesWith(bool_const); ASSERT(current_iterator()->Current() == call); current_iterator()->RemoveCurrentFromGraph(); diff --git a/runtime/vm/compiler/compiler_pass.cc b/runtime/vm/compiler/compiler_pass.cc index ae48bcb704f..82f1c16340e 100644 --- a/runtime/vm/compiler/compiler_pass.cc +++ b/runtime/vm/compiler/compiler_pass.cc @@ -493,6 +493,7 @@ COMPILER_PASS(AllocationSinking_DetachMaterializations, { }); COMPILER_PASS(AllocateRegisters, { + flow_graph->InsertPushArguments(); // Ensure loop hierarchy has been computed. flow_graph->GetLoopHierarchy(); // Perform register allocation on the SSA graph. diff --git a/runtime/vm/compiler/frontend/base_flow_graph_builder.cc b/runtime/vm/compiler/frontend/base_flow_graph_builder.cc index 6e5c7e85502..dd865889929 100644 --- a/runtime/vm/compiler/frontend/base_flow_graph_builder.cc +++ b/runtime/vm/compiler/frontend/base_flow_graph_builder.cc @@ -434,13 +434,6 @@ Fragment BaseFlowGraphBuilder::NullConstant() { return Constant(Instance::ZoneHandle(Z, Instance::null())); } -Fragment BaseFlowGraphBuilder::PushArgument() { - PushArgumentInstr* argument = new (Z) PushArgumentInstr(Pop()); - Push(argument); - ++pending_argument_count_; - return Fragment(argument); -} - Fragment BaseFlowGraphBuilder::GuardFieldLength(const Field& field, intptr_t deopt_id) { return Fragment(new (Z) GuardFieldLengthInstr(Pop(), field, deopt_id)); @@ -622,9 +615,7 @@ LocalVariable* BaseFlowGraphBuilder::MakeTemporary() { // will not be cleared (causing them to never be materialized in the // expression stack and skew stack depth). for (Value* item = stack_; item != nullptr; item = item->next_use()) { - if (!item->definition()->IsPushArgument()) { - item->definition()->set_ssa_temp_index(0); - } + item->definition()->set_ssa_temp_index(0); } return variable; @@ -719,18 +710,12 @@ JoinEntryInstr* BaseFlowGraphBuilder::BuildJoinEntry() { GetNextDeoptId(), GetStackDepth()); } -ArgumentArray BaseFlowGraphBuilder::GetArguments(int count) { - ArgumentArray arguments = - new (Z) ZoneGrowableArray(Z, count); +InputsArray* BaseFlowGraphBuilder::GetArguments(int count) { + InputsArray* arguments = new (Z) ZoneGrowableArray(Z, count); arguments->SetLength(count); for (intptr_t i = count - 1; i >= 0; --i) { - ASSERT(stack_->definition()->IsPushArgument()); - ASSERT(!stack_->definition()->HasSSATemp()); - arguments->data()[i] = stack_->definition()->AsPushArgument(); - Drop(); + arguments->data()[i] = Pop(); } - pending_argument_count_ -= count; - ASSERT(pending_argument_count_ >= 0); return arguments; } @@ -1035,11 +1020,8 @@ Fragment BaseFlowGraphBuilder::BuildEntryPointsIntrospection() { Fragment call_hook; call_hook += Constant(closure); - call_hook += PushArgument(); call_hook += Constant(function_name); - call_hook += PushArgument(); call_hook += LoadLocal(entry_point_num); - call_hook += PushArgument(); call_hook += Constant(Function::ZoneHandle(Z, closure.function())); call_hook += ClosureCall(TokenPosition::kNoSource, /*type_args_len=*/0, /*argument_count=*/3, @@ -1054,14 +1036,12 @@ Fragment BaseFlowGraphBuilder::ClosureCall(TokenPosition position, intptr_t argument_count, const Array& argument_names, bool is_statically_checked) { - Value* function = Pop(); - const intptr_t total_count = argument_count + (type_args_len > 0 ? 1 : 0); - ArgumentArray arguments = GetArguments(total_count); - ClosureCallInstr* call = new (Z) - ClosureCallInstr(function, arguments, type_args_len, argument_names, - position, GetNextDeoptId(), - is_statically_checked ? Code::EntryKind::kUnchecked - : Code::EntryKind::kNormal); + const intptr_t total_count = argument_count + (type_args_len > 0 ? 1 : 0) + 1; + InputsArray* arguments = GetArguments(total_count); + ClosureCallInstr* call = new (Z) ClosureCallInstr( + arguments, type_args_len, argument_names, position, GetNextDeoptId(), + is_statically_checked ? Code::EntryKind::kUnchecked + : Code::EntryKind::kNormal); Push(call); return Fragment(call); } diff --git a/runtime/vm/compiler/frontend/base_flow_graph_builder.h b/runtime/vm/compiler/frontend/base_flow_graph_builder.h index 17554e9666e..55af9c7985c 100644 --- a/runtime/vm/compiler/frontend/base_flow_graph_builder.h +++ b/runtime/vm/compiler/frontend/base_flow_graph_builder.h @@ -106,8 +106,6 @@ class TestFragment { SuccessorAddressArray* false_successor_addresses = nullptr; }; -typedef ZoneGrowableArray* ArgumentArray; - // Indicates which form of the unchecked entrypoint we are compiling. // // kNone: @@ -154,7 +152,6 @@ class BaseFlowGraphBuilder { current_try_index_(kInvalidTryIndex), next_used_try_index_(0), stack_(NULL), - pending_argument_count_(0), exit_collector_(exit_collector), inlining_unchecked_entry_(inlining_unchecked_entry) {} @@ -233,8 +230,7 @@ class BaseFlowGraphBuilder { // LocalVariable* MakeTemporary(); - Fragment PushArgument(); - ArgumentArray GetArguments(int count); + InputsArray* GetArguments(int count); TargetEntryInstr* BuildTargetEntry(); FunctionEntryInstr* BuildFunctionEntry(GraphEntryInstr* graph_entry); @@ -432,7 +428,6 @@ class BaseFlowGraphBuilder { intptr_t next_used_try_index_; Value* stack_; - intptr_t pending_argument_count_; InlineExitCollector* exit_collector_; const bool inlining_unchecked_entry_; diff --git a/runtime/vm/compiler/frontend/bytecode_flow_graph_builder.cc b/runtime/vm/compiler/frontend/bytecode_flow_graph_builder.cc index e5461257088..98a38efbcd0 100644 --- a/runtime/vm/compiler/frontend/bytecode_flow_graph_builder.cc +++ b/runtime/vm/compiler/frontend/bytecode_flow_graph_builder.cc @@ -434,31 +434,6 @@ bool BytecodeFlowGraphBuilder::IsStackEmpty() const { return B->GetStackDepth() == 0; } -ArgumentArray BytecodeFlowGraphBuilder::GetArguments(int count) { - ArgumentArray arguments = - new (Z) ZoneGrowableArray(Z, count); - arguments->SetLength(count); - for (intptr_t i = count - 1; i >= 0; --i) { - ASSERT(!IsStackEmpty()); - Definition* arg_def = B->stack_->definition(); - ASSERT(arg_def->temp_index() >= i); - - PushArgumentInstr* argument = new (Z) PushArgumentInstr(Pop()); - - if (code_.current == arg_def) { - code_ <<= argument; - } else { - Instruction* next = arg_def->next(); - ASSERT(next != nullptr); - arg_def->LinkTo(argument); - argument->LinkTo(next); - } - - arguments->data()[i] = argument; - } - return arguments; -} - InferredTypeMetadata BytecodeFlowGraphBuilder::GetInferredType(intptr_t pc) { ASSERT(!inferred_types_attribute_.IsNull()); intptr_t i = inferred_types_index_; @@ -890,7 +865,7 @@ void BytecodeFlowGraphBuilder::BuildDirectCallCommon(bool is_unchecked_call) { Array::Cast(ConstantAt(DecodeOperandD(), 1).value()); const ArgumentsDescriptor arg_desc(arg_desc_array); - ArgumentArray arguments = GetArguments(argc); + InputsArray* arguments = B->GetArguments(argc); StaticCallInstr* call = new (Z) StaticCallInstr( position_, target, arg_desc.TypeArgsLen(), @@ -970,7 +945,7 @@ void BytecodeFlowGraphBuilder::BuildInterfaceCallCommon( &checked_argument_count); const intptr_t argc = DecodeOperandF().value(); - const ArgumentArray arguments = GetArguments(argc); + InputsArray* arguments = B->GetArguments(argc); InstanceCallInstr* call = new (Z) InstanceCallInstr( position_, name, token_kind, arguments, arg_desc.TypeArgsLen(), @@ -1036,12 +1011,11 @@ void BytecodeFlowGraphBuilder::BuildUncheckedClosureCall() { /*clear_temp=*/false); code_ += B->LoadNativeField(Slot::Closure_function()); - Value* function = Pop(); - const ArgumentArray arguments = GetArguments(argc); + InputsArray* arguments = B->GetArguments(argc + 1); ClosureCallInstr* call = new (Z) ClosureCallInstr( - function, arguments, arg_desc.TypeArgsLen(), + arguments, arg_desc.TypeArgsLen(), Array::ZoneHandle(Z, arg_desc.GetArgumentNames()), position_, B->GetNextDeoptId(), Code::EntryKind::kUnchecked); @@ -1074,7 +1048,7 @@ void BytecodeFlowGraphBuilder::BuildDynamicCall() { &checked_argument_count); const intptr_t argc = DecodeOperandF().value(); - const ArgumentArray arguments = GetArguments(argc); + InputsArray* arguments = B->GetArguments(argc); const Function& interface_target = Function::null_function(); @@ -1105,7 +1079,7 @@ void BytecodeFlowGraphBuilder::BuildNativeCall() { const auto& name = String::ZoneHandle(Z, function().native_name()); const intptr_t num_args = function().NumParameters() + (function().IsGeneric() ? 1 : 0); - ArgumentArray arguments = GetArguments(num_args); + InputsArray* arguments = B->GetArguments(num_args); auto* call = new (Z) NativeCallInstr(&name, &function(), FLAG_link_natives_lazily, function().end_token_pos(), arguments); @@ -1783,7 +1757,7 @@ void BytecodeFlowGraphBuilder::BuildPrimitiveOp( // A DebugStepCheck is performed as part of the calling stub. LoadStackSlots(num_args); - const ArgumentArray arguments = GetArguments(num_args); + InputsArray* arguments = B->GetArguments(num_args); InstanceCallInstr* call = new (Z) InstanceCallInstr( position_, name, token_kind, arguments, 0, Array::null_array(), num_args, diff --git a/runtime/vm/compiler/frontend/bytecode_flow_graph_builder.h b/runtime/vm/compiler/frontend/bytecode_flow_graph_builder.h index 2739cb6bdbe..03a19ab3a70 100644 --- a/runtime/vm/compiler/frontend/bytecode_flow_graph_builder.h +++ b/runtime/vm/compiler/frontend/bytecode_flow_graph_builder.h @@ -159,7 +159,6 @@ class BytecodeFlowGraphBuilder { Value* Pop(); intptr_t GetStackDepth() const; bool IsStackEmpty() const; - ArgumentArray GetArguments(int count); InferredTypeMetadata GetInferredType(intptr_t pc); void PropagateStackState(intptr_t target_pc); void DropUnusedValuesFromStack(); diff --git a/runtime/vm/compiler/frontend/kernel_binary_flowgraph.cc b/runtime/vm/compiler/frontend/kernel_binary_flowgraph.cc index ae84ac85ac9..b4f6ad20f2d 100644 --- a/runtime/vm/compiler/frontend/kernel_binary_flowgraph.cc +++ b/runtime/vm/compiler/frontend/kernel_binary_flowgraph.cc @@ -364,7 +364,6 @@ Fragment StreamingFlowGraphBuilder::BuildInitializers( ReadCanonicalNameReference(); // read target_reference. instructions += LoadLocal(parsed_function()->receiver_var()); - instructions += PushArgument(); // TODO(jensj): ASSERT(init->arguments()->types().length() == 0); Array& argument_names = Array::ZoneHandle(Z); @@ -391,7 +390,6 @@ Fragment StreamingFlowGraphBuilder::BuildInitializers( ReadCanonicalNameReference(); // read target_reference. instructions += LoadLocal(parsed_function()->receiver_var()); - instructions += PushArgument(); // TODO(jensj): ASSERT(init->arguments()->types().length() == 0); Array& argument_names = Array::ZoneHandle(Z); @@ -535,7 +533,6 @@ Fragment StreamingFlowGraphBuilder::SetAsyncStackTrace( Fragment code; code += LoadLocal(async_stack_trace_var); - code += PushArgument(); // Call _asyncSetThreadStackTrace code += StaticCall(TokenPosition::kNoSource, target, /* argument_count = */ 1, ICData::kStatic); @@ -560,15 +557,14 @@ Fragment StreamingFlowGraphBuilder::TypeArgumentsHandling( if (dart_function.IsGeneric()) { prologue += LoadLocal(fn_type_args); - prologue += PushArgument(); + prologue += LoadLocal(closure); prologue += LoadNativeField(Slot::Closure_function_type_arguments()); - prologue += PushArgument(); + prologue += IntConstant(dart_function.NumParentTypeParameters()); - prologue += PushArgument(); + prologue += IntConstant(dart_function.NumTypeParameters() + dart_function.NumParentTypeParameters()); - prologue += PushArgument(); const Library& dart_internal = Library::Handle(Z, Library::InternalLibrary()); @@ -1627,10 +1623,6 @@ Fragment StreamingFlowGraphBuilder::Return(TokenPosition position, yield_index); } -Fragment StreamingFlowGraphBuilder::PushArgument() { - return flow_graph_builder_->PushArgument(); -} - Fragment StreamingFlowGraphBuilder::EvaluateAssertion() { return flow_graph_builder_->EvaluateAssertion(); } @@ -2059,9 +2051,7 @@ const TypeArguments& StreamingFlowGraphBuilder::BuildTypeArguments() { Fragment StreamingFlowGraphBuilder::BuildArguments(Array* argument_names, intptr_t* argument_count, - intptr_t* positional_count, - bool skip_push_arguments, - bool do_drop) { + intptr_t* positional_count) { intptr_t dummy; if (argument_count == NULL) argument_count = &dummy; *argument_count = ReadUInt(); // read arguments count. @@ -2074,22 +2064,17 @@ Fragment StreamingFlowGraphBuilder::BuildArguments(Array* argument_names, if (positional_count == NULL) positional_count = &dummy; *positional_count = ReadListLength(); // read length of expression list } - return BuildArgumentsFromActualArguments(argument_names, skip_push_arguments, - do_drop); + return BuildArgumentsFromActualArguments(argument_names); } Fragment StreamingFlowGraphBuilder::BuildArgumentsFromActualArguments( - Array* argument_names, - bool skip_push_arguments, - bool do_drop) { + Array* argument_names) { Fragment instructions; // List of positional. intptr_t list_length = ReadListLength(); // read list length. for (intptr_t i = 0; i < list_length; ++i) { instructions += BuildExpression(); // read ith expression. - if (!skip_push_arguments) instructions += PushArgument(); - if (do_drop) instructions += Drop(); } // List of named. @@ -2101,8 +2086,6 @@ Fragment StreamingFlowGraphBuilder::BuildArgumentsFromActualArguments( String& name = H.DartSymbolObfuscate(ReadStringReference()); // read ith name index. instructions += BuildExpression(); // read ith expression. - if (!skip_push_arguments) instructions += PushArgument(); - if (do_drop) instructions += Drop(); if (argument_names != NULL) { argument_names->SetAt(i, name); } @@ -2270,8 +2253,6 @@ Fragment StreamingFlowGraphBuilder::BuildPropertyGet(TokenPosition* p) { instructions += LoadLocal(receiver); } - instructions += PushArgument(); - const String& getter_name = ReadNameAsGetterName(); // read name. const Function* interface_target = &Function::null_function(); @@ -2346,13 +2327,10 @@ Fragment StreamingFlowGraphBuilder::BuildPropertySet(TokenPosition* p) { instructions += LoadLocal(receiver); } - instructions += PushArgument(); - const String& setter_name = ReadNameAsSetterName(); // read name. instructions += BuildExpression(); // read value. instructions += StoreLocal(TokenPosition::kNoSource, variable); - instructions += PushArgument(); const Function* interface_target = &Function::null_function(); const NameIndex itarget_name = @@ -2443,27 +2421,22 @@ Fragment StreamingFlowGraphBuilder::BuildAllocateInvocationMirrorCall( // First argument is receiver. instructions += LoadLocal(parsed_function()->receiver_var()); - instructions += PushArgument(); // Push the arguments for allocating the invocation mirror: // - the name. instructions += Constant(String::ZoneHandle(Z, name.raw())); - instructions += PushArgument(); // - the arguments descriptor. const Array& args_descriptor = Array::Handle(Z, ArgumentsDescriptor::New(num_type_arguments, num_arguments, argument_names)); instructions += Constant(Array::ZoneHandle(Z, args_descriptor.raw())); - instructions += PushArgument(); // - an array containing the actual arguments. instructions += LoadLocal(actuals_array); - instructions += PushArgument(); // - [true] indicating this is a `super` NoSuchMethod. instructions += Constant(Bool::True()); - instructions += PushArgument(); const Class& mirror_class = Class::Handle(Z, Library::LookupCoreClass(Symbols::InvocationMirror())); @@ -2531,7 +2504,6 @@ Fragment StreamingFlowGraphBuilder::BuildSuperPropertyGet(TokenPosition* p) { /* num_arguments = */ 1, /* argument_names = */ Object::empty_array(), actuals_array, /* build_rest_of_actuals = */ Fragment()); - instructions += PushArgument(); // second argument is invocation mirror Function& nsm_function = GetNoSuchMethodOrDie(Z, parent_klass); instructions += @@ -2543,7 +2515,6 @@ Fragment StreamingFlowGraphBuilder::BuildSuperPropertyGet(TokenPosition* p) { ASSERT(!function.IsNull()); instructions += LoadLocal(parsed_function()->receiver_var()); - instructions += PushArgument(); instructions += StaticCall(position, Function::ZoneHandle(Z, function.raw()), @@ -2587,7 +2558,6 @@ Fragment StreamingFlowGraphBuilder::BuildSuperPropertySet(TokenPosition* p) { /* num_arguments = */ 2, /* argument_names = */ Object::empty_array(), actuals_array, build_rest_of_actuals); - instructions += PushArgument(); // second argument - invocation mirror SkipCanonicalNameReference(); // skip target_reference. @@ -2600,11 +2570,9 @@ Fragment StreamingFlowGraphBuilder::BuildSuperPropertySet(TokenPosition* p) { } else { // receiver instructions += LoadLocal(parsed_function()->receiver_var()); - instructions += PushArgument(); instructions += BuildExpression(); // read value. instructions += StoreLocal(position, value); - instructions += PushArgument(); SkipCanonicalNameReference(); // skip target_reference. @@ -2665,7 +2633,6 @@ Fragment StreamingFlowGraphBuilder::BuildDirectPropertyGet(TokenPosition* p) { ASSERT(target.IsGetterFunction() || target.IsImplicitGetterFunction()); } - instructions += PushArgument(); // Static calls are marked as "no-rebind", which is currently safe because // DirectPropertyGet are only used in enums (index in toString) and enums // can't change their structure during hot reload. @@ -2683,7 +2650,6 @@ Fragment StreamingFlowGraphBuilder::BuildDirectPropertySet(TokenPosition* p) { LocalVariable* value = MakeTemporary(); instructions += BuildExpression(); // read receiver. - instructions += PushArgument(); const NameIndex target_reference = ReadCanonicalNameReference(); // read target_reference. @@ -2694,7 +2660,6 @@ Fragment StreamingFlowGraphBuilder::BuildDirectPropertySet(TokenPosition* p) { instructions += BuildExpression(); // read value. instructions += StoreLocal(TokenPosition::kNoSource, value); - instructions += PushArgument(); // Static calls are marked as "no-rebind", which is currently safe because // DirectPropertyGet are only used in enums (index in toString) and enums @@ -2789,7 +2754,6 @@ Fragment StreamingFlowGraphBuilder::BuildStaticSet(TokenPosition* p) { LocalVariable* variable = MakeTemporary(); instructions += LoadLocal(variable); if (!setter.IsNull() && field.NeedsSetter()) { - instructions += PushArgument(); instructions += StaticCall(position, setter, 1, ICData::kStatic); instructions += Drop(); } else { @@ -2805,7 +2769,6 @@ Fragment StreamingFlowGraphBuilder::BuildStaticSet(TokenPosition* p) { // Prepare argument. instructions += LoadLocal(variable); - instructions += PushArgument(); // Invoke the setter function. const Function& function = @@ -2866,8 +2829,6 @@ Fragment StreamingFlowGraphBuilder::BuildMethodInvocation(TokenPosition* p) { // type arguments here we need to push it between receiver_temp // and actual receiver. See the code below. type_arguments_temp = MakeTemporary(); - } else { - instructions += PushArgument(); } } type_args_len = list_length; @@ -2891,9 +2852,9 @@ Fragment StreamingFlowGraphBuilder::BuildMethodInvocation(TokenPosition* p) { PeekArgumentsFirstPositionalTag() == kNullLiteral)) { ASSERT(type_args_len == 0); // "==" or "!=" with null on either side. - instructions += BuildArguments(NULL /* named */, NULL /* arg count */, - NULL /* positional arg count */, - true); // read arguments. + instructions += + BuildArguments(NULL /* named */, NULL /* arg count */, + NULL /* positional arg count */); // read arguments. SkipCanonicalNameReference(); // read interface_target_reference. Token::Kind strict_cmp_kind = token_kind == Token::kEQ ? Token::kEQ_STRICT : Token::kNE_STRICT; @@ -2912,13 +2873,10 @@ Fragment StreamingFlowGraphBuilder::BuildMethodInvocation(TokenPosition* p) { // [type_arguments_temp][receiver_temp][type_arguments][receiver] ... // instructions += LoadLocal(type_arguments_temp); - instructions += PushArgument(); } instructions += LoadLocal(receiver_temp); } - instructions += PushArgument(); // push receiver as argument. - intptr_t argument_count; intptr_t positional_argument_count; Array& argument_names = Array::ZoneHandle(Z); @@ -3046,7 +3004,6 @@ Fragment StreamingFlowGraphBuilder::BuildDirectMethodInvocation( const TypeArguments& type_arguments = T.BuildTypeArguments(list_length); // read types. instructions += TranslateInstantiatedTypeArguments(type_arguments); - instructions += PushArgument(); } type_args_len = list_length; } @@ -3066,17 +3023,15 @@ Fragment StreamingFlowGraphBuilder::BuildDirectMethodInvocation( PeekArgumentsFirstPositionalTag() == kNullLiteral)) { ASSERT(type_args_len == 0); // "==" or "!=" with null on either side. - instructions += BuildArguments(NULL /* names */, NULL /* arg count */, - NULL /* positional arg count */, - true); // read arguments. + instructions += + BuildArguments(NULL /* names */, NULL /* arg count */, + NULL /* positional arg count */); // read arguments. Token::Kind strict_cmp_kind = token_kind == Token::kEQ ? Token::kEQ_STRICT : Token::kNE_STRICT; return instructions + StrictCompare(position, strict_cmp_kind, /*number_check = */ true); } - instructions += PushArgument(); // push receiver as argument. - const Function& target = Function::ZoneHandle(Z, H.LookupMethodByMember(kernel_name, method_name)); @@ -3190,7 +3145,6 @@ Fragment StreamingFlowGraphBuilder::BuildSuperMethodInvocation( position, method_name, type_list_length, /* num_arguments = */ argument_count + 1, argument_names, actuals_array, build_rest_of_actuals); - instructions += PushArgument(); // second argument - invocation mirror SkipCanonicalNameReference(); // skip target_reference. @@ -3211,13 +3165,11 @@ Fragment StreamingFlowGraphBuilder::BuildSuperMethodInvocation( const TypeArguments& type_arguments = T.BuildTypeArguments(list_length); // read types. instructions += TranslateInstantiatedTypeArguments(type_arguments); - instructions += PushArgument(); } } // receiver instructions += LoadLocal(parsed_function()->receiver_var()); - instructions += PushArgument(); Array& argument_names = Array::ZoneHandle(Z); intptr_t argument_count; @@ -3304,7 +3256,6 @@ Fragment StreamingFlowGraphBuilder::BuildStaticInvocation(TokenPosition* p) { instance_variable = MakeTemporary(); instructions += LoadLocal(instance_variable); - instructions += PushArgument(); } else if (target.IsFactory()) { // The VM requires currently a TypeArguments object as first parameter for // every factory constructor :-/ ! @@ -3313,7 +3264,6 @@ Fragment StreamingFlowGraphBuilder::BuildStaticInvocation(TokenPosition* p) { // into Kernel. const TypeArguments& type_arguments = PeekArgumentsInstantiatedType(klass); instructions += TranslateInstantiatedTypeArguments(type_arguments); - instructions += PushArgument(); } else if (!special_case) { AlternativeReadingScope alt(&reader_); ReadUInt(); // read argument count. @@ -3322,15 +3272,14 @@ Fragment StreamingFlowGraphBuilder::BuildStaticInvocation(TokenPosition* p) { const TypeArguments& type_arguments = T.BuildTypeArguments(list_length); // read types. instructions += TranslateInstantiatedTypeArguments(type_arguments); - instructions += PushArgument(); } type_args_len = list_length; } Array& argument_names = Array::ZoneHandle(Z); - instructions += BuildArguments(&argument_names, NULL /* arg count */, - NULL /* positional arg count */, - special_case); // read arguments. + instructions += + BuildArguments(&argument_names, NULL /* arg count */, + NULL /* positional arg count */); // read arguments. ASSERT(target.AreValidArguments(NNBDMode::kLegacyLib, type_args_len, argument_count, argument_names, NULL)); @@ -3400,7 +3349,6 @@ Fragment StreamingFlowGraphBuilder::BuildConstructorInvocation( LocalVariable* variable = MakeTemporary(); instructions += LoadLocal(variable); - instructions += PushArgument(); Array& argument_names = Array::ZoneHandle(Z); intptr_t argument_count; @@ -3633,12 +3581,9 @@ Fragment StreamingFlowGraphBuilder::BuildIsExpression(TokenPosition* p) { // Let condition be always true. instructions += Constant(Bool::True()); } else { - instructions += PushArgument(); - // See if simple instanceOf is applicable. if (dart::SimpleInstanceOfType(type)) { instructions += Constant(type); - instructions += PushArgument(); // Type. instructions += InstanceCall( position, Library::PrivateCoreLibName(Symbols::_simpleInstanceOf()), Token::kIS, 2, 2); // 2 checked arguments. @@ -3650,20 +3595,16 @@ Fragment StreamingFlowGraphBuilder::BuildIsExpression(TokenPosition* p) { } else { instructions += NullConstant(); } - instructions += PushArgument(); // Instantiator type arguments. if (!type.IsInstantiated(kFunctions)) { instructions += LoadFunctionTypeArguments(); } else { instructions += NullConstant(); } - instructions += PushArgument(); // Function type arguments. instructions += Constant(type); - instructions += PushArgument(); // Type. instructions += IntConstant(static_cast(nnbd_mode)); - instructions += PushArgument(); // nnbd_mode. instructions += InstanceCall( position, Library::PrivateCoreLibName(Symbols::_instanceOf()), @@ -3771,7 +3712,6 @@ Fragment StreamingFlowGraphBuilder::BuildListLiteral(TokenPosition* p) { LocalVariable* type = MakeTemporary(); instructions += LoadLocal(type); - instructions += PushArgument(); if (length == 0) { instructions += Constant(Object::empty_array()); } else { @@ -3788,7 +3728,6 @@ Fragment StreamingFlowGraphBuilder::BuildListLiteral(TokenPosition* p) { instructions += StoreIndexed(kArrayCid); } } - instructions += PushArgument(); // The array. const Class& factory_class = Class::Handle(Z, Library::LookupCoreClass(Symbols::List())); @@ -3810,7 +3749,6 @@ Fragment StreamingFlowGraphBuilder::BuildMapLiteral(TokenPosition* p) { // The type argument for the factory call `new Map._fromLiteral(List)`. Fragment instructions = TranslateInstantiatedTypeArguments(type_arguments); - instructions += PushArgument(); intptr_t length = ReadListLength(); // read list length. // Note: there will be "length" map entries (i.e. key and value expressions). @@ -3838,7 +3776,6 @@ Fragment StreamingFlowGraphBuilder::BuildMapLiteral(TokenPosition* p) { instructions += StoreIndexed(kArrayCid); } } - instructions += PushArgument(); // The array. const Class& map_class = Class::Handle(Z, Library::LookupCoreClass(Symbols::Map())); @@ -3954,7 +3891,6 @@ Fragment StreamingFlowGraphBuilder::BuildFutureNullValue( Fragment instructions; instructions += BuildNullLiteral(position); - instructions += PushArgument(); instructions += StaticCall(TokenPosition::kNoSource, constructor, /* argument_count = */ 1, ICData::kStatic); return instructions; @@ -4000,9 +3936,7 @@ Fragment StreamingFlowGraphBuilder::BuildPartialTearoffInstantiation( // when the closure is coming from a tearoff of a top-level method or from a // local closure. instructions += LoadLocal(original_closure); - instructions += PushArgument(); instructions += LoadLocal(type_args_vec); - instructions += PushArgument(); const Library& dart_internal = Library::Handle(Z, Library::InternalLibrary()); const Function& bounds_check_function = Function::ZoneHandle( Z, dart_internal.LookupFunctionAllowPrivate( @@ -4137,7 +4071,6 @@ Fragment StreamingFlowGraphBuilder::BuildAssertStatement() { const TokenPosition condition_end_offset = ReadPosition(); // read condition end offset. - instructions += PushArgument(); instructions += EvaluateAssertion(); instructions += CheckBoolean(condition_start_offset); instructions += Constant(Bool::True()); @@ -4157,16 +4090,13 @@ Fragment StreamingFlowGraphBuilder::BuildAssertStatement() { // or Throw). Fragment otherwise_fragment(otherwise); otherwise_fragment += IntConstant(condition_start_offset.Pos()); - otherwise_fragment += PushArgument(); // start otherwise_fragment += IntConstant(condition_end_offset.Pos()); - otherwise_fragment += PushArgument(); // end Tag tag = ReadTag(); // read (first part of) message. if (tag == kSomething) { otherwise_fragment += BuildExpression(); // read (rest of) message. } else { otherwise_fragment += Constant(Instance::ZoneHandle(Z)); // null. } - otherwise_fragment += PushArgument(); // message // Note: condition_start_offset points to the first token after the opening // paren, not the beginning of 'assert'. @@ -4373,7 +4303,6 @@ Fragment StreamingFlowGraphBuilder::BuildForInStatement(bool async) { TokenPosition iterable_position = TokenPosition::kNoSource; Fragment instructions = BuildExpression(&iterable_position); // read iterable. - instructions += PushArgument(); const String& iterator_getter = String::ZoneHandle(Z, Field::GetterSymbol(Symbols::Iterator())); @@ -4386,7 +4315,6 @@ Fragment StreamingFlowGraphBuilder::BuildForInStatement(bool async) { for_in_depth_inc(); loop_depth_inc(); Fragment condition = LoadLocal(iterator); - condition += PushArgument(); condition += InstanceCall(iterable_position, Symbols::MoveNext(), Token::kILLEGAL, 1); TargetEntryInstr* body_entry; @@ -4396,7 +4324,6 @@ Fragment StreamingFlowGraphBuilder::BuildForInStatement(bool async) { Fragment body(body_entry); body += EnterScope(offset); body += LoadLocal(iterator); - body += PushArgument(); const String& current_getter = String::ZoneHandle(Z, Field::GetterSymbol(Symbols::Current())); body += InstanceCall(body_position, current_getter, Token::kGET, 1); @@ -4493,14 +4420,9 @@ Fragment StreamingFlowGraphBuilder::BuildSwitchStatement() { LocalVariable* instance = MakeTemporary(); // Call _FallThroughError._create constructor. - body_fragment += LoadLocal(instance); - body_fragment += PushArgument(); // this - - body_fragment += Constant(url); - body_fragment += PushArgument(); // url - - body_fragment += NullConstant(); - body_fragment += PushArgument(); // line + body_fragment += LoadLocal(instance); // this + body_fragment += Constant(url); // url + body_fragment += NullConstant(); // line body_fragment += StaticCall(TokenPosition::kNoSource, constructor, 3, ICData::kStatic); @@ -4566,9 +4488,7 @@ Fragment StreamingFlowGraphBuilder::BuildSwitchStatement() { TokenPosition position = ReadPosition(); // read jth position. current_instructions += Constant( Instance::ZoneHandle(Z, constant_reader_.ReadConstantExpression())); - current_instructions += PushArgument(); current_instructions += LoadLocal(scopes()->switch_variable); - current_instructions += PushArgument(); current_instructions += InstanceCall(position, Symbols::EqualOperator(), Token::kEQ, /*argument_count=*/2, @@ -4788,24 +4708,24 @@ Fragment StreamingFlowGraphBuilder::BuildTryCatch() { if (type_guard != NULL) { catch_body += LoadLocal(CurrentException()); - catch_body += PushArgument(); // exception + if (!type_guard->IsInstantiated(kCurrentClass)) { catch_body += LoadInstantiatorTypeArguments(); } else { catch_body += NullConstant(); } - catch_body += PushArgument(); // instantiator type arguments + if (!type_guard->IsInstantiated(kFunctions)) { catch_body += LoadFunctionTypeArguments(); } else { catch_body += NullConstant(); } - catch_body += PushArgument(); // function type arguments + catch_body += Constant(*type_guard); - catch_body += PushArgument(); // guard type + const NNBDMode nnbd_mode = parsed_function()->function().nnbd_mode(); catch_body += IntConstant(static_cast(nnbd_mode)); - catch_body += PushArgument(); // nnbd_mode + catch_body += InstanceCall( position, Library::PrivateCoreLibName(Symbols::_instanceOf()), Token::kIS, 5); diff --git a/runtime/vm/compiler/frontend/kernel_binary_flowgraph.h b/runtime/vm/compiler/frontend/kernel_binary_flowgraph.h index 99aeaa024fd..65b29184409 100644 --- a/runtime/vm/compiler/frontend/kernel_binary_flowgraph.h +++ b/runtime/vm/compiler/frontend/kernel_binary_flowgraph.h @@ -158,7 +158,6 @@ class StreamingFlowGraphBuilder : public KernelReaderHelper { Fragment LoadLocal(LocalVariable* variable); Fragment Return(TokenPosition position, intptr_t yield_index = RawPcDescriptors::kInvalidYieldIndex); - Fragment PushArgument(); Fragment EvaluateAssertion(); Fragment RethrowException(TokenPosition position, int catch_try_index); Fragment ThrowNoSuchMethodError(); @@ -268,12 +267,8 @@ class StreamingFlowGraphBuilder : public KernelReaderHelper { const TypeArguments& BuildTypeArguments(); Fragment BuildArguments(Array* argument_names, intptr_t* argument_count, - intptr_t* positional_argument_count, - bool skip_push_arguments = false, - bool do_drop = false); - Fragment BuildArgumentsFromActualArguments(Array* argument_names, - bool skip_push_arguments = false, - bool do_drop = false); + intptr_t* positional_argument_count); + Fragment BuildArgumentsFromActualArguments(Array* argument_names); Fragment BuildInvalidExpression(TokenPosition* position); Fragment BuildVariableGet(TokenPosition* position); diff --git a/runtime/vm/compiler/frontend/kernel_to_il.cc b/runtime/vm/compiler/frontend/kernel_to_il.cc index 6ad928be8df..c7afab66154 100644 --- a/runtime/vm/compiler/frontend/kernel_to_il.cc +++ b/runtime/vm/compiler/frontend/kernel_to_il.cc @@ -336,7 +336,7 @@ Fragment FlowGraphBuilder::InstanceCall( bool use_unchecked_entry, const CallSiteAttributesMetadata* call_site_attrs) { const intptr_t total_count = argument_count + (type_args_len > 0 ? 1 : 0); - ArgumentArray arguments = GetArguments(total_count); + InputsArray* arguments = GetArguments(total_count); InstanceCallInstr* call = new (Z) InstanceCallInstr(position, name, kind, arguments, type_args_len, argument_names, checked_argument_count, ic_data_array_, @@ -469,7 +469,6 @@ Fragment FlowGraphBuilder::LoadLateField(const Field& field, /* argument_count = */ 0, ICData::kStatic); } else { initialize += LoadLocal(instance); - initialize += PushArgument(); initialize += StaticCall(position, init_function, /* argument_count = */ 1, ICData::kStatic); } @@ -510,8 +509,6 @@ Fragment FlowGraphBuilder::ThrowLateInitializationError(TokenPosition position, // Call _LateInitializationError._throwNew. instructions += Constant(name); - instructions += PushArgument(); // name - instructions += StaticCall(position, throw_new, /* argument_count = */ 1, ICData::kStatic); instructions += Drop(); @@ -590,7 +587,7 @@ Fragment FlowGraphBuilder::NativeCall(const String* name, InlineBailout("kernel::FlowGraphBuilder::NativeCall"); const intptr_t num_args = function->NumParameters() + (function->IsGeneric() ? 1 : 0); - ArgumentArray arguments = GetArguments(num_args); + InputsArray* arguments = GetArguments(num_args); NativeCallInstr* call = new (Z) NativeCallInstr(name, function, FLAG_link_natives_lazily, function->end_token_pos(), arguments); @@ -665,7 +662,7 @@ Fragment FlowGraphBuilder::StaticCall(TokenPosition position, intptr_t type_args_count, bool use_unchecked_entry) { const intptr_t total_count = argument_count + (type_args_count > 0 ? 1 : 0); - ArgumentArray arguments = GetArguments(total_count); + InputsArray* arguments = GetArguments(total_count); StaticCallInstr* call = new (Z) StaticCallInstr(position, target, type_args_count, argument_names, arguments, ic_data_array_, GetNextDeoptId(), rebind_rule); @@ -695,7 +692,6 @@ Fragment FlowGraphBuilder::StringInterpolateSingle(TokenPosition position) { cls, Library::PrivateCoreLibName(Symbols::InterpolateSingle()), kTypeArgsLen, kNumberOfArguments, kNoArgumentNames)); Fragment instructions; - instructions += PushArgument(); instructions += StaticCall(position, function, /* argument_count = */ 1, ICData::kStatic); return instructions; @@ -726,20 +722,11 @@ Fragment FlowGraphBuilder::ThrowTypeError() { LocalVariable* instance = MakeTemporary(); // Call _TypeError._create constructor. - instructions += LoadLocal(instance); - instructions += PushArgument(); // this - - instructions += Constant(url); - instructions += PushArgument(); // url - - instructions += NullConstant(); - instructions += PushArgument(); // line - - instructions += IntConstant(0); - instructions += PushArgument(); // column - - instructions += Constant(H.DartSymbolPlain("Malformed type.")); - instructions += PushArgument(); // message + instructions += LoadLocal(instance); // this + instructions += Constant(url); // url + instructions += NullConstant(); // line + instructions += IntConstant(0); // column + instructions += Constant(H.DartSymbolPlain("Malformed type.")); // message instructions += StaticCall(TokenPosition::kNoSource, constructor, /* argument_count = */ 5, ICData::kStatic); @@ -762,23 +749,14 @@ Fragment FlowGraphBuilder::ThrowNoSuchMethodError() { Fragment instructions; // Call NoSuchMethodError._throwNew static function. - instructions += NullConstant(); - instructions += PushArgument(); // receiver + instructions += NullConstant(); // receiver - instructions += Constant(H.DartString("", Heap::kOld)); - instructions += PushArgument(); // memberName - - instructions += IntConstant(-1); - instructions += PushArgument(); // invocation_type - - instructions += NullConstant(); - instructions += PushArgument(); // type arguments - - instructions += NullConstant(); - instructions += PushArgument(); // arguments - - instructions += NullConstant(); - instructions += PushArgument(); // argumentNames + instructions += + Constant(H.DartString("", Heap::kOld)); // memberName + instructions += IntConstant(-1); // invocation_type + instructions += NullConstant(); // type arguments + instructions += NullConstant(); // arguments + instructions += NullConstant(); // argumentNames instructions += StaticCall(TokenPosition::kNoSource, throw_function, /* argument_count = */ 6, ICData::kStatic); @@ -832,11 +810,9 @@ Fragment FlowGraphBuilder::NativeFunctionBody(const Function& function, String& name = String::ZoneHandle(Z, function.native_name()); if (function.IsGeneric()) { body += LoadLocal(parsed_function_->RawTypeArgumentsVariable()); - body += PushArgument(); } for (intptr_t i = 0; i < function.NumParameters(); ++i) { body += LoadLocal(parsed_function_->RawParameterVariable(i)); - body += PushArgument(); } body += NativeCall(&name, &function); // We typecheck results of native calls for type safety. @@ -1096,9 +1072,7 @@ FlowGraph* FlowGraphBuilder::BuildGraphOfRecognizedMethod( Fragment allocate(allocate_non_growable); allocate += LoadLocal(parsed_function_->RawParameterVariable(0)); - allocate += PushArgument(); allocate += LoadLocal(parsed_function_->RawParameterVariable(1)); - allocate += PushArgument(); allocate += StaticCall(TokenPosition::kNoSource, func, 2, ICData::kStatic); allocate += StoreLocal(TokenPosition::kNoSource, @@ -1118,9 +1092,7 @@ FlowGraph* FlowGraphBuilder::BuildGraphOfRecognizedMethod( Fragment allocate(allocate_growable); allocate += LoadLocal(parsed_function_->RawParameterVariable(0)); - allocate += PushArgument(); allocate += IntConstant(0); - allocate += PushArgument(); allocate += StaticCall(TokenPosition::kNoSource, func, 2, ICData::kStatic); allocate += StoreLocal(TokenPosition::kNoSource, @@ -1850,7 +1822,6 @@ Fragment FlowGraphBuilder::PushExplicitParameters(const Function& function) { n = function.NumParameters(); i < n; ++i) { instructions += LoadLocal(parsed_function_->ParameterVariable(i)); - instructions += PushArgument(); } return instructions; } @@ -1913,16 +1884,13 @@ FlowGraph* FlowGraphBuilder::BuildGraphOfNoSuchMethodDispatcher( // The receiver is the first argument to noSuchMethod, and it is the first // argument passed to the dispatcher function. body += LoadLocal(parsed_function_->ParameterVariable(0)); - body += PushArgument(); // The second argument to noSuchMethod is an invocation mirror. Push the // arguments for allocating the invocation mirror. First, the name. body += Constant(String::ZoneHandle(Z, function.name())); - body += PushArgument(); // Second, the arguments descriptor. body += Constant(descriptor_array); - body += PushArgument(); // Third, an array containing the original arguments. Create it and fill // it in. @@ -1955,11 +1923,9 @@ FlowGraph* FlowGraphBuilder::BuildGraphOfNoSuchMethodDispatcher( body += LoadLocal(parsed_function_->ParameterVariable(parameter_index)); body += StoreIndexed(kArrayCid); } - body += PushArgument(); // Fourth, false indicating this is not a super NoSuchMethod. body += Constant(Bool::False()); - body += PushArgument(); const Class& mirror_class = Class::Handle(Z, Library::LookupCoreClass(Symbols::InvocationMirror())); @@ -1970,7 +1936,6 @@ FlowGraph* FlowGraphBuilder::BuildGraphOfNoSuchMethodDispatcher( ASSERT(!allocation_function.IsNull()); body += StaticCall(TokenPosition::kMinSource, allocation_function, /* argument_count = */ 4, ICData::kStatic); - body += PushArgument(); // For the call to noSuchMethod. const int kTypeArgsLen = 0; ArgumentsDescriptor two_arguments( @@ -2048,7 +2013,6 @@ FlowGraph* FlowGraphBuilder::BuildGraphOfInvokeFieldDispatcher( LocalVariable* type_args = parsed_function_->function_type_arguments(); ASSERT(type_args != NULL); body += LoadLocal(type_args); - body += PushArgument(); } LocalVariable* closure = NULL; @@ -2060,7 +2024,6 @@ FlowGraph* FlowGraphBuilder::BuildGraphOfInvokeFieldDispatcher( } else { // Invoke the getter to get the field value. body += LoadLocal(parsed_function_->ParameterVariable(0)); - body += PushArgument(); const intptr_t kTypeArgsLen = 0; const intptr_t kNumArgsChecked = 1; body += InstanceCall(TokenPosition::kMinSource, getter_name, Token::kGET, @@ -2068,13 +2031,10 @@ FlowGraph* FlowGraphBuilder::BuildGraphOfInvokeFieldDispatcher( Function::null_function()); } - body += PushArgument(); - // Push all arguments onto the stack. intptr_t pos = 1; for (; pos < descriptor.Count(); pos++) { body += LoadLocal(parsed_function_->ParameterVariable(pos)); - body += PushArgument(); } if (is_closure_call) { @@ -2272,10 +2232,8 @@ FlowGraph* FlowGraphBuilder::BuildGraphOfNoSuchMethodForwarder( } else { body += LoadLocal(parsed_function_->ParameterVariable(0)); } - body += PushArgument(); body += Constant(String::ZoneHandle(Z, function.name())); - body += PushArgument(); if (!parsed_function_->has_arg_desc_var()) { // If there is no variable for the arguments descriptor (this function's @@ -2286,10 +2244,8 @@ FlowGraph* FlowGraphBuilder::BuildGraphOfNoSuchMethodForwarder( } else { body += LoadArgDescriptor(); } - body += PushArgument(); body += LoadLocal(arguments); - body += PushArgument(); if (throw_no_such_method_error) { const Function& parent = @@ -2311,7 +2267,6 @@ FlowGraph* FlowGraphBuilder::BuildGraphOfNoSuchMethodForwarder( } else { body += NullConstant(); } - body += PushArgument(); // Push the number of delayed type arguments. if (function.IsClosureFunction()) { @@ -2329,7 +2284,6 @@ FlowGraph* FlowGraphBuilder::BuildGraphOfNoSuchMethodForwarder( } else { body += IntConstant(0); } - body += PushArgument(); const Class& mirror_class = Class::Handle(Z, Library::LookupCoreClass(Symbols::InvocationMirror())); @@ -2340,7 +2294,6 @@ FlowGraph* FlowGraphBuilder::BuildGraphOfNoSuchMethodForwarder( ASSERT(!allocation_function.IsNull()); body += StaticCall(TokenPosition::kMinSource, allocation_function, /* argument_count = */ 5, ICData::kStatic); - body += PushArgument(); // For the call to noSuchMethod. if (throw_no_such_method_error) { const Class& klass = Class::ZoneHandle( @@ -2540,7 +2493,6 @@ FlowGraph* FlowGraphBuilder::BuildGraphOfImplicitClosureFunction( type_args_len = function.NumTypeParameters(); ASSERT(parsed_function_->function_type_arguments() != NULL); body += LoadLocal(parsed_function_->function_type_arguments()); - body += PushArgument(); } // Push receiver. @@ -2551,7 +2503,6 @@ FlowGraph* FlowGraphBuilder::BuildGraphOfImplicitClosureFunction( body += LoadNativeField(Slot::Closure_context()); body += LoadNativeField(Slot::GetContextVariableSlotFor( thread_, *parsed_function_->receiver_var())); - body += PushArgument(); } body += PushExplicitParameters(function); @@ -2790,13 +2741,11 @@ FlowGraph* FlowGraphBuilder::BuildGraphOfDynamicInvocationForwarder( type_args_len = function.NumTypeParameters(); ASSERT(parsed_function_->function_type_arguments() != nullptr); body += LoadLocal(parsed_function_->function_type_arguments()); - body += PushArgument(); } // Push receiver. ASSERT(function.NumImplicitParameters() == 1); body += LoadLocal(parsed_function_->receiver_var()); - body += PushArgument(); body += PushExplicitParameters(function); @@ -3049,7 +2998,6 @@ FlowGraph* FlowGraphBuilder::BuildGraphOfFfiCallback(const Function& function) { Push(parameter); body <<= parameter; body += FfiConvertArgumentToDart(ffi_type, arg_reps[i]); - body += PushArgument(); } // Call the target. diff --git a/runtime/vm/regexp_assembler_ir.cc b/runtime/vm/regexp_assembler_ir.cc index 28365d10bc1..500a52ff1cf 100644 --- a/runtime/vm/regexp_assembler_ir.cc +++ b/runtime/vm/regexp_assembler_ir.cc @@ -28,10 +28,10 @@ TAG_(); \ } #define TAG_() \ - Print(PushArgument(Bind(new (Z) ConstantInstr(String::ZoneHandle( \ + Print(Bind(new (Z) ConstantInstr(String::ZoneHandle( \ Z, String::Concat(String::Handle(String::New("TAG: ")), \ String::Handle(String::New(__FUNCTION__)), \ - Heap::kOld)))))); + Heap::kOld))))); #define PRINT(arg) \ if (FLAG_trace_irregexp) { \ @@ -179,7 +179,7 @@ void IRRegExpMacroAssembler::GenerateEntryBlock() { TAG(); // Store string.length. - PushArgumentInstr* string_push = PushLocal(string_param_); + Value* string_push = PushLocal(string_param_); StoreLocal(string_param_length_, Bind(InstanceCall(InstanceCallDescriptor(String::ZoneHandle( @@ -188,8 +188,8 @@ void IRRegExpMacroAssembler::GenerateEntryBlock() { // Store (start_index - string.length) as the current position (since it's a // negative offset from the end of the string). - PushArgumentInstr* start_index_push = PushLocal(start_index_param_); - PushArgumentInstr* length_push = PushLocal(string_param_length_); + Value* start_index_push = PushLocal(start_index_param_); + Value* length_push = PushLocal(string_param_length_); StoreLocal(current_position_, Bind(Sub(start_index_push, length_push))); @@ -199,12 +199,10 @@ void IRRegExpMacroAssembler::GenerateEntryBlock() { ClearRegisters(0, saved_registers_count_ - 1); // Generate a local list variable to represent the backtracking stack. - PushArgumentInstr* stack_cell_push = - PushArgument(Bind(new (Z) ConstantInstr(stack_array_cell_))); + Value* stack_cell_push = Bind(new (Z) ConstantInstr(stack_array_cell_)); StoreLocal(stack_, Bind(InstanceCall(InstanceCallDescriptor::FromToken(Token::kINDEX), - stack_cell_push, - PushArgument(Bind(Uint64Constant(0)))))); + stack_cell_push, Bind(Uint64Constant(0))))); StoreLocal(stack_pointer_, Bind(Int64Constant(-1))); // Jump to the start block. @@ -221,9 +219,8 @@ void IRRegExpMacroAssembler::GenerateBacktrackBlock() { TypedData& offsets = TypedData::ZoneHandle( Z, TypedData::New(kTypedDataInt32ArrayCid, entries_count, Heap::kOld)); - PushArgumentInstr* block_offsets_push = - PushArgument(Bind(new (Z) ConstantInstr(offsets))); - PushArgumentInstr* block_id_push = PushArgument(Bind(PopStack())); + Value* block_offsets_push = Bind(new (Z) ConstantInstr(offsets)); + Value* block_id_push = Bind(PopStack()); Value* offset_value = Bind(InstanceCall(InstanceCallDescriptor::FromToken(Token::kINDEX), @@ -252,15 +249,14 @@ void IRRegExpMacroAssembler::GenerateSuccessBlock() { // Store captured offsets in the `matches` parameter. for (intptr_t i = 0; i < saved_registers_count_; i++) { - PushArgumentInstr* matches_push = PushLocal(result_); - PushArgumentInstr* index_push = PushArgument(Bind(Uint64Constant(i))); + Value* matches_push = PushLocal(result_); + Value* index_push = Bind(Uint64Constant(i)); // Convert negative offsets from the end of the string to string indices. // TODO(zerny): use positive offsets from the get-go. - PushArgumentInstr* offset_push = PushArgument(LoadRegister(i)); - PushArgumentInstr* len_push = PushLocal(string_param_length_); - PushArgumentInstr* value_push = - PushArgument(Bind(Add(offset_push, len_push))); + Value* offset_push = LoadRegister(i); + Value* len_push = PushLocal(string_param_length_); + Value* value_push = Bind(Add(offset_push, len_push)); Do(InstanceCall(InstanceCallDescriptor::FromToken(Token::kASSIGN_INDEX), matches_push, index_push, value_push)); @@ -405,8 +401,8 @@ ConstantInstr* IRRegExpMacroAssembler::WordCharacterMapConstant() const { } ComparisonInstr* IRRegExpMacroAssembler::Comparison(ComparisonKind kind, - PushArgumentInstr* lhs, - PushArgumentInstr* rhs) { + Value* lhs, + Value* rhs) { Token::Kind strict_comparison = Token::kEQ_STRICT; Token::Kind intermediate_operator = Token::kILLEGAL; switch (kind) { @@ -447,25 +443,23 @@ ComparisonInstr* IRRegExpMacroAssembler::Comparison(ComparisonKind kind, ComparisonInstr* IRRegExpMacroAssembler::Comparison(ComparisonKind kind, Definition* lhs, Definition* rhs) { - PushArgumentInstr* lhs_push = PushArgument(Bind(lhs)); - PushArgumentInstr* rhs_push = PushArgument(Bind(rhs)); + Value* lhs_push = Bind(lhs); + Value* rhs_push = Bind(rhs); return Comparison(kind, lhs_push, rhs_push); } StaticCallInstr* IRRegExpMacroAssembler::StaticCall( const Function& function, ICData::RebindRule rebind_rule) const { - ZoneGrowableArray* arguments = - new (Z) ZoneGrowableArray(0); + InputsArray* arguments = new (Z) InputsArray(Z, 0); return StaticCall(function, arguments, rebind_rule); } StaticCallInstr* IRRegExpMacroAssembler::StaticCall( const Function& function, - PushArgumentInstr* arg1, + Value* arg1, ICData::RebindRule rebind_rule) const { - ZoneGrowableArray* arguments = - new (Z) ZoneGrowableArray(1); + InputsArray* arguments = new (Z) InputsArray(Z, 1); arguments->Add(arg1); return StaticCall(function, arguments, rebind_rule); @@ -473,11 +467,10 @@ StaticCallInstr* IRRegExpMacroAssembler::StaticCall( StaticCallInstr* IRRegExpMacroAssembler::StaticCall( const Function& function, - PushArgumentInstr* arg1, - PushArgumentInstr* arg2, + Value* arg1, + Value* arg2, ICData::RebindRule rebind_rule) const { - ZoneGrowableArray* arguments = - new (Z) ZoneGrowableArray(2); + InputsArray* arguments = new (Z) InputsArray(Z, 2); arguments->Add(arg1); arguments->Add(arg2); @@ -486,7 +479,7 @@ StaticCallInstr* IRRegExpMacroAssembler::StaticCall( StaticCallInstr* IRRegExpMacroAssembler::StaticCall( const Function& function, - ZoneGrowableArray* arguments, + InputsArray* arguments, ICData::RebindRule rebind_rule) const { const intptr_t kTypeArgsLen = 0; return new (Z) StaticCallInstr(TokenPosition::kNoSource, function, @@ -496,9 +489,8 @@ StaticCallInstr* IRRegExpMacroAssembler::StaticCall( InstanceCallInstr* IRRegExpMacroAssembler::InstanceCall( const InstanceCallDescriptor& desc, - PushArgumentInstr* arg1) const { - ZoneGrowableArray* arguments = - new (Z) ZoneGrowableArray(1); + Value* arg1) const { + InputsArray* arguments = new (Z) InputsArray(Z, 1); arguments->Add(arg1); return InstanceCall(desc, arguments); @@ -506,10 +498,9 @@ InstanceCallInstr* IRRegExpMacroAssembler::InstanceCall( InstanceCallInstr* IRRegExpMacroAssembler::InstanceCall( const InstanceCallDescriptor& desc, - PushArgumentInstr* arg1, - PushArgumentInstr* arg2) const { - ZoneGrowableArray* arguments = - new (Z) ZoneGrowableArray(2); + Value* arg1, + Value* arg2) const { + InputsArray* arguments = new (Z) InputsArray(Z, 2); arguments->Add(arg1); arguments->Add(arg2); @@ -518,11 +509,10 @@ InstanceCallInstr* IRRegExpMacroAssembler::InstanceCall( InstanceCallInstr* IRRegExpMacroAssembler::InstanceCall( const InstanceCallDescriptor& desc, - PushArgumentInstr* arg1, - PushArgumentInstr* arg2, - PushArgumentInstr* arg3) const { - ZoneGrowableArray* arguments = - new (Z) ZoneGrowableArray(3); + Value* arg1, + Value* arg2, + Value* arg3) const { + InputsArray* arguments = new (Z) InputsArray(Z, 3); arguments->Add(arg1); arguments->Add(arg2); arguments->Add(arg3); @@ -532,7 +522,7 @@ InstanceCallInstr* IRRegExpMacroAssembler::InstanceCall( InstanceCallInstr* IRRegExpMacroAssembler::InstanceCall( const InstanceCallDescriptor& desc, - ZoneGrowableArray* arguments) const { + InputsArray* arguments) const { const intptr_t kTypeArgsLen = 0; return new (Z) InstanceCallInstr( TokenPosition::kNoSource, desc.name, desc.token_kind, arguments, @@ -594,7 +584,6 @@ void IRRegExpMacroAssembler::AppendInstruction(Instruction* instruction) { ASSERT(current_instruction_->next() == NULL); temp_id_.Dealloc(instruction->InputCount()); - arg_id_.Dealloc(instruction->ArgumentCount()); current_instruction_->LinkTo(instruction); set_current_instruction(instruction); @@ -607,7 +596,6 @@ void IRRegExpMacroAssembler::CloseBlockWith(Instruction* instruction) { ASSERT(current_instruction_->next() == NULL); temp_id_.Dealloc(instruction->InputCount()); - arg_id_.Dealloc(instruction->ArgumentCount()); current_instruction_->LinkTo(instruction); set_current_instruction(NULL); @@ -633,24 +621,16 @@ void IRRegExpMacroAssembler::GoTo(JoinEntryInstr* to) { set_current_instruction(NULL); } -PushArgumentInstr* IRRegExpMacroAssembler::PushArgument(Value* value) { - arg_id_.Alloc(); - PushArgumentInstr* push = new (Z) PushArgumentInstr(value); - // Do *not* use Do() for push argument instructions. - AppendInstruction(push); - return push; -} - -PushArgumentInstr* IRRegExpMacroAssembler::PushLocal(LocalVariable* local) { - return PushArgument(Bind(LoadLocal(local))); +Value* IRRegExpMacroAssembler::PushLocal(LocalVariable* local) { + return Bind(LoadLocal(local)); } void IRRegExpMacroAssembler::Print(const char* str) { - Print(PushArgument(Bind(new (Z) ConstantInstr( - String::ZoneHandle(Z, String::New(str, Heap::kOld)))))); + Print(Bind(new (Z) ConstantInstr( + String::ZoneHandle(Z, String::New(str, Heap::kOld))))); } -void IRRegExpMacroAssembler::Print(PushArgumentInstr* argument) { +void IRRegExpMacroAssembler::Print(Value* argument) { const Library& lib = Library::Handle(Library::CoreLibrary()); const Function& print_fn = Function::ZoneHandle(Z, lib.LookupFunctionAllowPrivate(Symbols::print())); @@ -670,8 +650,8 @@ intptr_t IRRegExpMacroAssembler::stack_limit_slack() { void IRRegExpMacroAssembler::AdvanceCurrentPosition(intptr_t by) { TAG(); if (by != 0) { - PushArgumentInstr* cur_pos_push = PushLocal(current_position_); - PushArgumentInstr* by_push = PushArgument(Bind(Int64Constant(by))); + Value* cur_pos_push = PushLocal(current_position_); + Value* by_push = Bind(Int64Constant(by)); Value* new_pos_value = Bind(Add(cur_pos_push, by_push)); StoreLocal(current_position_, new_pos_value); @@ -684,11 +664,11 @@ void IRRegExpMacroAssembler::AdvanceRegister(intptr_t reg, intptr_t by) { ASSERT(reg < registers_count_); if (by != 0) { - PushArgumentInstr* registers_push = PushLocal(registers_); - PushArgumentInstr* index_push = PushRegisterIndex(reg); - PushArgumentInstr* reg_push = PushArgument(LoadRegister(reg)); - PushArgumentInstr* by_push = PushArgument(Bind(Int64Constant(by))); - PushArgumentInstr* value_push = PushArgument(Bind(Add(reg_push, by_push))); + Value* registers_push = PushLocal(registers_); + Value* index_push = PushRegisterIndex(reg); + Value* reg_push = LoadRegister(reg); + Value* by_push = Bind(Int64Constant(by)); + Value* value_push = Bind(Add(reg_push, by_push)); StoreRegister(registers_push, index_push, value_push); } } @@ -714,7 +694,7 @@ void IRRegExpMacroAssembler::BindBlock(BlockLabel* label) { set_current_instruction(label->block()); // Print the id of the current block if tracing. - PRINT(PushArgument(Bind(Uint64Constant(label->block()->block_id())))); + PRINT(Bind(Uint64Constant(label->block()->block_id()))); } intptr_t IRRegExpMacroAssembler::GetNextLocalIndex() { @@ -723,32 +703,32 @@ intptr_t IRRegExpMacroAssembler::GetNextLocalIndex() { } Value* IRRegExpMacroAssembler::LoadRegister(intptr_t index) { - PushArgumentInstr* registers_push = PushLocal(registers_); - PushArgumentInstr* index_push = PushRegisterIndex(index); + Value* registers_push = PushLocal(registers_); + Value* index_push = PushRegisterIndex(index); return Bind(InstanceCall(InstanceCallDescriptor::FromToken(Token::kINDEX), registers_push, index_push)); } void IRRegExpMacroAssembler::StoreRegister(intptr_t index, intptr_t value) { - PushArgumentInstr* registers_push = PushLocal(registers_); - PushArgumentInstr* index_push = PushRegisterIndex(index); - PushArgumentInstr* value_push = PushArgument(Bind(Uint64Constant(value))); + Value* registers_push = PushLocal(registers_); + Value* index_push = PushRegisterIndex(index); + Value* value_push = Bind(Uint64Constant(value)); StoreRegister(registers_push, index_push, value_push); } -void IRRegExpMacroAssembler::StoreRegister(PushArgumentInstr* registers, - PushArgumentInstr* index, - PushArgumentInstr* value) { +void IRRegExpMacroAssembler::StoreRegister(Value* registers, + Value* index, + Value* value) { TAG(); Do(InstanceCall(InstanceCallDescriptor::FromToken(Token::kASSIGN_INDEX), registers, index, value)); } -PushArgumentInstr* IRRegExpMacroAssembler::PushRegisterIndex(intptr_t index) { +Value* IRRegExpMacroAssembler::PushRegisterIndex(intptr_t index) { if (registers_count_ <= index) { registers_count_ = index + 1; } - return PushArgument(Bind(Uint64Constant(index))); + return Bind(Uint64Constant(index)); } void IRRegExpMacroAssembler::CheckCharacter(uint32_t c, BlockLabel* on_equal) { @@ -785,12 +765,11 @@ void IRRegExpMacroAssembler::CheckNotAtStart(intptr_t cp_offset, TAG(); // Are we at the start of the input, i.e. is (offset == string_length * -1)? - auto offset_def = - PushArgument(Bind(Add(PushLocal(current_position_), - PushArgument(Bind(Int64Constant(cp_offset)))))); - auto neg_len_def = PushArgument( + auto neg_len_def = Bind(InstanceCall(InstanceCallDescriptor::FromToken(Token::kNEGATE), - PushLocal(string_param_length_)))); + PushLocal(string_param_length_))); + auto offset_def = + Bind(Add(PushLocal(current_position_), Bind(Int64Constant(cp_offset)))); BranchOrBacktrack(Comparison(kNE, neg_len_def, offset_def), on_not_at_start); } @@ -829,8 +808,8 @@ void IRRegExpMacroAssembler::CheckNotBackReferenceIgnoreCase( BlockLabel fallthrough; - PushArgumentInstr* end_push = PushArgument(LoadRegister(start_reg + 1)); - PushArgumentInstr* start_push = PushArgument(LoadRegister(start_reg)); + Value* end_push = LoadRegister(start_reg + 1); + Value* start_push = LoadRegister(start_reg); StoreLocal(capture_length_, Bind(Sub(end_push, start_push))); // The length of a capture should not be negative. This can only happen @@ -848,8 +827,8 @@ void IRRegExpMacroAssembler::CheckNotBackReferenceIgnoreCase( Comparison(kEQ, LoadLocal(capture_length_), Uint64Constant(0)), &fallthrough); - PushArgumentInstr* pos_push = nullptr; - PushArgumentInstr* len_push = nullptr; + Value* pos_push = nullptr; + Value* len_push = nullptr; if (!read_backward) { // Check that there are sufficient characters left in the input. @@ -880,7 +859,7 @@ void IRRegExpMacroAssembler::CheckNotBackReferenceIgnoreCase( StoreLocal(match_start_index_, Bind(Sub(pos_push, len_push))); } - pos_push = PushArgument(LoadRegister(start_reg)); + pos_push = LoadRegister(start_reg); len_push = PushLocal(string_param_length_); StoreLocal(capture_start_index_, Bind(Add(pos_push, len_push))); @@ -902,8 +881,8 @@ void IRRegExpMacroAssembler::CheckNotBackReferenceIgnoreCase( &loop_increment); // Mismatch, try case-insensitive match (converting letters to lower-case). - PushArgumentInstr* match_char_push = PushLocal(char_in_match_); - PushArgumentInstr* mask_push = PushArgument(Bind(Uint64Constant(0x20))); + Value* match_char_push = PushLocal(char_in_match_); + Value* mask_push = Bind(Uint64Constant(0x20)); StoreLocal( char_in_match_, Bind(InstanceCall(InstanceCallDescriptor::FromToken(Token::kBIT_OR), @@ -935,8 +914,8 @@ void IRRegExpMacroAssembler::CheckNotBackReferenceIgnoreCase( // Also convert capture character. BindBlock(&convert_capture); - PushArgumentInstr* capture_char_push = PushLocal(char_in_capture_); - mask_push = PushArgument(Bind(Uint64Constant(0x20))); + Value* capture_char_push = PushLocal(char_in_capture_); + mask_push = Bind(Uint64Constant(0x20)); StoreLocal( char_in_capture_, Bind(InstanceCall(InstanceCallDescriptor::FromToken(Token::kBIT_OR), @@ -949,12 +928,12 @@ void IRRegExpMacroAssembler::CheckNotBackReferenceIgnoreCase( BindBlock(&loop_increment); // Increment indexes into capture and match strings. - PushArgumentInstr* index_push = PushLocal(capture_start_index_); - PushArgumentInstr* inc_push = PushArgument(Bind(Uint64Constant(1))); + Value* index_push = PushLocal(capture_start_index_); + Value* inc_push = Bind(Uint64Constant(1)); StoreLocal(capture_start_index_, Bind(Add(index_push, inc_push))); index_push = PushLocal(match_start_index_); - inc_push = PushArgument(Bind(Uint64Constant(1))); + inc_push = Bind(Uint64Constant(1)); StoreLocal(match_start_index_, Bind(Add(index_push, inc_push))); // Compare to end of match, and loop if not done. @@ -994,7 +973,7 @@ void IRRegExpMacroAssembler::CheckNotBackReferenceIgnoreCase( StoreLocal(current_position_, Bind(Sub(pos_push, len_push))); } else { // Move current character position to position after match. - PushArgumentInstr* match_end_push = PushLocal(match_end_index_); + Value* match_end_push = PushLocal(match_end_index_); len_push = PushLocal(string_param_length_); StoreLocal(current_position_, Bind(Sub(match_end_push, len_push))); } @@ -1012,8 +991,8 @@ void IRRegExpMacroAssembler::CheckNotBackReference(intptr_t start_reg, BlockLabel success; // Find length of back-referenced capture. - PushArgumentInstr* end_push = PushArgument(LoadRegister(start_reg + 1)); - PushArgumentInstr* start_push = PushArgument(LoadRegister(start_reg)); + Value* end_push = LoadRegister(start_reg + 1); + Value* start_push = LoadRegister(start_reg); StoreLocal(capture_length_, Bind(Sub(end_push, start_push))); // Fail on partial or illegal capture (start of capture after end of capture). @@ -1026,8 +1005,8 @@ void IRRegExpMacroAssembler::CheckNotBackReference(intptr_t start_reg, Comparison(kEQ, LoadLocal(capture_length_), Uint64Constant(0)), &fallthrough); - PushArgumentInstr* pos_push = nullptr; - PushArgumentInstr* len_push = nullptr; + Value* pos_push = nullptr; + Value* len_push = nullptr; if (!read_backward) { // Check that there are sufficient characters left in the input. @@ -1059,7 +1038,7 @@ void IRRegExpMacroAssembler::CheckNotBackReference(intptr_t start_reg, StoreLocal(match_start_index_, Bind(Sub(pos_push, len_push))); } - pos_push = PushArgument(LoadRegister(start_reg)); + pos_push = LoadRegister(start_reg); len_push = PushLocal(string_param_length_); StoreLocal(capture_start_index_, Bind(Add(pos_push, len_push))); @@ -1078,12 +1057,12 @@ void IRRegExpMacroAssembler::CheckNotBackReference(intptr_t start_reg, on_no_match); // Increment indexes into capture and match strings. - PushArgumentInstr* index_push = PushLocal(capture_start_index_); - PushArgumentInstr* inc_push = PushArgument(Bind(Uint64Constant(1))); + Value* index_push = PushLocal(capture_start_index_); + Value* inc_push = Bind(Uint64Constant(1)); StoreLocal(capture_start_index_, Bind(Add(index_push, inc_push))); index_push = PushLocal(match_start_index_); - inc_push = PushArgument(Bind(Uint64Constant(1))); + inc_push = Bind(Uint64Constant(1)); StoreLocal(match_start_index_, Bind(Add(index_push, inc_push))); // Check if we have reached end of match area. @@ -1100,7 +1079,7 @@ void IRRegExpMacroAssembler::CheckNotBackReference(intptr_t start_reg, StoreLocal(current_position_, Bind(Sub(pos_push, len_push))); } else { // Move current character position to position after match. - PushArgumentInstr* match_end_push = PushLocal(match_end_index_); + Value* match_end_push = PushLocal(match_end_index_); len_push = PushLocal(string_param_length_); StoreLocal(current_position_, Bind(Sub(match_end_push, len_push))); } @@ -1122,12 +1101,12 @@ void IRRegExpMacroAssembler::CheckCharacterAfterAnd(uint32_t c, TAG(); Definition* actual_def = LoadLocal(current_character_); - Definition* expected_def = Uint64Constant(c); - PushArgumentInstr* actual_push = PushArgument(Bind(actual_def)); - PushArgumentInstr* mask_push = PushArgument(Bind(Uint64Constant(mask))); + Value* actual_push = Bind(actual_def); + Value* mask_push = Bind(Uint64Constant(mask)); actual_def = InstanceCall(InstanceCallDescriptor::FromToken(Token::kBIT_AND), actual_push, mask_push); + Definition* expected_def = Uint64Constant(c); BranchOrBacktrack(Comparison(kEQ, actual_def, expected_def), on_equal); } @@ -1139,12 +1118,12 @@ void IRRegExpMacroAssembler::CheckNotCharacterAfterAnd( TAG(); Definition* actual_def = LoadLocal(current_character_); - Definition* expected_def = Uint64Constant(c); - PushArgumentInstr* actual_push = PushArgument(Bind(actual_def)); - PushArgumentInstr* mask_push = PushArgument(Bind(Uint64Constant(mask))); + Value* actual_push = Bind(actual_def); + Value* mask_push = Bind(Uint64Constant(mask)); actual_def = InstanceCall(InstanceCallDescriptor::FromToken(Token::kBIT_AND), actual_push, mask_push); + Definition* expected_def = Uint64Constant(c); BranchOrBacktrack(Comparison(kNE, actual_def, expected_def), on_not_equal); } @@ -1158,15 +1137,15 @@ void IRRegExpMacroAssembler::CheckNotCharacterAfterMinusAnd( ASSERT(minus < Utf16::kMaxCodeUnit); // NOLINT Definition* actual_def = LoadLocal(current_character_); - Definition* expected_def = Uint64Constant(c); - PushArgumentInstr* actual_push = PushArgument(Bind(actual_def)); - PushArgumentInstr* minus_push = PushArgument(Bind(Uint64Constant(minus))); + Value* actual_push = Bind(actual_def); + Value* minus_push = Bind(Uint64Constant(minus)); - actual_push = PushArgument(Bind(Sub(actual_push, minus_push))); - PushArgumentInstr* mask_push = PushArgument(Bind(Uint64Constant(mask))); + actual_push = Bind(Sub(actual_push, minus_push)); + Value* mask_push = Bind(Uint64Constant(mask)); actual_def = InstanceCall(InstanceCallDescriptor::FromToken(Token::kBIT_AND), actual_push, mask_push); + Definition* expected_def = Uint64Constant(c); BranchOrBacktrack(Comparison(kNE, actual_def, expected_def), on_not_equal); } @@ -1212,16 +1191,14 @@ void IRRegExpMacroAssembler::CheckBitInTable(const TypedData& table, BlockLabel* on_bit_set) { TAG(); - PushArgumentInstr* table_push = - PushArgument(Bind(new (Z) ConstantInstr(table))); - PushArgumentInstr* index_push = PushLocal(current_character_); + Value* table_push = Bind(new (Z) ConstantInstr(table)); + Value* index_push = PushLocal(current_character_); if (mode_ != ASCII || kTableMask != Symbols::kMaxOneCharCodeSymbol) { - PushArgumentInstr* mask_push = - PushArgument(Bind(Uint64Constant(kTableSize - 1))); - index_push = PushArgument( + Value* mask_push = Bind(Uint64Constant(kTableSize - 1)); + index_push = Bind(InstanceCall(InstanceCallDescriptor::FromToken(Token::kBIT_AND), - index_push, mask_push))); + index_push, mask_push)); } Definition* byte_def = InstanceCall( @@ -1295,9 +1272,8 @@ bool IRRegExpMacroAssembler::CheckSpecialCharacterClass( on_no_match); } - PushArgumentInstr* table_push = - PushArgument(Bind(WordCharacterMapConstant())); - PushArgumentInstr* index_push = PushLocal(current_character_); + Value* table_push = Bind(WordCharacterMapConstant()); + Value* index_push = PushLocal(current_character_); Definition* byte_def = InstanceCall(InstanceCallDescriptor::FromToken(Token::kINDEX), @@ -1319,9 +1295,8 @@ bool IRRegExpMacroAssembler::CheckSpecialCharacterClass( // TODO(zerny): Refactor to use CheckBitInTable if possible. - PushArgumentInstr* table_push = - PushArgument(Bind(WordCharacterMapConstant())); - PushArgumentInstr* index_push = PushLocal(current_character_); + Value* table_push = Bind(WordCharacterMapConstant()); + Value* index_push = PushLocal(current_character_); Definition* byte_def = InstanceCall(InstanceCallDescriptor::FromToken(Token::kINDEX), @@ -1380,8 +1355,8 @@ void IRRegExpMacroAssembler::IfRegisterGE(intptr_t reg, intptr_t comparand, BlockLabel* if_ge) { TAG(); - PushArgumentInstr* reg_push = PushArgument(LoadRegister(reg)); - PushArgumentInstr* pos = PushArgument(Bind(Int64Constant(comparand))); + Value* reg_push = LoadRegister(reg); + Value* pos = Bind(Int64Constant(comparand)); BranchOrBacktrack(Comparison(kGTE, reg_push, pos), if_ge); } @@ -1389,15 +1364,15 @@ void IRRegExpMacroAssembler::IfRegisterLT(intptr_t reg, intptr_t comparand, BlockLabel* if_lt) { TAG(); - PushArgumentInstr* reg_push = PushArgument(LoadRegister(reg)); - PushArgumentInstr* pos = PushArgument(Bind(Int64Constant(comparand))); + Value* reg_push = LoadRegister(reg); + Value* pos = Bind(Int64Constant(comparand)); BranchOrBacktrack(Comparison(kLT, reg_push, pos), if_lt); } void IRRegExpMacroAssembler::IfRegisterEqPos(intptr_t reg, BlockLabel* if_eq) { TAG(); - PushArgumentInstr* reg_push = PushArgument(LoadRegister(reg)); - PushArgumentInstr* pos = PushArgument(Bind(LoadLocal(current_position_))); + Value* reg_push = LoadRegister(reg); + Value* pos = Bind(LoadLocal(current_position_)); BranchOrBacktrack(Comparison(kEQ, reg_push, pos), if_eq); } @@ -1430,37 +1405,37 @@ void IRRegExpMacroAssembler::PopCurrentPosition() { void IRRegExpMacroAssembler::PopRegister(intptr_t reg) { TAG(); ASSERT(reg < registers_count_); - PushArgumentInstr* registers_push = PushLocal(registers_); - PushArgumentInstr* index_push = PushRegisterIndex(reg); - PushArgumentInstr* pop_push = PushArgument(Bind(PopStack())); + Value* registers_push = PushLocal(registers_); + Value* index_push = PushRegisterIndex(reg); + Value* pop_push = Bind(PopStack()); StoreRegister(registers_push, index_push, pop_push); } void IRRegExpMacroAssembler::PushStack(Definition* definition) { - PushArgumentInstr* stack_push = PushLocal(stack_); - PushArgumentInstr* stack_pointer_push = PushLocal(stack_pointer_); - StoreLocal(stack_pointer_, Bind(Add(stack_pointer_push, - PushArgument(Bind(Uint64Constant(1)))))); + Value* stack_push = PushLocal(stack_); + Value* stack_pointer_push = PushLocal(stack_pointer_); + StoreLocal(stack_pointer_, + Bind(Add(stack_pointer_push, Bind(Uint64Constant(1))))); stack_pointer_push = PushLocal(stack_pointer_); // TODO(zerny): bind value and push could break stack discipline. - PushArgumentInstr* value_push = PushArgument(Bind(definition)); + Value* value_push = Bind(definition); Do(InstanceCall(InstanceCallDescriptor::FromToken(Token::kASSIGN_INDEX), stack_push, stack_pointer_push, value_push)); } Definition* IRRegExpMacroAssembler::PopStack() { - PushArgumentInstr* stack_push = PushLocal(stack_); - PushArgumentInstr* stack_pointer_push1 = PushLocal(stack_pointer_); - PushArgumentInstr* stack_pointer_push2 = PushLocal(stack_pointer_); - StoreLocal(stack_pointer_, Bind(Sub(stack_pointer_push2, - PushArgument(Bind(Uint64Constant(1)))))); + Value* stack_push = PushLocal(stack_); + Value* stack_pointer_push1 = PushLocal(stack_pointer_); + Value* stack_pointer_push2 = PushLocal(stack_pointer_); + StoreLocal(stack_pointer_, + Bind(Sub(stack_pointer_push2, Bind(Uint64Constant(1))))); return InstanceCall(InstanceCallDescriptor::FromToken(Token::kINDEX), stack_push, stack_pointer_push1); } Definition* IRRegExpMacroAssembler::PeekStack() { - PushArgumentInstr* stack_push = PushLocal(stack_); - PushArgumentInstr* stack_pointer_push = PushLocal(stack_pointer_); + Value* stack_push = PushLocal(stack_); + Value* stack_pointer_push = PushLocal(stack_pointer_); return InstanceCall(InstanceCallDescriptor::FromToken(Token::kINDEX), stack_push, stack_pointer_push); } @@ -1490,13 +1465,13 @@ void IRRegExpMacroAssembler::PushCurrentPosition() { void IRRegExpMacroAssembler::PushRegister(intptr_t reg) { TAG(); // TODO(zerny): Refactor PushStack so it can be reused here. - PushArgumentInstr* stack_push = PushLocal(stack_); - PushArgumentInstr* stack_pointer_push = PushLocal(stack_pointer_); - StoreLocal(stack_pointer_, Bind(Add(stack_pointer_push, - PushArgument(Bind(Uint64Constant(1)))))); + Value* stack_push = PushLocal(stack_); + Value* stack_pointer_push = PushLocal(stack_pointer_); + StoreLocal(stack_pointer_, + Bind(Add(stack_pointer_push, Bind(Uint64Constant(1))))); stack_pointer_push = PushLocal(stack_pointer_); // TODO(zerny): bind value and push could break stack discipline. - PushArgumentInstr* value_push = PushArgument(LoadRegister(reg)); + Value* value_push = LoadRegister(reg); Do(InstanceCall(InstanceCallDescriptor::FromToken(Token::kASSIGN_INDEX), stack_push, stack_pointer_push, value_push)); CheckStackLimit(); @@ -1508,14 +1483,14 @@ void IRRegExpMacroAssembler::PushRegister(intptr_t reg) { // stack will be grown. void IRRegExpMacroAssembler::CheckStackLimit() { TAG(); - PushArgumentInstr* stack_push = PushLocal(stack_); - PushArgumentInstr* length_push = PushArgument( + Value* stack_push = PushLocal(stack_); + Value* length_push = Bind(InstanceCall(InstanceCallDescriptor(String::ZoneHandle( Field::GetterSymbol(Symbols::Length()))), - stack_push))); - PushArgumentInstr* capacity_push = PushArgument(Bind(Sub( - length_push, PushArgument(Bind(Uint64Constant(stack_limit_slack())))))); - PushArgumentInstr* stack_pointer_push = PushLocal(stack_pointer_); + stack_push)); + Value* capacity_push = + Bind(Sub(length_push, Bind(Uint64Constant(stack_limit_slack())))); + Value* stack_pointer_push = PushLocal(stack_pointer_); BranchInstr* branch = new (Z) BranchInstr( Comparison(kGT, capacity_push, stack_pointer_push), GetNextDeoptId()); CloseBlockWith(branch); @@ -1544,10 +1519,9 @@ void IRRegExpMacroAssembler::GrowStack() { // as a constant but :stack is a local variable and its value might be // comming from OSR or deoptimization. This means we should never use // stack_array_cell in the body of the :matcher to reload the :stack. - PushArgumentInstr* stack_cell_push = - PushArgument(Bind(new (Z) ConstantInstr(stack_array_cell_))); - PushArgumentInstr* index_push = PushArgument(Bind(Uint64Constant(0))); - PushArgumentInstr* stack_push = PushLocal(stack_); + Value* stack_cell_push = Bind(new (Z) ConstantInstr(stack_array_cell_)); + Value* index_push = Bind(Uint64Constant(0)); + Value* stack_push = PushLocal(stack_); Do(InstanceCall(InstanceCallDescriptor::FromToken(Token::kASSIGN_INDEX), stack_cell_push, index_push, stack_push)); } @@ -1603,11 +1577,11 @@ void IRRegExpMacroAssembler::WriteCurrentPositionToRegister( intptr_t cp_offset) { TAG(); - PushArgumentInstr* registers_push = PushLocal(registers_); - PushArgumentInstr* index_push = PushRegisterIndex(reg); - PushArgumentInstr* pos_push = PushLocal(current_position_); - PushArgumentInstr* off_push = PushArgument(Bind(Int64Constant(cp_offset))); - PushArgumentInstr* neg_off_push = PushArgument(Bind(Add(pos_push, off_push))); + Value* registers_push = PushLocal(registers_); + Value* index_push = PushRegisterIndex(reg); + Value* pos_push = PushLocal(current_position_); + Value* off_push = Bind(Int64Constant(cp_offset)); + Value* neg_off_push = Bind(Add(pos_push, off_push)); // Push the negative offset; these are converted to positive string positions // within the success block. StoreRegister(registers_push, index_push, neg_off_push); @@ -1623,12 +1597,11 @@ void IRRegExpMacroAssembler::ClearRegisters(intptr_t reg_from, // (-1 - string length), the offset of -1 from the end of the string. for (intptr_t reg = reg_from; reg <= reg_to; reg++) { - PushArgumentInstr* registers_push = PushLocal(registers_); - PushArgumentInstr* index_push = PushRegisterIndex(reg); - PushArgumentInstr* minus_one_push = PushArgument(Bind(Int64Constant(-1))); - PushArgumentInstr* length_push = PushLocal(string_param_length_); - PushArgumentInstr* value_push = - PushArgument(Bind(Sub(minus_one_push, length_push))); + Value* registers_push = PushLocal(registers_); + Value* index_push = PushRegisterIndex(reg); + Value* minus_one_push = Bind(Int64Constant(-1)); + Value* length_push = PushLocal(string_param_length_); + Value* value_push = Bind(Sub(minus_one_push, length_push)); StoreRegister(registers_push, index_push, value_push); } } @@ -1636,9 +1609,9 @@ void IRRegExpMacroAssembler::ClearRegisters(intptr_t reg_from, void IRRegExpMacroAssembler::WriteStackPointerToRegister(intptr_t reg) { TAG(); - PushArgumentInstr* registers_push = PushLocal(registers_); - PushArgumentInstr* index_push = PushRegisterIndex(reg); - PushArgumentInstr* tip_push = PushLocal(stack_pointer_); + Value* registers_push = PushLocal(registers_); + Value* index_push = PushRegisterIndex(reg); + Value* tip_push = PushLocal(stack_pointer_); StoreRegister(registers_push, index_push, tip_push); } @@ -1659,8 +1632,8 @@ void IRRegExpMacroAssembler::CheckPosition(intptr_t cp_offset, // We need to see if there's enough characters left in the string to go // back cp_offset characters, so get the normalized position and then // make sure that (normalized_position >= -cp_offset). - PushArgumentInstr* pos_push = PushLocal(current_position_); - PushArgumentInstr* len_push = PushLocal(string_param_length_); + Value* pos_push = PushLocal(current_position_); + Value* len_push = PushLocal(string_param_length_); BranchOrBacktrack( Comparison(kLT, Add(pos_push, len_push), Uint64Constant(-cp_offset)), on_outside_input); @@ -1734,13 +1707,11 @@ void IRRegExpMacroAssembler::CheckPreemption(bool is_backtrack) { : CheckStackOverflowInstr::kOsrOnly)); } -Definition* IRRegExpMacroAssembler::Add(PushArgumentInstr* lhs, - PushArgumentInstr* rhs) { +Definition* IRRegExpMacroAssembler::Add(Value* lhs, Value* rhs) { return InstanceCall(InstanceCallDescriptor::FromToken(Token::kADD), lhs, rhs); } -Definition* IRRegExpMacroAssembler::Sub(PushArgumentInstr* lhs, - PushArgumentInstr* rhs) { +Definition* IRRegExpMacroAssembler::Sub(Value* lhs, Value* rhs) { return InstanceCall(InstanceCallDescriptor::FromToken(Token::kSUB), lhs, rhs); } @@ -1760,11 +1731,10 @@ void IRRegExpMacroAssembler::LoadCurrentCharacterUnchecked( // Calculate the addressed string index as: // cp_offset + current_position_ + string_param_length_ // TODO(zerny): Avoid generating 'add' instance-calls here. - PushArgumentInstr* off_arg = PushArgument(Bind(Int64Constant(cp_offset))); - PushArgumentInstr* pos_arg = PushArgument(BindLoadLocal(*current_position_)); - PushArgumentInstr* off_pos_arg = PushArgument(Bind(Add(off_arg, pos_arg))); - PushArgumentInstr* len_arg = - PushArgument(BindLoadLocal(*string_param_length_)); + Value* off_arg = Bind(Int64Constant(cp_offset)); + Value* pos_arg = BindLoadLocal(*current_position_); + Value* off_pos_arg = Bind(Add(off_arg, pos_arg)); + Value* len_arg = BindLoadLocal(*string_param_length_); // Index is stored in a temporary local so that we can later load it safely. StoreLocal(index_temp_, Bind(Add(off_pos_arg, len_arg))); diff --git a/runtime/vm/regexp_assembler_ir.h b/runtime/vm/regexp_assembler_ir.h index d8c222a568f..fb92f1b16a1 100644 --- a/runtime/vm/regexp_assembler_ir.h +++ b/runtime/vm/regexp_assembler_ir.h @@ -228,37 +228,34 @@ class IRRegExpMacroAssembler : public RegExpMacroAssembler { // Used by generated RegExp code. ConstantInstr* WordCharacterMapConstant() const; - ComparisonInstr* Comparison(ComparisonKind kind, - PushArgumentInstr* lhs, - PushArgumentInstr* rhs); + ComparisonInstr* Comparison(ComparisonKind kind, Value* lhs, Value* rhs); ComparisonInstr* Comparison(ComparisonKind kind, Definition* lhs, Definition* rhs); InstanceCallInstr* InstanceCall(const InstanceCallDescriptor& desc, - PushArgumentInstr* arg1) const; + Value* arg1) const; InstanceCallInstr* InstanceCall(const InstanceCallDescriptor& desc, - PushArgumentInstr* arg1, - PushArgumentInstr* arg2) const; + Value* arg1, + Value* arg2) const; InstanceCallInstr* InstanceCall(const InstanceCallDescriptor& desc, - PushArgumentInstr* arg1, - PushArgumentInstr* arg2, - PushArgumentInstr* arg3) const; - InstanceCallInstr* InstanceCall( - const InstanceCallDescriptor& desc, - ZoneGrowableArray* arguments) const; + Value* arg1, + Value* arg2, + Value* arg3) const; + InstanceCallInstr* InstanceCall(const InstanceCallDescriptor& desc, + InputsArray* arguments) const; StaticCallInstr* StaticCall(const Function& function, ICData::RebindRule rebind_rule) const; StaticCallInstr* StaticCall(const Function& function, - PushArgumentInstr* arg1, + Value* arg1, ICData::RebindRule rebind_rule) const; StaticCallInstr* StaticCall(const Function& function, - PushArgumentInstr* arg1, - PushArgumentInstr* arg2, + Value* arg1, + Value* arg2, ICData::RebindRule rebind_rule) const; StaticCallInstr* StaticCall(const Function& function, - ZoneGrowableArray* arguments, + InputsArray* arguments, ICData::RebindRule rebind_rule) const; // Creates a new block consisting simply of a goto to dst. @@ -266,21 +263,18 @@ class IRRegExpMacroAssembler : public RegExpMacroAssembler { IndirectEntryInstr* IndirectWithJoinGoto(JoinEntryInstr* dst); // Adds, respectively subtracts lhs and rhs and returns the result. - Definition* Add(PushArgumentInstr* lhs, PushArgumentInstr* rhs); - Definition* Sub(PushArgumentInstr* lhs, PushArgumentInstr* rhs); + Definition* Add(Value* lhs, Value* rhs); + Definition* Sub(Value* lhs, Value* rhs); LoadLocalInstr* LoadLocal(LocalVariable* local) const; void StoreLocal(LocalVariable* local, Value* value); - PushArgumentInstr* PushArgument(Value* value); - PushArgumentInstr* PushLocal(LocalVariable* local); + Value* PushLocal(LocalVariable* local); - PushArgumentInstr* PushRegisterIndex(intptr_t reg); + Value* PushRegisterIndex(intptr_t reg); Value* LoadRegister(intptr_t reg); void StoreRegister(intptr_t reg, intptr_t value); - void StoreRegister(PushArgumentInstr* registers, - PushArgumentInstr* index, - PushArgumentInstr* value); + void StoreRegister(Value* registers, Value* index, Value* value); // Load a number of characters at the given offset from the // current position, into the current-character register. @@ -347,7 +341,7 @@ class IRRegExpMacroAssembler : public RegExpMacroAssembler { void GrowStack(); // Prints the specified argument. Used for debugging. - void Print(PushArgumentInstr* argument); + void Print(Value* argument); // A utility class tracking ids of various objects such as blocks, temps, etc. class IdAllocator : public ValueObject { @@ -442,7 +436,6 @@ class IRRegExpMacroAssembler : public RegExpMacroAssembler { IdAllocator block_id_; IdAllocator temp_id_; - IdAllocator arg_id_; IdAllocator local_id_; IdAllocator indirect_id_; };