Skip to content

Commit

Permalink
Add the pony_try function to receive Pony errors in C code
Browse files Browse the repository at this point in the history
This function is implemented in LLVM IR since it cannot be implemented
in C.

This change also exposes the `pony_error` function (renamed from
`pony_throw`) in the public runtime interface in order to allow C
programs to both raise and receive Pony errors.
  • Loading branch information
Benoit Vey committed Dec 28, 2017
1 parent 5bd1422 commit 7a5f753
Show file tree
Hide file tree
Showing 18 changed files with 141 additions and 82 deletions.
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -30,3 +30,6 @@ output/
_ReSharper.*
.vscode/
src/common/dtrace_probes.h

# Allow these paths
!src/libponyrt/lang/except_try_catch.ll
81 changes: 41 additions & 40 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,7 @@ ALL_CFLAGS = -std=gnu11 -fexceptions \
-DPONY_VERSION_STR=\"$(version_str)\" \
-D_FILE_OFFSET_BITS=64
ALL_CXXFLAGS = -std=gnu++11 -fno-rtti
LL_FLAGS = -mcpu=$(arch)

# Determine pointer size in bits.
BITS := $(bits)
Expand Down Expand Up @@ -178,6 +179,7 @@ endif

ifeq ($(config),release)
BUILD_FLAGS += -O3 -DNDEBUG
LL_FLAGS += -O3

ifeq ($(lto),yes)
BUILD_FLAGS += -flto -DPONY_USE_LTO
Expand All @@ -201,73 +203,55 @@ ifeq ($(OSTYPE),osx)
endif

ifndef LLVM_CONFIG
ifneq (,$(shell which /usr/local/opt/llvm/bin/llvm-config 2> /dev/null))
ifneq (,$(shell which /usr/local/opt/llvm/bin/llvm-config 2> /dev/null))
LLVM_CONFIG = /usr/local/opt/llvm/bin/llvm-config
LLVM_LINK = /usr/local/opt/llvm/bin/llvm-link
LLVM_OPT = /usr/local/opt/llvm/bin/opt
else ifneq (,$(shell which llvm-config-3.9 2> /dev/null))
LLVM_CONFIG = llvm-config-3.9
LLVM_LINK = llvm-link-3.9
LLVM_OPT = opt-3.9
else ifneq (,$(shell which /usr/local/opt/[email protected]/bin/llvm-config 2> /dev/null))
LLVM_CONFIG = /usr/local/opt/[email protected]/bin/llvm-config
LLVM_LINK = /usr/local/opt/[email protected]/bin/llvm-link
LLVM_OPT = /usr/local/opt/[email protected]/bin/opt
else ifneq (,$(shell which llvm-config-3.8 2> /dev/null))
LLVM_CONFIG = llvm-config-3.8
LLVM_LINK = llvm-link-3.8
LLVM_OPT = opt-3.8
else ifneq (,$(shell which llvm-config-mp-3.8 2> /dev/null))
LLVM_CONFIG = llvm-config-mp-3.8
LLVM_LINK = llvm-link-mp-3.8
LLVM_OPT = opt-mp-3.8
else ifneq (,$(shell which llvm-config-3.7 2> /dev/null))
LLVM_CONFIG = llvm-config-3.7
LLVM_LINK = llvm-link-3.7
LLVM_OPT = opt-3.7
else ifneq (,$(shell which llvm-config-3.6 2> /dev/null))
LLVM_CONFIG = llvm-config-3.6
LLVM_LINK = llvm-link-3.6
LLVM_OPT = opt-3.6
else ifneq (,$(shell which llvm-config39 2> /dev/null))
LLVM_CONFIG = llvm-config39
LLVM_LINK = llvm-link39
LLVM_OPT = opt39
else ifneq (,$(shell which llvm-config38 2> /dev/null))
LLVM_CONFIG = llvm-config38
LLVM_LINK = llvm-link38
LLVM_OPT = opt38
else ifneq (,$(shell which llvm-config37 2> /dev/null))
LLVM_CONFIG = llvm-config37
LLVM_LINK = llvm-link37
LLVM_OPT = opt37
else ifneq (,$(shell which /usr/local/opt/llvm/bin/llvm-config 2> /dev/null))
LLVM_CONFIG = /usr/local/opt/llvm/bin/llvm-config
LLVM_LINK = /usr/local/opt/llvm/bin/llvm-link
LLVM_OPT = /usr/local/opt/llvm/bin/opt
else ifneq (,$(shell which llvm-config 2> /dev/null))
LLVM_CONFIG = llvm-config
LLVM_LINK = llvm-link
LLVM_OPT = opt
else ifneq (,$(shell which llvm-config-5.0 2> /dev/null))
LLVM_CONFIG = llvm-config-5.0
LLVM_LINK = llvm-link-5.0
LLVM_OPT = opt-5.0
else ifneq (,$(shell which llvm-config-4.0 2> /dev/null))
LLVM_CONFIG = llvm-config-4.0
LLVM_LINK = llvm-link-4.0
LLVM_OPT = opt-4.0
else ifneq (,$(shell which /usr/local/opt/[email protected]/bin/llvm-config 2> /dev/null))
else ifneq (,$(shell which /usr/local/opt/[email protected]/bin/llvm-config 2> /dev/null))
LLVM_CONFIG = /usr/local/opt/[email protected]/bin/llvm-config
LLVM_LINK = /usr/local/opt/[email protected]/bin/llvm-link
LLVM_OPT = /usr/local/opt/[email protected]/bin/opt
else
$(error No LLVM installation found!)
endif
endif

