# HG changeset patch # User Doug Simon # Date 1370553405 -7200 # Node ID af909f4b80a9f5d0c07057e5172abe4a05cf4db6 # Parent ab90954e5fecee1efd783c4b1adf9dc7df226a5b options are grouped per top level class/interface when accessed via the service mechanism diff -r ab90954e5fec -r af909f4b80a9 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotOptions.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotOptions.java Thu Jun 06 21:22:43 2013 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotOptions.java Thu Jun 06 23:16:45 2013 +0200 @@ -30,15 +30,17 @@ public class HotSpotOptions { - private static final Map options = new HashMap<>(); + private static final Map options = new HashMap<>(); static { - ServiceLoader sl = ServiceLoader.loadInstalled(OptionProvider.class); - for (OptionProvider provider : sl) { - if (provider.getClass().getName().startsWith("com.oracle.graal")) { - String name = provider.getName(); - OptionProvider existing = options.put(name, provider); - assert existing == null : name + " option has multiple definitions: " + existing.getClass() + " and " + provider.getClass(); + ServiceLoader sl = ServiceLoader.loadInstalled(Options.class); + for (Options opts : sl) { + for (OptionDescriptor desc : opts) { + if (desc.getClass().getName().startsWith("com.oracle.graal")) { + String name = desc.getName(); + OptionDescriptor existing = options.put(name, desc); + assert existing == null : "Option named \"" + name + "\" has multiple definitions: " + existing.getLocation() + " and " + desc.getLocation(); + } } } } @@ -73,13 +75,13 @@ } } - OptionProvider optionProvider = options.get(optionName); - if (optionProvider == null) { + OptionDescriptor desc = options.get(optionName); + if (desc == null) { Logger.info("Could not find option " + optionName + " (use -G:+PrintFlags to see Graal options)"); return false; } - Class optionType = optionProvider.getType(); + Class optionType = desc.getType(); if (value == null) { if (optionType == Boolean.TYPE || optionType == Boolean.class) { @@ -109,7 +111,7 @@ } if (value != null) { - OptionValue optionValue = optionProvider.getOptionValue(); + OptionValue optionValue = desc.getOptionValue(); optionValue.setValue(value); // Logger.info("Set option " + fieldName + " to " + value); } else { @@ -122,12 +124,12 @@ private static void printFlags() { Logger.info("[Graal flags]"); - SortedMap sortedOptions = new TreeMap<>(options); - for (Map.Entry e : sortedOptions.entrySet()) { + SortedMap sortedOptions = new TreeMap<>(options); + for (Map.Entry e : sortedOptions.entrySet()) { e.getKey(); - OptionProvider opt = e.getValue(); - Object value = opt.getOptionValue().getValue(); - Logger.info(String.format("%9s %-40s = %-14s %s", opt.getType().getSimpleName(), e.getKey(), value, opt.getHelp())); + OptionDescriptor desc = e.getValue(); + Object value = desc.getOptionValue().getValue(); + Logger.info(String.format("%9s %-40s = %-14s %s", desc.getType().getSimpleName(), e.getKey(), value, desc.getHelp())); } System.exit(0); diff -r ab90954e5fec -r af909f4b80a9 graal/com.oracle.graal.options/src/com/oracle/graal/options/Option.java --- a/graal/com.oracle.graal.options/src/com/oracle/graal/options/Option.java Thu Jun 06 21:22:43 2013 +0200 +++ b/graal/com.oracle.graal.options/src/com/oracle/graal/options/Option.java Thu Jun 06 23:16:45 2013 +0200 @@ -27,6 +27,9 @@ /** * Describes the attributes of an option whose {@link OptionValue value} is in a static field * annotated by this annotation type. + * + * @see OptionProcessor + * @see OptionDescriptor */ @Retention(RetentionPolicy.CLASS) @Target(ElementType.FIELD) diff -r ab90954e5fec -r af909f4b80a9 graal/com.oracle.graal.options/src/com/oracle/graal/options/OptionDescriptor.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.options/src/com/oracle/graal/options/OptionDescriptor.java Thu Jun 06 23:16:45 2013 +0200 @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.options; + +/** + * Describes the attributes of a static field {@linkplain Option option} and provides access to its + * {@linkplain OptionValue value}. + */ +public class OptionDescriptor { + + protected final String name; + protected final Class type; + protected final String help; + protected final OptionValue option; + protected final String location; + + public OptionDescriptor(String name, Class type, String help, String location, OptionValue option) { + this.name = name; + this.type = type; + this.help = help; + this.option = option; + this.location = location; + } + + /** + * Gets the type of values stored in the option. + */ + public Class getType() { + return type; + } + + /** + * Gets a descriptive help message for the option. + */ + public String getHelp() { + return help; + } + + /** + * Gets the name of the option. It's up to the client of this object how to use the name to get + * a user specified value for the option from the environment. + */ + public String getName() { + return name; + } + + /** + * Gets the boxed option value. + */ + public OptionValue getOptionValue() { + return option; + } + + /** + * Gets a description of the location where this option is stored. + */ + public String getLocation() { + return location; + + } +} diff -r ab90954e5fec -r af909f4b80a9 graal/com.oracle.graal.options/src/com/oracle/graal/options/OptionProcessor.java --- a/graal/com.oracle.graal.options/src/com/oracle/graal/options/OptionProcessor.java Thu Jun 06 21:22:43 2013 +0200 +++ b/graal/com.oracle.graal.options/src/com/oracle/graal/options/OptionProcessor.java Thu Jun 06 23:16:45 2013 +0200 @@ -23,26 +23,25 @@ package com.oracle.graal.options; import java.io.*; -import java.lang.reflect.*; import java.util.*; import javax.annotation.processing.*; import javax.lang.model.*; import javax.lang.model.element.*; -import javax.lang.model.element.Modifier; import javax.lang.model.type.*; import javax.lang.model.util.*; import javax.tools.Diagnostic.Kind; import javax.tools.*; /** - * Processes static fields annotated with {@link Option}. An {@link OptionProvider} is generated for - * each such field that can be accessed as a {@linkplain ServiceLoader service} as follows: + * Processes static fields annotated with {@link Option}. An {@link Options} service is generated + * for each top level class containing at least one such field. These service objects can be + * retrieved as follows: * *
- * ServiceLoader<OptionProvider> sl = ServiceLoader.loadInstalled(OptionProvider.class);
- * for (OptionProvider provider : sl) {
- *     // use provider
+ * ServiceLoader<Options> sl = ServiceLoader.loadInstalled(Options.class);
+ * for (OptionDescriptor desc : sl) {
+ *     // use desc
  * }
  * 
*/ @@ -52,11 +51,7 @@ private final Set processed = new HashSet<>(); - private void processElement(Element element) { - if (processed.contains(element)) { - return; - } - processed.add(element); + private void processElement(Element element, OptionsInfo info) { if (!element.getModifiers().contains(Modifier.STATIC)) { processingEnv.getMessager().printMessage(Kind.ERROR, "Option field must be static", element); @@ -102,74 +97,92 @@ optionType = optionType.substring("java.lang.".length()); } - String pkg = null; Element enclosing = element.getEnclosingElement(); String declaringClass = ""; String separator = ""; - List originatingElementsList = new ArrayList<>(); + Set originatingElementsList = info.originatingElements; originatingElementsList.add(field); while (enclosing != null) { - originatingElementsList.add(enclosing); if (enclosing.getKind() == ElementKind.CLASS || enclosing.getKind() == ElementKind.INTERFACE) { if (enclosing.getModifiers().contains(Modifier.PRIVATE)) { String msg = String.format("Option field cannot be declared in a private %s %s", enclosing.getKind().name().toLowerCase(), enclosing); processingEnv.getMessager().printMessage(Kind.ERROR, msg, element); return; } + originatingElementsList.add(enclosing); declaringClass = enclosing.getSimpleName() + separator + declaringClass; separator = "."; } else { assert enclosing.getKind() == ElementKind.PACKAGE; - pkg = ((PackageElement) enclosing).getQualifiedName().toString(); } enclosing = enclosing.getEnclosingElement(); } - String providerClassName = declaringClass.replace('.', '_') + "_" + fieldName; - Element[] originatingElements = originatingElementsList.toArray(new Element[originatingElementsList.size()]); + info.options.add(new OptionInfo(optionName, annotation.help(), optionType, declaringClass, field)); + } + + private void createFiles(OptionsInfo info) { + String pkg = ((PackageElement) info.topDeclaringType.getEnclosingElement()).getQualifiedName().toString(); + Name declaringClass = info.topDeclaringType.getSimpleName(); + + String optionsClassName = declaringClass + "_" + Options.class.getSimpleName(); + Element[] originatingElements = info.originatingElements.toArray(new Element[info.originatingElements.size()]); Filer filer = processingEnv.getFiler(); - try (PrintWriter out = createSourceFile(pkg, providerClassName, filer, originatingElements)) { + try (PrintWriter out = createSourceFile(pkg, optionsClassName, filer, originatingElements)) { out.println("// CheckStyle: stop header check"); + out.println("// GENERATED CONTENT - DO NOT EDIT"); + out.println("// Source: " + declaringClass + ".java"); out.println("package " + pkg + ";"); out.println(""); - if (element.getModifiers().contains(Modifier.PRIVATE)) { - out.println("import " + Field.class.getName() + ";"); + out.println("import java.util.*;"); + out.println("import " + Options.class.getPackage().getName() + ".*;"); + out.println(""); + out.println("public class " + optionsClassName + " implements " + Options.class.getSimpleName() + " {"); + out.println(" @Override"); + out.println(" public Iterator<" + OptionDescriptor.class.getSimpleName() + "> iterator() {"); + out.println(" List<" + OptionDescriptor.class.getSimpleName() + "> options = Arrays.asList("); + + boolean needPrivateFieldAccessor = false; + int i = 0; + for (OptionInfo option : info.options) { + String optionValue; + if (option.field.getModifiers().contains(Modifier.PRIVATE)) { + needPrivateFieldAccessor = true; + optionValue = "field(" + option.declaringClass + ".class, \"" + option.field.getSimpleName() + "\")"; + } else { + optionValue = option.declaringClass + "." + option.field.getSimpleName(); + } + String name = option.name; + String type = option.type; + String help = option.help; + String location = pkg + "." + option.declaringClass + "." + option.field.getSimpleName(); + String comma = i == info.options.size() - 1 ? "" : ","; + out.printf(" new %s(\"%s\", %s.class, \"%s\", \"%s\", %s)%s%n", OptionDescriptor.class.getSimpleName(), name, type, help, location, optionValue, comma); + i++; } - out.println("import " + OptionValue.class.getName() + ";"); - out.println("import " + OptionProvider.class.getName() + ";"); - out.println(""); - out.println("public class " + providerClassName + " implements " + OptionProvider.class.getSimpleName() + " {"); - out.println(" public String getHelp() {"); - out.println(" return \"" + annotation.help() + "\";"); + out.println(" );"); + out.println(" return options.iterator();"); out.println(" }"); - out.println(" public String getName() {"); - out.println(" return \"" + optionName + "\";"); - out.println(" }"); - out.println(" public Class getType() {"); - out.println(" return " + optionType + ".class;"); - out.println(" }"); - out.println(" public " + OptionValue.class.getSimpleName() + " getOptionValue() {"); - if (!element.getModifiers().contains(Modifier.PRIVATE)) { - out.println(" return " + declaringClass + "." + fieldName + ";"); - } else { + if (needPrivateFieldAccessor) { + out.println(" private static " + OptionValue.class.getSimpleName() + " field(Class declaringClass, String fieldName) {"); out.println(" try {"); - out.println(" Field field = " + declaringClass + ".class.getDeclaredField(\"" + fieldName + "\");"); + out.println(" java.lang.reflect.Field field = declaringClass.getDeclaredField(fieldName);"); out.println(" field.setAccessible(true);"); out.println(" return (" + OptionValue.class.getSimpleName() + ") field.get(null);"); out.println(" } catch (Exception e) {"); out.println(" throw (InternalError) new InternalError().initCause(e);"); out.println(" }"); + out.println(" }"); } - out.println(" }"); out.println("}"); } try { - createProviderFile(pkg, providerClassName, originatingElements); + createProviderFile(pkg, optionsClassName, originatingElements); } catch (IOException e) { - processingEnv.getMessager().printMessage(Kind.ERROR, e.getMessage(), field); + processingEnv.getMessager().printMessage(Kind.ERROR, e.getMessage(), info.topDeclaringType); } } @@ -177,7 +190,7 @@ String filename = "META-INF/providers/" + pkg + "." + providerClassName; FileObject file = processingEnv.getFiler().createResource(StandardLocation.CLASS_OUTPUT, "", filename, originatingElements); PrintWriter writer = new PrintWriter(new OutputStreamWriter(file.openOutputStream(), "UTF-8")); - writer.println(OptionProvider.class.getName()); + writer.println(Options.class.getName()); writer.close(); } @@ -197,14 +210,84 @@ } } + static class OptionInfo { + + final String name; + final String help; + final String type; + final String declaringClass; + final VariableElement field; + + public OptionInfo(String name, String help, String type, String declaringClass, VariableElement field) { + this.name = name; + this.help = help; + this.type = type; + this.declaringClass = declaringClass; + this.field = field; + } + + @Override + public String toString() { + return declaringClass + "." + field; + } + } + + static class OptionsInfo { + + final Element topDeclaringType; + final List options = new ArrayList<>(); + final Set originatingElements = new HashSet<>(); + + public OptionsInfo(Element topDeclaringType) { + this.topDeclaringType = topDeclaringType; + } + } + + private static Element topDeclaringType(Element element) { + Element enclosing = element.getEnclosingElement(); + if (element == null || enclosing.getKind() == ElementKind.PACKAGE) { + assert element.getKind() == ElementKind.CLASS || element.getKind() == ElementKind.INTERFACE; + return element; + } + return topDeclaringType(enclosing); + } + @Override public boolean process(Set annotations, RoundEnvironment roundEnv) { if (roundEnv.processingOver()) { return true; } + Map map = new HashMap<>(); for (Element element : roundEnv.getElementsAnnotatedWith(Option.class)) { - processElement(element); + if (!processed.contains(element)) { + processed.add(element); + Element topDeclaringType = topDeclaringType(element); + OptionsInfo options = map.get(topDeclaringType); + if (options == null) { + options = new OptionsInfo(topDeclaringType); + map.put(topDeclaringType, options); + } + processElement(element, options); + } + } + + boolean ok = true; + Map uniqueness = new HashMap<>(); + for (OptionsInfo info : map.values()) { + for (OptionInfo option : info.options) { + OptionInfo conflict = uniqueness.put(option.name, option); + if (conflict != null) { + processingEnv.getMessager().printMessage(Kind.ERROR, "Duplicate option names for " + option + " and " + conflict, option.field); + ok = false; + } + } + } + + if (ok) { + for (OptionsInfo info : map.values()) { + createFiles(info); + } } return true; diff -r ab90954e5fec -r af909f4b80a9 graal/com.oracle.graal.options/src/com/oracle/graal/options/OptionProvider.java --- a/graal/com.oracle.graal.options/src/com/oracle/graal/options/OptionProvider.java Thu Jun 06 21:22:43 2013 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,54 +0,0 @@ -/* - * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.options; - -import java.util.*; - -/** - * Describes the attributes of an {@linkplain Option option} and provides access to its - * {@linkplain OptionValue value}. The {@link OptionProcessor} auto-generates instances of this - * interface that are accessible as a {@linkplain ServiceLoader service}. - */ -public interface OptionProvider { - - /** - * Gets the type of values stored in the option. - */ - Class getType(); - - /** - * Gets a descriptive help message for the option. - */ - String getHelp(); - - /** - * Gets the name of the option. It's up to the client of this object how to use the name to get - * a user specified value for the option from the environment. - */ - String getName(); - - /** - * Gets the boxed option value. - */ - OptionValue getOptionValue(); -} diff -r ab90954e5fec -r af909f4b80a9 graal/com.oracle.graal.options/src/com/oracle/graal/options/OptionValue.java --- a/graal/com.oracle.graal.options/src/com/oracle/graal/options/OptionValue.java Thu Jun 06 21:22:43 2013 +0200 +++ b/graal/com.oracle.graal.options/src/com/oracle/graal/options/OptionValue.java Thu Jun 06 23:16:45 2013 +0200 @@ -22,14 +22,8 @@ */ package com.oracle.graal.options; -import java.util.*; - /** - * A settable option value. - *

- * To access {@link OptionProvider} instances via a {@link ServiceLoader} for working with options, - * instances of this class should be assigned to static final fields that are annotated with - * {@link Option}. + * An option value. */ public class OptionValue { diff -r ab90954e5fec -r af909f4b80a9 graal/com.oracle.graal.options/src/com/oracle/graal/options/Options.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.options/src/com/oracle/graal/options/Options.java Thu Jun 06 23:16:45 2013 +0200 @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.options; + +import java.util.*; + +/** + * A {@linkplain ServiceLoader service} for accessing a set of {@link OptionDescriptor}s. + */ +public interface Options extends Iterable { +} diff -r ab90954e5fec -r af909f4b80a9 graal/com.oracle.graal.options/src/com/oracle/graal/options/StableOptionValue.java --- a/graal/com.oracle.graal.options/src/com/oracle/graal/options/StableOptionValue.java Thu Jun 06 21:22:43 2013 +0200 +++ b/graal/com.oracle.graal.options/src/com/oracle/graal/options/StableOptionValue.java Thu Jun 06 23:16:45 2013 +0200 @@ -23,7 +23,7 @@ package com.oracle.graal.options; /** - * A settable option that always returns the same {@linkplain #getValue() value}. + * An option that always returns the same {@linkplain #getValue() value}. */ public class StableOptionValue extends OptionValue { diff -r ab90954e5fec -r af909f4b80a9 make/build-graal.xml --- a/make/build-graal.xml Thu Jun 06 21:22:43 2013 +0200 +++ b/make/build-graal.xml Thu Jun 06 23:16:45 2013 +0200 @@ -81,161 +81,15 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + +