blob: 5cd3636eaadf1ec0d94d7e02f3c2a93db0f2c25c [file] [log] [blame]
/*
* Copyright (c) 2009, 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 jdk.vm.ci.code;
import static java.util.Collections.*;
import static jdk.vm.ci.meta.MetaUtil.*;
import java.util.*;
import jdk.vm.ci.meta.*;
import jdk.vm.ci.meta.Assumptions.*;
/**
* Represents the output from compiling a method, including the compiled machine code, associated
* data and references, relocation information, deoptimization information, etc.
*/
public class CompilationResult {
/**
* Represents a code position with associated additional information.
*/
public abstract static class Site {
/**
* The position (or offset) of this site with respect to the start of the target method.
*/
public final int pcOffset;
public Site(int pos) {
this.pcOffset = pos;
}
@Override
public final int hashCode() {
throw new UnsupportedOperationException("hashCode");
}
@Override
public String toString() {
return identityHashCodeString(this);
}
@Override
public abstract boolean equals(Object obj);
}
/**
* Represents an infopoint with associated debug info. Note that safepoints are also infopoints.
*/
public static class Infopoint extends Site implements Comparable<Infopoint> {
public final DebugInfo debugInfo;
public final InfopointReason reason;
public Infopoint(int pcOffset, DebugInfo debugInfo, InfopointReason reason) {
super(pcOffset);
this.debugInfo = debugInfo;
this.reason = reason;
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append(pcOffset);
sb.append("[<infopoint>]");
appendDebugInfo(sb, debugInfo);
return sb.toString();
}
@Override
public int compareTo(Infopoint o) {
if (pcOffset < o.pcOffset) {
return -1;
} else if (pcOffset > o.pcOffset) {
return 1;
}
return this.reason.compareTo(o.reason);
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj != null && obj.getClass() == getClass()) {
Infopoint that = (Infopoint) obj;
if (this.pcOffset == that.pcOffset && Objects.equals(this.debugInfo, that.debugInfo) && Objects.equals(this.reason, that.reason)) {
return true;
}
}
return false;
}
}
public enum MetaSpaceAccessType {
Move,
Store, // store only works for compressed oops (memory <- 32bit value). Compressed oops is
// not supported using AOT. TODO: Look at HotSpotStoreConstantOp
Compare; // HotSpotCompareMemoryConstantOp, HotSpotCompareConstantOp
private MetaSpaceAccessType() {
}
}
/**
* Represents a meta space pointer access in the code.
*/
public static final class MetaSpaceAccess extends Infopoint {
private static final long serialVersionUID = 1701958512608684706L;
/**
* Metaspace reference.
*/
public final Object reference; // Object here is a HotSpotResolvedObjectType or a
// HotSpotMetaSpaceConstant
public final MetaSpaceAccessType type;
/**
* Instruction size.
*/
public final int instructionSize;
public MetaSpaceAccess(Object reference, int instructionSize, MetaSpaceAccessType type, int pcOffset, DebugInfo debugInfo) {
super(pcOffset, debugInfo, InfopointReason.METASPACE_ACCESS);
this.type = type;
this.reference = reference;
this.instructionSize = instructionSize;
}
}
/**
* Represents a call in the code.
*/
public static final class Call extends Infopoint {
/**
* The target of the call.
*/
public final InvokeTarget target;
/**
* The size of the call instruction.
*/
public final int size;
/**
* Specifies if this call is direct or indirect. A direct call has an immediate operand
* encoding the absolute or relative (to the call itself) address of the target. An indirect
* call has a register or memory operand specifying the target address of the call.
*/
public final boolean direct;
public Call(InvokeTarget target, int pcOffset, int size, boolean direct, DebugInfo debugInfo) {
super(pcOffset, debugInfo, InfopointReason.CALL);
this.size = size;
this.target = target;
this.direct = direct;
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj instanceof Call && super.equals(obj)) {
Call that = (Call) obj;
if (this.size == that.size && this.direct == that.direct && Objects.equals(this.target, that.target)) {
return true;
}
}
return false;
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append(pcOffset);
sb.append('[');
sb.append(target);
sb.append(']');
if (debugInfo != null) {
appendDebugInfo(sb, debugInfo);
}
return sb.toString();
}
}
/**
* Represents some external data that is referenced by the code.
*/
public abstract static class Reference {
@Override
public abstract int hashCode();
@Override
public abstract boolean equals(Object obj);
}
public static final class ConstantReference extends Reference {
private final VMConstant constant;
public ConstantReference(VMConstant constant) {
this.constant = constant;
}
public VMConstant getConstant() {
return constant;
}
@Override
public String toString() {
return constant.toString();
}
@Override
public int hashCode() {
return constant.hashCode();
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj instanceof ConstantReference) {
ConstantReference that = (ConstantReference) obj;
return Objects.equals(this.constant, that.constant);
}
return false;
}
}
public static final class DataSectionReference extends Reference {
private boolean initialized;
private int offset;
public DataSectionReference() {
// will be set after the data section layout is fixed
offset = 0xDEADDEAD;
}
public int getOffset() {
assert initialized;
return offset;
}
public void setOffset(int offset) {
assert !initialized;
initialized = true;
this.offset = offset;
}
@Override
public int hashCode() {
return offset;
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj instanceof DataSectionReference) {
DataSectionReference that = (DataSectionReference) obj;
return this.offset == that.offset;
}
return false;
}
}
/**
* Represents a code site that references some data. The associated data can be either a
* {@link DataSectionReference reference} to the data section, or it may be an inlined
* {@link JavaConstant} that needs to be patched.
*/
public static final class DataPatch extends Site {
public Reference reference;
public Object note;
public DataPatch(int pcOffset, Reference reference) {
super(pcOffset);
this.reference = reference;
this.note = null;
}
public DataPatch(int pcOffset, Reference reference, Object note) {
super(pcOffset);
this.reference = reference;
this.note = note;
}
@Override
public String toString() {
if (note != null) {
return String.format("%d[<data patch referring to %s>, note: %s]", pcOffset, reference.toString(), note.toString());
} else {
return String.format("%d[<data patch referring to %s>]", pcOffset, reference.toString());
}
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj instanceof DataPatch) {
DataPatch that = (DataPatch) obj;
if (this.pcOffset == that.pcOffset && Objects.equals(this.reference, that.reference) && Objects.equals(this.note, that.note)) {
return true;
}
}
return false;
}
}
/**
* Provides extra information about instructions or data at specific positions in
* {@link CompilationResult#getTargetCode()}. This is optional information that can be used to
* enhance a disassembly of the code.
*/
public abstract static class CodeAnnotation {
public final int position;
public CodeAnnotation(int position) {
this.position = position;
}
@Override
public final int hashCode() {
throw new UnsupportedOperationException("hashCode");
}
@Override
public String toString() {
return identityHashCodeString(this);
}
@Override
public abstract boolean equals(Object obj);
}
/**
* A string comment about one or more instructions at a specific position in the code.
*/
public static final class CodeComment extends CodeAnnotation {
public final String value;
public CodeComment(int position, String comment) {
super(position);
this.value = comment;
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj instanceof CodeComment) {
CodeComment that = (CodeComment) obj;
if (this.position == that.position && this.value.equals(that.value)) {
return true;
}
}
return false;
}
@Override
public String toString() {
return getClass().getSimpleName() + "@" + position + ": " + value;
}
}
/**
* Describes a table of signed offsets embedded in the code. The offsets are relative to the
* starting address of the table. This type of table maybe generated when translating a
* multi-way branch based on a key value from a dense value set (e.g. the {@code tableswitch}
* JVM instruction).
*
* The table is indexed by the contiguous range of integers from {@link #low} to {@link #high}
* inclusive.
*/
public static final class JumpTable extends CodeAnnotation {
/**
* The low value in the key range (inclusive).
*/
public final int low;
/**
* The high value in the key range (inclusive).
*/
public final int high;
/**
* The size (in bytes) of each table entry.
*/
public final int entrySize;
public JumpTable(int position, int low, int high, int entrySize) {
super(position);
this.low = low;
this.high = high;
this.entrySize = entrySize;
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj instanceof JumpTable) {
JumpTable that = (JumpTable) obj;
if (this.position == that.position && this.entrySize == that.entrySize && this.low == that.low && this.high == that.high) {
return true;
}
}
return false;
}
@Override
public String toString() {
return getClass().getSimpleName() + "@" + position + ": [" + low + " .. " + high + "]";
}
}
/**
* Represents exception handler information for a specific code position. It includes the catch
* code position as well as the caught exception type.
*/
public static final class ExceptionHandler extends Site {
public final int handlerPos;
ExceptionHandler(int pcOffset, int handlerPos) {
super(pcOffset);
this.handlerPos = handlerPos;
}
@Override
public String toString() {
return String.format("%d[<exception edge to %d>]", pcOffset, handlerPos);
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj instanceof ExceptionHandler) {
ExceptionHandler that = (ExceptionHandler) obj;
if (this.pcOffset == that.pcOffset && this.handlerPos == that.handlerPos) {
return true;
}
}
return false;
}
}
/**
* Represents a mark in the machine code that can be used by the runtime for its own purposes. A
* mark can reference other marks.
*/
public static final class Mark extends Site {
public final Object id;
public Mark(int pcOffset, Object id) {
super(pcOffset);
this.id = id;
}
@Override
public String toString() {
if (id == null) {
return String.format("%d[<mar>]", pcOffset);
} else if (id instanceof Integer) {
return String.format("%d[<mark with id %s>]", pcOffset, Integer.toHexString((Integer) id));
} else {
return String.format("%d[<mark with id %s>]", pcOffset, id.toString());
}
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj instanceof Mark) {
Mark that = (Mark) obj;
if (this.pcOffset == that.pcOffset && Objects.equals(this.id, that.id)) {
return true;
}
}
return false;
}
}
private int id = -1;
/**
* Specifies whether this compilation is a {@code +ImmutableCode} {@code +GeneratePIC}
* compilation.
*/
private final boolean isImmutablePIC;
private int entryBCI = -1;
private final DataSection dataSection = new DataSection();
private final List<Infopoint> infopoints = new ArrayList<>();
private final List<DataPatch> dataPatches = new ArrayList<>();
private final List<ExceptionHandler> exceptionHandlers = new ArrayList<>();
private final List<Mark> marks = new ArrayList<>();
private int totalFrameSize = -1;
private int customStackAreaOffset = -1;
private final String name;
/**
* The buffer containing the emitted machine code.
*/
private byte[] targetCode;
/**
* The leading number of bytes in {@link #targetCode} containing the emitted machine code.
*/
private int targetCodeSize;
private ArrayList<CodeAnnotation> annotations;
private Assumption[] assumptions;
/**
* The list of the methods whose bytecodes were used as input to the compilation. If
* {@code null}, then the compilation did not record method dependencies. Otherwise, the first
* element of this array is the root method of the compilation.
*/
private ResolvedJavaMethod[] methods;
private int bytecodeSize;
private boolean hasUnsafeAccess;
public CompilationResult() {
this(null);
}
public CompilationResult(String name) {
this.name = name;
this.isImmutablePIC = false;
}
public CompilationResult(boolean isImmutablePIC) {
this.name = null;
this.isImmutablePIC = isImmutablePIC;
}
@Override
public int hashCode() {
// CompilationResult instances should not be used as hash map keys
throw new UnsupportedOperationException("hashCode");
}
@Override
public String toString() {
if (methods != null) {
return getClass().getName() + "[" + methods[0].format("%H.%n(%p)%r") + "]";
}
return identityHashCodeString(this);
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj != null && obj.getClass() == getClass()) {
CompilationResult that = (CompilationResult) obj;
// @formatter:off
if (this.entryBCI == that.entryBCI &&
this.id == that.id &&
this.customStackAreaOffset == that.customStackAreaOffset &&
this.totalFrameSize == that.totalFrameSize &&
this.targetCodeSize == that.targetCodeSize &&
Objects.equals(this.name, that.name) &&
Objects.equals(this.annotations, that.annotations) &&
Objects.equals(this.dataSection, that.dataSection) &&
Objects.equals(this.exceptionHandlers, that.exceptionHandlers) &&
Objects.equals(this.dataPatches, that.dataPatches) &&
Objects.equals(this.infopoints, that.infopoints) &&
Objects.equals(this.marks, that.marks) &&
Arrays.equals(this.assumptions, that.assumptions) &&
Arrays.equals(targetCode, that.targetCode)) {
return true;
}
// @formatter:on
}
return false;
}
/**
* @return the compile id
*/
public int getId() {
return id;
}
/**
* @param id the compile id to set
*/
public void setId(int id) {
this.id = id;
}
/**
* @return true is this is a {@code +ImmutableCode} {@code +GeneratePIC} compilation, false
* otherwise.
*/
public boolean isImmutablePIC() {
return isImmutablePIC;
}
/**
* @return the entryBCI
*/
public int getEntryBCI() {
return entryBCI;
}
/**
* @param entryBCI the entryBCI to set
*/
public void setEntryBCI(int entryBCI) {
this.entryBCI = entryBCI;
}
/**
* Sets the assumptions made during compilation.
*/
public void setAssumptions(Assumption[] assumptions) {
this.assumptions = assumptions;
}
/**
* Gets the assumptions made during compilation.
*/
public Assumption[] getAssumptions() {
return assumptions;
}
/**
* Sets the methods whose bytecodes were used as input to the compilation.
*
* @param rootMethod the root method of the compilation
* @param inlinedMethods the methods inlined during compilation
*/
public void setMethods(ResolvedJavaMethod rootMethod, Collection<ResolvedJavaMethod> inlinedMethods) {
assert rootMethod != null;
assert inlinedMethods != null;
if (inlinedMethods.contains(rootMethod)) {
methods = inlinedMethods.toArray(new ResolvedJavaMethod[inlinedMethods.size()]);
for (int i = 0; i < methods.length; i++) {
if (methods[i].equals(rootMethod)) {
if (i != 0) {
ResolvedJavaMethod tmp = methods[0];
methods[0] = methods[i];
methods[i] = tmp;
}
break;
}
}
} else {
methods = new ResolvedJavaMethod[1 + inlinedMethods.size()];
methods[0] = rootMethod;
int i = 1;
for (ResolvedJavaMethod m : inlinedMethods) {
methods[i++] = m;
}
}
}
/**
* Gets the methods whose bytecodes were used as input to the compilation.
*
* @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
*/
public ResolvedJavaMethod[] getMethods() {
return methods;
}
public void setBytecodeSize(int bytecodeSize) {
this.bytecodeSize = bytecodeSize;
}
public int getBytecodeSize() {
return bytecodeSize;
}
public DataSection getDataSection() {
return dataSection;
}
/**
* The total frame size of the method in bytes. This includes the return address pushed onto the
* stack, if any.
*
* @return the frame size
*/
public int getTotalFrameSize() {
assert totalFrameSize != -1 : "frame size not yet initialized!";
return totalFrameSize;
}
/**
* Sets the total frame size in bytes. This includes the return address pushed onto the stack,
* if any.
*
* @param size the size of the frame in bytes
*/
public void setTotalFrameSize(int size) {
totalFrameSize = size;
}
/**
* Sets the machine that has been generated by the compiler.
*
* @param code the machine code generated
* @param size the size of the machine code
*/
public void setTargetCode(byte[] code, int size) {
targetCode = code;
targetCodeSize = size;
}
/**
* Records a data patch in the code section. The data patch can refer to something in the
* {@link DataSectionReference data section} or directly to an {@link ConstantReference inlined
* constant}.
*
* @param codePos The position in the code that needs to be patched.
* @param ref The reference that should be inserted in the code.
*/
public void recordDataPatch(int codePos, Reference ref) {
assert codePos >= 0 && ref != null;
dataPatches.add(new DataPatch(codePos, ref));
}
/**
* Records a data patch in the code section. The data patch can refer to something in the
* {@link DataSectionReference data section} or directly to an {@link ConstantReference inlined
* constant}.
*
* @param codePos The position in the code that needs to be patched.
* @param ref The reference that should be inserted in the code.
* @param note The note attached to data patch for use by post-processing tools
*/
public void recordDataPatchWithNote(int codePos, Reference ref, Object note) {
assert codePos >= 0 && ref != null;
dataPatches.add(new DataPatch(codePos, ref, note));
}
/**
* Records metaspace access.
*/
public void recordMetaspaceAccess(Object reference, int instructionSize, MetaSpaceAccessType type, int codePos, DebugInfo debugInfo) {
final MetaSpaceAccess metaspace = new MetaSpaceAccess(reference, instructionSize, type, codePos, debugInfo);
addInfopoint(metaspace);
}
/**
* Records a call in the code array.
*
* @param codePos the position of the call in the code array
* @param size the size of the call instruction
* @param target the being called
* @param debugInfo the debug info for the call
* @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) {
final Call call = new Call(target, codePos, size, direct, debugInfo);
addInfopoint(call);
}
/**
* Records an exception handler for this method.
*
* @param codePos the position in the code that is covered by the handler
* @param handlerPos the position of the handler
*/
public void recordExceptionHandler(int codePos, int handlerPos) {
assert validateExceptionHandlerAdd(codePos, handlerPos) : String.format("Duplicate exception handler for pc 0x%x handlerPos 0x%x", codePos, handlerPos);
exceptionHandlers.add(new ExceptionHandler(codePos, handlerPos));
}
/**
* Validate if the exception handler for codePos already exists and handlerPos is different.
*
* @param codePos
* @param handlerPos
* @return true if the validation is successful
*/
private boolean validateExceptionHandlerAdd(int codePos, int handlerPos) {
ExceptionHandler exHandler = getExceptionHandlerForCodePos(codePos);
return exHandler == null || exHandler.handlerPos == handlerPos;
}
/**
* Returns the first ExceptionHandler which matches codePos.
*
* @param codePos position to search for
* @return first matching ExceptionHandler
*/
private ExceptionHandler getExceptionHandlerForCodePos(int codePos) {
for (ExceptionHandler h : exceptionHandlers) {
if (h.pcOffset == codePos) {
return h;
}
}
return null;
}
/**
* Records an infopoint in the code array.
*
* @param codePos the position of the infopoint in the code array
* @param debugInfo the debug info for the infopoint
*/
public void recordInfopoint(int codePos, DebugInfo debugInfo, InfopointReason reason) {
addInfopoint(new Infopoint(codePos, debugInfo, reason));
}
/**
* Records a custom infopoint in the code section.
*
* Compiler implementations can use this method to record non-standard infopoints, which are not
* handled by the dedicated methods like {@link #recordCall}.
*
* @param infopoint the infopoint to record, usually a derived class from {@link Infopoint}
*/
public void addInfopoint(Infopoint infopoint) {
// The infopoints list must always be sorted
if (!infopoints.isEmpty()) {
Infopoint previousInfopoint = infopoints.get(infopoints.size() - 1);
if (previousInfopoint.pcOffset > infopoint.pcOffset) {
// This re-sorting should be very rare
Collections.sort(infopoints);
previousInfopoint = infopoints.get(infopoints.size() - 1);
}
if (previousInfopoint.pcOffset == infopoint.pcOffset) {
if (infopoint.reason.canBeOmitted()) {
return;
}
if (previousInfopoint.reason.canBeOmitted()) {
Infopoint removed = infopoints.remove(infopoints.size() - 1);
assert removed == previousInfopoint;
} else {
throw new RuntimeException("Infopoints that can not be omited should have distinct PCs");
}
}
}
infopoints.add(infopoint);
}
/**
* Records an instruction mark within this method.
*
* @param codePos the position in the code that is covered by the handler
* @param markId the identifier for this mark
*/
public Mark recordMark(int codePos, Object markId) {
Mark mark = new Mark(codePos, markId);
marks.add(mark);
return mark;
}
/**
* Offset in bytes for the custom stack area (relative to sp).
*
* @return the offset in bytes
*/
public int getCustomStackAreaOffset() {
return customStackAreaOffset;
}
/**
* @see #getCustomStackAreaOffset()
* @param offset
*/
public void setCustomStackAreaOffset(int offset) {
customStackAreaOffset = offset;
}
/**
* @return the machine code generated for this method
*/
public byte[] getTargetCode() {
return targetCode;
}
/**
* @return the size of the machine code generated for this method
*/
public int getTargetCodeSize() {
return targetCodeSize;
}
/**
* @return the code annotations or {@code null} if there are none
*/
public List<CodeAnnotation> getAnnotations() {
if (annotations == null) {
return Collections.emptyList();
}
return annotations;
}
public void addAnnotation(CodeAnnotation annotation) {
assert annotation != null;
if (annotations == null) {
annotations = new ArrayList<>();
}
annotations.add(annotation);
}
private static void appendDebugInfo(StringBuilder sb, DebugInfo info) {
if (info != null) {
ReferenceMap refMap = info.getReferenceMap();
if (refMap != null) {
sb.append(refMap.toString());
sb.append(']');
}
RegisterSaveLayout calleeSaveInfo = info.getCalleeSaveInfo();
if (calleeSaveInfo != null) {
sb.append(" callee-save-info[");
String sep = "";
for (Map.Entry<Register, Integer> e : calleeSaveInfo.registersToSlots(true).entrySet()) {
sb.append(sep).append(e.getKey()).append("->").append(e.getValue());
sep = ", ";
}
sb.append(']');
}
BytecodePosition codePos = info.getBytecodePosition();
if (codePos != null) {
MetaUtil.appendLocation(sb.append(" "), codePos.getMethod(), codePos.getBCI());
if (info.hasFrame()) {
sb.append(" #locals=").append(info.frame().numLocals).append(" #expr=").append(info.frame().numStack);
if (info.frame().numLocks > 0) {
sb.append(" #locks=").append(info.frame().numLocks);
}
}
}
}
}
/**
* @return the list of infopoints, sorted by {@link Site#pcOffset}
*/
public List<Infopoint> getInfopoints() {
if (infopoints.isEmpty()) {
return emptyList();
}
return unmodifiableList(infopoints);
}
/**
* @return the list of data references
*/
public List<DataPatch> getDataPatches() {
if (dataPatches.isEmpty()) {
return emptyList();
}
return unmodifiableList(dataPatches);
}
/**
* @return the list of exception handlers
*/
public List<ExceptionHandler> getExceptionHandlers() {
if (exceptionHandlers.isEmpty()) {
return emptyList();
}
return unmodifiableList(exceptionHandlers);
}
/**
* @return the list of marks
*/
public List<Mark> getMarks() {
if (marks.isEmpty()) {
return emptyList();
}
return unmodifiableList(marks);
}
public String getName() {
return name;
}
public void setHasUnsafeAccess(boolean hasUnsafeAccess) {
this.hasUnsafeAccess = hasUnsafeAccess;
}
public boolean hasUnsafeAccess() {
return hasUnsafeAccess;
}
public void reset() {
hasUnsafeAccess = false;
infopoints.clear();
dataPatches.clear();
exceptionHandlers.clear();
marks.clear();
dataSection.clear();
if (annotations != null) {
annotations.clear();
}
}
}