changeset 15689:54011d1d1ae3

Merge
author Miguel Garcia <miguel.m.garcia@oracle.com>
date Thu, 15 May 2014 17:25:49 +0200
parents 8af4f23b3847 (current diff) 1b0141150854 (diff)
children d3c33144cab5
files
diffstat 17 files changed, 834 insertions(+), 112 deletions(-) [+]
line wrap: on
line diff
--- a/CHANGELOG.md	Thu May 15 16:17:35 2014 +0200
+++ b/CHANGELOG.md	Thu May 15 17:25:49 2014 +0200
@@ -3,6 +3,8 @@
 ## `tip`
 ### Graal
 * Made initialization of Graal runtime lazy in hosted mode.
+* Added supported for new 'jrelibrary' dependency type in mx/projects.
+* Java projects with compliance level higher than the JDKs specified by JAVA_HOME and EXTRA_JAVA_HOMES are ignored once mx/projects has been processed.
 
 ### Truffle
 * `truffle.jar`: strip out build-time only dependency into a seperated JAR file (`truffle-dsl-processor.jar`)
--- a/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/type/ObjectStamp.java	Thu May 15 16:17:35 2014 +0200
+++ b/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/type/ObjectStamp.java	Thu May 15 17:25:49 2014 +0200
@@ -107,6 +107,11 @@
             return StampFactory.illegal(Kind.Illegal);
         }
         ObjectStamp other = (ObjectStamp) otherStamp;
+        if (!isLegal()) {
+            return other;
+        } else if (!other.isLegal()) {
+            return this;
+        }
         ResolvedJavaType meetType;
         boolean meetExactType;
         boolean meetNonNull;
--- a/graal/com.oracle.graal.debug/src/com/oracle/graal/debug/Debug.java	Thu May 15 16:17:35 2014 +0200
+++ b/graal/com.oracle.graal.debug/src/com/oracle/graal/debug/Debug.java	Thu May 15 17:25:49 2014 +0200
@@ -741,7 +741,7 @@
 
     private static DebugMetric createMetric(String format, Object arg1, Object arg2) {
         String name = formatDebugName(format, arg1, arg2);
-        boolean conditional = enabledMetrics != null && enabledMetrics.contains(name);
+        boolean conditional = enabledMetrics == null || !enabledMetrics.contains(name);
         return new MetricImpl(name, conditional);
     }
 
@@ -981,7 +981,7 @@
 
     private static DebugTimer createTimer(String format, Object arg1, Object arg2) {
         String name = formatDebugName(format, arg1, arg2);
-        boolean conditional = enabledTimers != null && enabledTimers.contains(name);
+        boolean conditional = enabledTimers == null || !enabledTimers.contains(name);
         return new TimerImpl(name, conditional);
     }
 
--- a/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeBitMap.java	Thu May 15 16:17:35 2014 +0200
+++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeBitMap.java	Thu May 15 17:25:49 2014 +0200
@@ -197,4 +197,9 @@
     public boolean contains(Node node) {
         return isMarked(node);
     }
+
+    @Override
+    public String toString() {
+        return snapshot().toString();
+    }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot.jfr/src/com/oracle/graal/hotspot/jfr/events/JFREventProvider.java	Thu May 15 17:25:49 2014 +0200
@@ -0,0 +1,158 @@
+/*
+ * Copyright (c) 2014, 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.hotspot.jfr.events;
+
+import java.net.*;
+
+import com.oracle.graal.api.runtime.*;
+import com.oracle.graal.hotspot.events.*;
+import com.oracle.jrockit.jfr.*;
+
+/**
+ * A JFR implementation for {@link EventProvider}. This implementation is used when Flight Recorder
+ * is turned on.
+ */
+@ServiceProvider(EventProvider.class)
+public final class JFREventProvider implements EventProvider {
+
+    @SuppressWarnings("deprecation") private final Producer producer;
+
+    @SuppressWarnings("deprecation")
+    public JFREventProvider() {
+        try {
+            /*
+             * The "HotSpot JVM" producer is a native producer and we cannot use it. So we create
+             * our own. This has the downside that Mission Control is confused and doesn't show
+             * Graal's events in the "Code" tab. There are plans to revise the JFR code for JDK 9.
+             */
+            producer = new Producer("HotSpot JVM", "Oracle Hotspot JVM", "http://www.oracle.com/hotspot/jvm/");
+            producer.register();
+        } catch (URISyntaxException e) {
+            throw new InternalError(e);
+        }
+
+        // Register event classes with Producer.
+        for (Class<?> c : JFREventProvider.class.getDeclaredClasses()) {
+            if (c.isAnnotationPresent(EventDefinition.class)) {
+                assert com.oracle.jrockit.jfr.InstantEvent.class.isAssignableFrom(c) : c;
+                registerEvent(c);
+            }
+        }
+    }
+
+    /**
+     * Register an event class with the {@link Producer}.
+     *
+     * @param c event class
+     * @return the {@link EventToken event token}
+     */
+    @SuppressWarnings({"deprecation", "javadoc", "unchecked"})
+    private final EventToken registerEvent(Class<?> c) {
+        try {
+            return producer.addEvent((Class<? extends com.oracle.jrockit.jfr.InstantEvent>) c);
+        } catch (InvalidEventDefinitionException | InvalidValueException e) {
+            throw new InternalError(e);
+        }
+    }
+
+    public CompilationEvent newCompilationEvent() {
+        return new JFRCompilationEvent();
+    }
+
+    /**
+     * A JFR compilation event.
+     *
+     * <p>
+     * See: event {@code Compilation} in {@code src/share/vm/trace/trace.xml}
+     */
+    @SuppressWarnings("deprecation")
+    @EventDefinition(name = "Compilation", path = "vm/compiler/compilation")
+    public static class JFRCompilationEvent extends com.oracle.jrockit.jfr.DurationEvent implements CompilationEvent {
+
+        /*
+         * FIXME method should be a Method* but we can't express that in Java.
+         */
+        @ValueDefinition(name = "Java Method") public String method;
+        @ValueDefinition(name = "Compilation ID", relationKey = "COMP_ID") public int compileId;
+        @ValueDefinition(name = "Compilation Level") public short compileLevel;
+        @ValueDefinition(name = "Succeeded") public boolean succeeded;
+        @ValueDefinition(name = "On Stack Replacement") public boolean isOsr;
+        @ValueDefinition(name = "Compiled Code Size", contentType = ContentType.Bytes) public int codeSize;
+        @ValueDefinition(name = "Inlined Code Size", contentType = ContentType.Bytes) public int inlinedBytes;
+
+        public void setMethod(String method) {
+            this.method = method;
+        }
+
+        public void setCompileId(int id) {
+            this.compileId = id;
+        }
+
+        public void setCompileLevel(int compileLevel) {
+            this.compileLevel = (short) compileLevel;
+        }
+
+        public void setSucceeded(boolean succeeded) {
+            this.succeeded = succeeded;
+        }
+
+        public void setIsOsr(boolean isOsr) {
+            this.isOsr = isOsr;
+        }
+
+        public void setCodeSize(int codeSize) {
+            this.codeSize = codeSize;
+        }
+
+        public void setInlinedBytes(int inlinedBytes) {
+            this.inlinedBytes = inlinedBytes;
+        }
+    }
+
+    public CompilerFailureEvent newCompilerFailureEvent() {
+        return new JFRCompilerFailureEvent();
+    }
+
+    /**
+     * A JFR compiler failure event.
+     *
+     * <p>
+     * See: event {@code CompilerFailure} in {@code src/share/vm/trace/trace.xml}
+     */
+    @SuppressWarnings("deprecation")
+    @EventDefinition(name = "Compilation Failure", path = "vm/compiler/failure")
+    public static class JFRCompilerFailureEvent extends com.oracle.jrockit.jfr.InstantEvent implements CompilerFailureEvent {
+
+        @ValueDefinition(name = "Compilation ID", relationKey = "COMP_ID") public int compileId;
+        @ValueDefinition(name = "Message", description = "The failure message") public String failure;
+
+        public void setCompileId(int id) {
+            this.compileId = id;
+        }
+
+        public void setMessage(String message) {
+            this.failure = message;
+        }
+    }
+
+}
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/CompilationTask.java	Thu May 15 16:17:35 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/CompilationTask.java	Thu May 15 17:25:49 2014 +0200
@@ -40,6 +40,7 @@
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.code.CallingConvention.Type;
 import com.oracle.graal.api.meta.*;
