blob: 9f756136bd69c33424599ed43b05c029d5885543 [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 Kremenekea75c552007-11-28 21:32:21 +000026#include <fstream>
Ted Kremenekc637e6b2007-10-23 22:18:37 +000027#include <stdio.h>
Ted Kremenek018b3952007-11-06 19:50:53 +000028#include <list>
Ted Kremenekc637e6b2007-10-23 22:18:37 +000029
Ted Kremenekbfa82c42007-10-16 23:37:27 +000030using namespace clang;
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};
Ted Kremenek79a2a262007-11-28 19:21:47 +000046
47//===----------------------------------------------------------------------===//
48// Driver code.
49//===----------------------------------------------------------------------===//
50
Ted Kremenek4ac81212007-11-05 21:39:35 +000051class SerializationTest : public ASTConsumer {
52 ASTContext* Context;
Ted Kremenek018b3952007-11-06 19:50:53 +000053 std::list<Decl*> Decls;
Ted Kremenek4ac81212007-11-05 21:39:35 +000054
Ted Kremenekb899ad22007-11-14 17:46:35 +000055 enum { BasicMetadataBlock,
56 ASTContextBlock,
57 DeclsBlock };
Ted Kremenek018b3952007-11-06 19:50:53 +000058
59public:
60 SerializationTest() : Context(NULL) {};
Ted Kremenek4ac81212007-11-05 21:39:35 +000061 ~SerializationTest();
62
Ted Kremenek018b3952007-11-06 19:50:53 +000063 virtual void Initialize(ASTContext& context, unsigned) {
64 Context = &context;
65 }
66
67 virtual void HandleTopLevelDecl(Decl *D) {
68 Decls.push_back(D);
69 }
70
71private:
Ted Kremenek79a2a262007-11-28 19:21:47 +000072 void Serialize(llvm::sys::Path& Filename, llvm::sys::Path& FNameDeclPrint);
73 void Deserialize(llvm::sys::Path& Filename, llvm::sys::Path& FNameDeclPrint);
Ted Kremenek4ac81212007-11-05 21:39:35 +000074};
75
Ted Kremenekc637e6b2007-10-23 22:18:37 +000076} // end anonymous namespace
Ted Kremenekbfa82c42007-10-16 23:37:27 +000077
Ted Kremenek018b3952007-11-06 19:50:53 +000078ASTConsumer* clang::CreateSerializationTest() {
79 return new SerializationTest();
80}
81
82static void WritePreamble(llvm::BitstreamWriter& Stream) {
83 Stream.Emit((unsigned)'B', 8);
84 Stream.Emit((unsigned)'C', 8);
85 Stream.Emit(0xC, 4);
86 Stream.Emit(0xF, 4);
87 Stream.Emit(0xE, 4);
88 Stream.Emit(0x0, 4);
89}
90
Ted Kremenek07c0fd92007-11-06 23:52:19 +000091static bool ReadPreamble(llvm::BitstreamReader& Stream) {
Ted Kremenek018b3952007-11-06 19:50:53 +000092 return Stream.Read(8) != 'B' ||
93 Stream.Read(8) != 'C' ||
94 Stream.Read(4) != 0xC ||
95 Stream.Read(4) != 0xF ||
96 Stream.Read(4) != 0xE ||
97 Stream.Read(4) != 0x0;
98}
99
Ted Kremenek79a2a262007-11-28 19:21:47 +0000100void SerializationTest::Serialize(llvm::sys::Path& Filename,
101 llvm::sys::Path& FNameDeclPrint) {
Ted Kremenekc637e6b2007-10-23 22:18:37 +0000102
Ted Kremenek018b3952007-11-06 19:50:53 +0000103 // Reserve 256K for bitstream buffer.
104 std::vector<unsigned char> Buffer;
105 Buffer.reserve(256*1024);
106
107 // Create bitstream and write preamble.
108 llvm::BitstreamWriter Stream(Buffer);
109 WritePreamble(Stream);
110
111 // Create serializer.
112 llvm::Serializer Sezr(Stream);
113
114 // ===---------------------------------------------------===/
Ted Kremenek7a1f4db2007-11-10 02:07:12 +0000115 // Serialize the top-level decls.
116 // ===---------------------------------------------------===/
117
Ted Kremenekb899ad22007-11-14 17:46:35 +0000118 Sezr.EnterBlock(DeclsBlock);
Ted Kremeneke7201982007-11-13 22:56:10 +0000119
Ted Kremenek79a2a262007-11-28 19:21:47 +0000120 { // Create a printer to "consume" our deserialized ASTS.
121
122 Janitor<ASTConsumer> Printer(CreateASTPrinter());
Ted Kremenekea75c552007-11-28 21:32:21 +0000123 std::ofstream DeclPP(FNameDeclPrint.c_str());
124 assert (DeclPP && "Could not open file for printing out decls.");
125 Janitor<ASTConsumer> FilePrinter(CreateASTPrinter(&DeclPP));
Ted Kremeneke7201982007-11-13 22:56:10 +0000126
Ted Kremenek79a2a262007-11-28 19:21:47 +0000127 for (std::list<Decl*>::iterator I=Decls.begin(), E=Decls.end(); I!=E; ++I) {
128 llvm::cerr << "Serializing: Decl.\n";
129
130 Printer->HandleTopLevelDecl(*I);
131 FilePrinter->HandleTopLevelDecl(*I);
132
133 Sezr.EmitOwnedPtr(*I);
134 }
Ted Kremenek7a1f4db2007-11-10 02:07:12 +0000135 }
136
137 Sezr.ExitBlock();
138
139 // ===---------------------------------------------------===/
Ted Kremenek018b3952007-11-06 19:50:53 +0000140 // Serialize the "Translation Unit" metadata.
141 // ===---------------------------------------------------===/
142
Ted Kremenekb899ad22007-11-14 17:46:35 +0000143 // Emit ASTContext.
144 Sezr.EnterBlock(ASTContextBlock);
145 llvm::cerr << "Serializing: ASTContext.\n";
146 Sezr.EmitOwnedPtr(Context);
147 Sezr.ExitBlock();
148
149
150 Sezr.EnterBlock(BasicMetadataBlock);
Ted Kremenek018b3952007-11-06 19:50:53 +0000151
152 // "Fake" emit the SourceManager.
153 llvm::cerr << "Faux-serializing: SourceManager.\n";
154 Sezr.EmitPtr(&Context->SourceMgr);
155
156 // "Fake" emit the Target.
157 llvm::cerr << "Faux-serializing: Target.\n";
158 Sezr.EmitPtr(&Context->Target);
159
160 // "Fake" emit Selectors.
161 llvm::cerr << "Faux-serializing: Selectors.\n";
162 Sezr.EmitPtr(&Context->Selectors);
163
164 // Emit the Identifier Table.
165 llvm::cerr << "Serializing: IdentifierTable.\n";
166 Sezr.EmitOwnedPtr(&Context->Idents);
Ted Kremenekb899ad22007-11-14 17:46:35 +0000167
Ted Kremenek018b3952007-11-06 19:50:53 +0000168 Sezr.ExitBlock();
169
170 // ===---------------------------------------------------===/
Ted Kremenek79a2a262007-11-28 19:21:47 +0000171 // Finalize serialization: write the bits to disk.
Ted Kremenekea75c552007-11-28 21:32:21 +0000172 if (FILE* fp = fopen(Filename.c_str(),"wb")) {
173 fwrite((char*)&Buffer.front(), sizeof(char), Buffer.size(), fp);
174 fclose(fp);
175 }
176 else {
177 llvm::cerr << "Error: Cannot open " << Filename.c_str() << "\n";
178 return;
Ted Kremenekbfa82c42007-10-16 23:37:27 +0000179 }
Ted Kremenekc637e6b2007-10-23 22:18:37 +0000180
Ted Kremenek018b3952007-11-06 19:50:53 +0000181 llvm::cerr << "Commited bitstream to disk: " << Filename.c_str() << "\n";
Ted Kremenekbfa82c42007-10-16 23:37:27 +0000182}
183
Ted Kremenekbfa82c42007-10-16 23:37:27 +0000184
Ted Kremenek79a2a262007-11-28 19:21:47 +0000185void SerializationTest::Deserialize(llvm::sys::Path& Filename,
186 llvm::sys::Path& FNameDeclPrint) {
Ted Kremenek018b3952007-11-06 19:50:53 +0000187
188 // Create the memory buffer that contains the contents of the file.
189
190 using llvm::MemoryBuffer;
191
Ted Kremenek79a2a262007-11-28 19:21:47 +0000192 Janitor<MemoryBuffer> MBuffer(MemoryBuffer::getFile(Filename.c_str(),
193 strlen(Filename.c_str())));
Ted Kremenekbfa82c42007-10-16 23:37:27 +0000194
Ted Kremenek4ac81212007-11-05 21:39:35 +0000195 if(!MBuffer) {
196 llvm::cerr << "ERROR: Cannot read file for deserialization.\n";
197 return;
Ted Kremenekbfa82c42007-10-16 23:37:27 +0000198 }
Ted Kremenekbfa82c42007-10-16 23:37:27 +0000199
Ted Kremenek018b3952007-11-06 19:50:53 +0000200 // Check if the file is of the proper length.
Ted Kremenek4ac81212007-11-05 21:39:35 +0000201 if (MBuffer->getBufferSize() & 0x3) {
Ted Kremenek018b3952007-11-06 19:50:53 +0000202 llvm::cerr << "ERROR: AST file length should be a multiple of 4 bytes.\n";
Ted Kremenek4ac81212007-11-05 21:39:35 +0000203 return;
Ted Kremenekc637e6b2007-10-23 22:18:37 +0000204 }
205
Ted Kremenek018b3952007-11-06 19:50:53 +0000206 // Create the bitstream reader.
207 unsigned char *BufPtr = (unsigned char *) MBuffer->getBufferStart();
208 llvm::BitstreamReader Stream(BufPtr,BufPtr+MBuffer->getBufferSize());
Ted Kremenekc637e6b2007-10-23 22:18:37 +0000209
Ted Kremenek018b3952007-11-06 19:50:53 +0000210 // Sniff for the signature in the bitcode file.
Ted Kremenek07c0fd92007-11-06 23:52:19 +0000211 if (ReadPreamble(Stream)) {
Ted Kremenek4ac81212007-11-05 21:39:35 +0000212 llvm::cerr << "ERROR: Invalid AST-bitcode signature.\n";
213 return;
Ted Kremenek7a1f4db2007-11-10 02:07:12 +0000214 }
215
216 // Create the deserializer.
Ted Kremenek018b3952007-11-06 19:50:53 +0000217 llvm::Deserializer Dezr(Stream);
218
219 // ===---------------------------------------------------===/
220 // Deserialize the "Translation Unit" metadata.
221 // ===---------------------------------------------------===/
222
Ted Kremenekb899ad22007-11-14 17:46:35 +0000223 // Skip to the BasicMetaDataBlock. First jump to ASTContextBlock
224 // (which will appear earlier) and record its location.
225
226 bool FoundBlock = Dezr.SkipToBlock(ASTContextBlock);
227 assert (FoundBlock);
228
229 llvm::Deserializer::Location ASTContextBlockLoc =
230 Dezr.getCurrentBlockLocation();
231
232 FoundBlock = Dezr.SkipToBlock(BasicMetadataBlock);
Ted Kremenek7a1f4db2007-11-10 02:07:12 +0000233 assert (FoundBlock);
234
Ted Kremenek018b3952007-11-06 19:50:53 +0000235 // "Fake" read the SourceManager.
236 llvm::cerr << "Faux-Deserializing: SourceManager.\n";
237 Dezr.RegisterPtr(&Context->SourceMgr);
238
239 // "Fake" read the TargetInfo.
240 llvm::cerr << "Faux-Deserializing: Target.\n";
241 Dezr.RegisterPtr(&Context->Target);
242
243 // "Fake" read the Selectors.
244 llvm::cerr << "Faux-Deserializing: Selectors.\n";
245 Dezr.RegisterPtr(&Context->Selectors);
246
247 // Read the identifier table.
248 llvm::cerr << "Deserializing: IdentifierTable\n";
249 Dezr.ReadOwnedPtr<IdentifierTable>();
250
Ted Kremenekb899ad22007-11-14 17:46:35 +0000251 // Now jump back to ASTContextBlock and read the ASTContext.
252 Dezr.JumpTo(ASTContextBlockLoc);
253
Ted Kremenek018b3952007-11-06 19:50:53 +0000254 // Read the ASTContext.
255 llvm::cerr << "Deserializing: ASTContext.\n";
256 Dezr.ReadOwnedPtr<ASTContext>();
Ted Kremenek79a2a262007-11-28 19:21:47 +0000257
Ted Kremenek7a1f4db2007-11-10 02:07:12 +0000258 // "Rewind" the stream. Find the block with the serialized top-level decls.
259 Dezr.Rewind();
Ted Kremenekb899ad22007-11-14 17:46:35 +0000260 FoundBlock = Dezr.SkipToBlock(DeclsBlock);
Ted Kremenek7a1f4db2007-11-10 02:07:12 +0000261 assert (FoundBlock);
262 llvm::Deserializer::Location DeclBlockLoc = Dezr.getCurrentBlockLocation();
263
Ted Kremenek79a2a262007-11-28 19:21:47 +0000264 // Create a printer to "consume" our deserialized ASTS.
265 ASTConsumer* Printer = CreateASTPrinter();
266 Janitor<ASTConsumer> PrinterJanitor(Printer);
Ted Kremenekea75c552007-11-28 21:32:21 +0000267 std::ofstream DeclPP(FNameDeclPrint.c_str());
268 assert (DeclPP && "Could not open file for printing out decls.");
269 Janitor<ASTConsumer> FilePrinter(CreateASTPrinter(&DeclPP));
Ted Kremenek79a2a262007-11-28 19:21:47 +0000270
Ted Kremenek018b3952007-11-06 19:50:53 +0000271 // The remaining objects in the file are top-level decls.
Ted Kremenek7a1f4db2007-11-10 02:07:12 +0000272 while (!Dezr.FinishedBlock(DeclBlockLoc)) {
Ted Kremenek018b3952007-11-06 19:50:53 +0000273 llvm::cerr << "Deserializing: Decl.\n";
274 Decl* decl = Dezr.ReadOwnedPtr<Decl>();
Ted Kremenek79a2a262007-11-28 19:21:47 +0000275 Printer->HandleTopLevelDecl(decl);
276 FilePrinter->HandleTopLevelDecl(decl);
Ted Kremenek018b3952007-11-06 19:50:53 +0000277 }
278}
279
Ted Kremenek79a2a262007-11-28 19:21:47 +0000280namespace {
281 class TmpDirJanitor {
282 llvm::sys::Path& Dir;
283 public:
284 explicit TmpDirJanitor(llvm::sys::Path& dir) : Dir(dir) {}
285
286 ~TmpDirJanitor() {
287 llvm::cerr << "Removing: " << Dir.c_str() << '\n';
288 Dir.eraseFromDisk(true);
289 }
290 };
291}
Ted Kremenek018b3952007-11-06 19:50:53 +0000292
293SerializationTest::~SerializationTest() {
Ted Kremenek79a2a262007-11-28 19:21:47 +0000294
Ted Kremenek018b3952007-11-06 19:50:53 +0000295 std::string ErrMsg;
Ted Kremenek79a2a262007-11-28 19:21:47 +0000296 llvm::sys::Path Dir = llvm::sys::Path::GetTemporaryDirectory(&ErrMsg);
Ted Kremenek018b3952007-11-06 19:50:53 +0000297
Ted Kremenek79a2a262007-11-28 19:21:47 +0000298 if (Dir.isEmpty()) {
Ted Kremenek018b3952007-11-06 19:50:53 +0000299 llvm::cerr << "Error: " << ErrMsg << "\n";
300 return;
Ted Kremenekc637e6b2007-10-23 22:18:37 +0000301 }
302
Ted Kremenek79a2a262007-11-28 19:21:47 +0000303 TmpDirJanitor RemoveTmpOnExit(Dir);
304
305 llvm::sys::Path FNameDeclBefore = Dir;
306 FNameDeclBefore.appendComponent("test.decl_before.txt");
307
308 if (FNameDeclBefore.makeUnique(true,&ErrMsg)) {
Ted Kremenek018b3952007-11-06 19:50:53 +0000309 llvm::cerr << "Error: " << ErrMsg << "\n";
310 return;
311 }
Ted Kremenek4ac81212007-11-05 21:39:35 +0000312
Ted Kremenek79a2a262007-11-28 19:21:47 +0000313 llvm::sys::Path FNameDeclAfter = Dir;
314 FNameDeclAfter.appendComponent("test.decl_after.txt");
315
316 if (FNameDeclAfter.makeUnique(true,&ErrMsg)) {
317 llvm::cerr << "Error: " << ErrMsg << "\n";
318 return;
319 }
320
321 llvm::sys::Path ASTFilename = Dir;
322 ASTFilename.appendComponent("test.ast");
323
324 if (ASTFilename.makeUnique(true,&ErrMsg)) {
325 llvm::cerr << "Error: " << ErrMsg << "\n";
326 return;
327 }
328
329 // Serialize and then deserialize the ASTs.
330 Serialize(ASTFilename, FNameDeclBefore);
331 Deserialize(ASTFilename, FNameDeclAfter);
332
333 // Read both pretty-printed files and compare them.
334
335 using llvm::MemoryBuffer;
336
337 Janitor<MemoryBuffer>
338 MBufferSer(MemoryBuffer::getFile(FNameDeclBefore.c_str(),
339 strlen(FNameDeclBefore.c_str())));
340
341 if(!MBufferSer) {
342 llvm::cerr << "ERROR: Cannot read pretty-printed file (pre-pickle).\n";
343 return;
344 }
345
346 Janitor<MemoryBuffer>
347 MBufferDSer(MemoryBuffer::getFile(FNameDeclAfter.c_str(),
348 strlen(FNameDeclAfter.c_str())));
349
350 if(!MBufferDSer) {
351 llvm::cerr << "ERROR: Cannot read pretty-printed file (post-pickle).\n";
352 return;
353 }
354
355 const char *p1 = MBufferSer->getBufferStart();
356 const char *e1 = MBufferSer->getBufferEnd();
357 const char *p2 = MBufferDSer->getBufferStart();
358 const char *e2 = MBufferDSer->getBufferEnd();
359
360 if (MBufferSer->getBufferSize() == MBufferDSer->getBufferSize())
361 for ( ; p1 != e1 ; ++p1, ++p2 )
362 if (*p1 != *p2) break;
363
364 if (p1 != e1 || p2 != e2 )
365 llvm::cerr << "ERROR: Pretty-printed files are not the same.\n";
366 else
367 llvm::cerr << "SUCCESS: Pretty-printed files are the same.\n";
Ted Kremenekc637e6b2007-10-23 22:18:37 +0000368}