|  | // Copyright (c) 2012, 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_BACKEND_INLINER_H_ | 
|  | #define RUNTIME_VM_COMPILER_BACKEND_INLINER_H_ | 
|  |  | 
|  | #if defined(DART_PRECOMPILED_RUNTIME) | 
|  | #error "AOT runtime should not use compiler sources (including header files)" | 
|  | #endif  // defined(DART_PRECOMPILED_RUNTIME) | 
|  |  | 
|  | #include "vm/allocation.h" | 
|  | #include "vm/growable_array.h" | 
|  | #include "vm/token_position.h" | 
|  |  | 
|  | namespace dart { | 
|  |  | 
|  | class Definition; | 
|  | class Field; | 
|  | class FlowGraph; | 
|  | class ForwardInstructionIterator; | 
|  | class Function; | 
|  | class FunctionEntryInstr; | 
|  | class GraphEntryInstr; | 
|  | class ICData; | 
|  | class InstanceCallInstr; | 
|  | class Instruction; | 
|  | struct InstructionSource; | 
|  | class Precompiler; | 
|  | class StaticCallInstr; | 
|  | class TargetEntryInstr; | 
|  |  | 
|  | class SpeculativeInliningPolicy { | 
|  | public: | 
|  | explicit SpeculativeInliningPolicy(bool enable_suppression, | 
|  | intptr_t limit = -1) | 
|  | : enable_suppression_(enable_suppression), remaining_(limit) {} | 
|  |  | 
|  | bool AllowsSpeculativeInlining() const { | 
|  | return !enable_suppression_ || remaining_ > 0; | 
|  | } | 
|  |  | 
|  | bool IsAllowedForInlining(intptr_t call_deopt_id) const { | 
|  | // If we are not suppressing, we always enable optimistic inlining. | 
|  | if (!enable_suppression_) { | 
|  | return true; | 
|  | } | 
|  |  | 
|  | // If we have already suppressed the deopt-id we don't allow inlining it. | 
|  | if (IsSuppressed(call_deopt_id)) { | 
|  | return false; | 
|  | } | 
|  |  | 
|  | // Allow it if we can bailout at least one more time. | 
|  | return remaining_ > 0; | 
|  | } | 
|  |  | 
|  | bool AddBlockedDeoptId(intptr_t id) { | 
|  | ASSERT(enable_suppression_); | 
|  | #if defined(DEBUG) | 
|  | ASSERT(!IsSuppressed(id)); | 
|  | #endif | 
|  |  | 
|  | // If we exhausted the number of suppression entries there is no point | 
|  | // in adding entries to the list. | 
|  | if (remaining_ <= 0) return false; | 
|  |  | 
|  | inlining_suppressions_.Add(id); | 
|  | remaining_ -= 1; | 
|  | return true; | 
|  | } | 
|  |  | 
|  | intptr_t length() const { return inlining_suppressions_.length(); } | 
|  |  | 
|  | private: | 
|  | bool IsSuppressed(intptr_t id) const { | 
|  | for (intptr_t i = 0; i < inlining_suppressions_.length(); ++i) { | 
|  | if (inlining_suppressions_[i] == id) return true; | 
|  | } | 
|  | return false; | 
|  | } | 
|  |  | 
|  | // Whether we enable suppressing inlining at specific deopt-ids. | 
|  | const bool enable_suppression_; | 
|  |  | 
|  | // After we reach [remaining_] number of deopt-ids in [inlining_suppressions_] | 
|  | // list, we'll disable speculative inlining entirely. | 
|  | intptr_t remaining_; | 
|  | GrowableArray<intptr_t> inlining_suppressions_; | 
|  | }; | 
|  |  | 
|  | class FlowGraphInliner : ValueObject { | 
|  | public: | 
|  | FlowGraphInliner(FlowGraph* flow_graph, | 
|  | GrowableArray<const Function*>* inline_id_to_function, | 
|  | GrowableArray<TokenPosition>* inline_id_to_token_pos, | 
|  | GrowableArray<intptr_t>* caller_inline_id, | 
|  | SpeculativeInliningPolicy* speculative_policy, | 
|  | Precompiler* precompiler); | 
|  |  | 
|  | // The flow graph is destructively updated upon inlining.  Returns the max | 
|  | // depth that we inlined. | 
|  | int Inline(); | 
|  |  | 
|  | // Computes graph information (instruction and call site count). | 
|  | // For the non-specialized cases (num_constants_args == 0), the | 
|  | // method uses a cache to avoid recomputing the counts (the cached | 
|  | // value may still be approximate but close). The 'force' flag is | 
|  | // used to update the cached value at the end of running the full pipeline | 
|  | // on non-specialized cases. Specialized cases (num_constants_args > 0) | 
|  | // always recompute the counts without caching. | 
|  | // | 
|  | // TODO(ajcbik): cache for specific constant argument combinations too? | 
|  | static void CollectGraphInfo(FlowGraph* flow_graph, | 
|  | intptr_t num_constant_args, | 
|  | bool force, | 
|  | intptr_t* instruction_count, | 
|  | intptr_t* call_site_count); | 
|  |  | 
|  | static void SetInliningId(FlowGraph* flow_graph, intptr_t inlining_id); | 
|  |  | 
|  | bool AlwaysInline(const Function& function); | 
|  |  | 
|  | static bool FunctionHasPreferInlinePragma(const Function& function); | 
|  | static bool FunctionHasNeverInlinePragma(const Function& function); | 
|  | static bool FunctionHasAlwaysConsiderInliningPragma(const Function& function); | 
|  |  | 
|  | FlowGraph* flow_graph() const { return flow_graph_; } | 
|  | intptr_t NextInlineId(const Function& function, | 
|  | const InstructionSource& source); | 
|  |  | 
|  | bool trace_inlining() const { return trace_inlining_; } | 
|  |  | 
|  | SpeculativeInliningPolicy* speculative_policy() { | 
|  | return speculative_policy_; | 
|  | } | 
|  |  | 
|  | private: | 
|  | friend class CallSiteInliner; | 
|  |  | 
|  | FlowGraph* flow_graph_; | 
|  | GrowableArray<const Function*>* inline_id_to_function_; | 
|  | GrowableArray<TokenPosition>* inline_id_to_token_pos_; | 
|  | GrowableArray<intptr_t>* caller_inline_id_; | 
|  | const bool trace_inlining_; | 
|  | SpeculativeInliningPolicy* speculative_policy_; | 
|  | Precompiler* precompiler_; | 
|  |  | 
|  | DISALLOW_COPY_AND_ASSIGN(FlowGraphInliner); | 
|  | }; | 
|  |  | 
|  | }  // namespace dart | 
|  |  | 
|  | #endif  // RUNTIME_VM_COMPILER_BACKEND_INLINER_H_ |