Skip to content

Commit

Permalink
Bytebuddy cogen, removed cglib (java 17) (#1737)
Browse files Browse the repository at this point in the history
  • Loading branch information
pshirshov authored Jun 1, 2022
1 parent b73ef9d commit 7bef107
Show file tree
Hide file tree
Showing 26 changed files with 182 additions and 151 deletions.
2 changes: 1 addition & 1 deletion .jvmopts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
-Xmx3G
-Xmx12G
-XX:ReservedCodeCacheSize=256M
-XX:MaxMetaspaceSize=2560M

Expand Down
12 changes: 6 additions & 6 deletions build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -1374,7 +1374,7 @@ lazy val `distage-core-api` = project.in(file("distage/distage-core-api"))
)
.disablePlugins(AssemblyPlugin)

lazy val `distage-core-proxy-cglib` = project.in(file("distage/distage-core-proxy-cglib"))
lazy val `distage-core-proxy-bytebuddy` = project.in(file("distage/distage-core-proxy-bytebuddy"))
.dependsOn(
`distage-core-api` % "test->compile;compile->compile"
)
Expand All @@ -1383,7 +1383,7 @@ lazy val `distage-core-proxy-cglib` = project.in(file("distage/distage-core-prox
compilerPlugin("org.typelevel" % "kind-projector" % V.kind_projector cross CrossVersion.full),
"org.scala-lang.modules" %% "scala-collection-compat" % V.collection_compat,
"org.scalatest" %% "scalatest" % V.scalatest % Test,
"cglib" % "cglib-nodep" % V.cglib_nodep
"net.bytebuddy" % "byte-buddy" % V.bytebuddy
)
)
.settings(
Expand Down Expand Up @@ -1506,7 +1506,7 @@ lazy val `distage-core-proxy-cglib` = project.in(file("distage/distage-core-prox
lazy val `distage-core` = project.in(file("distage/distage-core"))
.dependsOn(
`distage-core-api` % "test->compile;compile->compile",
`distage-core-proxy-cglib` % "test->compile;compile->compile"
`distage-core-proxy-bytebuddy` % "test->compile"
)
.settings(
libraryDependencies ++= Seq(
Expand Down Expand Up @@ -3289,7 +3289,7 @@ lazy val `microsite` = project.in(file("doc/microsite"))
`fundamentals-orphans` % "test->compile;compile->compile",
`fundamentals-literals` % "test->compile;compile->compile",
`distage-core-api` % "test->compile;compile->compile",
`distage-core-proxy-cglib` % "test->compile;compile->compile",
`distage-core-proxy-bytebuddy` % "test->compile;compile->compile",
`distage-core` % "test->compile;compile->compile",
`distage-extension-config` % "test->compile;compile->compile",
`distage-extension-plugins` % "test->compile;compile->compile",
Expand Down Expand Up @@ -3681,7 +3681,7 @@ lazy val `distage` = (project in file(".agg/distage-distage"))
.disablePlugins(AssemblyPlugin)
.aggregate(
`distage-core-api`,
`distage-core-proxy-cglib`,
`distage-core-proxy-bytebuddy`,
`distage-core`,
`distage-extension-config`,
`distage-extension-plugins`,
Expand All @@ -3705,7 +3705,7 @@ lazy val `distage-jvm` = (project in file(".agg/distage-distage-jvm"))
.disablePlugins(AssemblyPlugin)
.aggregate(
`distage-core-api`,
`distage-core-proxy-cglib`,
`distage-core-proxy-bytebuddy`,
`distage-core`,
`distage-extension-config`,
`distage-extension-plugins`,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
package izumi.distage.provisioning.strategies.cglib.exceptions
package izumi.distage.model.exceptions.interpretation

import izumi.distage.model.exceptions.DIException
import izumi.distage.model.plan.ExecutableOp
import izumi.distage.model.provisioning.proxies.ProxyProvider.ProxyParams

class CgLibInstantiationOpException(message: String, val target: Class[?], val params: ProxyParams, val op: ExecutableOp, cause: Throwable)
class ProxyInstantiationException(message: String, val target: Class[?], val params: ProxyParams, val op: ExecutableOp, cause: Throwable)
extends DIException(message, cause)
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package izumi.distage.provisioning.strategies.cglib
package izumi.distage.model.provisioning.proxies

trait DistageProxy {
def _distageProxyReference: AnyRef
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ trait ProxyProvider {
}

object ProxyProvider {
class ProxyProviderFailingImpl extends ProxyProvider {
object ProxyProviderFailingImpl extends ProxyProvider {
override def makeCycleProxy(deferredKey: DIKey, proxyContext: ProxyContext): DeferredInit = {
throw new ProxyProviderFailingImplCalledException(s"ProxyProviderFailingImpl can't create cycle-breaking proxies, failed op: ${proxyContext.op}", this)
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,34 +1,33 @@
package izumi.distage.provisioning.strategies.cglib

import java.lang.reflect.Method
package izumi.distage.provisioning.strategies.bytebuddyproxy

import izumi.distage.model.provisioning.proxies.DistageProxy
import izumi.distage.model.provisioning.proxies.ProxyDispatcher.AtomicProxyDispatcher
import net.sf.cglib.proxy.{MethodInterceptor, MethodProxy}

import java.lang.reflect.{InvocationHandler, Method}

// dynamic dispatching is not optimal, uhu
private[distage] class CglibAtomicRefDispatcher(
private[distage] class ByteBuddyAtomicRefDispatcher(
nullProxy: AnyRef
) extends AtomicProxyDispatcher
with MethodInterceptor {

override def intercept(o: scala.Any, method: Method, objects: Array[AnyRef], methodProxy: MethodProxy): AnyRef = {
with InvocationHandler {
override def invoke(o: scala.Any, method: Method, objects: Array[AnyRef]): AnyRef = {
val methodName = method.getName
if (methodName == "equals" && (method.getParameterTypes sameElements Array(classOf[AnyRef]))) {
objects.headOption match {
case Some(r: DistageProxy) =>
Boolean.box(getRef() == r._distageProxyReference)
Boolean.box(getRef == r._distageProxyReference)

case _ =>
method.invoke(getRef(), objects: _*)
method.invoke(getRef, objects: _*)
}
} else if (methodName == "_distageProxyReference" && method.getParameterCount == 0) {
getRef()
getRef
} else {
method.invoke(getRef(), objects: _*)
method.invoke(getRef, objects: _*)
}
}

@inline private[this] final def getRef(): AnyRef = {
@inline private[this] final def getRef: AnyRef = {
val value = reference.get()
if (value ne null) value else nullProxy
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,16 +1,15 @@
package izumi.distage.provisioning.strategies.cglib
package izumi.distage.provisioning.strategies.bytebuddyproxy

import izumi.distage.model.exceptions.interpretation.MissingRefException

import java.lang.reflect.Method
import izumi.distage.model.reflection.DIKey
import net.sf.cglib.proxy.{MethodInterceptor, MethodProxy}

import java.lang.reflect.{InvocationHandler, Method}

// we use this to be able to display something for uninitialized proxies
private[distage] class CglibNullMethodInterceptor(
private[distage] class ByteBuddyNullMethodInterceptor(
key: DIKey
) extends MethodInterceptor {
override def intercept(o: Any, method: Method, objects: Array[AnyRef], methodProxy: MethodProxy): AnyRef = {
) extends InvocationHandler {
override def invoke(o: Any, method: Method, objects: Array[AnyRef]): AnyRef = {
if (method.getName == "toString" && method.getParameterCount == 0) {
s"__UninitializedProxy__:$key"
} else {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
package izumi.distage.provisioning.strategies.dynamicproxy

import izumi.distage.model.exceptions.interpretation.ProxyInstantiationException
import izumi.distage.model.provisioning.proxies.ProxyProvider.ProxyParams.{Empty, Params}
import izumi.distage.model.provisioning.proxies.ProxyProvider.{DeferredInit, ProxyContext}
import izumi.distage.model.provisioning.proxies.{DistageProxy, ProxyProvider}
import izumi.distage.model.reflection.DIKey
import izumi.distage.provisioning.strategies.bytebuddyproxy.{ByteBuddyAtomicRefDispatcher, ByteBuddyNullMethodInterceptor}
import net.bytebuddy.ByteBuddy
import net.bytebuddy.dynamic.scaffold.TypeValidation
import net.bytebuddy.implementation.InvocationHandlerAdapter
import net.bytebuddy.matcher.{ElementMatcher, ElementMatchers}
import izumi.fundamentals.platform.exceptions.IzThrowable.*
import net.bytebuddy.description.method.MethodDescription

import java.lang.reflect.InvocationHandler

object DynamicProxyProvider extends ProxyProvider {

override def makeCycleProxy(deferredKey: DIKey, proxyContext: ProxyContext): DeferredInit = {
val nullDispatcher = new ByteBuddyNullMethodInterceptor(deferredKey)
val nullProxy = mkDynamic(nullDispatcher, proxyContext)

val realDispatcher = new ByteBuddyAtomicRefDispatcher(nullProxy)
val realProxy = mkDynamic(realDispatcher, proxyContext)

DeferredInit(realDispatcher, realProxy)
}

private def mkDynamic(dispatcher: InvocationHandler, proxyContext: ProxyContext): AnyRef = {
val clazz = proxyContext.runtimeClass.asInstanceOf[Class[AnyRef]]

val constructedProxyClass: Class[AnyRef] = new ByteBuddy()
.`with`(TypeValidation.DISABLED)
.subclass(clazz)
.method(ElementMatchers.isMethod.asInstanceOf[ElementMatcher[MethodDescription]])
.intercept(InvocationHandlerAdapter.of(dispatcher))
.implement(classOf[DistageProxy])
.make()
.load(clazz.getClassLoader)
.getLoaded.asInstanceOf[Class[AnyRef]]

try {
proxyContext.params match {
case Empty =>
constructedProxyClass.getDeclaredConstructor().newInstance()
case Params(types, values) =>
val c = constructedProxyClass.getDeclaredConstructor(types: _*)
c.newInstance(values.map(_.asInstanceOf[AnyRef]): _*)
}
} catch {
case f: Throwable =>
throw new ProxyInstantiationException(
s"Failed to instantiate class with CGLib, make sure you don't dereference proxied parameters in constructors: " +
s"class=${proxyContext.runtimeClass}, params=${proxyContext.params}, exception=${f.stackTrace}",
clazz,
proxyContext.params,
proxyContext.op,
f,
)
}
}
}

This file was deleted.

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package izumi.distage.bootstrap

import izumi.distage.model.provisioning.proxies.ProxyProvider
import izumi.distage.model.provisioning.proxies.ProxyProvider.ProxyProviderFailingImpl

object DynamicProxyBootstrap {
val DynamicProxyProvider: ProxyProvider = ProxyProviderFailingImpl
}

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package izumi.distage.bootstrap

import izumi.distage.model.provisioning.proxies.ProxyProvider
import izumi.fundamentals.reflection.TypeUtil

import scala.util.Try

object DynamicProxyBootstrap {
val dynProxyProviderName = "izumi.distage.provisioning.strategies.dynamicproxy.DynamicProxyProvider$"

val DynamicProxyProvider: ProxyProvider =
Try(TypeUtil.instantiateObject[ProxyProvider](Class.forName(dynProxyProviderName))).toOption match {
case Some(value) =>
value
case None =>
import izumi.distage.model.provisioning.proxies.ProxyProvider.ProxyProviderFailingImpl
ProxyProviderFailingImpl
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import distage.DIKey
import izumi.distage.model.PlannerInput
import izumi.distage.model.definition.{Activation, ModuleDef}
import izumi.distage.model.plan.Roots
import izumi.distage.model.provisioning.proxies.DistageProxy
import org.scalatest.wordspec.AnyWordSpec

import scala.collection.immutable
Expand All @@ -30,10 +31,20 @@ class GcBasicTestsJvm extends AnyWordSpec with MkGcInjector {

val result = injector.produce(plan).unsafeGet()
assert(result.find[Trash].isEmpty)
assert(result.get[Circular1].c2 != null)
assert(result.get[Circular2].c1 != null)
assert(result.get[Circular1].c2.isInstanceOf[Circular2])
assert(result.get[Circular2].c1.isInstanceOf[Circular1])
val c1 = result.get[Circular1]
val c2 = result.get[Circular2]

assert(c1.c2 != null)
assert(c2.c1 != null)

assert(c2.test == 1)

assert(c1.c2.isInstanceOf[Circular2])
assert(c2.c1.isInstanceOf[Circular1])

assert(c2.isInstanceOf[DistageProxy] || c1.isInstanceOf[DistageProxy])
val p = List(c1, c2).collect { case p: DistageProxy => p }
assert(p.forall(_._distageProxyReference != null))
}

"keep by-name loops alive" in {
Expand Down
Loading

0 comments on commit 7bef107

Please sign in to comment.