aboutsummaryrefslogtreecommitdiff
path: root/Driver/SerializationTest.cpp
blob: 811dddbb74b12cd2baf9caaf3e67a4d754dc6917 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
//===--- SerializationTest.cpp - Experimental Object Serialization --------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file was developed by Ted Kremenek and is distributed under
// the University of Illinois Open Source License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
//  This file implements prototype code for serialization of objects in clang.
//  It is not intended yet for public use, but simply is a placeholder to
//  experiment with new serialization features.  Serialization will eventually
//  be integrated as a proper component of the clang libraries.
//
//===----------------------------------------------------------------------===//

#include "ASTConsumers.h"
#include "clang/AST/AST.h"
#include "clang/AST/ASTConsumer.h"
#include "clang/AST/ASTContext.h"
#include "llvm/System/Path.h"
#include "llvm/Support/Streams.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Bitcode/Serialization.h"
#include <stdio.h>

//===----------------------------------------------------------------------===//
// Driver code.
//===----------------------------------------------------------------------===//

using namespace clang;

namespace {
  template<typename T>
  struct Janitor {
    T* Obj;
    Janitor(T* obj) : Obj(obj) {}
    ~Janitor() { delete Obj; }
  };
} // end anonymous namespace

namespace {
  class SerializationTest : public ASTConsumer {
    IdentifierTable* IdTable;
    unsigned MainFileID;
  public:
    void Initialize(ASTContext& Context, unsigned mainFileID) {
      IdTable = &Context.Idents;
      MainFileID = mainFileID;
    }
    
    ~SerializationTest() {
      RunSerializationTest();
    }
    
    void RunSerializationTest();
    bool WriteTable(llvm::sys::Path& Filename, IdentifierTable* T);
    IdentifierTable* ReadTable(llvm::sys::Path& Filename);
    
    virtual void HandleTopLevelDecl(Decl *D) {}
  };
} // end anonymous namespace

ASTConsumer* clang::CreateSerializationTest() {
  return new SerializationTest();
}

void SerializationTest::RunSerializationTest() { 
  std::string ErrMsg;
  llvm::sys::Path Filename = llvm::sys::Path::GetTemporaryDirectory(&ErrMsg);
  
  if (Filename.isEmpty()) {
    llvm::cerr << "Error: " << ErrMsg << "\n";
    return;
  }
  
  Filename.appendComponent("test.ast");
  
  if (Filename.makeUnique(true,&ErrMsg)) {
    llvm::cerr << "Error: " << ErrMsg << "\n";
    return;
  }
  
  llvm::cerr << "Writing out Identifier table\n";
  WriteTable(Filename,IdTable);
  llvm::cerr << "Reading in Identifier Table\n";
  IdentifierTable* T = ReadTable(Filename);
  Janitor<IdentifierTable> roger(T);
  
  Filename.appendSuffix("2");
  llvm::cerr << "Writing out Identifier table (2)\n";
  WriteTable(Filename,T);
  llvm::cerr << "Reading in Identifier Table (2)\n";
  Janitor<IdentifierTable> wilco(ReadTable(Filename));
}

bool SerializationTest::WriteTable(llvm::sys::Path& Filename,
                                   IdentifierTable* T) {
  if (!T)
    return false;
  
  std::vector<unsigned char> Buffer;
  Buffer.reserve(256*1024);
  
  llvm::BitstreamWriter Stream(Buffer);
  
  Stream.Emit((unsigned)'B', 8);
  Stream.Emit((unsigned)'C', 8);
  Stream.Emit(0xC, 4);
  Stream.Emit(0xF, 4);
  Stream.Emit(0xE, 4);
  Stream.Emit(0x0, 4);

  llvm::Serializer S(Stream);
  S.Emit(*T);
  S.Flush();
  
  if (FILE *fp = fopen(Filename.c_str(),"wb")) {
    fwrite((char*)&Buffer.front(), sizeof(char), Buffer.size(), fp);
    fclose(fp);
  }
  else { 
    llvm::cerr << "Error: Cannot open " << Filename.c_str() << "\n";
    return false;
  }
  
  llvm::cerr << "Wrote file: " << Filename.c_str() << "\n";
  return true;
}


IdentifierTable* SerializationTest::ReadTable(llvm::sys::Path& Filename) {
  llvm::MemoryBuffer* Buffer = 
    llvm::MemoryBuffer::getFile(Filename.c_str(), strlen(Filename.c_str()));
  
  if(!Buffer) {
    llvm::cerr << "Error reading file\n";
    return NULL;
  }
  
  Janitor<llvm::MemoryBuffer> AutoReleaseBuffer(Buffer);
  
  if (Buffer->getBufferSize() & 0x3) {
    llvm::cerr << "AST file should be a multiple of 4 bytes in length\n";
    return NULL;
  }
  
  unsigned char *BufPtr = (unsigned char *)Buffer->getBufferStart();
  llvm::BitstreamReader Stream(BufPtr,BufPtr+Buffer->getBufferSize());
  
  // Sniff for the signature.
  if (Stream.Read(8) != 'B' ||
      Stream.Read(8) != 'C' ||
      Stream.Read(4) != 0xC ||
      Stream.Read(4) != 0xF ||
      Stream.Read(4) != 0xE ||
      Stream.Read(4) != 0x0) {
    llvm::cerr << "Invalid AST-bitcode signature\n";
    return NULL;
  }
  
  llvm::Deserializer D(Stream);

  llvm::cerr << "Materializing identifier table.\n";
  return D.Materialize<IdentifierTable>();
}