+import com.oracle.graal.api.runtime.*;
 import com.oracle.graal.baseline.*;
 import com.oracle.graal.compiler.*;
 import com.oracle.graal.compiler.common.*;
@@ -47,6 +48,9 @@
 import com.oracle.graal.debug.Debug.Scope;
 import com.oracle.graal.debug.internal.*;
 import com.oracle.graal.hotspot.bridge.*;
+import com.oracle.graal.hotspot.events.*;
+import com.oracle.graal.hotspot.events.EventProvider.CompilationEvent;
+import com.oracle.graal.hotspot.events.EventProvider.CompilerFailureEvent;
 import com.oracle.graal.hotspot.meta.*;
 import com.oracle.graal.hotspot.phases.*;
 import com.oracle.graal.java.*;
@@ -144,6 +148,11 @@
         return method;
     }
 
+    /**
+     * Returns the compilation id of this task.
+     *
+     * @return compile id
+     */
     public int getId() {
         return id;
     }
@@ -237,12 +246,16 @@
         long previousInlinedBytecodes = InlinedBytecodes.getCurrentValue();
         long previousCompilationTime = CompilationTime.getCurrentValue();
         HotSpotInstalledCode installedCode = null;
+        final boolean isOSR = entryBCI != StructuredGraph.INVOCATION_ENTRY_BCI;
+
+        // Log a compilation event.
+        EventProvider eventProvider = Graal.getRequiredCapability(EventProvider.class);
+        CompilationEvent compilationEvent = eventProvider.newCompilationEvent();
 
         try (TimerCloseable a = CompilationTime.start()) {
             if (!tryToChangeStatus(CompilationStatus.Queued, CompilationStatus.Running)) {
                 return;
             }
-            boolean isOSR = entryBCI != StructuredGraph.INVOCATION_ENTRY_BCI;
 
             // If there is already compiled code for this method on our level we simply return.
             // Graal compiles are always at the highest compile level, even in non-tiered mode so we
@@ -266,6 +279,8 @@
             final long allocatedBytesBefore = threadMXBean.getThreadAllocatedBytes(threadId);
 
             try (Scope s = Debug.scope("Compiling", new DebugDumpScope(String.valueOf(id), true))) {
+                // Begin the compilation event.
+                compilationEvent.begin();
 
                 if (UseBaselineCompiler.getValue() == true) {
                     HotSpotProviders providers = backend.getProviders();
@@ -307,6 +322,9 @@
             } catch (Throwable e) {
                 throw Debug.handle(e);
             } finally {
+                // End the compilation event.
+                compilationEvent.end();
+
                 filter.remove();
                 final boolean printAfterCompilation = PrintAfterCompilation.getValue() && !TTY.isSuppressed();
 
@@ -346,16 +364,37 @@
             if (PrintStackTraceOnException.getValue() || ExitVMOnException.getValue()) {
                 t.printStackTrace(TTY.cachedOut);
             }
+
+            // Log a failure event.
+            CompilerFailureEvent event = eventProvider.newCompilerFailureEvent();
+            if (event.shouldWrite()) {
+                event.setCompileId(getId());
+                event.setMessage(t.getMessage());
+                event.commit();
+            }
+
             if (ExitVMOnException.getValue()) {
                 System.exit(-1);
             }
         } finally {
-            int processedBytes = (int) (InlinedBytecodes.getCurrentValue() - previousInlinedBytecodes);
+            final int processedBytes = (int) (InlinedBytecodes.getCurrentValue() - previousInlinedBytecodes);
+
+            // Log a compilation event.
+            if (compilationEvent.shouldWrite()) {
+                compilationEvent.setMethod(MetaUtil.format("%H.%n(%p)", method));
+                compilationEvent.setCompileId(getId());
+                compilationEvent.setCompileLevel(config.compilationLevelFullOptimization);
+                compilationEvent.setSucceeded(true);
+                compilationEvent.setIsOsr(isOSR);
+                compilationEvent.setCodeSize(installedCode.getSize());
+                compilationEvent.setInlinedBytes(processedBytes);
+                compilationEvent.commit();
+            }
+
             if (ctask != 0L) {
                 unsafe.putInt(ctask + config.compileTaskNumInlinedBytecodesOffset, processedBytes);
             }
             if ((config.ciTime || config.ciTimeEach || PrintCompRate.getValue() != 0) && installedCode != null) {
-
                 long time = CompilationTime.getCurrentValue() - previousCompilationTime;
                 TimeUnit timeUnit = CompilationTime.getTimeUnit();
                 long timeUnitsPerSecond = timeUnit.convert(1, TimeUnit.SECONDS);
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotGraalRuntime.java	Thu May 15 16:17:35 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotGraalRuntime.java	Thu May 15 17:25:49 2014 +0200
@@ -43,6 +43,7 @@
 import com.oracle.graal.compiler.target.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.hotspot.bridge.*;
+import com.oracle.graal.hotspot.events.*;
 import com.oracle.graal.hotspot.logging.*;
 import com.oracle.graal.hotspot.meta.*;
 import com.oracle.graal.options.*;
@@ -274,6 +275,8 @@
             }
             registerBackend(factory.createBackend(this, hostBackend));
         }
+
+        eventProvider = createEventProvider();
     }
 
     private HotSpotBackend registerBackend(HotSpotBackend backend) {
@@ -379,6 +382,22 @@
 
     private final NodeCollectionsProvider nodeCollectionsProvider = new DefaultNodeCollectionsProvider();
 
+    private final EventProvider eventProvider;
+
+    private EventProvider createEventProvider() {
+        if (config.flightRecorder) {
+            ServiceLoader<EventProvider> sl = ServiceLoader.loadInstalled(EventProvider.class);
+            EventProvider singleProvider = null;
+            for (EventProvider ep : sl) {
+                assert singleProvider == null : String.format("multiple %s service implementations found: %s and %s", EventProvider.class.getName(), singleProvider.getClass().getName(),
+                                ep.getClass().getName());
+                singleProvider = ep;
+            }
+            return singleProvider;
+        }
+        return new EmptyEventProvider();
+    }
+
     @SuppressWarnings("unchecked")
     @Override
     public <T> T getCapability(Class<T> clazz) {
@@ -392,6 +411,8 @@
             return (T) getHostProviders().getSnippetReflection();
         } else if (clazz == MethodHandleAccessProvider.class) {
             return (T) getHostProviders().getMethodHandleAccess();
+        } else if (clazz == EventProvider.class) {
+            return (T) eventProvider;
         }
         return null;
     }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotVMConfig.java	Thu May 15 16:17:35 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotVMConfig.java	Thu May 15 17:25:49 2014 +0200
@@ -737,6 +737,8 @@
     @HotSpotVMFlag(name = "AllocatePrefetchStepSize") @Stable public int allocatePrefetchStepSize;
     @HotSpotVMFlag(name = "AllocatePrefetchDistance") @Stable public int allocatePrefetchDistance;
 
+    @HotSpotVMFlag(name = "FlightRecorder", optional = true) @Stable public boolean flightRecorder;
+
     @HotSpotVMField(name = "Universe::_collectedHeap", type = "CollectedHeap*", get = HotSpotVMField.Type.VALUE) @Stable private long universeCollectedHeap;
     @HotSpotVMField(name = "CollectedHeap::_total_collections", type = "unsigned int", get = HotSpotVMField.Type.OFFSET) @Stable private int collectedHeapTotalCollectionsOffset;
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/events/EmptyEventProvider.java	Thu May 15 17:25:49 2014 +0200
@@ -0,0 +1,105 @@
+/*
+ * Copyright (c) 2014, 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.hotspot.events;
+
+import com.oracle.graal.compiler.common.*;
+
+/**
+ * An empty implementation for {@link EventProvider}. This implementation is used when no logging is
+ * requested.
+ */
+public final class EmptyEventProvider implements EventProvider {
+
+    public CompilationEvent newCompilationEvent() {
+        return new EmptyCompilationEvent();
+    }
+
+    class EmptyCompilationEvent implements CompilationEvent {
+        public void commit() {
+            throw GraalInternalError.shouldNotReachHere();
+        }
+
+        public boolean shouldWrite() {
+            // Events of this class should never been written.
+            return false;
+        }
+
+        public void begin() {
+        }
+
+        public void end() {
+        }
+
+        public void setMethod(String method) {
+            throw GraalInternalError.shouldNotReachHere();
+        }
+
+        public void setCompileId(int compileId) {
+            throw GraalInternalError.shouldNotReachHere();
+        }
+
+        public void setCompileLevel(int compileLevel) {
+            throw GraalInternalError.shouldNotReachHere();
+        }
+
+        public void setSucceeded(boolean succeeded) {
+            throw GraalInternalError.shouldNotReachHere();
+        }
+
+        public void setIsOsr(boolean isOsr) {
+            throw GraalInternalError.shouldNotReachHere();
+        }
+
+        public void setCodeSize(int codeSize) {
+            throw GraalInternalError.shouldNotReachHere();
+        }
+
+        public void setInlinedBytes(int inlinedBytes) {
+            throw GraalInternalError.shouldNotReachHere();
+        }
+    }
+
+    public CompilerFailureEvent newCompilerFailureEvent() {
+        return new EmptyCompilerFailureEvent();
+    }
+
+    class EmptyCompilerFailureEvent implements CompilerFailureEvent {
+        public void commit() {
+            throw GraalInternalError.shouldNotReachHere();
+        }
+
+        public boolean shouldWrite() {
+            // Events of this class should never been written.
+            return false;
+        }
+
+        public void setCompileId(int compileId) {
+            throw GraalInternalError.shouldNotReachHere();
+        }
+
+        public void setMessage(String message) {
+            throw GraalInternalError.shouldNotReachHere();
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/events/EventProvider.java	Thu May 15 17:25:49 2014 +0200
@@ -0,0 +1,105 @@
+/*
+ * Copyright (c) 2014, 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.hotspot.events;
+
+/**
+ * A provider that provides a specific implementation for events that can be logged in the compiler.
+ */
+public interface EventProvider {
+
+    /**
+     * An instant event is an event that is not considered to have taken any time.
+     */
+    interface InstantEvent {
+        /**
+         * Commits the event.
+         */
+        void commit();
+
+        /**
+         * Determines if this particular event instance would be committed to the data stream right
+         * now if application called {@link #commit()}. This in turn depends on whether the event is
+         * enabled and possible other factors.
+         *
+         * @return if this event would be committed on a call to {@link #commit()}.
+         */
+        boolean shouldWrite();
+    }
+
+    /**
+     * Timed events describe an operation that somehow consumes time.
+     */
+    interface TimedEvent extends InstantEvent {
+        /**
+         * Starts the timing for this event.
+         */
+        void begin();
+
+        /**
+         * Ends the timing period for this event.
+         */
+        void end();
+    }
+
+    /**
+     * Creates a new {@link CompilationEvent}.
+     *
+     * @return a compilation event
+     */
+    CompilationEvent newCompilationEvent();
+
+    /**
+     * A compilation event.
+     */
+    interface CompilationEvent extends TimedEvent {
+        void setMethod(String method);
+
+        void setCompileId(int compileId);
+
+        void setCompileLevel(int compileLevel);
+
+        void setSucceeded(boolean succeeded);
+
+        void setIsOsr(boolean isOsr);
+
+        void setCodeSize(int codeSize);
+
+        void setInlinedBytes(int inlinedBytes);
+    }
+
+    /**
+     * Creates a new {@link CompilerFailureEvent}.
+     *
+     * @return a compiler failure event
+     */
+    CompilerFailureEvent newCompilerFailureEvent();
+
+    /**
+     * A compiler failure event.
+     */
+    interface CompilerFailureEvent extends InstantEvent {
+        void setCompileId(int compileId);
+
+        void setMessage(String message);
+    }
+}
--- a/graal/com.oracle.graal.nodes.test/src/com/oracle/graal/nodes/test/ObjectStampJoinTest.java	Thu May 15 16:17:35 2014 +0200
+++ b/graal/com.oracle.graal.nodes.test/src/com/oracle/graal/nodes/test/ObjectStampJoinTest.java	Thu May 15 17:25:49 2014 +0200
@@ -26,34 +26,16 @@
 
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.common.type.*;
-import com.oracle.graal.compiler.test.*;
 import com.oracle.graal.nodes.type.*;
 
-public class ObjectStampJoinTest extends GraalCompilerTest {
-
-    private static class A {
-
-    }
-
-    private static class B extends A {
-
-    }
-
-    private static class C extends B implements I {
+public class ObjectStampJoinTest extends ObjectStampTest {
 
-    }
-
-    private static class D extends A {
-
-    }
-
-    private abstract static class E extends A {
-
-    }
-
-    private interface I {
-
-    }
+    // class A
+    // class B extends A
+    // class C extends B implements I
+    // class D extends A
+    // abstract class E extends A
+    // interface I
 
     @Test
     public void testJoin0() {
@@ -142,8 +124,8 @@
     @Test
     public void testJoinInterface0() {
         Stamp a = StampFactory.declared(getType(A.class));
-        Stamp b = StampFactory.declared(getType(I.class));
-        Assert.assertNotSame(StampFactory.illegal(Kind.Object), join(a, b));
+        Stamp i = StampFactory.declared(getType(I.class));
+        Assert.assertNotSame(StampFactory.illegal(Kind.Object), join(a, i));
     }
 
     @Test
@@ -163,14 +145,4 @@
         Assert.assertEquals(StampFactory.illegal(Kind.Object), join);
     }
 
-    private static Stamp join(Stamp a, Stamp b) {
-        Stamp ab = a.join(b);
-        Stamp ba = b.join(a);
-        Assert.assertEquals(ab, ba);
-        return ab;
-    }
-
-    private ResolvedJavaType getType(Class<?> clazz) {
-        return getMetaAccess().lookupJavaType(clazz);
-    }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.nodes.test/src/com/oracle/graal/nodes/test/ObjectStampMeetTest.java	Thu May 15 17:25:49 2014 +0200
@@ -0,0 +1,122 @@
+/*
+ * Copyright (c) 2013, 2014, 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.nodes.test;
+
+import org.junit.*;
+
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.compiler.common.type.*;
+
+public class ObjectStampMeetTest extends ObjectStampTest {
+
+    // class A
+    // class B extends A
+    // class C extends B implements I
+    // class D extends A
+    // abstract class E extends A
+    // interface I
+
+    @Test
+    public void testMeet0() {
+        Stamp a = StampFactory.declared(getType(A.class));
+        Stamp b = StampFactory.declared(getType(B.class));
+        Assert.assertEquals(a, meet(a, b));
+    }
+
+    @Test
+    public void testMeet1() {
+        Stamp a = StampFactory.declared(getType(A.class));
+        Stamp aNonNull = StampFactory.declaredNonNull(getType(A.class));
+        Stamp b = StampFactory.declared(getType(B.class));
+        Stamp bNonNull = StampFactory.declaredNonNull(getType(B.class));
+        Assert.assertEquals(a, meet(aNonNull, b));
+        Assert.assertEquals(aNonNull, meet(aNonNull, bNonNull));
+    }
+
+    @Test
+    public void testMeet2() {
+        Stamp a = StampFactory.declared(getType(A.class));
+        Stamp aExact = StampFactory.exactNonNull(getType(A.class));
+        Stamp b = StampFactory.declared(getType(B.class));
+        Assert.assertEquals(a, meet(aExact, b));
+    }
+
+    @Test
+    public void testMeet3() {
+        Stamp a = StampFactory.declared(getType(A.class));
+        Stamp d = StampFactory.declared(getType(D.class));
+        Stamp c = StampFactory.declared(getType(C.class));
+        Assert.assertEquals(a, meet(c, d));
+    }
+
+    @Test
+    public void testMeet4() {
+        Stamp dExactNonNull = StampFactory.exactNonNull(getType(D.class));
+        Stamp cExactNonNull = StampFactory.exactNonNull(getType(C.class));
+        Stamp aNonNull = StampFactory.declaredNonNull(getType(A.class));
+        Assert.assertEquals(aNonNull, meet(cExactNonNull, dExactNonNull));
+    }
+
+    @Test
+    public void testMeet() {
+        Stamp dExact = StampFactory.exact(getType(D.class));
+        Stamp c = StampFactory.declared(getType(C.class));
+        Stamp a = StampFactory.declared(getType(A.class));
+        Assert.assertEquals(a, meet(dExact, c));
+    }
+
+    @Test
+    public void testMeet6() {
+        Stamp dExactNonNull = StampFactory.exactNonNull(getType(D.class));
+        Stamp alwaysNull = StampFactory.alwaysNull();
+        Stamp dExact = StampFactory.exact(getType(D.class));
+        Assert.assertEquals(dExact, meet(dExactNonNull, alwaysNull));
+    }
+
+    @Test
+    public void testMeet7() {
+        Stamp aExact = StampFactory.exact(getType(A.class));
+        Stamp e = StampFactory.declared(getType(E.class));
+        Stamp a = StampFactory.declared(getType(A.class));
+        Assert.assertEquals(a, meet(aExact, e));
+    }
+
+    @Test
+    public void testMeetInterface0() {
+        Stamp a = StampFactory.declared(getType(A.class));
+        Stamp i = StampFactory.declared(getType(I.class));
+        Assert.assertNotSame(StampFactory.object(), meet(a, i));
+    }
+
+    @Test
+    public void testMeetIllegal1() {
+        for (Class<?> clazz : new Class<?>[]{A.class, B.class, C.class, D.class, E.class, I.class, Object.class}) {
+            ResolvedJavaType type = getType(clazz);
+            for (Stamp test : new Stamp[]{StampFactory.declared(type), StampFactory.declaredNonNull(type), StampFactory.exact(type), StampFactory.exactNonNull(type)}) {
+                if (!type.isAbstract() || !((ObjectStamp) test).isExactType()) {
+                    Assert.assertEquals("meeting illegal and " + test, test, meet(StampFactory.illegal(Kind.Object), test));
+                }
+            }
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.nodes.test/src/com/oracle/graal/nodes/test/ObjectStampTest.java	Thu May 15 17:25:49 2014 +0200
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 2013, 2014, 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.nodes.test;
+
+import org.junit.*;
+
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.compiler.common.type.*;
+import com.oracle.graal.compiler.test.*;
+
+public class ObjectStampTest extends GraalCompilerTest {
+
+    protected static class A {
+
+    }
+
+    protected static class B extends A {
+
+    }
+
+    protected static class C extends B implements I {
+
+    }
+
+    protected static class D extends A {
+
+    }
+
+    protected abstract static class E extends A {
+
+    }
+
+    protected interface I {
+
+    }
+
+    protected static Stamp join(Stamp a, Stamp b) {
+        Stamp ab = a.join(b);
+        Stamp ba = b.join(a);
+        Assert.assertEquals(ab, ba);
+        return ab;
+    }
+
+    protected static Stamp meet(Stamp a, Stamp b) {
+        Stamp ab = a.meet(b);
+        Stamp ba = b.meet(a);
+        Assert.assertEquals(ab, ba);
+        return ab;
+    }
+
+    protected ResolvedJavaType getType(Class<?> clazz) {
+        return getMetaAccess().lookupJavaType(clazz);
+    }
+}
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/DeoptimizationGroupingPhase.java	Thu May 15 16:17:35 2014 +0200
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/DeoptimizationGroupingPhase.java	Thu May 15 17:25:49 2014 +0200
@@ -62,7 +62,7 @@
                         merge.addForwardEnd(firstEnd);
                         reasonActionPhi.addInput(((AbstractDeoptimizeNode) target).getActionAndReason(context.getMetaAccess()));
                         speculationPhi.addInput(((AbstractDeoptimizeNode) target).getSpeculation(context.getMetaAccess()));
-                        target.predecessor().replaceFirstSuccessor(target, firstEnd);
+                        target.replaceAtPredecessor(firstEnd);
 
                         exitLoops((AbstractDeoptimizeNode) target, firstEnd, cfg);
 
@@ -77,7 +77,7 @@
                     merge.addForwardEnd(newEnd);
                     reasonActionPhi.addInput(deopt.getActionAndReason(context.getMetaAccess()));
                     speculationPhi.addInput(deopt.getSpeculation(context.getMetaAccess()));
-                    deopt.predecessor().replaceFirstSuccessor(deopt, newEnd);
+                    deopt.replaceAtPredecessor(newEnd);
                     exitLoops(deopt, newEnd, cfg);
                     obsoletes.add(deopt);
                 }
--- a/graal/com.oracle.graal.test/src/com/oracle/graal/test/GraalVerboseTextListener.java	Thu May 15 16:17:35 2014 +0200
+++ b/graal/com.oracle.graal.test/src/com/oracle/graal/test/GraalVerboseTextListener.java	Thu May 15 17:25:49 2014 +0200
@@ -65,7 +65,7 @@
 
     @Override
     public void testFailed(Failure failure) {
-        getWriter().println("FAILED");
+        getWriter().print("FAILED");
     }
 
     @Override
--- a/mx/projects	Thu May 15 16:17:35 2014 +0200
+++ b/mx/projects	Thu May 15 17:25:49 2014 +0200
@@ -2,8 +2,7 @@
 mxversion=1.0
 suite=graal
 
-library@JDK_TOOLS@path=${JAVA_HOME}/lib/tools.jar
-library@JDK_TOOLS@optional=true
+jrelibrary@JFR@jar=jfr.jar
 
 library@JUNIT@path=lib/junit-4.11.jar
 library@JUNIT@urls=http://repo1.maven.org/maven2/junit/junit/4.11/junit-4.11.jar
@@ -75,6 +74,7 @@
 com.oracle.graal.truffle.hotspot.amd64,\
 com.oracle.graal.hotspot.sparc,\
 com.oracle.graal.hotspot,\
+com.oracle.graal.hotspot.jfr,\
 com.oracle.graal.hotspot.hsail
 distribution@GRAAL@exclude=FINDBUGS
 
@@ -191,6 +191,16 @@
 project@com.oracle.graal.hotspot@javaCompliance=1.8
 project@com.oracle.graal.hotspot@workingSets=Graal,HotSpot
 
+# graal.hotspot.jfr
+project@com.oracle.graal.hotspot.jfr@subDir=graal
+project@com.oracle.graal.hotspot.jfr@sourceDirs=src
+project@com.oracle.graal.hotspot.jfr@dependencies=com.oracle.graal.hotspot,JFR
+project@com.oracle.graal.hotspot.jfr@checkstyle=com.oracle.graal.graph
+project@com.oracle.graal.hotspot.jfr@annotationProcessors=com.oracle.graal.service.processor
+project@com.oracle.graal.hotspot.jfr@javaCompliance=1.8
+project@com.oracle.graal.hotspot.jfr@profile=
+project@com.oracle.graal.hotspot.jfr@workingSets=Graal,HotSpot
+
 # graal.hotspot.amd64
 project@com.oracle.graal.hotspot.amd64@subDir=graal
 project@com.oracle.graal.hotspot.amd64@sourceDirs=src
--- a/mxtool/mx.py	Thu May 15 16:17:35 2014 +0200
+++ b/mxtool/mx.py	Thu May 15 17:25:49 2014 +0200
@@ -49,6 +49,7 @@
 
 _projects = dict()
 _libs = dict()
+_jreLibs = dict()
 _dists = dict()
 _suites = dict()
 _annotationProcessors = None
@@ -123,7 +124,7 @@
                             for arcname in lp.namelist():
                                 overwriteCheck(srcArc.zf, arcname, lpath + '!' + arcname)
                                 srcArc.zf.writestr(arcname, lp.read(arcname))
-                else:
+                elif dep.isProject():
                     p = dep
 
                     isCoveredByDependecy = False
@@ -138,9 +139,7 @@
 
                     # skip a  Java project if its Java compliance level is "higher" than the configured JDK
                     jdk = java(p.javaCompliance)
-                    if not jdk:
-                        log('Excluding {0} from {2} (Java compliance level {1} required)'.format(p.name, p.javaCompliance, self.path))
-                        continue
+                    assert jdk
 
                     logv('[' + self.path + ': adding project ' + p.name + ']')
                     outputDir = p.output_dir()
@@ -207,6 +206,9 @@
     def isLibrary(self):
         return isinstance(self, Library)
 
+    def isJreLibrary(self):
+        return isinstance(self, JreLibrary)
+
     def isProject(self):
         return isinstance(self, Project)
 
@@ -235,7 +237,7 @@
             if not exists(s):
                 os.mkdir(s)
 
-    def all_deps(self, deps, includeLibs, includeSelf=True, includeAnnotationProcessors=False):
+    def all_deps(self, deps, includeLibs, includeSelf=True, includeJreLibs=False, includeAnnotationProcessors=False):
         """
         Add the transitive set of dependencies for this project, including
         libraries if 'includeLibs' is true, to the 'deps' list.
@@ -248,8 +250,8 @@
         for name in childDeps:
             assert name != self.name
             dep = dependency(name)
-            if not dep in deps and (includeLibs or not dep.isLibrary()):
-                dep.all_deps(deps, includeLibs=includeLibs, includeAnnotationProcessors=includeAnnotationProcessors)
+            if not dep in deps and (dep.isProject or (dep.isLibrary() and includeLibs) or (dep.isJreLibrary() and includeJreLibs)):
+                dep.all_deps(deps, includeLibs=includeLibs, includeJreLibs=includeJreLibs, includeAnnotationProcessors=includeAnnotationProcessors)
         if not self in deps and includeSelf:
             deps.append(self)
         return deps
@@ -512,17 +514,74 @@
 
     return path
 
-class Library(Dependency):
-    def __init__(self, suite, name, path, mustExist, urls, sha1, sourcePath, sourceUrls, sourceSha1, deps):
+class BaseLibrary(Dependency):
+    def __init__(self, suite, name, optional):
         Dependency.__init__(self, suite, name)
+        self.optional = optional
+
+    def __ne__(self, other):
+        result = self.__eq__(other)
+        if result is NotImplemented:
+            return result
+        return not result
+
+"""
+A library that will be provided by the JDK but may be absent.
+Any project or normal library that depends on a missing library
+will be removed from the global project and library dictionaries
+(i.e., _projects and _libs).
+
+This mechanism exists primarily to be able to support code
+that may use functionality in one JDK (e.g., Oracle JDK)
+that is not present in another JDK (e.g., OpenJDK). A
+motivating example is the Java Flight Recorder library
+found in the Oracle JDK. 
+"""
+class JreLibrary(BaseLibrary):
+    def __init__(self, suite, name, jar, optional):
+        BaseLibrary.__init__(self, suite, name, optional)
+        self.jar = jar
+
+    def __eq__(self, other):
+        if isinstance(other, JreLibrary):
+            return self.jar == other.jar
+        else:
+            return NotImplemented
+
+    def is_present_in_jdk(self, jdk):
+        for e in jdk.bootclasspath().split(os.pathsep):
+            if basename(e) == self.jar:
+                return True
+        for d in jdk.extdirs().split(os.pathsep):
+            if len(d) and self.jar in os.listdir(d):
+                return True
+        for d in jdk.endorseddirs().split(os.pathsep):
+            if len(d) and self.jar in os.listdir(d):
+                return True
+        return False
+
+    def all_deps(self, deps, includeLibs, includeSelf=True, includeJreLibs=False, includeAnnotationProcessors=False):
+        """
+        Add the transitive set of dependencies for this JRE library to the 'deps' list.
+        """
+        if includeJreLibs and includeSelf and not self in deps:
+            deps.append(self)
+        return deps
+
+class Library(BaseLibrary):
+    def __init__(self, suite, name, path, optional, urls, sha1, sourcePath, sourceUrls, sourceSha1, deps):
+        BaseLibrary.__init__(self, suite, name, optional)
         self.path = path.replace('/', os.sep)
         self.urls = urls
         self.sha1 = sha1
-        self.mustExist = mustExist
         self.sourcePath = sourcePath
         self.sourceUrls = sourceUrls
         self.sourceSha1 = sourceSha1
         self.deps = deps
+        abspath = _make_absolute(self.path, self.suite.dir)
+        if not optional and not exists(abspath):
+            if not len(urls):
+                abort('Non-optional library {} must either exist at {} or specify one or more URLs from which it can be retrieved'.format(name, abspath))
         for url in urls:
             if url.endswith('/') != self.path.endswith(os.sep):
                 abort('Path for dependency directory must have a URL ending with "/": path=' + self.path + ' url=' + url)
@@ -536,14 +595,6 @@
         else:
             return NotImplemented
 
-
-    def __ne__(self, other):
-        result = self.__eq__(other)
-        if result is NotImplemented:
-            return result
-        return not result
-
-
     def get_path(self, resolve):
         path = _make_absolute(self.path, self.suite.dir)
         sha1path = path + '.sha1'
@@ -552,8 +603,7 @@
         if includedInJDK and java().javaCompliance >= JavaCompliance(includedInJDK):
             return None
 
-        return _download_file_with_sha1(self.name, path, self.urls, self.sha1, sha1path, resolve, self.mustExist)
-
+        return _download_file_with_sha1(self.name, path, self.urls, self.sha1, sha1path, resolve, self.optional)
 
     def get_source_path(self, resolve):
         if self.sourcePath is None:
@@ -568,7 +618,7 @@
         if path and (exists(path) or not resolve):
             cp.append(path)
 
-    def all_deps(self, deps, includeLibs, includeSelf=True, includeAnnotationProcessors=False):
+    def all_deps(self, deps, includeLibs, includeSelf=True, includeJreLibs=False, includeAnnotationProcessors=False):
         """
         Add the transitive set of dependencies for this library to the 'deps' list.
         """
@@ -581,7 +631,7 @@
             assert name != self.name
             dep = library(name)
             if not dep in deps:
-                dep.all_deps(deps, includeLibs=includeLibs, includeAnnotationProcessors=includeAnnotationProcessors)
+                dep.all_deps(deps, includeLibs=includeLibs, includeJreLibs=includeJreLibs, includeAnnotationProcessors=includeAnnotationProcessors)
         if not self in deps and includeSelf:
             deps.append(self)
         return deps
@@ -637,6 +687,7 @@
         self.mxDir = mxDir
         self.projects = []
         self.libs = []
+        self.jreLibs = []
         self.dists = []
         self.commands = None
         self.primary = primary
@@ -654,6 +705,7 @@
 
     def _load_projects(self):
         libsMap = dict()
+        jreLibsMap = dict()
         projsMap = dict()
         distsMap = dict()
         projectsFile = join(self.mxDir, 'projects')
@@ -703,6 +755,8 @@
                         m = projsMap
                     elif kind == 'library':
                         m = libsMap
+                    elif kind == 'jrelibrary':
+                        m = jreLibsMap
                     elif kind == 'distribution':
                         m = distsMap
                     else:
@@ -743,16 +797,24 @@
             p.__dict__.update(attrs)
             self.projects.append(p)
 
+        for name, attrs in jreLibsMap.iteritems():
+            jar = attrs.pop('jar')
+            # JRE libraries are optional by default
+            optional = attrs.pop('optional', 'true') != 'false'
+            l = JreLibrary(self, name, jar, optional)
+            self.jreLibs.append(l)
+
         for name, attrs in libsMap.iteritems():
             path = attrs.pop('path')
-            mustExist = attrs.pop('optional', 'false') != 'true'
             urls = pop_list(attrs, 'urls')
             sha1 = attrs.pop('sha1', None)
             sourcePath = attrs.pop('sourcePath', None)
             sourceUrls = pop_list(attrs, 'sourceUrls')
             sourceSha1 = attrs.pop('sourceSha1', None)
             deps = pop_list(attrs, 'dependencies')
-            l = Library(self, name, path, mustExist, urls, sha1, sourcePath, sourceUrls, sourceSha1, deps)
+            # Add support optional libraries once we have a good use case
+            optional = False
+            l = Library(self, name, path, optional, urls, sha1, sourcePath, sourceUrls, sourceSha1, deps)
             l.__dict__.update(attrs)
             self.libs.append(l)
 
@@ -842,6 +904,12 @@
             if existing is not None and existing != l:
                 abort('inconsistent library redefinition of ' + l.name + ' in ' + existing.suite.dir + ' and ' + l.suite.dir)
             _libs[l.name] = l
+        for l in self.jreLibs:
+            existing = _jreLibs.get(l.name)
+            # Check that suites that define same library are consistent
+            if existing is not None and existing != l:
+                abort('inconsistent JRE library redefinition of ' + l.name + ' in ' + existing.suite.dir + ' and ' + l.suite.dir)
+            _jreLibs[l.name] = l
         for d in self.dists:
             existing = _dists.get(d.name)
             if existing is not None:
@@ -850,6 +918,54 @@
                 warn('distribution ' + d.name + ' redefined')
                 d.path = existing.path
             _dists[d.name] = d
+
+        # Remove projects and libraries that (recursively) depend on an optional library
+        # whose artifact does not exist or on a JRE library that is not present in the
+        # JDK for a project. Also remove projects whose Java compliance requirement
+        # cannot be satisfied by the configured JDKs.
+        #
+        # Removed projects and libraries are also removed from
+        # distributions in they are listed as dependencies.
+        for d in sorted_deps(includeLibs=True):
+            if d.isLibrary():
+                if d.optional:
+                    try:
+                        d.optional = False
+                        path = d.get_path(resolve=True)
+                    except SystemExit:
+                        path = None
+                    finally:
+                        d.optional = True
+                    if not path:
+                        logv('[omitting optional library {} as {} does not exist]'.format(d, d.path))
+                        del _libs[d.name]
+                        self.libs.remove(d)
+            elif d.isProject():
+                if java(d.javaCompliance) is None:
+                    logv('[omitting project {} as Java compliance {} cannot be satisfied by configured JDKs]'.format(d, d.javaCompliance))
+                    del _projects[d.name]
+                    self.projects.remove(d)
+                else:
+                    for name in list(d.deps):
+                        jreLib = _jreLibs.get(name)
+                        if jreLib:
+                            if not jreLib.is_present_in_jdk(java(d.javaCompliance)):
+                                if jreLib.optional:
+                                    logv('[omitting project {} as dependency {} is missing]'.format(d, name))
+                                    del _projects[d.name]
+                                    self.projects.remove(d)
+                                else:
+                                    abort('JRE library {} required by {} not found'.format(jreLib, d))
+                        elif not dependency(name, fatalIfMissing=False):
+                            logv('[omitting project {} as dependency {} is missing]'.format(d, name))
+                            del _projects[d.name]
+                            self.projects.remove(d)
+        for dist in _dists.values():
+            for name in list(dist.deps):
+                if not dependency(name, fatalIfMissing=False):
+                    logv('[omitting {} from distribution {}]'.format(name, dist))
+                    dist.deps.remove(name)
+
         if hasattr(self, 'mx_post_parse_cmd_line'):
             self.mx_post_parse_cmd_line(opts)
 
@@ -1031,6 +1147,8 @@
     d = _projects.get(name)
     if d is None:
         d = _libs.get(name)
+        if d is None:
+            d = _jreLibs.get(name)
     if d is None and fatalIfMissing:
         if name in _opts.ignored_projects:
             abort('project named ' + name + ' is ignored')
@@ -1546,6 +1664,8 @@
         self.javadoc = exe_suffix(join(self.jdk, 'bin', 'javadoc'))
         self.toolsjar = join(self.jdk, 'lib', 'tools.jar')
         self._bootclasspath = None
+        self._extdirs = None
+        self._endorseddirs = None
 
         if not exists(self.java):
             abort('Java launcher does not exist: ' + self.java)
@@ -1714,8 +1834,6 @@
     if _opts.killwithsigquit:
         _send_sigquit()
 
-    # import traceback
-    # traceback.print_stack()
     for p, args in _currentSubprocesses:
         try:
             if get_os() == 'windows':
@@ -1725,6 +1843,9 @@
         except BaseException as e:
             log('error while killing subprocess {} "{}": {}'.format(p.pid, ' '.join(args), e))
 
+    if _opts and _opts.verbose:
+        import traceback
+        traceback.print_stack()
     raise SystemExit(codeOrMessage)
 
 def download(path, urls, verbose=False):
@@ -2030,9 +2151,7 @@
         # skip building this Java project if its Java compliance level is "higher" than the configured JDK
         requiredCompliance = p.javaCompliance if p.javaCompliance else JavaCompliance(args.compliance) if args.compliance else None
         jdk = java(requiredCompliance)
-        if not jdk:
-            log('Excluding {0} from build (Java compliance level {1} required)'.format(p.name, requiredCompliance))
-            continue
+        assert jdk
 
         outputDir = prepareOutputDirs(p, args.clean)
 
@@ -2628,9 +2747,7 @@
 
         # skip checking this Java project if its Java compliance level is "higher" than the configured JDK
         jdk = java(p.javaCompliance)
-        if not jdk:
-            log('Excluding {0} from checking (Java compliance level {1} required)'.format(p.name, p.javaCompliance))
-            continue
+        assert jdk
 
         for sourceDir in sourceDirs:
             javafilelist = []
@@ -2874,7 +2991,7 @@
             elif dep.get_source_path(resolve=True):
                 memento = XMLDoc().element('archive', {'detectRoot' : 'true', 'path' : dep.get_source_path(resolve=True)}).xml(standalone='no')
                 slm.element('container', {'memento' : memento, 'typeId':'org.eclipse.debug.core.containerType.externalArchive'})
-        else:
+        elif dep.isProject():
             memento = XMLDoc().element('javaProject', {'name' : dep.name}).xml(standalone='no')
             slm.element('container', {'memento' : memento, 'typeId':'org.eclipse.jdt.launching.sourceContainer.javaProject'})
             if javaCompliance is None or dep.javaCompliance < javaCompliance:
@@ -3041,9 +3158,7 @@
         if p.native:
             continue
 
-        if not java(p.javaCompliance):
-            log('Excluding {0} (JDK with compliance level {1} not available)'.format(p.name, p.javaCompliance))
-            continue
+        assert java(p.javaCompliance)
 
         if not exists(p.dir):
             os.makedirs(p.dir)
@@ -3084,7 +3199,7 @@
                     libraryDeps -= set(dep.all_deps([], True))
                 else:
                     libraryDeps.add(dep)
-            else:
+            elif dep.isProject():
                 projectDeps.add(dep)
 
         for dep in containerDeps:
@@ -3093,8 +3208,6 @@
         for dep in libraryDeps:
             path = dep.path
             dep.get_path(resolve=True)
-            if not path or (not exists(path) and not dep.mustExist):
-                continue
 
             # Relative paths for "lib" class path entries have various semantics depending on the Eclipse
             # version being used (e.g. see https://bugs.eclipse.org/bugs/show_bug.cgi?id=274737) so it's
@@ -3252,16 +3365,13 @@
                 for dep in dependency(ap).all_deps([], True):
                     if dep.isLibrary():
                         if not hasattr(dep, 'eclipse.container') and not hasattr(dep, 'eclipse.project'):
-                            if dep.mustExist:
-                                path = dep.get_path(resolve=True)
-                                if path:
-                                    # Relative paths for "lib" class path entries have various semantics depending on the Eclipse
-                                    # version being used (e.g. see https://bugs.eclipse.org/bugs/show_bug.cgi?id=274737) so it's
-                                    # safest to simply use absolute paths.
-                                    path = _make_absolute(path, p.suite.dir)
-                                    out.element('factorypathentry', {'kind' : 'EXTJAR', 'id' : path, 'enabled' : 'true', 'runInBatchMode' : 'false'})
-                                    files.append(path)
-                    else:
+                            # Relative paths for "lib" class path entries have various semantics depending on the Eclipse
+                            # version being used (e.g. see https://bugs.eclipse.org/bugs/show_bug.cgi?id=274737) so it's
+                            # safest to simply use absolute paths.
+                            path = _make_absolute(dep.get_path(resolve=True), p.suite.dir)
+                            out.element('factorypathentry', {'kind' : 'EXTJAR', 'id' : path, 'enabled' : 'true', 'runInBatchMode' : 'false'})
+                            files.append(path)
+                    elif dep.isProject():
                         out.element('factorypathentry', {'kind' : 'WKSPJAR', 'id' : '/' + dep.name + '/' + dep.name + '.jar', 'enabled' : 'true', 'runInBatchMode' : 'false'})
             out.close('factorypath')
             update_file(join(p.dir, '.factorypath'), out.xml(indent='\t', newl='\n'))
@@ -3564,10 +3674,7 @@
             os.makedirs(join(p.dir, 'nbproject'))
 
         jdk = java(p.javaCompliance)
-
-        if not jdk:
-            log('Excluding {0} (JDK with compliance level {1} not available)'.format(p.name, p.javaCompliance))
-            continue
+        assert jdk
 
         jdks.add(jdk)
 
@@ -3608,7 +3715,7 @@
             if dep == p:
                 continue
 
-            if not dep.isLibrary():
+            if dep.isProject():
                 n = dep.name.replace('.', '_')
                 if firstDep:
                     out.open('references', {'xmlns' : 'http://www.netbeans.org/ns/ant-project-references/1'})
@@ -3743,8 +3850,6 @@
                 continue
 
             if dep.isLibrary():
-                if not dep.mustExist:
-                    continue
                 path = dep.get_path(resolve=True)
                 if path:
                     if os.sep == '\\':
@@ -3753,7 +3858,7 @@
                     print >> out, ref + '=' + path
                     libFiles.append(path)
 
-            else:
+            elif dep.isProject():
                 n = dep.name.replace('.', '_')
                 relDepPath = os.path.relpath(dep.dir, p.dir).replace(os.sep, '/')
                 ref = 'reference.' + n + '.jar'
@@ -3820,9 +3925,7 @@
         if p.native:
             continue
 
-        if not java(p.javaCompliance):
-            log('Excluding {0} (JDK with compliance level {1} not available)'.format(p.name, p.javaCompliance))
-            continue
+        assert java(p.javaCompliance)
 
         if not exists(p.dir):
             os.makedirs(p.dir)
@@ -3869,10 +3972,9 @@
                 continue
 
             if dep.isLibrary():
-                if dep.mustExist:
-                    libraries.add(dep)
-                    moduleXml.element('orderEntry', attributes={'type': 'library', 'name': dep.name, 'level': 'project'})
-            else:
+                libraries.add(dep)
+                moduleXml.element('orderEntry', attributes={'type': 'library', 'name': dep.name, 'level': 'project'})
+            elif dep.isProject():
                 moduleXml.element('orderEntry', attributes={'type': 'module', 'module-name': dep.name})
 
         moduleXml.close('component')
@@ -3944,7 +4046,7 @@
                 for entry in pDep.all_deps([], True):
                     if entry.isLibrary():
                         compilerXml.element('entry', attributes={'name': '$PROJECT_DIR$/' + os.path.relpath(entry.path, suite.dir)})
-                    else:
+                    elif entry.isProject():
                         assert entry.isProject()
                         compilerXml.element('entry', attributes={'name': '$PROJECT_DIR$/' + os.path.relpath(entry.output_dir(), suite.dir)})
             compilerXml.close('processorPath')