// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file // for details. All rights reserved. Use of this source code is governed by a // BSD-style license that can be found in the LICENSE file. #ifndef RUNTIME_VM_COMPILER_CALL_SPECIALIZER_H_ #define RUNTIME_VM_COMPILER_CALL_SPECIALIZER_H_ #include "vm/compiler/backend/flow_graph.h" #include "vm/compiler/backend/il.h" namespace dart { class SpeculativeInliningPolicy; // Call specialization pass is responsible for replacing instance calls by // faster alternatives based on type feedback (JIT), type speculations (AOT), // locally propagated type information or global type information. // // This pass for example can // // * Replace a call to a binary arithmetic operator with corresponding IL // instructions and necessary checks; // * Replace a dynamic call with a static call, if reciever is known // to have a certain class id; // * Replace type check with a range check // // CallSpecializer is a base class that contains logic shared between // JIT and AOT compilation pipelines, see JitCallSpecializer for JIT specific // optimizations and AotCallSpecializer for AOT specific optimizations. class CallSpecializer : public FlowGraphVisitor { public: CallSpecializer(FlowGraph* flow_graph, SpeculativeInliningPolicy* speculative_policy, bool should_clone_fields) : FlowGraphVisitor(flow_graph->reverse_postorder()), speculative_policy_(speculative_policy), should_clone_fields_(should_clone_fields), flow_graph_(flow_graph) {} virtual ~CallSpecializer() {} FlowGraph* flow_graph() const { return flow_graph_; } // Use ICData to optimize, replace or eliminate instructions. void ApplyICData(); // Use propagated class ids to optimize, replace or eliminate instructions. void ApplyClassIds(); void InsertBefore(Instruction* next, Instruction* instr, Environment* env, FlowGraph::UseKind use_kind) { flow_graph_->InsertBefore(next, instr, env, use_kind); } virtual void VisitStaticCall(StaticCallInstr* instr); // TODO(dartbug.com/30633) these methods have nothing to do with // specialization of calls. They are here for historical reasons. // Find a better place for them. virtual void VisitLoadCodeUnits(LoadCodeUnitsInstr* instr); protected: Thread* thread() const { return flow_graph_->thread(); } Isolate* isolate() const { return flow_graph_->isolate(); } Zone* zone() const { return flow_graph_->zone(); } const Function& function() const { return flow_graph_->function(); } bool TryReplaceWithIndexedOp(InstanceCallInstr* call, const ICData* unary_checks); bool TryReplaceWithBinaryOp(InstanceCallInstr* call, Token::Kind op_kind); bool TryReplaceWithUnaryOp(InstanceCallInstr* call, Token::Kind op_kind); bool TryReplaceWithEqualityOp(InstanceCallInstr* call, Token::Kind op_kind); bool TryReplaceWithRelationalOp(InstanceCallInstr* call, Token::Kind op_kind); bool TryInlineInstanceGetter(InstanceCallInstr* call); bool TryInlineInstanceSetter(InstanceCallInstr* call, const ICData& unary_ic_data); bool TryInlineInstanceMethod(InstanceCallInstr* call); void ReplaceWithInstanceOf(InstanceCallInstr* instr); void ReplaceWithTypeCast(InstanceCallInstr* instr); void ReplaceCall(Definition* call, Definition* replacement); // Add a class check for the call's first argument (receiver). void AddReceiverCheck(InstanceCallInstr* call) { AddChecksForArgNr(call, call->ArgumentAt(0), /* argument_number = */ 0); } // Insert a null check if needed. void AddCheckNull(Value* to_check, const String& function_name, intptr_t deopt_id, Environment* deopt_environment, Instruction* insert_before); // Attempt to build ICData for call using propagated class-ids. virtual bool TryCreateICData(InstanceCallInstr* call); static bool HasOnlyTwoOf(const ICData& ic_data, intptr_t cid); virtual bool TryReplaceInstanceOfWithRangeCheck(InstanceCallInstr* call, const AbstractType& type); virtual bool TryReplaceTypeCastWithRangeCheck(InstanceCallInstr* call, const AbstractType& type); virtual bool TryOptimizeStaticCallUsingStaticTypes(StaticCallInstr* call) = 0; protected: void InlineImplicitInstanceGetter(Definition* call, const Field& field); SpeculativeInliningPolicy* speculative_policy_; const bool should_clone_fields_; private: bool TypeCheckAsClassEquality(const AbstractType& type); // Insert a check of 'to_check' determined by 'unary_checks'. If the // check fails it will deoptimize to 'deopt_id' using the deoptimization // environment 'deopt_environment'. The check is inserted immediately // before 'insert_before'. void AddCheckClass(Definition* to_check, const Cids& cids, intptr_t deopt_id, Environment* deopt_environment, Instruction* insert_before); // Insert a Smi check if needed. void AddCheckSmi(Definition* to_check, intptr_t deopt_id, Environment* deopt_environment, Instruction* insert_before); // Add a class check for a call's nth argument immediately before the // call, using the call's IC data to determine the check, and the call's // deopt ID and deoptimization environment if the check fails. void AddChecksForArgNr(InstanceCallInstr* call, Definition* instr, int argument_number); bool InlineSimdBinaryOp(InstanceCallInstr* call, intptr_t cid, Token::Kind op_kind); bool TryInlineImplicitInstanceGetter(InstanceCallInstr* call); RawBool* InstanceOfAsBool(const ICData& ic_data, const AbstractType& type, ZoneGrowableArray* results) const; bool TryOptimizeInstanceOfUsingStaticTypes(InstanceCallInstr* call, const AbstractType& type); void ReplaceWithMathCFunction(InstanceCallInstr* call, MethodRecognizer::Kind recognized_kind); bool TryStringLengthOneEquality(InstanceCallInstr* call, Token::Kind op_kind); RawField* GetField(intptr_t class_id, const String& field_name); void SpecializePolymorphicInstanceCall(PolymorphicInstanceCallInstr* call); // Tries to add cid tests to 'results' so that no deoptimization is // necessary for common number-related type tests. Unconditionally adds an // entry for the Smi type to the start of the array. static bool SpecializeTestCidsForNumericTypes( ZoneGrowableArray* results, const AbstractType& type); FlowGraph* flow_graph_; }; } // namespace dart #endif // RUNTIME_VM_COMPILER_CALL_SPECIALIZER_H_