Skip to content

Commit

Permalink
https://github.com/manifold-systems/manifold/issues/639
Browse files Browse the repository at this point in the history
- support --release, particularly with manifold-ext
  • Loading branch information
rsmckinney committed Nov 8, 2024
1 parent bd6b556 commit 69c599d
Show file tree
Hide file tree
Showing 3 changed files with 78 additions and 67 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import com.sun.tools.javac.api.BasicJavacTask;
import com.sun.tools.javac.api.JavacTool;
import com.sun.tools.javac.api.JavacTrees;
import com.sun.tools.javac.code.Source;
import com.sun.tools.javac.code.Symbol;
import com.sun.tools.javac.code.Symtab;
import com.sun.tools.javac.tree.JCTree;
Expand All @@ -29,17 +30,10 @@
import java.io.IOException;
import java.io.StringWriter;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;
import javax.tools.DiagnosticListener;
import javax.tools.JavaFileManager;
import javax.tools.JavaFileObject;
import javax.tools.StandardJavaFileManager;
import javax.tools.StandardLocation;
import javax.tools.*;

import com.sun.tools.javac.util.Options;
import manifold.api.fs.IResource;
Expand Down Expand Up @@ -91,6 +85,7 @@ private ClassSymbols( IModule module )

StringWriter errors = new StringWriter();
BasicJavacTask task = (BasicJavacTask)_javacTool.getTask( errors, _fm, null, makeJavacArgs(), null, null );
pushModuleSymbol( task );
if( errors.getBuffer().length() > 0 )
{
// report errors to console
Expand All @@ -108,13 +103,7 @@ private ClassSymbols( IModule module )
BasicJavacTask task = (BasicJavacTask)_javacTool.getTask( errors, _wfm, null, makeJavacArgs(), null, null );
if( _wfm instanceof ManifoldJavaFileManager )
{
if( JreUtil.isJava9orLater() )
{
// Java 9+ requires a module when resolving a symbol, it's always 'noModule' with this particular java task
Stack stack = new Stack();
stack.push( ReflectUtil.field( Symtab.instance( task.getContext() ), "noModule" ).get() );
task.getContext().put( ManifoldJavaFileManager.MODULE_CTX, stack );
}
pushModuleSymbol( task );
((ManifoldJavaFileManager)_wfm).setContext( task.getContext() );
}

Expand All @@ -127,32 +116,51 @@ private ClassSymbols( IModule module )
} );
}

private static void pushModuleSymbol( BasicJavacTask task )
{
if( JreUtil.isJava8() )
{
return;
}

// module to be in task's context for JavaDynamicJdk_XX#getTypeElement
String moduleFieldName = JreUtil.isJava9NoModule( JavacPlugin.instance().getContext() )
? "noModule"
: "unnamedModule";

Context ctx = task.getContext();
/*ModuleSymbol*/ Object moduleSym;
moduleSym = ReflectUtil.field( Symtab.instance( ctx ), moduleFieldName ).get();

Stack</*ModuleSymbol*/Object> stack = new Stack<>();
stack.push( moduleSym );
task.getContext().put( ManifoldJavaFileManager.MODULE_CTX, stack );
}

private List<String> makeJavacArgs()
{
return new ArrayList<String>() {{
add( "-proc:none" );
add( "-Xprefer:source" );
add( "-implicit:none" );

// Must work with types compatible with the originating compiler's settings (-source/-target/--release).
// Particularly with the --release option, because it produces a class symbol that must reflect the classes available
// in the originating JDK e.g., the structure of java.lang.String (super types, method parameters, etc.) must be
// available in the originating JDK. Otherwise, if we deliver java.lang.String with JDK 21's new super types to
// the originating JDK that is --release 17, it won't compile.

// add "--release 8" if compiling say from Java 11 but targeting Java 8 with "--release 8" which runs against the
// actual Java 8 JRE classes, not the Java 11 ones. Otherwise, there is trouble if we bring in JRE 11 sources here,
// which have Java 11 features that won't compile with source level 8.
JavacPlugin javacPlugin = JavacPlugin.instance();
Options options = javacPlugin == null ? null : Options.instance( javacPlugin.getContext() );
String release = options == null ? null : options.get( "--release" );
if( release == null && JreUtil.isJava9orLater() && options != null ) // must be *building* with Java 9+
{
release = options.get( "-target" );
release = release == null ? options.get( "--target" ) : release;
}
if( "8".equals( release ) || "1.8".equals( release ) )
if( release != null )
{
add( "--release" );
add( "8" );
add( release );
}
else
else if( javacPlugin != null )
{
add( "-source" ); add( "1.8" );
// much wrath: add( "-source" ); add( javacPlugin == null ? "1.8" : Source.instance( javacPlugin.getContext() ).name );
add( "-source" ); add( Source.instance( javacPlugin.getContext() ).name );
}
}};
}
Expand Down Expand Up @@ -182,7 +190,7 @@ private void init()
{
fm.setLocation( StandardLocation.PLATFORM_CLASS_PATH, extendBootclasspath( fm.getLocation( StandardLocation.PLATFORM_CLASS_PATH ) ) );
}
_fm = fm;
_fm = new MyFm( fm, new Context() );
}
catch( IOException e )
{
Expand All @@ -191,6 +199,26 @@ private void init()
}
}

