blob: c0ebff78017706e39a203875e43198e238bf0a0a [file] [log] [blame]
Ted Kremenekbfa82c42007-10-16 23:37:27 +00001//===--- SerializationTest.cpp - Experimental Object Serialization --------===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file was developed by Ted Kremenek and is distributed under
6// the University of Illinois Open Source License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9//
10// This file implements prototype code for serialization of objects in clang.
11// It is not intended yet for public use, but simply is a placeholder to
12// experiment with new serialization features. Serialization will eventually
13// be integrated as a proper component of the clang libraries.
14//
15//===----------------------------------------------------------------------===//
16
17#include "ASTConsumers.h"
18#include "clang/AST/AST.h"
19#include "clang/AST/ASTConsumer.h"
20#include "clang/AST/ASTContext.h"
21#include "llvm/System/Path.h"
Ted Kremenekc637e6b2007-10-23 22:18:37 +000022#include "llvm/Support/Streams.h"
23#include "llvm/Support/MemoryBuffer.h"
Ted Kremeneka2bfb912007-10-24 19:06:02 +000024#include "llvm/Bitcode/Serialize.h"
25#include "llvm/Bitcode/Deserialize.h"
Ted Kremenekc637e6b2007-10-23 22:18:37 +000026#include <stdio.h>
Ted Kremenek018b3952007-11-06 19:50:53 +000027#include <list>
Ted Kremenekc637e6b2007-10-23 22:18:37 +000028
Ted Kremenekbfa82c42007-10-16 23:37:27 +000029using namespace clang;
Ted Kremenek4ac81212007-11-05 21:39:35 +000030using llvm::sys::TimeValue;
Ted Kremenekbfa82c42007-10-16 23:37:27 +000031
Ted Kremenek79a2a262007-11-28 19:21:47 +000032//===----------------------------------------------------------------------===//
33// Utility classes
34//===----------------------------------------------------------------------===//
35
Ted Kremenekbfa82c42007-10-16 23:37:27 +000036namespace {
Ted Kremenekbfa82c42007-10-16 23:37:27 +000037
Ted Kremenek79a2a262007-11-28 19:21:47 +000038template<typename T> class Janitor {
Ted Kremenek4ac81212007-11-05 21:39:35 +000039 T* Obj;
Ted Kremenek79a2a262007-11-28 19:21:47 +000040public:
41 explicit Janitor(T* obj) : Obj(obj) {}
Ted Kremenek4ac81212007-11-05 21:39:35 +000042 ~Janitor() { delete Obj; }
Ted Kremenek79a2a262007-11-28 19:21:47 +000043 operator T*() const { return Obj; }
44 T* operator->() { return Obj; }
Ted Kremenek4ac81212007-11-05 21:39:35 +000045};
46
Ted Kremenek79a2a262007-11-28 19:21:47 +000047class FileSP {
48 FILE* f;
49public:
50 FileSP(const llvm::sys::Path& fname, const char* mode = "wb")
51 : f(fopen(fname.c_str(),mode)) {}
52
53 ~FileSP() { if (f) fclose(f); }
54
55 operator FILE*() const { return f; }
56private:
57 void operator=(const FileSP& RHS) {}
58 FileSP(const FileSP& RHS) {}
59};
60
61//===----------------------------------------------------------------------===//
62// Driver code.
63//===----------------------------------------------------------------------===//
64
Ted Kremenek4ac81212007-11-05 21:39:35 +000065class SerializationTest : public ASTConsumer {
66 ASTContext* Context;
Ted Kremenek018b3952007-11-06 19:50:53 +000067 std::list<Decl*> Decls;
Ted Kremenek4ac81212007-11-05 21:39:35 +000068
Ted Kremenekb899ad22007-11-14 17:46:35 +000069 enum { BasicMetadataBlock,
70 ASTContextBlock,
71 DeclsBlock };
Ted Kremenek018b3952007-11-06 19:50:53 +000072
73public:
74 SerializationTest() : Context(NULL) {};
Ted Kremenek4ac81212007-11-05 21:39:35 +000075 ~SerializationTest();
76
Ted Kremenek018b3952007-11-06 19:50:53 +000077 virtual void Initialize(ASTContext& context, unsigned) {
78 Context = &context;
79 }
80
81 virtual void HandleTopLevelDecl(Decl *D) {
82 Decls.push_back(D);
83 }
84
85private:
Ted Kremenek79a2a262007-11-28 19:21:47 +000086 void Serialize(llvm::sys::Path& Filename, llvm::sys::Path& FNameDeclPrint);
87 void Deserialize(llvm::sys::Path& Filename, llvm::sys::Path& FNameDeclPrint);
Ted Kremenek4ac81212007-11-05 21:39:35 +000088};
89
Ted Kremenekc637e6b2007-10-23 22:18:37 +000090} // end anonymous namespace
Ted Kremenekbfa82c42007-10-16 23:37:27 +000091
Ted Kremenek018b3952007-11-06 19:50:53 +000092ASTConsumer* clang::CreateSerializationTest() {
93 return new SerializationTest();
94}
95
96static void WritePreamble(llvm::BitstreamWriter& Stream) {
97 Stream.Emit((unsigned)'B', 8);
98 Stream.Emit((unsigned)'C', 8);
99 Stream.Emit(0xC, 4);
100 Stream.Emit(0xF, 4);
101 Stream.Emit(0xE, 4);
102 Stream.Emit(0x0, 4);
103}
104
Ted Kremenek07c0fd92007-11-06 23:52:19 +0000105static bool ReadPreamble(llvm::BitstreamReader& Stream) {
Ted Kremenek018b3952007-11-06 19:50:53 +0000106 return Stream.Read(8) != 'B' ||
107 Stream.Read(8) != 'C' ||
108 Stream.Read(4) != 0xC ||
109 Stream.Read(4) != 0xF ||
110 Stream.Read(4) != 0xE ||
111 Stream.Read(4) != 0x0;
112}
113
Ted Kremenek79a2a262007-11-28 19:21:47 +0000114void SerializationTest::Serialize(llvm::sys::Path& Filename,
115 llvm::sys::Path& FNameDeclPrint) {
Ted Kremenekc637e6b2007-10-23 22:18:37 +0000116
Ted Kremenek018b3952007-11-06 19:50:53 +0000117 // Reserve 256K for bitstream buffer.
118 std::vector<unsigned char> Buffer;
119 Buffer.reserve(256*1024);
120
121 // Create bitstream and write preamble.
122 llvm::BitstreamWriter Stream(Buffer);
123 WritePreamble(Stream);
124
125 // Create serializer.
126 llvm::Serializer Sezr(Stream);
127
128 // ===---------------------------------------------------===/
Ted Kremenek7a1f4db2007-11-10 02:07:12 +0000129 // Serialize the top-level decls.
130 // ===---------------------------------------------------===/
131
Ted Kremenekb899ad22007-11-14 17:46:35 +0000132 Sezr.EnterBlock(DeclsBlock);
Ted Kremeneke7201982007-11-13 22:56:10 +0000133
Ted Kremenek79a2a262007-11-28 19:21:47 +0000134 { // Create a printer to "consume" our deserialized ASTS.
135
136 Janitor<ASTConsumer> Printer(CreateASTPrinter());
137 FileSP DeclFP(FNameDeclPrint,"w");
138 assert (DeclFP && "Could not open file for printing out decls.");
139 Janitor<ASTConsumer> FilePrinter(CreateASTPrinter(DeclFP));
Ted Kremeneke7201982007-11-13 22:56:10 +0000140
Ted Kremenek79a2a262007-11-28 19:21:47 +0000141 for (std::list<Decl*>::iterator I=Decls.begin(), E=Decls.end(); I!=E; ++I) {
142 llvm::cerr << "Serializing: Decl.\n";
143
144 Printer->HandleTopLevelDecl(*I);
145 FilePrinter->HandleTopLevelDecl(*I);
146
147 Sezr.EmitOwnedPtr(*I);
148 }
Ted Kremenek7a1f4db2007-11-10 02:07:12 +0000149 }
150
151 Sezr.ExitBlock();
152
153 // ===---------------------------------------------------===/
Ted Kremenek018b3952007-11-06 19:50:53 +0000154 // Serialize the "Translation Unit" metadata.
155 // ===---------------------------------------------------===/
156
Ted Kremenekb899ad22007-11-14 17:46:35 +0000157 // Emit ASTContext.
158 Sezr.EnterBlock(ASTContextBlock);
159 llvm::cerr << "Serializing: ASTContext.\n";
160 Sezr.EmitOwnedPtr(Context);
161 Sezr.ExitBlock();
162
163
164 Sezr.EnterBlock(BasicMetadataBlock);
Ted Kremenek018b3952007-11-06 19:50:53 +0000165
166 // "Fake" emit the SourceManager.
167 llvm::cerr << "Faux-serializing: SourceManager.\n";
168 Sezr.EmitPtr(&Context->SourceMgr);
169
170 // "Fake" emit the Target.
171 llvm::cerr << "Faux-serializing: Target.\n";
172 Sezr.EmitPtr(&Context->Target);
173
174 // "Fake" emit Selectors.
175 llvm::cerr << "Faux-serializing: Selectors.\n";
176 Sezr.EmitPtr(&Context->Selectors);
177
178 // Emit the Identifier Table.
179 llvm::cerr << "Serializing: IdentifierTable.\n";
180 Sezr.EmitOwnedPtr(&Context->Idents);
Ted Kremenekb899ad22007-11-14 17:46:35 +0000181
Ted Kremenek018b3952007-11-06 19:50:53 +0000182 Sezr.ExitBlock();
183
184 // ===---------------------------------------------------===/
Ted Kremenek79a2a262007-11-28 19:21:47 +0000185 // Finalize serialization: write the bits to disk.
186 {
187 FileSP fp(Filename);
188
189 if (fp)
190 fwrite((char*)&Buffer.front(), sizeof(char), Buffer.size(), fp);
191 else {
192 llvm::cerr << "Error: Cannot open " << Filename.c_str() << "\n";
193 return;
194 }
Ted Kremenekbfa82c42007-10-16 23:37:27 +0000195 }
Ted Kremenekc637e6b2007-10-23 22:18:37 +0000196
Ted Kremenek018b3952007-11-06 19:50:53 +0000197 llvm::cerr << "Commited bitstream to disk: " << Filename.c_str() << "\n";
Ted Kremenekbfa82c42007-10-16 23:37:27 +0000198}
199
Ted Kremenekbfa82c42007-10-16 23:37:27 +0000200
Ted Kremenek79a2a262007-11-28 19:21:47 +0000201void SerializationTest::Deserialize(llvm::sys::Path& Filename,
202 llvm::sys::Path& FNameDeclPrint) {
Ted Kremenek018b3952007-11-06 19:50:53 +0000203
204 // Create the memory buffer that contains the contents of the file.
205
206 using llvm::MemoryBuffer;
207
Ted Kremenek79a2a262007-11-28 19:21:47 +0000208 Janitor<MemoryBuffer> MBuffer(MemoryBuffer::getFile(Filename.c_str(),
209 strlen(Filename.c_str())));
Ted Kremenekbfa82c42007-10-16 23:37:27 +0000210
Ted Kremenek4ac81212007-11-05 21:39:35 +0000211 if(!MBuffer) {
212 llvm::cerr << "ERROR: Cannot read file for deserialization.\n";
213 return;
Ted Kremenekbfa82c42007-10-16 23:37:27 +0000214 }
Ted Kremenekbfa82c42007-10-16 23:37:27 +0000215
Ted Kremenek018b3952007-11-06 19:50:53 +0000216 // Check if the file is of the proper length.
Ted Kremenek4ac81212007-11-05 21:39:35 +0000217 if (MBuffer->getBufferSize() & 0x3) {
Ted Kremenek018b3952007-11-06 19:50:53 +0000218 llvm::cerr << "ERROR: AST file length should be a multiple of 4 bytes.\n";
Ted Kremenek4ac81212007-11-05 21:39:35 +0000219 return;
Ted Kremenekc637e6b2007-10-23 22:18:37 +0000220 }
221
Ted Kremenek018b3952007-11-06 19:50:53 +0000222 // Create the bitstream reader.
223 unsigned char *BufPtr = (unsigned char *) MBuffer->getBufferStart();
224 llvm::BitstreamReader Stream(BufPtr,BufPtr+MBuffer->getBufferSize());
Ted Kremenekc637e6b2007-10-23 22:18:37 +0000225
Ted Kremenek018b3952007-11-06 19:50:53 +0000226 // Sniff for the signature in the bitcode file.
Ted Kremenek07c0fd92007-11-06 23:52:19 +0000227 if (ReadPreamble(Stream)) {
Ted Kremenek4ac81212007-11-05 21:39:35 +0000228 llvm::cerr << "ERROR: Invalid AST-bitcode signature.\n";
229 return;
Ted Kremenek7a1f4db2007-11-10 02:07:12 +0000230 }
231
232 // Create the deserializer.
Ted Kremenek018b3952007-11-06 19:50:53 +0000233 llvm::Deserializer Dezr(Stream);
234
235 // ===---------------------------------------------------===/
236 // Deserialize the "Translation Unit" metadata.
237 // ===---------------------------------------------------===/
238
Ted Kremenekb899ad22007-11-14 17:46:35 +0000239 // Skip to the BasicMetaDataBlock. First jump to ASTContextBlock
240 // (which will appear earlier) and record its location.
241
242 bool FoundBlock = Dezr.SkipToBlock(ASTContextBlock);
243 assert (FoundBlock);
244
245 llvm::Deserializer::Location ASTContextBlockLoc =
246 Dezr.getCurrentBlockLocation();
247
248 FoundBlock = Dezr.SkipToBlock(BasicMetadataBlock);
Ted Kremenek7a1f4db2007-11-10 02:07:12 +0000249 assert (FoundBlock);
250
Ted Kremenek018b3952007-11-06 19:50:53 +0000251 // "Fake" read the SourceManager.
252 llvm::cerr << "Faux-Deserializing: SourceManager.\n";
253 Dezr.RegisterPtr(&Context->SourceMgr);
254
255 // "Fake" read the TargetInfo.
256 llvm::cerr << "Faux-Deserializing: Target.\n";
257 Dezr.RegisterPtr(&Context->Target);
258
259 // "Fake" read the Selectors.
260 llvm::cerr << "Faux-Deserializing: Selectors.\n";
261 Dezr.RegisterPtr(&Context->Selectors);
262
263 // Read the identifier table.
264 llvm::cerr << "Deserializing: IdentifierTable\n";
265 Dezr.ReadOwnedPtr<IdentifierTable>();
266
Ted Kremenekb899ad22007-11-14 17:46:35 +0000267 // Now jump back to ASTContextBlock and read the ASTContext.
268 Dezr.JumpTo(ASTContextBlockLoc);
269
Ted Kremenek018b3952007-11-06 19:50:53 +0000270 // Read the ASTContext.
271 llvm::cerr << "Deserializing: ASTContext.\n";
272 Dezr.ReadOwnedPtr<ASTContext>();
Ted Kremenek79a2a262007-11-28 19:21:47 +0000273
Ted Kremenek7a1f4db2007-11-10 02:07:12 +0000274 // "Rewind" the stream. Find the block with the serialized top-level decls.
275 Dezr.Rewind();
Ted Kremenekb899ad22007-11-14 17:46:35 +0000276 FoundBlock = Dezr.SkipToBlock(DeclsBlock);
Ted Kremenek7a1f4db2007-11-10 02:07:12 +0000277 assert (FoundBlock);
278 llvm::Deserializer::Location DeclBlockLoc = Dezr.getCurrentBlockLocation();
279
Ted Kremenek79a2a262007-11-28 19:21:47 +0000280 // Create a printer to "consume" our deserialized ASTS.
281 ASTConsumer* Printer = CreateASTPrinter();
282 Janitor<ASTConsumer> PrinterJanitor(Printer);
283 FileSP DeclFP(FNameDeclPrint,"w");
284 assert (DeclFP && "Could not open file for printing out decls.");
285 Janitor<ASTConsumer> FilePrinter(CreateASTPrinter(DeclFP));
286
Ted Kremenek018b3952007-11-06 19:50:53 +0000287 // The remaining objects in the file are top-level decls.
Ted Kremenek7a1f4db2007-11-10 02:07:12 +0000288 while (!Dezr.FinishedBlock(DeclBlockLoc)) {
Ted Kremenek018b3952007-11-06 19:50:53 +0000289 llvm::cerr << "Deserializing: Decl.\n";
290 Decl* decl = Dezr.ReadOwnedPtr<Decl>();
Ted Kremenek79a2a262007-11-28 19:21:47 +0000291 Printer->HandleTopLevelDecl(decl);
292 FilePrinter->HandleTopLevelDecl(decl);
Ted Kremenek018b3952007-11-06 19:50:53 +0000293 }
294}
295
Ted Kremenek79a2a262007-11-28 19:21:47 +0000296namespace {
297 class TmpDirJanitor {
298 llvm::sys::Path& Dir;
299 public:
300 explicit TmpDirJanitor(llvm::sys::Path& dir) : Dir(dir) {}
301
302 ~TmpDirJanitor() {
303 llvm::cerr << "Removing: " << Dir.c_str() << '\n';
304 Dir.eraseFromDisk(true);
305 }
306 };
307}
Ted Kremenek018b3952007-11-06 19:50:53 +0000308
309SerializationTest::~SerializationTest() {
Ted Kremenek79a2a262007-11-28 19:21:47 +0000310
Ted Kremenek018b3952007-11-06 19:50:53 +0000311 std::string ErrMsg;
Ted Kremenek79a2a262007-11-28 19:21:47 +0000312 llvm::sys::Path Dir = llvm::sys::Path::GetTemporaryDirectory(&ErrMsg);
Ted Kremenek018b3952007-11-06 19:50:53 +0000313
Ted Kremenek79a2a262007-11-28 19:21:47 +0000314 if (Dir.isEmpty()) {
Ted Kremenek018b3952007-11-06 19:50:53 +0000315 llvm::cerr << "Error: " << ErrMsg << "\n";
316 return;
Ted Kremenekc637e6b2007-10-23 22:18:37 +0000317 }
318
Ted Kremenek79a2a262007-11-28 19:21:47 +0000319 TmpDirJanitor RemoveTmpOnExit(Dir);
320
321 llvm::sys::Path FNameDeclBefore = Dir;
322 FNameDeclBefore.appendComponent("test.decl_before.txt");
323
324 if (FNameDeclBefore.makeUnique(true,&ErrMsg)) {
Ted Kremenek018b3952007-11-06 19:50:53 +0000325 llvm::cerr << "Error: " << ErrMsg << "\n";
326 return;
327 }
Ted Kremenek4ac81212007-11-05 21:39:35 +0000328
Ted Kremenek79a2a262007-11-28 19:21:47 +0000329 llvm::sys::Path FNameDeclAfter = Dir;
330 FNameDeclAfter.appendComponent("test.decl_after.txt");
331
332 if (FNameDeclAfter.makeUnique(true,&ErrMsg)) {
333 llvm::cerr << "Error: " << ErrMsg << "\n";
334 return;
335 }
336
337 llvm::sys::Path ASTFilename = Dir;
338 ASTFilename.appendComponent("test.ast");
339
340 if (ASTFilename.makeUnique(true,&ErrMsg)) {
341 llvm::cerr << "Error: " << ErrMsg << "\n";
342 return;
343 }
344
345 // Serialize and then deserialize the ASTs.
346 Serialize(ASTFilename, FNameDeclBefore);
347 Deserialize(ASTFilename, FNameDeclAfter);
348
349 // Read both pretty-printed files and compare them.
350
351 using llvm::MemoryBuffer;
352
353 Janitor<MemoryBuffer>
354 MBufferSer(MemoryBuffer::getFile(FNameDeclBefore.c_str(),
355 strlen(FNameDeclBefore.c_str())));
356
357 if(!MBufferSer) {
358 llvm::cerr << "ERROR: Cannot read pretty-printed file (pre-pickle).\n";
359 return;
360 }
361
362 Janitor<MemoryBuffer>
363 MBufferDSer(MemoryBuffer::getFile(FNameDeclAfter.c_str(),
364 strlen(FNameDeclAfter.c_str())));
365
366 if(!MBufferDSer) {
367 llvm::cerr << "ERROR: Cannot read pretty-printed file (post-pickle).\n";
368 return;
369 }
370
371 const char *p1 = MBufferSer->getBufferStart();
372 const char *e1 = MBufferSer->getBufferEnd();
373 const char *p2 = MBufferDSer->getBufferStart();
374 const char *e2 = MBufferDSer->getBufferEnd();
375
376 if (MBufferSer->getBufferSize() == MBufferDSer->getBufferSize())
377 for ( ; p1 != e1 ; ++p1, ++p2 )
378 if (*p1 != *p2) break;
379
380 if (p1 != e1 || p2 != e2 )
381 llvm::cerr << "ERROR: Pretty-printed files are not the same.\n";
382 else
383 llvm::cerr << "SUCCESS: Pretty-printed files are the same.\n";
Ted Kremenekc637e6b2007-10-23 22:18:37 +0000384}