|
1 | 1 | package ch.epfl.scala.debugadapter.internal.evaluator |
2 | 2 |
|
3 | 3 | import com.sun.jdi._ |
4 | | -import scala.collection.JavaConverters.* |
5 | 4 |
|
6 | | -private[internal] object JdiClassLoader { |
7 | | - def fromFrame(frame: FrameReference): Safe[JdiClassLoader] = Safe { |
8 | | - val scalaLibClassLoader = |
9 | | - for { |
10 | | - scalaLibClass <- frame.thread.virtualMachine.allClasses.asScala |
11 | | - .find(c => c.name.startsWith("scala.runtime")) |
12 | | - classLoader <- Option(scalaLibClass.classLoader) |
13 | | - } yield classLoader |
14 | | - |
15 | | - val classLoader = Option(frame.current().location.method.declaringType.classLoader) |
16 | | - .orElse(scalaLibClassLoader) |
17 | | - .getOrElse(throw new Exception("Cannot find the classloader of the Scala library")) |
18 | | - JdiClassLoader(classLoader, frame.thread) |
19 | | - } |
20 | | - |
21 | | - def apply( |
22 | | - classLoader: ClassLoaderReference, |
23 | | - thread: ThreadReference |
24 | | - ): JdiClassLoader = { |
25 | | - val classLoaderType = classLoader.referenceType |
26 | | - val loadClassMethod = method( |
27 | | - "loadClass", |
28 | | - "(Ljava/lang/String;)Ljava/lang/Class;", |
29 | | - classLoaderType |
30 | | - ) |
31 | | - new JdiClassLoader(classLoader, loadClassMethod, thread) |
32 | | - } |
33 | | -} |
| 5 | +import java.nio.file.Path |
34 | 6 |
|
35 | | -private[internal] case class JdiClassLoader( |
36 | | - classLoaderRef: ClassLoaderReference, |
37 | | - loadClassMethod: Method, |
| 7 | +private[internal] class JdiClassLoader( |
| 8 | + reference: ClassLoaderReference, |
38 | 9 | thread: ThreadReference |
39 | | -) { |
| 10 | +) extends JdiObject(reference, thread) { |
40 | 11 |
|
41 | | - def loadClass(name: String): Safe[JdiClassObject] = { |
| 12 | + private def loadClassClass: Safe[JdiClass] = |
42 | 13 | for { |
43 | | - nameValue <- mirrorOf(name) |
44 | | - classObject <- invokeMethod( |
45 | | - classLoaderRef, |
46 | | - loadClassMethod, |
47 | | - List(nameValue), |
48 | | - thread |
| 14 | + classClassName <- mirrorOf("java.lang.Class") |
| 15 | + classClass <- invoke("loadClass", "(Ljava/lang/String;)Ljava/lang/Class;", Seq(classClassName)) |
| 16 | + } yield classClass.asClass |
| 17 | + |
| 18 | + def loadClass(className: String): Safe[JdiClass] = |
| 19 | + for { |
| 20 | + classNameValue <- mirrorOf(className) |
| 21 | + classClass <- loadClassClass |
| 22 | + classObject <- classClass.invokeStatic( |
| 23 | + "forName", |
| 24 | + "(Ljava/lang/String;ZLjava/lang/ClassLoader;)Ljava/lang/Class;", |
| 25 | + Seq(classNameValue, mirrorOf(true), this) |
49 | 26 | ) |
| 27 | + } yield classObject.asClass |
| 28 | + |
| 29 | + def mirrorOf(str: String): Safe[JdiString] = |
| 30 | + Safe(thread.virtualMachine.mirrorOf(str)).map(new JdiString(_, thread)) |
| 31 | + |
| 32 | + def mirrorOf(boolean: Boolean): JdiValue = |
| 33 | + new JdiValue(thread.virtualMachine.mirrorOf(boolean), thread) |
| 34 | + |
| 35 | + def mirrorOf(integer: Int): JdiValue = |
| 36 | + new JdiValue(thread.virtualMachine.mirrorOf(integer), thread) |
| 37 | + |
| 38 | + def boxIfPrimitive(value: JdiValue): Safe[JdiValue] = |
| 39 | + value.value match { |
| 40 | + case value: BooleanValue => box(value.value) |
| 41 | + case value: CharValue => box(value.value) |
| 42 | + case value: DoubleValue => box(value.value) |
| 43 | + case value: FloatValue => box(value.value) |
| 44 | + case value: IntegerValue => box(value.value) |
| 45 | + case value: LongValue => box(value.value) |
| 46 | + case value: ShortValue => box(value.value) |
| 47 | + case value => Safe(JdiValue(value, thread)) |
| 48 | + } |
| 49 | + |
| 50 | + def box(value: AnyVal): Safe[JdiObject] = |
| 51 | + for { |
| 52 | + jdiValue <- mirrorOf(value.toString) |
| 53 | + _ = getClass |
| 54 | + (className, sig) = value match { |
| 55 | + case _: Boolean => ("java.lang.Boolean", "(Ljava/lang/String;)Ljava/lang/Boolean;") |
| 56 | + case _: Byte => ("java.lang.Byte", "(Ljava/lang/String;)Ljava/lang/Byte;") |
| 57 | + case _: Char => ("java.lang.Character", "(Ljava/lang/String;)Ljava/lang/Character;") |
| 58 | + case _: Double => ("java.lang.Double", "(Ljava/lang/String;)Ljava/lang/Double;") |
| 59 | + case _: Float => ("java.lang.Float", "(Ljava/lang/String;)Ljava/lang/Float;") |
| 60 | + case _: Int => ("java.lang.Integer", "(Ljava/lang/String;)Ljava/lang/Integer;") |
| 61 | + case _: Long => ("java.lang.Long", "(Ljava/lang/String;)Ljava/lang/Long;") |
| 62 | + case _: Short => ("java.lang.Short", "(Ljava/lang/String;)Ljava/lang/Short;") |
| 63 | + } |
| 64 | + clazz <- loadClass(className) |
| 65 | + objectRef <- clazz.invokeStatic("valueOf", sig, List(jdiValue)) |
| 66 | + } yield objectRef.asObject |
| 67 | + |
| 68 | + def createArray(arrayType: String, values: Seq[JdiValue]): Safe[JdiArray] = |
| 69 | + for { |
| 70 | + arrayTypeClass <- loadClass(arrayType) |
| 71 | + arrayClass <- loadClass("java.lang.reflect.Array") |
| 72 | + size = mirrorOf(values.size) |
| 73 | + array <- arrayClass |
| 74 | + .invokeStatic("newInstance", "(Ljava/lang/Class;I)Ljava/lang/Object;", Seq(arrayTypeClass, size)) |
| 75 | + .map(_.asArray) |
50 | 76 | } yield { |
51 | | - new JdiClassObject( |
52 | | - classObject.asInstanceOf[ClassObjectReference], |
53 | | - this, |
54 | | - thread |
55 | | - ) |
| 77 | + array.setValues(values) |
| 78 | + array |
56 | 79 | } |
57 | | - } |
58 | 80 |
|
59 | | - def mirrorOf(str: String): Safe[StringReference] = { |
60 | | - Safe(thread.virtualMachine.mirrorOf(str)) |
61 | | - } |
| 81 | + def createChildLoader(classPathEntry: Path): Safe[JdiClassLoader] = |
| 82 | + for { |
| 83 | + classPathValue <- mirrorOf(classPathEntry.toUri.toString) |
| 84 | + urlClass <- loadClass("java.net.URL") |
| 85 | + url <- urlClass.newInstance("(Ljava/lang/String;)V", List(classPathValue)) |
| 86 | + urls <- createArray("java.net.URL", Seq(url)) |
| 87 | + classOfUrlClassLoader <- loadClass("java.net.URLClassLoader") |
| 88 | + urlClassLoader <- classOfUrlClassLoader.newInstance("([Ljava/net/URL;Ljava/lang/ClassLoader;)V", List(urls, this)) |
| 89 | + } yield urlClassLoader.asClassLoader |
| 90 | +} |
| 91 | + |
| 92 | +private[internal] object JdiClassLoader { |
| 93 | + def apply(ref: ClassLoaderReference, thread: ThreadReference): JdiClassLoader = |
| 94 | + new JdiClassLoader(ref, thread) |
62 | 95 | } |
0 commit comments