| // ASM: a very small and fast Java bytecode manipulation framework |
| // Copyright (c) 2000-2011 INRIA, France Telecom |
| // All rights reserved. |
| // |
| // Redistribution and use in source and binary forms, with or without |
| // modification, are permitted provided that the following conditions |
| // are met: |
| // 1. Redistributions of source code must retain the above copyright |
| // notice, this list of conditions and the following disclaimer. |
| // 2. Redistributions in binary form must reproduce the above copyright |
| // notice, this list of conditions and the following disclaimer in the |
| // documentation and/or other materials provided with the distribution. |
| // 3. Neither the name of the copyright holders nor the names of its |
| // contributors may be used to endorse or promote products derived from |
| // this software without specific prior written permission. |
| // |
| // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" |
| // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
| // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
| // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE |
| // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
| // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
| // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
| // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
| // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
| // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF |
| // THE POSSIBILITY OF SUCH DAMAGE. |
| package org.apache.tapestry5.internal.plastic.asm; |
| |
| /** |
| * A {@link ModuleVisitor} that generates the corresponding Module, ModulePackages and |
| * ModuleMainClass attributes, as defined in the Java Virtual Machine Specification (JVMS). |
| * |
| * @see <a href="https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7.25">JVMS |
| * 4.7.25</a> |
| * @see <a href="https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7.26">JVMS |
| * 4.7.26</a> |
| * @see <a href="https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7.27">JVMS |
| * 4.7.27</a> |
| * @author Remi Forax |
| * @author Eric Bruneton |
| */ |
| final class ModuleWriter extends ModuleVisitor { |
| |
| /** Where the constants used in this AnnotationWriter must be stored. */ |
| private final SymbolTable symbolTable; |
| |
| /** The module_name_index field of the JVMS Module attribute. */ |
| private final int moduleNameIndex; |
| |
| /** The module_flags field of the JVMS Module attribute. */ |
| private final int moduleFlags; |
| |
| /** The module_version_index field of the JVMS Module attribute. */ |
| private final int moduleVersionIndex; |
| |
| /** The requires_count field of the JVMS Module attribute. */ |
| private int requiresCount; |
| |
| /** The binary content of the 'requires' array of the JVMS Module attribute. */ |
| private final ByteVector requires; |
| |
| /** The exports_count field of the JVMS Module attribute. */ |
| private int exportsCount; |
| |
| /** The binary content of the 'exports' array of the JVMS Module attribute. */ |
| private final ByteVector exports; |
| |
| /** The opens_count field of the JVMS Module attribute. */ |
| private int opensCount; |
| |
| /** The binary content of the 'opens' array of the JVMS Module attribute. */ |
| private final ByteVector opens; |
| |
| /** The uses_count field of the JVMS Module attribute. */ |
| private int usesCount; |
| |
| /** The binary content of the 'uses_index' array of the JVMS Module attribute. */ |
| private final ByteVector usesIndex; |
| |
| /** The provides_count field of the JVMS Module attribute. */ |
| private int providesCount; |
| |
| /** The binary content of the 'provides' array of the JVMS Module attribute. */ |
| private final ByteVector provides; |
| |
| /** The provides_count field of the JVMS ModulePackages attribute. */ |
| private int packageCount; |
| |
| /** The binary content of the 'package_index' array of the JVMS ModulePackages attribute. */ |
| private final ByteVector packageIndex; |
| |
| /** The main_class_index field of the JVMS ModuleMainClass attribute, or 0. */ |
| private int mainClassIndex; |
| |
| ModuleWriter(final SymbolTable symbolTable, final int name, final int access, final int version) { |
| super(/* latest api = */ Opcodes.ASM8); |
| this.symbolTable = symbolTable; |
| this.moduleNameIndex = name; |
| this.moduleFlags = access; |
| this.moduleVersionIndex = version; |
| this.requires = new ByteVector(); |
| this.exports = new ByteVector(); |
| this.opens = new ByteVector(); |
| this.usesIndex = new ByteVector(); |
| this.provides = new ByteVector(); |
| this.packageIndex = new ByteVector(); |
| } |
| |
| @Override |
| public void visitMainClass(final String mainClass) { |
| this.mainClassIndex = symbolTable.addConstantClass(mainClass).index; |
| } |
| |
| @Override |
| public void visitPackage(final String packaze) { |
| packageIndex.putShort(symbolTable.addConstantPackage(packaze).index); |
| packageCount++; |
| } |
| |
| @Override |
| public void visitRequire(final String module, final int access, final String version) { |
| requires |
| .putShort(symbolTable.addConstantModule(module).index) |
| .putShort(access) |
| .putShort(version == null ? 0 : symbolTable.addConstantUtf8(version)); |
| requiresCount++; |
| } |
| |
| @Override |
| public void visitExport(final String packaze, final int access, final String... modules) { |
| exports.putShort(symbolTable.addConstantPackage(packaze).index).putShort(access); |
| if (modules == null) { |
| exports.putShort(0); |
| } else { |
| exports.putShort(modules.length); |
| for (String module : modules) { |
| exports.putShort(symbolTable.addConstantModule(module).index); |
| } |
| } |
| exportsCount++; |
| } |
| |
| @Override |
| public void visitOpen(final String packaze, final int access, final String... modules) { |
| opens.putShort(symbolTable.addConstantPackage(packaze).index).putShort(access); |
| if (modules == null) { |
| opens.putShort(0); |
| } else { |
| opens.putShort(modules.length); |
| for (String module : modules) { |
| opens.putShort(symbolTable.addConstantModule(module).index); |
| } |
| } |
| opensCount++; |
| } |
| |
| @Override |
| public void visitUse(final String service) { |
| usesIndex.putShort(symbolTable.addConstantClass(service).index); |
| usesCount++; |
| } |
| |
| @Override |
| public void visitProvide(final String service, final String... providers) { |
| provides.putShort(symbolTable.addConstantClass(service).index); |
| provides.putShort(providers.length); |
| for (String provider : providers) { |
| provides.putShort(symbolTable.addConstantClass(provider).index); |
| } |
| providesCount++; |
| } |
| |
| @Override |
| public void visitEnd() { |
| // Nothing to do. |
| } |
| |
| /** |
| * Returns the number of Module, ModulePackages and ModuleMainClass attributes generated by this |
| * ModuleWriter. |
| * |
| * @return the number of Module, ModulePackages and ModuleMainClass attributes (between 1 and 3). |
| */ |
| int getAttributeCount() { |
| return 1 + (packageCount > 0 ? 1 : 0) + (mainClassIndex > 0 ? 1 : 0); |
| } |
| |
| /** |
| * Returns the size of the Module, ModulePackages and ModuleMainClass attributes generated by this |
| * ModuleWriter. Also add the names of these attributes in the constant pool. |
| * |
| * @return the size in bytes of the Module, ModulePackages and ModuleMainClass attributes. |
| */ |
| int computeAttributesSize() { |
| symbolTable.addConstantUtf8(Constants.MODULE); |
| // 6 attribute header bytes, 6 bytes for name, flags and version, and 5 * 2 bytes for counts. |
| int size = |
| 22 + requires.length + exports.length + opens.length + usesIndex.length + provides.length; |
| if (packageCount > 0) { |
| symbolTable.addConstantUtf8(Constants.MODULE_PACKAGES); |
| // 6 attribute header bytes, and 2 bytes for package_count. |
| size += 8 + packageIndex.length; |
| } |
| if (mainClassIndex > 0) { |
| symbolTable.addConstantUtf8(Constants.MODULE_MAIN_CLASS); |
| // 6 attribute header bytes, and 2 bytes for main_class_index. |
| size += 8; |
| } |
| return size; |
| } |
| |
| /** |
| * Puts the Module, ModulePackages and ModuleMainClass attributes generated by this ModuleWriter |
| * in the given ByteVector. |
| * |
| * @param output where the attributes must be put. |
| */ |
| void putAttributes(final ByteVector output) { |
| // 6 bytes for name, flags and version, and 5 * 2 bytes for counts. |
| int moduleAttributeLength = |
| 16 + requires.length + exports.length + opens.length + usesIndex.length + provides.length; |
| output |
| .putShort(symbolTable.addConstantUtf8(Constants.MODULE)) |
| .putInt(moduleAttributeLength) |
| .putShort(moduleNameIndex) |
| .putShort(moduleFlags) |
| .putShort(moduleVersionIndex) |
| .putShort(requiresCount) |
| .putByteArray(requires.data, 0, requires.length) |
| .putShort(exportsCount) |
| .putByteArray(exports.data, 0, exports.length) |
| .putShort(opensCount) |
| .putByteArray(opens.data, 0, opens.length) |
| .putShort(usesCount) |
| .putByteArray(usesIndex.data, 0, usesIndex.length) |
| .putShort(providesCount) |
| .putByteArray(provides.data, 0, provides.length); |
| if (packageCount > 0) { |
| output |
| .putShort(symbolTable.addConstantUtf8(Constants.MODULE_PACKAGES)) |
| .putInt(2 + packageIndex.length) |
| .putShort(packageCount) |
| .putByteArray(packageIndex.data, 0, packageIndex.length); |
| } |
| if (mainClassIndex > 0) { |
| output |
| .putShort(symbolTable.addConstantUtf8(Constants.MODULE_MAIN_CLASS)) |
| .putInt(2) |
| .putShort(mainClassIndex); |
| } |
| } |
| } |