ifndef LLVM_CONFIG
LLVM_CONFIG_ABS := $(shell which $(LLVM_CONFIG) 2> /dev/null)

ifeq (,$(LLVM_CONFIG_ABS))
$(error No LLVM installation found!)
endif

LLVM_PREFIX := $(dir $(LLVM_CONFIG_ABS))
LLVM_SUFFIX := $(subst llvm-config,,$(notdir $(LLVM_CONFIG_ABS)))

LLVM_LINK := $(LLVM_PREFIX)llvm-link$(LLVM_SUFFIX)
LLVM_OPT := $(LLVM_PREFIX)opt$(LLVM_SUFFIX)
LLVM_LLC := $(LLVM_PREFIX)llc$(LLVM_SUFFIX)
LLVM_AS := $(LLVM_PREFIX)llvm-as$(LLVM_SUFFIX)

llvm_version := $(shell $(LLVM_CONFIG) --version)

ifeq (,$(LLVM_LINK_STATIC))
Expand Down Expand Up @@ -512,11 +496,13 @@ endif

ifeq ($(OSTYPE), linux)
libponyrt-pic.buildoptions += -fpic
libponyrt-pic.buildoptions-ll += -relocation-model=pic
endif

# default enable PIC compiling if requested
ifdef default_pic
libponyrt.buildoptions += -fpic
libponyrt.buildoptions-ll += -relocation-model=pic
BUILD_FLAGS += -DPONY_DEFAULT_PIC=true
endif

Expand Down Expand Up @@ -615,7 +601,7 @@ define ENUMERATE
sourcefiles := $$($(1).files)
else
sourcefiles := $$(shell find $$(sourcedir) -type f -name "*.c" -or -name\
"*.cc" | grep -v '.*/\.')
"*.cc" -or -name "*.ll" | grep -v '.*/\.')
endif

ifdef $(1).except
Expand All @@ -633,11 +619,16 @@ define CONFIGURE_COMPILER
compiler := $(CC)
flags := $(ALL_CFLAGS) $(CFLAGS)
endif

ifeq ($(suffix $(1)),.bc)
compiler := $(CC)
flags := $(ALL_CFLAGS) $(CFLAGS)
endif

ifeq ($(suffix $(1)),.ll)
compiler := $(CC)
flags := $(ALL_CFLAGS) $(CFLAGS) -Wno-override-module
endif
endef

