@@ -63,158 +63,167 @@ constexpr uint8_t RecContinued = Flags(7, 1, 1);
6363constexpr uint8_t RecContinuation = Flags(6 , 1 , 1 );
6464
6565// 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 {
7377 // / The underlying raw_pwrite_stream.
7478 raw_pwrite_stream &OS;
7579
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 ;
9282
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 ;
9685
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;
10988
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 ;
11291
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] ;
11594
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 ;
11998
12099public:
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 ();
127102
128103 raw_pwrite_stream &getOS () { return OS; }
104+ size_t getWrittenSize () const { return PhysicalRecords * GOFF::RecordLength; }
105+ uint32_t getNumLogicalRecords () { return LogicalRecords; }
129106
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);
133109
134- uint32_t logicalRecords () { return LogicalRecords; }
110+ // / Write zeroes, up to a maximum of 16 bytes.
111+ void write_zeros (unsigned NumZeros);
135112
136- // Support for endian-specific data.
113+ // / Support for endian-specific data.
137114 template <typename value_type> void writebe (value_type Value) {
138115 Value =
139116 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));
141118 }
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 ();
142133};
134+ } // namespace
135+
136+ GOFFOstream::GOFFOstream (raw_pwrite_stream &OS) : OS(OS) {}
143137
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)
148145 TypeAndFlags |= RecContinued;
146+ else
147+ TypeAndFlags &= ~RecContinued;
148+
149149 OS << static_cast <unsigned char >(GOFF::PTVPrefix) // Record Type
150150 << static_cast <unsigned char >(TypeAndFlags) // Continuation
151151 << static_cast <unsigned char >(0 ); // Version
152+
153+ ++PhysicalRecords;
152154}
153155
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);
168158}
169159
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;
179178 }
180- flush ();
181- assert (RemainingSize == 0 && " Not fully flushed" );
182- assert (GetNumBytesInBuffer () == 0 && " Buffer not fully empty" );
183- }
184179
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;
200185 }
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 ;
215201 }
202+
203+ // Otherwise some field value is cleared.
204+ static char Zeros[16 ] = {
205+ 0 ,
206+ };
207+ write (Zeros, NumZeros);
216208}
217209
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+
218227class GOFFObjectWriter : public MCObjectWriter {
219228 // The target specific GOFF writer instance.
220229 std::unique_ptr<MCGOFFObjectTargetWriter> TargetObjectWriter;
@@ -242,7 +251,7 @@ class GOFFObjectWriter : public MCObjectWriter {
242251} // end anonymous namespace
243252
244253void GOFFObjectWriter::writeHeader () {
245- OS.newRecord (GOFF::RT_HDR, /* Size= */ 57 );
254+ OS.newRecord (GOFF::RT_HDR);
246255 OS.write_zeros (1 ); // Reserved
247256 OS.writebe <uint32_t >(0 ); // Target Hardware Environment
248257 OS.writebe <uint32_t >(0 ); // Target Operating System Environment
@@ -262,7 +271,7 @@ void GOFFObjectWriter::writeEnd() {
262271
263272 // TODO Set Flags/AMODE/ESDID for entry point.
264273
265- OS.newRecord (GOFF::RT_END, /* Size= */ 13 );
274+ OS.newRecord (GOFF::RT_END);
266275 OS.writebe <uint8_t >(Flags (6 , 2 , F)); // Indicator flags
267276 OS.writebe <uint8_t >(AMODE); // AMODE
268277 OS.write_zeros (3 ); // Reserved
@@ -271,18 +280,19 @@ void GOFFObjectWriter::writeEnd() {
271280 // being zero.
272281 OS.writebe <uint32_t >(0 ); // Record Count
273282 OS.writebe <uint32_t >(ESDID); // ESDID (of entry point)
274- OS.finalize ();
275283}
276284
277285uint64_t GOFFObjectWriter::writeObject (MCAssembler &Asm) {
278- uint64_t StartOffset = OS.tell ();
279-
280286 writeHeader ();
281287 writeEnd ();
282288
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." );
284294
285- return OS.tell () - StartOffset ;
295+ return OS.getWrittenSize () ;
286296}
287297
288298std::unique_ptr<MCObjectWriter>
0 commit comments