Skip to content

Commit

Permalink
Merge pull request #3934 from armanbilge/topic/static
Browse files Browse the repository at this point in the history
Apply `@static` annotation internally
  • Loading branch information
djspiewak authored Jan 15, 2024
2 parents 0207637 + da8bb43 commit 1bc18fe
Show file tree
Hide file tree
Showing 17 changed files with 116 additions and 75 deletions.
7 changes: 6 additions & 1 deletion build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -767,7 +767,12 @@ lazy val core = crossProject(JSPlatform, JVMPlatform, NativePlatform)
ProblemFilters.exclude[DirectMissingMethodProblem](
"cats.effect.unsafe.WorkStealingThreadPool.this"),
// annoying consequence of reverting #2473
ProblemFilters.exclude[AbstractClassProblem]("cats.effect.ExitCode")
ProblemFilters.exclude[AbstractClassProblem]("cats.effect.ExitCode"),
// #3934 which made these internal vals into proper static fields
ProblemFilters.exclude[DirectMissingMethodProblem](
"cats.effect.unsafe.IORuntime.allRuntimes"),
ProblemFilters.exclude[DirectMissingMethodProblem](
"cats.effect.unsafe.IORuntime.globalFatalFailureHandled")
)
} else Seq()
}
Expand Down
2 changes: 1 addition & 1 deletion core/js/src/main/scala/cats/effect/CallbackStack.scala
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ private final class CallbackStackOps[A](private val callbacks: js.Array[A => Uni
}

private object CallbackStack {
@inline def apply[A](cb: A => Unit): CallbackStack[A] =
@inline def of[A](cb: A => Unit): CallbackStack[A] =
js.Array(cb).asInstanceOf[CallbackStack[A]]

@inline implicit def ops[A](stack: CallbackStack[A]): CallbackStackOps[A] =
Expand Down
2 changes: 2 additions & 0 deletions core/js/src/main/scala/cats/effect/Platform.scala
Original file line number Diff line number Diff line change
Expand Up @@ -20,4 +20,6 @@ private object Platform {
final val isJs = true
final val isJvm = false
final val isNative = false

class static extends scala.annotation.Annotation
}
6 changes: 4 additions & 2 deletions core/jvm-native/src/main/scala/cats/effect/ArrayStack.scala
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@

package cats.effect

import Platform.static

private final class ArrayStack[A <: AnyRef](
private[this] var buffer: Array[AnyRef],
private[this] var index: Int) {
Expand Down Expand Up @@ -78,8 +80,8 @@ private final class ArrayStack[A <: AnyRef](

private object ArrayStack {

def apply[A <: AnyRef](): ArrayStack[A] = new ArrayStack()
@static def apply[A <: AnyRef](): ArrayStack[A] = new ArrayStack()

def apply[A <: AnyRef](size: Int): ArrayStack[A] = new ArrayStack(size)
@static def apply[A <: AnyRef](size: Int): ArrayStack[A] = new ArrayStack(size)

}
24 changes: 15 additions & 9 deletions core/jvm-native/src/main/scala/cats/effect/ByteStack.scala
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,17 @@

package cats.effect

import Platform.static

private[effect] final class ByteStack

private object ByteStack {

type T = Array[Int]

final def toDebugString(stack: Array[Int], translate: Byte => String = _.toString): String = {
@static final def toDebugString(
stack: Array[Int],
translate: Byte => String = _.toString): String = {
val count = size(stack)
((count - 1) to 0 by -1)
.foldLeft(
Expand All @@ -38,10 +44,10 @@ private object ByteStack {
.toString
}

final def create(initialMaxOps: Int): Array[Int] =
@static final def create(initialMaxOps: Int): Array[Int] =
new Array[Int](1 + 1 + ((initialMaxOps - 1) >> 3)) // count-slot + 1 for each set of 8 ops

final def growIfNeeded(stack: Array[Int], count: Int): Array[Int] = {
@static final def growIfNeeded(stack: Array[Int], count: Int): Array[Int] = {
if ((1 + ((count + 1) >> 3)) < stack.length) {
stack
} else {
Expand All @@ -51,7 +57,7 @@ private object ByteStack {
}
}

final def push(stack: Array[Int], op: Byte): Array[Int] = {
@static final def push(stack: Array[Int], op: Byte): Array[Int] = {
val c = stack(0) // current count of elements
val use = growIfNeeded(stack, c) // alias so we add to the right place
val s = (c >> 3) + 1 // current slot in `use`
Expand All @@ -61,24 +67,24 @@ private object ByteStack {
use
}

final def size(stack: Array[Int]): Int =
@static final def size(stack: Array[Int]): Int =
stack(0)

final def isEmpty(stack: Array[Int]): Boolean =
@static final def isEmpty(stack: Array[Int]): Boolean =
stack(0) < 1

final def read(stack: Array[Int], pos: Int): Byte = {
@static final def read(stack: Array[Int], pos: Int): Byte = {
if (pos < 0 || pos >= stack(0)) throw new ArrayIndexOutOfBoundsException()
((stack((pos >> 3) + 1) >>> ((pos & 7) << 2)) & 0x0000000f).toByte
}

final def peek(stack: Array[Int]): Byte = {
@static final def peek(stack: Array[Int]): Byte = {
val c = stack(0) - 1
if (c < 0) throw new ArrayIndexOutOfBoundsException()
((stack((c >> 3) + 1) >>> ((c & 7) << 2)) & 0x0000000f).toByte
}

final def pop(stack: Array[Int]): Byte = {
@static final def pop(stack: Array[Int]): Byte = {
val op = peek(stack)
stack(0) -= 1
op
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ import scala.annotation.tailrec

import java.util.concurrent.atomic.AtomicReference

import Platform.static

private final class CallbackStack[A](private[this] var callback: A => Unit)
extends AtomicReference[CallbackStack[A]] {

Expand Down Expand Up @@ -149,7 +151,7 @@ private final class CallbackStack[A](private[this] var callback: A => Unit)
}

private object CallbackStack {
def apply[A](cb: A => Unit): CallbackStack[A] =
@static def of[A](cb: A => Unit): CallbackStack[A] =
new CallbackStack(cb)

type Handle = Byte
Expand Down
2 changes: 2 additions & 0 deletions core/jvm/src/main/scala/cats/effect/Platform.scala
Original file line number Diff line number Diff line change
Expand Up @@ -20,4 +20,6 @@ private object Platform {
final val isJs = false
final val isJvm = true
final val isNative = false

type static = org.typelevel.scalaccompat.annotation.static3
}
2 changes: 2 additions & 0 deletions core/native/src/main/scala/cats/effect/Platform.scala
Original file line number Diff line number Diff line change
Expand Up @@ -20,4 +20,6 @@ private object Platform {
final val isJs = false
final val isJvm = false
final val isNative = true

class static extends scala.annotation.Annotation
}
4 changes: 3 additions & 1 deletion core/shared/src/main/scala/cats/effect/ContState.scala
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ import cats.effect.unsafe.WeakBag

import java.util.concurrent.atomic.AtomicReference

import Platform.static

/**
* Possible states (held in the `AtomicReference`):
* - "initial": `get() == null`
Expand Down Expand Up @@ -49,6 +51,6 @@ private object ContState {
* important. It must be private (so that no user code can access it), and it mustn't be used
* for any other purpose.
*/
private val waitingSentinel: Either[Throwable, Any] =
@static private val waitingSentinel: Either[Throwable, Any] =
new Right(null)
}
10 changes: 7 additions & 3 deletions core/shared/src/main/scala/cats/effect/IO.scala
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,8 @@ import scala.util.control.NonFatal
import java.util.UUID
import java.util.concurrent.Executor

import Platform.static

/**
* A pure abstraction representing the intention to perform a side effect, where the result of
* that side effect may be obtained synchronously (via return) or asynchronously (via callback).
Expand Down Expand Up @@ -1109,6 +1111,9 @@ private[effect] trait IOLowPriorityImplicits {

object IO extends IOCompanionPlatform with IOLowPriorityImplicits {

@static private[this] val _alignForIO = new IOAlign
@static private[this] val _asyncForIO: kernel.Async[IO] = new IOAsync

/**
* Newtype encoding for an `IO` datatype that has a `cats.Applicative` capable of doing
* parallel processing in `ap` and `map2`, needed for implementing `cats.Parallel`.
Expand Down Expand Up @@ -1787,7 +1792,7 @@ object IO extends IOCompanionPlatform with IOLowPriorityImplicits {

implicit def alignForIO: Align[IO] = _alignForIO

private[this] val _alignForIO = new Align[IO] {
private[this] final class IOAlign extends Align[IO] {
def align[A, B](fa: IO[A], fb: IO[B]): IO[Ior[A, B]] =
alignWith(fa, fb)(identity)

Expand All @@ -1800,8 +1805,7 @@ object IO extends IOCompanionPlatform with IOLowPriorityImplicits {
def functor: Functor[IO] = Functor[IO]
}

private[this] val _asyncForIO: kernel.Async[IO] = new kernel.Async[IO]
with StackSafeMonad[IO] {
private[this] final class IOAsync extends kernel.Async[IO] with StackSafeMonad[IO] {

override def asyncCheckAttempt[A](
k: (Either[Throwable, A] => Unit) => IO[Either[Option[IO[Unit]], A]]): IO[A] =
Expand Down
2 changes: 1 addition & 1 deletion core/shared/src/main/scala/cats/effect/IODeferred.scala
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ private final class IODeferred[A] extends Deferred[IO, A] {
}

private[this] val cell = new AtomicReference(initial)
private[this] val callbacks = CallbackStack[Right[Nothing, A]](null)
private[this] val callbacks = CallbackStack.of[Right[Nothing, A]](null)
private[this] val clearCounter = new AtomicInteger

def complete(a: A): IO[Boolean] = IO {
Expand Down
14 changes: 8 additions & 6 deletions core/shared/src/main/scala/cats/effect/IOFiber.scala
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ import scala.util.control.NonFatal
import java.util.concurrent.RejectedExecutionException
import java.util.concurrent.atomic.AtomicBoolean

import Platform.static

/*
* Rationale on memory barrier exploitation in this class...
*
Expand Down Expand Up @@ -85,7 +87,7 @@ private final class IOFiber[A](
private[this] var currentCtx: ExecutionContext = startEC
private[this] val objectState: ArrayStack[AnyRef] = ArrayStack()
private[this] val finalizers: ArrayStack[IO[Unit]] = ArrayStack()
private[this] val callbacks: CallbackStack[OutcomeIO[A]] = CallbackStack(cb)
private[this] val callbacks: CallbackStack[OutcomeIO[A]] = CallbackStack.of(cb)
private[this] var resumeTag: Byte = ExecR
private[this] var resumeIO: IO[Any] = startIO
private[this] val runtime: IORuntime = rt
Expand All @@ -96,7 +98,7 @@ private final class IOFiber[A](
* Ideally these would be on the stack, but they can't because we sometimes need to
* relocate our runloop to another fiber.
*/
private[this] var conts: ByteStack = _
private[this] var conts: ByteStack.T = _

private[this] var canceled: Boolean = false
private[this] var masks: Int = 0
Expand Down Expand Up @@ -1569,11 +1571,11 @@ private final class IOFiber[A](

private object IOFiber {
/* prefetch */
private[IOFiber] val TypeBlocking = Sync.Type.Blocking
private[IOFiber] val OutcomeCanceled = Outcome.Canceled()
private[effect] val RightUnit = Right(())
@static private[IOFiber] val TypeBlocking = Sync.Type.Blocking
@static private[IOFiber] val OutcomeCanceled = Outcome.Canceled()
@static private[effect] val RightUnit = Right(())

def onFatalFailure(t: Throwable): Nothing = {
@static def onFatalFailure(t: Throwable): Nothing = {
val interrupted = Thread.interrupted()

if (IORuntime.globalFatalFailureHandled.compareAndSet(false, true)) {
Expand Down
61 changes: 32 additions & 29 deletions core/shared/src/main/scala/cats/effect/SyncIO.scala
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ import scala.concurrent.duration._
import scala.util.Try
import scala.util.control.NonFatal

import Platform.static

/**
* A pure abstraction representing the intention to perform a side effect, where the result of
* that side effect is obtained synchronously.
Expand Down Expand Up @@ -396,7 +398,8 @@ private[effect] trait SyncIOLowPriorityImplicits {

object SyncIO extends SyncIOCompanionPlatform with SyncIOLowPriorityImplicits {

private[this] val Delay = Sync.Type.Delay
@static private[this] val Delay = Sync.Type.Delay
@static private[this] val _syncForSyncIO: Sync[SyncIO] = new SyncIOSync

// constructors

Expand Down Expand Up @@ -576,48 +579,48 @@ object SyncIO extends SyncIOCompanionPlatform with SyncIOLowPriorityImplicits {
def functor: Functor[SyncIO] = Functor[SyncIO]
}

private[this] val _syncForSyncIO: Sync[SyncIO] =
new Sync[SyncIO]
private[this] final class SyncIOSync
extends Sync[SyncIO]
with StackSafeMonad[SyncIO]
with MonadCancel.Uncancelable[SyncIO, Throwable] {

def pure[A](x: A): SyncIO[A] =
SyncIO.pure(x)
def pure[A](x: A): SyncIO[A] =
SyncIO.pure(x)

def raiseError[A](e: Throwable): SyncIO[A] =
SyncIO.raiseError(e)
def raiseError[A](e: Throwable): SyncIO[A] =
SyncIO.raiseError(e)

def handleErrorWith[A](fa: SyncIO[A])(f: Throwable => SyncIO[A]): SyncIO[A] =
fa.handleErrorWith(f)
def handleErrorWith[A](fa: SyncIO[A])(f: Throwable => SyncIO[A]): SyncIO[A] =
fa.handleErrorWith(f)

def flatMap[A, B](fa: SyncIO[A])(f: A => SyncIO[B]): SyncIO[B] =
fa.flatMap(f)
def flatMap[A, B](fa: SyncIO[A])(f: A => SyncIO[B]): SyncIO[B] =
fa.flatMap(f)

def monotonic: SyncIO[FiniteDuration] =
SyncIO.monotonic
def monotonic: SyncIO[FiniteDuration] =
SyncIO.monotonic

def realTime: SyncIO[FiniteDuration] =
SyncIO.realTime
def realTime: SyncIO[FiniteDuration] =
SyncIO.realTime

def suspend[A](hint: Sync.Type)(thunk: => A): SyncIO[A] =
Suspend(hint, () => thunk)
def suspend[A](hint: Sync.Type)(thunk: => A): SyncIO[A] =
Suspend(hint, () => thunk)

override def attempt[A](fa: SyncIO[A]): SyncIO[Either[Throwable, A]] =
fa.attempt
override def attempt[A](fa: SyncIO[A]): SyncIO[Either[Throwable, A]] =
fa.attempt

override def redeem[A, B](fa: SyncIO[A])(recover: Throwable => B, f: A => B): SyncIO[B] =
fa.redeem(recover, f)
override def redeem[A, B](fa: SyncIO[A])(recover: Throwable => B, f: A => B): SyncIO[B] =
fa.redeem(recover, f)

override def redeemWith[A, B](
fa: SyncIO[A])(recover: Throwable => SyncIO[B], bind: A => SyncIO[B]): SyncIO[B] =
fa.redeemWith(recover, bind)
override def redeemWith[A, B](
fa: SyncIO[A])(recover: Throwable => SyncIO[B], bind: A => SyncIO[B]): SyncIO[B] =
fa.redeemWith(recover, bind)

override def unit: SyncIO[Unit] =
SyncIO.unit
override def unit: SyncIO[Unit] =
SyncIO.unit

def forceR[A, B](fa: SyncIO[A])(fb: SyncIO[B]): SyncIO[B] =
fa.attempt.productR(fb)
}
def forceR[A, B](fa: SyncIO[A])(fb: SyncIO[B]): SyncIO[B] =
fa.attempt.productR(fb)
}

implicit def syncForSyncIO: Sync[SyncIO] with MonadCancel[SyncIO, Throwable] = _syncForSyncIO

Expand Down
2 changes: 0 additions & 2 deletions core/shared/src/main/scala/cats/effect/package.scala
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,4 @@ package object effect {
val Ref = cekernel.Ref

private[effect] type IOLocalState = scala.collection.immutable.Map[IOLocal[_], Any]

private[effect] type ByteStack = ByteStack.T
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,10 @@
* limitations under the License.
*/

package cats.effect.tracing
package cats.effect
package tracing

import Platform.static

private[effect] final class RingBuffer private (logSize: Int) {

Expand Down Expand Up @@ -59,6 +62,6 @@ private[effect] final class RingBuffer private (logSize: Int) {
}

private[effect] object RingBuffer {
def empty(logSize: Int): RingBuffer =
@static def empty(logSize: Int): RingBuffer =
new RingBuffer(logSize)
}
Loading

0 comments on commit 1bc18fe

Please sign in to comment.