1 /*
  2  * Copyright (c) 2022, 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.internal.classfile.impl;
 26 
 27 import java.lang.classfile.*;
 28 import java.lang.classfile.constantpool.Utf8Entry;
 29 import java.lang.constant.MethodTypeDesc;
 30 import java.lang.reflect.AccessFlag;
 31 import java.util.List;
 32 import java.util.Optional;
 33 import java.util.function.Consumer;
 34 
 35 public final class MethodImpl
 36         extends AbstractElement
 37         implements MethodModel, MethodInfo, Util.Writable {
 38 
 39     private final ClassReader reader;
 40     private final int startPos, endPos, attributesPos;
 41     private List<Attribute<?>> attributes;
 42     private int[] parameterSlots;
 43 
 44     public MethodImpl(ClassReader reader, int startPos, int endPos, int attrStart) {
 45         this.reader = reader;
 46         this.startPos = startPos;
 47         this.endPos = endPos;
 48         this.attributesPos = attrStart;
 49     }
 50 
 51     @Override
 52     public AccessFlags flags() {
 53         return new AccessFlagsImpl(AccessFlag.Location.METHOD, reader.readU2(startPos));
 54     }
 55 
 56     @Override
 57     public Optional<ClassModel> parent() {
 58         if (reader instanceof ClassReaderImpl cri)
 59             return Optional.of(cri.getContainedClass());
 60         else
 61             return Optional.empty();
 62     }
 63 
 64     @Override
 65     public Utf8Entry methodName() {
 66         return reader.readEntry(startPos + 2, Utf8Entry.class);
 67     }
 68 
 69     @Override
 70     public Utf8Entry methodType() {
 71         return reader.readEntry(startPos + 4, Utf8Entry.class);
 72     }
 73 
 74     @Override
 75     public MethodTypeDesc methodTypeSymbol() {
 76         return Util.methodTypeSymbol(methodType());
 77     }
 78 
 79     @Override
 80     public int methodFlags() {
 81         return reader.readU2(startPos);
 82     }
 83 
 84     @Override
 85     public int parameterSlot(int paramNo) {
 86         if (parameterSlots == null)
 87             parameterSlots = Util.parseParameterSlots(methodFlags(), methodTypeSymbol());
 88         return parameterSlots[paramNo];
 89     }
 90 
 91     @Override
 92     public List<Attribute<?>> attributes() {
 93         if (attributes == null) {
 94             attributes = BoundAttribute.readAttributes(this, reader, attributesPos, reader.customAttributes());
 95         }
 96         return attributes;
 97     }
 98 
 99     @Override
100     public void writeTo(BufWriterImpl buf) {
101         if (Util.canSkipMethodInflation(reader, this, buf)) {
102             reader.copyBytesTo(buf, startPos, endPos - startPos);
103         }
104         else {
105             buf.writeU2U2U2(flags().flagsMask(),
106                     buf.cpIndex(methodName()),
107                     buf.cpIndex(methodType()));
108             Util.writeAttributes(buf, attributes());
109         }
110     }
111 
112     // MethodModel
113 
114     @Override
115     public Optional<CodeModel> code() {
116         return findAttribute(Attributes.code()).map(a -> (CodeModel) a);
117     }
118 
119     @Override
120     public void forEach(Consumer<? super MethodElement> consumer) {
121         consumer.accept(flags());
122         for (Attribute<?> attr : attributes()) {
123             if (attr instanceof MethodElement e)
124                 consumer.accept(e);
125         }
126     }
127 
128     @Override
129     public void writeTo(DirectClassBuilder builder) {
130         if (builder.canWriteDirect(reader)) {
131             builder.withMethod(this);
132         }
133         else {
134             builder.withMethod(methodName(), methodType(), methodFlags(), Util.writingAll(this));
135         }
136     }
137 
138     @Override
139     public String toString() {
140         return String.format("MethodModel[methodName=%s, methodType=%s, flags=%d]",
141                 methodName().stringValue(), methodType().stringValue(), flags().flagsMask());
142     }
143 }