diff --git a/nativelib/src/main/resources/gc/boehm/gc.c b/nativelib/src/main/resources/gc/boehm/gc.c index d5719573a7b..81913e9a877 100644 --- a/nativelib/src/main/resources/gc/boehm/gc.c +++ b/nativelib/src/main/resources/gc/boehm/gc.c @@ -1,26 +1,24 @@ #include +#include +#include // At the moment we rely on the conservative // mode of Boehm GC as our garbage collector. -void scalanative_init() { - GC_init(); -} +void scalanative_init() { GC_init(); } -void* scalanative_alloc(void* info, size_t size) { - void** alloc = (void**) GC_malloc(size); +void *scalanative_alloc(void *info, size_t size) { + void **alloc = (void **)GC_malloc(size); *alloc = info; - return (void*) alloc; + return (void *)alloc; } -void* scalanative_alloc_raw(size_t size) { - return GC_malloc(size); -} +void *scalanative_alloc_raw(size_t size) { return GC_malloc(size); } -void* scalanative_alloc_raw_atomic(size_t size) { +void *scalanative_alloc_raw_atomic(size_t size) { return GC_malloc_atomic(size); } -void scalanative_collect() { - GC_gcollect(); -} +void scalanative_collect() { GC_gcollect(); } + +void scalanative_safepoint() {} diff --git a/nativelib/src/main/resources/gc/none/gc.c b/nativelib/src/main/resources/gc/none/gc.c index 8f6920d17fe..cf04a95a00b 100644 --- a/nativelib/src/main/resources/gc/none/gc.c +++ b/nativelib/src/main/resources/gc/none/gc.c @@ -9,7 +9,7 @@ // Dummy GC that maps chunks of 4GB and allocates but never frees. // Map 4GB -#define CHUNK (4*1024*1024*1024L) +#define CHUNK (4 * 1024 * 1024 * 1024L) // Allow read and write #define DUMMY_GC_PROT (PROT_READ | PROT_WRITE) // Map private anonymous memory, and prevent from reserving swap @@ -18,20 +18,22 @@ #define DUMMY_GC_FD -1 #define DUMMY_GC_FD_OFFSET 0 +void *current = 0; +void *end = 0; -void* current = 0; -void* end = 0; - +void scalanative_safepoint_init(); void scalanative_init() { - current = mmap(NULL, CHUNK, DUMMY_GC_PROT, DUMMY_GC_FLAGS, DUMMY_GC_FD, DUMMY_GC_FD_OFFSET); + current = mmap(NULL, CHUNK, DUMMY_GC_PROT, DUMMY_GC_FLAGS, DUMMY_GC_FD, + DUMMY_GC_FD_OFFSET); end = current + CHUNK; + scalanative_safepoint_init(); } -void* scalanative_alloc_raw(size_t size) { +void *scalanative_alloc_raw(size_t size) { size = size + (8 - size % 8); if (current != 0 && current + size < end) { - void* alloc = current; + void *alloc = current; current += size; return alloc; } else { @@ -40,14 +42,16 @@ void* scalanative_alloc_raw(size_t size) { } } -void* scalanative_alloc_raw_atomic(size_t size) { +void *scalanative_alloc_raw_atomic(size_t size) { return scalanative_alloc_raw(size); } -void* scalanative_alloc(void* info, size_t size) { - void** alloc = (void**) scalanative_alloc_raw(size); +void *scalanative_alloc(void *info, size_t size) { + void **alloc = (void **)scalanative_alloc_raw(size); *alloc = info; - return (void*) alloc; + return (void *)alloc; } void scalanative_collect() {} + +void scalanative_safepoint() {} diff --git a/nativelib/src/main/resources/safepoint.c b/nativelib/src/main/resources/safepoint.c new file mode 100644 index 00000000000..b17aab2899e --- /dev/null +++ b/nativelib/src/main/resources/safepoint.c @@ -0,0 +1,34 @@ +#include +#include +#include +#include + +extern unsigned char scalanative_safepoint_trigger[4096] __attribute__((aligned(4096))); + +void scalanative_safepoint(); + +void scalanative_safepoint_on() { + mprotect((void*) &scalanative_safepoint_trigger, 4096, PROT_NONE); +} + +void scalanative_safepoint_off() { + mprotect((void*) &scalanative_safepoint_trigger, 4096, PROT_READ); +} + +void scalanative_safepoint_handler(int sig, siginfo_t *info, void *ucontext) { + if (info->si_addr == (void*) &scalanative_safepoint_trigger) { + scalanative_safepoint(); + } else { + printf("Segfault %d at %p", sig, info->si_addr); + exit(1); + } +} + +void scalanative_safepoint_init() { + struct sigaction action; + action.sa_sigaction = scalanative_safepoint_handler; + action.sa_flags = SA_RESTART | SA_SIGINFO; + sigemptyset(&action.sa_mask); + sigaction(SIGSEGV, &action, NULL); + sigaction(SIGBUS, &action, NULL); +} diff --git a/tools/src/main/scala/scala/scalanative/optimizer/Driver.scala b/tools/src/main/scala/scala/scalanative/optimizer/Driver.scala index 5ecbf51a9d4..135aead2f1c 100644 --- a/tools/src/main/scala/scala/scalanative/optimizer/Driver.scala +++ b/tools/src/main/scala/scala/scalanative/optimizer/Driver.scala @@ -21,8 +21,8 @@ object Driver { inject.RuntimeTypeInformation, inject.ClassStruct, inject.ObjectArrayId, - inject.ModuleArray, - inject.SafepointTrigger + inject.ModuleArray + // inject.SafepointTrigger ) private val fastOptPasses = Seq( @@ -61,8 +61,8 @@ object Driver { pass.AllocLowering, pass.SizeofLowering, pass.CopyPropagation, - pass.DeadCodeElimination, - pass.SafepointInsertion + pass.DeadCodeElimination + // pass.SafepointInsertion ) /** Create driver with default pipeline for this configuration. */ diff --git a/tools/src/main/scala/scala/scalanative/optimizer/inject/SafepointTrigger.scala b/tools/src/main/scala/scala/scalanative/optimizer/inject/SafepointTrigger.scala new file mode 100644 index 00000000000..ae77fcdaa23 --- /dev/null +++ b/tools/src/main/scala/scala/scalanative/optimizer/inject/SafepointTrigger.scala @@ -0,0 +1,27 @@ +package scala.scalanative.optimizer.inject + +import scala.collection.mutable +import scala.scalanative.nir._ +import scala.scalanative.optimizer.analysis.ClassHierarchy.Top +import scala.scalanative.optimizer.{Inject, InjectCompanion} +import scala.scalanative.tools.Config + +class SafepointTrigger(top: Top) extends Inject { + import SafepointTrigger._ + + override def apply(buf: mutable.Buffer[Defn]) = + buf += safepointTriggerDefn +} + +object SafepointTrigger extends InjectCompanion { + val safepointTriggerName = Global.Top("scalanative_safepoint_trigger") + val safepointTriggerTy = Type.Array(Type.Byte, 4096) + val safepointTriggerInit = Val.Zero(safepointTriggerTy) + val safepointTriggerDefn = + Defn.Var(Attrs(align = Some(4096)), + safepointTriggerName, + safepointTriggerTy, + safepointTriggerInit) + + override def apply(config: Config, top: Top) = new SafepointTrigger(top) +} diff --git a/tools/src/main/scala/scala/scalanative/optimizer/pass/SafepointInsertion.scala b/tools/src/main/scala/scala/scalanative/optimizer/pass/SafepointInsertion.scala new file mode 100755 index 00000000000..1b17bf0458d --- /dev/null +++ b/tools/src/main/scala/scala/scalanative/optimizer/pass/SafepointInsertion.scala @@ -0,0 +1,50 @@ +package scala.scalanative +package optimizer +package pass + +import scala.collection.mutable +import analysis.ClassHierarchy.Top +import nir._ + +/** Inserts safepoint probes before every return. */ +class SafepointInsertion(implicit fresh: Fresh) extends Pass { + import SafepointInsertion._ + + override def onDefns(defns: Seq[Defn]): Seq[Defn] = { + val buf = mutable.UnrolledBuffer.empty[Defn] + + defns.foreach { + case defn: Defn.Define if defn.attrs.inline ne Attr.AlwaysInline => + buf += defn.copy(insts = onInsts(defn.insts)) + + case defn => + buf += defn + } + + buf + } + + override def onInsts(insts: Seq[Inst]): Seq[Inst] = { + val buf = new nir.Buffer + import buf._ + + insts.foreach { + case inst: Inst.Ret => + let(Op.Load(Type.Byte, safepointTriggerVal, isVolatile = true)) + buf += inst + + case inst => + buf += inst + } + + buf.toSeq + } +} + +object SafepointInsertion extends PassCompanion { + val safepointTriggerName = Global.Top("scalanative_safepoint_trigger") + val safepointTriggerVal = Val.Global(safepointTriggerName, Type.Ptr) + + override def apply(config: tools.Config, top: Top) = + new SafepointInsertion()(top.fresh) +}