Skip to content

Commit

Permalink
Preliminary support for segfault-based safepoints
Browse files Browse the repository at this point in the history
  • Loading branch information
densh committed May 8, 2017
1 parent 206f28e commit 9c6f256
Show file tree
Hide file tree
Showing 6 changed files with 141 additions and 28 deletions.
24 changes: 11 additions & 13 deletions nativelib/src/main/resources/gc/boehm/gc.c
@@ -1,26 +1,24 @@
#include <gc.h>
#include <stdlib.h>
#include <stdio.h>

// 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() {}
26 changes: 15 additions & 11 deletions nativelib/src/main/resources/gc/none/gc.c
Expand Up @@ -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
Expand All @@ -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 {
Expand All @@ -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() {}
34 changes: 34 additions & 0 deletions nativelib/src/main/resources/safepoint.c
@@ -0,0 +1,34 @@
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/mman.h>

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);
}
8 changes: 4 additions & 4 deletions tools/src/main/scala/scala/scalanative/optimizer/Driver.scala
Expand Up @@ -21,8 +21,8 @@ object Driver {
inject.RuntimeTypeInformation,
inject.ClassStruct,
inject.ObjectArrayId,
inject.ModuleArray,
inject.SafepointTrigger
inject.ModuleArray
// inject.SafepointTrigger
)

private val fastOptPasses = Seq(
Expand Down Expand Up @@ -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. */
Expand Down
@@ -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)
}
@@ -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)
}

0 comments on commit 9c6f256

Please sign in to comment.