blob: 26a4df85d8bfe0bd9c8e3e4eb06321ac6ca2e242 [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>
27
28//===----------------------------------------------------------------------===//
29// Driver code.
30//===----------------------------------------------------------------------===//
Ted Kremenekbfa82c42007-10-16 23:37:27 +000031
32using namespace clang;
Ted Kremenekbfa82c42007-10-16 23:37:27 +000033
34namespace {
Ted Kremenekc637e6b2007-10-23 22:18:37 +000035 template<typename T>
36 struct Janitor {
37 T* Obj;
38 Janitor(T* obj) : Obj(obj) {}
39 ~Janitor() { delete Obj; }
40 };
41} // end anonymous namespace
Ted Kremenekbfa82c42007-10-16 23:37:27 +000042
Ted Kremenekc637e6b2007-10-23 22:18:37 +000043namespace {
44 class SerializationTest : public ASTConsumer {
45 IdentifierTable* IdTable;
46 unsigned MainFileID;
47 public:
48 void Initialize(ASTContext& Context, unsigned mainFileID) {
49 IdTable = &Context.Idents;
50 MainFileID = mainFileID;
51 }
Ted Kremenekbfa82c42007-10-16 23:37:27 +000052
Ted Kremenekc637e6b2007-10-23 22:18:37 +000053 ~SerializationTest() {
54 RunSerializationTest();
55 }
Ted Kremenekbfa82c42007-10-16 23:37:27 +000056
Ted Kremenekc637e6b2007-10-23 22:18:37 +000057 void RunSerializationTest();
58 bool WriteTable(llvm::sys::Path& Filename, IdentifierTable* T);
59 IdentifierTable* ReadTable(llvm::sys::Path& Filename);
60
61 virtual void HandleTopLevelDecl(Decl *D) {}
62 };
63} // end anonymous namespace
Ted Kremenekbfa82c42007-10-16 23:37:27 +000064
65ASTConsumer* clang::CreateSerializationTest() {
66 return new SerializationTest();
67}
Ted Kremenekbfa82c42007-10-16 23:37:27 +000068
69void SerializationTest::RunSerializationTest() {
70 std::string ErrMsg;
71 llvm::sys::Path Filename = llvm::sys::Path::GetTemporaryDirectory(&ErrMsg);
Ted Kremenekc637e6b2007-10-23 22:18:37 +000072
Ted Kremenekbfa82c42007-10-16 23:37:27 +000073 if (Filename.isEmpty()) {
Ted Kremenekc637e6b2007-10-23 22:18:37 +000074 llvm::cerr << "Error: " << ErrMsg << "\n";
Ted Kremenekbfa82c42007-10-16 23:37:27 +000075 return;
76 }
77
Ted Kremenekc637e6b2007-10-23 22:18:37 +000078 Filename.appendComponent("test.ast");
Ted Kremenekbfa82c42007-10-16 23:37:27 +000079
80 if (Filename.makeUnique(true,&ErrMsg)) {
Ted Kremenekc637e6b2007-10-23 22:18:37 +000081 llvm::cerr << "Error: " << ErrMsg << "\n";
Ted Kremenekbfa82c42007-10-16 23:37:27 +000082 return;
83 }
84
Ted Kremenekc637e6b2007-10-23 22:18:37 +000085 llvm::cerr << "Writing out Identifier table\n";
86 WriteTable(Filename,IdTable);
87 llvm::cerr << "Reading in Identifier Table\n";
88 IdentifierTable* T = ReadTable(Filename);
89 Janitor<IdentifierTable> roger(T);
Ted Kremenekbfa82c42007-10-16 23:37:27 +000090
Ted Kremenekc637e6b2007-10-23 22:18:37 +000091 Filename.appendSuffix("2");
92 llvm::cerr << "Writing out Identifier table (2)\n";
93 WriteTable(Filename,T);
94 llvm::cerr << "Reading in Identifier Table (2)\n";
95 Janitor<IdentifierTable> wilco(ReadTable(Filename));
Ted Kremenekbfa82c42007-10-16 23:37:27 +000096}
97
Ted Kremenekc637e6b2007-10-23 22:18:37 +000098bool SerializationTest::WriteTable(llvm::sys::Path& Filename,
99 IdentifierTable* T) {
100 if (!T)
101 return false;
Ted Kremenekbfa82c42007-10-16 23:37:27 +0000102
Ted Kremenekc637e6b2007-10-23 22:18:37 +0000103 std::vector<unsigned char> Buffer;
104 Buffer.reserve(256*1024);
105
106 llvm::BitstreamWriter Stream(Buffer);
107
108 Stream.Emit((unsigned)'B', 8);
109 Stream.Emit((unsigned)'C', 8);
110 Stream.Emit(0xC, 4);
111 Stream.Emit(0xF, 4);
112 Stream.Emit(0xE, 4);
113 Stream.Emit(0x0, 4);
114
115 llvm::Serializer S(Stream);
116 S.Emit(*T);
117 S.Flush();
118
119 if (FILE *fp = fopen(Filename.c_str(),"wb")) {
120 fwrite((char*)&Buffer.front(), sizeof(char), Buffer.size(), fp);
121 fclose(fp);
122 }
123 else {
124 llvm::cerr << "Error: Cannot open " << Filename.c_str() << "\n";
Ted Kremenekbfa82c42007-10-16 23:37:27 +0000125 return false;
126 }
Ted Kremenekc637e6b2007-10-23 22:18:37 +0000127
128 llvm::cerr << "Wrote file: " << Filename.c_str() << "\n";
Ted Kremenekbfa82c42007-10-16 23:37:27 +0000129 return true;
130}
131
Ted Kremenekbfa82c42007-10-16 23:37:27 +0000132
Ted Kremenekc637e6b2007-10-23 22:18:37 +0000133IdentifierTable* SerializationTest::ReadTable(llvm::sys::Path& Filename) {
134 llvm::MemoryBuffer* Buffer =
135 llvm::MemoryBuffer::getFile(Filename.c_str(), strlen(Filename.c_str()));
Ted Kremenekbfa82c42007-10-16 23:37:27 +0000136
Ted Kremenekc637e6b2007-10-23 22:18:37 +0000137 if(!Buffer) {
138 llvm::cerr << "Error reading file\n";
139 return NULL;
Ted Kremenekbfa82c42007-10-16 23:37:27 +0000140 }
Ted Kremenekbfa82c42007-10-16 23:37:27 +0000141
Ted Kremenekc637e6b2007-10-23 22:18:37 +0000142 Janitor<llvm::MemoryBuffer> AutoReleaseBuffer(Buffer);
Ted Kremenekbfa82c42007-10-16 23:37:27 +0000143
Ted Kremenekc637e6b2007-10-23 22:18:37 +0000144 if (Buffer->getBufferSize() & 0x3) {
145 llvm::cerr << "AST file should be a multiple of 4 bytes in length\n";
146 return NULL;
147 }
148
149 unsigned char *BufPtr = (unsigned char *)Buffer->getBufferStart();
150 llvm::BitstreamReader Stream(BufPtr,BufPtr+Buffer->getBufferSize());
151
152 // Sniff for the signature.
153 if (Stream.Read(8) != 'B' ||
154 Stream.Read(8) != 'C' ||
155 Stream.Read(4) != 0xC ||
156 Stream.Read(4) != 0xF ||
157 Stream.Read(4) != 0xE ||
158 Stream.Read(4) != 0x0) {
159 llvm::cerr << "Invalid AST-bitcode signature\n";
160 return NULL;
161 }
162
163 llvm::Deserializer D(Stream);
Ted Kremenekbfa82c42007-10-16 23:37:27 +0000164
Ted Kremenekc637e6b2007-10-23 22:18:37 +0000165 llvm::cerr << "Materializing identifier table.\n";
166 return D.Materialize<IdentifierTable>();
167}