| Index: runtime/vm/flow_graph_inliner.cc | 
| =================================================================== | 
| --- runtime/vm/flow_graph_inliner.cc	(revision 41687) | 
| +++ runtime/vm/flow_graph_inliner.cc	(working copy) | 
| @@ -51,6 +51,8 @@ | 
| DEFINE_FLAG(int, max_inlined_per_depth, 500, | 
| "Max. number of inlined calls per depth"); | 
| DEFINE_FLAG(bool, print_inlining_tree, false, "Print inlining tree"); | 
| +DEFINE_FLAG(bool, enable_inlining_annotations, false, | 
| +            "Enable inlining annotations"); | 
|  | 
| DECLARE_FLAG(bool, compiler_stats); | 
| DECLARE_FLAG(bool, enable_type_checks); | 
| @@ -448,6 +450,25 @@ | 
| }; | 
|  | 
|  | 
| +static bool HasAnnotation(const Function& function, const char* annotation) { | 
| +  const Class& owner = Class::Handle(function.Owner()); | 
| +  const Library& library = Library::Handle(owner.library()); | 
| +  const Array& metadata = | 
| +      Array::Cast(Object::Handle(library.GetMetadata(function))); | 
| + | 
| +  if (metadata.Length() > 0) { | 
| +    Object& val = Object::Handle(); | 
| +    for (intptr_t i = 0; i < metadata.Length(); i++) { | 
| +      val = metadata.At(i); | 
| +      if (val.IsString() && String::Cast(val).Equals(annotation)) { | 
| +        return true; | 
| +      } | 
| +    } | 
| +  } | 
| +  return false; | 
| +} | 
| + | 
| + | 
| class CallSiteInliner : public ValueObject { | 
| public: | 
| explicit CallSiteInliner(FlowGraph* flow_graph) | 
| @@ -593,6 +614,13 @@ | 
| return false; | 
| } | 
|  | 
| +    const char* kNeverInlineAnnotation = "NeverInline"; | 
| +    if (FLAG_enable_inlining_annotations && | 
| +        HasAnnotation(function, kNeverInlineAnnotation)) { | 
| +      TRACE_INLINING(OS::Print("     Bailout: NeverInline annotation\n")); | 
| +      return false; | 
| +    } | 
| + | 
| GrowableArray<Value*>* arguments = call_data->arguments; | 
| const intptr_t constant_arguments = CountConstants(*arguments); | 
| if (!ShouldWeInline(function, | 
| @@ -614,7 +642,6 @@ | 
| // Abort if this is a recursive occurrence. | 
| Definition* call = call_data->call; | 
| if (!FLAG_inline_recursive && IsCallRecursive(unoptimized_code, call)) { | 
| -      function.set_is_inlinable(false); | 
| TRACE_INLINING(OS::Print("     Bailout: recursive function\n")); | 
| PRINT_INLINING_TREE("Recursive function", | 
| &call_data->caller, &function, call_data->call); | 
| @@ -1685,6 +1712,14 @@ | 
|  | 
|  | 
| bool FlowGraphInliner::AlwaysInline(const Function& function) { | 
| +  const char* kAlwaysInlineAnnotation = "AlwaysInline"; | 
| +  if (FLAG_enable_inlining_annotations && | 
| +      HasAnnotation(function, kAlwaysInlineAnnotation)) { | 
| +    TRACE_INLINING(OS::Print("AlwaysInline annotation for %s\n", | 
| +                             function.ToCString())); | 
| +    return true; | 
| +  } | 
| + | 
| if (function.IsImplicitGetterFunction() || function.IsGetterFunction() || | 
| function.IsImplicitSetterFunction() || function.IsSetterFunction()) { | 
| const intptr_t count = function.optimized_instruction_count(); | 
|  |