692 lines
25 KiB
Java
692 lines
25 KiB
Java
/*
|
|
* This program and the accompanying materials
|
|
* are made available under the terms of the Eclipse Public License v1.0
|
|
* which accompanies this distribution, and is available at
|
|
* http://www.eclipse.org/legal/epl-v10.html.
|
|
*
|
|
* This file is a derivative of code released under the terms listed below.
|
|
*
|
|
*/
|
|
/*
|
|
* Copyright (c) 2013,
|
|
* Tobias Blaschke <code@tobiasblaschke.de>
|
|
* All rights reserved.
|
|
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions are met:
|
|
*
|
|
* 1. Redistributions of source code must retain the above copyright notice,
|
|
* this list of conditions and the following disclaimer.
|
|
*
|
|
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
|
* this list of conditions and the following disclaimer in the documentation
|
|
* and/or other materials provided with the distribution.
|
|
*
|
|
* 3. The names of the contributors may not be used to endorse or promote
|
|
* products derived from this software without specific prior written
|
|
* permission.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
|
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
* POSSIBILITY OF SUCH DAMAGE.
|
|
*/
|
|
package com.ibm.wala.dalvik.ipa.callgraph.androidModel.parameters;
|
|
|
|
import java.util.ArrayList;
|
|
import java.util.HashMap;
|
|
import java.util.List;
|
|
import java.util.Map;
|
|
import java.util.logging.Logger;
|
|
|
|
import com.ibm.wala.ssa.SSAInstruction;
|
|
import com.ibm.wala.types.MethodReference;
|
|
import com.ibm.wala.types.TypeReference;
|
|
import com.ibm.wala.util.ssa.ParameterAccessor;
|
|
import com.ibm.wala.util.ssa.SSAValue;
|
|
|
|
/**
|
|
* Manages SSA-Numbers for the arguments to Entrypoints.
|
|
*
|
|
* This class comes in handy if you want to use loops or mix a return value of a function into the
|
|
* parameter of a later function. It supports multiple levels of cascading code blocks and delivers
|
|
* information which SSA-Value is the latest to use or which aught to be combined using a Phi-Statement.
|
|
* <p>
|
|
* However it does no allocations or Phi-Statements on its own. It just juggles with the numbers.
|
|
*
|
|
* @see com.ibm.wala.dalvik.ipa.callgraph.androidModel.structure.AbstractAndroidModel
|
|
* @see com.ibm.wala.dalvik.ipa.callgraph.impl.DexFakeRootMethod
|
|
*
|
|
* @author Tobias Blaschke <code@toiasblaschke.de>
|
|
* @since 2013-09-19
|
|
*
|
|
* TODO:
|
|
* @todo Track if a variable has been refered to to be able to prune unused Phi-Instructions later
|
|
* @todo Trim Memory consumption? The whole class should not be in memory for long time so this
|
|
* might be not neccessary.
|
|
*/
|
|
public class AndroidModelParameterManager {
|
|
|
|
private enum ValueStatus {
|
|
UNUSED, /** Value has never been mentioned before */
|
|
UNALLOCATED, /** Awaiting to be set using setAllocation */
|
|
ALLOCATED, /** Set and ready to use */
|
|
FREE, /** Has to be assigned using a Phi-Instruction */
|
|
INVALIDATED, /** Should only be used as argument to a Phi Instruction */
|
|
CLOSED, /** Should not be referenced any more */
|
|
FREE_INVALIDATED, /** Well FREE and INVALIDATED */
|
|
FREE_CLOSED /** Well FREE and CLOSED */
|
|
}
|
|
|
|
// TODO: nextLocal may be 0 on getUnamanged!
|
|
/** The next variable not under management yet */
|
|
private int nextLocal;
|
|
/** for managing cascaded code blocks */
|
|
private int currentScope = 0;
|
|
/** For checking if type is CREATE or REUSE (optional) */
|
|
private IInstantiationBehavior behaviour = null;
|
|
/** Description only used for toString() */
|
|
private String description;
|
|
// private MethodReference forMethod;
|
|
|
|
/**
|
|
* Representing a ssa-number - thus a version of an instance to a type.
|
|
*/
|
|
private static class ManagedParameter {
|
|
public ValueStatus status = ValueStatus.UNUSED;
|
|
public TypeReference type = null;
|
|
public int ssa = -1;
|
|
// public SSAInstruction setBy = null;
|
|
public int setInScope = -1;
|
|
}
|
|
|
|
/** The main data-structure of the management */
|
|
private Map<TypeReference, List<ManagedParameter>> seenTypes = new HashMap<TypeReference, List<ManagedParameter>>();
|
|
|
|
/**
|
|
* Setting the behaviour may be handy in the later model.
|
|
*
|
|
* However it brings no benefit to the AndroidModelParameterManager.
|
|
*/
|
|
public AndroidModelParameterManager(IInstantiationBehavior behaviour) {
|
|
this.behaviour = behaviour;
|
|
this.description = " based on behaviours of " + behaviour;
|
|
// this.forMethod = null; // XXX
|
|
}
|
|
|
|
public AndroidModelParameterManager(MethodReference mRef, boolean isStatic) {
|
|
this(new ParameterAccessor(mRef, isStatic));
|
|
this.description = " based on MethodReference " + mRef;
|
|
// this.forMethod = mRef;
|
|
}
|
|
|
|
public AndroidModelParameterManager(ParameterAccessor acc) {
|
|
this.behaviour = null;
|
|
nextLocal = acc.getFirstAfter();
|
|
|
|
/*
|
|
for (Parameter param: acc.all()) {
|
|
setAllocation(param.getType(), param.getNumber());
|
|
}*/
|
|
|
|
this.description = " based on ParameterAccessor " + acc;
|
|
// this.forMethod = acc.forMethod();
|
|
}
|
|
|
|
//public AndroidModelParameterManager() {
|
|
// this.behaviour = null;
|
|
//}
|
|
|
|
/*
|
|
public void readDescriptior(Descriptor forMethod) {
|
|
for (int i=0; i < forMethod.getParameters().length; ++i) {
|
|
setAllocation(forMethod.getParameters()[i], i + 1);
|
|
}
|
|
}*/
|
|
|
|
/**
|
|
* Register a variable _after_ allocation.
|
|
*
|
|
* The proper way to add an allocation is to get a Variable using {@link #getUnallocated}. Then
|
|
* assign it a value. And at last call this function.
|
|
*
|
|
* You can however directly call the function if the type has not been seen before.
|
|
*
|
|
* @param type The type allocated
|
|
* @param ssaValue an unallocated SSA-Variable to assign the allocation to
|
|
* @param setBy The instruction that set the value
|
|
* @throws IllegalStateException if you set more than one allocation for that type (TODO better check!)
|
|
* @throws IllegalArgumentException if type is null or ssaValue is zero or negative
|
|
*/
|
|
public void setAllocation(TypeReference type, int ssaValue, SSAInstruction setBy) {
|
|
if (type == null) {
|
|
throw new IllegalArgumentException("The argument type may not be null");
|
|
}
|
|
if (ssaValue <= 0) {
|
|
throw new IllegalArgumentException("The SSA-Variable may not be zero or negative.");
|
|
}
|
|
|
|
if (seenTypes.containsKey(type)) {
|
|
for (ManagedParameter param : seenTypes.get(type)) {
|
|
if (param.status == ValueStatus.UNALLOCATED) {
|
|
// XXX: Allow more?
|
|
assert (param.type.equals(type)) : "Inequal types";
|
|
|
|
if ((ssaValue + 1) > nextLocal) {
|
|
nextLocal = ssaValue + 1;
|
|
}
|
|
|
|
|
|
param.status = ValueStatus.ALLOCATED;
|
|
param.ssa = ssaValue;
|
|
param.setInScope = currentScope;
|
|
// param.setBy = setBy;
|
|
|
|
return;
|
|
} else {
|
|
continue;
|
|
}
|
|
}
|
|
throw new IllegalStateException("The parameter " + type.getName() + " has already been allocated!");
|
|
} else {
|
|
ManagedParameter param = new ManagedParameter();
|
|
param.status = ValueStatus.ALLOCATED;
|
|
param.type = type;
|
|
param.ssa = ssaValue;
|
|
if ((ssaValue + 1) > nextLocal) {
|
|
nextLocal = ssaValue + 1;
|
|
}
|
|
param.setInScope = currentScope;
|
|
|
|
List<ManagedParameter> aParam = new ArrayList<ManagedParameter>();
|
|
aParam.add(param);
|
|
|
|
|
|
seenTypes.put(type, aParam);
|
|
return;
|
|
}
|
|
}
|
|
|
|
public void setAllocation(TypeReference type, int ssaValue) {
|
|
setAllocation(type, ssaValue, null);
|
|
}
|
|
|
|
public void setAllocation(SSAValue val) {
|
|
setAllocation(val.getType(), val.getNumber(), null);
|
|
}
|
|
|
|
/**
|
|
* Register a Phi-Instruction _after_ added to the model.
|
|
*
|
|
* @param type the type the Phi-Instruction sets
|
|
* @param ssaValue the number the SSA-Instruction assignes to
|
|
* @param setBy the Phi-Instruction itself - may be null
|
|
* @throws IllegalArgumentException if you assign to a number requested using
|
|
* {@link #getFree(TypeReference)} but types mismach.
|
|
* @throws IllegalStateException if you forgot to close some Phis
|
|
*/
|
|
public void setPhi(TypeReference type, int ssaValue, SSAInstruction setBy) {
|
|
if (type == null) {
|
|
throw new IllegalArgumentException("The argument type may not be null");
|
|
}
|
|
if (ssaValue <= 0) {
|
|
throw new IllegalArgumentException("The SSA-Variable may not be zero or negative.");
|
|
}
|
|
|
|
boolean didPhi = false;
|
|
|
|
if (seenTypes.containsKey(type)) {
|
|
for (ManagedParameter param : seenTypes.get(type)) {
|
|
if ((param.status == ValueStatus.FREE) ||
|
|
(param.status == ValueStatus.FREE_INVALIDATED) ||
|
|
(param.status == ValueStatus.FREE_CLOSED)) {
|
|
// XXX: Allow more?
|
|
assert (param.type.equals(type)) : "Inequal types";
|
|
if (param.ssa != ssaValue) {
|
|
if ((param.status == ValueStatus.FREE) &&
|
|
(param.setInScope == currentScope)) {
|
|
param.status = ValueStatus.FREE_CLOSED;
|
|
}
|
|
continue;
|
|
}
|
|
|
|
if (param.status == ValueStatus.FREE) {
|
|
param.status = ValueStatus.ALLOCATED;
|
|
} else if (param.status == ValueStatus.FREE_INVALIDATED) {
|
|
param.status = ValueStatus.INVALIDATED;
|
|
} else if (param.status == ValueStatus.FREE_CLOSED) {
|
|
param.status = ValueStatus.CLOSED;
|
|
}
|
|
param.setInScope = currentScope;
|
|
// param.setBy = setBy;
|
|
|
|
didPhi = true;
|
|
} else if (param.setInScope == currentScope) {
|
|
if (param.status == ValueStatus.INVALIDATED) {
|
|
|
|
param.status = ValueStatus.CLOSED;
|
|
} else if (param.status == ValueStatus.FREE_INVALIDATED) { // TODO: FREE CLOSED
|
|
|
|
param.status = ValueStatus.FREE_CLOSED;
|
|
}
|
|
} else if (param.setInScope < currentScope) {
|
|
//param.status = ValueStatus.INVALIDATED;
|
|
} else {
|
|
// TODO: NO! I JUST WANTED TO ADD THEM! *grrr*
|
|
//logger.error("MISSING PHI for "
|
|
//throw new IllegalStateException("You forgot Phis in subordinate blocks");
|
|
}
|
|
}
|
|
assert (didPhi);
|
|
return;
|
|
} else {
|
|
ManagedParameter param = new ManagedParameter();
|
|
param.status = ValueStatus.ALLOCATED;
|
|
param.type = type;
|
|
param.setInScope = currentScope;
|
|
param.ssa = ssaValue;
|
|
if ((ssaValue + 1) > nextLocal) {
|
|
nextLocal = ssaValue + 1;
|
|
}
|
|
|
|
|
|
List<ManagedParameter> aParam = new ArrayList<ManagedParameter>();
|
|
aParam.add(param);
|
|
|
|
seenTypes.put(type, aParam);
|
|
return;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Returns and registers a free SSA-Number to a Type.
|
|
*
|
|
* You have to set the type using a Phi-Instruction. Also you don't have to add
|
|
* that instruction immediatly it is required that it is added before the Model
|
|
* gets finished.
|
|
*
|
|
* You can request the List of unmet Phi-Instructions by using XXX
|
|
*
|
|
* @return an unused SSA-Number
|
|
* @throws IllegalArgumentException if type is null
|
|
*/
|
|
public int getFree(TypeReference type) {
|
|
if (type == null) {
|
|
throw new IllegalArgumentException("The argument type may not be null");
|
|
}
|
|
|
|
ManagedParameter param = new ManagedParameter();
|
|
param.status = ValueStatus.FREE;
|
|
param.type = type;
|
|
param.ssa = nextLocal++;
|
|
param.setInScope = currentScope;
|
|
|
|
if (seenTypes.containsKey(type)) {
|
|
seenTypes.get(type).add(param);
|
|
} else {
|
|
List<ManagedParameter> aParam = new ArrayList<ManagedParameter>();
|
|
aParam.add(param);
|
|
|
|
seenTypes.put(type, aParam);
|
|
}
|
|
|
|
|
|
return param.ssa;
|
|
}
|
|
|
|
/**
|
|
* Get an unused number to assign to.
|
|
*
|
|
* There may only be one unallocated value for each type at a time. XXX: Really?
|
|
*
|
|
* @return SSA-Variable
|
|
* @throws IllegalStateException if there is already an unallocated variable of that type
|
|
* @throws IllegalArgumentException if type is null
|
|
*/
|
|
public int getUnallocated(TypeReference type) {
|
|
if (type == null) {
|
|
throw new IllegalArgumentException("The argument type may not be null");
|
|
}
|
|
|
|
if (seenTypes.containsKey(type)) {
|
|
for (ManagedParameter p : seenTypes.get(type)) {
|
|
if (p.status == ValueStatus.UNALLOCATED) {
|
|
throw new IllegalStateException("There may be only one unallocated instance to a type (" + type +
|
|
") at a time" );
|
|
}
|
|
}
|
|
}
|
|
|
|
ManagedParameter param = new ManagedParameter();
|
|
param.status = ValueStatus.UNALLOCATED;
|
|
param.type = type;
|
|
param.ssa = nextLocal++;
|
|
param.setInScope = currentScope;
|
|
|
|
if (seenTypes.containsKey(type)) {
|
|
seenTypes.get(type).add(param);
|
|
} else {
|
|
List<ManagedParameter> aParam = new ArrayList<ManagedParameter>();
|
|
aParam.add(param);
|
|
|
|
seenTypes.put(type, aParam);
|
|
}
|
|
|
|
|
|
return param.ssa;
|
|
}
|
|
|
|
/**
|
|
* Retreive a SSA-Value that is not under management.
|
|
*
|
|
* Use instead of 'nextLocal++', else SSA-Values will clash!
|
|
*
|
|
* @return SSA-Variable
|
|
*/
|
|
public int getUnmanaged() {
|
|
int ret = nextLocal++;
|
|
return ret;
|
|
}
|
|
|
|
/**
|
|
* Retreive the SSA-Number that is valid for a type in the current scope.
|
|
*
|
|
* Either that number origins from an allocation or a PhiInstruction (to be).
|
|
*
|
|
* @return a ssa number
|
|
* @throws IllegalStateException if no number is assignable
|
|
* @throws IllegalArgumentException if type was not seen before or is null
|
|
*/
|
|
public int getCurrent(TypeReference type) {
|
|
if (type == null) {
|
|
throw new IllegalArgumentException("The argument type may not be null");
|
|
}
|
|
|
|
int candidateSSA = -1;
|
|
int candidateScope = -1;
|
|
|
|
if (seenTypes.containsKey(type)) {
|
|
for (ManagedParameter param : seenTypes.get(type)) {
|
|
if ((param.status == ValueStatus.FREE) ||
|
|
(param.status == ValueStatus.ALLOCATED)) {
|
|
assert (param.type.equals(type)) : "Inequal types";
|
|
if (param.setInScope > currentScope) {
|
|
|
|
continue;
|
|
} else if (param.setInScope == currentScope) {
|
|
|
|
return param.ssa;
|
|
} else {
|
|
if (param.setInScope > candidateScope) {
|
|
candidateScope = param.setInScope;
|
|
candidateSSA = param.ssa;
|
|
}
|
|
}
|
|
} else {
|
|
|
|
}
|
|
}
|
|
} else {
|
|
throw new IllegalArgumentException("Type " + type + " has never been seen before!");
|
|
}
|
|
|
|
if (candidateSSA < 0 ) {
|
|
|
|
return candidateSSA;
|
|
} else {
|
|
throw new IllegalStateException("No suitable candidate has been found for " + type.getName());
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Retreive the SSA-Number that is valid for a type in the super-ordinate scope.
|
|
*
|
|
* Either that number origins from an allocation or a PhiInstruction (to be).
|
|
*
|
|
* @return a ssa number
|
|
* @throws IllegalStateException if no number is assignable
|
|
* @throws IllegalArgumentException if type was not seen before or is null
|
|
*/
|
|
public int getSuper(TypeReference type) {
|
|
if (type == null) {
|
|
throw new IllegalArgumentException("The argument type may not be null");
|
|
}
|
|
|
|
int ssa;
|
|
currentScope--;
|
|
assert(currentScope >= 0 );
|
|
ssa = getCurrent(type);
|
|
currentScope++;
|
|
return ssa;
|
|
}
|
|
|
|
/**
|
|
*
|
|
* @throws IllegalArgumentException if type was not seen before or is null
|
|
*/
|
|
public List<Integer> getAllForPhi(TypeReference type) {
|
|
if (type == null) {
|
|
throw new IllegalArgumentException("The argument type may not be null");
|
|
}
|
|
|
|
List<Integer> ret = new ArrayList<Integer>();
|
|
|
|
if (seenTypes.containsKey(type)) {
|
|
for (ManagedParameter param : seenTypes.get(type)) {
|
|
if ((param.status == ValueStatus.FREE) ||
|
|
(param.status == ValueStatus.ALLOCATED)) {
|
|
assert (param.type.equals(type)) : "Inequal types";
|
|
|
|
ret.add(param.ssa);
|
|
} else if ((param.status == ValueStatus.INVALIDATED) &&
|
|
param.setInScope > currentScope) {
|
|
|
|
ret.add(param.ssa);
|
|
}
|
|
}
|
|
} else {
|
|
throw new IllegalArgumentException("Type " + type + " has never been seen before!");
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
/**
|
|
* Return if the type is managed by this class.
|
|
*
|
|
* @param withSuper when true return true if a managed key may be cast to type,
|
|
* when false type has to match exactly
|
|
* @param type the type in question
|
|
* @throws IllegalArgumentException if type is null
|
|
*/
|
|
public boolean isSeen(TypeReference type, boolean withSuper) {
|
|
if (type == null) {
|
|
throw new IllegalArgumentException("The argument type may not be null");
|
|
}
|
|
|
|
if (withSuper) {
|
|
return seenTypes.containsKey(type);
|
|
} else {
|
|
if (seenTypes.containsKey(type)) {
|
|
if (seenTypes.get(type).get(0).type.equals(type)) {
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
|
|
}
|
|
}
|
|
|
|
public boolean isSeen(TypeReference type) {
|
|
return isSeen(type, true);
|
|
}
|
|
|
|
/**
|
|
* Returns if an instance for that type needs to be allocated.
|
|
*
|
|
* However this function does not respect weather a PhiInstruction is
|
|
* needed.
|
|
*
|
|
* @throws IllegalArgumentException if type is null
|
|
*/
|
|
public boolean needsAllocation(TypeReference type) {
|
|
if (type == null) {
|
|
throw new IllegalArgumentException("The argument type may not be null");
|
|
}
|
|
|
|
if (seenTypes.containsKey(type)) {
|
|
if (seenTypes.get(type).size() > 1) { // TODO INCORRECT may all be UNALLOCATED
|
|
return false;
|
|
} else {
|
|
return (seenTypes.get(type).get(0).status == ValueStatus.UNALLOCATED);
|
|
}
|
|
} else {
|
|
return true;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Returns if a PhiInstruction (still) has to be added.
|
|
*
|
|
* This is true if the Value has changed in a deeper scope, has been invalidated
|
|
* or requested using getFree
|
|
*
|
|
* @throws IllegalArgumentException if type is null or has not been seen before
|
|
*/
|
|
public boolean needsPhi(TypeReference type) {
|
|
if (type == null) {
|
|
throw new IllegalArgumentException("The argument type may not be null");
|
|
}
|
|
|
|
boolean seenLive = false;
|
|
|
|
if (seenTypes.containsKey(type)) {
|
|
|
|
for (ManagedParameter param : seenTypes.get(type)) { // TODO: Check all these
|
|
if ((param.status == ValueStatus.FREE)) { // TODO: What about scopes
|
|
return true;
|
|
}
|
|
|
|
if (param.status == ValueStatus.ALLOCATED) {
|
|
if (seenLive) {
|
|
return true;
|
|
} else {
|
|
seenLive = true;
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
throw new IllegalArgumentException("Type " + type + " has never been seen before!");
|
|
}
|
|
|
|
throw new IllegalStateException("No suitable candidate has been found"); // TODO WRONG text
|
|
}
|
|
|
|
/**
|
|
* @throws IllegalArgumentException if type was not seen before or is null
|
|
*/
|
|
public void invalidate(TypeReference type) {
|
|
if (type == null) {
|
|
throw new IllegalArgumentException("The argument type may not be null");
|
|
}
|
|
|
|
if (seenTypes.containsKey(type)) {
|
|
for (ManagedParameter param : seenTypes.get(type)) {
|
|
if ((param.status != ValueStatus.CLOSED) &&
|
|
(param.status != ValueStatus.FREE_CLOSED) &&
|
|
(param.status != ValueStatus.FREE_INVALIDATED) &&
|
|
(param.status != ValueStatus.INVALIDATED) &&
|
|
(param.setInScope==currentScope) ) {
|
|
assert(param.type.equals(type));
|
|
|
|
if (param.status == ValueStatus.FREE) {
|
|
param.status = ValueStatus.FREE_INVALIDATED;
|
|
} else {
|
|
param.status = ValueStatus.INVALIDATED;
|
|
}
|
|
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
* Enter a subordinate scope.
|
|
*
|
|
* Call this whenever a new code block starts i.e. when ever you would have to put a
|
|
* left curly-bracket in yout java code.
|
|
* <p>
|
|
* This function influences the placement of Phi-Functions. Thus if you don't change
|
|
* values you don't have to call it.
|
|
*
|
|
* @param doesLoop set to true if the scope is introduced for a loop
|
|
* @return The depth
|
|
*/
|
|
public int scopeDown(boolean doesLoop) { // TODO: Rename scopeInto
|
|
// TODO: Delete Parameters if therw already was scopeNo
|
|
currentScope++;
|
|
return currentScope;
|
|
}
|
|
|
|
/**
|
|
* Leave a subordinate scope.
|
|
*
|
|
* All changes are marked invalid thus to be expected to be collected by a PhiInstruction.
|
|
* @throws IllegalStateException if already at top level
|
|
*/
|
|
public int scopeUp() { // TODO: Rename scopeOut
|
|
// First: Invalidate changed values
|
|
for (List<ManagedParameter> plist : seenTypes.values()) {
|
|
for (ManagedParameter param : plist) {
|
|
if (param.setInScope == currentScope) {
|
|
invalidate(param.type);
|
|
} else if ((param.setInScope > currentScope) &&
|
|
((param.status != ValueStatus.INVALIDATED) ||
|
|
(param.status != ValueStatus.CLOSED))) {
|
|
throw new IllegalStateException("Something went wrong in leaving a sub-subordinate scope");
|
|
}
|
|
}
|
|
}
|
|
currentScope--;
|
|
return currentScope;
|
|
}
|
|
|
|
/**
|
|
* Handed through to an IInstantiationBehavior if set in the constructor.
|
|
*
|
|
* @return true if Type is a REUSE type
|
|
* @throws IllegalStateExcpetion if AndroidModelParameterManager was constructed without an IInstanciationBehavior
|
|
*/
|
|
public boolean isReuse(TypeReference type) {
|
|
if (this.behaviour == null) {
|
|
throw new IllegalStateException("AndroidModelParameterManager was constructed without an IInstanciationBehavior");
|
|
}
|
|
if (type.isPrimitiveType()) return false;
|
|
final IInstantiationBehavior.InstanceBehavior beh = this.behaviour.getBehavior(type.getName(), null, null, null); // TODO: More info here!
|
|
return (beh == IInstantiationBehavior.InstanceBehavior.REUSE);
|
|
}
|
|
|
|
/**
|
|
* Shorthand for not({@link #isReuse(TypeReference)}.
|
|
*
|
|
* @return true if type is a CREATE-Type
|
|
* @throws IllegalStateExcpetion if AndroidModelParameterManager was constructed without an IInstanciationBehavior
|
|
*/
|
|
public boolean isCreate(TypeReference type) {
|
|
return (! isReuse(type));
|
|
}
|
|
|
|
@Override
|
|
public String toString() {
|
|
return "<AndroidModelParameterManager " + this.description + ">";
|
|
}
|
|
}
|