1 /*
  2  * Copyright (c) 2024, 2025, Oracle and/or its affiliates. All rights reserved.
  3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  4  *
  5  * This code is free software; you can redistribute it and/or modify it
  6  * under the terms of the GNU General Public License version 2 only, as
  7  * published by the Free Software Foundation.  Oracle designates this
  8  * particular file as subject to the "Classpath" exception as provided
  9  * by Oracle in the LICENSE file that accompanied this code.
 10  *
 11  * This code is distributed in the hope that it will be useful, but WITHOUT
 12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 14  * version 2 for more details (a copy is included in the LICENSE file that
 15  * accompanied this code).
 16  *
 17  * You should have received a copy of the GNU General Public License version
 18  * 2 along with this work; if not, write to the Free Software Foundation,
 19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 20  *
 21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 22  * or visit www.oracle.com if you need additional information or have any
 23  * questions.
 24  */
 25 package jdk.incubator.code.bytecode.impl;
 26 
 27 import java.lang.classfile.CodeBuilder;
 28 import java.lang.classfile.CodeElement;
 29 import java.lang.classfile.CodeTransform;
 30 import java.lang.classfile.Opcode;
 31 import java.lang.classfile.PseudoInstruction;
 32 import java.lang.classfile.instruction.BranchInstruction;
 33 import java.lang.classfile.instruction.LabelTarget;
 34 import java.util.ArrayList;
 35 import java.util.List;
 36 
 37 /**
 38  * BranchCompactor is a CodeTransform skipping redundant branches to immediate targets.
 39  */
 40 public final class BranchCompactor implements CodeTransform {
 41 
 42     private BranchInstruction branch;
 43     private final List<PseudoInstruction> buffer = new ArrayList<>();
 44 
 45     public BranchCompactor() {
 46     }
 47 
 48     @Override
 49     public void accept(CodeBuilder cob, CodeElement coe) {
 50         if (branch == null) {
 51             if (coe instanceof BranchInstruction bi && isUnconditionalBranch(bi.opcode())) {
 52                 //unconditional branch is stored
 53                 branch = bi;
 54             } else {
 55                 //all other elements are passed
 56                 cob.with(coe);
 57             }
 58         } else {
 59             switch (coe) {
 60                 case LabelTarget lt when branch.target() == lt.label() -> {
 61                     //skip branch to immediate target
 62                     branch = null;
 63                     //flush the buffer
 64                     atEnd(cob);
 65                     //pass the target
 66                     cob.with(lt);
 67                 }
 68                 case PseudoInstruction pi -> {
 69                     //buffer pseudo instructions
 70                     buffer.add(pi);
 71                 }
 72                 default -> {
 73                     //any other instruction flushes the branch and buffer
 74                     atEnd(cob);
 75                     //replay the code element
 76                     accept(cob, coe);
 77                 }
 78             }
 79         }
 80     }
 81 
 82     @Override
 83     public void atEnd(CodeBuilder cob) {
 84         if (branch != null) {
 85             //flush the branch
 86             cob.with(branch);
 87             branch = null;
 88         }
 89         //flush the buffer
 90         buffer.forEach(cob::with);
 91         buffer.clear();
 92     }
 93 
 94     static boolean isUnconditionalBranch(Opcode opcode) {
 95         return switch (opcode) {
 96             case GOTO, ATHROW, GOTO_W, LOOKUPSWITCH, TABLESWITCH -> true;
 97             default -> opcode.kind() == Opcode.Kind.RETURN;
 98         };
 99     }
100 }