001/*
002 * Licensed to the Apache Software Foundation (ASF) under one
003 * or more contributor license agreements.  See the NOTICE file
004 * distributed with this work for additional information
005 * regarding copyright ownership.  The ASF licenses this file
006 * to you under the Apache License, Version 2.0 (the
007 * "License"); you may not use this file except in compliance
008 * with the License.  You may obtain a copy of the License at
009 *
010 *   https://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing,
013 * software distributed under the License is distributed on an
014 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015 * KIND, either express or implied.  See the License for the
016 * specific language governing permissions and limitations
017 * under the License.
018 */
019
020package org.apache.bcel.classfile;
021
022import java.io.DataInput;
023import java.io.DataOutputStream;
024import java.io.IOException;
025import java.util.Arrays;
026
027import org.apache.bcel.Const;
028import org.apache.bcel.util.Args;
029import org.apache.commons.lang3.ArrayUtils;
030
031/**
032 * This class represents a chunk of Java byte code contained in a method. It is instantiated by the
033 * <em>Attribute.readAttribute()</em> method. A <em>Code</em> attribute contains information about operand stack, local
034 * variables, byte code and the exceptions handled within this method.
035 *
036 * This attribute has attributes itself, namely <em>LineNumberTable</em> which is used for debugging purposes and
037 * <em>LocalVariableTable</em> which contains information about the local variables.
038 *
039 * <pre>
040 * Code_attribute {
041 *   u2 attribute_name_index;
042 *   u4 attribute_length;
043 *   u2 max_stack;
044 *   u2 max_locals;
045 *   u4 code_length;
046 *   u1 code[code_length];
047 *   u2 exception_table_length;
048 *   {
049 *     u2 start_pc;
050 *     u2 end_pc;
051 *     u2 handler_pc;
052 *     u2 catch_type;
053 *   } exception_table[exception_table_length];
054 *   u2 attributes_count;
055 *   attribute_info attributes[attributes_count];
056 * }
057 * </pre>
058 *
059 * <p>
060 * The layout above uses the standard Code header. This class also supports compact Code headers found in historical class file versions 45.0 through 45.2.
061 * Here, "compact" describes the narrower encoding of three fields: {@code max_stack} and {@code max_locals} each use {@code u1}, and {@code code_length}
062 * uses {@code u2}, instead of {@code u2}, {@code u2}, and {@code u4}, respectively. The notation {@code u1}, {@code u2}, and {@code u4} denotes unsigned
063 * one-, two-, and four-byte values. These three fields therefore occupy 4 bytes instead of 8, excluding the common six-byte attribute prefix.
064 * The layout of that prefix and the remaining Code fields is unchanged; the bytecode itself is not compressed.
065 * {@link #isCompactCodeHeader()} identifies this narrower layout.
066 * </p>
067 *
068 * <p>
069 * Class file versions 45.0 through 45.2 also occur with standard Code headers accepted by modern JVMs, so the version alone does not identify the layout.
070 * {@link ClassParser} uses standard headers by default; {@link ClassParser#setCompactCodeHeaderEnabled(boolean)} explicitly selects compact headers
071 * for those versions.
072 * </p>
073 *
074 * @see Attribute
075 * @see CodeException
076 * @see LineNumberTable
077 * @see LocalVariableTable
078 */
079public final class Code extends Attribute {
080
081    /**
082     * Whether {@code max_stack}, {@code max_locals}, and {@code code_length} use {@code u1/u1/u2} (4 bytes) instead of {@code u2/u2/u4} (8 bytes).
083     * Compact describes these field widths, not compression of the bytecode or the rest of the attribute.
084     */
085    private boolean compactCodeHeader;
086    private int maxStack; // Maximum size of stack used by this method // TODO this could be made final (setter is not used)
087    private int maxLocals; // Number of local variables // TODO this could be made final (setter is not used)
088    private byte[] code; // Actual byte code
089    private CodeException[] exceptionTable; // Table of handled exceptions
090    private Attribute[] attributes; // or LocalVariable
091
092    /**
093     * Initialize from another object. Note that both objects use the same references (shallow copy). Use copy() for a
094     * physical copy.
095     *
096     * @param code The source Code.
097     */
098    public Code(final Code code) {
099        this(code.getNameIndex(), code.getLength(), code.getMaxStack(), code.getMaxLocals(), code.getCode(), code.getExceptionTable(), code.getAttributes(),
100                code.getConstantPool(), code.compactCodeHeader);
101    }
102
103    /**
104     * Constructs a Code attribute object from a DataInput.
105     *
106     * @param nameIndex    Index pointing to the name <em>Code</em>.
107     * @param length       Content length in bytes.
108     * @param dataInput    Data input.
109     * @param constantPool Array of constants.
110     * @throws ClassFormatException Thrown if the code array read from {@code file} is greater than {@link Const#MAX_CODE_SIZE}.
111     */
112    Code(final int nameIndex, final int length, final DataInput dataInput, final ConstantPool constantPool) throws IOException {
113        this(nameIndex, length, dataInput, constantPool, false);
114    }
115
116    /**
117     * Reads a Code attribute using the selected header layout.
118     */
119    Code(final int nameIndex, final int length, final DataInput dataInput, final ConstantPool constantPool, final boolean compactCodeHeader) throws IOException {
120        // Compact headers encode max_stack/max_locals/code_length as u1/u1/u2; standard headers use u2/u2/u4.
121        // Initialize the remaining fields with default values, then read them below.
122        this(nameIndex, length, compactCodeHeader ? dataInput.readUnsignedByte() : dataInput.readUnsignedShort(),
123                compactCodeHeader ? dataInput.readUnsignedByte() : dataInput.readUnsignedShort(), null, null, null, constantPool, compactCodeHeader);
124        final int codeLength = Args.requireU4(compactCodeHeader ? dataInput.readUnsignedShort() : dataInput.readInt(), 0, Const.MAX_CODE_SIZE,
125                "Code length attribute");
126        code = new byte[codeLength]; // Read byte code
127        dataInput.readFully(code);
128        /*
129         * Read exception table that contains all regions where an exception handler is active, that is, a try { ... } catch () block.
130         */
131        final int exceptionTableLength = dataInput.readUnsignedShort();
132        exceptionTable = new CodeException[exceptionTableLength];
133        for (int i = 0; i < exceptionTableLength; i++) {
134            exceptionTable[i] = new CodeException(dataInput);
135        }
136        /*
137         * Read all attributes, currently 'LineNumberTable' and 'LocalVariableTable'
138         */
139        final int attributesCount = dataInput.readUnsignedShort();
140        attributes = new Attribute[attributesCount];
141        for (int i = 0; i < attributesCount; i++) {
142            attributes[i] = readAttribute(dataInput, constantPool, compactCodeHeader);
143        }
144        /*
145         * Adjust length, because of setAttributes in this(), s.b. length is incorrect, because it didn't take the internal attributes into account yet! Very
146         * subtle bug, fixed in 3.1.1.
147         */
148        super.setLength(length);
149    }
150
151    /**
152     * Constructs a Code attribute using a standard eight-byte header.
153     *
154     * <p>
155     * Use {@link #setCompactCodeHeader(boolean)} to select the compact four-byte header after construction.
156     * </p>
157     *
158     * @param nameIndex Index pointing to the name <em>Code</em>.
159     * @param length Content length in bytes.
160     * @param maxStack Maximum size of stack.
161     * @param maxLocals Number of local variables.
162     * @param code Actual byte code.
163     * @param exceptionTable of handled exceptions.
164     * @param attributes Attributes of code: LineNumber or LocalVariable.
165     * @param constantPool Array of constants.
166     * @throws ClassFormatException Thrown if the code array is greater than {@link Const#MAX_CODE_SIZE}.
167     */
168    public Code(final int nameIndex, final int length, final int maxStack, final int maxLocals, final byte[] code, final CodeException[] exceptionTable,
169        final Attribute[] attributes, final ConstantPool constantPool) {
170        this(nameIndex, length, maxStack, maxLocals, code, exceptionTable, attributes, constantPool, false);
171    }
172
173    private Code(final int nameIndex, final int length, final int maxStack, final int maxLocals, final byte[] code, final CodeException[] exceptionTable,
174        final Attribute[] attributes, final ConstantPool constantPool, final boolean compactCodeHeader) {
175        super(Const.ATTR_CODE, nameIndex, length, constantPool);
176        this.compactCodeHeader = compactCodeHeader;
177        this.maxStack = Args.requireU2(maxStack, "maxStack");
178        this.maxLocals = Args.requireU2(maxLocals, "maxLocals");
179        this.code = ArrayUtils.nullToEmpty(code);
180        Args.requireU4(this.code.length, 0, Const.MAX_CODE_SIZE, "Code length attribute");
181        this.exceptionTable = ArrayUtils.nullToEmpty(exceptionTable, CodeException[].class);
182        Args.requireU2(this.exceptionTable.length, "exceptionTable.length");
183        this.attributes = attributes != null ? attributes : EMPTY_ARRAY;
184        super.setLength(calculateLength()); // Adjust length
185    }
186
187    /**
188     * Called by objects that are traversing the nodes of the tree implicitly defined by the contents of a Java class.
189     * That is, the hierarchy of methods, fields, attributes, and other elements forms a tree of objects.
190     *
191     * @param v Visitor object.
192     */
193    @Override
194    public void accept(final Visitor v) {
195        v.visitCode(this);
196    }
197
198    /**
199     * @return The full size of this code attribute, minus its first 6 bytes, including the size of all its contained attributes.
200     */
201    private int calculateLength() {
202        int len = 0;
203        if (attributes != null) {
204            for (final Attribute attribute : attributes) {
205                len += attribute.getLength() + 6 /* attribute header size */;
206            }
207        }
208        return len + getInternalLength();
209    }
210
211    /**
212     * Creates a deep copy of this attribute.
213     *
214     * @param constantPool The constant pool to duplicate.
215     * @return deep copy of this attribute.
216     */
217    @Override
218    public Attribute copy(final ConstantPool constantPool) {
219        final Code c = (Code) clone();
220        if (code != null) {
221            c.code = code.clone();
222        }
223        c.setConstantPool(constantPool);
224        c.exceptionTable = new CodeException[exceptionTable.length];
225        Arrays.setAll(c.exceptionTable, i -> exceptionTable[i].copy());
226        c.attributes = new Attribute[attributes.length];
227        Arrays.setAll(c.attributes, i -> attributes[i].copy(constantPool));
228        return c;
229    }
230
231    /**
232     * Dumps code attribute to file stream in binary format.
233     *
234     * @param file Output file stream.
235     * @throws IOException Thrown if an I/O error occurs.
236     * @throws ClassFormatException Thrown if a compact header's {@code max_stack} or {@code max_locals} is outside 0 through 255,
237     *         or its code length exceeds 65535 bytes.
238     */
239    @Override
240    public void dump(final DataOutputStream file) throws IOException {
241        if (compactCodeHeader) {
242            Args.requireU1(maxStack, "maxStack");
243            Args.requireU1(maxLocals, "maxLocals");
244            Args.requireU2(code.length, "Code length attribute");
245        }
246        super.dump(file);
247        if (compactCodeHeader) {
248            file.writeByte(maxStack);
249            file.writeByte(maxLocals);
250            file.writeShort(code.length);
251        } else {
252            file.writeShort(maxStack);
253            file.writeShort(maxLocals);
254            file.writeInt(code.length);
255        }
256        file.write(code, 0, code.length);
257        file.writeShort(Args.requireU2(exceptionTable.length, "exceptionTable.length"));
258        for (final CodeException exception : exceptionTable) {
259            exception.dump(file);
260        }
261        file.writeShort(Args.requireU2(attributes.length, "attributes.length"));
262        for (final Attribute attribute : attributes) {
263            attribute.dump(file);
264        }
265    }
266
267    /**
268     * Gets the collection of code attributes.
269     *
270     * @return Collection of code attributes.
271     * @see Attribute
272     */
273    public Attribute[] getAttributes() {
274        return attributes;
275    }
276
277    /**
278     * Gets the actual byte code of the method.
279     *
280     * @return Actual byte code of the method.
281     */
282    public byte[] getCode() {
283        return code;
284    }
285
286    /**
287     * Gets the table of handled exceptions.
288     *
289     * @return Table of handled exceptions.
290     * @see CodeException
291     */
292    public CodeException[] getExceptionTable() {
293        return exceptionTable;
294    }
295
296    /**
297     * Gets the internal length of this code attribute (minus the first 6 bytes) and excluding all its attributes.
298     *
299     * @return The internal length of this code attribute (minus the first 6 bytes) and excluding all its attributes.
300     */
301    private int getInternalLength() {
302        // Only max_stack, max_locals, and code_length differ: 1 + 1 + 2 compact bytes versus 2 + 2 + 4 standard bytes.
303        return (compactCodeHeader ? 4 : 8)
304            + code.length /* byte-code */
305            + 2 /* exception-table length */
306            + 8 * (exceptionTable == null ? 0 : exceptionTable.length) /* exception table */
307            + 2 /* attributes count */;
308    }
309
310    /**
311     * Gets the LineNumberTable of Code, if it has one.
312     *
313     * @return LineNumberTable of Code, if it has one.
314     */
315    public LineNumberTable getLineNumberTable() {
316        for (final Attribute attribute : attributes) {
317            if (attribute instanceof LineNumberTable) {
318                return (LineNumberTable) attribute;
319            }
320        }
321        return null;
322    }
323
324    /**
325     * Gets the LocalVariableTable of Code, if it has one.
326     *
327     * @return LocalVariableTable of Code, if it has one.
328     */
329    public LocalVariableTable getLocalVariableTable() {
330        for (final Attribute attribute : attributes) {
331            if (attribute instanceof LocalVariableTable) {
332                return (LocalVariableTable) attribute;
333            }
334        }
335        return null;
336    }
337
338    /**
339     * Gets the local variable type table attribute {@link LocalVariableTypeTable}.
340     *
341     * @return LocalVariableTypeTable of Code, if it has one, null otherwise.
342     * @since 6.10.0
343     */
344    public LocalVariableTypeTable getLocalVariableTypeTable() {
345        for (final Attribute attribute : attributes) {
346            if (attribute instanceof LocalVariableTypeTable) {
347                return (LocalVariableTypeTable) attribute;
348            }
349        }
350        return null;
351    }
352
353    /**
354     * Gets the number of local variables.
355     *
356     * @return Number of local variables.
357     */
358    public int getMaxLocals() {
359        return maxLocals;
360    }
361
362    /**
363     * Gets the maximum size of stack used by this method.
364     *
365     * @return Maximum size of stack used by this method.
366     */
367    public int getMaxStack() {
368        return maxStack;
369    }
370
371    /**
372     * Gets the {@link StackMap} attribute.
373     *
374     * @return StackMap of Code, if it has one, else null.
375     * @since 6.8.0
376     */
377    public StackMap getStackMap() {
378        for (final Attribute attribute : attributes) {
379            if (attribute instanceof StackMap) {
380                return (StackMap) attribute;
381            }
382        }
383        return null;
384    }
385
386    /**
387     * Gets whether this attribute uses the compact four-byte Code header.
388     *
389     * @return Whether {@code max_stack}, {@code max_locals}, and {@code code_length} use {@code u1}, {@code u1}, and {@code u2}, respectively,
390     *         instead of the standard {@code u2}, {@code u2}, and {@code u4}.
391     * @since 6.14.0
392     * @see #setCompactCodeHeader(boolean)
393     */
394    public boolean isCompactCodeHeader() {
395        return compactCodeHeader;
396    }
397
398    /**
399     * Sets the attributes for this Code.
400     *
401     * @param attributes The attributes to set for this Code.
402     */
403    public void setAttributes(final Attribute[] attributes) {
404        this.attributes = attributes != null ? attributes : EMPTY_ARRAY;
405        super.setLength(calculateLength()); // Adjust length
406    }
407
408    /**
409     * Sets the byte code.
410     *
411     * @param code byte code.
412     * @throws ClassFormatException Thrown if the code array is greater than {@link Const#MAX_CODE_SIZE}.
413     */
414    public void setCode(final byte[] code) {
415        this.code = ArrayUtils.nullToEmpty(code);
416        Args.requireU4(this.code.length, 0, Const.MAX_CODE_SIZE, "Code length attribute");
417        super.setLength(calculateLength()); // Adjust length
418    }
419
420    /**
421     * Sets the Code header layout and recalculates the attribute length.
422     *
423     * <p>
424     * Compact headers encode {@code max_stack}, {@code max_locals}, and {@code code_length} as {@code u1}, {@code u1}, and {@code u2}, respectively,
425     * totaling 4 bytes instead of the standard 8. This limits {@code max_stack} and {@code max_locals} to 0 through 255 and the code length to 65535 bytes.
426     * The remaining attribute layout is unchanged. Compact headers are intended for historical class file versions 45.0 through 45.2.
427     * Enabling compact headers validates these values before changing the layout. Subsequent changes to them are checked by {@link #dump(DataOutputStream)}.
428     * </p>
429     *
430     * <p>
431     * This setting controls this attribute's own dump. When dumping an entire class, {@link JavaClass#dump(DataOutputStream)} selects one layout for
432     * all method Code attributes based on the class version and the methods' header settings, without changing this attribute's setting.
433     * </p>
434     *
435     * @param compactCodeHeader Whether to use a compact four-byte header ({@code true}) or a standard eight-byte header ({@code false}).
436     * @throws ClassFormatException Thrown if {@code compactCodeHeader} is {@code true} and the current values do not fit in a compact header.
437     * @since 6.14.0
438     */
439    public void setCompactCodeHeader(final boolean compactCodeHeader) {
440        if (compactCodeHeader) {
441            Args.requireU1(maxStack, "maxStack");
442            Args.requireU1(maxLocals, "maxLocals");
443            Args.requireU2(code.length, "Code length attribute");
444        }
445        this.compactCodeHeader = compactCodeHeader;
446        super.setLength(calculateLength());
447    }
448
449    /**
450     * Sets the exception table.
451     *
452     * @param exceptionTable exception table.
453     */
454    public void setExceptionTable(final CodeException[] exceptionTable) {
455        this.exceptionTable = exceptionTable != null ? exceptionTable : CodeException.EMPTY_ARRAY;
456        Args.requireU2(this.exceptionTable.length, "exceptionTable.length");
457        super.setLength(calculateLength()); // Adjust length
458    }
459
460    /**
461     * Sets the maximum number of local variables.
462     *
463     * @param maxLocals maximum number of local variables.
464     */
465    public void setMaxLocals(final int maxLocals) {
466        this.maxLocals = maxLocals;
467    }
468
469    /**
470     * Sets the maximum stack size.
471     *
472     * @param maxStack maximum stack size.
473     */
474    public void setMaxStack(final int maxStack) {
475        this.maxStack = maxStack;
476    }
477
478    /**
479     * @return String representation of code chunk.
480     */
481    @Override
482    public String toString() {
483        return toString(true);
484    }
485
486    /**
487     * Converts this object to a String.
488     *
489     * @param verbose Provides verbose output when true.
490     * @return String representation of code chunk.
491     */
492    public String toString(final boolean verbose) {
493        final StringBuilder buf = new StringBuilder(100); // CHECKSTYLE IGNORE MagicNumber
494        buf.append("Code(maxStack = ").append(maxStack).append(", maxLocals = ").append(maxLocals).append(", code_length = ").append(code.length).append(")\n")
495            .append(Utility.codeToString(code, super.getConstantPool(), 0, -1, verbose));
496        if (exceptionTable.length > 0) {
497            buf.append("\nException handler(s) = \n").append("From\tTo\tHandler\tType\n");
498            for (final CodeException exception : exceptionTable) {
499                buf.append(exception.toString(super.getConstantPool(), verbose)).append("\n");
500            }
501        }
502        if (attributes.length > 0) {
503            buf.append("\nAttribute(s) = ");
504            for (final Attribute attribute : attributes) {
505                buf.append("\n").append(attribute.getName()).append(":");
506                buf.append("\n").append(attribute);
507            }
508        }
509        return buf.toString();
510    }
511}