/// emitAssembly - Print the frametable. The ocaml frametable format is thus: /// /// extern "C" struct align(sizeof(intptr_t)) { /// uint16_t NumDescriptors; /// struct align(sizeof(intptr_t)) { /// void *ReturnAddress; /// uint16_t FrameSize; /// uint16_t NumLiveOffsets; /// uint16_t LiveOffsets[NumLiveOffsets]; /// } Descriptors[NumDescriptors]; /// } caml${module}__frametable; /// /// Note that this precludes programs from stack frames larger than 64K /// (FrameSize and LiveOffsets would overflow). FrameTablePrinter will abort if /// either condition is detected in a function which uses the GC. /// void OcamlGCMetadataPrinter::finishAssembly(AsmPrinter &AP) { unsigned IntPtrSize = AP.TM.getTargetData()->getPointerSize(); AP.OutStreamer.SwitchSection(AP.getObjFileLowering().getTextSection()); EmitCamlGlobal(getModule(), AP, "code_end"); AP.OutStreamer.SwitchSection(AP.getObjFileLowering().getDataSection()); EmitCamlGlobal(getModule(), AP, "data_end"); // FIXME: Why does ocaml emit this?? AP.OutStreamer.EmitIntValue(0, IntPtrSize, 0); AP.OutStreamer.SwitchSection(AP.getObjFileLowering().getDataSection()); EmitCamlGlobal(getModule(), AP, "frametable"); for (iterator I = begin(), IE = end(); I != IE; ++I) { GCFunctionInfo &FI = **I; uint64_t FrameSize = FI.getFrameSize(); if (FrameSize >= 1<<16) { // Very rude! report_fatal_error("Function '" + FI.getFunction().getName() + "' is too large for the ocaml GC! " "Frame size " + Twine(FrameSize) + ">= 65536.\n" "(" + Twine(uintptr_t(&FI)) + ")"); } AP.OutStreamer.AddComment("live roots for " + Twine(FI.getFunction().getName())); AP.OutStreamer.AddBlankLine(); for (GCFunctionInfo::iterator J = FI.begin(), JE = FI.end(); J != JE; ++J) { size_t LiveCount = FI.live_size(J); if (LiveCount >= 1<<16) { // Very rude! report_fatal_error("Function '" + FI.getFunction().getName() + "' is too large for the ocaml GC! " "Live root count "+Twine(LiveCount)+" >= 65536."); } AP.OutStreamer.EmitSymbolValue(J->Label, IntPtrSize, 0); AP.EmitInt16(FrameSize); AP.EmitInt16(LiveCount); for (GCFunctionInfo::live_iterator K = FI.live_begin(J), KE = FI.live_end(J); K != KE; ++K) { assert(K->StackOffset < 1<<16 && "GC root stack offset is outside of fixed stack frame and out " "of range for ocaml GC!"); AP.EmitInt32(K->StackOffset); } AP.EmitAlignment(IntPtrSize == 4 ? 2 : 3); } } }
void ErlangGCPrinter::finishAssembly(Module &M, GCModuleInfo &Info, AsmPrinter &AP) { MCStreamer &OS = *AP.OutStreamer; unsigned IntPtrSize = M.getDataLayout().getPointerSize(); // Put this in a custom .note section. OS.SwitchSection( AP.getObjFileLowering().getContext().getELFSection(".note.gc", ELF::SHT_PROGBITS, 0)); // For each function... for (GCModuleInfo::FuncInfoVec::iterator FI = Info.funcinfo_begin(), IE = Info.funcinfo_end(); FI != IE; ++FI) { GCFunctionInfo &MD = **FI; if (MD.getStrategy().getName() != getStrategy().getName()) // this function is managed by some other GC continue; /** A compact GC layout. Emit this data structure: * * struct { * int16_t PointCount; * void *SafePointAddress[PointCount]; * int16_t StackFrameSize; (in words) * int16_t StackArity; * int16_t LiveCount; * int16_t LiveOffsets[LiveCount]; * } __gcmap_<FUNCTIONNAME>; **/ // Align to address width. AP.EmitAlignment(IntPtrSize == 4 ? 2 : 3); // Emit PointCount. OS.AddComment("safe point count"); AP.EmitInt16(MD.size()); // And each safe point... for (GCFunctionInfo::iterator PI = MD.begin(), PE = MD.end(); PI != PE; ++PI) { // Emit the address of the safe point. OS.AddComment("safe point address"); MCSymbol *Label = PI->Label; AP.EmitLabelPlusOffset(Label /*Hi*/, 0 /*Offset*/, 4 /*Size*/); } // Stack information never change in safe points! Only print info from the // first call-site. GCFunctionInfo::iterator PI = MD.begin(); // Emit the stack frame size. OS.AddComment("stack frame size (in words)"); AP.EmitInt16(MD.getFrameSize() / IntPtrSize); // Emit stack arity, i.e. the number of stacked arguments. unsigned RegisteredArgs = IntPtrSize == 4 ? 5 : 6; unsigned StackArity = MD.getFunction().arg_size() > RegisteredArgs ? MD.getFunction().arg_size() - RegisteredArgs : 0; OS.AddComment("stack arity"); AP.EmitInt16(StackArity); // Emit the number of live roots in the function. OS.AddComment("live root count"); AP.EmitInt16(MD.live_size(PI)); // And for each live root... for (GCFunctionInfo::live_iterator LI = MD.live_begin(PI), LE = MD.live_end(PI); LI != LE; ++LI) { // Emit live root's offset within the stack frame. OS.AddComment("stack index (offset / wordsize)"); AP.EmitInt16(LI->StackOffset / IntPtrSize); } } }
/// emitAssembly - Print the frametable. The ocaml frametable format is thus: /// /// extern "C" struct align(sizeof(intptr_t)) { /// uint16_t NumDescriptors; /// struct align(sizeof(intptr_t)) { /// void *ReturnAddress; /// uint16_t FrameSize; /// uint16_t NumLiveOffsets; /// uint16_t LiveOffsets[NumLiveOffsets]; /// } Descriptors[NumDescriptors]; /// } caml${module}__frametable; /// /// Note that this precludes programs from stack frames larger than 64K /// (FrameSize and LiveOffsets would overflow). FrameTablePrinter will abort if /// either condition is detected in a function which uses the GC. /// void OcamlGCMetadataPrinter::finishAssembly(AsmPrinter &AP) { unsigned IntPtrSize = AP.TM.getTargetData()->getPointerSize(); AP.OutStreamer.SwitchSection(AP.getObjFileLowering().getTextSection()); EmitCamlGlobal(getModule(), AP, "code_end"); AP.OutStreamer.SwitchSection(AP.getObjFileLowering().getDataSection()); EmitCamlGlobal(getModule(), AP, "data_end"); // FIXME: Why does ocaml emit this?? AP.OutStreamer.EmitIntValue(0, IntPtrSize, 0); AP.OutStreamer.SwitchSection(AP.getObjFileLowering().getDataSection()); EmitCamlGlobal(getModule(), AP, "frametable"); int NumDescriptors = 0; for (iterator I = begin(), IE = end(); I != IE; ++I) { GCFunctionInfo &FI = **I; for (GCFunctionInfo::iterator J = FI.begin(), JE = FI.end(); J != JE; ++J) { NumDescriptors++; } } if (NumDescriptors >= 1<<16) { // Very rude! report_fatal_error(" Too much descriptor for ocaml GC"); } AP.EmitInt16(NumDescriptors); AP.EmitAlignment(IntPtrSize == 4 ? 2 : 3); const MCRegisterInfo &MRI = AP.OutStreamer.getContext().getRegisterInfo(); for (iterator I = begin(), IE = end(); I != IE; ++I) { GCFunctionInfo &FI = **I; uint64_t FrameSize = FI.getFrameSize(); if (FrameSize >= 1<<16) { // Very rude! report_fatal_error("Function '" + FI.getFunction().getName() + "' is too large for the ocaml GC! " "Frame size " + Twine(FrameSize) + ">= 65536.\n" "(" + Twine(uintptr_t(&FI)) + ")"); } AP.OutStreamer.AddComment("live roots for " + Twine(FI.getFunction().getName())); AP.OutStreamer.AddBlankLine(); for (unsigned PI = 0, PE = FI.size(); PI != PE; ++PI) { size_t LiveCount = FI.live_size(PI); if (LiveCount >= 1<<16) { // Very rude! report_fatal_error("Function '" + FI.getFunction().getName() + "' is too large for the ocaml GC! " "Live root count "+Twine(LiveCount)+" >= 65536."); } GCPoint &Point = FI.getPoint(PI); AP.OutStreamer.EmitSymbolValue(Point.Label, IntPtrSize, 0); AP.EmitInt16(FrameSize); AP.EmitInt16(LiveCount); for (GCFunctionInfo::live_iterator K = FI.live_begin(PI), KE = FI.live_end(PI); K != KE; ++K) { if (K->isReg()) { AP.OutStreamer.AddComment("register root at " + Twine(MRI.getName(K->Loc.PhysReg))); AP.OutStreamer.AddBlankLine(); continue; } if (K->Loc.StackOffset >= 1<<16) { // Very rude! report_fatal_error( "GC root stack offset is outside of fixed stack frame and out " "of range for ocaml GC!"); } AP.EmitInt16(K->Loc.StackOffset); } AP.EmitAlignment(IntPtrSize == 4 ? 2 : 3); } } }
/// emitAssembly - Print the frametable. The ocaml frametable format is thus: /// /// extern "C" struct align(sizeof(intptr_t)) { /// uint16_t NumDescriptors; /// struct align(sizeof(intptr_t)) { /// void *ReturnAddress; /// uint16_t FrameSize; /// uint16_t NumLiveOffsets; /// uint16_t LiveOffsets[NumLiveOffsets]; /// } Descriptors[NumDescriptors]; /// } caml${module}__frametable; /// /// Note that this precludes programs from stack frames larger than 64K /// (FrameSize and LiveOffsets would overflow). FrameTablePrinter will abort if /// either condition is detected in a function which uses the GC. /// void OcamlGCMetadataPrinter::finishAssembly(Module &M, GCModuleInfo &Info, AsmPrinter &AP) { unsigned IntPtrSize = M.getDataLayout().getPointerSize(); AP.OutStreamer->SwitchSection(AP.getObjFileLowering().getTextSection()); EmitCamlGlobal(M, AP, "code_end"); AP.OutStreamer->SwitchSection(AP.getObjFileLowering().getDataSection()); EmitCamlGlobal(M, AP, "data_end"); // FIXME: Why does ocaml emit this?? AP.OutStreamer->EmitIntValue(0, IntPtrSize); AP.OutStreamer->SwitchSection(AP.getObjFileLowering().getDataSection()); EmitCamlGlobal(M, AP, "frametable"); int NumDescriptors = 0; for (GCModuleInfo::FuncInfoVec::iterator I = Info.funcinfo_begin(), IE = Info.funcinfo_end(); I != IE; ++I) { GCFunctionInfo &FI = **I; if (FI.getStrategy().getName() != getStrategy().getName()) // this function is managed by some other GC continue; for (GCFunctionInfo::iterator J = FI.begin(), JE = FI.end(); J != JE; ++J) { NumDescriptors++; } } if (NumDescriptors >= 1 << 16) { // Very rude! report_fatal_error(" Too much descriptor for ocaml GC"); } AP.EmitInt16(NumDescriptors); AP.EmitAlignment(IntPtrSize == 4 ? 2 : 3); for (GCModuleInfo::FuncInfoVec::iterator I = Info.funcinfo_begin(), IE = Info.funcinfo_end(); I != IE; ++I) { GCFunctionInfo &FI = **I; if (FI.getStrategy().getName() != getStrategy().getName()) // this function is managed by some other GC continue; uint64_t FrameSize = FI.getFrameSize(); if (FrameSize >= 1 << 16) { // Very rude! report_fatal_error("Function '" + FI.getFunction().getName() + "' is too large for the ocaml GC! " "Frame size " + Twine(FrameSize) + ">= 65536.\n" "(" + Twine(uintptr_t(&FI)) + ")"); } AP.OutStreamer->AddComment("live roots for " + Twine(FI.getFunction().getName())); AP.OutStreamer->AddBlankLine(); for (GCFunctionInfo::iterator J = FI.begin(), JE = FI.end(); J != JE; ++J) { size_t LiveCount = FI.live_size(J); if (LiveCount >= 1 << 16) { // Very rude! report_fatal_error("Function '" + FI.getFunction().getName() + "' is too large for the ocaml GC! " "Live root count " + Twine(LiveCount) + " >= 65536."); } AP.OutStreamer->EmitSymbolValue(J->Label, IntPtrSize); AP.EmitInt16(FrameSize); AP.EmitInt16(LiveCount); for (GCFunctionInfo::live_iterator K = FI.live_begin(J), KE = FI.live_end(J); K != KE; ++K) { if (K->StackOffset >= 1 << 16) { // Very rude! report_fatal_error( "GC root stack offset is outside of fixed stack frame and out " "of range for ocaml GC!"); } AP.EmitInt16(K->StackOffset); } AP.EmitAlignment(IntPtrSize == 4 ? 2 : 3); } } }