Index: ELF/ICF.cpp =================================================================== --- ELF/ICF.cpp +++ ELF/ICF.cpp @@ -362,17 +362,12 @@ // vector. Therefore, Sections vector can be considered as contiguous // groups of sections, grouped by the class. // -// This function calls Fn on every group that starts within [Begin, End). -// Note that a group must start in that range but doesn't necessarily -// have to end before End. +// This function calls Fn on every group within [Begin, End). template void ICF::forEachClassRange(size_t Begin, size_t End, std::function Fn) { - if (Begin > 0) - Begin = findBoundary(Begin - 1, End); - while (Begin < End) { - size_t Mid = findBoundary(Begin, Sections.size()); + size_t Mid = findBoundary(Begin, End); Fn(Begin, Mid); Begin = Mid; } @@ -392,12 +387,23 @@ Current = Cnt % 2; Next = (Cnt + 1) % 2; - // Split sections into 256 shards and call Fn in parallel. - size_t NumShards = 256; + // Shard into non-overlapping intervals, and call Fn in parallel. + // The sharding must be completed before any calls to Fn are made + // so that Fn can modify the Chunks in its shard without causing data + // races. + const size_t NumShards = 256; size_t Step = Sections.size() / NumShards; - parallelForEachN(0, NumShards, [&](size_t I) { - size_t End = (I == NumShards - 1) ? Sections.size() : (I + 1) * Step; - forEachClassRange(I * Step, End, Fn); + size_t Boundaries[NumShards + 1]; + Boundaries[0] = 0; + Boundaries[NumShards] = Sections.size(); + + parallelForEachN(1, NumShards, [&](size_t I) { + Boundaries[I] = findBoundary((I - 1) * Step, Sections.size()); + }); + + parallelForEachN(1, NumShards + 1, [&](size_t I) { + if (Boundaries[I - 1] < Boundaries[I]) + forEachClassRange(Boundaries[I - 1], Boundaries[I], Fn); }); ++Cnt; }