diff options
author | Iain Buclaw <ibuclaw@gcc.gnu.org> | 2018-10-28 19:51:47 +0000 |
---|---|---|
committer | Iain Buclaw <ibuclaw@gcc.gnu.org> | 2018-10-28 19:51:47 +0000 |
commit | b4c522fabd0df7be08882d2207df8b2765026110 (patch) | |
tree | b5ffc312b0a441c1ba24323152aec463fdbe5e9f /libphobos/testsuite/libphobos.shared | |
parent | 01ce9e31a02c8039d88e90f983735104417bf034 (diff) | |
download | gcc-b4c522fabd0df7be08882d2207df8b2765026110.zip gcc-b4c522fabd0df7be08882d2207df8b2765026110.tar.gz gcc-b4c522fabd0df7be08882d2207df8b2765026110.tar.bz2 |
Add D front-end, libphobos library, and D2 testsuite.
ChangeLog:
* Makefile.def (target_modules): Add libphobos.
(flags_to_pass): Add GDC, GDCFLAGS, GDC_FOR_TARGET and
GDCFLAGS_FOR_TARGET.
(dependencies): Make libphobos depend on libatomic, libbacktrace
configure, and zlib configure.
(language): Add language d.
* Makefile.in: Rebuild.
* Makefile.tpl (BUILD_EXPORTS): Add GDC and GDCFLAGS.
(HOST_EXPORTS): Add GDC.
(POSTSTAGE1_HOST_EXPORTS): Add GDC and GDC_FOR_BUILD.
(BASE_TARGET_EXPORTS): Add GDC.
(GDC_FOR_BUILD, GDC, GDCFLAGS): New variables.
(GDC_FOR_TARGET, GDC_FLAGS_FOR_TARGET): New variables.
(EXTRA_HOST_FLAGS): Add GDC.
(STAGE1_FLAGS_TO_PASS): Add GDC.
(EXTRA_TARGET_FLAGS): Add GDC and GDCFLAGS.
* config-ml.in: Treat GDC and GDCFLAGS like other compiler/flag
environment variables.
* configure: Rebuild.
* configure.ac: Add target-libphobos to target_libraries. Set and
substitute GDC_FOR_BUILD and GDC_FOR_TARGET.
config/ChangeLog:
* multi.m4: Set GDC.
gcc/ChangeLog:
* Makefile.in (tm_d_file_list, tm_d_include_list): New variables.
(TM_D_H, D_TARGET_DEF, D_TARGET_H, D_TARGET_OBJS): New variables.
(tm_d.h, cs-tm_d.h, default-d.o): New rules.
(d/d-target-hooks-def.h, s-d-target-hooks-def-h): New rules.
(s-tm-texi): Also check timestamp on d-target.def.
(generated_files): Add TM_D_H and d-target-hooks-def.h.
(build/genhooks.o): Also depend on D_TARGET_DEF.
* config.gcc (tm_d_file, d_target_objs, target_has_targetdm): New
variables.
* config/aarch64/aarch64-d.c: New file.
* config/aarch64/aarch64-linux.h (GNU_USER_TARGET_D_CRITSEC_SIZE):
Define.
* config/aarch64/aarch64-protos.h (aarch64_d_target_versions): New
prototype.
* config/aarch64/aarch64.h (TARGET_D_CPU_VERSIONS): Define.
* config/aarch64/t-aarch64 (aarch64-d.o): New rule.
* config/arm/arm-d.c: New file.
* config/arm/arm-protos.h (arm_d_target_versions): New prototype.
* config/arm/arm.h (TARGET_D_CPU_VERSIONS): Define.
* config/arm/linux-eabi.h (EXTRA_TARGET_D_OS_VERSIONS): Define.
* config/arm/t-arm (arm-d.o): New rule.
* config/default-d.c: New file.
* config/glibc-d.c: New file.
* config/gnu.h (GNU_USER_TARGET_D_OS_VERSIONS): Define.
* config/i386/i386-d.c: New file.
* config/i386/i386-protos.h (ix86_d_target_versions): New prototype.
* config/i386/i386.h (TARGET_D_CPU_VERSIONS): Define.
* config/i386/linux-common.h (EXTRA_TARGET_D_OS_VERSIONS): Define.
(GNU_USER_TARGET_D_CRITSEC_SIZE): Define.
* config/i386/t-i386 (i386-d.o): New rule.
* config/kfreebsd-gnu.h (GNU_USER_TARGET_D_OS_VERSIONS): Define.
* config/kopensolaris-gnu.h (GNU_USER_TARGET_D_OS_VERSIONS): Define.
* config/linux-android.h (ANDROID_TARGET_D_OS_VERSIONS): Define.
* config/linux.h (GNU_USER_TARGET_D_OS_VERSIONS): Define.
* config/mips/linux-common.h (EXTRA_TARGET_D_OS_VERSIONS): Define.
* config/mips/mips-d.c: New file.
* config/mips/mips-protos.h (mips_d_target_versions): New prototype.
* config/mips/mips.h (TARGET_D_CPU_VERSIONS): Define.
* config/mips/t-mips (mips-d.o): New rule.
* config/powerpcspe/linux.h (GNU_USER_TARGET_D_OS_VERSIONS): Define.
* config/powerpcspe/linux64.h (GNU_USER_TARGET_D_OS_VERSIONS): Define.
* config/powerpcspe/powerpcspe-d.c: New file.
* config/powerpcspe/powerpcspe-protos.h (rs6000_d_target_versions):
New prototype.
* config/powerpcspe/powerpcspe.c (rs6000_output_function_epilogue):
Support GNU D by using 0 as the language type.
* config/powerpcspe/powerpcspe.h (TARGET_D_CPU_VERSIONS): Define.
* config/powerpcspe/t-powerpcspe (powerpcspe-d.o): New rule.
* config/riscv/riscv-d.c: New file.
* config/riscv/riscv-protos.h (riscv_d_target_versions): New
prototype.
* config/riscv/riscv.h (TARGET_D_CPU_VERSIONS): Define.
* config/riscv/t-riscv (riscv-d.o): New rule.
* config/rs6000/linux.h (GNU_USER_TARGET_D_OS_VERSIONS): Define.
* config/rs6000/linux64.h (GNU_USER_TARGET_D_OS_VERSIONS): Define.
* config/rs6000/rs6000-d.c: New file.
* config/rs6000/rs6000-protos.h (rs6000_d_target_versions): New
prototype.
* config/rs6000/rs6000.c (rs6000_output_function_epilogue):
Support GNU D by using 0 as the language type.
* config/rs6000/rs6000.h (TARGET_D_CPU_VERSIONS): Define.
* config/rs6000/t-rs6000 (rs6000-d.o): New rule.
* config/s390/s390-d.c: New file.
* config/s390/s390-protos.h (s390_d_target_versions): New prototype.
* config/s390/s390.h (TARGET_D_CPU_VERSIONS): Define.
* config/s390/t-s390 (s390-d.o): New rule.
* config/sparc/sparc-d.c: New file.
* config/sparc/sparc-protos.h (sparc_d_target_versions): New
prototype.
* config/sparc/sparc.h (TARGET_D_CPU_VERSIONS): Define.
* config/sparc/t-sparc (sparc-d.o): New rule.
* config/t-glibc (glibc-d.o): New rule.
* configure: Regenerated.
* configure.ac (tm_d_file): New variable.
(tm_d_file_list, tm_d_include_list, d_target_objs): Add substitutes.
* doc/contrib.texi (Contributors): Add self for the D frontend.
* doc/frontends.texi (G++ and GCC): Mention D as a supported language.
* doc/install.texi (Configuration): Mention libphobos as an option for
--enable-shared. Mention d as an option for --enable-languages.
(Testing): Mention check-d as a target.
* doc/invoke.texi (Overall Options): Mention .d, .dd, and .di as file
name suffixes. Mention d as a -x option.
* doc/sourcebuild.texi (Top Level): Mention libphobos.
* doc/standards.texi (Standards): Add section on D language.
* doc/tm.texi: Regenerated.
* doc/tm.texi.in: Add @node for D language and ABI, and @hook for
TARGET_CPU_VERSIONS, TARGET_D_OS_VERSIONS, and TARGET_D_CRITSEC_SIZE.
* dwarf2out.c (is_dlang): New function.
(gen_compile_unit_die): Use DW_LANG_D for D.
(declare_in_namespace): Return module die for D, instead of adding
extra declarations into the namespace.
(gen_namespace_die): Generate DW_TAG_module for D.
(gen_decl_die): Handle CONST_DECLSs for D.
(dwarf2out_decl): Likewise.
(prune_unused_types_walk_local_classes): Handle DW_tag_interface_type.
(prune_unused_types_walk): Handle DW_tag_interface_type same as other
kinds of aggregates.
* gcc.c (default_compilers): Add entries for .d, .dd and .di.
* genhooks.c: Include d/d-target.def.
gcc/po/ChangeLog:
* EXCLUDES: Add sources from d/dmd.
gcc/testsuite/ChangeLog:
* gcc.misc-tests/help.exp: Add D to option descriptions check.
* gdc.dg/asan/asan.exp: New file.
* gdc.dg/asan/gdc272.d: New test.
* gdc.dg/compilable.d: New test.
* gdc.dg/dg.exp: New file.
* gdc.dg/gdc254.d: New test.
* gdc.dg/gdc260.d: New test.
* gdc.dg/gdc270a.d: New test.
* gdc.dg/gdc270b.d: New test.
* gdc.dg/gdc282.d: New test.
* gdc.dg/gdc283.d: New test.
* gdc.dg/imports/gdc170.d: New test.
* gdc.dg/imports/gdc231.d: New test.
* gdc.dg/imports/gdc239.d: New test.
* gdc.dg/imports/gdc241a.d: New test.
* gdc.dg/imports/gdc241b.d: New test.
* gdc.dg/imports/gdc251a.d: New test.
* gdc.dg/imports/gdc251b.d: New test.
* gdc.dg/imports/gdc253.d: New test.
* gdc.dg/imports/gdc254a.d: New test.
* gdc.dg/imports/gdc256.d: New test.
* gdc.dg/imports/gdc27.d: New test.
* gdc.dg/imports/gdcpkg256/package.d: New test.
* gdc.dg/imports/runnable.d: New test.
* gdc.dg/link.d: New test.
* gdc.dg/lto/lto.exp: New file.
* gdc.dg/lto/ltotests_0.d: New test.
* gdc.dg/lto/ltotests_1.d: New test.
* gdc.dg/runnable.d: New test.
* gdc.dg/simd.d: New test.
* gdc.test/gdc-test.exp: New file.
* lib/gdc-dg.exp: New file.
* lib/gdc.exp: New file.
libphobos/ChangeLog:
* Makefile.am: New file.
* Makefile.in: New file.
* acinclude.m4: New file.
* aclocal.m4: New file.
* config.h.in: New file.
* configure: New file.
* configure.ac: New file.
* d_rules.am: New file.
* libdruntime/Makefile.am: New file.
* libdruntime/Makefile.in: New file.
* libdruntime/__entrypoint.di: New file.
* libdruntime/__main.di: New file.
* libdruntime/gcc/attribute.d: New file.
* libdruntime/gcc/backtrace.d: New file.
* libdruntime/gcc/builtins.d: New file.
* libdruntime/gcc/config.d.in: New file.
* libdruntime/gcc/deh.d: New file.
* libdruntime/gcc/libbacktrace.d.in: New file.
* libdruntime/gcc/unwind/arm.d: New file.
* libdruntime/gcc/unwind/arm_common.d: New file.
* libdruntime/gcc/unwind/c6x.d: New file.
* libdruntime/gcc/unwind/generic.d: New file.
* libdruntime/gcc/unwind/package.d: New file.
* libdruntime/gcc/unwind/pe.d: New file.
* m4/autoconf.m4: New file.
* m4/druntime.m4: New file.
* m4/druntime/cpu.m4: New file.
* m4/druntime/libraries.m4: New file.
* m4/druntime/os.m4: New file.
* m4/gcc_support.m4: New file.
* m4/gdc.m4: New file.
* m4/libtool.m4: New file.
* src/Makefile.am: New file.
* src/Makefile.in: New file.
* src/libgphobos.spec.in: New file.
* testsuite/Makefile.am: New file.
* testsuite/Makefile.in: New file.
* testsuite/config/default.exp: New file.
* testsuite/lib/libphobos-dg.exp: New file.
* testsuite/lib/libphobos.exp: New file.
* testsuite/testsuite_flags.in: New file.
From-SVN: r265573
Diffstat (limited to 'libphobos/testsuite/libphobos.shared')
20 files changed, 849 insertions, 0 deletions
diff --git a/libphobos/testsuite/libphobos.shared/finalize.d b/libphobos/testsuite/libphobos.shared/finalize.d new file mode 100644 index 0000000..f31b818 --- /dev/null +++ b/libphobos/testsuite/libphobos.shared/finalize.d @@ -0,0 +1,63 @@ +import core.runtime; +import core.stdc.stdio; +import core.stdc.string; +import core.thread; +import core.sys.posix.dlfcn; + +void runTest() +{ + Object obj; + obj = Object.factory("lib.MyFinalizer"); + assert(obj.toString() == "lib.MyFinalizer"); + obj = Object.factory("lib.MyFinalizerBig"); + assert(obj.toString() == "lib.MyFinalizerBig"); +} + +class NoFinalize +{ + size_t _finalizeCounter; + + ~this() + { + ++_finalizeCounter; + } +} + +class NoFinalizeBig : NoFinalize +{ + ubyte[4096] _big = void; +} + +extern (C) alias SetFinalizeCounter = void function(shared(size_t*)); + +void main(string[] args) +{ + auto name = args[0] ~ '\0'; + const pathlen = strrchr(name.ptr, '/') - name.ptr + 1; + name = name[0 .. pathlen] ~ "lib.so"; + + auto h = Runtime.loadLibrary(name); + assert(h !is null); + + auto nf1 = new NoFinalize; + auto nf2 = new NoFinalizeBig; + + shared size_t finalizeCounter; + auto setFinalizeCounter = cast(SetFinalizeCounter)dlsym(h, "setFinalizeCounter"); + setFinalizeCounter(&finalizeCounter); + + runTest(); + auto thr = new Thread(&runTest); + thr.start(); + thr.join(); + + auto r = Runtime.unloadLibrary(h); + if (!r) + assert(0); + if (finalizeCounter != 4) + assert(0); + if (nf1._finalizeCounter) + assert(0); + if (nf2._finalizeCounter) + assert(0); +} diff --git a/libphobos/testsuite/libphobos.shared/host.c b/libphobos/testsuite/libphobos.shared/host.c new file mode 100644 index 0000000..81e896a --- /dev/null +++ b/libphobos/testsuite/libphobos.shared/host.c @@ -0,0 +1,60 @@ +#include <stdlib.h> +#include <string.h> +#include <dlfcn.h> +#include <assert.h> + +int main(int argc, char* argv[]) +{ +#if defined(__FreeBSD__) + // workaround for Bugzilla 14824 + void *druntime = dlopen(argv[1], RTLD_LAZY); // load druntime + assert(druntime); +#endif + + const size_t pathlen = strrchr(argv[0], '/') - argv[0] + 1; + char *name = malloc(pathlen + sizeof("plugin1.so")); + memcpy(name, argv[0], pathlen); + memcpy(name+pathlen, "plugin1.so", sizeof("plugin1.so")); + + void* plugin1 = dlopen(name, RTLD_LAZY); + name[pathlen + sizeof("plugin1.so") - 5] = '2'; + void* plugin2 = dlopen(name, RTLD_LAZY); + + int (*plugin1_init)() = dlsym(plugin1, "plugin_init"); + int (*plugin1_term)() = dlsym(plugin1, "plugin_term"); + int (*runTests1)() = dlsym(plugin1, "runTests"); + int (*plugin2_init)() = dlsym(plugin2, "plugin_init"); + int (*plugin2_term)() = dlsym(plugin2, "plugin_term"); + int (*runTests2)() = dlsym(plugin2, "runTests"); + assert(plugin1_init()); + assert(runTests1()); + assert(plugin2_init()); + assert(runTests2()); + + assert(plugin1_term()); + assert(dlclose(plugin1) == 0); + assert(runTests2()); + + name[pathlen + sizeof("plugin1.so") - 5] = '1'; + plugin1 = dlopen(name, RTLD_LAZY); + plugin1_init = dlsym(plugin1, "plugin_init"); + plugin1_term = dlsym(plugin1, "plugin_term"); + runTests1 = dlsym(plugin1, "runTests"); + assert(plugin1_init()); + assert(runTests1()); + assert(runTests2()); + + assert(plugin2_term()); + assert(dlclose(plugin2) == 0); + assert(runTests1()); + + assert(plugin1_term()); + assert(dlclose(plugin1) == 0); + + free(name); + +#if defined(__FreeBSD__) + dlclose(druntime); +#endif + return EXIT_SUCCESS; +} diff --git a/libphobos/testsuite/libphobos.shared/lib.d b/libphobos/testsuite/libphobos.shared/lib.d new file mode 100644 index 0000000..0e4eb44 --- /dev/null +++ b/libphobos/testsuite/libphobos.shared/lib.d @@ -0,0 +1,133 @@ +module lib; + +// test EH +void throwException() +{ + throw new Exception(null); +} + +Exception collectException(void delegate() dg) +{ + try + dg(); + catch (Exception e) + return e; + return null; +} + +// test GC +__gshared Object root; +void alloc() { root = new Object(); } +void access() { assert(root.toString() !is null); } // vtbl call will fail if finalized +void free() { root = null; } + +Object tls_root; +void tls_alloc() { tls_root = new Object(); } +void tls_access() { assert(tls_root.toString() !is null); } // vtbl call will fail if finalized +void tls_free() { tls_root = null; } + +void stack(alias func)() +{ + // allocate some extra stack space to not keep references to GC memory on the scanned stack + ubyte[1024] buf = void; + func(); +} + +void testGC() +{ + import core.memory; + + stack!alloc(); + stack!tls_alloc(); + stack!access(); + stack!tls_access(); + GC.collect(); + stack!tls_access(); + stack!access(); + stack!tls_free(); + stack!free(); +} + +// test Init +import core.atomic : atomicOp; +shared uint shared_static_ctor, shared_static_dtor, static_ctor, static_dtor; +shared static this() { if (atomicOp!"+="(shared_static_ctor, 1) != 1) assert(0); } +shared static ~this() { if (atomicOp!"+="(shared_static_dtor, 1) != 1) assert(0); } +static this() { atomicOp!"+="(static_ctor, 1); } +static ~this() { atomicOp!"+="(static_dtor, 1); } + +extern(C) int runTests() +{ + try + runTestsImpl(); + catch (Throwable) + return 0; + return 1; +} + +void runTestsImpl() +{ + import core.thread; + + bool passed; + try + throwException(); + catch (Exception e) + passed = true; + assert(passed); + assert(collectException({throwException();}) !is null); + + testGC(); + + assert(shared_static_ctor == 1); + assert(static_ctor == 1); + static void run() + { + assert(static_ctor == 2); + assert(shared_static_ctor == 1); + testGC(); + } + auto thr = new Thread(&run); + thr.start(); + thr.join(); + assert(static_dtor == 1); + + passed = false; + foreach (m; ModuleInfo) + if (m.name == "lib") passed = true; + assert(passed); +} + +// Provide a way to initialize D from C programs that are D agnostic. +import core.runtime : rt_init, rt_term; + +extern(C) int lib_init() +{ + return rt_init(); +} + +extern(C) int lib_term() +{ + return rt_term(); +} + +shared size_t* _finalizeCounter; + +class MyFinalizer +{ + ~this() + { + import core.atomic; + atomicOp!"+="(*_finalizeCounter, 1); + } +} + +class MyFinalizerBig : MyFinalizer +{ + ubyte[4096] _big = void; +} + +extern(C) void setFinalizeCounter(shared(size_t)* p) +{ + _finalizeCounter = p; +} diff --git a/libphobos/testsuite/libphobos.shared/lib_13414.d b/libphobos/testsuite/libphobos.shared/lib_13414.d new file mode 100644 index 0000000..2859438 --- /dev/null +++ b/libphobos/testsuite/libphobos.shared/lib_13414.d @@ -0,0 +1,4 @@ +shared void function() sharedStaticDtorHook; +shared void function() staticDtorHook; +shared static ~this() { sharedStaticDtorHook(); } +static ~this() { staticDtorHook(); } diff --git a/libphobos/testsuite/libphobos.shared/liblinkdep.d b/libphobos/testsuite/libphobos.shared/liblinkdep.d new file mode 100644 index 0000000..c2d2cc6 --- /dev/null +++ b/libphobos/testsuite/libphobos.shared/liblinkdep.d @@ -0,0 +1,6 @@ +import lib; + +extern(C) int runDepTests() +{ + return runTests(); +} diff --git a/libphobos/testsuite/libphobos.shared/libloaddep.d b/libphobos/testsuite/libphobos.shared/libloaddep.d new file mode 100644 index 0000000..93a2dab --- /dev/null +++ b/libphobos/testsuite/libphobos.shared/libloaddep.d @@ -0,0 +1,13 @@ +import core.runtime, core.sys.posix.dlfcn; + +extern(C) alias RunTests = int function(); + +extern(C) int runDepTests(const char* name) +{ + auto h = rt_loadLibrary(name); + if (h is null) return false; + auto runTests = cast(RunTests).dlsym(h, "runTests"); + assert(runTests !is null); + if (!runTests()) return false; + return rt_unloadLibrary(h); +} diff --git a/libphobos/testsuite/libphobos.shared/link.d b/libphobos/testsuite/libphobos.shared/link.d new file mode 100644 index 0000000..433da66 --- /dev/null +++ b/libphobos/testsuite/libphobos.shared/link.d @@ -0,0 +1,64 @@ +import lib; + +void testEH() +{ + bool passed; + try + lib.throwException(); + catch (Exception e) + passed = true; + assert(passed); passed = false; + + assert(lib.collectException({throw new Exception(null);}) !is null); + assert(lib.collectException({lib.throwException();}) !is null); +} + +void testGC() +{ + import core.memory; + lib.alloc(); + lib.tls_alloc(); + lib.access(); + lib.tls_access(); + GC.collect(); + lib.tls_access(); + lib.access(); + lib.tls_free(); + lib.free(); +} + +import core.atomic : atomicOp; +shared static this() { assert(lib.shared_static_ctor == 1); } +shared static ~this() { assert(lib.shared_static_dtor == 0); } +shared uint static_ctor, static_dtor; +static this() { assert(lib.static_ctor == atomicOp!"+="(static_ctor, 1)); } +static ~this() { assert(lib.static_dtor + 1 == atomicOp!"+="(static_dtor, 1)); } + +void testInit() +{ + import core.thread; + + assert(lib.static_ctor == 1); + assert(lib.static_dtor == 0); + static void foo() + { + assert(lib.shared_static_ctor == 1); + assert(lib.shared_static_dtor == 0); + assert(lib.static_ctor == 2); + assert(lib.static_dtor == 0); + } + auto thr = new Thread(&foo); + thr.start(); + assert(thr.join() is null); + assert(lib.shared_static_ctor == 1); + assert(lib.shared_static_dtor == 0); + assert(lib.static_ctor == 2); + assert(lib.static_dtor == 1); +} + +void main() +{ + testEH(); + testGC(); + testInit(); +} diff --git a/libphobos/testsuite/libphobos.shared/linkD.c b/libphobos/testsuite/libphobos.shared/linkD.c new file mode 100644 index 0000000..657c9e8 --- /dev/null +++ b/libphobos/testsuite/libphobos.shared/linkD.c @@ -0,0 +1,14 @@ +#include <stdlib.h> +#include <assert.h> + +extern int runTests(void); +extern int lib_init(void); +extern int lib_term(void); + +int main(int argc, char* argv[]) +{ + if (!lib_init()) return EXIT_SUCCESS; + const int res = runTests() ? EXIT_SUCCESS : EXIT_FAILURE; + if (!lib_term()) return EXIT_FAILURE; + return res; +} diff --git a/libphobos/testsuite/libphobos.shared/linkDR.c b/libphobos/testsuite/libphobos.shared/linkDR.c new file mode 100644 index 0000000..924709c --- /dev/null +++ b/libphobos/testsuite/libphobos.shared/linkDR.c @@ -0,0 +1,28 @@ +#include <stdlib.h> +#include <string.h> +#include <dlfcn.h> +#include <assert.h> + +extern void* rt_loadLibrary(const char*); +extern int rt_unloadLibrary(void*); +extern int rt_init(void); +extern int rt_term(void); + +int main(int argc, char* argv[]) +{ + if (!rt_init()) return EXIT_FAILURE; + const size_t pathlen = strrchr(argv[0], '/') - argv[0] + 1; + char *name = malloc(pathlen + sizeof("lib.so")); + memcpy(name, argv[0], pathlen); + memcpy(name+pathlen, "lib.so", sizeof("lib.so")); + + void *dlib = rt_loadLibrary(name); + free(name); + assert(dlib); + + int (*runTests)(void) = dlsym(dlib, "runTests"); + assert(runTests()); + assert(rt_unloadLibrary(dlib)); + if (!rt_term()) return EXIT_FAILURE; + return EXIT_SUCCESS; +} diff --git a/libphobos/testsuite/libphobos.shared/link_linkdep.d b/libphobos/testsuite/libphobos.shared/link_linkdep.d new file mode 100644 index 0000000..ca72e7e --- /dev/null +++ b/libphobos/testsuite/libphobos.shared/link_linkdep.d @@ -0,0 +1,6 @@ +import liblinkdep; + +void main() +{ + runDepTests(); +} diff --git a/libphobos/testsuite/libphobos.shared/link_loaddep.d b/libphobos/testsuite/libphobos.shared/link_loaddep.d new file mode 100644 index 0000000..8e0c58e --- /dev/null +++ b/libphobos/testsuite/libphobos.shared/link_loaddep.d @@ -0,0 +1,7 @@ +import libloaddep; + +void main(string[] args) +{ + auto libname = args[0][0..$-"link_loaddep".length] ~ "lib.so\0"; + runDepTests(libname.ptr); +} diff --git a/libphobos/testsuite/libphobos.shared/link_mod_collision.d b/libphobos/testsuite/libphobos.shared/link_mod_collision.d new file mode 100644 index 0000000..9c3d1c7 --- /dev/null +++ b/libphobos/testsuite/libphobos.shared/link_mod_collision.d @@ -0,0 +1,5 @@ +module lib; // module collides with lib.so + +void main() +{ +} diff --git a/libphobos/testsuite/libphobos.shared/load.d b/libphobos/testsuite/libphobos.shared/load.d new file mode 100644 index 0000000..8c13f51 --- /dev/null +++ b/libphobos/testsuite/libphobos.shared/load.d @@ -0,0 +1,147 @@ +import core.runtime; +import core.stdc.stdio; +import core.stdc.string; +import core.thread; + +version (linux) import core.sys.linux.dlfcn; +else version (FreeBSD) import core.sys.freebsd.dlfcn; +else version (NetBSD) import core.sys.netbsd.dlfcn; +else static assert(0, "unimplemented"); + +void loadSym(T)(void* handle, ref T val, const char* mangle) +{ + val = cast(T).dlsym(handle, mangle); +} + +void* openLib(string s) +{ + auto h = Runtime.loadLibrary(s); + assert(h !is null); + + loadSym(h, libThrowException, "_D3lib14throwExceptionFZv"); + loadSym(h, libCollectException, "_D3lib16collectExceptionFDFZvZC9Exception"); + + loadSym(h, libAlloc, "_D3lib5allocFZv"); + loadSym(h, libTlsAlloc, "_D3lib9tls_allocFZv"); + loadSym(h, libAccess, "_D3lib6accessFZv"); + loadSym(h, libTlsAccess, "_D3lib10tls_accessFZv"); + loadSym(h, libFree, "_D3lib4freeFZv"); + loadSym(h, libTlsFree, "_D3lib8tls_freeFZv"); + + loadSym(h, libSharedStaticCtor, "_D3lib18shared_static_ctorOk"); + loadSym(h, libSharedStaticDtor, "_D3lib18shared_static_dtorOk"); + loadSym(h, libStaticCtor, "_D3lib11static_ctorOk"); + loadSym(h, libStaticDtor, "_D3lib11static_dtorOk"); + + return h; +} + +void closeLib(void* h) +{ + Runtime.unloadLibrary(h); +} + +__gshared +{ + void function() libThrowException; + Exception function(void delegate()) libCollectException; + + void function() libAlloc; + void function() libTlsAlloc; + void function() libAccess; + void function() libTlsAccess; + void function() libFree; + void function() libTlsFree; + + shared uint* libSharedStaticCtor; + shared uint* libSharedStaticDtor; + shared uint* libStaticCtor; + shared uint* libStaticDtor; +} + +void testEH() +{ + bool passed; + try + libThrowException(); + catch (Exception e) + passed = true; + assert(passed); passed = false; + + assert(libCollectException({throw new Exception(null);}) !is null); + assert(libCollectException({libThrowException();}) !is null); +} + +void testGC() +{ + import core.memory; + libAlloc(); + libTlsAlloc(); + libAccess(); + libTlsAccess(); + GC.collect(); + libTlsAccess(); + libAccess(); + libTlsFree(); + libFree(); +} + +void testInit() +{ + + assert(*libStaticCtor == 1); + assert(*libStaticDtor == 0); + static void run() + { + assert(*libSharedStaticCtor == 1); + assert(*libSharedStaticDtor == 0); + assert(*libStaticCtor == 2); + assert(*libStaticDtor == 0); + } + auto thr = new Thread(&run); + thr.start(); + thr.join(); + assert(*libSharedStaticCtor == 1); + assert(*libSharedStaticDtor == 0); + assert(*libStaticCtor == 2); + assert(*libStaticDtor == 1); +} + +const(ModuleInfo)* findModuleInfo(string name) +{ + foreach (m; ModuleInfo) + if (m.name == name) return m; + return null; +} + +void runTests(string libName) +{ + assert(findModuleInfo("lib") is null); + auto handle = openLib(libName); + assert(findModuleInfo("lib") !is null); + + testEH(); + testGC(); + testInit(); + + closeLib(handle); + assert(findModuleInfo("lib") is null); +} + +void main(string[] args) +{ + auto name = args[0] ~ '\0'; + const pathlen = strrchr(name.ptr, '/') - name.ptr + 1; + name = name[0 .. pathlen] ~ "lib.so"; + + runTests(name); + + // lib is no longer resident + name ~= '\0'; + assert(.dlopen(name.ptr, RTLD_LAZY | RTLD_NOLOAD) is null); + name = name[0 .. $-1]; + + auto thr = new Thread({runTests(name);}); + thr.start(); + thr.join(); +} diff --git a/libphobos/testsuite/libphobos.shared/loadDR.c b/libphobos/testsuite/libphobos.shared/loadDR.c new file mode 100644 index 0000000..08508cbc --- /dev/null +++ b/libphobos/testsuite/libphobos.shared/loadDR.c @@ -0,0 +1,39 @@ +#include <stdlib.h> +#include <string.h> +#include <dlfcn.h> +#include <assert.h> + +int main(int argc, char* argv[]) +{ + if (argc != 2) + return EXIT_FAILURE; + void *h = dlopen(argv[1], RTLD_LAZY); // load druntime + assert(h != NULL); + + int (*rt_init)(void) = dlsym(h, "rt_init"); + int (*rt_term)(void) = dlsym(h, "rt_term"); + void* (*rt_loadLibrary)(const char*) = dlsym(h, "rt_loadLibrary"); + int (*rt_unloadLibrary)(void*) = dlsym(h, "rt_unloadLibrary"); + + int res = EXIT_FAILURE; + if (!rt_init()) goto Lexit; + + const size_t pathlen = strrchr(argv[0], '/') - argv[0] + 1; + char *name = malloc(pathlen + sizeof("lib.so")); + memcpy(name, argv[0], pathlen); + memcpy(name+pathlen, "lib.so", sizeof("lib.so")); + + void *dlib = rt_loadLibrary(name); + free(name); + assert(dlib); + + int (*runTests)(void) = dlsym(dlib, "runTests"); + assert(runTests()); + assert(rt_unloadLibrary(dlib)); + + if (rt_term()) res = EXIT_SUCCESS; + +Lexit: + assert(dlclose(h) == 0); + return res; +} diff --git a/libphobos/testsuite/libphobos.shared/load_13414.d b/libphobos/testsuite/libphobos.shared/load_13414.d new file mode 100644 index 0000000..f7cbf45 --- /dev/null +++ b/libphobos/testsuite/libphobos.shared/load_13414.d @@ -0,0 +1,30 @@ +import core.runtime; +import core.atomic; +import core.stdc.string; +import core.sys.posix.dlfcn; + +shared uint tlsDtor, dtor; +void staticDtorHook() { atomicOp!"+="(tlsDtor, 1); } +void sharedStaticDtorHook() { atomicOp!"+="(dtor, 1); } + +void runTest(string name) +{ + auto h = Runtime.loadLibrary(name); + assert(h !is null); + + *cast(void function()*).dlsym(h, "_D9lib_1341414staticDtorHookOPFZv") = &staticDtorHook; + *cast(void function()*).dlsym(h, "_D9lib_1341420sharedStaticDtorHookOPFZv") = &sharedStaticDtorHook; + + Runtime.unloadLibrary(h); + assert(tlsDtor == 1); + assert(dtor == 1); +} + +void main(string[] args) +{ + auto name = args[0] ~ '\0'; + const pathlen = strrchr(name.ptr, '/') - name.ptr + 1; + name = name[0 .. pathlen] ~ "lib_13414.so"; + + runTest(name); +} diff --git a/libphobos/testsuite/libphobos.shared/load_linkdep.d b/libphobos/testsuite/libphobos.shared/load_linkdep.d new file mode 100644 index 0000000..5f5dcf2 --- /dev/null +++ b/libphobos/testsuite/libphobos.shared/load_linkdep.d @@ -0,0 +1,18 @@ +import core.runtime; +import core.stdc.string; +import core.sys.posix.dlfcn; + +extern(C) alias RunDepTests = int function(); + +void main(string[] args) +{ + auto name = args[0] ~ '\0'; + const pathlen = strrchr(name.ptr, '/') - name.ptr + 1; + name = name[0 .. pathlen] ~ "liblinkdep.so"; + + auto h = Runtime.loadLibrary(name); + assert(h); + auto runDepTests = cast(RunDepTests)dlsym(h, "runDepTests"); + assert(runDepTests()); + assert(Runtime.unloadLibrary(h)); +} diff --git a/libphobos/testsuite/libphobos.shared/load_loaddep.d b/libphobos/testsuite/libphobos.shared/load_loaddep.d new file mode 100644 index 0000000..c189683e --- /dev/null +++ b/libphobos/testsuite/libphobos.shared/load_loaddep.d @@ -0,0 +1,17 @@ +import core.runtime; +import core.stdc.string; +import core.sys.posix.dlfcn; + +extern(C) alias RunDepTests = int function(const char*); + +void main(string[] args) +{ + auto name = args[0] ~ '\0'; + const pathlen = strrchr(name.ptr, '/') - name.ptr + 1; + auto root = name[0 .. pathlen]; + auto libloaddep = root ~ "libloaddep.so"; + auto h = Runtime.loadLibrary(libloaddep); + auto runDepTests = cast(RunDepTests)dlsym(h, "runDepTests"); + assert(runDepTests((root ~ "lib.so\0").ptr)); + assert(Runtime.unloadLibrary(h)); +} diff --git a/libphobos/testsuite/libphobos.shared/load_mod_collision.d b/libphobos/testsuite/libphobos.shared/load_mod_collision.d new file mode 100644 index 0000000..64243d4 --- /dev/null +++ b/libphobos/testsuite/libphobos.shared/load_mod_collision.d @@ -0,0 +1,14 @@ +module lib; // module collides with lib.so + +import core.runtime; +import core.stdc.stdio; +import core.stdc.string; +import core.sys.posix.dlfcn; + +void main(string[] args) +{ + auto name = args[0] ~ '\0'; + const pathlen = strrchr(name.ptr, '/') - name.ptr + 1; + name = name[0 .. pathlen] ~ "lib.so"; + auto lib = Runtime.loadLibrary(name); +} diff --git a/libphobos/testsuite/libphobos.shared/plugin.d b/libphobos/testsuite/libphobos.shared/plugin.d new file mode 100644 index 0000000..74d6601 --- /dev/null +++ b/libphobos/testsuite/libphobos.shared/plugin.d @@ -0,0 +1,73 @@ +import core.thread, core.memory, core.atomic; + +// test init +shared uint gctor, gdtor, tctor, tdtor; +shared static this() { if (atomicOp!"+="(gctor, 1) != 1) assert(0); } +shared static ~this() { if (atomicOp!"+="(gdtor, 1) != 1) assert(0); } +static this() { atomicOp!"+="(tctor, 1); } +static ~this() { atomicOp!"+="(tdtor, 1); } + +// test GC +__gshared Object root; +void alloc() { root = new Object(); } +void access() { assert(root.toString() !is null); } // vtbl call will fail if finalized +void free() { root = null; } + +Object tls_root; +void tls_alloc() { tls_root = new Object(); } +void tls_access() { assert(tls_root.toString() !is null); } // vtbl call will fail if finalized +void tls_free() { tls_root = null; } + +void stack(alias func)() +{ + // allocate some extra stack space to not keep references to GC memory on the scanned stack + ubyte[1024] buf = void; + func(); +} + +void testGC() +{ + import core.memory; + + stack!alloc(); + stack!tls_alloc(); + stack!access(); + stack!tls_access(); + GC.collect(); + stack!tls_access(); + stack!access(); + stack!tls_free(); + stack!free(); +} + +extern(C) int runTests() +{ + try + { + assert(atomicLoad!(MemoryOrder.acq)(gctor) == 1); + assert(atomicLoad!(MemoryOrder.acq)(gdtor) == 0); + assert(atomicLoad!(MemoryOrder.acq)(tctor) >= 1); + assert(atomicLoad!(MemoryOrder.acq)(tdtor) >= 0); + // test some runtime functionality + testGC(); + new Thread(&testGC).start.join; + } + catch (Throwable) + { + return false; + } + return true; +} + +// Provide a way to initialize D from C programs that are D agnostic. +import core.runtime : rt_init, rt_term; + +extern(C) int plugin_init() +{ + return rt_init(); +} + +extern(C) int plugin_term() +{ + return rt_term(); +} diff --git a/libphobos/testsuite/libphobos.shared/shared.exp b/libphobos/testsuite/libphobos.shared/shared.exp new file mode 100644 index 0000000..5555b3b --- /dev/null +++ b/libphobos/testsuite/libphobos.shared/shared.exp @@ -0,0 +1,108 @@ +# Copyright (C) 2017-2018 Free Software Foundation, Inc. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with GCC; see the file COPYING3. If not see +# <http://www.gnu.org/licenses/>. + +load_lib libphobos-dg.exp + +# Immediately exit if target doesn't support shared. +if { ![is-effective-target shared] } { + return +} + +# If a testcase doesn't have special options, use these. +if ![info exists DEFAULT_CFLAGS] then { + set DEFAULT_CFLAGS "-g" +} + +# +# Build all shared libraries, used as dependencies for other tests. +# + +proc shared_library { source destfile options } { + global DEFAULT_DFLAGS + global all_libraries + + # Compiling with -fno-gnu-unique as tests call dlopen/dlclose multiple times on the same library. + lappend options "additional_flags=$DEFAULT_DFLAGS -fno-gnu-unique -fpic -shared -shared-libphobos" + + set comp_output [libphobos_target_compile "$source" "$destfile" "executable" $options] + if ![ string match "" $comp_output ] { + fail "libphobos.shared/[file tail $source]" + verbose -log $comp_output + return 1 + } + + lappend all_libraries $destfile +} + +# lib.so +shared_library "$srcdir/$subdir/lib.d" "lib.so" "" + +# liblinkdep.so +shared_library "$srcdir/$subdir/liblinkdep.d" "liblinkdep.so" \ + [list "additional_flags=-I$srcdir/$subdir lib.so"] + +# libloaddep.so +shared_library "$srcdir/$subdir/libloaddep.d" "libloaddep.so" "" + +# lib_13414.so +shared_library "$srcdir/$subdir/lib_13414.d" "lib_13414.so" "" + +# plugin.so +shared_library "$srcdir/$subdir/plugin.d" "plugin1.so" "" +shared_library "$srcdir/$subdir/plugin.d" "plugin2.so" "" + +# Initialize dg. +dg-init + +# Main loop. +dg-test "$srcdir/$subdir/link.d" "-I$srcdir/$subdir lib.so -shared-libphobos" \ + "$DEFAULT_DFLAGS" + +dg-test "$srcdir/$subdir/link_linkdep.d" \ + "-I$srcdir/$subdir liblinkdep.so lib.so -shared-libphobos" \ + "$DEFAULT_DFLAGS" + +dg-test "$srcdir/$subdir/link_loaddep.d" \ + "-I$srcdir/$subdir libloaddep.so -shared-libphobos" "$DEFAULT_DFLAGS" + +# dlopen() tests. +if [is-effective-target dlopen] { + dg-test "$srcdir/$subdir/load.d" "-shared-libphobos -ldl" "$DEFAULT_DFLAGS" + dg-test "$srcdir/$subdir/load_linkdep.d" "-shared-libphobos -ldl" "$DEFAULT_DFLAGS" + dg-test "$srcdir/$subdir/load_loaddep.d" "-shared-libphobos -ldl" "$DEFAULT_DFLAGS" + dg-test "$srcdir/$subdir/load_13414.d" "-shared-libphobos -ldl" "$DEFAULT_DFLAGS" + dg-test "$srcdir/$subdir/finalize.d" "-shared-libphobos -ldl" "$DEFAULT_DFLAGS" +} + +# C program link tests. +if { [is-effective-target dlopen] && [is-effective-target pthread] } { + dg-test "$srcdir/$subdir/linkD.c" "lib.so -ldl -pthread" "$DEFAULT_CFLAGS" + dg-test "$srcdir/$subdir/linkDR.c" "-shared-libphobos -ldl -pthread" "$DEFAULT_CFLAGS" + dg-test "$srcdir/$subdir/host.c" "-ldl -pthread" "$DEFAULT_CFLAGS" + + # Test requires a command line argument to be passed to the program. + set libphobos_run_args "$objdir/../src/.libs/libgphobos.so" + dg-test "$srcdir/$subdir/loadDR.c" "-ldl -pthread -g" "$DEFAULT_CFLAGS" + set libphobos_run_args "" +} + +# All done. +dg-finish + +# Remove all libraries built before running tests. +foreach lib $all_libraries { + catch "file delete -force -- $lib" +} |