diff --git a/compiler/cli/src/org/jetbrains/jet/compiler/CompileEnvironment.java b/compiler/cli/src/org/jetbrains/jet/compiler/CompileEnvironment.java index 1404bc105cf..2a8442f2d2d 100644 --- a/compiler/cli/src/org/jetbrains/jet/compiler/CompileEnvironment.java +++ b/compiler/cli/src/org/jetbrains/jet/compiler/CompileEnvironment.java @@ -17,23 +17,21 @@ package org.jetbrains.jet.compiler; import com.intellij.openapi.Disposable; -import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Disposer; import com.intellij.openapi.util.io.FileUtil; -import com.intellij.psi.JavaPsiFacade; -import com.intellij.psi.search.GlobalSearchScope; +import com.intellij.testFramework.LightVirtualFile; +import com.intellij.util.LocalTimeCounter; import com.intellij.util.Processor; import jet.modules.AllModules; import jet.modules.Module; -import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.jet.codegen.ClassFileFactory; import org.jetbrains.jet.codegen.GeneratedClassLoader; import org.jetbrains.jet.lang.psi.JetFile; import org.jetbrains.jet.lang.psi.JetPsiUtil; import org.jetbrains.jet.lang.resolve.java.JvmAbi; +import org.jetbrains.jet.plugin.JetLanguage; import org.jetbrains.jet.plugin.JetMainDetector; -import org.jetbrains.jet.plugin.compiler.PathUtil; import java.io.*; import java.lang.reflect.Method; @@ -59,10 +57,18 @@ public class CompileEnvironment { private boolean ignoreErrors = false; public CompileEnvironment() { - this(FileNameTransformer.IDENTITY); + this(FileNameTransformer.IDENTITY, null); } + public CompileEnvironment(ClassLoader loader) { + this(FileNameTransformer.IDENTITY, loader); + } + public CompileEnvironment(FileNameTransformer fileNameTransformer) { + this(fileNameTransformer, null); + } + + public CompileEnvironment(FileNameTransformer fileNameTransformer, ClassLoader loader) { myRootDisposable = new Disposable() { @Override public void dispose() { @@ -70,6 +76,10 @@ public class CompileEnvironment { }; myEnvironment = new JetCoreEnvironment(myRootDisposable); myFileNameTransformer = fileNameTransformer; + + if(loader != null) { + myEnvironment.addToClasspathFromClassLoader(loader); + } } public void setErrorStream(PrintStream errorStream) { @@ -84,78 +94,6 @@ public class CompileEnvironment { Disposer.dispose(myRootDisposable); } - @Nullable - public static File getUnpackedRuntimePath() { - URL url = CompileEnvironment.class.getClassLoader().getResource("jet/JetObject.class"); - if (url != null && url.getProtocol().equals("file")) { - return new File(url.getPath()).getParentFile().getParentFile(); - } - return null; - } - - @Nullable - public static File getRuntimeJarPath() { - URL url = CompileEnvironment.class.getClassLoader().getResource("jet/JetObject.class"); - if (url != null && url.getProtocol().equals("jar")) { - String path = url.getPath(); - return new File(path.substring(path.indexOf(":") + 1, path.indexOf("!/"))); - } - return null; - } - - public void ensureRuntime() { - ensureRuntime(myEnvironment); - } - - public static void ensureRuntime(@NotNull JetCoreEnvironment env) { - Project project = env.getProject(); - if (JavaPsiFacade.getInstance(project).findClass("java.lang.Object", GlobalSearchScope.allScope(project)) == null) { - // TODO: prepend - env.addToClasspath(findRtJar()); - } - - if (JavaPsiFacade.getInstance(project).findClass("jet.JetObject", GlobalSearchScope.allScope(project)) == null) { - // TODO: prepend - File kotlin = PathUtil.getDefaultRuntimePath(); - if (kotlin == null || !kotlin.exists()) { - kotlin = getUnpackedRuntimePath(); - if (kotlin == null) kotlin = getRuntimeJarPath(); - } - if (kotlin == null) { - throw new IllegalStateException("kotlin runtime not found"); - } - env.addToClasspath(kotlin); - } - } - - public static File findRtJar() { - String javaHome = System.getProperty("java.home"); - if ("jre".equals(new File(javaHome).getName())) { - javaHome = new File(javaHome).getParent(); - } - - File rtJar = findRtJar(javaHome); - - if (rtJar == null || !rtJar.exists()) { - throw new CompileEnvironmentException("No JDK rt.jar found under" + javaHome); - } - - return rtJar; - } - - private static File findRtJar(String javaHome) { - File rtJar = new File(javaHome, "jre/lib/rt.jar"); - if (rtJar.exists()) { - return rtJar; - } - - File classesJar = new File(new File(javaHome).getParentFile().getAbsolutePath(), "Classes/classes.jar"); - if (classesJar.exists()) { - return classesJar; - } - return null; - } - public void compileModuleScript(String moduleFile, @Nullable String jarPath, @Nullable String outputDir, boolean jarRuntime) { final List modules = loadModuleScript(moduleFile); @@ -189,7 +127,7 @@ public class CompileEnvironment { public List loadModuleScript(String moduleFile) { CompileSession scriptCompileSession = new CompileSession(myEnvironment, myFileNameTransformer); scriptCompileSession.addSources(moduleFile); - ensureRuntime(); + myEnvironment.ensureRuntime(); if (!scriptCompileSession.analyze(myErrorStream)) { return null; @@ -212,8 +150,9 @@ public class CompileEnvironment { method.setAccessible(true); method.invoke(null); - ArrayList answer = new ArrayList(AllModules.modules); - AllModules.modules.clear(); + ArrayList modules = AllModules.modules.get(); + ArrayList answer = new ArrayList(modules); + modules.clear(); return answer; } catch (Exception e) { @@ -247,7 +186,7 @@ public class CompileEnvironment { myEnvironment.addToClasspath(new File(classpathRoot)); } - ensureRuntime(); + myEnvironment.ensureRuntime(); if (!moduleCompileSession.analyze(myErrorStream) && !ignoreErrors) { return null; @@ -285,7 +224,7 @@ public class CompileEnvironment { } private static void writeRuntimeToJar(final JarOutputStream stream) throws IOException { - final File unpackedRuntimePath = getUnpackedRuntimePath(); + final File unpackedRuntimePath = JetCoreEnvironment.getUnpackedRuntimePath(); if (unpackedRuntimePath != null) { FileUtil.processFilesRecursively(unpackedRuntimePath, new Processor() { @Override @@ -308,7 +247,7 @@ public class CompileEnvironment { }); } else { - File runtimeJarPath = getRuntimeJarPath(); + File runtimeJarPath = JetCoreEnvironment.getRuntimeJarPath(); if (runtimeJarPath != null) { JarInputStream jis = new JarInputStream(new FileInputStream(runtimeJarPath)); try { @@ -332,6 +271,18 @@ public class CompileEnvironment { } } + public ClassLoader compileText(String code) { + CompileSession session = new CompileSession(myEnvironment, myFileNameTransformer); + session.addSources(new LightVirtualFile("script" + LocalTimeCounter.currentTime() + ".kt", JetLanguage.INSTANCE, code)); + + if (!session.analyze(myErrorStream) && !ignoreErrors) { + return null; + } + + ClassFileFactory factory = session.generate(); + return new GeneratedClassLoader(factory); + } + public boolean compileBunchOfSources(String sourceFileOrDir, String jar, String outputDir, boolean includeRuntime) { CompileSession session = new CompileSession(myEnvironment, myFileNameTransformer); session.addSources(sourceFileOrDir); @@ -345,7 +296,7 @@ public class CompileEnvironment { } } - ensureRuntime(); + myEnvironment.ensureRuntime(); if (!session.analyze(myErrorStream) && !ignoreErrors) { return false; diff --git a/compiler/cli/src/org/jetbrains/jet/compiler/JetCoreEnvironment.java b/compiler/cli/src/org/jetbrains/jet/compiler/JetCoreEnvironment.java index a101157b641..d9e30c32d26 100644 --- a/compiler/cli/src/org/jetbrains/jet/compiler/JetCoreEnvironment.java +++ b/compiler/cli/src/org/jetbrains/jet/compiler/JetCoreEnvironment.java @@ -20,12 +20,19 @@ import com.intellij.core.JavaCoreEnvironment; import com.intellij.lang.java.JavaParserDefinition; import com.intellij.mock.MockApplication; import com.intellij.openapi.Disposable; +import com.intellij.openapi.project.Project; import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.psi.JavaPsiFacade; +import com.intellij.psi.search.GlobalSearchScope; +import org.jetbrains.annotations.Nullable; import org.jetbrains.jet.lang.parsing.JetParserDefinition; import org.jetbrains.jet.lang.types.JetStandardLibrary; import org.jetbrains.jet.plugin.JetFileType; import org.jetbrains.jet.plugin.compiler.PathUtil; +import java.io.File; +import java.net.URL; +import java.net.URLClassLoader; import java.util.ArrayList; import java.util.List; @@ -57,6 +64,74 @@ public class JetCoreEnvironment extends JavaCoreEnvironment { JetStandardLibrary.initialize(getProject()); } + @Nullable + public static File getUnpackedRuntimePath() { + URL url = CompileEnvironment.class.getClassLoader().getResource("jet/JetObject.class"); + if (url != null && url.getProtocol().equals("file")) { + return new File(url.getPath()).getParentFile().getParentFile(); + } + return null; + } + + @Nullable + public static File getRuntimeJarPath() { + URL url = CompileEnvironment.class.getClassLoader().getResource("jet/JetObject.class"); + if (url != null && url.getProtocol().equals("jar")) { + String path = url.getPath(); + return new File(path.substring(path.indexOf(":") + 1, path.indexOf("!/"))); + } + return null; + } + + public static File findRtJar() { + String javaHome = System.getProperty("java.home"); + if ("jre".equals(new File(javaHome).getName())) { + javaHome = new File(javaHome).getParent(); + } + + File rtJar = findRtJar(javaHome); + + if (rtJar == null || !rtJar.exists()) { + throw new CompileEnvironmentException("No JDK rt.jar found under" + javaHome); + } + + return rtJar; + } + + private static File findRtJar(String javaHome) { + File rtJar = new File(javaHome, "jre/lib/rt.jar"); + if (rtJar.exists()) { + return rtJar; + } + + File classesJar = new File(new File(javaHome).getParentFile().getAbsolutePath(), "Classes/classes.jar"); + if (classesJar.exists()) { + return classesJar; + } + return null; + } + + public void ensureRuntime() { + Project project = getProject(); + if (JavaPsiFacade.getInstance(project).findClass("java.lang.Object", GlobalSearchScope.allScope(project)) == null) { + // TODO: prepend + addToClasspath(findRtJar()); + } + + if (JavaPsiFacade.getInstance(project).findClass("jet.JetObject", GlobalSearchScope.allScope(project)) == null) { + // TODO: prepend + File kotlin = PathUtil.getDefaultRuntimePath(); + if (kotlin == null || !kotlin.exists()) { + kotlin = getUnpackedRuntimePath(); + if (kotlin == null) kotlin = getRuntimeJarPath(); + } + if (kotlin == null) { + throw new IllegalStateException("kotlin runtime not found"); + } + addToClasspath(kotlin); + } + } + public MockApplication getApplication() { return myApplication; } @@ -68,4 +143,18 @@ public class JetCoreEnvironment extends JavaCoreEnvironment { public void setCompilerPlugins(List compilerPlugins) { this.compilerPlugins = compilerPlugins; } + + public void addToClasspathFromClassLoader(ClassLoader loader) { + ClassLoader parent = loader.getParent(); + if(parent != null) + addToClasspathFromClassLoader(parent); + + if(loader instanceof URLClassLoader) { + for (URL url : ((URLClassLoader) loader).getURLs()) { + File file = new File(url.getPath()); + if(!file.isFile() || file.getPath().endsWith(".jar")) + addToClasspath(file); + } + } + } } diff --git a/compiler/tests/org/jetbrains/jet/JetLiteFixture.java b/compiler/tests/org/jetbrains/jet/JetLiteFixture.java index 003828c1df8..6abb1f2d2aa 100644 --- a/compiler/tests/org/jetbrains/jet/JetLiteFixture.java +++ b/compiler/tests/org/jetbrains/jet/JetLiteFixture.java @@ -30,7 +30,6 @@ import com.intellij.testFramework.LightVirtualFile; import com.intellij.testFramework.TestDataFile; import com.intellij.testFramework.UsefulTestCase; import org.jetbrains.annotations.NonNls; -import org.jetbrains.jet.compiler.CompileEnvironment; import org.jetbrains.jet.compiler.JetCoreEnvironment; import org.jetbrains.jet.lang.psi.JetFile; import org.jetbrains.jet.plugin.JetLanguage; @@ -75,7 +74,7 @@ public abstract class JetLiteFixture extends UsefulTestCase { protected void createEnvironmentWithFullJdk() { myEnvironment = new JetCoreEnvironment(getTestRootDisposable()); - final File rtJar = CompileEnvironment.findRtJar(); + final File rtJar = JetCoreEnvironment.findRtJar(); myEnvironment.addToClasspath(rtJar); } diff --git a/compiler/tests/org/jetbrains/jet/codegen/CodegenTestCase.java b/compiler/tests/org/jetbrains/jet/codegen/CodegenTestCase.java index e0a828624fb..73b78acc40c 100644 --- a/compiler/tests/org/jetbrains/jet/codegen/CodegenTestCase.java +++ b/compiler/tests/org/jetbrains/jet/codegen/CodegenTestCase.java @@ -223,18 +223,4 @@ public abstract class CodegenTestCase extends JetLiteFixture { return loadClass(name, codegens); } - private static class MyClassLoader extends ClassLoader { - public MyClassLoader(ClassLoader parent) { - super(parent); - } - - public Class doDefineClass(String name, byte[] data) { - return defineClass(name, data, 0, data.length); - } - - @Override - public Class loadClass(String name) throws ClassNotFoundException { - return super.loadClass(name); - } - } } diff --git a/compiler/tests/org/jetbrains/jet/codegen/CompileTextTest.java b/compiler/tests/org/jetbrains/jet/codegen/CompileTextTest.java new file mode 100644 index 00000000000..12957a478cd --- /dev/null +++ b/compiler/tests/org/jetbrains/jet/codegen/CompileTextTest.java @@ -0,0 +1,35 @@ +/* + * Copyright 2000-2012 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jetbrains.jet.codegen; + +import junit.framework.TestCase; +import org.jetbrains.jet.compiler.CompileEnvironment; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; + +public class CompileTextTest extends TestCase { + public void testMe() throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException { + String text = "import org.jetbrains.jet.codegen.CompileTextTest; fun x() = CompileTextTest()"; + CompileEnvironment compileEnvironment = new CompileEnvironment(getClass().getClassLoader()); + ClassLoader classLoader = compileEnvironment.compileText(text); + Class namespace = classLoader.loadClass("namespace"); + Method x = namespace.getDeclaredMethod("x"); + Object invoke = x.invoke(null); + assertTrue(invoke instanceof CompileTextTest); + } +} \ No newline at end of file diff --git a/compiler/tests/org/jetbrains/jet/codegen/StdlibTest.java b/compiler/tests/org/jetbrains/jet/codegen/StdlibTest.java index bc9dc187f48..a1715e25b0e 100644 --- a/compiler/tests/org/jetbrains/jet/codegen/StdlibTest.java +++ b/compiler/tests/org/jetbrains/jet/codegen/StdlibTest.java @@ -16,8 +16,6 @@ package org.jetbrains.jet.codegen; -import org.jetbrains.jet.compiler.CompileEnvironment; - import java.lang.reflect.Method; import java.net.MalformedURLException; import java.net.URL; @@ -32,7 +30,7 @@ public class StdlibTest extends CodegenTestCase { super.setUp(); createEnvironmentWithFullJdk(); myEnvironment.addToClasspath(ForTestCompileStdlib.stdlibJarForTests()); - CompileEnvironment.ensureRuntime(myEnvironment); + myEnvironment.ensureRuntime(); } @Override diff --git a/stdlib/ktSrc/modules/ModuleBuilder.kt b/stdlib/ktSrc/modules/ModuleBuilder.kt index 487ef408f20..301e41930a8 100644 --- a/stdlib/ktSrc/modules/ModuleBuilder.kt +++ b/stdlib/ktSrc/modules/ModuleBuilder.kt @@ -6,7 +6,7 @@ import jet.modules.* fun module(name: String, callback: ModuleBuilder.() -> Unit) { val builder = ModuleBuilder(name) builder.callback() - AllModules.modules?.add(builder) + AllModules.modules.sure().get()?.add(builder) } class SourcesBuilder(val parent: ModuleBuilder) { diff --git a/stdlib/src/jet/modules/AllModules.java b/stdlib/src/jet/modules/AllModules.java index d40c79c1d1f..a6580fe39ed 100644 --- a/stdlib/src/jet/modules/AllModules.java +++ b/stdlib/src/jet/modules/AllModules.java @@ -22,5 +22,14 @@ package jet.modules; import java.util.ArrayList; public class AllModules { - public static final ArrayList modules = new ArrayList(); + + public static final ThreadLocal> modules = new ThreadLocal>() { + @Override + protected ArrayList initialValue() { + return new ArrayList(); + } + }; + + private AllModules() { + } }