Skip to content

Commit 159134b

Browse files
committed
Add @foreignExport
Makes an object method available as a native function with the specified name
1 parent 89acba2 commit 159134b

File tree

2 files changed

+45
-0
lines changed

2 files changed

+45
-0
lines changed

src/compiler/scala/tools/nsc/backend/llvm/GenLLVM.scala

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ abstract class GenLLVM extends SubComponent {
4444
val LlvmdefsAnnotSym = definitions.getClass("scala.llvmdefs")
4545
val ForeignAnnotSym = definitions.getClass("scala.ffi.foreign")
4646
val ForeignValueAnnotSym = definitions.getClass("scala.ffi.foreignValue")
47+
val ForeignExportAnnotSym = definitions.getClass("scala.ffi.foreignExport")
4748
val CodegenAnnotations = Set(LlvmimplAnnotSym, ForeignAnnotSym, ForeignValueAnnotSym)
4849
val PtrSym = definitions.getClass("scala.ffi.Ptr")
4950
val PtrObjSym = PtrSym.companionModule
@@ -732,6 +733,47 @@ abstract class GenLLVM extends SubComponent {
732733
}
733734
}
734735

736+
def exportFunction(m: IMethod): Seq[ModuleComp] = {
737+
m.symbol.getAnnotation(ForeignExportAnnotSym) match {
738+
case Some(AnnotationInfo(_,List(Literal(Constant(foreignSymbol: String))),_)) => {
739+
val methType = m.symbol.info
740+
if (!m.symbol.isStatic) {
741+
error("Only object methods can be exported"); Seq.empty
742+
} else if (methType.paramSectionCount != 1) {
743+
error("Exported functions must take exactly one parameter list"); Seq.empty
744+
} else if (!isMarshallableResult(methType.resultType)) {
745+
error("Exported functions must have marshallable return type"); Seq.empty
746+
} else if (methType.paramTypes.exists(pt => !isMarshallable(pt))) {
747+
error("All parameters to exported functions must be marshallable"); Seq.empty
748+
} else {
749+
val args = m.params.map(p => new LocalVariable(llvmName(p.sym), marshalledType(p.sym.info)))
750+
val argSpec = args.map(lv => ArgSpec(lv))
751+
val exportedFun = new LMFunction(
752+
typeKindType(m.returnType), foreignSymbol, argSpec, false,
753+
Externally_visible, Default, Ccc,
754+
Seq.empty, Seq.empty, None, None, None)
755+
val methodFun = functionForMethod(m)._1
756+
val modGlobal = new CGlobalAddress(externModule(m.symbol.enclClass))
757+
val body = if (m.returnType == UNIT) {
758+
Seq(
759+
new call_void(moduleInitFun(m.symbol.owner), Seq.empty),
760+
new call_void(methodFun, Seq(modGlobal) ++ args),
761+
retvoid
762+
)
763+
} else {
764+
val result = new LocalVariable(".result", typeKindType(m.returnType))
765+
Seq(
766+
new call_void(moduleInitFun(m.symbol.owner), Seq.empty),
767+
new call(result, methodFun, Seq(modGlobal) ++ args),
768+
new ret(result)
769+
)
770+
}
771+
Seq(exportedFun.define(Seq(LMBlock(None, body))))
772+
}
773+
}
774+
}
775+
}
776+
735777
def genForeignFun(m: IMethod): Seq[ModuleComp] = {
736778
m.symbol.getAnnotation(ForeignAnnotSym) match {
737779
case Some(AnnotationInfo(_,List(Literal(Constant(foreignSymbol: String))),_)) => {
@@ -1716,6 +1758,7 @@ abstract class GenLLVM extends SubComponent {
17161758
c.methods.filter(_.native).map(_.symbol).foreach(externFun)
17171759
val externDecls = externFuns.filterKeys(!internalFuns.contains(_)).values.map(_.declare)++externClasses.values.map(_.declare)++externStatics.values.map(_.declare)
17181760
val otherModules = externModules.filterKeys(_.moduleClass!=c.symbol)
1761+
val exportedFunctions = c.methods.filter(_.symbol.hasAnnotation(ForeignExportAnnotSym)).flatMap(exportFunction)
17191762
val module = new Module(Seq.concat(
17201763
Seq(header_comment),
17211764
externTypes.values.map {
@@ -1729,6 +1772,7 @@ abstract class GenLLVM extends SubComponent {
17291772
classInfo,
17301773
methodFuns,
17311774
llvmmethodFuns,
1775+
exportedFunctions,
17321776
foreignFuns,
17331777
foreignVals,
17341778
extraDefs,

src/llvm-ffi/scala/ffi/foreign.scala

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,4 @@ package scala.ffi
22

33
class foreign(name: String) extends StaticAnnotation
44
class foreignValue(name: String) extends StaticAnnotation
5+
class foreignExport(name: String) extends StaticAnnotation

0 commit comments

Comments
 (0)