| Index: runtime/vm/precompiler.cc | 
| diff --git a/runtime/vm/precompiler.cc b/runtime/vm/precompiler.cc | 
| index 1d111ddc7486877dc08c0d04320fec32d86d4532..887c3d1ae4a451b2c9905dc4dcdbc161caa8de2b 100644 | 
| --- a/runtime/vm/precompiler.cc | 
| +++ b/runtime/vm/precompiler.cc | 
| @@ -213,6 +213,7 @@ void Precompiler::DoCompileAll( | 
| DropLibraries(); | 
|  | 
| BindStaticCalls(); | 
| +    SwitchICCalls(); | 
|  | 
| DedupStackmaps(); | 
| DedupStackmapLists(); | 
| @@ -1655,6 +1656,84 @@ void Precompiler::BindStaticCalls() { | 
| } | 
|  | 
|  | 
| +void Precompiler::SwitchICCalls() { | 
| +  // Now that all functions have been compiled, we can switch to an instance | 
| +  // call sequence that loads the Code object and entry point directly from | 
| +  // the ic data array instead indirectly through a Function in the ic data | 
| +  // array. Iterate all the object pools and rewrite the ic data from | 
| +  // (cid, target function, count) to (cid, target code, entry point), and | 
| +  // replace the ICLookupThroughFunction stub with ICLookupThroughCode. | 
| + | 
| +  class SwitchICCallsVisitor : public FunctionVisitor { | 
| +   public: | 
| +    explicit SwitchICCallsVisitor(Zone* zone) : | 
| +        code_(Code::Handle(zone)), | 
| +        pool_(ObjectPool::Handle(zone)), | 
| +        entry_(Object::Handle(zone)), | 
| +        ic_(ICData::Handle(zone)), | 
| +        target_(Function::Handle(zone)), | 
| +        target_code_(Code::Handle(zone)), | 
| +        entry_point_(Smi::Handle(zone)) { | 
| +    } | 
| + | 
| +    void VisitFunction(const Function& function) { | 
| +      if (!function.HasCode()) { | 
| +        ASSERT(function.HasImplicitClosureFunction()); | 
| +        return; | 
| +      } | 
| + | 
| +      code_ = function.CurrentCode(); | 
| +      pool_ = code_.object_pool(); | 
| +      for (intptr_t i = 0; i < pool_.Length(); i++) { | 
| +        if (pool_.InfoAt(i) != ObjectPool::kTaggedObject) continue; | 
| +        entry_ = pool_.ObjectAt(i); | 
| +        if (entry_.IsICData()) { | 
| +          ic_ ^= entry_.raw(); | 
| + | 
| +          // Only single check ICs are SwitchableCalls that use the ICLookup | 
| +          // stubs. Some operators like + have ICData that check the types of | 
| +          // arguments in addition to the receiver and use special stubs | 
| +          // with fast paths for Smi operations. | 
| +          if (ic_.NumArgsTested() != 1) continue; | 
| + | 
| +          for (intptr_t j = 0; j < ic_.NumberOfChecks(); j++) { | 
| +            entry_ = ic_.GetTargetOrCodeAt(j); | 
| +            if (entry_.IsFunction()) { | 
| +              target_ ^= entry_.raw(); | 
| +              ASSERT(target_.HasCode()); | 
| +              target_code_ = target_.CurrentCode(); | 
| +              entry_point_ = Smi::FromAlignedAddress(target_code_.EntryPoint()); | 
| +              ic_.SetCodeAt(j, target_code_); | 
| +              ic_.SetEntryPointAt(j, entry_point_); | 
| +            } else { | 
| +              // We've already seen and switched this ICData. | 
| +              ASSERT(entry_.IsCode()); | 
| +            } | 
| +          } | 
| +        } else if (entry_.raw() == | 
| +                   StubCode::ICLookupThroughFunction_entry()->code()) { | 
| +          target_code_ = StubCode::ICLookupThroughCode_entry()->code(); | 
| +          pool_.SetObjectAt(i, target_code_); | 
| +        } | 
| +      } | 
| +    } | 
| + | 
| +   private: | 
| +    Code& code_; | 
| +    ObjectPool& pool_; | 
| +    Object& entry_; | 
| +    ICData& ic_; | 
| +    Function& target_; | 
| +    Code& target_code_; | 
| +    Smi& entry_point_; | 
| +  }; | 
| + | 
| +  ASSERT(!I->compilation_allowed()); | 
| +  SwitchICCallsVisitor visitor(Z); | 
| +  VisitFunctions(&visitor); | 
| +} | 
| + | 
| + | 
| void Precompiler::DedupStackmaps() { | 
| class DedupStackmapsVisitor : public FunctionVisitor { | 
| public: | 
|  |