@@ -167,84 +167,103 @@ Section::~Section() {
167
167
B->~Block ();
168
168
}
169
169
170
- Block &LinkGraph::splitBlock (Block &B, size_t SplitIndex,
171
- SplitBlockCache *Cache) {
172
-
173
- assert (SplitIndex > 0 && " splitBlock can not be called with SplitIndex == 0" );
174
-
175
- // If the split point covers all of B then just return B.
176
- if (SplitIndex == B.getSize ())
177
- return B;
178
-
179
- assert (SplitIndex < B.getSize () && " SplitIndex out of range" );
180
-
181
- // Create the new block covering [ 0, SplitIndex ).
182
- auto &NewBlock =
183
- B.isZeroFill ()
184
- ? createZeroFillBlock (B.getSection (), SplitIndex, B.getAddress (),
185
- B.getAlignment (), B.getAlignmentOffset ())
186
- : createContentBlock (
187
- B.getSection (), B.getContent ().slice (0 , SplitIndex),
188
- B.getAddress (), B.getAlignment (), B.getAlignmentOffset ());
189
-
190
- // Modify B to cover [ SplitIndex, B.size() ).
191
- B.setAddress (B.getAddress () + SplitIndex);
192
- B.setContent (B.getContent ().slice (SplitIndex));
193
- B.setAlignmentOffset ((B.getAlignmentOffset () + SplitIndex) %
194
- B.getAlignment ());
195
-
196
- // Handle edge transfer/update.
197
- {
198
- // Copy edges to NewBlock (recording their iterators so that we can remove
199
- // them from B), and update of Edges remaining on B.
200
- std::vector<Block::edge_iterator> EdgesToRemove;
201
- for (auto I = B.edges ().begin (); I != B.edges ().end ();) {
202
- if (I->getOffset () < SplitIndex) {
203
- NewBlock.addEdge (*I);
204
- I = B.removeEdge (I);
205
- } else {
206
- I->setOffset (I->getOffset () - SplitIndex);
207
- ++I;
208
- }
209
- }
170
+ std::vector<Block *> LinkGraph::splitBlockImpl (std::vector<Block *> Blocks,
171
+ SplitBlockCache *Cache) {
172
+ assert (!Blocks.empty () && " Blocks must at least contain the original block" );
173
+
174
+ // Fix up content of all blocks.
175
+ ArrayRef<char > Content = Blocks.front ()->getContent ();
176
+ for (size_t I = 0 ; I != Blocks.size () - 1 ; ++I) {
177
+ Blocks[I]->setContent (
178
+ Content.slice (Blocks[I]->getAddress () - Blocks[0 ]->getAddress (),
179
+ Blocks[I + 1 ]->getAddress () - Blocks[I]->getAddress ()));
210
180
}
181
+ Blocks.back ()->setContent (
182
+ Content.slice (Blocks.back ()->getAddress () - Blocks[0 ]->getAddress ()));
183
+ bool IsMutable = Blocks[0 ]->ContentMutable ;
184
+ for (auto *B : Blocks)
185
+ B->ContentMutable = IsMutable;
211
186
212
- // Handle symbol transfer/update .
187
+ // Transfer symbols .
213
188
{
214
- // Initialize the symbols cache if necessary.
215
189
SplitBlockCache LocalBlockSymbolsCache;
216
190
if (!Cache)
217
191
Cache = &LocalBlockSymbolsCache;
192
+
193
+ // Build cache if required.
218
194
if (*Cache == std::nullopt) {
219
195
*Cache = SplitBlockCache::value_type ();
220
- for (auto *Sym : B.getSection ().symbols ())
221
- if (&Sym->getBlock () == &B)
222
- (*Cache)->push_back (Sym);
223
196
197
+ for (auto *Sym : Blocks[0 ]->getSection ().symbols ())
198
+ if (&Sym->getBlock () == Blocks[0 ])
199
+ (*Cache)->push_back (Sym);
224
200
llvm::sort (**Cache, [](const Symbol *LHS, const Symbol *RHS) {
225
- return LHS->getOffset () > RHS->getOffset ();
201
+ return LHS->getAddress () > RHS->getAddress ();
226
202
});
227
203
}
228
- auto &BlockSymbols = **Cache;
229
-
230
- // Transfer all symbols with offset less than SplitIndex to NewBlock.
231
- while (!BlockSymbols.empty () &&
232
- BlockSymbols.back ()->getOffset () < SplitIndex) {
233
- auto *Sym = BlockSymbols.back ();
234
- // If the symbol extends beyond the split, update the size to be within
235
- // the new block.
236
- if (Sym->getOffset () + Sym->getSize () > SplitIndex)
237
- Sym->setSize (SplitIndex - Sym->getOffset ());
238
- Sym->setBlock (NewBlock);
239
- BlockSymbols.pop_back ();
204
+
205
+ auto TransferSymbol = [](Symbol &Sym, Block &B) {
206
+ Sym.setOffset (Sym.getAddress () - B.getAddress ());
207
+ if (Sym.getSize () > B.getSize ())
208
+ Sym.setSize (B.getSize () - Sym.getOffset ());
209
+ Sym.setBlock (B);
210
+ };
211
+
212
+ // Transfer symbols to all blocks except the last one.
213
+ for (size_t I = 0 ; I != Blocks.size () - 1 ; ++I) {
214
+ if ((*Cache)->empty ())
215
+ break ;
216
+ while (!(*Cache)->empty () &&
217
+ (*Cache)->back ()->getAddress () < Blocks[I + 1 ]->getAddress ()) {
218
+ TransferSymbol (*(*Cache)->back (), *Blocks[I]);
219
+ (*Cache)->pop_back ();
220
+ }
221
+ }
222
+ // Transfer symbols to the last block, checking that all are in-range.
223
+ while (!(*Cache)->empty ()) {
224
+ auto &Sym = *(*Cache)->back ();
225
+ (*Cache)->pop_back ();
226
+ assert (Sym.getAddress () >= Blocks.back ()->getAddress () &&
227
+ " Symbol address preceeds block" );
228
+ assert (Sym.getAddress () <= Blocks.back ()->getRange ().End &&
229
+ " Symbol address starts past end of block" );
230
+ TransferSymbol (Sym, *Blocks.back ());
231
+ }
232
+ }
233
+
234
+ // Transfer edges.
235
+ auto &Edges = Blocks[0 ]->Edges ;
236
+ llvm::sort (Edges, [](const Edge &LHS, const Edge &RHS) {
237
+ return LHS.getOffset () < RHS.getOffset ();
238
+ });
239
+
240
+ for (size_t I = Blocks.size () - 1 ; I != 0 ; --I) {
241
+
242
+ // If all edges have been transferred then bail out.
243
+ if (Edges.empty ())
244
+ break ;
245
+
246
+ Edge::OffsetT Delta = Blocks[I]->getAddress () - Blocks[0 ]->getAddress ();
247
+
248
+ // If no edges to move for this block then move to the next one.
249
+ if (Edges.back ().getOffset () < Delta)
250
+ continue ;
251
+
252
+ size_t EI = Edges.size () - 1 ;
253
+ while (EI != 0 && Edges[EI - 1 ].getOffset () >= Delta)
254
+ --EI;
255
+
256
+ for (size_t J = EI; J != Edges.size (); ++J) {
257
+ Blocks[I]->Edges .push_back (std::move (Edges[J]));
258
+ Blocks[I]->Edges .back ().setOffset (Blocks[I]->Edges .back ().getOffset () -
259
+ Delta);
240
260
}
241
261
242
- // Update offsets for all remaining symbols in B.
243
- for (auto *Sym : BlockSymbols)
244
- Sym->setOffset (Sym->getOffset () - SplitIndex);
262
+ while (Edges.size () > EI)
263
+ Edges.pop_back ();
245
264
}
246
265
247
- return NewBlock ;
266
+ return Blocks ;
248
267
}
249
268
250
269
void LinkGraph::dump (raw_ostream &OS) {
0 commit comments