Code with Finding: |
class Subroutines {
/**
* Constructor.
* @param mg A MethodGen object representing method to
* create the Subroutine objects of.
* @param enableJustIceCheck whether to enable additional JustIce checks
* @since 6.0
*/
public Subroutines(MethodGen mg, boolean enableJustIceCheck){
InstructionHandle[] all = mg.getInstructionList().getInstructionHandles();
CodeExceptionGen[] handlers = mg.getExceptionHandlers();
// Define our "Toplevel" fake subroutine.
TOPLEVEL = new SubroutineImpl();
// Calculate "real" subroutines.
Set<InstructionHandle> sub_leaders = new HashSet<>(); // Elements: InstructionHandle
for (InstructionHandle element : all) {
Instruction inst = element.getInstruction();
if (inst instanceof JsrInstruction){
sub_leaders.add(((JsrInstruction) inst).getTarget());
}
}
// Build up the database.
for (InstructionHandle astore : sub_leaders) {
SubroutineImpl sr = new SubroutineImpl();
sr.setLocalVariable( ((ASTORE) (astore.getInstruction())).getIndex() );
subroutines.put(astore, sr);
}
// Fake it a bit. We want a virtual "TopLevel" subroutine.
subroutines.put(all[0], TOPLEVEL);
sub_leaders.add(all[0]);
// Tell the subroutines about their JsrInstructions.
// Note that there cannot be a JSR targeting the top-level
// since "Jsr 0" is disallowed in Pass 3a.
// Instructions shared by a subroutine and the toplevel are
// disallowed and checked below, after the BFS.
for (InstructionHandle element : all) {
Instruction inst = element.getInstruction();
if (inst instanceof JsrInstruction){
InstructionHandle leader = ((JsrInstruction) inst).getTarget();
((SubroutineImpl) getSubroutine(leader)).addEnteringJsrInstruction(element);
}
}
// Now do a BFS from every subroutine leader to find all the
// instructions that belong to a subroutine.
// we don't want to assign an instruction to two or more Subroutine objects.
Set<InstructionHandle> instructions_assigned = new HashSet<>();
//Graph colouring. Key: InstructionHandle, Value: ColourConstants enum .
Map<InstructionHandle, ColourConstants> colors = new HashMap<>();
List<InstructionHandle> Q = new ArrayList<>();
for (InstructionHandle actual : sub_leaders) {
// Do some BFS with "actual" as the root of the graph.
// Init colors
for (InstructionHandle element : all) {
colors.put(element, ColourConstants.WHITE);
}
colors.put(actual, ColourConstants.GRAY);
// Init Queue
Q.clear();
Q.add(actual); // add(Obj) adds to the end, remove(0) removes from the start.
/*
* BFS ALGORITHM MODIFICATION:
* Start out with multiple "root" nodes, as exception handlers are starting points of top-level code, too.
* [why top-level?
* TODO: Refer to the special JustIce notion of subroutines.]
*/
if (actual == all[0]){
for (CodeExceptionGen handler : handlers) {
colors.put(handler.getHandlerPC(), ColourConstants.GRAY);
Q.add(handler.getHandlerPC());
}
}
/* CONTINUE NORMAL BFS ALGORITHM */
// Loop until Queue is empty
while (Q.size() != 0){
InstructionHandle u = Q.remove(0);
InstructionHandle[] successors = getSuccessors(u);
for (InstructionHandle successor : successors) {
if (colors.get(successor) == ColourConstants.WHITE){
colors.put(successor, ColourConstants.GRAY);
Q.add(successor);
}
}
colors.put(u, ColourConstants.BLACK);
}
// BFS ended above.
for (InstructionHandle element : all) {
if (colors.get(element) == ColourConstants.BLACK){
((SubroutineImpl) (actual==all[0]?getTopLevel():getSubroutine(actual))).addInstruction(element);
if (instructions_assigned.contains(element)){
throw new StructuralCodeConstraintException("Instruction '"+element+
"' is part of more than one subroutine (or of the top level and a subroutine).");
}
instructions_assigned.add(element);
}
}
if (actual != all[0]){// If we don't deal with the top-level 'subroutine'
((SubroutineImpl) getSubroutine(actual)).setLeavingRET();
}
}
if (enableJustIceCheck) {
// Now make sure no instruction of a Subroutine is protected by exception handling code
// as is mandated by JustIces notion of subroutines.
for (CodeExceptionGen handler : handlers) {
InstructionHandle _protected = handler.getStartPC();
while (_protected != handler.getEndPC().getNext()){
// Note the inclusive/inclusive notation of "generic API" exception handlers!
for (Subroutine sub : subroutines.values()) {
if (sub != subroutines.get(all[0])){ // We don't want to forbid top-level exception handlers.
if (sub.contains(_protected)){
throw new StructuralCodeConstraintException("Subroutine instruction '"+_protected+
"' is protected by an exception handler, '"+handler+
"'. This is forbidden by the JustIce verifier due to its clear definition of subroutines.");
}
}
}
_protected = _protected.getNext();
}
}
}
// Now make sure no subroutine is calling a subroutine
// that uses the same local variable for the RET as themselves
// (recursively).
// This includes that subroutines may not call themselves
// recursively, even not through intermediate calls to other
// subroutines.
noRecursiveCalls(getTopLevel(), new HashSet<Integer>());
}
}
|