static class MyFm extends JavacFileManagerBridge
{
protected MyFm( JavaFileManager fileManager, Context ctx )
{
super( fileManager, ctx );
}

@Override
public JavaFileObject getJavaFileForInput( Location location, String className, JavaFileObject.Kind kind ) throws IOException
{
if( className.contains( "module-info" ) )
{
// The Java tasks used in here do not need to be modular, keep javac from finding module-info.java classes.
// Note, this is key to making extension classes etc. work with --release mode.
return null;
}
return super.getJavaFileForInput( location, className, kind );
}
}

private Iterable<? extends File> extendBootclasspath( Iterable<? extends File> existing )
{
if( JavacPlugin.instance() == null )
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@
import com.sun.source.util.TaskEvent;
import com.sun.source.util.TaskListener;
import com.sun.tools.javac.api.BasicJavacTask;
import com.sun.tools.javac.code.Source;
import com.sun.tools.javac.code.Symbol;
import com.sun.tools.javac.code.Types;
import com.sun.tools.javac.comp.*;
Expand Down Expand Up @@ -195,42 +194,6 @@ public void init( JavacTask task, String... args )
hijackJavacFileManager();
overrideJavacToolEnter();
task.addTaskListener( this );
warnings();
}

private void warnings()
{
sourceWarning();
}

// Is the --source JDK lower than the compiling JDK?
// If so, report a warning if manifold-ext is in use and if the compiling JDK is 17+. Because extension classes on JDK
// classes such as String may have issues because although the --source is specified the compiler still loads the String
// class directly from the compiling JDK, which includes whatever new changes that may be in String, mainly super types
// type refs elsewhere in the class. You see, --source only prevents compiling source code from referencing types, methods, fields, etc.
// from the JDK class that are not in the older --source version of the class -- it is just the newer type information that the
// compiler prohibits the use of, but the String type itself is still there with all the new stuff in it. Because a
// manifold extension on String loads the type to generate the stub source, the generated class has all the new type info
// in it, regardless of whatever --source may be.
private void sourceWarning()
{
if( !isExtensionsEnabled() || !JreUtil.isJava9orLater() )
{
return;
}

String source = Source.instance( getContext() ).name;
int sourceValue = new BigDecimal( source ).intValue();
if( sourceValue < JreUtil.JAVA_VERSION )
{
getIssueReporter().reportWarning(
"\n" +
"Usage of `manifold-ext` compiling with JDK " + JreUtil.JAVA_VERSION + " may not support source version " + source + " if\n" +
"your application uses extensions on JRE classes like String, List, etc. Generally,\n" +
"with JDK 11 or greater it is best to compile --source X with JDK X. If you experience\n" +
"compile errors corresponding with JRE classes, please consider changing your compiler\n" +
"to JDK " + source + " or changing --source to " + JreUtil.JAVA_VERSION + ". Otherwise, ignore this message.\n" );
}
}

private void overrideJavacToolEnter()
Expand Down
20 changes: 20 additions & 0 deletions manifold-util/src/main/java/manifold/util/JreUtil.java
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ public class JreUtil
public static final int JAVA_VERSION = getJavaVersion();
private static Boolean _modular;
private static Boolean _modularRuntime;
private static Boolean _noModule;

private static int getJavaVersion()
{
Expand Down Expand Up @@ -178,6 +179,25 @@ public static boolean isJava9Modular_compiler( Object/*Context*/ ctx )
return _modular;
}

public static boolean isJava9NoModule( Object/*Context*/ ctx )
{
if( _noModule == null )
{
if( isJava8() )
{
_noModule = true;
}
else
{
//noinspection ConstantConditions
Object modulesUtil = ReflectUtil.method( ReflectUtil.type( "com.sun.tools.javac.comp.Modules" ), "instance", ReflectUtil.type( "com.sun.tools.javac.util.Context" ) ).invokeStatic( ctx );
Object defModule = ReflectUtil.method( modulesUtil, "getDefaultModule" ).invoke();
_noModule = defModule == null || (boolean)ReflectUtil.method( defModule, "isNoModule" ).invoke();
}
}
return _noModule;
}

public static boolean isJava9Modular_runtime()
{
if( _modularRuntime == null )
Expand Down

0 comments on commit 69c599d

Please sign in to comment.