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: |