Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

bugfix: Fix compilation on newer JDK #785

Merged
merged 1 commit into from
Aug 17, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@ import scala.tools.nsc.Settings
import scala.tools.nsc.io.AbstractFile
import scala.tools.nsc.io.VirtualDirectory
import scala.annotation.implicitNotFound
import mdoc.internal.CompatClassloader
import mdoc.internal.worksheets.Compat._

class MarkdownCompiler(
Expand Down
45 changes: 34 additions & 11 deletions mdoc/src/main/scala/mdoc/internal/CompatClassloader.scala
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,15 @@ package mdoc.internal

import java.net.URLClassLoader
import java.net.URL
import sun.misc.Unsafe
import mdoc.internal.pos.PositionSyntax._

object CompatClassloader {

abstract class Unsafe {
def objectFieldOffset(field: java.lang.reflect.Field): Long
def getObject(obj: AnyRef, offset: Long): AnyRef
}

/** Utility to get SystemClassLoader/ClassLoader urls in java8 and java9+ Based upon:
* https://gist.github.com/hengyunabc/644f8e84908b7b405c532a51d8e34ba9
*/
Expand All @@ -21,9 +25,10 @@ object CompatClassloader {
.startsWith("jdk.internal.loader.ClassLoaders$")
) {
try {
val field = classOf[Unsafe].getDeclaredField("theUnsafe")
val unsafeClass = classLoader.loadClass("sun.misc.Unsafe")
val field = unsafeClass.getDeclaredField("theUnsafe")
field.setAccessible(true)
val unsafe = field.get(null).asInstanceOf[Unsafe]
val unsafe = field.get(null)

// jdk.internal.loader.ClassLoaders.AppClassLoader.ucp
val ucpField = {
Expand All @@ -34,14 +39,32 @@ object CompatClassloader {
classLoader.getClass()
}
}.getDeclaredField("ucp")
val ucpFieldOffset: Long = unsafe.objectFieldOffset(ucpField)
val ucpObject = unsafe.getObject(classLoader, ucpFieldOffset)

// jdk.internal.loader.URLClassPath.path
val pathField = ucpField.getType().getDeclaredField("path")
val pathFieldOffset = unsafe.objectFieldOffset(pathField)
val paths: Seq[URL] = unsafe
.getObject(ucpObject, pathFieldOffset)

def objectFieldOffset(field: java.lang.reflect.Field): Long =
unsafeClass
.getMethod(
"objectFieldOffset",
classOf[java.lang.reflect.Field]
)
.invoke(unsafe, field)
.asInstanceOf[Long]

def getObject(obj: AnyRef, offset: Long): AnyRef =
unsafeClass
.getMethod(
"getObject",
classOf[AnyRef],
classOf[Long]
)
.invoke(unsafe, obj, offset.asInstanceOf[AnyRef])
.asInstanceOf[AnyRef]

val ucpFieldOffset = objectFieldOffset(ucpField)
val ucpObject = getObject(classLoader, ucpFieldOffset)

val pathField = ucpField.getType().getDeclaredField("path")
val pathFieldOffset = objectFieldOffset(pathField)
val paths: Seq[URL] = getObject(ucpObject, pathFieldOffset)
.asInstanceOf[java.util.ArrayList[URL]]
.asScala
.toSeq
Expand Down