• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //===- ErlangGCPrinter.cpp - Erlang/OTP 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 the compiler plugin that is used in order to emit
11 // garbage collection information in a convenient layout for parsing and
12 // loading in the Erlang/OTP runtime.
13 //
14 //===----------------------------------------------------------------------===//
15 
16 #include "llvm/BinaryFormat/ELF.h"
17 #include "llvm/CodeGen/AsmPrinter.h"
18 #include "llvm/CodeGen/GCMetadata.h"
19 #include "llvm/CodeGen/GCMetadataPrinter.h"
20 #include "llvm/CodeGen/GCStrategy.h"
21 #include "llvm/CodeGen/GCs.h"
22 #include "llvm/IR/DataLayout.h"
23 #include "llvm/IR/Function.h"
24 #include "llvm/IR/Module.h"
25 #include "llvm/MC/MCContext.h"
26 #include "llvm/MC/MCSectionELF.h"
27 #include "llvm/MC/MCStreamer.h"
28 #include "llvm/MC/MCSymbol.h"
29 #include "llvm/Target/TargetLoweringObjectFile.h"
30 
31 using namespace llvm;
32 
33 namespace {
34 
35 class ErlangGCPrinter : public GCMetadataPrinter {
36 public:
37   void finishAssembly(Module &M, GCModuleInfo &Info, AsmPrinter &AP) override;
38 };
39 
40 } // end anonymous namespace
41 
42 static GCMetadataPrinterRegistry::Add<ErlangGCPrinter>
43     X("erlang", "erlang-compatible garbage collector");
44 
finishAssembly(Module & M,GCModuleInfo & Info,AsmPrinter & AP)45 void ErlangGCPrinter::finishAssembly(Module &M, GCModuleInfo &Info,
46                                      AsmPrinter &AP) {
47   MCStreamer &OS = *AP.OutStreamer;
48   unsigned IntPtrSize = M.getDataLayout().getPointerSize();
49 
50   // Put this in a custom .note section.
51   OS.SwitchSection(
52       AP.getObjFileLowering().getContext().getELFSection(".note.gc",
53                                                          ELF::SHT_PROGBITS, 0));
54 
55   // For each function...
56   for (GCModuleInfo::FuncInfoVec::iterator FI = Info.funcinfo_begin(),
57                                            IE = Info.funcinfo_end();
58        FI != IE; ++FI) {
59     GCFunctionInfo &MD = **FI;
60     if (MD.getStrategy().getName() != getStrategy().getName())
61       // this function is managed by some other GC
62       continue;
63     /** A compact GC layout. Emit this data structure:
64      *
65      * struct {
66      *   int16_t PointCount;
67      *   void *SafePointAddress[PointCount];
68      *   int16_t StackFrameSize; (in words)
69      *   int16_t StackArity;
70      *   int16_t LiveCount;
71      *   int16_t LiveOffsets[LiveCount];
72      * } __gcmap_<FUNCTIONNAME>;
73      **/
74 
75     // Align to address width.
76     AP.EmitAlignment(IntPtrSize == 4 ? 2 : 3);
77 
78     // Emit PointCount.
79     OS.AddComment("safe point count");
80     AP.emitInt16(MD.size());
81 
82     // And each safe point...
83     for (GCFunctionInfo::iterator PI = MD.begin(), PE = MD.end(); PI != PE;
84          ++PI) {
85       // Emit the address of the safe point.
86       OS.AddComment("safe point address");
87       MCSymbol *Label = PI->Label;
88       AP.EmitLabelPlusOffset(Label /*Hi*/, 0 /*Offset*/, 4 /*Size*/);
89     }
90 
91     // Stack information never change in safe points! Only print info from the
92     // first call-site.
93     GCFunctionInfo::iterator PI = MD.begin();
94 
95     // Emit the stack frame size.
96     OS.AddComment("stack frame size (in words)");
97     AP.emitInt16(MD.getFrameSize() / IntPtrSize);
98 
99     // Emit stack arity, i.e. the number of stacked arguments.
100     unsigned RegisteredArgs = IntPtrSize == 4 ? 5 : 6;
101     unsigned StackArity = MD.getFunction().arg_size() > RegisteredArgs
102                               ? MD.getFunction().arg_size() - RegisteredArgs
103                               : 0;
104     OS.AddComment("stack arity");
105     AP.emitInt16(StackArity);
106 
107     // Emit the number of live roots in the function.
108     OS.AddComment("live root count");
109     AP.emitInt16(MD.live_size(PI));
110 
111     // And for each live root...
112     for (GCFunctionInfo::live_iterator LI = MD.live_begin(PI),
113                                        LE = MD.live_end(PI);
114          LI != LE; ++LI) {
115       // Emit live root's offset within the stack frame.
116       OS.AddComment("stack index (offset / wordsize)");
117       AP.emitInt16(LI->StackOffset / IntPtrSize);
118     }
119   }
120 }
121 
linkErlangGCPrinter()122 void llvm::linkErlangGCPrinter() {}
123