define CONFIGURE_LIBS
Expand Down Expand Up @@ -693,8 +684,8 @@ define PREPARE
$(eval objectfiles := $(subst $(sourcedir)/,$(outdir)/,$(addsuffix .o,\
$(sourcefiles))))
$(eval bitcodefiles := $(subst .o,.bc,$(objectfiles)))
$(eval dependencies := $(subst .c,,$(subst .cc,,$(subst .o,.d,\
$(objectfiles)))))
$(eval dependencies := $(subst .c,,$(subst .cc,,$(subst .ll,,$(subst .o,.d,\
$(objectfiles))))))
endef

define EXPAND_OBJCMD
Expand All @@ -703,17 +694,27 @@ $(eval $(call CONFIGURE_COMPILER,$(file)))

ifeq ($(3),libponyrtyes)
ifneq ($(suffix $(file)),.bc)
$(subst .c,,$(subst .cc,,$(1))): $(subst .c,.bc,$(subst .cc,.bc,$(file)))
$(subst .c,,$(subst .cc,,$(subst .ll,,$(1)))): $(subst .c,.bc,$(subst .cc,.bc,$(subst .ll,.bc,$(file))))
@echo '$$(notdir $$<)'
@mkdir -p $$(dir $$@)
$(SILENT)$(compiler) $(flags) -c -o $$@ $$<
else ifeq ($(suffix $(subst .bc,,$(file))),.ll)
$(subst .ll,,$(1)): $(subst $(outdir)/,$(sourcedir)/,$(subst .bc,,$(file)))
@echo '$$(notdir $$<)'
@mkdir -p $$(dir $$@)
$(SILENT)$(LLVM_AS) -o $$@ $$<
else
$(subst .c,,$(subst .cc,,$(1))): $(subst $(outdir)/,$(sourcedir)/,$(subst .bc,,$(file)))
@echo '$$(notdir $$<)'
@mkdir -p $$(dir $$@)
$(SILENT)$(compiler) -MMD -MP $(filter-out $($(2).disable),$(BUILD_FLAGS)) \
$(flags) $($(2).buildoptions) -emit-llvm -c -o $$@ $$< $($(2).include)
endif
else ifeq ($(suffix $(file)),.ll)
$(subst .ll,,$(1)): $(subst $(outdir)/,$(sourcedir)/,$(file))
@echo '$$(notdir $$<)'
@mkdir -p $$(dir $$@)
$(SILENT)$(LLVM_LLC) $(LL_FLAGS) $($(2).buildoptions-ll) -filetype=obj -o $$@ $$<
else
$(subst .c,,$(subst .cc,,$(1))): $(subst $(outdir)/,$(sourcedir)/,$(file))
@echo '$$(notdir $$<)'
Expand All @@ -725,8 +726,8 @@ endef

define EXPAND_COMMAND
$(eval $(call PREPARE,$(1)))
$(eval ofiles := $(subst .c,,$(subst .cc,,$(objectfiles))))
$(eval bcfiles := $(subst .c,,$(subst .cc,,$(bitcodefiles))))
$(eval ofiles := $(subst .c,,$(subst .cc,,$(subst .ll,,$(objectfiles)))))
$(eval bcfiles := $(subst .c,,$(subst .cc,,$(subst .ll,,$(bitcodefiles)))))
$(eval depends := )
$(foreach d,$($(1).depends),$(eval depends += $($(d))/$(d).$(LIB_EXT)))

Expand Down
4 changes: 2 additions & 2 deletions src/libponyc/codegen/codegen.c
Original file line number Diff line number Diff line change
Expand Up @@ -786,9 +786,9 @@ static void init_runtime(compile_t* c)
LLVMAddFunctionAttr(value, LLVMReadOnlyAttribute);
#endif

// void pony_throw()
// void pony_error()
type = LLVMFunctionType(c->void_type, NULL, 0, false);
value = LLVMAddFunction(c->module, "pony_throw", type);
value = LLVMAddFunction(c->module, "pony_error", type);
#if PONY_LLVM >= 309
LLVMAddAttributeAtIndex(value, LLVMAttributeFunctionIndex, noreturn_attr);
#else
Expand Down
4 changes: 2 additions & 2 deletions src/libponyc/codegen/gencall.c
Original file line number Diff line number Diff line change
Expand Up @@ -1359,9 +1359,9 @@ LLVMValueRef gencall_allocstruct(compile_t* c, reach_type_t* t)
return result;
}

