aboutsummaryrefslogtreecommitdiff
path: root/lib/CodeGen/FileHandler.cc
diff options
context:
space:
mode:
Diffstat (limited to 'lib/CodeGen/FileHandler.cc')
-rw-r--r--lib/CodeGen/FileHandler.cc51
1 files changed, 19 insertions, 32 deletions
diff --git a/lib/CodeGen/FileHandler.cc b/lib/CodeGen/FileHandler.cc
index 275139a..66a7606 100644
--- a/lib/CodeGen/FileHandler.cc
+++ b/lib/CodeGen/FileHandler.cc
@@ -1,5 +1,6 @@
#include "cps/FileHandler.h"
#include "cps/RuntimeCheck.h"
+#include "cps/ExceptionHandler.h"
#include "llvm/IR/Constants.h"
#include "llvm/IR/DerivedTypes.h"
#include "llvm/IR/Function.h"
@@ -9,8 +10,8 @@ using namespace llvm;
using namespace cps;
FileHandler::FileHandler(LLVMContext &Ctx, IRBuilder<> &B, llvm::Module &M,
- RuntimeCheck &RC)
- : Context(Ctx), Builder(B), Module(M), Checker(RC) {
+ RuntimeCheck &RC, ExceptionHandler &EH)
+ : Context(Ctx), Builder(B), Module(M), Checker(RC), Exceptions(EH) {
// Nothing is declared or emitted here: the whole runtime is synthesized
// lazily by ensureRuntime() so file-free programs keep their IR unchanged.
}
@@ -57,21 +58,6 @@ void FileHandler::setupGlobals() {
ModeReadStr = Builder.CreateGlobalStringPtr("r", "file_mode_r", 0, &Module);
ModeWriteStr = Builder.CreateGlobalStringPtr("w", "file_mode_w", 0, &Module);
ModeAppendStr = Builder.CreateGlobalStringPtr("a", "file_mode_a", 0, &Module);
-
- ErrOpenFail = Builder.CreateGlobalStringPtr(
- "[Fatal] line %d: Cannot open file '%s'\n", "err_file_open", 0, &Module);
- ErrAlreadyOpen = Builder.CreateGlobalStringPtr(
- "[Fatal] line %d: File '%s' is already open\n", "err_file_already_open", 0, &Module);
- ErrTableFull = Builder.CreateGlobalStringPtr(
- "[Fatal] line %d: Too many open files\n", "err_file_table_full", 0, &Module);
- ErrNotOpen = Builder.CreateGlobalStringPtr(
- "[Fatal] line %d: File '%s' is not open\n", "err_file_not_open", 0, &Module);
- ErrNotRead = Builder.CreateGlobalStringPtr(
- "[Fatal] line %d: File '%s' is not open for READ\n", "err_file_not_read", 0, &Module);
- ErrNotWrite = Builder.CreateGlobalStringPtr(
- "[Fatal] line %d: File '%s' is not open for WRITE\n", "err_file_not_write", 0, &Module);
- ErrPastEof = Builder.CreateGlobalStringPtr(
- "[Fatal] line %d: Read past end of file '%s'\n", "err_file_past_eof", 0, &Module);
}
void FileHandler::ensureRuntime() {
@@ -97,6 +83,7 @@ void FileHandler::ensureRuntime() {
Function *FileHandler::createHelper(const char *Name, FunctionType *FT) {
Function *F = Function::Create(FT, Function::InternalLinkage, Name, &Module);
+ Exceptions.prepareFunction(F);
BasicBlock *Entry = BasicBlock::Create(Context, "entry", F);
Builder.SetInsertPoint(Entry);
return F;
@@ -108,11 +95,11 @@ Value *FileHandler::emitSlotGEP(GlobalVariable *Table, Type *ElemTy, Value *Idx)
}
// Shared prologue of every helper that operates on an already-open file:
-// look the name up, die with "not open" on a miss, return the slot index.
+// look the name up, throw on a miss, return the slot index.
Value *FileHandler::emitLookupOrFail(Value *Name, Value *Line) {
Value *Idx = Builder.CreateCall(FindFn, {Name}, "slot");
Value *NotOpen = Builder.CreateICmpSLT(Idx, ConstantInt::get(Context, APInt(64, 0)), "not_open");
- Checker.emitErrorAndExit(NotOpen, ErrNotOpen, {Line, Name});
+ Checker.emitCheck(NotOpen);
return Idx;
}
@@ -184,7 +171,7 @@ void FileHandler::buildOpenFn() {
Value *Existing = Builder.CreateCall(FindFn, {Name}, "existing");
Value *AlreadyOpen = Builder.CreateICmpSGE(Existing, ConstantInt::get(Context, APInt(64, 0)), "already_open");
- Checker.emitErrorAndExit(AlreadyOpen, ErrAlreadyOpen, {Line, Name});
+ Checker.emitCheck(AlreadyOpen);
// First-free-slot scan; SlotVar stays -1 when the table is full.
AllocaInst *IdxVar = Builder.CreateAlloca(I64, nullptr, "idx");
@@ -221,7 +208,7 @@ void FileHandler::buildOpenFn() {
Builder.SetInsertPoint(AfterBB);
Value *Slot = Builder.CreateLoad(I64, SlotVar, "free_slot");
Value *NoFree = Builder.CreateICmpSLT(Slot, ConstantInt::get(Context, APInt(64, 0)), "table_full");
- Checker.emitErrorAndExit(NoFree, ErrTableFull, {Line});
+ Checker.emitCheck(NoFree);
// Branch-free fopen-mode selection: 1 -> "r", 2 -> "w", 3 -> "a".
Value *IsWrite = Builder.CreateICmpEQ(Mode, ConstantInt::get(I8, uint8_t(FileMode::Write)));
@@ -231,7 +218,7 @@ void FileHandler::buildOpenFn() {
Value *Handle = Builder.CreateCall(FopenFunc, {Name, ModeStr}, "handle");
Value *OpenFailed = Builder.CreateICmpEQ(Handle, ConstantPointerNull::get(PtrTy), "open_failed");
- Checker.emitErrorAndExit(OpenFailed, ErrOpenFail, {Line, Name});
+ Checker.emitCheck(OpenFailed);
Builder.CreateStore(Name, emitSlotGEP(FileNames, PtrTy, Slot));
Builder.CreateStore(Handle, emitSlotGEP(FileHandles, PtrTy, Slot));
@@ -241,7 +228,7 @@ void FileHandler::buildOpenFn() {
// ptr __cps_file_read(ptr name, i32 line): read one line into a fresh heap
// STRING ('\n' consumed and stripped, trailing '\r' dropped). Reading at EOF
-// is a fatal error — CIE programs are expected to guard with EOF().
+// throws an exception — CIE programs are expected to guard with EOF().
void FileHandler::buildReadFn() {
PointerType *PtrTy = PointerType::getUnqual(Context);
Type *I64 = Type::getInt64Ty(Context);
@@ -257,13 +244,13 @@ void FileHandler::buildReadFn() {
Value *Idx = emitLookupOrFail(Name, Line);
Value *Mode = Builder.CreateLoad(I8, emitSlotGEP(FileModes, I8, Idx), "mode");
Value *NotRead = Builder.CreateICmpNE(Mode, ConstantInt::get(I8, uint8_t(FileMode::Read)), "not_read");
- Checker.emitErrorAndExit(NotRead, ErrNotRead, {Line, Name});
+ Checker.emitCheck(NotRead);
Value *Handle = Builder.CreateLoad(PtrTy, emitSlotGEP(FileHandles, PtrTy, Idx), "handle");
Value *MinusOne = ConstantInt::get(Context, APInt(32, -1, /*isSigned=*/true));
Value *Peek = Builder.CreateCall(FgetcFunc, {Handle}, "peek");
Value *AtEof = Builder.CreateICmpEQ(Peek, MinusOne, "at_eof");
- Checker.emitErrorAndExit(AtEof, ErrPastEof, {Line, Name});
+ Checker.emitCheck(AtEof);
Builder.CreateCall(UngetcFunc, {Peek, Handle});
// Growing buffer: cap doubles, always leaving room for byte + NUL.
@@ -361,7 +348,7 @@ void FileHandler::buildWriteFn() {
Value *Idx = emitLookupOrFail(Name, Line);
Value *Mode = Builder.CreateLoad(I8, emitSlotGEP(FileModes, I8, Idx), "mode");
Value *IsReadMode = Builder.CreateICmpEQ(Mode, ConstantInt::get(I8, uint8_t(FileMode::Read)), "read_only");
- Checker.emitErrorAndExit(IsReadMode, ErrNotWrite, {Line, Name});
+ Checker.emitCheck(IsReadMode);
Value *Handle = Builder.CreateLoad(PtrTy, emitSlotGEP(FileHandles, PtrTy, Idx), "handle");
Builder.CreateCall(FputsFunc, {Data, Handle});
@@ -407,7 +394,7 @@ void FileHandler::buildEofFn() {
Value *Idx = emitLookupOrFail(Name, Line);
Value *Mode = Builder.CreateLoad(I8, emitSlotGEP(FileModes, I8, Idx), "mode");
Value *NotRead = Builder.CreateICmpNE(Mode, ConstantInt::get(I8, uint8_t(FileMode::Read)), "not_read");
- Checker.emitErrorAndExit(NotRead, ErrNotRead, {Line, Name});
+ Checker.emitCheck(NotRead);
Value *Handle = Builder.CreateLoad(PtrTy, emitSlotGEP(FileHandles, PtrTy, Idx), "handle");
Value *Ch = Builder.CreateCall(FgetcFunc, {Handle}, "c");
@@ -420,7 +407,7 @@ void FileHandler::buildEofFn() {
void FileHandler::emitOpen(Value *NameStr, FileMode Mode, int Line) {
if (!NameStr) return;
ensureRuntime();
- Builder.CreateCall(OpenFn, {NameStr,
+ Exceptions.emitCall(OpenFn, {NameStr,
ConstantInt::get(Type::getInt8Ty(Context), uint8_t(Mode)),
ConstantInt::get(Context, APInt(32, Line))});
}
@@ -428,25 +415,25 @@ void FileHandler::emitOpen(Value *NameStr, FileMode Mode, int Line) {
Value *FileHandler::emitRead(Value *NameStr, int Line) {
if (!NameStr) return nullptr;
ensureRuntime();
- return Builder.CreateCall(ReadFn, {NameStr, ConstantInt::get(Context, APInt(32, Line))},
+ return Exceptions.emitCall(ReadFn, {NameStr, ConstantInt::get(Context, APInt(32, Line))},
"file_line");
}
void FileHandler::emitWrite(Value *NameStr, Value *DataStr, int Line) {
if (!NameStr || !DataStr) return;
ensureRuntime();
- Builder.CreateCall(WriteFn, {NameStr, DataStr, ConstantInt::get(Context, APInt(32, Line))});
+ Exceptions.emitCall(WriteFn, {NameStr, DataStr, ConstantInt::get(Context, APInt(32, Line))});
}
void FileHandler::emitClose(Value *NameStr, int Line) {
if (!NameStr) return;
ensureRuntime();
- Builder.CreateCall(CloseFn, {NameStr, ConstantInt::get(Context, APInt(32, Line))});
+ Exceptions.emitCall(CloseFn, {NameStr, ConstantInt::get(Context, APInt(32, Line))});
}
Value *FileHandler::emitEof(Value *NameStr, int Line) {
if (!NameStr) return nullptr;
ensureRuntime();
- return Builder.CreateCall(EofFn, {NameStr, ConstantInt::get(Context, APInt(32, Line))},
+ return Exceptions.emitCall(EofFn, {NameStr, ConstantInt::get(Context, APInt(32, Line))},
"file_eof");
}