2 * Copyright 2000-2017 JetBrains s.r.o.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
16 package com.intellij.debugger.impl;
18 import com.intellij.debugger.engine.DebugProcess;
19 import com.intellij.debugger.engine.JVMNameUtil;
20 import com.intellij.debugger.engine.evaluation.EvaluateException;
21 import com.intellij.debugger.engine.evaluation.EvaluationContext;
22 import com.intellij.debugger.engine.evaluation.EvaluationContextImpl;
23 import com.intellij.debugger.jdi.VirtualMachineProxyImpl;
24 import com.intellij.openapi.util.io.StreamUtil;
25 import com.intellij.rt.debugger.ImageSerializer;
27 import org.jetbrains.annotations.Nullable;
29 import java.io.IOException;
30 import java.io.InputStream;
31 import java.util.ArrayList;
32 import java.util.Arrays;
33 import java.util.Collections;
34 import java.util.List;
39 public class ClassLoadingUtils {
40 private ClassLoadingUtils() {}
42 public static ClassLoaderReference getClassLoader(EvaluationContext context, DebugProcess process) throws EvaluateException {
44 // TODO [egor]: cache?
45 ClassType loaderClass = (ClassType)process.findClass(context, "java.net.URLClassLoader", context.getClassLoader());
46 Method ctorMethod = loaderClass.concreteMethodByName(JVMNameUtil.CONSTRUCTOR_NAME, "([Ljava/net/URL;Ljava/lang/ClassLoader;)V");
47 ClassLoaderReference reference = (ClassLoaderReference)process.newInstance(context, loaderClass, ctorMethod, Arrays
48 .asList(createURLArray(context), context.getClassLoader()));
49 DebuggerUtilsEx.keep(reference, context);
53 throw new EvaluateException("Error creating evaluation class loader: " + e, e);
57 public static void defineClass(String name,
59 EvaluationContext context,
61 ClassLoaderReference classLoader) throws EvaluateException {
63 VirtualMachineProxyImpl proxy = (VirtualMachineProxyImpl)process.getVirtualMachineProxy();
65 ((ClassType)classLoader.referenceType()).concreteMethodByName("defineClass", "(Ljava/lang/String;[BII)Ljava/lang/Class;");
66 StringReference nameObj = proxy.mirrorOf(name);
67 DebuggerUtilsEx.keep(nameObj, context);
68 process.invokeMethod(context, classLoader, defineMethod,
69 Arrays.asList(nameObj,
70 mirrorOf(bytes, context, process),
72 proxy.mirrorOf(bytes.length)));
75 throw new EvaluateException("Error during class " + name + " definition: " + e, e);
80 * Finds and if necessary defines helper class
81 * May modify class loader in evaluationContext
84 public static ClassType getHelperClass(String name, EvaluationContext evaluationContext, DebugProcess process) throws EvaluateException {
85 // TODO [egor]: cache and load in boostrap class loader
87 ClassLoaderReference classLoader = evaluationContext.getClassLoader();
88 return (ClassType)process.findClass(evaluationContext, name, classLoader);
89 } catch (EvaluateException e) {
90 Throwable cause = e.getCause();
91 if (cause instanceof InvocationException) {
92 if ("java.lang.ClassNotFoundException".equals(((InvocationException)cause).exception().type().name())) {
94 ClassLoaderReference classLoader = getClassLoader(evaluationContext, process);
95 InputStream stream = ImageSerializer.class.getResourceAsStream("/" + name.replaceAll("[.]", "/") + ".class");
97 if (stream == null) return null;
98 defineClass(name, StreamUtil.loadFromStream(stream), evaluationContext, process, classLoader);
99 ((EvaluationContextImpl)evaluationContext).setClassLoader(classLoader);
100 return (ClassType)process.findClass(evaluationContext, name, classLoader);
102 catch (IOException ioe) {
103 throw new EvaluateException("Unable to read " + name + " class bytes", ioe);
107 if (stream != null) {
111 catch (IOException ignored) {}
119 private static ArrayReference createURLArray(EvaluationContext context)
120 throws EvaluateException, InvalidTypeException, ClassNotLoadedException {
121 DebugProcess process = context.getDebugProcess();
122 ArrayType arrayType = (ArrayType)process.findClass(context, "java.net.URL[]", context.getClassLoader());
123 ArrayReference arrayRef = arrayType.newInstance(1);
124 DebuggerUtilsEx.keep(arrayRef, context);
125 ClassType classType = (ClassType)process.findClass(context, "java.net.URL", context.getClassLoader());
126 VirtualMachineProxyImpl proxy = (VirtualMachineProxyImpl)process.getVirtualMachineProxy();
127 StringReference url = proxy.mirrorOf("file:a");
128 DebuggerUtilsEx.keep(url, context);
129 ObjectReference reference = process.newInstance(context,
131 classType.concreteMethodByName(JVMNameUtil.CONSTRUCTOR_NAME, "(Ljava/lang/String;)V"),
132 Collections.singletonList(url));
133 DebuggerUtilsEx.keep(reference, context);
134 arrayRef.setValues(Collections.singletonList(reference));
138 private static ArrayReference mirrorOf(byte[] bytes, EvaluationContext context, DebugProcess process)
139 throws EvaluateException, InvalidTypeException, ClassNotLoadedException {
140 ArrayType arrayClass = (ArrayType)process.findClass(context, "byte[]", context.getClassLoader());
141 ArrayReference reference = process.newInstance(arrayClass, bytes.length);
142 DebuggerUtilsEx.keep(reference, context);
143 List<Value> mirrors = new ArrayList<>(bytes.length);
144 for (byte b : bytes) {
145 mirrors.add(((VirtualMachineProxyImpl)process.getVirtualMachineProxy()).mirrorOf(b));
147 reference.setValues(mirrors);