@@ -63,158 +63,167 @@ constexpr uint8_t RecContinued = Flags(7, 1, 1);
63
63
constexpr uint8_t RecContinuation = Flags(6 , 1 , 1 );
64
64
65
65
// The GOFFOstream is responsible to write the data into the fixed physical
66
- // records of the format. A user of this class announces the start of a new
67
- // logical record and the size of its content. While writing the content, the
68
- // physical records are created for the data. Possible fill bytes at the end of
69
- // a physical record are written automatically. In principle, the GOFFOstream
70
- // is agnostic of the endianness of the content. However, it also supports
71
- // writing data in big endian byte order.
72
- class GOFFOstream : public raw_ostream {
66
+ // records of the format. A user of this class announces the begin of a new
67
+ // logical record. While writing the payload, the physical records are created
68
+ // for the data. Possible fill bytes at the end of a physical record are written
69
+ // automatically. In principle, the GOFFOstream is agnostic of the endianness of
70
+ // the payload. However, it also supports writing data in big endian byte order.
71
+ //
72
+ // The physical records use the flag field to indicate if the there is a
73
+ // successor and predecessor record. To be able to set these flags while
74
+ // writing, the basic implementation idea is to always buffer the last seen
75
+ // physical record.
76
+ class GOFFOstream {
73
77
// / The underlying raw_pwrite_stream.
74
78
raw_pwrite_stream &OS;
75
79
76
- // / The remaining size of this logical record, including fill bytes.
77
- size_t RemainingSize;
78
-
79
- #ifndef NDEBUG
80
- // / The number of bytes needed to fill up the last physical record.
81
- size_t Gap = 0 ;
82
- #endif
83
-
84
- // / The number of logical records emitted to far.
85
- uint32_t LogicalRecords;
86
-
87
- // / The type of the current (logical) record.
88
- GOFF::RecordType CurrentType;
89
-
90
- // / Signals start of new record.
91
- bool NewLogicalRecord;
80
+ // / The number of logical records emitted so far.
81
+ uint32_t LogicalRecords = 0 ;
92
82
93
- // / Static allocated buffer for the stream, used by the raw_ostream class. The
94
- // / buffer is sized to hold the content of a physical record.
95
- char Buffer[GOFF::RecordContentLength];
83
+ // / The number of physical records emitted so far.
84
+ uint32_t PhysicalRecords = 0 ;
96
85
97
- // Return the number of bytes left to write until next physical record.
98
- // Please note that we maintain the total numbers of byte left, not the
99
- // written size.
100
- size_t bytesToNextPhysicalRecord () {
101
- size_t Bytes = RemainingSize % GOFF::RecordContentLength;
102
- return Bytes ? Bytes : GOFF::RecordContentLength;
103
- }
104
-
105
- // / Write the record prefix of a physical record, using the given record type.
106
- static void writeRecordPrefix (raw_ostream &OS, GOFF::RecordType Type,
107
- size_t RemainingSize,
108
- uint8_t Flags = RecContinuation);
86
+ // / The size of the buffer. Same as the payload size of a physical record.
87
+ static constexpr uint8_t BufferSize = GOFF::PayloadLength;
109
88
110
- // / Fill the last physical record of a logical record with zero bytes .
111
- void fillRecord () ;
89
+ // / Current position in buffer .
90
+ char *BufferPtr = Buffer ;
112
91
113
- // / See raw_ostream::write_impl .
114
- void write_impl ( const char * Ptr , size_t Size ) override ;
92
+ // / Static allocated buffer for the stream .
93
+ char Buffer[BufferSize] ;
115
94
116
- // / Return the current position within the stream, not counting the bytes
117
- // / currently in the buffer .
118
- uint64_t current_pos () const override { return OS. tell (); }
95
+ // / The type of the current logical record, and the flags (aka continued and
96
+ // / continuation indicators) for the previous (physical) record .
97
+ uint8_t TypeAndFlags = 0 ;
119
98
120
99
public:
121
- explicit GOFFOstream (raw_pwrite_stream &OS)
122
- : OS(OS), RemainingSize(0 ), LogicalRecords(0 ), NewLogicalRecord(false ) {
123
- SetBuffer (Buffer, sizeof (Buffer));
124
- }
125
-
126
- ~GOFFOstream () { finalize (); }
100
+ GOFFOstream (raw_pwrite_stream &OS);
101
+ ~GOFFOstream ();
127
102
128
103
raw_pwrite_stream &getOS () { return OS; }
104
+ size_t getWrittenSize () const { return PhysicalRecords * GOFF::RecordLength; }
105
+ uint32_t getNumLogicalRecords () { return LogicalRecords; }
129
106
130
- void newRecord (GOFF::RecordType Type, size_t Size );
131
-
132
- void finalize () { fillRecord (); }
107
+ // / Write the specified bytes.
108
+ void write (const char *Ptr , size_t Size );
133
109
134
- uint32_t logicalRecords () { return LogicalRecords; }
110
+ // / Write zeroes, up to a maximum of 16 bytes.
111
+ void write_zeros (unsigned NumZeros);
135
112
136
- // Support for endian-specific data.
113
+ // / Support for endian-specific data.
137
114
template <typename value_type> void writebe (value_type Value) {
138
115
Value =
139
116
support::endian::byte_swap<value_type>(Value, llvm::endianness::big);
140
- write (reinterpret_cast < const char *>( &Value) , sizeof (value_type));
117
+ write (( const char *) &Value, sizeof (value_type));
141
118
}
119
+
120
+ // / Begin a new logical record. Implies finalizing the previous record.
121
+ void newRecord (GOFF::RecordType Type);
122
+
123
+ // / Ends a logical record.
124
+ void finalizeRecord ();
125
+
126
+ private:
127
+ // / Updates the continued/continuation flags, and writes the record prefix of
128
+ // / a physical record.
129
+ void updateFlagsAndWritePrefix (bool IsContinued);
130
+
131
+ // / Returns the remaining size in the buffer.
132
+ size_t getRemainingSize ();
142
133
};
134
+ } // namespace
135
+
136
+ GOFFOstream::GOFFOstream (raw_pwrite_stream &OS) : OS(OS) {}
143
137
144
- void GOFFOstream::writeRecordPrefix (raw_ostream &OS, GOFF::RecordType Type,
145
- size_t RemainingSize, uint8_t Flags) {
146
- uint8_t TypeAndFlags = Flags | (Type << 4 );
147
- if (RemainingSize > GOFF::RecordLength)
138
+ GOFFOstream::~GOFFOstream () { finalizeRecord (); }
139
+
140
+ void GOFFOstream::updateFlagsAndWritePrefix (bool IsContinued) {
141
+ // Update the flags based on the previous state and the flag IsContinued.
142
+ if (TypeAndFlags & RecContinued)
143
+ TypeAndFlags |= RecContinuation;
144
+ if (IsContinued)
148
145
TypeAndFlags |= RecContinued;
146
+ else
147
+ TypeAndFlags &= ~RecContinued;
148
+
149
149
OS << static_cast <unsigned char >(GOFF::PTVPrefix) // Record Type
150
150
<< static_cast <unsigned char >(TypeAndFlags) // Continuation
151
151
<< static_cast <unsigned char >(0 ); // Version
152
+
153
+ ++PhysicalRecords;
152
154
}
153
155
154
- void GOFFOstream::newRecord (GOFF::RecordType Type, size_t Size ) {
155
- fillRecord ();
156
- CurrentType = Type;
157
- RemainingSize = Size ;
158
- #ifdef NDEBUG
159
- size_t Gap;
160
- #endif
161
- Gap = (RemainingSize % GOFF::RecordContentLength);
162
- if (Gap) {
163
- Gap = GOFF::RecordContentLength - Gap;
164
- RemainingSize += Gap;
165
- }
166
- NewLogicalRecord = true ;
167
- ++LogicalRecords;
156
+ size_t GOFFOstream::getRemainingSize () {
157
+ return size_t (&Buffer[BufferSize] - BufferPtr);
168
158
}
169
159
170
- void GOFFOstream::fillRecord () {
171
- assert ((GetNumBytesInBuffer () <= RemainingSize) &&
172
- " More bytes in buffer than expected" );
173
- size_t Remains = RemainingSize - GetNumBytesInBuffer ();
174
- if (Remains) {
175
- assert (Remains == Gap && " Wrong size of fill gap" );
176
- assert ((Remains < GOFF::RecordLength) &&
177
- " Attempt to fill more than one physical record" );
178
- raw_ostream::write_zeros (Remains);
160
+ void GOFFOstream::write (const char *Ptr , size_t Size ) {
161
+ size_t RemainingSize = getRemainingSize ();
162
+
163
+ // Data fits into the buffer.
164
+ if (LLVM_LIKELY (Size <= RemainingSize)) {
165
+ memcpy (BufferPtr, Ptr , Size );
166
+ BufferPtr += Size ;
167
+ return ;
168
+ }
169
+
170
+ // Otherwise the buffer is partially filled or full, and data does not fit
171
+ // into it.
172
+ updateFlagsAndWritePrefix (/* IsContinued=*/ true );
173
+ OS.write (Buffer, size_t (BufferPtr - Buffer));
174
+ if (RemainingSize > 0 ) {
175
+ OS.write (Ptr , RemainingSize);
176
+ Ptr += RemainingSize;
177
+ Size -= RemainingSize;
179
178
}
180
- flush ();
181
- assert (RemainingSize == 0 && " Not fully flushed" );
182
- assert (GetNumBytesInBuffer () == 0 && " Buffer not fully empty" );
183
- }
184
179
185
- // This function is called from the raw_ostream implementation if:
186
- // - The internal buffer is full. Size is excactly the size of the buffer.
187
- // - Data larger than the internal buffer is written. Size is a multiple of the
188
- // buffer size.
189
- // - flush() has been called. Size is at most the buffer size.
190
- // The GOFFOstream implementation ensures that flush() is called before a new
191
- // logical record begins. Therefore it is sufficient to check for a new block
192
- // only once.
193
- void GOFFOstream::write_impl (const char *Ptr , size_t Size ) {
194
- assert ((RemainingSize >= Size ) && " Attempt to write too much data" );
195
- assert (RemainingSize && " Logical record overflow" );
196
- if (!(RemainingSize % GOFF::RecordContentLength)) {
197
- writeRecordPrefix (OS, CurrentType, RemainingSize,
198
- NewLogicalRecord ? 0 : RecContinuation);
199
- NewLogicalRecord = false ;
180
+ while (Size > BufferSize) {
181
+ updateFlagsAndWritePrefix (/* IsContinued=*/ true );
182
+ OS.write (Ptr , BufferSize);
183
+ Ptr += BufferSize;
184
+ Size -= BufferSize;
200
185
}
201
- assert (!NewLogicalRecord &&
202
- " New logical record not on physical record boundary" );
203
-
204
- size_t Idx = 0 ;
205
- while (Size > 0 ) {
206
- size_t BytesToWrite = bytesToNextPhysicalRecord ();
207
- if (BytesToWrite > Size )
208
- BytesToWrite = Size ;
209
- OS.write (Ptr + Idx, BytesToWrite);
210
- Idx += BytesToWrite;
211
- Size -= BytesToWrite;
212
- RemainingSize -= BytesToWrite;
213
- if (Size )
214
- writeRecordPrefix (OS, CurrentType, RemainingSize);
186
+
187
+ // The remaining bytes fit into the buffer.
188
+ memcpy (Buffer, Ptr , Size );
189
+ BufferPtr = &Buffer[Size ];
190
+ }
191
+
192
+ void GOFFOstream::write_zeros (unsigned NumZeros) {
193
+ assert (NumZeros <= 16 && " Range for zeros too large" );
194
+
195
+ // Handle the common case first: all fits in the buffer.
196
+ size_t RemainingSize = getRemainingSize ();
197
+ if (LLVM_LIKELY (RemainingSize >= NumZeros)) {
198
+ memset (BufferPtr, 0 , NumZeros);
199
+ BufferPtr += NumZeros;
200
+ return ;
215
201
}
202
+
203
+ // Otherwise some field value is cleared.
204
+ static char Zeros[16 ] = {
205
+ 0 ,
206
+ };
207
+ write (Zeros, NumZeros);
216
208
}
217
209
210
+ void GOFFOstream::newRecord (GOFF::RecordType Type) {
211
+ finalizeRecord ();
212
+ TypeAndFlags = Type << 4 ;
213
+ ++LogicalRecords;
214
+ }
215
+
216
+ void GOFFOstream::finalizeRecord () {
217
+ if (Buffer == BufferPtr)
218
+ return ;
219
+ updateFlagsAndWritePrefix (/* IsContinued=*/ false );
220
+ OS.write (Buffer, size_t (BufferPtr - Buffer));
221
+ OS.write_zeros (getRemainingSize ());
222
+ BufferPtr = Buffer;
223
+ }
224
+
225
+ namespace {
226
+
218
227
class GOFFObjectWriter : public MCObjectWriter {
219
228
// The target specific GOFF writer instance.
220
229
std::unique_ptr<MCGOFFObjectTargetWriter> TargetObjectWriter;
@@ -242,7 +251,7 @@ class GOFFObjectWriter : public MCObjectWriter {
242
251
} // end anonymous namespace
243
252
244
253
void GOFFObjectWriter::writeHeader () {
245
- OS.newRecord (GOFF::RT_HDR, /* Size= */ 57 );
254
+ OS.newRecord (GOFF::RT_HDR);
246
255
OS.write_zeros (1 ); // Reserved
247
256
OS.writebe <uint32_t >(0 ); // Target Hardware Environment
248
257
OS.writebe <uint32_t >(0 ); // Target Operating System Environment
@@ -262,7 +271,7 @@ void GOFFObjectWriter::writeEnd() {
262
271
263
272
// TODO Set Flags/AMODE/ESDID for entry point.
264
273
265
- OS.newRecord (GOFF::RT_END, /* Size= */ 13 );
274
+ OS.newRecord (GOFF::RT_END);
266
275
OS.writebe <uint8_t >(Flags (6 , 2 , F)); // Indicator flags
267
276
OS.writebe <uint8_t >(AMODE); // AMODE
268
277
OS.write_zeros (3 ); // Reserved
@@ -271,18 +280,19 @@ void GOFFObjectWriter::writeEnd() {
271
280
// being zero.
272
281
OS.writebe <uint32_t >(0 ); // Record Count
273
282
OS.writebe <uint32_t >(ESDID); // ESDID (of entry point)
274
- OS.finalize ();
275
283
}
276
284
277
285
uint64_t GOFFObjectWriter::writeObject (MCAssembler &Asm) {
278
- uint64_t StartOffset = OS.tell ();
279
-
280
286
writeHeader ();
281
287
writeEnd ();
282
288
283
- LLVM_DEBUG (dbgs () << " Wrote " << OS.logicalRecords () << " logical records." );
289
+ // Make sure all records are written.
290
+ OS.finalizeRecord ();
291
+
292
+ LLVM_DEBUG (dbgs () << " Wrote " << OS.getNumLogicalRecords ()
293
+ << " logical records." );
284
294
285
- return OS.tell () - StartOffset ;
295
+ return OS.getWrittenSize () ;
286
296
}
287
297
288
298
std::unique_ptr<MCObjectWriter>
0 commit comments