blob: 80049d4f2bb07c2077716a9062514ec2d686a6fd [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"
Ted Kremenekc4ca2882007-12-03 22:48:14 +000018#include "clang/Basic/TargetInfo.h"
Ted Kremenekbfa82c42007-10-16 23:37:27 +000019#include "clang/AST/AST.h"
20#include "clang/AST/ASTConsumer.h"
21#include "clang/AST/ASTContext.h"
Ted Kremenek5656b782007-11-29 01:24:25 +000022#include "clang/AST/CFG.h"
Ted Kremenekc4ca2882007-12-03 22:48:14 +000023#include "clang.h"
Ted Kremenekbfa82c42007-10-16 23:37:27 +000024#include "llvm/System/Path.h"
Ted Kremenekc637e6b2007-10-23 22:18:37 +000025#include "llvm/Support/Streams.h"
26#include "llvm/Support/MemoryBuffer.h"
Ted Kremeneka2bfb912007-10-24 19:06:02 +000027#include "llvm/Bitcode/Serialize.h"
28#include "llvm/Bitcode/Deserialize.h"
Ted Kremenekea75c552007-11-28 21:32:21 +000029#include <fstream>
Ted Kremenekc637e6b2007-10-23 22:18:37 +000030#include <stdio.h>
Ted Kremenek018b3952007-11-06 19:50:53 +000031#include <list>
Ted Kremenekc637e6b2007-10-23 22:18:37 +000032
Ted Kremenekbfa82c42007-10-16 23:37:27 +000033using namespace clang;
Ted Kremenekbfa82c42007-10-16 23:37:27 +000034
Ted Kremenek79a2a262007-11-28 19:21:47 +000035//===----------------------------------------------------------------------===//
36// Utility classes
37//===----------------------------------------------------------------------===//
38
Ted Kremenekbfa82c42007-10-16 23:37:27 +000039namespace {
Ted Kremenekbfa82c42007-10-16 23:37:27 +000040
Ted Kremenek79a2a262007-11-28 19:21:47 +000041template<typename T> class Janitor {
Ted Kremenek4ac81212007-11-05 21:39:35 +000042 T* Obj;
Ted Kremenek79a2a262007-11-28 19:21:47 +000043public:
44 explicit Janitor(T* obj) : Obj(obj) {}
Ted Kremenek4ac81212007-11-05 21:39:35 +000045 ~Janitor() { delete Obj; }
Ted Kremenek79a2a262007-11-28 19:21:47 +000046 operator T*() const { return Obj; }
47 T* operator->() { return Obj; }
Ted Kremenek4ac81212007-11-05 21:39:35 +000048};
Ted Kremenek79a2a262007-11-28 19:21:47 +000049
50//===----------------------------------------------------------------------===//
51// Driver code.
52//===----------------------------------------------------------------------===//
53
Ted Kremenek4ac81212007-11-05 21:39:35 +000054class SerializationTest : public ASTConsumer {
55 ASTContext* Context;
Ted Kremenekc4ca2882007-12-03 22:48:14 +000056 Diagnostic &Diags;
Ted Kremenek018b3952007-11-06 19:50:53 +000057 std::list<Decl*> Decls;
Ted Kremenek4ac81212007-11-05 21:39:35 +000058
Ted Kremenekbdbb2852007-11-30 22:46:56 +000059 enum { BasicMetadataBlock = 1,
60 ASTContextBlock = 2,
61 DeclsBlock = 3 };
Ted Kremenek018b3952007-11-06 19:50:53 +000062
63public:
Ted Kremenekc4ca2882007-12-03 22:48:14 +000064 SerializationTest(Diagnostic &d) : Context(NULL), Diags(d) {};
Ted Kremenek4ac81212007-11-05 21:39:35 +000065 ~SerializationTest();
66
Ted Kremenek018b3952007-11-06 19:50:53 +000067 virtual void Initialize(ASTContext& context, unsigned) {
68 Context = &context;
69 }
70
71 virtual void HandleTopLevelDecl(Decl *D) {
72 Decls.push_back(D);
73 }
74
75private:
Ted Kremenek79a2a262007-11-28 19:21:47 +000076 void Serialize(llvm::sys::Path& Filename, llvm::sys::Path& FNameDeclPrint);
77 void Deserialize(llvm::sys::Path& Filename, llvm::sys::Path& FNameDeclPrint);
Ted Kremenek4ac81212007-11-05 21:39:35 +000078};
79
Ted Kremenekc637e6b2007-10-23 22:18:37 +000080} // end anonymous namespace
Ted Kremenekbfa82c42007-10-16 23:37:27 +000081
Ted Kremenekc4ca2882007-12-03 22:48:14 +000082ASTConsumer* clang::CreateSerializationTest(Diagnostic &Diags) {
83 return new SerializationTest(Diags);
Ted Kremenek018b3952007-11-06 19:50:53 +000084}
85
86static void WritePreamble(llvm::BitstreamWriter& Stream) {
87 Stream.Emit((unsigned)'B', 8);
88 Stream.Emit((unsigned)'C', 8);
89 Stream.Emit(0xC, 4);
90 Stream.Emit(0xF, 4);
91 Stream.Emit(0xE, 4);
92 Stream.Emit(0x0, 4);
93}
94
Ted Kremenek07c0fd92007-11-06 23:52:19 +000095static bool ReadPreamble(llvm::BitstreamReader& Stream) {
Ted Kremenek018b3952007-11-06 19:50:53 +000096 return Stream.Read(8) != 'B' ||
97 Stream.Read(8) != 'C' ||
98 Stream.Read(4) != 0xC ||
99 Stream.Read(4) != 0xF ||
100 Stream.Read(4) != 0xE ||
101 Stream.Read(4) != 0x0;
102}
103
Ted Kremenek79a2a262007-11-28 19:21:47 +0000104void SerializationTest::Serialize(llvm::sys::Path& Filename,
105 llvm::sys::Path& FNameDeclPrint) {
Ted Kremenekc637e6b2007-10-23 22:18:37 +0000106
Ted Kremenek018b3952007-11-06 19:50:53 +0000107 // Reserve 256K for bitstream buffer.
108 std::vector<unsigned char> Buffer;
109 Buffer.reserve(256*1024);
110
111 // Create bitstream and write preamble.
112 llvm::BitstreamWriter Stream(Buffer);
113 WritePreamble(Stream);
114
115 // Create serializer.
116 llvm::Serializer Sezr(Stream);
117
118 // ===---------------------------------------------------===/
Ted Kremenek7a1f4db2007-11-10 02:07:12 +0000119 // Serialize the top-level decls.
120 // ===---------------------------------------------------===/
121
Ted Kremenekb899ad22007-11-14 17:46:35 +0000122 Sezr.EnterBlock(DeclsBlock);
Ted Kremeneke7201982007-11-13 22:56:10 +0000123
Ted Kremenek79a2a262007-11-28 19:21:47 +0000124 { // Create a printer to "consume" our deserialized ASTS.
125
126 Janitor<ASTConsumer> Printer(CreateASTPrinter());
Ted Kremenekea75c552007-11-28 21:32:21 +0000127 std::ofstream DeclPP(FNameDeclPrint.c_str());
128 assert (DeclPP && "Could not open file for printing out decls.");
129 Janitor<ASTConsumer> FilePrinter(CreateASTPrinter(&DeclPP));
Ted Kremeneke7201982007-11-13 22:56:10 +0000130
Ted Kremenek79a2a262007-11-28 19:21:47 +0000131 for (std::list<Decl*>::iterator I=Decls.begin(), E=Decls.end(); I!=E; ++I) {
132 llvm::cerr << "Serializing: Decl.\n";
133
Ted Kremenek6127b122007-11-29 19:04:54 +0000134 // Only serialize the head of a decl chain. The ASTConsumer interfaces
135 // provides us with each top-level decl, including those nested in
136 // a decl chain, so we may be passed decls that are already serialized.
137 if (!Sezr.isRegistered(*I)) {
138 Printer->HandleTopLevelDecl(*I);
139 FilePrinter->HandleTopLevelDecl(*I);
140
141 if (FunctionDecl* FD = dyn_cast<FunctionDecl>(*I))
142 if (FD->getBody()) {
143 // Construct and print a CFG.
144 Janitor<CFG> cfg(CFG::buildCFG(FD->getBody()));
145 cfg->print(DeclPP);
146 }
147
148 // Serialize the decl.
149 Sezr.EmitOwnedPtr(*I);
150 }
Ted Kremenek79a2a262007-11-28 19:21:47 +0000151 }
Ted Kremenek7a1f4db2007-11-10 02:07:12 +0000152 }
153
154 Sezr.ExitBlock();
155
156 // ===---------------------------------------------------===/
Ted Kremenek018b3952007-11-06 19:50:53 +0000157 // Serialize the "Translation Unit" metadata.
158 // ===---------------------------------------------------===/
159
Ted Kremenekb899ad22007-11-14 17:46:35 +0000160 // Emit ASTContext.
161 Sezr.EnterBlock(ASTContextBlock);
162 llvm::cerr << "Serializing: ASTContext.\n";
163 Sezr.EmitOwnedPtr(Context);
164 Sezr.ExitBlock();
165
166
167 Sezr.EnterBlock(BasicMetadataBlock);
Ted Kremenek018b3952007-11-06 19:50:53 +0000168
Ted Kremenekbdbb2852007-11-30 22:46:56 +0000169 // Block for SourceManager and Target. Allows easy skipping around
170 // to the Selectors during deserialization.
171 Sezr.EnterBlock();
172
Ted Kremenek018b3952007-11-06 19:50:53 +0000173 // "Fake" emit the SourceManager.
174 llvm::cerr << "Faux-serializing: SourceManager.\n";
175 Sezr.EmitPtr(&Context->SourceMgr);
176
Ted Kremenekc4ca2882007-12-03 22:48:14 +0000177 // Emit the Target.
178 llvm::cerr << "Serializing: Target.\n";
Ted Kremenek018b3952007-11-06 19:50:53 +0000179 Sezr.EmitPtr(&Context->Target);
Ted Kremenekc4ca2882007-12-03 22:48:14 +0000180 Sezr.EmitCStr(Context->Target.getTargetTriple());
Ted Kremenek018b3952007-11-06 19:50:53 +0000181
Ted Kremenekbdbb2852007-11-30 22:46:56 +0000182 Sezr.ExitBlock();
183
184 // Emit the Selectors.
185 llvm::cerr << "Serializing: Selectors.\n";
186 Sezr.Emit(Context->Selectors);
Ted Kremenek018b3952007-11-06 19:50:53 +0000187
188 // Emit the Identifier Table.
189 llvm::cerr << "Serializing: IdentifierTable.\n";
Ted Kremenekbdbb2852007-11-30 22:46:56 +0000190 Sezr.Emit(Context->Idents);
Ted Kremenekb899ad22007-11-14 17:46:35 +0000191
Ted Kremenek018b3952007-11-06 19:50:53 +0000192 Sezr.ExitBlock();
193
194 // ===---------------------------------------------------===/
Ted Kremenek79a2a262007-11-28 19:21:47 +0000195 // Finalize serialization: write the bits to disk.
Ted Kremenekea75c552007-11-28 21:32:21 +0000196 if (FILE* fp = fopen(Filename.c_str(),"wb")) {
197 fwrite((char*)&Buffer.front(), sizeof(char), Buffer.size(), fp);
198 fclose(fp);
199 }
200 else {
201 llvm::cerr << "Error: Cannot open " << Filename.c_str() << "\n";
202 return;
Ted Kremenekbfa82c42007-10-16 23:37:27 +0000203 }
Ted Kremenekc637e6b2007-10-23 22:18:37 +0000204
Ted Kremenek018b3952007-11-06 19:50:53 +0000205 llvm::cerr << "Commited bitstream to disk: " << Filename.c_str() << "\n";
Ted Kremenekbfa82c42007-10-16 23:37:27 +0000206}
207
Ted Kremenekbfa82c42007-10-16 23:37:27 +0000208
Ted Kremenek79a2a262007-11-28 19:21:47 +0000209void SerializationTest::Deserialize(llvm::sys::Path& Filename,
210 llvm::sys::Path& FNameDeclPrint) {
Ted Kremenek018b3952007-11-06 19:50:53 +0000211
212 // Create the memory buffer that contains the contents of the file.
213
214 using llvm::MemoryBuffer;
215
Ted Kremenek79a2a262007-11-28 19:21:47 +0000216 Janitor<MemoryBuffer> MBuffer(MemoryBuffer::getFile(Filename.c_str(),
217 strlen(Filename.c_str())));
Ted Kremenekbfa82c42007-10-16 23:37:27 +0000218
Ted Kremenek4ac81212007-11-05 21:39:35 +0000219 if(!MBuffer) {
220 llvm::cerr << "ERROR: Cannot read file for deserialization.\n";
221 return;
Ted Kremenekbfa82c42007-10-16 23:37:27 +0000222 }
Ted Kremenekbfa82c42007-10-16 23:37:27 +0000223
Ted Kremenek018b3952007-11-06 19:50:53 +0000224 // Check if the file is of the proper length.
Ted Kremenek4ac81212007-11-05 21:39:35 +0000225 if (MBuffer->getBufferSize() & 0x3) {
Ted Kremenek018b3952007-11-06 19:50:53 +0000226 llvm::cerr << "ERROR: AST file length should be a multiple of 4 bytes.\n";
Ted Kremenek4ac81212007-11-05 21:39:35 +0000227 return;
Ted Kremenekc637e6b2007-10-23 22:18:37 +0000228 }
229
Ted Kremenek018b3952007-11-06 19:50:53 +0000230 // Create the bitstream reader.
231 unsigned char *BufPtr = (unsigned char *) MBuffer->getBufferStart();
232 llvm::BitstreamReader Stream(BufPtr,BufPtr+MBuffer->getBufferSize());
Ted Kremenekc637e6b2007-10-23 22:18:37 +0000233
Ted Kremenek018b3952007-11-06 19:50:53 +0000234 // Sniff for the signature in the bitcode file.
Ted Kremenek07c0fd92007-11-06 23:52:19 +0000235 if (ReadPreamble(Stream)) {
Ted Kremenek4ac81212007-11-05 21:39:35 +0000236 llvm::cerr << "ERROR: Invalid AST-bitcode signature.\n";
237 return;
Ted Kremenek7a1f4db2007-11-10 02:07:12 +0000238 }
239
240 // Create the deserializer.
Ted Kremenek018b3952007-11-06 19:50:53 +0000241 llvm::Deserializer Dezr(Stream);
242
243 // ===---------------------------------------------------===/
244 // Deserialize the "Translation Unit" metadata.
245 // ===---------------------------------------------------===/
246
Ted Kremenekb899ad22007-11-14 17:46:35 +0000247 // Skip to the BasicMetaDataBlock. First jump to ASTContextBlock
248 // (which will appear earlier) and record its location.
249
250 bool FoundBlock = Dezr.SkipToBlock(ASTContextBlock);
251 assert (FoundBlock);
252
253 llvm::Deserializer::Location ASTContextBlockLoc =
254 Dezr.getCurrentBlockLocation();
255
256 FoundBlock = Dezr.SkipToBlock(BasicMetadataBlock);
Ted Kremenek7a1f4db2007-11-10 02:07:12 +0000257 assert (FoundBlock);
258
Ted Kremenek018b3952007-11-06 19:50:53 +0000259 // "Fake" read the SourceManager.
260 llvm::cerr << "Faux-Deserializing: SourceManager.\n";
261 Dezr.RegisterPtr(&Context->SourceMgr);
262
Ted Kremenekc4ca2882007-12-03 22:48:14 +0000263 { // Read the TargetInfo.
264 llvm::cerr << "Deserializing: Target.\n";
265 llvm::SerializedPtrID PtrID = Dezr.ReadPtrID();
266 char* triple = Dezr.ReadCStr(NULL,0,true);
267 std::vector<std::string> triples;
268 triples.push_back(triple);
269 delete [] triple;
270 Dezr.RegisterPtr(PtrID,CreateTargetInfo(triples,Diags));
271 }
272
Ted Kremenekbdbb2852007-11-30 22:46:56 +0000273 // For Selectors, we must read the identifier table first because the
274 // SelectorTable depends on the identifiers being already deserialized.
Ted Kremenekc4ca2882007-12-03 22:48:14 +0000275 llvm::Deserializer::Location SelectorBlockLoc =
276 Dezr.getCurrentBlockLocation();
277
Ted Kremenekbdbb2852007-11-30 22:46:56 +0000278 Dezr.SkipBlock();
Ted Kremenek018b3952007-11-06 19:50:53 +0000279
280 // Read the identifier table.
281 llvm::cerr << "Deserializing: IdentifierTable\n";
Ted Kremenekbdbb2852007-11-30 22:46:56 +0000282 IdentifierTable::CreateAndRegister(Dezr);
283
284 // Now jump back and read the selectors.
285 llvm::cerr << "Deserializing: Selectors\n";
286 Dezr.JumpTo(SelectorBlockLoc);
287 SelectorTable::CreateAndRegister(Dezr);
Ted Kremenek018b3952007-11-06 19:50:53 +0000288
Ted Kremenekb899ad22007-11-14 17:46:35 +0000289 // Now jump back to ASTContextBlock and read the ASTContext.
Ted Kremenek018b3952007-11-06 19:50:53 +0000290 llvm::cerr << "Deserializing: ASTContext.\n";
Ted Kremenekbdbb2852007-11-30 22:46:56 +0000291 Dezr.JumpTo(ASTContextBlockLoc);
Ted Kremenek018b3952007-11-06 19:50:53 +0000292 Dezr.ReadOwnedPtr<ASTContext>();
Ted Kremenek79a2a262007-11-28 19:21:47 +0000293
Ted Kremenek7a1f4db2007-11-10 02:07:12 +0000294 // "Rewind" the stream. Find the block with the serialized top-level decls.
295 Dezr.Rewind();
Ted Kremenekb899ad22007-11-14 17:46:35 +0000296 FoundBlock = Dezr.SkipToBlock(DeclsBlock);
Ted Kremenek7a1f4db2007-11-10 02:07:12 +0000297 assert (FoundBlock);
298 llvm::Deserializer::Location DeclBlockLoc = Dezr.getCurrentBlockLocation();
299
Ted Kremenek79a2a262007-11-28 19:21:47 +0000300 // Create a printer to "consume" our deserialized ASTS.
301 ASTConsumer* Printer = CreateASTPrinter();
302 Janitor<ASTConsumer> PrinterJanitor(Printer);
Ted Kremenekea75c552007-11-28 21:32:21 +0000303 std::ofstream DeclPP(FNameDeclPrint.c_str());
304 assert (DeclPP && "Could not open file for printing out decls.");
305 Janitor<ASTConsumer> FilePrinter(CreateASTPrinter(&DeclPP));
Ted Kremenek79a2a262007-11-28 19:21:47 +0000306
Ted Kremenek018b3952007-11-06 19:50:53 +0000307 // The remaining objects in the file are top-level decls.
Ted Kremenek7a1f4db2007-11-10 02:07:12 +0000308 while (!Dezr.FinishedBlock(DeclBlockLoc)) {
Ted Kremenek018b3952007-11-06 19:50:53 +0000309 llvm::cerr << "Deserializing: Decl.\n";
310 Decl* decl = Dezr.ReadOwnedPtr<Decl>();
Ted Kremenek79a2a262007-11-28 19:21:47 +0000311 Printer->HandleTopLevelDecl(decl);
312 FilePrinter->HandleTopLevelDecl(decl);
Ted Kremenek5656b782007-11-29 01:24:25 +0000313
314 if (FunctionDecl* FD = dyn_cast<FunctionDecl>(decl))
315 if (FD->getBody()) {
316 // Construct and print a CFG.
317 Janitor<CFG> cfg(CFG::buildCFG(FD->getBody()));
318 cfg->print(DeclPP);
319 }
Ted Kremenek018b3952007-11-06 19:50:53 +0000320 }
321}
322
Ted Kremenek79a2a262007-11-28 19:21:47 +0000323namespace {
324 class TmpDirJanitor {
325 llvm::sys::Path& Dir;
326 public:
327 explicit TmpDirJanitor(llvm::sys::Path& dir) : Dir(dir) {}
328
329 ~TmpDirJanitor() {
330 llvm::cerr << "Removing: " << Dir.c_str() << '\n';
331 Dir.eraseFromDisk(true);
332 }
333 };
334}
Ted Kremenek018b3952007-11-06 19:50:53 +0000335
336SerializationTest::~SerializationTest() {
Ted Kremenek79a2a262007-11-28 19:21:47 +0000337
Ted Kremenek018b3952007-11-06 19:50:53 +0000338 std::string ErrMsg;
Ted Kremenek79a2a262007-11-28 19:21:47 +0000339 llvm::sys::Path Dir = llvm::sys::Path::GetTemporaryDirectory(&ErrMsg);
Ted Kremenek018b3952007-11-06 19:50:53 +0000340
Ted Kremenek79a2a262007-11-28 19:21:47 +0000341 if (Dir.isEmpty()) {
Ted Kremenek018b3952007-11-06 19:50:53 +0000342 llvm::cerr << "Error: " << ErrMsg << "\n";
343 return;
Ted Kremenekc637e6b2007-10-23 22:18:37 +0000344 }
345
Ted Kremenek79a2a262007-11-28 19:21:47 +0000346 TmpDirJanitor RemoveTmpOnExit(Dir);
347
348 llvm::sys::Path FNameDeclBefore = Dir;
349 FNameDeclBefore.appendComponent("test.decl_before.txt");
350
351 if (FNameDeclBefore.makeUnique(true,&ErrMsg)) {
Ted Kremenek018b3952007-11-06 19:50:53 +0000352 llvm::cerr << "Error: " << ErrMsg << "\n";
353 return;
354 }
Ted Kremenek4ac81212007-11-05 21:39:35 +0000355
Ted Kremenek79a2a262007-11-28 19:21:47 +0000356 llvm::sys::Path FNameDeclAfter = Dir;
357 FNameDeclAfter.appendComponent("test.decl_after.txt");
358
359 if (FNameDeclAfter.makeUnique(true,&ErrMsg)) {
360 llvm::cerr << "Error: " << ErrMsg << "\n";
361 return;
362 }
363
364 llvm::sys::Path ASTFilename = Dir;
365 ASTFilename.appendComponent("test.ast");
366
367 if (ASTFilename.makeUnique(true,&ErrMsg)) {
368 llvm::cerr << "Error: " << ErrMsg << "\n";
369 return;
370 }
371
372 // Serialize and then deserialize the ASTs.
373 Serialize(ASTFilename, FNameDeclBefore);
374 Deserialize(ASTFilename, FNameDeclAfter);
375
376 // Read both pretty-printed files and compare them.
377
378 using llvm::MemoryBuffer;
379
380 Janitor<MemoryBuffer>
381 MBufferSer(MemoryBuffer::getFile(FNameDeclBefore.c_str(),
382 strlen(FNameDeclBefore.c_str())));
383
384 if(!MBufferSer) {
385 llvm::cerr << "ERROR: Cannot read pretty-printed file (pre-pickle).\n";
386 return;
387 }
388
389 Janitor<MemoryBuffer>
390 MBufferDSer(MemoryBuffer::getFile(FNameDeclAfter.c_str(),
391 strlen(FNameDeclAfter.c_str())));
392
393 if(!MBufferDSer) {
394 llvm::cerr << "ERROR: Cannot read pretty-printed file (post-pickle).\n";
395 return;
396 }
397
398 const char *p1 = MBufferSer->getBufferStart();
399 const char *e1 = MBufferSer->getBufferEnd();
400 const char *p2 = MBufferDSer->getBufferStart();
401 const char *e2 = MBufferDSer->getBufferEnd();
402
403 if (MBufferSer->getBufferSize() == MBufferDSer->getBufferSize())
404 for ( ; p1 != e1 ; ++p1, ++p2 )
405 if (*p1 != *p2) break;
406
407 if (p1 != e1 || p2 != e2 )
408 llvm::cerr << "ERROR: Pretty-printed files are not the same.\n";
409 else
410 llvm::cerr << "SUCCESS: Pretty-printed files are the same.\n";
Ted Kremenekc637e6b2007-10-23 22:18:37 +0000411}