blob: f8d4b7820e34401fb8e97368917123927781e59e [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"
Ted Kremenek5656b782007-11-29 01:24:25 +000021#include "clang/AST/CFG.h"
Ted Kremenekbfa82c42007-10-16 23:37:27 +000022#include "llvm/System/Path.h"
Ted Kremenekc637e6b2007-10-23 22:18:37 +000023#include "llvm/Support/Streams.h"
24#include "llvm/Support/MemoryBuffer.h"
Ted Kremeneka2bfb912007-10-24 19:06:02 +000025#include "llvm/Bitcode/Serialize.h"
26#include "llvm/Bitcode/Deserialize.h"
Ted Kremenekea75c552007-11-28 21:32:21 +000027#include <fstream>
Ted Kremenekc637e6b2007-10-23 22:18:37 +000028#include <stdio.h>
Ted Kremenek018b3952007-11-06 19:50:53 +000029#include <list>
Ted Kremenekc637e6b2007-10-23 22:18:37 +000030
Ted Kremenekbfa82c42007-10-16 23:37:27 +000031using namespace clang;
Ted Kremenekbfa82c42007-10-16 23:37:27 +000032
Ted Kremenek79a2a262007-11-28 19:21:47 +000033//===----------------------------------------------------------------------===//
34// Utility classes
35//===----------------------------------------------------------------------===//
36
Ted Kremenekbfa82c42007-10-16 23:37:27 +000037namespace {
Ted Kremenekbfa82c42007-10-16 23:37:27 +000038
Ted Kremenek79a2a262007-11-28 19:21:47 +000039template<typename T> class Janitor {
Ted Kremenek4ac81212007-11-05 21:39:35 +000040 T* Obj;
Ted Kremenek79a2a262007-11-28 19:21:47 +000041public:
42 explicit Janitor(T* obj) : Obj(obj) {}
Ted Kremenek4ac81212007-11-05 21:39:35 +000043 ~Janitor() { delete Obj; }
Ted Kremenek79a2a262007-11-28 19:21:47 +000044 operator T*() const { return Obj; }
45 T* operator->() { return Obj; }
Ted Kremenek4ac81212007-11-05 21:39:35 +000046};
Ted Kremenek79a2a262007-11-28 19:21:47 +000047
48//===----------------------------------------------------------------------===//
49// Driver code.
50//===----------------------------------------------------------------------===//
51
Ted Kremenek4ac81212007-11-05 21:39:35 +000052class SerializationTest : public ASTConsumer {
53 ASTContext* Context;
Ted Kremenek018b3952007-11-06 19:50:53 +000054 std::list<Decl*> Decls;
Ted Kremenek4ac81212007-11-05 21:39:35 +000055
Ted Kremenekbdbb2852007-11-30 22:46:56 +000056 enum { BasicMetadataBlock = 1,
57 ASTContextBlock = 2,
58 DeclsBlock = 3 };
Ted Kremenek018b3952007-11-06 19:50:53 +000059
60public:
61 SerializationTest() : Context(NULL) {};
Ted Kremenek4ac81212007-11-05 21:39:35 +000062 ~SerializationTest();
63
Ted Kremenek018b3952007-11-06 19:50:53 +000064 virtual void Initialize(ASTContext& context, unsigned) {
65 Context = &context;
66 }
67
68 virtual void HandleTopLevelDecl(Decl *D) {
69 Decls.push_back(D);
70 }
71
72private:
Ted Kremenek79a2a262007-11-28 19:21:47 +000073 void Serialize(llvm::sys::Path& Filename, llvm::sys::Path& FNameDeclPrint);
74 void Deserialize(llvm::sys::Path& Filename, llvm::sys::Path& FNameDeclPrint);
Ted Kremenek4ac81212007-11-05 21:39:35 +000075};
76
Ted Kremenekc637e6b2007-10-23 22:18:37 +000077} // end anonymous namespace
Ted Kremenekbfa82c42007-10-16 23:37:27 +000078
Ted Kremenek018b3952007-11-06 19:50:53 +000079ASTConsumer* clang::CreateSerializationTest() {
80 return new SerializationTest();
81}
82
83static void WritePreamble(llvm::BitstreamWriter& Stream) {
84 Stream.Emit((unsigned)'B', 8);
85 Stream.Emit((unsigned)'C', 8);
86 Stream.Emit(0xC, 4);
87 Stream.Emit(0xF, 4);
88 Stream.Emit(0xE, 4);
89 Stream.Emit(0x0, 4);
90}
91
Ted Kremenek07c0fd92007-11-06 23:52:19 +000092static bool ReadPreamble(llvm::BitstreamReader& Stream) {
Ted Kremenek018b3952007-11-06 19:50:53 +000093 return Stream.Read(8) != 'B' ||
94 Stream.Read(8) != 'C' ||
95 Stream.Read(4) != 0xC ||
96 Stream.Read(4) != 0xF ||
97 Stream.Read(4) != 0xE ||
98 Stream.Read(4) != 0x0;
99}
100
Ted Kremenek79a2a262007-11-28 19:21:47 +0000101void SerializationTest::Serialize(llvm::sys::Path& Filename,
102 llvm::sys::Path& FNameDeclPrint) {
Ted Kremenekc637e6b2007-10-23 22:18:37 +0000103
Ted Kremenek018b3952007-11-06 19:50:53 +0000104 // Reserve 256K for bitstream buffer.
105 std::vector<unsigned char> Buffer;
106 Buffer.reserve(256*1024);
107
108 // Create bitstream and write preamble.
109 llvm::BitstreamWriter Stream(Buffer);
110 WritePreamble(Stream);
111
112 // Create serializer.
113 llvm::Serializer Sezr(Stream);
114
115 // ===---------------------------------------------------===/
Ted Kremenek7a1f4db2007-11-10 02:07:12 +0000116 // Serialize the top-level decls.
117 // ===---------------------------------------------------===/
118
Ted Kremenekb899ad22007-11-14 17:46:35 +0000119 Sezr.EnterBlock(DeclsBlock);
Ted Kremeneke7201982007-11-13 22:56:10 +0000120
Ted Kremenek79a2a262007-11-28 19:21:47 +0000121 { // Create a printer to "consume" our deserialized ASTS.
122
123 Janitor<ASTConsumer> Printer(CreateASTPrinter());
Ted Kremenekea75c552007-11-28 21:32:21 +0000124 std::ofstream DeclPP(FNameDeclPrint.c_str());
125 assert (DeclPP && "Could not open file for printing out decls.");
126 Janitor<ASTConsumer> FilePrinter(CreateASTPrinter(&DeclPP));
Ted Kremeneke7201982007-11-13 22:56:10 +0000127
Ted Kremenek79a2a262007-11-28 19:21:47 +0000128 for (std::list<Decl*>::iterator I=Decls.begin(), E=Decls.end(); I!=E; ++I) {
129 llvm::cerr << "Serializing: Decl.\n";
130
Ted Kremenek6127b122007-11-29 19:04:54 +0000131 // Only serialize the head of a decl chain. The ASTConsumer interfaces
132 // provides us with each top-level decl, including those nested in
133 // a decl chain, so we may be passed decls that are already serialized.
134 if (!Sezr.isRegistered(*I)) {
135 Printer->HandleTopLevelDecl(*I);
136 FilePrinter->HandleTopLevelDecl(*I);
137
138 if (FunctionDecl* FD = dyn_cast<FunctionDecl>(*I))
139 if (FD->getBody()) {
140 // Construct and print a CFG.
141 Janitor<CFG> cfg(CFG::buildCFG(FD->getBody()));
142 cfg->print(DeclPP);
143 }
144
145 // Serialize the decl.
146 Sezr.EmitOwnedPtr(*I);
147 }
Ted Kremenek79a2a262007-11-28 19:21:47 +0000148 }
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
Ted Kremenekbdbb2852007-11-30 22:46:56 +0000166 // Block for SourceManager and Target. Allows easy skipping around
167 // to the Selectors during deserialization.
168 Sezr.EnterBlock();
169
Ted Kremenek018b3952007-11-06 19:50:53 +0000170 // "Fake" emit the SourceManager.
171 llvm::cerr << "Faux-serializing: SourceManager.\n";
172 Sezr.EmitPtr(&Context->SourceMgr);
173
174 // "Fake" emit the Target.
175 llvm::cerr << "Faux-serializing: Target.\n";
176 Sezr.EmitPtr(&Context->Target);
177
Ted Kremenekbdbb2852007-11-30 22:46:56 +0000178 Sezr.ExitBlock();
179
180 // Emit the Selectors.
181 llvm::cerr << "Serializing: Selectors.\n";
182 Sezr.Emit(Context->Selectors);
Ted Kremenek018b3952007-11-06 19:50:53 +0000183
184 // Emit the Identifier Table.
185 llvm::cerr << "Serializing: IdentifierTable.\n";
Ted Kremenekbdbb2852007-11-30 22:46:56 +0000186 Sezr.Emit(Context->Idents);
Ted Kremenekb899ad22007-11-14 17:46:35 +0000187
Ted Kremenek018b3952007-11-06 19:50:53 +0000188 Sezr.ExitBlock();
189
190 // ===---------------------------------------------------===/
Ted Kremenek79a2a262007-11-28 19:21:47 +0000191 // Finalize serialization: write the bits to disk.
Ted Kremenekea75c552007-11-28 21:32:21 +0000192 if (FILE* fp = fopen(Filename.c_str(),"wb")) {
193 fwrite((char*)&Buffer.front(), sizeof(char), Buffer.size(), fp);
194 fclose(fp);
195 }
196 else {
197 llvm::cerr << "Error: Cannot open " << Filename.c_str() << "\n";
198 return;
Ted Kremenekbfa82c42007-10-16 23:37:27 +0000199 }
Ted Kremenekc637e6b2007-10-23 22:18:37 +0000200
Ted Kremenek018b3952007-11-06 19:50:53 +0000201 llvm::cerr << "Commited bitstream to disk: " << Filename.c_str() << "\n";
Ted Kremenekbfa82c42007-10-16 23:37:27 +0000202}
203
Ted Kremenekbfa82c42007-10-16 23:37:27 +0000204
Ted Kremenek79a2a262007-11-28 19:21:47 +0000205void SerializationTest::Deserialize(llvm::sys::Path& Filename,
206 llvm::sys::Path& FNameDeclPrint) {
Ted Kremenek018b3952007-11-06 19:50:53 +0000207
208 // Create the memory buffer that contains the contents of the file.
209
210 using llvm::MemoryBuffer;
211
Ted Kremenek79a2a262007-11-28 19:21:47 +0000212 Janitor<MemoryBuffer> MBuffer(MemoryBuffer::getFile(Filename.c_str(),
213 strlen(Filename.c_str())));
Ted Kremenekbfa82c42007-10-16 23:37:27 +0000214
Ted Kremenek4ac81212007-11-05 21:39:35 +0000215 if(!MBuffer) {
216 llvm::cerr << "ERROR: Cannot read file for deserialization.\n";
217 return;
Ted Kremenekbfa82c42007-10-16 23:37:27 +0000218 }
Ted Kremenekbfa82c42007-10-16 23:37:27 +0000219
Ted Kremenek018b3952007-11-06 19:50:53 +0000220 // Check if the file is of the proper length.
Ted Kremenek4ac81212007-11-05 21:39:35 +0000221 if (MBuffer->getBufferSize() & 0x3) {
Ted Kremenek018b3952007-11-06 19:50:53 +0000222 llvm::cerr << "ERROR: AST file length should be a multiple of 4 bytes.\n";
Ted Kremenek4ac81212007-11-05 21:39:35 +0000223 return;
Ted Kremenekc637e6b2007-10-23 22:18:37 +0000224 }
225
Ted Kremenek018b3952007-11-06 19:50:53 +0000226 // Create the bitstream reader.
227 unsigned char *BufPtr = (unsigned char *) MBuffer->getBufferStart();
228 llvm::BitstreamReader Stream(BufPtr,BufPtr+MBuffer->getBufferSize());
Ted Kremenekc637e6b2007-10-23 22:18:37 +0000229
Ted Kremenek018b3952007-11-06 19:50:53 +0000230 // Sniff for the signature in the bitcode file.
Ted Kremenek07c0fd92007-11-06 23:52:19 +0000231 if (ReadPreamble(Stream)) {
Ted Kremenek4ac81212007-11-05 21:39:35 +0000232 llvm::cerr << "ERROR: Invalid AST-bitcode signature.\n";
233 return;
Ted Kremenek7a1f4db2007-11-10 02:07:12 +0000234 }
235
236 // Create the deserializer.
Ted Kremenek018b3952007-11-06 19:50:53 +0000237 llvm::Deserializer Dezr(Stream);
238
239 // ===---------------------------------------------------===/
240 // Deserialize the "Translation Unit" metadata.
241 // ===---------------------------------------------------===/
242
Ted Kremenekb899ad22007-11-14 17:46:35 +0000243 // Skip to the BasicMetaDataBlock. First jump to ASTContextBlock
244 // (which will appear earlier) and record its location.
245
246 bool FoundBlock = Dezr.SkipToBlock(ASTContextBlock);
247 assert (FoundBlock);
248
249 llvm::Deserializer::Location ASTContextBlockLoc =
250 Dezr.getCurrentBlockLocation();
251
252 FoundBlock = Dezr.SkipToBlock(BasicMetadataBlock);
Ted Kremenek7a1f4db2007-11-10 02:07:12 +0000253 assert (FoundBlock);
254
Ted Kremenek018b3952007-11-06 19:50:53 +0000255 // "Fake" read the SourceManager.
256 llvm::cerr << "Faux-Deserializing: SourceManager.\n";
257 Dezr.RegisterPtr(&Context->SourceMgr);
258
259 // "Fake" read the TargetInfo.
260 llvm::cerr << "Faux-Deserializing: Target.\n";
261 Dezr.RegisterPtr(&Context->Target);
262
Ted Kremenekbdbb2852007-11-30 22:46:56 +0000263 // For Selectors, we must read the identifier table first because the
264 // SelectorTable depends on the identifiers being already deserialized.
265 llvm::Deserializer::Location SelectorBlockLoc = Dezr.getCurrentBlockLocation();
266 Dezr.SkipBlock();
Ted Kremenek018b3952007-11-06 19:50:53 +0000267
268 // Read the identifier table.
269 llvm::cerr << "Deserializing: IdentifierTable\n";
Ted Kremenekbdbb2852007-11-30 22:46:56 +0000270 IdentifierTable::CreateAndRegister(Dezr);
271
272 // Now jump back and read the selectors.
273 llvm::cerr << "Deserializing: Selectors\n";
274 Dezr.JumpTo(SelectorBlockLoc);
275 SelectorTable::CreateAndRegister(Dezr);
Ted Kremenek018b3952007-11-06 19:50:53 +0000276
Ted Kremenekb899ad22007-11-14 17:46:35 +0000277 // Now jump back to ASTContextBlock and read the ASTContext.
Ted Kremenek018b3952007-11-06 19:50:53 +0000278 llvm::cerr << "Deserializing: ASTContext.\n";
Ted Kremenekbdbb2852007-11-30 22:46:56 +0000279 Dezr.JumpTo(ASTContextBlockLoc);
Ted Kremenek018b3952007-11-06 19:50:53 +0000280 Dezr.ReadOwnedPtr<ASTContext>();
Ted Kremenek79a2a262007-11-28 19:21:47 +0000281
Ted Kremenek7a1f4db2007-11-10 02:07:12 +0000282 // "Rewind" the stream. Find the block with the serialized top-level decls.
283 Dezr.Rewind();
Ted Kremenekb899ad22007-11-14 17:46:35 +0000284 FoundBlock = Dezr.SkipToBlock(DeclsBlock);
Ted Kremenek7a1f4db2007-11-10 02:07:12 +0000285 assert (FoundBlock);
286 llvm::Deserializer::Location DeclBlockLoc = Dezr.getCurrentBlockLocation();
287
Ted Kremenek79a2a262007-11-28 19:21:47 +0000288 // Create a printer to "consume" our deserialized ASTS.
289 ASTConsumer* Printer = CreateASTPrinter();
290 Janitor<ASTConsumer> PrinterJanitor(Printer);
Ted Kremenekea75c552007-11-28 21:32:21 +0000291 std::ofstream DeclPP(FNameDeclPrint.c_str());
292 assert (DeclPP && "Could not open file for printing out decls.");
293 Janitor<ASTConsumer> FilePrinter(CreateASTPrinter(&DeclPP));
Ted Kremenek79a2a262007-11-28 19:21:47 +0000294
Ted Kremenek018b3952007-11-06 19:50:53 +0000295 // The remaining objects in the file are top-level decls.
Ted Kremenek7a1f4db2007-11-10 02:07:12 +0000296 while (!Dezr.FinishedBlock(DeclBlockLoc)) {
Ted Kremenek018b3952007-11-06 19:50:53 +0000297 llvm::cerr << "Deserializing: Decl.\n";
298 Decl* decl = Dezr.ReadOwnedPtr<Decl>();
Ted Kremenek79a2a262007-11-28 19:21:47 +0000299 Printer->HandleTopLevelDecl(decl);
300 FilePrinter->HandleTopLevelDecl(decl);
Ted Kremenek5656b782007-11-29 01:24:25 +0000301
302 if (FunctionDecl* FD = dyn_cast<FunctionDecl>(decl))
303 if (FD->getBody()) {
304 // Construct and print a CFG.
305 Janitor<CFG> cfg(CFG::buildCFG(FD->getBody()));
306 cfg->print(DeclPP);
307 }
Ted Kremenek018b3952007-11-06 19:50:53 +0000308 }
309}
310
Ted Kremenek79a2a262007-11-28 19:21:47 +0000311namespace {
312 class TmpDirJanitor {
313 llvm::sys::Path& Dir;
314 public:
315 explicit TmpDirJanitor(llvm::sys::Path& dir) : Dir(dir) {}
316
317 ~TmpDirJanitor() {
318 llvm::cerr << "Removing: " << Dir.c_str() << '\n';
319 Dir.eraseFromDisk(true);
320 }
321 };
322}
Ted Kremenek018b3952007-11-06 19:50:53 +0000323
324SerializationTest::~SerializationTest() {
Ted Kremenek79a2a262007-11-28 19:21:47 +0000325
Ted Kremenek018b3952007-11-06 19:50:53 +0000326 std::string ErrMsg;
Ted Kremenek79a2a262007-11-28 19:21:47 +0000327 llvm::sys::Path Dir = llvm::sys::Path::GetTemporaryDirectory(&ErrMsg);
Ted Kremenek018b3952007-11-06 19:50:53 +0000328
Ted Kremenek79a2a262007-11-28 19:21:47 +0000329 if (Dir.isEmpty()) {
Ted Kremenek018b3952007-11-06 19:50:53 +0000330 llvm::cerr << "Error: " << ErrMsg << "\n";
331 return;
Ted Kremenekc637e6b2007-10-23 22:18:37 +0000332 }
333
Ted Kremenek79a2a262007-11-28 19:21:47 +0000334 TmpDirJanitor RemoveTmpOnExit(Dir);
335
336 llvm::sys::Path FNameDeclBefore = Dir;
337 FNameDeclBefore.appendComponent("test.decl_before.txt");
338
339 if (FNameDeclBefore.makeUnique(true,&ErrMsg)) {
Ted Kremenek018b3952007-11-06 19:50:53 +0000340 llvm::cerr << "Error: " << ErrMsg << "\n";
341 return;
342 }
Ted Kremenek4ac81212007-11-05 21:39:35 +0000343
Ted Kremenek79a2a262007-11-28 19:21:47 +0000344 llvm::sys::Path FNameDeclAfter = Dir;
345 FNameDeclAfter.appendComponent("test.decl_after.txt");
346
347 if (FNameDeclAfter.makeUnique(true,&ErrMsg)) {
348 llvm::cerr << "Error: " << ErrMsg << "\n";
349 return;
350 }
351
352 llvm::sys::Path ASTFilename = Dir;
353 ASTFilename.appendComponent("test.ast");
354
355 if (ASTFilename.makeUnique(true,&ErrMsg)) {
356 llvm::cerr << "Error: " << ErrMsg << "\n";
357 return;
358 }
359
360 // Serialize and then deserialize the ASTs.
361 Serialize(ASTFilename, FNameDeclBefore);
362 Deserialize(ASTFilename, FNameDeclAfter);
363
364 // Read both pretty-printed files and compare them.
365
366 using llvm::MemoryBuffer;
367
368 Janitor<MemoryBuffer>
369 MBufferSer(MemoryBuffer::getFile(FNameDeclBefore.c_str(),
370 strlen(FNameDeclBefore.c_str())));
371
372 if(!MBufferSer) {
373 llvm::cerr << "ERROR: Cannot read pretty-printed file (pre-pickle).\n";
374 return;
375 }
376
377 Janitor<MemoryBuffer>
378 MBufferDSer(MemoryBuffer::getFile(FNameDeclAfter.c_str(),
379 strlen(FNameDeclAfter.c_str())));
380
381 if(!MBufferDSer) {
382 llvm::cerr << "ERROR: Cannot read pretty-printed file (post-pickle).\n";
383 return;
384 }
385
386 const char *p1 = MBufferSer->getBufferStart();
387 const char *e1 = MBufferSer->getBufferEnd();
388 const char *p2 = MBufferDSer->getBufferStart();
389 const char *e2 = MBufferDSer->getBufferEnd();
390
391 if (MBufferSer->getBufferSize() == MBufferDSer->getBufferSize())
392 for ( ; p1 != e1 ; ++p1, ++p2 )
393 if (*p1 != *p2) break;
394
395 if (p1 != e1 || p2 != e2 )
396 llvm::cerr << "ERROR: Pretty-printed files are not the same.\n";
397 else
398 llvm::cerr << "SUCCESS: Pretty-printed files are the same.\n";
Ted Kremenekc637e6b2007-10-23 22:18:37 +0000399}