diff --git a/mak/COPY b/mak/COPY
index 876b2cb71f..75dc52e0e8 100644
--- a/mak/COPY
+++ b/mak/COPY
@@ -22,6 +22,7 @@ COPY=\
$(IMPDIR)\core\internal\string.d \
$(IMPDIR)\core\internal\traits.d \
\
+ $(IMPDIR)\core\stdc\clang_block.d \
$(IMPDIR)\core\stdc\complex.d \
$(IMPDIR)\core\stdc\config.d \
$(IMPDIR)\core\stdc\ctype.d \
diff --git a/mak/SRCS b/mak/SRCS
index d1a9ba9725..c43cf55d32 100644
--- a/mak/SRCS
+++ b/mak/SRCS
@@ -23,6 +23,7 @@ SRCS=\
src\core\internal\string.d \
src\core\internal\traits.d \
\
+ src\core\stdc\clang_block.d \
src\core\stdc\config.d \
src\core\stdc\ctype.d \
src\core\stdc\errno.d \
diff --git a/posix.mak b/posix.mak
index e5d645bcd6..8ca675eb78 100644
--- a/posix.mak
+++ b/posix.mak
@@ -30,9 +30,11 @@ IMPDIR=import
OPTIONAL_PIC:=$(if $(PIC),-fPIC,)
ifeq (osx,$(OS))
+ CLANG_BLOCKS:=1
DOTDLL:=.dylib
DOTLIB:=.a
else
+ CLANG_BLOCKS:=0
DOTDLL:=.so
DOTLIB:=.a
endif
@@ -90,12 +92,6 @@ SRCS:=$(subst \,/,$(SRCS))
OBJS= $(ROOT)/errno_c.o $(ROOT)/bss_section.o $(ROOT)/threadasm.o
-ifeq ($(OS),osx)
-ifeq ($(MODEL), 64)
- OBJS+=$(ROOT)/osx_tls.o
-endif
-endif
-
# build with shared library support
SHARED=$(if $(findstring $(OS),linux freebsd),1,)
@@ -194,6 +190,10 @@ HAS_ADDITIONAL_TESTS:=$(shell test -d test && echo 1)
ifeq ($(HAS_ADDITIONAL_TESTS),1)
ADDITIONAL_TESTS:=test/init_fini test/exceptions test/coverage test/profile
ADDITIONAL_TESTS+=$(if $(SHARED),test/shared,)
+
+ ifeq ($(CLANG_BLOCKS),1)
+ ADDITIONAL_TESTS+=test/clang_block
+ endif
endif
.PHONY : unittest
diff --git a/src/core/stdc/clang_block.d b/src/core/stdc/clang_block.d
new file mode 100644
index 0000000000..54cd84d5a6
--- /dev/null
+++ b/src/core/stdc/clang_block.d
@@ -0,0 +1,206 @@
+/**
+ * This module contains functionality for interfacing with
+ * $(LINK2 http://clang.llvm.org/docs/BlockLanguageSpec.html, Clang Blocks).
+ *
+ * The examples below first shows a C function, using Clang Blocks, to call and
+ * then the D code for calling the C function.
+ *
+ * Examples:
+ *
+ * Basic example of calling a function taking a block with no arguments that
+ * returns void.
+ *
+ * $(CCODE void foo(void (^block)(void));)
+ *
+ * Will look like:
+ *
+ * ---
+ * import core.stdc.clang_block;
+ *
+ * // The `Block` type is used to represent the Clang block in D
+ * extern(C) void foo(Block!()* block);
+ *
+ * void main()
+ * {
+ * // The `block` function is used to initialize an instance of `Block`.
+ * // A delegate will be passed to the `block` function which will be the
+ * // body of the block.
+ * auto b = block({ writeln("foo"); });
+ * foo(&b);
+ * }
+ * ---
+ *
+ * Example of calling a function taking a block with arguments that returns
+ * void.
+ *
+ * $(CCODE void foo(void (^block)(int));)
+ *
+ * Will look like:
+ *
+ * ---
+ * import core.stdc.clang_block;
+ *
+ * // The type parameters to the instantiation of `Block` is first the return
+ * // type, `void`, and then the parameter types, `int`.
+ * extern(C) void foo(Block!(void, int)* block);
+ *
+ * void main()
+ * {
+ * // The delegate to the `block` function cannot use inferred type
+ * // parameters.
+ * auto b = block((int a){ writeln(a); });
+ * foo(&b);
+ * }
+ * ---
+ *
+ * Example of calling a function taking a block with no arguments that returns
+ * an int.
+ *
+ * $(CCODE void foo(int (^block)(void));)
+ *
+ * Will look like:
+ *
+ * ---
+ * import core.stdc.clang_block;
+ *
+ * extern(C) void foo(Block!(int)* block);
+ *
+ * void main()
+ * {
+ * // The return type can be inferred
+ * auto b = block({ return 3; });
+ * foo(&b);
+ * }
+ * ---
+ *
+ * To build on non Apple platforms the C code needs to be compiled using Clang
+ * and it's required to link with the
+ * $(LINK2 http://compiler-rt.llvm.org, Blocks runtime). On Debian based
+ * platforms install the following packages:
+ * "llvm", "clang" and "libblocksruntime-dev". Example of compiling on Linux:
+ *
+ * $(CCODE
+ * $ clang foo.c -o foo.o
+ * $ dmd main.d foo.o -L-lBlocksRuntime
+ * )
+ *
+ * Copyright: Copyright Jacob Carlborg 2016.
+ * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
+ * Authors: Jacob Carlborg
+ * Source: $(DRUNTIMESRC core/_clang_block.d)
+ */
+module core.stdc.clang_block;
+
+import core.stdc.config;
+
+/**
+ * This struct is the D representation of a Clang Block.
+ *
+ * Params:
+ * R = the return type of the block
+ * Params = the parameter types of the block
+ */
+struct Block(R = void, Params...)
+{
+private:
+
+ alias extern(C) R function(Block*, Params) Invoke;
+
+ void* isa;
+ int flags;
+ int reserved = 0;
+ Invoke invoke;
+ Descriptor* descriptor;
+
+ // Imported variables go here
+ R delegate(Params) dg;
+
+ this(void* isa, int flags, Invoke invoke, R delegate(Params) dg)
+ {
+ this.isa = isa;
+ this.flags = flags;
+ this.invoke = invoke;
+ this.dg = dg;
+ this.descriptor = &.descriptor;
+ }
+}
+
+/**
+ * Creates a new block that can be passed to a C function expecting a
+ * Clang Block.
+ *
+ * Params:
+ * R = the return type of the block
+ * Params = the parameter types of the block
+ * dg = the body of the block
+ *
+ * Returns: the newly created block
+ */
+Block!(R, Params) block(R, Params...)(R delegate(Params) dg)
+{
+ static if (Params.length == 0)
+ enum flags = 0x50000000;
+ else
+ enum flags = 0x40000000;
+
+ return Block!(R, Params)(
+ &_NSConcreteStackBlock, flags, &invoke!(R, Params), dg
+ );
+}
+
+private:
+
+/*
+ * The the block implementation specification is available here:
+ * http://clang.llvm.org/docs/Block-ABI-Apple.html
+ */
+
+// Block descriptor
+struct Descriptor
+{
+ // null/0
+ c_ulong reserved;
+
+ // Block!(R, Params).sizeof
+ c_ulong size;
+
+ // Optional helper functions
+ // extern(C) void function(void* dst, void* src) copy_helper;
+ // extern(C) void function(void* src) dispose_helper;
+
+ /*
+ * Signature of the block, using Objective-C type encoding.
+ * Seems not to be used.
+ */
+ const(char)* signature;
+}
+
+// Block of uninitialized memory used for stack block literals
+extern(C) extern __gshared void*[32] _NSConcreteStackBlock;
+
+/*
+ * Shared block descriptor. Since the descriptor will always look the same we
+ * can reuse a single descriptor.
+ */
+__gshared auto descriptor = Descriptor(0, Block!().sizeof);
+
+/*
+ * The body of a block that the C runtime will call.
+ *
+ * The implementation forwards to the delegate stored in the block struct
+ * containing the real D body.
+ *
+ * Since a delegate is used to store the actual D body of the block a single
+ * body can be shared for all blocks.
+ *
+ * Params:
+ * R = the return type of the block
+ * Args = the parameter types of the block
+ * args = the argument that was passed to the block
+ *
+ * Returns: whatever the delegate stored in the block returns
+ */
+extern(C) R invoke(R, Args...)(Block!(R, Args)* block, Args args)
+{
+ return block.dg(args);
+}
diff --git a/src/rt/osx_tls.c b/src/rt/osx_tls.c
deleted file mode 100644
index 6cdffff672..0000000000
--- a/src/rt/osx_tls.c
+++ /dev/null
@@ -1,51 +0,0 @@
-/**
- * Helpers for determining TLS memory ranges on OS X.
- *
- * This unfortunately cannot be entirely done in D, as the OS X API uses
- * the Apple-specific blocks C extension.
- *
- * Copyright: David Nadlinger, 2012.
- * License: Boost License 1.0.
- * Authors: David Nadlinger
- */
-
-#ifndef __APPLE__
-#ifndef __BLOCKS__
- #error "Need a C compiler with Apple Blocks support – not building on OS X with Clang?"
-#endif
-#endif
-
-#include
-#include
-#include
-
-/*
- * Declarations from dyld_priv.h, available on 10.7+.
- */
-enum dyld_tlv_states {
- dyld_tlv_state_allocated = 10,
- dyld_tlv_state_deallocated = 20
-};
-typedef struct {
- size_t info_size;
- void * tlv_addr;
- size_t tlv_size;
-} dyld_tlv_info;
-typedef void (^dyld_tlv_state_change_handler)(enum dyld_tlv_states state, const dyld_tlv_info *info);
-extern void dyld_register_tlv_state_change_handler(enum dyld_tlv_states state, dyld_tlv_state_change_handler handler);
-extern void dyld_enumerate_tlv_storage(dyld_tlv_state_change_handler handler);
-
-void _d_dyld_getTLSRange(void* arbitraryTLSSymbol, void** start, size_t* size) {
- dyld_enumerate_tlv_storage(
- ^(enum dyld_tlv_states state, const dyld_tlv_info *info) {
- assert(state == dyld_tlv_state_allocated);
- if (info->tlv_addr <= arbitraryTLSSymbol &&
- arbitraryTLSSymbol < (info->tlv_addr + info->tlv_size)
- ) {
- // Found the range.
- *start = info->tlv_addr;
- *size = info->tlv_size;
- }
- }
- );
-}
diff --git a/src/rt/sections_osx_x86_64.d b/src/rt/sections_osx_x86_64.d
index 1bfcef3680..5fcd40c21d 100644
--- a/src/rt/sections_osx_x86_64.d
+++ b/src/rt/sections_osx_x86_64.d
@@ -24,6 +24,7 @@ version(Darwin):
version(X86_64):
// debug = PRINTF;
+import core.stdc.clang_block;
import core.stdc.stdio;
import core.stdc.string, core.stdc.stdlib;
import core.sys.posix.pthread;
@@ -95,11 +96,9 @@ void finiSections()
void[] initTLSRanges()
{
- void* start = null;
- size_t size = 0;
- _d_dyld_getTLSRange(&dummyTlsSymbol, &start, &size);
- assert(start && size, "Could not determine TLS range.");
- return start[0 .. size];
+ auto range = getTLSRange();
+ assert(range.isValid, "Could not determine TLS range.");
+ return range.toArray();
}
void finiTLSRanges(void[] rng)
@@ -114,11 +113,65 @@ void scanTLSRanges(void[] rng, scope void delegate(void* pbeg, void* pend) nothr
private:
-extern(C) void _d_dyld_getTLSRange(void*, void**, size_t*);
+// Declarations from dyld_priv.h in dyld, available on 10.7+.
+enum dyld_tlv_states
+{
+ allocated = 10,
+ deallocated = 20
+}
+
+struct dyld_tlv_info
+{
+ size_t info_size;
+ void * tlv_addr;
+ size_t tlv_size;
+}
+
+alias dyld_tlv_state_change_handler = Block!(void, dyld_tlv_states, dyld_tlv_info*)*;
+extern(C) void dyld_enumerate_tlv_storage(dyld_tlv_state_change_handler handler);
-__gshared SectionGroup _sections;
ubyte dummyTlsSymbol;
+struct TLSRange
+{
+ void* start;
+ size_t size;
+
+ bool isValid()
+ {
+ return start !is null && size > 0;
+ }
+
+ void[] toArray()
+ {
+ return start[0 .. size];
+ }
+}
+
+TLSRange getTLSRange()
+{
+ void* tlsSymbol = &dummyTlsSymbol;
+ TLSRange range;
+
+ scope dg = (dyld_tlv_states state, dyld_tlv_info* info) {
+ assert(state == dyld_tlv_states.allocated);
+
+ if (info.tlv_addr <= tlsSymbol && tlsSymbol <
+ (info.tlv_addr + info.tlv_size)
+ )
+ {
+ range = TLSRange(info.tlv_addr, info.tlv_size);
+ }
+ };
+
+ auto handler = block(dg);
+ dyld_enumerate_tlv_storage(&handler);
+
+ return range;
+}
+
+__gshared SectionGroup _sections;
+
extern (C) void sections_osx_onAddImage(in mach_header* h, intptr_t slide)
{
foreach (e; dataSegs)
diff --git a/test/clang_block/Makefile b/test/clang_block/Makefile
new file mode 100644
index 0000000000..8846dad56b
--- /dev/null
+++ b/test/clang_block/Makefile
@@ -0,0 +1,21 @@
+include ../common.mak
+
+TESTS:=clang_block
+
+.PHONY: all clean
+all: $(addprefix $(ROOT)/,$(addsuffix .done,$(TESTS)))
+
+$(ROOT)/%.done: $(ROOT)/%
+ @echo Testing $*
+ $(QUIET)$(TIMELIMIT)$(ROOT)/$* $(RUN_ARGS)
+ @touch $@
+
+$(ROOT)/%_c: $(SRC)/%.c
+ @mkdir -p $(@D)
+ $(QUIET)$(CC) $(CFLAGS) -o $@.o -c $<
+
+$(ROOT)/%: $(SRC)/%.d $(ROOT)/%_c
+ $(QUIET)$(DMD) $(DFLAGS) -main -unittest -of$@ $@_c.o $<
+
+clean:
+ rm -rf $(GENERATED)
diff --git a/test/clang_block/src/clang_block.c b/test/clang_block/src/clang_block.c
new file mode 100644
index 0000000000..7775260b6b
--- /dev/null
+++ b/test/clang_block/src/clang_block.c
@@ -0,0 +1,23 @@
+#ifndef __BLOCKS__
+ #error "Need a C compiler with Blocks support – not building with Clang?"
+#endif
+
+void voidVoidArgs(void(^block)(void))
+{
+ block();
+}
+
+int intVoidArgs(int(^block)(void))
+{
+ return block();
+}
+
+void voidIntArgs(void(^block)(int), int arg)
+{
+ block(arg);
+}
+
+int intIntArgs(int(^block)(int), int arg)
+{
+ return block(arg);
+}
diff --git a/test/clang_block/src/clang_block.d b/test/clang_block/src/clang_block.d
new file mode 100644
index 0000000000..54cbdffaf1
--- /dev/null
+++ b/test/clang_block/src/clang_block.d
@@ -0,0 +1,52 @@
+import core.stdc.clang_block;
+
+extern(C) void voidVoidArgs(Block!()*);
+extern(C) int intVoidArgs(Block!(int)*);
+extern(C) void voidIntArgs(Block!(void, int)*, int);
+extern(C) int intIntArgs(Block!(int, int)*, int);
+
+// block returning void taking no arguments
+unittest
+{
+ enum value = 3;
+
+ int result;
+ auto b = block({ result = value; });
+ voidVoidArgs(&b);
+ assert(result == value);
+}
+
+// block returning int taking no arguments
+unittest
+{
+ enum value = 3;
+
+ auto b = block({ return value; });
+ auto result = intVoidArgs(&b);
+ assert(result == value);
+}
+
+// block returning void taking int argument
+unittest
+{
+ enum value = 3;
+
+ int result;
+ auto b = block((int v) {
+ result = v;
+ });
+ voidIntArgs(&b, value);
+ assert(result == value);
+}
+
+// block returning int taking int argument
+unittest
+{
+ enum value = 3;
+
+ auto b = block((int v) {
+ return v;
+ });
+ auto result = intIntArgs(&b, value);
+ assert(result == value);
+}
diff --git a/win32.mak b/win32.mak
index a678e71365..bec788ee02 100644
--- a/win32.mak
+++ b/win32.mak
@@ -85,6 +85,9 @@ $(DOCDIR)\core_time.html : src\core\time.d
$(DOCDIR)\core_vararg.html : src\core\vararg.d
$(DMD) $(DDOCFLAGS) -Df$@ $(DOCFMT) $**
+$(DOCDIR)\core_stdc_clang_block.html : src\core\stdc\clang_block.d
+ $(DMD) $(DDOCFLAGS) -Df$@ $(DOCFMT) $**
+
$(DOCDIR)\core_stdc_complex.html : src\core\stdc\complex.d
$(DMD) $(DDOCFLAGS) -Df$@ $(DOCFMT) $**
@@ -278,6 +281,9 @@ $(IMPDIR)\core\internal\string.d : src\core\internal\string.d
$(IMPDIR)\core\internal\traits.d : src\core\internal\traits.d
copy $** $@
+$(IMPDIR)\core\stdc\clang_block.d : src\core\stdc\clang_block.d
+ copy $** $@
+
$(IMPDIR)\core\stdc\complex.d : src\core\stdc\complex.d
copy $** $@
diff --git a/win64.mak b/win64.mak
index cc61982605..23fc1c456e 100644
--- a/win64.mak
+++ b/win64.mak
@@ -93,6 +93,9 @@ $(DOCDIR)\core_vararg.html : src\core\vararg.d
$(DMD) $(DDOCFLAGS) -Df$@ $(DOCFMT) $**
+$(DOCDIR)\core_stdc_clang_block.html : src\core\stdc\clang_block.d
+ $(DMD) $(DDOCFLAGS) -Df$@ $(DOCFMT) $**
+
$(DOCDIR)\core_stdc_complex.html : src\core\stdc\complex.d
$(DMD) $(DDOCFLAGS) -Df$@ $(DOCFMT) $**
@@ -286,6 +289,9 @@ $(IMPDIR)\core\internal\string.d : src\core\internal\string.d
$(IMPDIR)\core\internal\traits.d : src\core\internal\traits.d
copy $** $@
+$(IMPDIR)\core\stdc\clang_block.d : src\core\stdc\clang_block.d
+ copy $** $@
+
$(IMPDIR)\core\stdc\complex.d : src\core\stdc\complex.d
copy $** $@