Skip to content

Commit

Permalink
fix: Ensure to always call monitorEnter and monitorExit statically (#…
Browse files Browse the repository at this point in the history
…3773)

* Ensure to always call monitorEnter and monitorExit statically to make their detection and optimization easier in the future.

* Fix Scala 2 compilation, allow to generate static forwarders for methods with access boundary as it is done in Scala 3

* [ci-skip] clean nscplugin
  • Loading branch information
WojciechMazur committed Feb 16, 2024
1 parent c5b6458 commit e24a9dc
Show file tree
Hide file tree
Showing 8 changed files with 144 additions and 48 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ object NativeThread {
@alwaysinline def onSpinWait(): Unit = Platform.yieldProcessor()

@inline def holdsLock(obj: Object): Boolean = if (isMultithreadingEnabled) {
getMonitor(obj).isLockedBy(currentThread)
getMonitor(obj.asInstanceOf[_Object]).isLockedBy(currentThread)
} else false

def threadRoutineArgs(thread: NativeThread): ThreadRoutineArg =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,24 +20,25 @@ package object runtime {
/** Used as a stub right hand of intrinsified methods. */
private[scalanative] def intrinsic: Nothing = throwUndefined()

// Called statically by the compiler, do not modify!
/** Enter monitor of given object. */
@alwaysinline
def enterMonitor(obj: Object): Unit =
private[runtime] def enterMonitor(obj: _Object): Unit =
if (isMultithreadingEnabled) {
getMonitor(obj).enter(obj)
}

// Called statically by the compiler, do not modify!
/** Enter monitor of given object. */

@alwaysinline
def exitMonitor(obj: Object): Unit =
private[runtime] def exitMonitor(obj: _Object): Unit =
if (isMultithreadingEnabled) {
getMonitor(obj).exit(obj)
}

/** Get monitor for given object. */
@alwaysinline
def getMonitor(obj: Object) = {
def getMonitor(obj: _Object) = {
if (isMultithreadingEnabled)
new BasicMonitor(
elemRawPtr(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ trait NirGenExpr[G <: nsc.Global with Singleton] { self: NirGenPhase[G] =>
import SimpleType.{fromType, fromSymbol}

sealed case class ValTree(value: nir.Val) extends Tree
sealed case class ContTree(f: () => nir.Val) extends Tree
sealed case class ContTree(f: ExprBuffer => nir.Val) extends Tree

class FixupBuffer(implicit fresh: nir.Fresh) extends nir.InstructionBuilder {
private var labeled = false
Expand Down Expand Up @@ -60,7 +60,7 @@ trait NirGenExpr[G <: nsc.Global with Singleton] { self: NirGenPhase[G] =>
case ValTree(value) =>
value
case ContTree(f) =>
f()
f(this)
case tree: Block =>
genBlock(tree)
case tree: LabelDef =>
Expand Down Expand Up @@ -359,8 +359,8 @@ trait NirGenExpr[G <: nsc.Global with Singleton] { self: NirGenPhase[G] =>
buf.genIf(
retty = retty,
condp = ValTree(cond),
thenp = ContTree(() => genExpr(body)),
elsep = ContTree(() => loop(elsep))
thenp = ContTree(_.genExpr(body)),
elsep = ContTree(_ => loop(elsep))
)

case Nil => optDefaultLabel.getOrElse(genExpr(defaultp))
Expand Down Expand Up @@ -458,7 +458,7 @@ trait NirGenExpr[G <: nsc.Global with Singleton] { self: NirGenPhase[G] =>
case Bind(_, _) =>
(genType(pat.symbol.tpe), Some(pat.symbol))
}
val f = { () =>
val f = ContTree { (buf: ExprBuffer) =>
withFreshBlockScope(body.pos) { _ =>
symopt.foreach { sym =>
val cast = buf.as(excty, exc, unwind)
Expand All @@ -474,7 +474,7 @@ trait NirGenExpr[G <: nsc.Global with Singleton] { self: NirGenPhase[G] =>
}

def wrap(
cases: Seq[(nir.Type, () => nir.Val, nir.SourcePosition)]
cases: Seq[(nir.Type, ContTree, nir.SourcePosition)]
): nir.Val =
cases match {
case Seq() =>
Expand All @@ -485,8 +485,8 @@ trait NirGenExpr[G <: nsc.Global with Singleton] { self: NirGenPhase[G] =>
genIf(
retty,
ValTree(cond),
ContTree(f),
ContTree(() => wrap(rest))
f,
ContTree(_ => wrap(rest))
)(pos)
}

Expand Down Expand Up @@ -613,7 +613,6 @@ trait NirGenExpr[G <: nsc.Global with Singleton] { self: NirGenPhase[G] =>
def genArrayValue(tpt: Tree, elems: Seq[Tree])(implicit
pos: nir.SourcePosition
): nir.Val = {
// println(s"array[${tpt.tpe}]: {${elems.mkString(", ")}}")
val elemty = genType(tpt.tpe)
val values = genSimpleArgs(elems)

Expand Down Expand Up @@ -1107,7 +1106,7 @@ trait NirGenExpr[G <: nsc.Global with Singleton] { self: NirGenPhase[G] =>
params.size == 2 && params.head.tpe.typeSymbol == IntClass
}

def genDynCall(arrayUpdate: Boolean) = {
def genDynCall(arrayUpdate: Boolean)(buf: ExprBuffer) = {

// In the case of an array update we need to manually erase the return type.
val methodName: nir.Sig =
Expand Down Expand Up @@ -1148,7 +1147,7 @@ trait NirGenExpr[G <: nsc.Global with Singleton] { self: NirGenPhase[G] =>

// If the signature matches an array update, tests at runtime if it really is an array update.
if (isArrayLikeOp) {
val cond = ContTree { () =>
val cond = ContTree { (buf: ExprBuffer) =>
buf.is(
nir.Type.Ref(
nir.Global.Top("scala.scalanative.runtime.ObjectArray")
Expand All @@ -1157,8 +1156,8 @@ trait NirGenExpr[G <: nsc.Global with Singleton] { self: NirGenPhase[G] =>
unwind
)
}
val thenp = ContTree { () => genDynCall(arrayUpdate = true) }
val elsep = ContTree { () => genDynCall(arrayUpdate = false) }
val thenp = ContTree(genDynCall(arrayUpdate = true))
val elsep = ContTree(genDynCall(arrayUpdate = false))
genIf(
nir.Type.Ref(nir.Global.Top("java.lang.Object")),
cond,
Expand All @@ -1167,7 +1166,7 @@ trait NirGenExpr[G <: nsc.Global with Singleton] { self: NirGenPhase[G] =>
)

} else {
genDynCall(arrayUpdate = false)
genDynCall(arrayUpdate = false)(this)
}
}

Expand Down Expand Up @@ -2586,8 +2585,10 @@ trait NirGenExpr[G <: nsc.Global with Singleton] { self: NirGenPhase[G] =>
val mergen = fresh()

// scalanative.runtime.`package`.enterMonitor(receiver)
genExpr(
treeBuild.mkMethodCall(RuntimeEnterMonitorMethod, List(receiverp))
genApplyStaticMethod(
sym = RuntimeEnterMonitorMethod,
receiver = RuntimePackageClass,
argsp = List(receiverp)
)
// synchronized block
val retValue = scoped(curUnwindHandler := Some(handler)) {
Expand All @@ -2610,8 +2611,13 @@ trait NirGenExpr[G <: nsc.Global with Singleton] { self: NirGenPhase[G] =>
buf.jump(nir.Next(normaln))
buf ++= genTryFinally(
// scalanative.runtime.`package`.exitMonitor(receiver)
finallyp =
treeBuild.mkMethodCall(RuntimeExitMonitorMethod, List(receiverp)),
finallyp = ContTree(
_.genApplyStaticMethod(
sym = RuntimeExitMonitorMethod,
receiver = RuntimePackageClass,
argsp = List(receiverp)
)
),
insts = nested.toSeq
)
val mergev = nir.Val.Local(fresh(), retty)
Expand Down Expand Up @@ -2860,7 +2866,7 @@ trait NirGenExpr[G <: nsc.Global with Singleton] { self: NirGenPhase[G] =>
require(!sym.isExtern, sym.owner)
val name = genStaticMemberName(sym, receiver)
val method = nir.Val.Global(name, nir.Type.Ptr)
val sig = genMethodSig(sym)
val sig = genMethodSig(sym, statically = true)
val args = genMethodArgs(sym, argsp)
buf.call(sig, method, args, unwind)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1200,9 +1200,7 @@ trait NirGenStat[G <: nsc.Global with Singleton] { self: NirGenPhase[G] =>
(o eq ObjectClass) || (o eq AnyRefClass) || (o eq AnyClass)
}

m.isDeferred || m.isConstructor || m.hasAccessBoundary ||
m.isExtern ||
isOfJLObject
m.isDeferred || m.isConstructor || m.isExtern || isOfJLObject
}

val forwarders = for {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -208,15 +208,19 @@ trait NirGenType[G <: Global with Singleton] { self: NirGenPhase[G] =>
case _ => 'O'
}

def genMethodSig(sym: Symbol): nir.Type.Function =
genMethodSigImpl(sym, isExtern = false)
def genMethodSig(
sym: Symbol,
statically: Boolean = false
): nir.Type.Function =
genMethodSigImpl(sym, statically = statically, isExtern = false)

def genExternMethodSig(sym: Symbol): nir.Type.Function =
genMethodSigImpl(sym, isExtern = true)
genMethodSigImpl(sym, isExtern = true, statically = true)

private def genMethodSigImpl(
sym: Symbol,
isExtern: Boolean
isExtern: Boolean,
statically: Boolean
): nir.Type.Function = {
def resolve() = {
require(sym.isMethod || sym.isStaticMember, "symbol is not a method")
Expand All @@ -225,7 +229,7 @@ trait NirGenType[G <: Global with Singleton] { self: NirGenPhase[G] =>
val owner = sym.owner
val paramtys = genMethodSigParamsImpl(sym, isExtern)
val selfty =
if (isExtern || sym.isStaticInNIR) None
if (statically | isExtern || sym.isStaticInNIR) None
else Some(genType(owner.tpe))
val retty =
if (sym.isClassConstructor) nir.Type.Unit
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ trait NirGenExpr(using Context) {
import positionsConversions.fromSpan

sealed case class ValTree(value: nir.Val) extends Tree
sealed case class ContTree(f: () => nir.Val) extends Tree
sealed case class ContTree(f: ExprBuffer => nir.Val) extends Tree

class ExprBuffer(using fresh: nir.Fresh) extends FixupBuffer {
buf =>
Expand All @@ -49,7 +49,7 @@ trait NirGenExpr(using Context) {
tree match {
case EmptyTree => nir.Val.Unit
case ValTree(value) => value
case ContTree(f) => f()
case ContTree(f) => f(this)
case tree: Apply =>
val updatedTree = lazyValsAdapter.transformApply(tree)
genApply(updatedTree)
Expand Down Expand Up @@ -679,8 +679,8 @@ trait NirGenExpr(using Context) {
buf.genIf(
retty = retty,
condp = ValTree(cond),
thenp = ContTree(() => genExpr(body)),
elsep = ContTree(() => loop(elsep))
thenp = ContTree(_.genExpr(body)),
elsep = ContTree(_ => loop(elsep))
)

case Nil => optDefaultLabel.getOrElse(genExpr(defaultp))
Expand Down Expand Up @@ -867,7 +867,7 @@ trait NirGenExpr(using Context) {
case Bind(_, _) =>
genType(pat.tpe) -> Some(pat.symbol)
}
val f = { () =>
val f = ContTree { (buf: ExprBuffer) =>
withFreshBlockScope(body.span) { _ =>
symopt.foreach { sym =>
val cast = buf.as(excty, exc, unwind)(cd.span, getScopeId)
Expand All @@ -883,7 +883,7 @@ trait NirGenExpr(using Context) {
}

def wrap(
cases: Seq[(nir.Type, () => nir.Val, nir.SourcePosition)]
cases: Seq[(nir.Type, ContTree, nir.SourcePosition)]
): nir.Val =
cases match {
case Seq() =>
Expand All @@ -894,8 +894,8 @@ trait NirGenExpr(using Context) {
genIf(
retty,
ValTree(cond),
ContTree(f),
ContTree(() => wrap(rest))
f,
ContTree(_ => wrap(rest))
)(using pos)
}

Expand Down Expand Up @@ -1296,7 +1296,7 @@ trait NirGenExpr(using Context) {
)(using nir.SourcePosition): nir.Val = {
require(!sym.isExtern, sym)

val sig = genMethodSig(sym)
val sig = genMethodSig(sym, statically = true)
val args = genMethodArgs(sym, argsp)
val methodName = genStaticMemberName(sym, receiver)
val method = nir.Val.Global(methodName, nir.Type.Ptr)
Expand Down Expand Up @@ -1969,7 +1969,11 @@ trait NirGenExpr(using Context) {
val mergen = fresh()

// scalanative.runtime.`package`.enterMonitor(receiver)
genExpr(Apply(ref(defnNir.RuntimePackage_enterMonitor), List(receiverp)))
genApplyStaticMethod(
defnNir.RuntimePackage_enterMonitor,
defnNir.RuntimePackageClass,
List(receiverp)
)

// synchronized block
val retValue = scoped(curUnwindHandler := Some(handler)) {
Expand All @@ -1993,7 +1997,13 @@ trait NirGenExpr(using Context) {
buf.jump(nir.Next(normaln))
buf ++= genTryFinally(
// scalanative.runtime.`package`.exitMonitor(receiver)
Apply(ref(defnNir.RuntimePackage_exitMonitor), List(receiverp)),
ContTree(
_.genApplyStaticMethod(
defnNir.RuntimePackage_exitMonitor,
defnNir.RuntimePackageClass,
List(receiverp)
)
),
nested.toSeq
)
buf.labelExcludeUnitValue(mergen, mergev)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -309,15 +309,19 @@ trait NirGenType(using Context) {
defn.DoubleClass -> 'D'
)

def genMethodSig(sym: Symbol): nir.Type.Function =
genMethodSigImpl(sym, isExtern = false)
def genMethodSig(
sym: Symbol,
statically: Boolean = false
): nir.Type.Function =
genMethodSigImpl(sym, statically = statically, isExtern = false)

def genExternMethodSig(sym: Symbol): nir.Type.Function =
genMethodSigImpl(sym, isExtern = true)
genMethodSigImpl(sym, isExtern = true, statically = true)

private def genMethodSigImpl(
sym: Symbol,
isExtern: Boolean
isExtern: Boolean,
statically: Boolean
): nir.Type.Function = {
def resolve() = {
require(
Expand All @@ -327,7 +331,7 @@ trait NirGenType(using Context) {

val owner = sym.owner
val paramtys = genMethodSigParamsImpl(sym, isExtern)
val selfty = Option.unless(isExtern || sym.isStaticInNIR) {
val selfty = Option.unless(statically | isExtern || sym.isStaticInNIR) {
genType(owner)
}
val resultType = sym.info.resultType
Expand Down

0 comments on commit e24a9dc

Please sign in to comment.