void gencall_throw(compile_t* c)
void gencall_error(compile_t* c)
{
LLVMValueRef func = LLVMGetNamedFunction(c->module, "pony_throw");
LLVMValueRef func = LLVMGetNamedFunction(c->module, "pony_error");

if(c->frame->invoke_target != NULL)
invoke_fun(c, func, NULL, 0, "", false);
Expand Down
2 changes: 1 addition & 1 deletion src/libponyc/codegen/gencall.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ LLVMValueRef gencall_alloc(compile_t* c, reach_type_t* t);

LLVMValueRef gencall_allocstruct(compile_t* c, reach_type_t* t);

void gencall_throw(compile_t* c);
void gencall_error(compile_t* c);

void gencall_memcpy(compile_t* c, LLVMValueRef dst, LLVMValueRef src,
LLVMValueRef n);
Expand Down
2 changes: 1 addition & 1 deletion src/libponyc/codegen/gencontrol.c
Original file line number Diff line number Diff line change
Expand Up @@ -629,7 +629,7 @@ LLVMValueRef gen_error(compile_t* c, ast_t* ast)

codegen_scope_lifetime_end(c);
codegen_debugloc(c, ast);
gencall_throw(c);
gencall_error(c);
codegen_debugloc(c, NULL);

return GEN_NOVALUE;
Expand Down
2 changes: 1 addition & 1 deletion src/libponyc/codegen/genprim.c
Original file line number Diff line number Diff line change
Expand Up @@ -581,7 +581,7 @@ static void maybe_apply(compile_t* c, void* data, token_id cap)
LLVMBuildRet(c->builder, result);

LLVMPositionBuilderAtEnd(c->builder, is_true);
gencall_throw(c);
gencall_error(c);

codegen_finishfun(c);
}
Expand Down
1 change: 0 additions & 1 deletion src/libponyrt/gc/serialise.c
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@

#include "serialise.h"
#include "../sched/scheduler.h"
#include "../lang/lang.h"
#include "ponyassert.h"
#include <string.h>

Expand Down
1 change: 0 additions & 1 deletion src/libponyrt/lang/directory.c
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@

#include <platform.h>
#include <pony.h>
#include "lang.h"
#include <string.h>

#if defined(PLATFORM_IS_WINDOWS)
Expand Down
22 changes: 22 additions & 0 deletions src/libponyrt/lang/except_try_catch.ll
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
; This file implements the `pony_try` function in LLVM IR as it cannot be
; implemented in C.
; Since the LLVM project doesn't particularly care about IR backwards
; compatibility, please try to keep this file as minimal as possible in order
; to minimise the chances of breakage with newer LLVM versions.

declare i32 @pony_personality_v0(...)

define i1 @pony_try(void (i8*)* %fun, i8* %ctx) personality i32 (...)* @pony_personality_v0 {
entry:
invoke void %fun(i8* %ctx)
to label %post unwind label %unwind

unwind:
%lp = landingpad { i8*, i32 }
catch i8* null
br label %post

post:
%ret = phi i1 [ true, %entry ], [ false, %unwind ]
ret i1 %ret
}
12 changes: 0 additions & 12 deletions src/libponyrt/lang/lang.h

This file was deleted.

1 change: 0 additions & 1 deletion src/libponyrt/lang/paths.c
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
#include <platform.h>
#include <pony.h>
#include "lang.h"
#include <string.h>

PONY_EXTERN_C_BEGIN
Expand Down
2 changes: 1 addition & 1 deletion src/libponyrt/lang/posix_except.c
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ static void exception_cleanup(_Unwind_Reason_Code reason,
(void)exception;
}

PONY_API void pony_throw()
PONY_API void pony_error()
{
#ifdef PLATFORM_IS_ARM
memcpy(exception.exception_class, "Pony\0\0\0\0", 8);
Expand Down
Loading

0 comments on commit 7a5f753

Please sign in to comment.