blob: b431fb3a154c9dfec9bd57215eca2b121c1177f1 [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
29//===----------------------------------------------------------------------===//
30// Driver code.
31//===----------------------------------------------------------------------===//
Ted Kremenekbfa82c42007-10-16 23:37:27 +000032
33using namespace clang;
Ted Kremenek4ac81212007-11-05 21:39:35 +000034using llvm::sys::TimeValue;
Ted Kremenekbfa82c42007-10-16 23:37:27 +000035
36namespace {
Ted Kremenekbfa82c42007-10-16 23:37:27 +000037
Ted Kremenek4ac81212007-11-05 21:39:35 +000038template<typename T> struct Janitor {
39 T* Obj;
40 Janitor(T* obj) : Obj(obj) {}
41 ~Janitor() { delete Obj; }
42};
43
44class SerializationTest : public ASTConsumer {
45 ASTContext* Context;
Ted Kremenek018b3952007-11-06 19:50:53 +000046 std::list<Decl*> Decls;
Ted Kremenek4ac81212007-11-05 21:39:35 +000047
Ted Kremenekb899ad22007-11-14 17:46:35 +000048 enum { BasicMetadataBlock,
49 ASTContextBlock,
50 DeclsBlock };
Ted Kremenek018b3952007-11-06 19:50:53 +000051
52public:
53 SerializationTest() : Context(NULL) {};
Ted Kremenek4ac81212007-11-05 21:39:35 +000054 ~SerializationTest();
55
Ted Kremenek018b3952007-11-06 19:50:53 +000056 virtual void Initialize(ASTContext& context, unsigned) {
57 Context = &context;
58 }
59
60 virtual void HandleTopLevelDecl(Decl *D) {
61 Decls.push_back(D);
62 }
63
64private:
65 void Serialize(llvm::sys::Path& Filename);
66 void Deserialize(llvm::sys::Path& Filename);
Ted Kremenek4ac81212007-11-05 21:39:35 +000067};
68
Ted Kremenekc637e6b2007-10-23 22:18:37 +000069} // end anonymous namespace
Ted Kremenekbfa82c42007-10-16 23:37:27 +000070
Ted Kremenek018b3952007-11-06 19:50:53 +000071ASTConsumer* clang::CreateSerializationTest() {
72 return new SerializationTest();
73}
74
75static void WritePreamble(llvm::BitstreamWriter& Stream) {
76 Stream.Emit((unsigned)'B', 8);
77 Stream.Emit((unsigned)'C', 8);
78 Stream.Emit(0xC, 4);
79 Stream.Emit(0xF, 4);
80 Stream.Emit(0xE, 4);
81 Stream.Emit(0x0, 4);
82}
83
Ted Kremenek07c0fd92007-11-06 23:52:19 +000084static bool ReadPreamble(llvm::BitstreamReader& Stream) {
Ted Kremenek018b3952007-11-06 19:50:53 +000085 return Stream.Read(8) != 'B' ||
86 Stream.Read(8) != 'C' ||
87 Stream.Read(4) != 0xC ||
88 Stream.Read(4) != 0xF ||
89 Stream.Read(4) != 0xE ||
90 Stream.Read(4) != 0x0;
91}
92
93void SerializationTest::Serialize(llvm::sys::Path& Filename) {
Ted Kremenekc637e6b2007-10-23 22:18:37 +000094
Ted Kremenek018b3952007-11-06 19:50:53 +000095 // Reserve 256K for bitstream buffer.
96 std::vector<unsigned char> Buffer;
97 Buffer.reserve(256*1024);
98
99 // Create bitstream and write preamble.
100 llvm::BitstreamWriter Stream(Buffer);
101 WritePreamble(Stream);
102
103 // Create serializer.
104 llvm::Serializer Sezr(Stream);
105
106 // ===---------------------------------------------------===/
Ted Kremenek7a1f4db2007-11-10 02:07:12 +0000107 // Serialize the top-level decls.
108 // ===---------------------------------------------------===/
109
Ted Kremenekb899ad22007-11-14 17:46:35 +0000110 Sezr.EnterBlock(DeclsBlock);
Ted Kremenek7a1f4db2007-11-10 02:07:12 +0000111
Ted Kremeneke7201982007-11-13 22:56:10 +0000112 // Create a printer to "consume" our deserialized ASTS.
113 ASTConsumer* Printer = CreateASTPrinter();
114 Janitor<ASTConsumer> PrinterJanitor(Printer);
115
Ted Kremenek7a1f4db2007-11-10 02:07:12 +0000116 for (std::list<Decl*>::iterator I=Decls.begin(), E=Decls.end(); I!=E; ++I) {
Ted Kremeneke7201982007-11-13 22:56:10 +0000117 llvm::cerr << "Serializing: Decl.\n";
118
119 Printer->HandleTopLevelDecl(*I);
120
Ted Kremenek7a1f4db2007-11-10 02:07:12 +0000121 Sezr.EmitOwnedPtr(*I);
122 }
123
124 Sezr.ExitBlock();
125
126 // ===---------------------------------------------------===/
Ted Kremenek018b3952007-11-06 19:50:53 +0000127 // Serialize the "Translation Unit" metadata.
128 // ===---------------------------------------------------===/
129
Ted Kremenekb899ad22007-11-14 17:46:35 +0000130 // Emit ASTContext.
131 Sezr.EnterBlock(ASTContextBlock);
132 llvm::cerr << "Serializing: ASTContext.\n";
133 Sezr.EmitOwnedPtr(Context);
134 Sezr.ExitBlock();
135
136
137 Sezr.EnterBlock(BasicMetadataBlock);
Ted Kremenek018b3952007-11-06 19:50:53 +0000138
139 // "Fake" emit the SourceManager.
140 llvm::cerr << "Faux-serializing: SourceManager.\n";
141 Sezr.EmitPtr(&Context->SourceMgr);
142
143 // "Fake" emit the Target.
144 llvm::cerr << "Faux-serializing: Target.\n";
145 Sezr.EmitPtr(&Context->Target);
146
147 // "Fake" emit Selectors.
148 llvm::cerr << "Faux-serializing: Selectors.\n";
149 Sezr.EmitPtr(&Context->Selectors);
150
151 // Emit the Identifier Table.
152 llvm::cerr << "Serializing: IdentifierTable.\n";
153 Sezr.EmitOwnedPtr(&Context->Idents);
Ted Kremenekb899ad22007-11-14 17:46:35 +0000154
Ted Kremenek018b3952007-11-06 19:50:53 +0000155 Sezr.ExitBlock();
156
157 // ===---------------------------------------------------===/
Ted Kremenek018b3952007-11-06 19:50:53 +0000158 // Finalize serialization: write the bits to disk.
159 // ===---------------------------------------------------===/
Ted Kremenekc637e6b2007-10-23 22:18:37 +0000160
161 if (FILE *fp = fopen(Filename.c_str(),"wb")) {
Ted Kremenek018b3952007-11-06 19:50:53 +0000162 fwrite((char*)&Buffer.front(), sizeof(char), Buffer.size(), fp);
Ted Kremenekc637e6b2007-10-23 22:18:37 +0000163 fclose(fp);
164 }
165 else {
166 llvm::cerr << "Error: Cannot open " << Filename.c_str() << "\n";
Ted Kremenek4ac81212007-11-05 21:39:35 +0000167 return;
Ted Kremenekbfa82c42007-10-16 23:37:27 +0000168 }
Ted Kremenekc637e6b2007-10-23 22:18:37 +0000169
Ted Kremenek018b3952007-11-06 19:50:53 +0000170 llvm::cerr << "Commited bitstream to disk: " << Filename.c_str() << "\n";
Ted Kremenekbfa82c42007-10-16 23:37:27 +0000171}
172
Ted Kremenekbfa82c42007-10-16 23:37:27 +0000173
Ted Kremenek018b3952007-11-06 19:50:53 +0000174void SerializationTest::Deserialize(llvm::sys::Path& Filename) {
175
176 // Create the memory buffer that contains the contents of the file.
177
178 using llvm::MemoryBuffer;
179
180 MemoryBuffer* MBuffer = MemoryBuffer::getFile(Filename.c_str(),
181 strlen(Filename.c_str()));
Ted Kremenekbfa82c42007-10-16 23:37:27 +0000182
Ted Kremenek4ac81212007-11-05 21:39:35 +0000183 if(!MBuffer) {
184 llvm::cerr << "ERROR: Cannot read file for deserialization.\n";
185 return;
Ted Kremenekbfa82c42007-10-16 23:37:27 +0000186 }
Ted Kremenekbfa82c42007-10-16 23:37:27 +0000187
Ted Kremenek018b3952007-11-06 19:50:53 +0000188 // Create an "autocollector" object to release the memory buffer upon
189 // termination of the current scope.
190 Janitor<MemoryBuffer> AutoReleaseBuffer(MBuffer);
Ted Kremenekbfa82c42007-10-16 23:37:27 +0000191
Ted Kremenek018b3952007-11-06 19:50:53 +0000192 // Check if the file is of the proper length.
Ted Kremenek4ac81212007-11-05 21:39:35 +0000193 if (MBuffer->getBufferSize() & 0x3) {
Ted Kremenek018b3952007-11-06 19:50:53 +0000194 llvm::cerr << "ERROR: AST file length should be a multiple of 4 bytes.\n";
Ted Kremenek4ac81212007-11-05 21:39:35 +0000195 return;
Ted Kremenekc637e6b2007-10-23 22:18:37 +0000196 }
197
Ted Kremenek018b3952007-11-06 19:50:53 +0000198 // Create the bitstream reader.
199 unsigned char *BufPtr = (unsigned char *) MBuffer->getBufferStart();
200 llvm::BitstreamReader Stream(BufPtr,BufPtr+MBuffer->getBufferSize());
Ted Kremenekc637e6b2007-10-23 22:18:37 +0000201
Ted Kremenek018b3952007-11-06 19:50:53 +0000202 // Sniff for the signature in the bitcode file.
Ted Kremenek07c0fd92007-11-06 23:52:19 +0000203 if (ReadPreamble(Stream)) {
Ted Kremenek4ac81212007-11-05 21:39:35 +0000204 llvm::cerr << "ERROR: Invalid AST-bitcode signature.\n";
205 return;
Ted Kremenek7a1f4db2007-11-10 02:07:12 +0000206 }
207
208 // Create the deserializer.
Ted Kremenek018b3952007-11-06 19:50:53 +0000209 llvm::Deserializer Dezr(Stream);
210
211 // ===---------------------------------------------------===/
212 // Deserialize the "Translation Unit" metadata.
213 // ===---------------------------------------------------===/
214
Ted Kremenekb899ad22007-11-14 17:46:35 +0000215 // Skip to the BasicMetaDataBlock. First jump to ASTContextBlock
216 // (which will appear earlier) and record its location.
217
218 bool FoundBlock = Dezr.SkipToBlock(ASTContextBlock);
219 assert (FoundBlock);
220
221 llvm::Deserializer::Location ASTContextBlockLoc =
222 Dezr.getCurrentBlockLocation();
223
224 FoundBlock = Dezr.SkipToBlock(BasicMetadataBlock);
Ted Kremenek7a1f4db2007-11-10 02:07:12 +0000225 assert (FoundBlock);
226
Ted Kremenek018b3952007-11-06 19:50:53 +0000227 // "Fake" read the SourceManager.
228 llvm::cerr << "Faux-Deserializing: SourceManager.\n";
229 Dezr.RegisterPtr(&Context->SourceMgr);
230
231 // "Fake" read the TargetInfo.
232 llvm::cerr << "Faux-Deserializing: Target.\n";
233 Dezr.RegisterPtr(&Context->Target);
234
235 // "Fake" read the Selectors.
236 llvm::cerr << "Faux-Deserializing: Selectors.\n";
237 Dezr.RegisterPtr(&Context->Selectors);
238
239 // Read the identifier table.
240 llvm::cerr << "Deserializing: IdentifierTable\n";
241 Dezr.ReadOwnedPtr<IdentifierTable>();
242
Ted Kremenekb899ad22007-11-14 17:46:35 +0000243 // Now jump back to ASTContextBlock and read the ASTContext.
244 Dezr.JumpTo(ASTContextBlockLoc);
245
Ted Kremenek018b3952007-11-06 19:50:53 +0000246 // Read the ASTContext.
247 llvm::cerr << "Deserializing: ASTContext.\n";
248 Dezr.ReadOwnedPtr<ASTContext>();
249
250 // Create a printer to "consume" our deserialized ASTS.
251 ASTConsumer* Printer = CreateASTPrinter();
252 Janitor<ASTConsumer> PrinterJanitor(Printer);
253
Ted Kremenek7a1f4db2007-11-10 02:07:12 +0000254 // "Rewind" the stream. Find the block with the serialized top-level decls.
255 Dezr.Rewind();
Ted Kremenekb899ad22007-11-14 17:46:35 +0000256 FoundBlock = Dezr.SkipToBlock(DeclsBlock);
Ted Kremenek7a1f4db2007-11-10 02:07:12 +0000257 assert (FoundBlock);
258 llvm::Deserializer::Location DeclBlockLoc = Dezr.getCurrentBlockLocation();
259
Ted Kremenek018b3952007-11-06 19:50:53 +0000260 // The remaining objects in the file are top-level decls.
Ted Kremenek7a1f4db2007-11-10 02:07:12 +0000261 while (!Dezr.FinishedBlock(DeclBlockLoc)) {
Ted Kremenek018b3952007-11-06 19:50:53 +0000262 llvm::cerr << "Deserializing: Decl.\n";
263 Decl* decl = Dezr.ReadOwnedPtr<Decl>();
264 Printer->HandleTopLevelDecl(decl);
265 }
266}
267
268
269SerializationTest::~SerializationTest() {
270
271 std::string ErrMsg;
272 llvm::sys::Path Filename = llvm::sys::Path::GetTemporaryDirectory(&ErrMsg);
273
274 if (Filename.isEmpty()) {
275 llvm::cerr << "Error: " << ErrMsg << "\n";
276 return;
Ted Kremenekc637e6b2007-10-23 22:18:37 +0000277 }
278
Ted Kremenek018b3952007-11-06 19:50:53 +0000279 Filename.appendComponent("test.ast");
Ted Kremenek4ac81212007-11-05 21:39:35 +0000280
Ted Kremenek018b3952007-11-06 19:50:53 +0000281 if (Filename.makeUnique(true,&ErrMsg)) {
282 llvm::cerr << "Error: " << ErrMsg << "\n";
283 return;
284 }
Ted Kremenek4ac81212007-11-05 21:39:35 +0000285
Ted Kremenek018b3952007-11-06 19:50:53 +0000286 Serialize(Filename);
287 Deserialize(Filename);
Ted Kremenekc637e6b2007-10-23 22:18:37 +0000288}