8144083: [JVMCI] CompilationResult should be finalized by JVMCI compiler and made effectively final
Reviewed-by: iveresov, twisti
--- 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());