/* * Copyright (C) 2015 Sebastian Daschner, sebastian-daschner.com * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.sebastian_daschner.jaxrs_analyzer.analysis.bytecode.reduction; import com.sebastian_daschner.jaxrs_analyzer.model.instructions.Instruction; import com.sebastian_daschner.jaxrs_analyzer.model.instructions.LoadInstruction; import com.sebastian_daschner.jaxrs_analyzer.model.instructions.LoadStoreInstruction; import java.util.HashSet; import java.util.List; import java.util.Set; import java.util.TreeSet; import java.util.function.Predicate; /** * Searches for specific instruction occurrences in the byte code. * * @author Sebastian Daschner */ final class InstructionFinder { private InstructionFinder() { throw new UnsupportedOperationException(); } /** * Searches for all LOAD indexes which occur in the given instructions. * The LOAD instruction is checked against the given predicate if it should be ignored. * * @param instructions The instructions where to search * @param isLoadIgnored The ignore predicate * @return All found LOAD indexes */ static Set<Integer> findLoadIndexes(final List<Instruction> instructions, final Predicate<LoadInstruction> isLoadIgnored) { return instructions.stream().filter(i -> i.getType() == Instruction.InstructionType.LOAD).map(i -> (LoadInstruction) i) .filter(i -> !isLoadIgnored.test(i)).map(LoadInstruction::getNumber).collect(TreeSet::new, Set::add, Set::addAll); } /** * Searches for all LOAD & STORE occurrences with {@code index} in the given instructions. * * @param index The LOAD / STORE index * @param instructions The instructions where to search * @return The positions of all found LOAD_{@code index} / STORE_{@code index} */ static Set<Integer> findLoadStores(final int index, final List<Instruction> instructions) { final Predicate<Instruction> loadStoreType = instruction -> instruction.getType() == Instruction.InstructionType.LOAD || instruction.getType() == Instruction.InstructionType.STORE; return find(loadStoreType.and(instruction -> ((LoadStoreInstruction) instruction).getNumber() == index), instructions); } /** * Searches for return instructions in the given instructions. * * @param instructions The instructions where to search * @return The positions of all found return instructions */ static Set<Integer> findReturnsAndThrows(final List<Instruction> instructions) { return find(instruction -> instruction.getType() == Instruction.InstructionType.RETURN || instruction.getType() == Instruction.InstructionType.THROW, instructions); } /** * Searches for certain instruction positions be testing against the predicate. * * @param predicate The criteria predicate * @param instructions The instructions where to search * @return The positions of all matching instructions */ private static Set<Integer> find(final Predicate<Instruction> predicate, final List<Instruction> instructions) { final Set<Integer> positions = new HashSet<>(); for (int i = 0; i < instructions.size(); i++) { final Instruction instruction = instructions.get(i); if (predicate.test(instruction)) { positions.add(i); } } return positions; } }