blob: 811dddbb74b12cd2baf9caaf3e67a4d754dc6917 [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"
24#include "llvm/Bitcode/Serialization.h"
25#include <stdio.h>
26
27//===----------------------------------------------------------------------===//
28// Driver code.
29//===----------------------------------------------------------------------===//
Ted Kremenekbfa82c42007-10-16 23:37:27 +000030
31using namespace clang;
Ted Kremenekbfa82c42007-10-16 23:37:27 +000032
33namespace {
Ted Kremenekc637e6b2007-10-23 22:18:37 +000034 template<typename T>
35 struct Janitor {
36 T* Obj;
37 Janitor(T* obj) : Obj(obj) {}
38 ~Janitor() { delete Obj; }
39 };
40} // end anonymous namespace
Ted Kremenekbfa82c42007-10-16 23:37:27 +000041
Ted Kremenekc637e6b2007-10-23 22:18:37 +000042namespace {
43 class SerializationTest : public ASTConsumer {
44 IdentifierTable* IdTable;
45 unsigned MainFileID;
46 public:
47 void Initialize(ASTContext& Context, unsigned mainFileID) {
48 IdTable = &Context.Idents;
49 MainFileID = mainFileID;
50 }
Ted Kremenekbfa82c42007-10-16 23:37:27 +000051
Ted Kremenekc637e6b2007-10-23 22:18:37 +000052 ~SerializationTest() {
53 RunSerializationTest();
54 }
Ted Kremenekbfa82c42007-10-16 23:37:27 +000055
Ted Kremenekc637e6b2007-10-23 22:18:37 +000056 void RunSerializationTest();
57 bool WriteTable(llvm::sys::Path& Filename, IdentifierTable* T);
58 IdentifierTable* ReadTable(llvm::sys::Path& Filename);
59
60 virtual void HandleTopLevelDecl(Decl *D) {}
61 };
62} // end anonymous namespace
Ted Kremenekbfa82c42007-10-16 23:37:27 +000063
64ASTConsumer* clang::CreateSerializationTest() {
65 return new SerializationTest();
66}
Ted Kremenekbfa82c42007-10-16 23:37:27 +000067
68void SerializationTest::RunSerializationTest() {
69 std::string ErrMsg;
70 llvm::sys::Path Filename = llvm::sys::Path::GetTemporaryDirectory(&ErrMsg);
Ted Kremenekc637e6b2007-10-23 22:18:37 +000071
Ted Kremenekbfa82c42007-10-16 23:37:27 +000072 if (Filename.isEmpty()) {
Ted Kremenekc637e6b2007-10-23 22:18:37 +000073 llvm::cerr << "Error: " << ErrMsg << "\n";
Ted Kremenekbfa82c42007-10-16 23:37:27 +000074 return;
75 }
76
Ted Kremenekc637e6b2007-10-23 22:18:37 +000077 Filename.appendComponent("test.ast");
Ted Kremenekbfa82c42007-10-16 23:37:27 +000078
79 if (Filename.makeUnique(true,&ErrMsg)) {
Ted Kremenekc637e6b2007-10-23 22:18:37 +000080 llvm::cerr << "Error: " << ErrMsg << "\n";
Ted Kremenekbfa82c42007-10-16 23:37:27 +000081 return;
82 }
83
Ted Kremenekc637e6b2007-10-23 22:18:37 +000084 llvm::cerr << "Writing out Identifier table\n";
85 WriteTable(Filename,IdTable);
86 llvm::cerr << "Reading in Identifier Table\n";
87 IdentifierTable* T = ReadTable(Filename);
88 Janitor<IdentifierTable> roger(T);
Ted Kremenekbfa82c42007-10-16 23:37:27 +000089
Ted Kremenekc637e6b2007-10-23 22:18:37 +000090 Filename.appendSuffix("2");
91 llvm::cerr << "Writing out Identifier table (2)\n";
92 WriteTable(Filename,T);
93 llvm::cerr << "Reading in Identifier Table (2)\n";
94 Janitor<IdentifierTable> wilco(ReadTable(Filename));
Ted Kremenekbfa82c42007-10-16 23:37:27 +000095}
96
Ted Kremenekc637e6b2007-10-23 22:18:37 +000097bool SerializationTest::WriteTable(llvm::sys::Path& Filename,
98 IdentifierTable* T) {
99 if (!T)
100 return false;
Ted Kremenekbfa82c42007-10-16 23:37:27 +0000101
Ted Kremenekc637e6b2007-10-23 22:18:37 +0000102 std::vector<unsigned char> Buffer;
103 Buffer.reserve(256*1024);
104
105 llvm::BitstreamWriter Stream(Buffer);
106
107 Stream.Emit((unsigned)'B', 8);
108 Stream.Emit((unsigned)'C', 8);
109 Stream.Emit(0xC, 4);
110 Stream.Emit(0xF, 4);
111 Stream.Emit(0xE, 4);
112 Stream.Emit(0x0, 4);
113
114 llvm::Serializer S(Stream);
115 S.Emit(*T);
116 S.Flush();
117
118 if (FILE *fp = fopen(Filename.c_str(),"wb")) {
119 fwrite((char*)&Buffer.front(), sizeof(char), Buffer.size(), fp);
120 fclose(fp);
121 }
122 else {
123 llvm::cerr << "Error: Cannot open " << Filename.c_str() << "\n";
Ted Kremenekbfa82c42007-10-16 23:37:27 +0000124 return false;
125 }
Ted Kremenekc637e6b2007-10-23 22:18:37 +0000126
127 llvm::cerr << "Wrote file: " << Filename.c_str() << "\n";
Ted Kremenekbfa82c42007-10-16 23:37:27 +0000128 return true;
129}
130
Ted Kremenekbfa82c42007-10-16 23:37:27 +0000131
Ted Kremenekc637e6b2007-10-23 22:18:37 +0000132IdentifierTable* SerializationTest::ReadTable(llvm::sys::Path& Filename) {
133 llvm::MemoryBuffer* Buffer =
134 llvm::MemoryBuffer::getFile(Filename.c_str(), strlen(Filename.c_str()));
Ted Kremenekbfa82c42007-10-16 23:37:27 +0000135
Ted Kremenekc637e6b2007-10-23 22:18:37 +0000136 if(!Buffer) {
137 llvm::cerr << "Error reading file\n";
138 return NULL;
Ted Kremenekbfa82c42007-10-16 23:37:27 +0000139 }
Ted Kremenekbfa82c42007-10-16 23:37:27 +0000140
Ted Kremenekc637e6b2007-10-23 22:18:37 +0000141 Janitor<llvm::MemoryBuffer> AutoReleaseBuffer(Buffer);
Ted Kremenekbfa82c42007-10-16 23:37:27 +0000142
Ted Kremenekc637e6b2007-10-23 22:18:37 +0000143 if (Buffer->getBufferSize() & 0x3) {
144 llvm::cerr << "AST file should be a multiple of 4 bytes in length\n";
145 return NULL;
146 }
147
148 unsigned char *BufPtr = (unsigned char *)Buffer->getBufferStart();
149 llvm::BitstreamReader Stream(BufPtr,BufPtr+Buffer->getBufferSize());
150
151 // Sniff for the signature.
152 if (Stream.Read(8) != 'B' ||
153 Stream.Read(8) != 'C' ||
154 Stream.Read(4) != 0xC ||
155 Stream.Read(4) != 0xF ||
156 Stream.Read(4) != 0xE ||
157 Stream.Read(4) != 0x0) {
158 llvm::cerr << "Invalid AST-bitcode signature\n";
159 return NULL;
160 }
161
162 llvm::Deserializer D(Stream);
Ted Kremenekbfa82c42007-10-16 23:37:27 +0000163
Ted Kremenekc637e6b2007-10-23 22:18:37 +0000164 llvm::cerr << "Materializing identifier table.\n";
165 return D.Materialize<IdentifierTable>();
166}