Skip to content

Commit

Permalink
Add the pony_try function to receive Pony errors in C code (#2457)
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 authored Jan 4, 2018
1 parent b955480 commit 24982d5
Show file tree
Hide file tree
Showing 19 changed files with 152 additions and 91 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
87 changes: 41 additions & 46 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,50 @@ 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
else ifeq (,$(shell which $(LLVM_CONFIG) 2> /dev/null))
$(error No LLVM installation found!)
endif

LLVM_BINDIR := $(shell $(LLVM_CONFIG) --bindir 2> /dev/null)

LLVM_LINK := $(LLVM_BINDIR)/llvm-link
LLVM_OPT := $(LLVM_BINDIR)/opt
LLVM_LLC := $(LLVM_BINDIR)/llc
LLVM_AS := $(LLVM_BINDIR)/llvm-as

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

ifeq (,$(LLVM_LINK_STATIC))
Expand All @@ -278,9 +257,8 @@ ifeq (,$(LLVM_LINK_STATIC))
endif

ifeq ($(OSTYPE),osx)
llvm_bindir := $(shell $(LLVM_CONFIG) --bindir $(LLVM_LINK_STATIC))
ifneq (,$(shell which $(llvm_bindir)/llvm-ar 2> /dev/null))
AR = $(llvm_bindir)/llvm-ar
ifneq (,$(shell which $(LLVM_BINDIR)/llvm-ar 2> /dev/null))
AR = $(LLVM_BINDIR)/llvm-ar
AR_FLAGS := rcs
else ifneq (,$(shell which llvm-ar-mp-3.8 2> /dev/null))
AR = llvm-ar-mp-3.8
Expand All @@ -290,7 +268,7 @@ ifeq ($(OSTYPE),osx)
AR_FLAGS := rcs
else
AR = /usr/bin/ar
AR_FLAGS := -rcs
AR_FLAGS := -rcs
endif
endif

Expand Down Expand Up @@ -510,11 +488,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 @@ -613,7 +593,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 @@ -631,11 +611,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 @@ -691,8 +676,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 @@ -701,17 +686,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 @@ -723,8 +718,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 @@ -787,9 +787,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 24982d5

Please sign in to comment.