aboutsummaryrefslogtreecommitdiff
path: root/nailgun_launcher
diff options
context:
space:
mode:
authorJan Christopher Vogt <oss.nsp@cvogt.org>2017-02-10 01:11:22 -0500
committerGitHub <noreply@github.com>2017-02-10 01:11:22 -0500
commitd743136c6b98fa91f501cc15dc47530f8f93b8fe (patch)
treeaedb9af30e41f056aea148cc9e3b37d17327ca54 /nailgun_launcher
parente2cb8726735ba306ade3befefae3b87549b52c9f (diff)
parentf5e653e033e468c58e8a832e0dce3a7020a66ce4 (diff)
downloadcbt-d743136c6b98fa91f501cc15dc47530f8f93b8fe.tar.gz
cbt-d743136c6b98fa91f501cc15dc47530f8f93b8fe.tar.bz2
cbt-d743136c6b98fa91f501cc15dc47530f8f93b8fe.zip
Merge pull request #314 from cvogt/fix-update-bugs
better caching and change propagation fixing link-time errors
Diffstat (limited to 'nailgun_launcher')
-rw-r--r--nailgun_launcher/BuildStage1Result.java8
-rw-r--r--nailgun_launcher/CbtURLClassLoader.java33
-rw-r--r--nailgun_launcher/ClassLoaderCache.java66
-rw-r--r--nailgun_launcher/ClassLoaderCache2.java37
-rw-r--r--nailgun_launcher/EarlyDependencies.java210
-rw-r--r--nailgun_launcher/NailgunLauncher.java128
-rw-r--r--nailgun_launcher/Stage0Lib.java67
-rw-r--r--nailgun_launcher/TrapSecurityManager.java2
8 files changed, 327 insertions, 224 deletions
diff --git a/nailgun_launcher/BuildStage1Result.java b/nailgun_launcher/BuildStage1Result.java
index 312871d..64a660d 100644
--- a/nailgun_launcher/BuildStage1Result.java
+++ b/nailgun_launcher/BuildStage1Result.java
@@ -1,12 +1,14 @@
package cbt;
public class BuildStage1Result{
- public Boolean changed;
+ public long start;
+ public long stage1LastModified;
public ClassLoader classLoader;
public String stage1Classpath;
public String nailgunClasspath;
public String compatibilityClasspath;
- public BuildStage1Result( Boolean changed, ClassLoader classLoader, String stage1Classpath, String nailgunClasspath, String compatibilityClasspath ){
- this.changed = changed;
+ public BuildStage1Result( long start, long stage1LastModified, ClassLoader classLoader, String stage1Classpath, String nailgunClasspath, String compatibilityClasspath ){
+ this.start = start;
+ this.stage1LastModified = stage1LastModified;
this.classLoader = classLoader;
this.stage1Classpath = stage1Classpath;
this.nailgunClasspath = nailgunClasspath;
diff --git a/nailgun_launcher/CbtURLClassLoader.java b/nailgun_launcher/CbtURLClassLoader.java
index 38fc905..bf698b0 100644
--- a/nailgun_launcher/CbtURLClassLoader.java
+++ b/nailgun_launcher/CbtURLClassLoader.java
@@ -15,30 +15,29 @@ public class CbtURLClassLoader extends java.net.URLClassLoader{
+ "\n)"
);
}
- ClassLoaderCache2<Class> cache = new ClassLoaderCache2<Class>(
- new ConcurrentHashMap<String, Object>(),
- new ConcurrentHashMap<Object, Class>()
- );
+ ConcurrentHashMap<String,Class> cache = new ConcurrentHashMap<String,Class>();
public Class loadClass(String name) throws ClassNotFoundException{
Class _class = super.loadClass(name);
if(_class == null) throw new ClassNotFoundException(name);
else return _class;
}
- public Class loadClass(String name, Boolean resolve) throws ClassNotFoundException{
+ public Class loadClass(String name, boolean resolve) throws ClassNotFoundException{
//System.out.println("loadClass("+name+") on \n"+this);
- if(!cache.contains(name))
- try{
- cache.put(super.loadClass(name, resolve), name);
- } catch (ClassNotFoundException e){
- cache.put(Object.class, name);
+ synchronized( cache ){
+ if(!cache.containsKey(name))
+ try{
+ cache.put(name, super.loadClass(name, resolve));
+ } catch (ClassNotFoundException e){
+ cache.put(name, Object.class);
+ }
+ Class _class = cache.get(name);
+ if(_class == Object.class){
+ if( name.equals("java.lang.Object") )
+ return Object.class;
+ else return null;
+ } else {
+ return _class;
}
- Class _class = cache.get(name);
- if(_class == Object.class){
- if( name == "java.lang.Object" )
- return Object.class;
- else return null;
- } else {
- return _class;
}
}
void assertExist(URL[] urls){
diff --git a/nailgun_launcher/ClassLoaderCache.java b/nailgun_launcher/ClassLoaderCache.java
new file mode 100644
index 0000000..6bffad0
--- /dev/null
+++ b/nailgun_launcher/ClassLoaderCache.java
@@ -0,0 +1,66 @@
+package cbt;
+
+import java.util.*;
+import static java.io.File.pathSeparator;
+import static cbt.Stage0Lib.*;
+
+final public class ClassLoaderCache{
+ public Map<Object,Object> hashMap;
+ final ThreadLocal<HashSet<String>> seen = new ThreadLocal<HashSet<String>>(){
+ @Override protected HashSet<String> initialValue(){
+ return new HashSet<String>();
+ }
+ };
+
+ public ClassLoaderCache(
+ Map<Object,Object> hashMap
+ ){
+ this.hashMap = hashMap;
+ }
+
+ public ClassLoader get( String key, long timestamp ){
+ seen.get().add( key );
+ @SuppressWarnings("unchecked")
+ ClassLoader t = (ClassLoader) hashMap.get(
+ hashMap.get( key )
+ );
+ assert hashMap.get(t).equals(timestamp);
+ return t;
+ }
+
+ public boolean containsKey( String key, long timestamp ){
+ boolean contains = hashMap.containsKey( key );
+ if( contains ){
+ Object keyObject = hashMap.get( key );
+ Object classLoader = hashMap.get( keyObject );
+ long oldTimestamp = (long) hashMap.get( classLoader );
+ boolean res = oldTimestamp == timestamp;
+ return res;
+ } else {
+ return false;
+ }
+ }
+
+ public void put( String key, ClassLoader value, long timestamp ){
+ assert !seen.get().contains( key ): "Thread tries to update cache key after observing it: " + key;
+ LockableJavaKey keyObject = new LockableJavaKey();
+ hashMap.put( key, keyObject );
+ hashMap.put( keyObject, value );
+ hashMap.put( value, timestamp );
+ }
+
+ @Override public String toString(){
+ StringBuilder res = new StringBuilder();
+ res.append("ClassLoaderCache(\n\n");
+ for( Object key: hashMap.keySet() ){
+ if( key instanceof String )
+ res.append(
+ join( "\n", key.toString().split(":") ) + " -> " + hashMap.get( hashMap.get(key) )
+ + "\n\n"
+ );
+ }
+ res.append("\n\n");
+ return res.toString();
+ }
+}
+class LockableJavaKey{}
diff --git a/nailgun_launcher/ClassLoaderCache2.java b/nailgun_launcher/ClassLoaderCache2.java
deleted file mode 100644
index bf9ca3b..0000000
--- a/nailgun_launcher/ClassLoaderCache2.java
+++ /dev/null
@@ -1,37 +0,0 @@
-package cbt;
-
-import java.util.*;
-import java.util.concurrent.ConcurrentHashMap;
-import static java.io.File.pathSeparator;
-import static cbt.Stage0Lib.*;
-
-final class ClassLoaderCache2<T>{
- ConcurrentHashMap<String,Object> keys;
- ConcurrentHashMap<Object,T> values;
-
- public ClassLoaderCache2(
- ConcurrentHashMap<String,Object> keys,
- ConcurrentHashMap<Object,T> values
- ){
- this.keys = keys;
- this.values = values;
- }
-
- public T get( String key ){
- return values.get(
- keys.get( key )
- );
- }
-
- public Boolean contains( String key ){
- return keys.containsKey( key );
- }
-
- public T put( T value, String key ){
- LockableKey2 keyObject = new LockableKey2();
- keys.put( key, keyObject );
- values.put( keyObject, value );
- return value;
- }
-}
-class LockableKey2{} \ No newline at end of file
diff --git a/nailgun_launcher/EarlyDependencies.java b/nailgun_launcher/EarlyDependencies.java
index 4ffbdfd..8709e69 100644
--- a/nailgun_launcher/EarlyDependencies.java
+++ b/nailgun_launcher/EarlyDependencies.java
@@ -4,6 +4,7 @@ import java.io.*;
import java.nio.file.*;
import java.net.*;
import java.security.*;
+import java.util.*;
import static cbt.Stage0Lib.*;
import static cbt.NailgunLauncher.*;
@@ -19,125 +20,134 @@ class EarlyDependencies{
String scalaCompiler_2_11_8_File;
String scalaXml_1_0_5_File;
String scalaLibrary_2_11_8_File;
- String zinc_0_3_9_File;
- String incrementalCompiler_0_13_9_File;
- String compilerInterface_0_13_9_File;
- String scalaCompiler_2_10_5_File;
- String sbtInterface_0_13_9_File;
- String scalaReflect_2_10_5_File;
- String scalaLibrary_2_10_5_File;
+ String zinc_0_3_12_File;
+ String incrementalCompiler_0_13_12_File;
+ String compilerInterface_0_13_12_File;
+ String scalaCompiler_2_10_6_File;
+ String sbtInterface_0_13_12_File;
+ String scalaReflect_2_10_6_File;
+ String scalaLibrary_2_10_6_File;
public EarlyDependencies(
- String mavenCache, String mavenUrl, ClassLoaderCache2<ClassLoader> classLoaderCache, ClassLoader rootClassLoader
+ String mavenCache, String mavenUrl, ClassLoaderCache classLoaderCache, ClassLoader rootClassLoader
) throws Throwable {
scalaReflect_2_11_8_File = mavenCache + "/org/scala-lang/scala-reflect/2.11.8/scala-reflect-2.11.8.jar";
scalaCompiler_2_11_8_File = mavenCache + "/org/scala-lang/scala-compiler/2.11.8/scala-compiler-2.11.8.jar";
scalaXml_1_0_5_File = mavenCache + "/org/scala-lang/modules/scala-xml_2.11/1.0.5/scala-xml_2.11-1.0.5.jar";
scalaLibrary_2_11_8_File = mavenCache + "/org/scala-lang/scala-library/2.11.8/scala-library-2.11.8.jar";
- zinc_0_3_9_File = mavenCache + "/com/typesafe/zinc/zinc/0.3.9/zinc-0.3.9.jar";
- incrementalCompiler_0_13_9_File = mavenCache + "/com/typesafe/sbt/incremental-compiler/0.13.9/incremental-compiler-0.13.9.jar";
- compilerInterface_0_13_9_File = mavenCache + "/com/typesafe/sbt/compiler-interface/0.13.9/compiler-interface-0.13.9-sources.jar";
- scalaCompiler_2_10_5_File = mavenCache + "/org/scala-lang/scala-compiler/2.10.5/scala-compiler-2.10.5.jar";
- sbtInterface_0_13_9_File = mavenCache + "/com/typesafe/sbt/sbt-interface/0.13.9/sbt-interface-0.13.9.jar";
- scalaReflect_2_10_5_File = mavenCache + "/org/scala-lang/scala-reflect/2.10.5/scala-reflect-2.10.5.jar";
- scalaLibrary_2_10_5_File = mavenCache + "/org/scala-lang/scala-library/2.10.5/scala-library-2.10.5.jar";
+ zinc_0_3_12_File = mavenCache + "/com/typesafe/zinc/zinc/0.3.12/zinc-0.3.12.jar";
+ incrementalCompiler_0_13_12_File = mavenCache + "/com/typesafe/sbt/incremental-compiler/0.13.12/incremental-compiler-0.13.12.jar";
+ compilerInterface_0_13_12_File = mavenCache + "/com/typesafe/sbt/compiler-interface/0.13.12/compiler-interface-0.13.12-sources.jar";
+ scalaCompiler_2_10_6_File = mavenCache + "/org/scala-lang/scala-compiler/2.10.6/scala-compiler-2.10.6.jar";
+ sbtInterface_0_13_12_File = mavenCache + "/com/typesafe/sbt/sbt-interface/0.13.12/sbt-interface-0.13.12.jar";
+ scalaReflect_2_10_6_File = mavenCache + "/org/scala-lang/scala-reflect/2.10.6/scala-reflect-2.10.6.jar";
+ scalaLibrary_2_10_6_File = mavenCache + "/org/scala-lang/scala-library/2.10.6/scala-library-2.10.6.jar";
download(new URL(mavenUrl + "/org/scala-lang/scala-reflect/2.11.8/scala-reflect-2.11.8.jar"), Paths.get(scalaReflect_2_11_8_File), "b74530deeba742ab4f3134de0c2da0edc49ca361");
download(new URL(mavenUrl + "/org/scala-lang/scala-compiler/2.11.8/scala-compiler-2.11.8.jar"), Paths.get(scalaCompiler_2_11_8_File), "fe1285c9f7b58954c5ef6d80b59063569c065e9a");
- // org.scala-lang:scala-library:2.10.5
- download(new URL(mavenUrl + "/org/scala-lang/scala-library/2.10.5/scala-library-2.10.5.jar"), Paths.get(scalaLibrary_2_10_5_File), "57ac67a6cf6fd591e235c62f8893438e8d10431d");
-
- String[] scalaLibrary_2_10_5_ClasspathArray = new String[]{scalaLibrary_2_10_5_File};
- String scalaLibrary_2_10_5_Classpath = classpath( scalaLibrary_2_10_5_ClasspathArray );
- ClassLoader scalaLibrary_2_10_5_ =
- classLoaderCache.contains( scalaLibrary_2_10_5_Classpath )
- ? classLoaderCache.get( scalaLibrary_2_10_5_Classpath )
- : classLoaderCache.put( classLoader( scalaLibrary_2_10_5_File, rootClassLoader ), scalaLibrary_2_10_5_Classpath );
-
- // org.scala-lang:scala-reflect:2.10.5
- download(new URL(mavenUrl + "/org/scala-lang/scala-reflect/2.10.5/scala-reflect-2.10.5.jar"), Paths.get(scalaReflect_2_10_5_File), "7392facb48876c67a89fcb086112b195f5f6bbc3");
-
- String[] scalaReflect_2_10_5_ClasspathArray = new String[]{scalaLibrary_2_10_5_File, scalaReflect_2_10_5_File};
- String scalaReflect_2_10_5_Classpath = classpath( scalaReflect_2_10_5_ClasspathArray );
- ClassLoader scalaReflect_2_10_5_ =
- classLoaderCache.contains( scalaReflect_2_10_5_Classpath )
- ? classLoaderCache.get( scalaReflect_2_10_5_Classpath )
- : classLoaderCache.put( classLoader( scalaReflect_2_10_5_File, scalaLibrary_2_10_5_ ), scalaReflect_2_10_5_Classpath );
-
- // com.typesafe.sbt:sbt-interface:0.13.9
- download(new URL(mavenUrl + "/com/typesafe/sbt/sbt-interface/0.13.9/sbt-interface-0.13.9.jar"), Paths.get(sbtInterface_0_13_9_File), "29848631415402c81b732e919be88f268df37250");
-
- String[] sbtInterface_0_13_9_ClasspathArray = new String[]{sbtInterface_0_13_9_File, scalaLibrary_2_10_5_File, scalaReflect_2_10_5_File};
- String sbtInterface_0_13_9_Classpath = classpath( sbtInterface_0_13_9_ClasspathArray );
- ClassLoader sbtInterface_0_13_9_ =
- classLoaderCache.contains( sbtInterface_0_13_9_Classpath )
- ? classLoaderCache.get( sbtInterface_0_13_9_Classpath )
- : classLoaderCache.put( classLoader( sbtInterface_0_13_9_File, scalaReflect_2_10_5_ ), sbtInterface_0_13_9_Classpath );
-
- // org.scala-lang:scala-compiler:2.10.5
- download(new URL(mavenUrl + "/org/scala-lang/scala-compiler/2.10.5/scala-compiler-2.10.5.jar"), Paths.get(scalaCompiler_2_10_5_File), "f0f5bb444ca26a6e489af3dd35e24f7e2d2d118e");
-
- String[] scalaCompiler_2_10_5_ClasspathArray = new String[]{sbtInterface_0_13_9_File, scalaCompiler_2_10_5_File, scalaLibrary_2_10_5_File, scalaReflect_2_10_5_File};
- String scalaCompiler_2_10_5_Classpath = classpath( scalaCompiler_2_10_5_ClasspathArray );
- ClassLoader scalaCompiler_2_10_5_ =
- classLoaderCache.contains( scalaCompiler_2_10_5_Classpath )
- ? classLoaderCache.get( scalaCompiler_2_10_5_Classpath )
- : classLoaderCache.put( classLoader( scalaCompiler_2_10_5_File, sbtInterface_0_13_9_ ), scalaCompiler_2_10_5_Classpath );
-
- // com.typesafe.sbt:compiler-interface:0.13.9
- download(new URL(mavenUrl + "/com/typesafe/sbt/compiler-interface/0.13.9/compiler-interface-0.13.9-sources.jar"), Paths.get(compilerInterface_0_13_9_File), "2311addbed1182916ad00f83c57c0eeca1af382b");
-
- String[] compilerInterface_0_13_9_ClasspathArray = new String[]{compilerInterface_0_13_9_File, sbtInterface_0_13_9_File, scalaCompiler_2_10_5_File, scalaLibrary_2_10_5_File, scalaReflect_2_10_5_File};
- String compilerInterface_0_13_9_Classpath = classpath( compilerInterface_0_13_9_ClasspathArray );
- ClassLoader compilerInterface_0_13_9_ =
- classLoaderCache.contains( compilerInterface_0_13_9_Classpath )
- ? classLoaderCache.get( compilerInterface_0_13_9_Classpath )
- : classLoaderCache.put( classLoader( compilerInterface_0_13_9_File, scalaCompiler_2_10_5_ ), compilerInterface_0_13_9_Classpath );
-
- // com.typesafe.sbt:incremental-compiler:0.13.9
- download(new URL(mavenUrl + "/com/typesafe/sbt/incremental-compiler/0.13.9/incremental-compiler-0.13.9.jar"), Paths.get(incrementalCompiler_0_13_9_File), "fbbf1cadbed058aa226643e83543c35de43b13f0");
-
- String[] incrementalCompiler_0_13_9_ClasspathArray = new String[]{compilerInterface_0_13_9_File, incrementalCompiler_0_13_9_File, sbtInterface_0_13_9_File, scalaCompiler_2_10_5_File, scalaLibrary_2_10_5_File, scalaReflect_2_10_5_File};
- String incrementalCompiler_0_13_9_Classpath = classpath( incrementalCompiler_0_13_9_ClasspathArray );
- ClassLoader incrementalCompiler_0_13_9_ =
- classLoaderCache.contains( incrementalCompiler_0_13_9_Classpath )
- ? classLoaderCache.get( incrementalCompiler_0_13_9_Classpath )
- : classLoaderCache.put( classLoader( incrementalCompiler_0_13_9_File, compilerInterface_0_13_9_ ), incrementalCompiler_0_13_9_Classpath );
-
- // com.typesafe.zinc:zinc:0.3.9
- download(new URL(mavenUrl + "/com/typesafe/zinc/zinc/0.3.9/zinc-0.3.9.jar"), Paths.get(zinc_0_3_9_File), "46a4556d1f36739879f4b2cc19a73d12b3036e9a");
-
- String[] zinc_0_3_9_ClasspathArray = new String[]{compilerInterface_0_13_9_File, incrementalCompiler_0_13_9_File, sbtInterface_0_13_9_File, zinc_0_3_9_File, scalaCompiler_2_10_5_File, scalaLibrary_2_10_5_File, scalaReflect_2_10_5_File};
- String zinc_0_3_9_Classpath = classpath( zinc_0_3_9_ClasspathArray );
- ClassLoader zinc_0_3_9_ =
- classLoaderCache.contains( zinc_0_3_9_Classpath )
- ? classLoaderCache.get( zinc_0_3_9_Classpath )
- : classLoaderCache.put( classLoader( zinc_0_3_9_File, incrementalCompiler_0_13_9_ ), zinc_0_3_9_Classpath );
+ // org.scala-lang:scala-library:2.10.6
+ String[] scalaLibrary_2_10_6_ClasspathArray = new String[]{scalaLibrary_2_10_6_File};
+ ClassLoader scalaLibrary_2_10_6_ = loadDependency(
+ mavenUrl + "/org/scala-lang/scala-library/2.10.6/scala-library-2.10.6.jar",
+ scalaLibrary_2_10_6_File,
+ "421989aa8f95a05a4f894630aad96b8c7b828732",
+ classLoaderCache,
+ rootClassLoader,
+ scalaLibrary_2_10_6_ClasspathArray
+ );
+
+ // org.scala-lang:scala-reflect:2.10.6
+ String[] scalaReflect_2_10_6_ClasspathArray = new String[]{scalaLibrary_2_10_6_File, scalaReflect_2_10_6_File};
+ ClassLoader scalaReflect_2_10_6_ = loadDependency(
+ mavenUrl + "/org/scala-lang/scala-reflect/2.10.6/scala-reflect-2.10.6.jar",
+ scalaReflect_2_10_6_File,
+ "3259f3df0f166f017ef5b2d385445808398c316c",
+ classLoaderCache,
+ scalaLibrary_2_10_6_,
+ scalaReflect_2_10_6_ClasspathArray
+ );
+
+ // com.typesafe.sbt:sbt-interface:0.13.12
+ String[] sbtInterface_0_13_12_ClasspathArray = new String[]{sbtInterface_0_13_12_File, scalaLibrary_2_10_6_File, scalaReflect_2_10_6_File};
+ ClassLoader sbtInterface_0_13_12_ = loadDependency(
+ mavenUrl + "/com/typesafe/sbt/sbt-interface/0.13.12/sbt-interface-0.13.12.jar",
+ sbtInterface_0_13_12_File,
+ "fcc7875c02f0d4641fac0518121bd71475d3909b",
+ classLoaderCache,
+ scalaReflect_2_10_6_,
+ sbtInterface_0_13_12_ClasspathArray
+ );
+
+ // org.scala-lang:scala-compiler:2.10.6
+ String[] scalaCompiler_2_10_6_ClasspathArray = new String[]{sbtInterface_0_13_12_File, scalaCompiler_2_10_6_File, scalaLibrary_2_10_6_File, scalaReflect_2_10_6_File};
+ ClassLoader scalaCompiler_2_10_6_ = loadDependency(
+ mavenUrl + "/org/scala-lang/scala-compiler/2.10.6/scala-compiler-2.10.6.jar",
+ scalaCompiler_2_10_6_File,
+ "9b15174852f5b6bb1edbf303d5722286a0a54011",
+ classLoaderCache,
+ sbtInterface_0_13_12_,
+ scalaCompiler_2_10_6_ClasspathArray
+ );
+
+ // com.typesafe.sbt:compiler-interface:0.13.12
+ String[] compilerInterface_0_13_12_ClasspathArray = new String[]{compilerInterface_0_13_12_File, sbtInterface_0_13_12_File, scalaCompiler_2_10_6_File, scalaLibrary_2_10_6_File, scalaReflect_2_10_6_File};
+ ClassLoader compilerInterface_0_13_12_ = loadDependency(
+ mavenUrl + "/com/typesafe/sbt/compiler-interface/0.13.12/compiler-interface-0.13.12-sources.jar",
+ compilerInterface_0_13_12_File,
+ "d9c3270576e162bf017b146af262364c2db87a32",
+ classLoaderCache,
+ scalaCompiler_2_10_6_,
+ compilerInterface_0_13_12_ClasspathArray
+ );
+
+ // com.typesafe.sbt:incremental-compiler:0.13.12
+ String[] incrementalCompiler_0_13_12_ClasspathArray = new String[]{compilerInterface_0_13_12_File, incrementalCompiler_0_13_12_File, sbtInterface_0_13_12_File, scalaCompiler_2_10_6_File, scalaLibrary_2_10_6_File, scalaReflect_2_10_6_File};
+ ClassLoader incrementalCompiler_0_13_12_ = loadDependency(
+ mavenUrl + "/com/typesafe/sbt/incremental-compiler/0.13.12/incremental-compiler-0.13.12.jar",
+ incrementalCompiler_0_13_12_File,
+ "259f6d24a5a3791bb233787d6a8e639c4ab86fe5",
+ classLoaderCache,
+ compilerInterface_0_13_12_,
+ incrementalCompiler_0_13_12_ClasspathArray
+ );
+
+ // com.typesafe.zinc:zinc:0.3.12
+ String[] zinc_0_3_12_ClasspathArray = new String[]{compilerInterface_0_13_12_File, incrementalCompiler_0_13_12_File, sbtInterface_0_13_12_File, zinc_0_3_12_File, scalaCompiler_2_10_6_File, scalaLibrary_2_10_6_File, scalaReflect_2_10_6_File};
+ ClassLoader zinc_0_3_12_ = loadDependency(
+ mavenUrl + "/com/typesafe/zinc/zinc/0.3.12/zinc-0.3.12.jar",
+ zinc_0_3_12_File,
+ "c4339e93f5b7273f49ad026248f4fdb1d4d6c7c4",
+ classLoaderCache,
+ incrementalCompiler_0_13_12_,
+ zinc_0_3_12_ClasspathArray
+ );
// org.scala-lang:scala-library:2.11.8
- download(new URL(mavenUrl + "/org/scala-lang/scala-library/2.11.8/scala-library-2.11.8.jar"), Paths.get(scalaLibrary_2_11_8_File), "ddd5a8bced249bedd86fb4578a39b9fb71480573");
-
String[] scalaLibrary_2_11_8_ClasspathArray = new String[]{scalaLibrary_2_11_8_File};
- String scalaLibrary_2_11_8_Classpath = classpath( scalaLibrary_2_11_8_ClasspathArray );
- ClassLoader scalaLibrary_2_11_8_ =
- classLoaderCache.contains( scalaLibrary_2_11_8_Classpath )
- ? classLoaderCache.get( scalaLibrary_2_11_8_Classpath )
- : classLoaderCache.put( classLoader( scalaLibrary_2_11_8_File, rootClassLoader ), scalaLibrary_2_11_8_Classpath );
+ ClassLoader scalaLibrary_2_11_8_ = loadDependency(
+ mavenUrl + "/org/scala-lang/scala-library/2.11.8/scala-library-2.11.8.jar",
+ scalaLibrary_2_11_8_File,
+ "ddd5a8bced249bedd86fb4578a39b9fb71480573",
+ classLoaderCache,
+ rootClassLoader,
+ scalaLibrary_2_11_8_ClasspathArray
+ );
// org.scala-lang.modules:scala-xml_2.11:1.0.5
- download(new URL(mavenUrl + "/org/scala-lang/modules/scala-xml_2.11/1.0.5/scala-xml_2.11-1.0.5.jar"), Paths.get(scalaXml_1_0_5_File), "77ac9be4033768cf03cc04fbd1fc5e5711de2459");
-
String[] scalaXml_1_0_5_ClasspathArray = new String[]{scalaXml_1_0_5_File, scalaLibrary_2_11_8_File};
- String scalaXml_1_0_5_Classpath = classpath( scalaXml_1_0_5_ClasspathArray );
- ClassLoader scalaXml_1_0_5_ =
- classLoaderCache.contains( scalaXml_1_0_5_Classpath )
- ? classLoaderCache.get( scalaXml_1_0_5_Classpath )
- : classLoaderCache.put( classLoader( scalaXml_1_0_5_File, scalaLibrary_2_11_8_ ), scalaXml_1_0_5_Classpath );
-
+ ClassLoader scalaXml_1_0_5_ = loadDependency(
+ mavenUrl + "/org/scala-lang/modules/scala-xml_2.11/1.0.5/scala-xml_2.11-1.0.5.jar",
+ scalaXml_1_0_5_File,
+ "77ac9be4033768cf03cc04fbd1fc5e5711de2459",
+ classLoaderCache,
+ scalaLibrary_2_11_8_,
+ scalaXml_1_0_5_ClasspathArray
+ );
+
classLoader = scalaXml_1_0_5_;
classpathArray = scalaXml_1_0_5_ClasspathArray;
- zinc = zinc_0_3_9_;
+ zinc = zinc_0_3_12_;
}
}
diff --git a/nailgun_launcher/NailgunLauncher.java b/nailgun_launcher/NailgunLauncher.java
index 944daf8..d89c764 100644
--- a/nailgun_launcher/NailgunLauncher.java
+++ b/nailgun_launcher/NailgunLauncher.java
@@ -4,7 +4,6 @@ import java.lang.reflect.*;
import java.net.*;
import java.security.*;
import java.util.*;
-import java.util.concurrent.ConcurrentHashMap;
import static cbt.Stage0Lib.*;
import static java.io.File.pathSeparator;
@@ -15,10 +14,7 @@ import static java.io.File.pathSeparator;
*/
public class NailgunLauncher{
/** Persistent cache for caching classloaders for the JVM life time. */
- private final static ClassLoaderCache2<ClassLoader> classLoaderCache = new ClassLoaderCache2<ClassLoader>(
- new ConcurrentHashMap<String,Object>(),
- new ConcurrentHashMap<Object,ClassLoader>()
- );
+ private static Map<Object,Object> classLoaderCacheHashMap = new HashMap<Object,Object>();
public final static SecurityManager initialSecurityManager
= System.getSecurityManager();
@@ -30,14 +26,13 @@ public class NailgunLauncher{
@SuppressWarnings("unchecked")
public static Object getBuild( Object context ) throws Throwable{
BuildStage1Result res = buildStage1(
- (Boolean) get(context, "cbtHasChangedCompat"),
- (Long) get(context, "startCompat"),
+ (long) get(context, "cbtLastModified"),
+ (long) get(context, "start"),
((File) get(context, "cache")).toString() + "/",
((File) get(context, "cbtHome")).toString(),
((File) get(context, "compatibilityTarget")).toString() + "/",
- new ClassLoaderCache2<ClassLoader>(
- (ConcurrentHashMap<String,Object>) get(context, "permanentKeys"),
- (ConcurrentHashMap<Object,ClassLoader>) get(context, "permanentClassLoaders")
+ new ClassLoaderCache(
+ (HashMap) get(context, "persistentCache")
)
);
return
@@ -48,8 +43,16 @@ public class NailgunLauncher{
.invoke(null, context, res);
}
+ public static long nailgunLauncherLastModified = -1; // this initial value should be overwritten, never read
+
+ // wrap for caching
+ public static ClassLoader jdkClassLoader = new CbtURLClassLoader(
+ new URL[]{},
+ ClassLoader.getSystemClassLoader().getParent()
+ );
+
public static void main( String[] args ) throws Throwable {
- Long _start = System.currentTimeMillis();
+ long _start = System.currentTimeMillis();
if(args[0].equals("check-alive")){
System.exit(33);
return;
@@ -65,13 +68,13 @@ public class NailgunLauncher{
// scala.Console, which captured them at startup
try{
System.out.getClass().getDeclaredField("streams"); // nailgun ThreadLocalPrintStream
- assert(System.out.getClass().getName() == "com.martiansoftware.nailgun.ThreadLocalPrintStream");
+ assert(System.out.getClass().getName().equals("com.martiansoftware.nailgun.ThreadLocalPrintStream"));
} catch( NoSuchFieldException e ){
System.setOut( new PrintStream(new ThreadLocalOutputStream(System.out), true) );
}
try{
System.err.getClass().getDeclaredField("streams"); // nailgun ThreadLocalPrintStream
- assert(System.err.getClass().getName() == "com.martiansoftware.nailgun.ThreadLocalPrintStream");
+ assert(System.err.getClass().getName().equals("com.martiansoftware.nailgun.ThreadLocalPrintStream"));
} catch( NoSuchFieldException e ){
System.setErr( new PrintStream(new ThreadLocalOutputStream(System.err), true) );
}
@@ -81,28 +84,38 @@ public class NailgunLauncher{
String CBT_HOME = System.getenv("CBT_HOME");
String cache = CBT_HOME + "/cache/";
String compatibilityTarget = CBT_HOME + "/compatibility/" + TARGET;
+ // copy cache, so that this thread has a consistent view despite other threads
+ // changing their copies
+ // replace again before returning, see below
+ ClassLoaderCache classLoaderCache = new ClassLoaderCache(
+ new HashMap<Object,Object>(classLoaderCacheHashMap)
+ );
+
+ String nailgunTarget = CBT_HOME + "/" + NAILGUN + TARGET;
+ long nailgunLauncherLastModified = new File( nailgunTarget + "../classes.last-success" ).lastModified();
+
BuildStage1Result res = buildStage1(
- false, start, cache, CBT_HOME, compatibilityTarget, classLoaderCache
+ nailgunLauncherLastModified, start, cache, CBT_HOME, compatibilityTarget, classLoaderCache
);
try{
- System.exit(
- (Integer) res
- .classLoader
- .loadClass("cbt.Stage1")
- .getMethod(
- "run",
- String[].class, File.class, File.class, BuildStage1Result.class,
- Long.class, ConcurrentHashMap.class, ConcurrentHashMap.class
- )
- .invoke(
- null,
- (Object) args, new File(cache), new File(CBT_HOME), res,
- start, classLoaderCache.keys, classLoaderCache.values
- )
- );
+ int exitCode = (int) res
+ .classLoader
+ .loadClass("cbt.Stage1")
+ .getMethod(
+ "run", String[].class, File.class, File.class, BuildStage1Result.class, Map.class
+ ).invoke(
+ null, (Object) args, new File(cache), new File(CBT_HOME), res, classLoaderCache.hashMap
+ );
+
+ System.exit( exitCode );
} catch (java.lang.reflect.InvocationTargetException e) {
throw unwrapInvocationTargetException(e);
+ } finally {
+ // This replaces the cache and should be thread-safe.
+ // For competing threads the last one wins with a consistent cache.
+ // So worst case, we loose some of the cache that's replaced.
+ classLoaderCacheHashMap = classLoaderCache.hashMap;
}
}
@@ -115,7 +128,8 @@ public class NailgunLauncher{
}
public static BuildStage1Result buildStage1(
- Boolean changed, long start, String cache, String cbtHome, String compatibilityTarget, ClassLoaderCache2<ClassLoader> classLoaderCache
+ final long lastModified, final long start, final String cache, final String cbtHome,
+ final String compatibilityTarget, final ClassLoaderCache classLoaderCache
) throws Throwable {
_assert(TARGET != null, "environment variable TARGET not defined");
String nailgunTarget = cbtHome + "/" + NAILGUN + TARGET;
@@ -128,30 +142,32 @@ public class NailgunLauncher{
ClassLoader rootClassLoader = new CbtURLClassLoader( new URL[]{}, ClassLoader.getSystemClassLoader().getParent() ); // wrap for caching
EarlyDependencies earlyDeps = new EarlyDependencies(mavenCache, mavenUrl, classLoaderCache, rootClassLoader);
- ClassLoader compatibilityClassLoader;
+ long nailgunLauncherLastModified = new File( nailgunTarget + "../classes.last-success" ).lastModified();
+
+ long compatibilityLastModified;
if(!compatibilityTarget.startsWith(cbtHome)){
- compatibilityClassLoader = classLoaderCache.get( compatibilityTarget );
+ compatibilityLastModified = new File( compatibilityTarget + "../classes.last-success" ).lastModified();
} else {
List<File> compatibilitySourceFiles = new ArrayList<File>();
for( File f: compatibilitySources.listFiles() ){
- if( f.isFile() && (f.toString().endsWith(".scala") || f.toString().endsWith(".java")) ){
+ if( f.isFile() && f.toString().endsWith(".java") ){
compatibilitySourceFiles.add(f);
}
}
- changed = compile(changed, start, "", compatibilityTarget, earlyDeps, compatibilitySourceFiles);
-
- if( classLoaderCache.contains( compatibilityTarget ) ){
- compatibilityClassLoader = classLoaderCache.get( compatibilityTarget );
- } else {
- compatibilityClassLoader = classLoaderCache.put( classLoader(compatibilityTarget, rootClassLoader), compatibilityTarget );
+
+ compatibilityLastModified = compile( 0L, "", compatibilityTarget, earlyDeps, compatibilitySourceFiles);
+
+ if( !classLoaderCache.containsKey( compatibilityTarget, compatibilityLastModified ) ){
+ classLoaderCache.put( compatibilityTarget, classLoader(compatibilityTarget, rootClassLoader), compatibilityLastModified );
}
}
+ final ClassLoader compatibilityClassLoader = classLoaderCache.get( compatibilityTarget, compatibilityLastModified );
String[] nailgunClasspathArray = append( earlyDeps.classpathArray, nailgunTarget );
String nailgunClasspath = classpath( nailgunClasspathArray );
- ClassLoader nailgunClassLoader = new CbtURLClassLoader( new URL[]{}, NailgunLauncher.class.getClassLoader() ); // wrap for caching
- if( !classLoaderCache.contains( nailgunClasspath ) ){
- nailgunClassLoader = classLoaderCache.put( nailgunClassLoader, nailgunClasspath );
+ final ClassLoader nailgunClassLoader = new CbtURLClassLoader( new URL[]{}, NailgunLauncher.class.getClassLoader() ); // wrap for caching
+ if( !classLoaderCache.containsKey( nailgunClasspath, nailgunLauncherLastModified ) ){
+ classLoaderCache.put( nailgunClasspath, nailgunClassLoader, nailgunLauncherLastModified );
}
String[] stage1ClasspathArray =
@@ -164,14 +180,24 @@ public class NailgunLauncher{
stage1SourceFiles.add(f);
}
}
- changed = compile(changed, start, stage1Classpath, stage1Target, earlyDeps, stage1SourceFiles);
- ClassLoader stage1classLoader;
- if( !changed && classLoaderCache.contains( stage1Classpath ) ){
- stage1classLoader = classLoaderCache.get( stage1Classpath );
- } else {
- stage1classLoader =
+ final long stage1BeforeCompiled = System.currentTimeMillis();
+ final long stage0LastModified = Math.max(
+ lastModified,
+ Math.max( lastModified, compatibilityLastModified )
+ );
+ final long stage1LastModified = compile(
+ stage0LastModified, stage1Classpath, stage1Target, earlyDeps, stage1SourceFiles
+ );
+
+ if( stage1LastModified < compatibilityLastModified )
+ throw new AssertionError(
+ "Cache invalidation bug: cbt compatibility layer recompiled, but cbt stage1 did not."
+ );
+
+ if( !classLoaderCache.containsKey( stage1Classpath, stage1LastModified ) ){
classLoaderCache.put(
+ stage1Classpath,
classLoader(
stage1Target,
new MultiClassLoader2(
@@ -180,12 +206,14 @@ public class NailgunLauncher{
earlyDeps.classLoader
)
),
- stage1Classpath
+ stage1LastModified
);
}
+ final ClassLoader stage1classLoader = classLoaderCache.get( stage1Classpath, stage1LastModified );
return new BuildStage1Result(
- changed,
+ start,
+ stage1LastModified,
stage1classLoader,
stage1Classpath,
nailgunClasspath,
diff --git a/nailgun_launcher/Stage0Lib.java b/nailgun_launcher/Stage0Lib.java
index 452bdae..8237c3c 100644
--- a/nailgun_launcher/Stage0Lib.java
+++ b/nailgun_launcher/Stage0Lib.java
@@ -11,16 +11,17 @@ import static java.io.File.pathSeparator;
import static cbt.NailgunLauncher.*;
import java.nio.file.*;
import java.nio.file.attribute.FileTime;
+import static java.lang.Math.min;
public class Stage0Lib{
- public static void _assert(Boolean condition, Object msg){
+ public static void _assert(boolean condition, Object msg){
if(!condition){
throw new AssertionError("Assertion failed: "+msg);
}
}
public static int runMain(String cls, String[] args, ClassLoader cl) throws Throwable{
- Boolean trapExitCodeBefore = TrapSecurityManager.trapExitCode().get();
+ boolean trapExitCodeBefore = TrapSecurityManager.trapExitCode().get();
try{
TrapSecurityManager.trapExitCode().set(true);
cl.loadClass(cls)
@@ -47,33 +48,65 @@ public class Stage0Lib{
return join( pathSeparator, files );
}
+ public static long lastModified( String... files ){
+ List<Long> lastModified = new ArrayList<Long>();
+ for( String file: files ){
+ lastModified.add( new File(file).lastModified() );
+ }
+ return Collections.max( lastModified );
+ }
+
+ public static ClassLoader loadDependency(
+ String url,
+ String file,
+ String hash,
+ ClassLoaderCache classLoaderCache,
+ ClassLoader parent,
+ String... classpathArray
+ ) throws Throwable {
+ download(new URL(url), Paths.get(file), hash);
+
+ final long lastModified = lastModified( classpathArray );
+ final String classpath = classpath( classpathArray );
+
+ if( !classLoaderCache.containsKey( classpath, lastModified ) )
+ classLoaderCache.put( classpath, classLoader( file, parent ), lastModified );
+
+ return classLoaderCache.get( classpath, lastModified );
+ }
+
public static File write(File file, String content, OpenOption... options) throws Throwable{
file.getParentFile().mkdirs();
Files.write(file.toPath(), content.getBytes(), options);
return file;
}
- public static Boolean compile(
- Boolean changed, Long start, String classpath, String target,
+ public static long compile(
+ long lastModified, String classpath, String target,
EarlyDependencies earlyDeps, List<File> sourceFiles
) throws Throwable{
File statusFile = new File( new File(target) + ".last-success" );
- Long lastSuccessfullCompile = statusFile.lastModified();
+ long lastCompiled = statusFile.lastModified();
+
+ long maxLastModified = lastModified;
+ final long start = System.currentTimeMillis(); // <- before recursing, so we catch them all
+
for( File file: sourceFiles ){
- if( file.lastModified() > lastSuccessfullCompile ){
- changed = true;
- break;
- }
+ long l = file.lastModified();
+ if( l > maxLastModified ) maxLastModified = l;
+ // performance optimization because we'll recompile and don't need to check other files
+ if( l > lastCompiled ) break;
}
- if(changed){
+
+ if( maxLastModified > lastCompiled ){
List<String> zincArgs = new ArrayList<String>(
Arrays.asList(
new String[]{
"-scala-compiler", earlyDeps.scalaCompiler_2_11_8_File,
"-scala-library", earlyDeps.scalaLibrary_2_11_8_File,
"-scala-extra", earlyDeps.scalaReflect_2_11_8_File,
- "-sbt-interface", earlyDeps.sbtInterface_0_13_9_File,
- "-compiler-interface", earlyDeps.compilerInterface_0_13_9_File,
+ "-sbt-interface", earlyDeps.sbtInterface_0_13_12_File,
+ "-compiler-interface", earlyDeps.compilerInterface_0_13_12_File,
"-cp", classpath,
"-d", target,
"-S-deprecation",
@@ -100,8 +133,10 @@ public class Stage0Lib{
} finally {
System.setOut(oldOut);
}
+ return statusFile.lastModified(); // can't just use `start` here as system time precision is less than milliseconds on OSX
+ } else {
+ return lastCompiled;
}
- return changed;
}
public static ClassLoader classLoader( String file ) throws Throwable{
@@ -117,7 +152,7 @@ public class Stage0Lib{
private static String getVarFromEnv(String envKey) {
String value = System.getenv(envKey);
- if(value==null || value.isEmpty()) {
+ if(value == null || value.isEmpty()) {
value = System.getenv(envKey.toUpperCase());
}
return value;
@@ -126,7 +161,7 @@ public class Stage0Lib{
private static void setProxyfromPropOrEnv(String envKey, String propKeyH, String propKeyP) {
String proxyHost = System.getProperty(propKeyH);
String proxyPort = System.getProperty(propKeyP);
- if((proxyHost==null || proxyHost.isEmpty()) && (proxyPort==null || proxyPort.isEmpty())) {
+ if((proxyHost == null || proxyHost.isEmpty()) && (proxyPort == null || proxyPort.isEmpty())) {
String envVar = getVarFromEnv(envKey);
if(envVar != null && !envVar.isEmpty()) {
String[] proxy = envVar.replaceFirst("^https?://", "").split(":", 2);
@@ -140,7 +175,7 @@ public class Stage0Lib{
setProxyfromPropOrEnv("http_proxy", "http.proxyHost", "http.proxyPort");
setProxyfromPropOrEnv("https_proxy", "https.proxyHost", "https.proxyPort");
String nonHosts = System.getProperty("http.nonProxyHosts");
- if(nonHosts==null || nonHosts.isEmpty()) {
+ if(nonHosts == null || nonHosts.isEmpty()) {
String envVar = getVarFromEnv("no_proxy");
if(envVar != null && !envVar.isEmpty()) {
System.setProperty("http.nonProxyHosts", envVar.replaceAll(",","|"));
diff --git a/nailgun_launcher/TrapSecurityManager.java b/nailgun_launcher/TrapSecurityManager.java
index 48e152b..be59671 100644
--- a/nailgun_launcher/TrapSecurityManager.java
+++ b/nailgun_launcher/TrapSecurityManager.java
@@ -39,7 +39,7 @@ public class TrapSecurityManager extends ProxySecurityManager{
public TrapSecurityManager(){
super(NailgunLauncher.initialSecurityManager);
}
-
+
public void checkPermission( Permission permission ){
/*
NOTE: is it actually ok, to just make these empty?