8144083: [JVMCI] CompilationResult should be finalized by JVMCI compiler and made effectively final
authortwisti
Tue, 01 Dec 2015 15:11:15 -1000
changeset 34508 838d37db4223
parent 34507 636a88905e3b
child 34509 5b125fa28ea9
8144083: [JVMCI] CompilationResult should be finalized by JVMCI compiler and made effectively final Reviewed-by: iveresov, twisti
hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/CompilationResult.java
hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/DataSection.java
hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotCompiledCode.java
--- a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/CompilationResult.java	Wed Nov 25 18:13:13 2015 +0000
+++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/CompilationResult.java	Tue Dec 01 15:11:15 2015 -1000
@@ -552,6 +552,8 @@
      */
     private final boolean isImmutablePIC;
 
+    private boolean closed;
+
     private int entryBCI = -1;
 
     private final DataSection dataSection = new DataSection();
@@ -666,6 +668,7 @@
      * @param entryBCI the entryBCI to set
      */
     public void setEntryBCI(int entryBCI) {
+        checkOpen();
         this.entryBCI = entryBCI;
     }
 
@@ -673,11 +676,14 @@
      * Sets the assumptions made during compilation.
      */
     public void setAssumptions(Assumption[] assumptions) {
+        checkOpen();
         this.assumptions = assumptions;
     }
 
     /**
      * Gets the assumptions made during compilation.
+     *
+     * The caller must not modify the contents of the returned array.
      */
     public Assumption[] getAssumptions() {
         return assumptions;
@@ -690,6 +696,7 @@
      * @param inlinedMethods the methods inlined during compilation
      */
     public void setMethods(ResolvedJavaMethod rootMethod, Collection<ResolvedJavaMethod> inlinedMethods) {
+        checkOpen();
         assert rootMethod != null;
         assert inlinedMethods != null;
         if (inlinedMethods.contains(rootMethod)) {
@@ -717,6 +724,8 @@
     /**
      * Gets the methods whose bytecodes were used as input to the compilation.
      *
+     * The caller must not modify the contents of the returned array.
+     *
      * @return {@code null} if the compilation did not record method dependencies otherwise the
      *         methods whose bytecodes were used as input to the compilation with the first element
      *         being the root method of the compilation
@@ -726,6 +735,7 @@
     }
 
     public void setBytecodeSize(int bytecodeSize) {
+        checkOpen();
         this.bytecodeSize = bytecodeSize;
     }
 
@@ -755,6 +765,7 @@
      * @param size the size of the frame in bytes
      */
     public void setTotalFrameSize(int size) {
+        checkOpen();
         totalFrameSize = size;
     }
 
@@ -765,6 +776,7 @@
      * @param size the size of the machine code
      */
     public void setTargetCode(byte[] code, int size) {
+        checkOpen();
         targetCode = code;
         targetCodeSize = size;
     }
@@ -778,6 +790,7 @@
      * @param ref The reference that should be inserted in the code.
      */
     public void recordDataPatch(int codePos, Reference ref) {
+        checkOpen();
         assert codePos >= 0 && ref != null;
         dataPatches.add(new DataPatch(codePos, ref));
     }
@@ -814,6 +827,7 @@
      * @param direct specifies if this is a {@linkplain Call#direct direct} call
      */
     public void recordCall(int codePos, int size, InvokeTarget target, DebugInfo debugInfo, boolean direct) {
+        checkOpen();
         final Call call = new Call(target, codePos, size, direct, debugInfo);
         addInfopoint(call);
     }
@@ -825,6 +839,7 @@
      * @param handlerPos the position of the handler
      */
     public void recordExceptionHandler(int codePos, int handlerPos) {
+        checkOpen();
         assert validateExceptionHandlerAdd(codePos, handlerPos) : String.format("Duplicate exception handler for pc 0x%x handlerPos 0x%x", codePos, handlerPos);
         exceptionHandlers.add(new ExceptionHandler(codePos, handlerPos));
     }
@@ -875,6 +890,7 @@
      * @param infopoint the infopoint to record, usually a derived class from {@link Infopoint}
      */
     public void addInfopoint(Infopoint infopoint) {
+        checkOpen();
         infopoints.add(infopoint);
     }
 
@@ -885,6 +901,7 @@
      * @param markId the identifier for this mark
      */
     public Mark recordMark(int codePos, Object markId) {
+        checkOpen();
         Mark mark = new Mark(codePos, markId);
         marks.add(mark);
         return mark;
@@ -904,6 +921,7 @@
      * @param offset
      */
     public void setCustomStackAreaOffset(int offset) {
+        checkOpen();
         customStackAreaOffset = offset;
     }
 
@@ -932,6 +950,7 @@
     }
 
     public void addAnnotation(CodeAnnotation annotation) {
+        checkOpen();
         assert annotation != null;
         if (annotations == null) {
             annotations = new ArrayList<>();
@@ -1014,6 +1033,7 @@
     }
 
     public void setHasUnsafeAccess(boolean hasUnsafeAccess) {
+        checkOpen();
         this.hasUnsafeAccess = hasUnsafeAccess;
     }
 
@@ -1021,8 +1041,14 @@
         return hasUnsafeAccess;
     }
 
-    public void reset() {
-        hasUnsafeAccess = false;
+    /**
+     * Clears the information in this object pertaining to generating code. That is, the
+     * {@linkplain #getMarks() marks}, {@linkplain #getInfopoints() infopoints},
+     * {@linkplain #getExceptionHandlers() exception handlers}, {@linkplain #getDataPatches() data
+     * patches} and {@linkplain #getAnnotations() annotations} recorded in this object are cleared.
+     */
+    public void resetForEmittingCode() {
+        checkOpen();
         infopoints.clear();
         dataPatches.clear();
         exceptionHandlers.clear();
@@ -1032,4 +1058,21 @@
             annotations.clear();
         }
     }
+
+    private void checkOpen() {
+        if (closed) {
+            throw new IllegalStateException();
+        }
+    }
+
+    /**
+     * Closes this compilation result to future updates.
+     */
+    public void close() {
+        if (closed) {
+            throw new IllegalStateException("Cannot re-close compilation result " + this);
+        }
+        dataSection.close();
+        closed = true;
+    }
 }
--- a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/DataSection.java	Wed Nov 25 18:13:13 2015 +0000
+++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/DataSection.java	Tue Dec 01 15:11:15 2015 -1000
@@ -141,7 +141,7 @@
 
     private final ArrayList<Data> dataItems = new ArrayList<>();
 
-    private boolean finalLayout;
+    private boolean closed;
     private int sectionAlignment;
     private int sectionSize;
 
@@ -163,7 +163,7 @@
         }
         if (obj instanceof DataSection) {
             DataSection that = (DataSection) obj;
-            if (this.finalLayout == that.finalLayout && this.sectionAlignment == that.sectionAlignment && this.sectionSize == that.sectionSize && Objects.equals(this.dataItems, that.dataItems)) {
+            if (this.closed == that.closed && this.sectionAlignment == that.sectionAlignment && this.sectionSize == that.sectionSize && Objects.equals(this.dataItems, that.dataItems)) {
                 return true;
             }
         }
@@ -171,14 +171,14 @@
     }
 
     /**
-     * Insert a {@link Data} item into the data section. If the item is already in the data section,
-     * the same {@link DataSectionReference} is returned.
+     * Inserts a {@link Data} item into the data section. If the item is already in the data
+     * section, the same {@link DataSectionReference} is returned.
      *
      * @param data the {@link Data} item to be inserted
      * @return a unique {@link DataSectionReference} identifying the {@link Data} item
      */
     public DataSectionReference insertData(Data data) {
-        assert !finalLayout;
+        checkOpen();
         synchronized (data) {
             if (data.ref == null) {
                 data.ref = new DataSectionReference();
@@ -193,7 +193,8 @@
      * {@link DataSection}, and empties the other section.
      */
     public void addAll(DataSection other) {
-        assert !finalLayout && !other.finalLayout;
+        checkOpen();
+        other.checkOpen();
 
         for (Data data : other.dataItems) {
             assert data.ref != null;
@@ -203,12 +204,20 @@
     }
 
     /**
-     * Compute the layout of the data section. This can be called only once, and after it has been
-     * called, the data section can no longer be modified.
+     * Determines if this object has been {@link #close() closed}.
      */
-    public void finalizeLayout() {
-        assert !finalLayout;
-        finalLayout = true;
+    public boolean closed() {
+        return closed;
+    }
+
+    /**
+     * Computes the layout of the data section and closes this object to further updates.
+     *
+     * This must be called exactly once.
+     */
+    void close() {
+        checkOpen();
+        closed = true;
 
         // simple heuristic: put items with larger alignment requirement first
         dataItems.sort((a, b) -> a.alignment - b.alignment);
@@ -227,37 +236,38 @@
         sectionSize = position;
     }
 
-    public boolean isFinalized() {
-        return finalLayout;
-    }
-
     /**
-     * Get the size of the data section. Can only be called after {@link #finalizeLayout}.
+     * Gets the size of the data section.
+     *
+     * This must only be called once this object has been {@linkplain #closed() closed}.
      */
     public int getSectionSize() {
-        assert finalLayout;
+        checkClosed();
         return sectionSize;
     }
 
     /**
-     * Get the minimum alignment requirement of the data section. Can only be called after
-     * {@link #finalizeLayout}.
+     * Gets the minimum alignment requirement of the data section.
+     *
+     * This must only be called once this object has been {@linkplain #closed() closed}.
      */
     public int getSectionAlignment() {
-        assert finalLayout;
+        checkClosed();
         return sectionAlignment;
     }
 
     /**
-     * Build the data section. Can only be called after {@link #finalizeLayout}.
+     * Builds the data section into a given buffer.
+     *
+     * This must only be called once this object has been {@linkplain #closed() closed}.
      *
-     * @param buffer The {@link ByteBuffer} where the data section should be built. The buffer must
+     * @param buffer the {@link ByteBuffer} where the data section should be built. The buffer must
      *            hold at least {@link #getSectionSize()} bytes.
-     * @param patch A {@link Consumer} to receive {@link DataPatch data patches} for relocations in
-     *            the data section.
+     * @param patch a {@link Consumer} to receive {@link DataPatch data patches} for relocations in
+     *            the data section
      */
     public void buildDataSection(ByteBuffer buffer, Consumer<DataPatch> patch) {
-        assert finalLayout;
+        checkClosed();
         for (Data d : dataItems) {
             buffer.position(d.ref.getOffset());
             d.builder.emit(buffer, patch);
@@ -300,8 +310,20 @@
         return ((position + alignment - 1) / alignment) * alignment;
     }
 
+    private void checkClosed() {
+        if (!closed) {
+            throw new IllegalStateException();
+        }
+    }
+
+    private void checkOpen() {
+        if (closed) {
+            throw new IllegalStateException();
+        }
+    }
+
     public void clear() {
-        assert !finalLayout;
+        checkOpen();
         this.dataItems.clear();
         this.sectionAlignment = 0;
         this.sectionSize = 0;
--- a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotCompiledCode.java	Wed Nov 25 18:13:13 2015 +0000
+++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotCompiledCode.java	Tue Dec 01 15:11:15 2015 -1000
@@ -123,7 +123,6 @@
         targetCodeSize = compResult.getTargetCodeSize();
 
         DataSection data = compResult.getDataSection();
-        data.finalizeLayout();
         dataSection = new byte[data.getSectionSize()];
 
         ByteBuffer buffer = ByteBuffer.wrap(dataSection).order(ByteOrder.nativeOrder());