Line data Source code
1 : //===- OcamlGCPrinter.cpp - Ocaml frametable emitter ----------------------===//
2 : //
3 : // The LLVM Compiler Infrastructure
4 : //
5 : // This file is distributed under the University of Illinois Open Source
6 : // License. See LICENSE.TXT for details.
7 : //
8 : //===----------------------------------------------------------------------===//
9 : //
10 : // This file implements printing the assembly code for an Ocaml frametable.
11 : //
12 : //===----------------------------------------------------------------------===//
13 :
14 : #include "llvm/ADT/STLExtras.h"
15 : #include "llvm/ADT/SmallString.h"
16 : #include "llvm/ADT/Twine.h"
17 : #include "llvm/CodeGen/AsmPrinter.h"
18 : #include "llvm/CodeGen/GCMetadata.h"
19 : #include "llvm/CodeGen/GCMetadataPrinter.h"
20 : #include "llvm/CodeGen/GCs.h"
21 : #include "llvm/IR/DataLayout.h"
22 : #include "llvm/IR/Function.h"
23 : #include "llvm/IR/Mangler.h"
24 : #include "llvm/IR/Module.h"
25 : #include "llvm/MC/MCContext.h"
26 : #include "llvm/MC/MCDirectives.h"
27 : #include "llvm/MC/MCStreamer.h"
28 : #include "llvm/Support/ErrorHandling.h"
29 : #include "llvm/Target/TargetLoweringObjectFile.h"
30 : #include <cctype>
31 : #include <cstddef>
32 : #include <cstdint>
33 : #include <string>
34 :
35 : using namespace llvm;
36 :
37 : namespace {
38 :
39 3 : class OcamlGCMetadataPrinter : public GCMetadataPrinter {
40 : public:
41 : void beginAssembly(Module &M, GCModuleInfo &Info, AsmPrinter &AP) override;
42 : void finishAssembly(Module &M, GCModuleInfo &Info, AsmPrinter &AP) override;
43 : };
44 :
45 : } // end anonymous namespace
46 :
47 : static GCMetadataPrinterRegistry::Add<OcamlGCMetadataPrinter>
48 : Y("ocaml", "ocaml 3.10-compatible collector");
49 :
50 0 : void llvm::linkOcamlGCPrinter() {}
51 :
52 15 : static void EmitCamlGlobal(const Module &M, AsmPrinter &AP, const char *Id) {
53 : const std::string &MId = M.getModuleIdentifier();
54 :
55 : std::string SymName;
56 : SymName += "caml";
57 15 : size_t Letter = SymName.size();
58 30 : SymName.append(MId.begin(), llvm::find(MId, '.'));
59 : SymName += "__";
60 : SymName += Id;
61 :
62 : // Capitalize the first letter of the module name.
63 15 : SymName[Letter] = toupper(SymName[Letter]);
64 :
65 : SmallString<128> TmpStr;
66 15 : Mangler::getNameWithPrefix(TmpStr, SymName, M.getDataLayout());
67 :
68 30 : MCSymbol *Sym = AP.OutContext.getOrCreateSymbol(TmpStr);
69 :
70 15 : AP.OutStreamer->EmitSymbolAttribute(Sym, MCSA_Global);
71 15 : AP.OutStreamer->EmitLabel(Sym);
72 15 : }
73 :
74 3 : void OcamlGCMetadataPrinter::beginAssembly(Module &M, GCModuleInfo &Info,
75 : AsmPrinter &AP) {
76 3 : AP.OutStreamer->SwitchSection(AP.getObjFileLowering().getTextSection());
77 3 : EmitCamlGlobal(M, AP, "code_begin");
78 :
79 3 : AP.OutStreamer->SwitchSection(AP.getObjFileLowering().getDataSection());
80 3 : EmitCamlGlobal(M, AP, "data_begin");
81 3 : }
82 :
83 : /// emitAssembly - Print the frametable. The ocaml frametable format is thus:
84 : ///
85 : /// extern "C" struct align(sizeof(intptr_t)) {
86 : /// uint16_t NumDescriptors;
87 : /// struct align(sizeof(intptr_t)) {
88 : /// void *ReturnAddress;
89 : /// uint16_t FrameSize;
90 : /// uint16_t NumLiveOffsets;
91 : /// uint16_t LiveOffsets[NumLiveOffsets];
92 : /// } Descriptors[NumDescriptors];
93 : /// } caml${module}__frametable;
94 : ///
95 : /// Note that this precludes programs from stack frames larger than 64K
96 : /// (FrameSize and LiveOffsets would overflow). FrameTablePrinter will abort if
97 : /// either condition is detected in a function which uses the GC.
98 : ///
99 3 : void OcamlGCMetadataPrinter::finishAssembly(Module &M, GCModuleInfo &Info,
100 : AsmPrinter &AP) {
101 3 : unsigned IntPtrSize = M.getDataLayout().getPointerSize();
102 :
103 3 : AP.OutStreamer->SwitchSection(AP.getObjFileLowering().getTextSection());
104 3 : EmitCamlGlobal(M, AP, "code_end");
105 :
106 3 : AP.OutStreamer->SwitchSection(AP.getObjFileLowering().getDataSection());
107 3 : EmitCamlGlobal(M, AP, "data_end");
108 :
109 : // FIXME: Why does ocaml emit this??
110 3 : AP.OutStreamer->EmitIntValue(0, IntPtrSize);
111 :
112 3 : AP.OutStreamer->SwitchSection(AP.getObjFileLowering().getDataSection());
113 3 : EmitCamlGlobal(M, AP, "frametable");
114 :
115 : int NumDescriptors = 0;
116 : for (GCModuleInfo::FuncInfoVec::iterator I = Info.funcinfo_begin(),
117 : IE = Info.funcinfo_end();
118 6 : I != IE; ++I) {
119 : GCFunctionInfo &FI = **I;
120 9 : if (FI.getStrategy().getName() != getStrategy().getName())
121 : // this function is managed by some other GC
122 : continue;
123 4 : for (GCFunctionInfo::iterator J = FI.begin(), JE = FI.end(); J != JE; ++J) {
124 1 : NumDescriptors++;
125 : }
126 : }
127 :
128 3 : if (NumDescriptors >= 1 << 16) {
129 : // Very rude!
130 0 : report_fatal_error(" Too much descriptor for ocaml GC");
131 : }
132 3 : AP.emitInt16(NumDescriptors);
133 6 : AP.EmitAlignment(IntPtrSize == 4 ? 2 : 3);
134 :
135 : for (GCModuleInfo::FuncInfoVec::iterator I = Info.funcinfo_begin(),
136 : IE = Info.funcinfo_end();
137 6 : I != IE; ++I) {
138 : GCFunctionInfo &FI = **I;
139 9 : if (FI.getStrategy().getName() != getStrategy().getName())
140 : // this function is managed by some other GC
141 0 : continue;
142 :
143 3 : uint64_t FrameSize = FI.getFrameSize();
144 3 : if (FrameSize >= 1 << 16) {
145 : // Very rude!
146 0 : report_fatal_error("Function '" + FI.getFunction().getName() +
147 : "' is too large for the ocaml GC! "
148 : "Frame size " +
149 : Twine(FrameSize) + ">= 65536.\n"
150 : "(" +
151 0 : Twine(uintptr_t(&FI)) + ")");
152 : }
153 :
154 3 : AP.OutStreamer->AddComment("live roots for " +
155 6 : Twine(FI.getFunction().getName()));
156 3 : AP.OutStreamer->AddBlankLine();
157 :
158 4 : for (GCFunctionInfo::iterator J = FI.begin(), JE = FI.end(); J != JE; ++J) {
159 1 : size_t LiveCount = FI.live_size(J);
160 1 : if (LiveCount >= 1 << 16) {
161 : // Very rude!
162 0 : report_fatal_error("Function '" + FI.getFunction().getName() +
163 : "' is too large for the ocaml GC! "
164 : "Live root count " +
165 : Twine(LiveCount) + " >= 65536.");
166 : }
167 :
168 1 : AP.OutStreamer->EmitSymbolValue(J->Label, IntPtrSize);
169 1 : AP.emitInt16(FrameSize);
170 1 : AP.emitInt16(LiveCount);
171 :
172 : for (GCFunctionInfo::live_iterator K = FI.live_begin(J),
173 : KE = FI.live_end(J);
174 1 : K != KE; ++K) {
175 0 : if (K->StackOffset >= 1 << 16) {
176 : // Very rude!
177 0 : report_fatal_error(
178 : "GC root stack offset is outside of fixed stack frame and out "
179 : "of range for ocaml GC!");
180 : }
181 0 : AP.emitInt16(K->StackOffset);
182 : }
183 :
184 1 : AP.EmitAlignment(IntPtrSize == 4 ? 2 : 3);
185 : }
186 : }
187 3 : }
|