/** Adds a use, if not already present, without propagating state. */ public boolean addOriginalUse(BigBang bb, TypeFlow<?> use) { return addUse(bb, use, false, false); }
@SuppressWarnings("unchecked") public <T extends TypeFlow<?>> T lookupCloneOf(BigBang bb, T original) { assert original != null && !original.isClone(); assert !(original instanceof FieldTypeFlow) : "Trying to clone a field type flow"; assert !(original instanceof ArrayElementsTypeFlow) : "Trying to clone an mixed elements type flow"; if (original instanceof AllInstantiatedTypeFlow || original instanceof AllSynchronizedTypeFlow) { /* All instantiated is not cloneable. */ return original; } int slot = original.getSlot(); assert slot >= 0 && slot < linearizedGraph.length : "Slot index out of bounds " + slot + " : " + original + " [" + original.getSource() + "]"; TypeFlow<?> clone = linearizedGraph[slot]; if (clone == null) { if (sealed) { shouldNotReachHere("Trying to create a clone after the method flows have been sealed."); } // copy only makes a shallow copy of the original flows; // it does not copy it's uses or inputs (for those flows that have inputs) clone = original.copy(bb, this); assert slot == clone.getSlot(); assert linearizedGraph[slot] == null : "Clone already exists: " + slot + " : " + original; linearizedGraph[slot] = clone; } return (T) clone; }
public void update(BigBang bb) { TypeState curState = getState(); for (TypeFlow<?> use : getUses()) { use.addState(bb, curState); } notifyObservers(bb); }
private static void updateFlow(BigBang bb, TypeFlow<?> flow, TypeState newState, List<TypeFlow<?>> changedFlows) { if (!flow.getState().equals(newState)) { flow.setState(bb, newState); if (changedFlows != null && (flow.getUses().size() > 0 || flow.getObservers().size() > 0)) { changedFlows.add(flow); } } }
clone.initClone(bb); for (TypeFlow<?> originalObserver : original.getObservers()) { assert !(originalObserver.isClone()); clone.addObserver(bb, originalObserver); } else if (crossMethodUse(original, originalObserver)) { clone.addObserver(bb, clonedObserver); for (TypeFlow<?> originalUse : original.getUses()) { assert !(originalUse.isClone()); clone.addUse(bb, originalUse); } else if (crossMethodUse(original, originalUse)) { clone.addUse(bb, clonedUse);
private static void reportTypeFlowStats(BufferedWriter out) { doWrite(out, String.format("%-35s\t%-10s\t%-10s\t%-10s\t%-10s\t%-10s\t%-10s\t%-10s\t%-10s\t%-10s\t%-10s\t%-10s\t%10s\n", "TypeFlow", "TypeStateID", "StateObjects#", "CanBeNull", "IsClone", "Uses", "Observers", "Uses+Observers", "RetainReason", "QueuedUpdates", "AllUpdates", "TypeStateAdds", "All Updates History (<update frequency>x<type state id>)")); typeFlowStats.entrySet().stream() .forEach(e -> { TypeFlow<?> flow = e.getKey(); TypeFlowStats stats = e.getValue(); doWrite(out, String.format("%-35s\t%-10d\t%-10d\t%-10b\t%-10b\t%-10d\t%-10d\t%-10d\t%-10s\t%-10d\t%10d\t%10d\t%10s\n", asString(flow), stateToId.get(flow.getState()), objectsCount(flow.getState()), flow.getState().canBeNull(), flow.isClone(), flow.getUses().size(), flow.getObservers().size(), flow.getUses().size() + flow.getObservers().size(), retainReson.getOrDefault(flow, ""), stats.queuedUpdatesCount(), stats.successfulUpdatesCount(), stats.allUpdatesCount(), stats.allUpdatesHistory())); }); }
@Override public void onObservedUpdate(BigBang bb) { /* Only a clone should be updated */ assert this.isClone(); TypeState arrayState = getObjectState(); if (arrayState.isUnknown()) { bb.reportIllegalUnknownUse(graphRef.getMethod(), source, "Illegal: Index loading from UnknownTypeState. Load: " + source); return; } for (AnalysisObject object : arrayState.objects()) { if (object.isPrimitiveArray() || object.isEmptyObjectArrayConstant(bb)) { /* Nothing to read from a primitive array or an empty array constant. */ continue; } /* Add the indexed load flow as a use to the elements flow. */ TypeFlow<?> elementsFlow = object.getArrayElementsFlow(bb, false); if (elementsFlow.getState().isUnknown()) { bb.getUnsupportedFeatures().addMessage(graphRef.getMethod().format("%H.%n(%p)"), graphRef.getMethod(), "Illegal: Index loading UnknownTypeState from array. Store: " + this.getSource()); return; } elementsFlow.addUse(bb, this); } }
/** * Shallow copy constructor. Does not copy the flows or the state. * * @param original the original flow * @param graphRef the holder method clone */ public TypeFlow(TypeFlow<T> original, MethodFlowsGraph graphRef) { this(original.getSource(), original.getDeclaredType(), TypeState.forEmpty(), original.getSlot(), true, graphRef); this.usedAsAParameter = original.usedAsAParameter; this.usedAsAReceiver = original.usedAsAReceiver; PointsToStats.registerTypeFlowRetainReason(this, original); }
private void add(TypeFlow<?> flow, WorkListEntry reason) { if (processed.contains(flow)) { return; } processed.add(flow); WorkListEntry entry = new WorkListEntry(flow, reason); worklist.add(entry); if (!flow.isClone() && flow.getSource() instanceof ValueNode) { AnalysisMethod method = (AnalysisMethod) ((ValueNode) flow.getSource()).graph().method(); for (MethodFlowsGraph methodFlow : method.getTypeFlow().getMethodContextFlows().values()) { TypeFlow<?> curClone = methodFlow.lookupCloneOf(bb, flow); add(curClone, entry); } } } }
private static String formatSource(TypeFlow<?> flow) { Object source = flow.getSource(); if (source instanceof ValueNode) { ValueNode node = (ValueNode) source; NodeSourcePosition nodeSource = node.getNodeSourcePosition(); if (nodeSource != null) { return formatMethod(nodeSource.getMethod()) + ":" + nodeSource.getBCI(); } else if (flow.graphRef() != null) { return formatMethod(flow.graphRef().getMethod()); } else { return "<unknown-source>"; } } else if (source instanceof AnalysisType) { return formatType((AnalysisType) source); } else if (source instanceof AnalysisField) { return formatField((AnalysisField) source); } else if (source == null) { return "<no-source>"; } else { return source.getClass().getSimpleName(); } }
public AnalysisMethod method() { return super.getSource(); }
protected boolean doAddObserver(BigBang bb, TypeFlow<?> observer, boolean registerObservees) { if (observer.equals(this)) { return false; } if (bb.trackTypeFlowInputs() || registerObservees) { observer.addObservee(this); } return observers.addElement(observer); }
private boolean checkUsages() { for (TypeFlow<?> use : getUses()) { assert !use.isClone() || use instanceof ProxyTypeFlow || use instanceof SourceTypeFlowBase || use instanceof DynamicNewInstanceTypeFlow || use instanceof FilterTypeFlow || use instanceof ActualReturnTypeFlow : use.getClass(); } return true; }
public final void finish() { while (!worklist.isEmpty()) { WorkListEntry entry = worklist.removeFirst(); if (process(entry.flow)) { for (TypeFlow<?> use : entry.flow.getUses()) { add(use, entry); } } } }
useFlow.addOriginalUse(bb, flow); observerFlow.addOriginalObserver(bb, flow);
@Override public void initClone(BigBang bb) { /* When the clone is linked check if the all-instantiated contains the source state type. */ if (sourceState.isNull() || sourceState.isEmpty() || bb.getAllInstantiatedTypeFlow().getState().containsType(sourceState.exactType())) { /* If yes, set the state and propagate it to uses. */ addState(bb, sourceState); } else { /* * If no, update the can-be-null state of the source flow and register it as an observer * for all-instantiated. */ addState(bb, sourceState.canBeNull() ? TypeState.forNull() : TypeState.forEmpty()); bb.getAllInstantiatedTypeFlow().addObserver(bb, this); } }
/** Adds an observer, if not already present, without triggering update. */ public boolean addOriginalObserver(BigBang bb, TypeFlow<?> observer) { return addObserver(bb, observer, false, false); }
returnTypeFlow = new ProxyTypeFlow(null, returnTypeFlow); FormalReturnTypeFlow resultFlow = new FormalReturnTypeFlow(null, returnType, method); returnTypeFlow.addOriginalUse(this.bb, resultFlow); methodFlow.addMiscEntry(returnTypeFlow); methodFlow.setResult(resultFlow);