1 /* 2 * Copyright (c) 2016, 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. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 package org.openjdk.asmtools.jasm; 24 25 import org.openjdk.asmtools.common.Module; 26 27 import java.io.IOException; 28 import java.util.*; 29 import java.util.function.BiConsumer; 30 import java.util.function.Consumer; 31 import java.util.function.Function; 32 33 /** 34 * The module attribute 35 */ 36 class ModuleAttr extends AttrData { 37 // shared data 38 private Module.Builder builder; 39 private final ClassData clsData; 40 private final Function<String, ConstantPool.ConstCell> findCellAsciz; 41 private final Function<String, ConstantPool.ConstCell> findCellClassByName; 42 private final Function<String, ConstantPool.ConstCell> findCellModuleByName; 43 private final Function<String, ConstantPool.ConstCell> findCellPackageByName; 44 45 // entries to populate tables of the module attribute 46 BiConsumer<String, Integer> requires = (mn, f) -> this.builder.require(mn, f); 47 BiConsumer<String, Set<String>> exports = (pn, ms) -> this.builder.exports(new Module.Exported(pn), ms); 48 BiConsumer<String, Set<String>> opens = (pn, ms) -> this.builder.opens(new Module.Opened(pn), ms); 49 BiConsumer<String, Set<String>> provides = (tn, ts) -> this.builder.provides(new Module.Provided(tn), ts); 50 Consumer<Set<String>> uses = (ts) -> this.builder.uses(ts); 51 52 ModuleAttr(ClassData cdata) { 53 super(cdata, Tables.AttrTag.ATT_Module.parsekey()); 54 builder = new Module.Builder(); 55 clsData = cdata; 56 findCellAsciz = (name) -> clsData.pool.FindCellAsciz(name); 57 findCellClassByName = (name) -> clsData.pool.FindCellClassByName(name); 58 findCellModuleByName = (name) -> clsData.pool.FindCellModuleByName(name); 59 findCellPackageByName = (name) -> clsData.pool.FindCellPackageByName(name); 60 } 61 62 void openModule() { 63 builder.setModuleFlags(Module.Modifier.ACC_OPEN); 64 } 65 void setModuleName(String value) { builder.setModuleName(value);} 66 67 ModuleAttr build() { 68 Module module = builder.build(); 69 Content.instance.header = new HeaderStruct(module.header, findCellModuleByName, findCellAsciz); 70 Content.instance.requiresStruct = new SetStruct<>(module.requires, findCellModuleByName, findCellAsciz); 71 Content.instance.exportsMapStruct = new MapStruct<>(module.exports, findCellPackageByName, findCellModuleByName ); 72 Content.instance.opensMapStruct = new MapStruct<>(module.opens,findCellPackageByName, findCellModuleByName ); 73 Content.instance.usesStruct = new SetStruct<>(module.uses, findCellClassByName, null); 74 Content.instance.providesMapStruct = new MapStruct<>(module.provides, findCellClassByName, findCellClassByName); 75 return this; 76 } 77 78 @Override 79 public int attrLength() { 80 return Content.instance.getLength(); 81 } 82 83 @Override 84 public void write(CheckedDataOutputStream out) throws IOException { 85 super.write(out); 86 Content.instance.write(out); 87 } 88 89 private enum Content implements Data { 90 instance { 91 @Override 92 public int getLength() { 93 return header.getLength() + 94 requiresStruct.getLength() + 95 exportsMapStruct.getLength() + 96 opensMapStruct.getLength() + 97 usesStruct.getLength() + 98 providesMapStruct.getLength(); 99 } 100 101 @Override 102 public void write(CheckedDataOutputStream out) throws IOException { 103 // keep order! 104 header.write(out); 105 requiresStruct.write(out); 106 exportsMapStruct.write(out); 107 opensMapStruct.write(out); 108 usesStruct.write(out); 109 providesMapStruct.write(out); 110 } 111 }; 112 113 HeaderStruct header ; 114 SetStruct<Module.Dependence> requiresStruct; 115 MapStruct<Module.Exported> exportsMapStruct; 116 MapStruct<Module.Opened> opensMapStruct; 117 SetStruct<Module.Uses> usesStruct; 118 MapStruct<Module.Provided> providesMapStruct; 119 } 120 121 /** 122 * u2 {exports|opens}_count; 123 * { u2 {exports|opens}_index; 124 * u2 {exports|opens}_flags; 125 * u2 {exports|opens}_to_count; 126 * u2 {exports|opens}_to_index[{exports|opens}_to_count]; 127 * } {exports|opens}[{exports|opens}_count]; 128 * or 129 * u2 provides_count; 130 * { u2 provides_index; 131 * u2 provides_with_count; 132 * u2 provides_with_index[provides_with_count]; 133 * } provides[provides_count]; 134 */ 135 private class MapStruct<T extends Module.TargetType> implements Data { 136 final List<Triplet<ConstantPool.ConstCell, Integer, List<ConstantPool.ConstCell>>> exportsOpensList = new ArrayList<>(); 137 final List<Pair<ConstantPool.ConstCell, List<ConstantPool.ConstCell>>> providesList = new ArrayList<>(); 138 139 MapStruct(Map<T, Set<String>> source, 140 Function<String,ConstantPool.ConstCell> nameFinder, 141 Function<String,ConstantPool.ConstCell> targetFinder) { 142 Objects.requireNonNull(source); 143 source.entrySet().stream() 144 .sorted(Map.Entry.comparingByKey()) 145 .forEach(e -> { 146 ArrayList<ConstantPool.ConstCell> to = new ArrayList<>(); 147 e.getValue().forEach(mn -> to.add(targetFinder.apply(mn))); 148 if (e.getKey().isFlagged()) { 149 exportsOpensList.add(new Triplet<> 150 ( nameFinder.apply(e.getKey().getTypeName()), 151 ((Module.FlaggedTargetType) e.getKey()).getFlags(), 152 to)); 153 } else { 154 providesList.add(new Pair<>(nameFinder.apply(e.getKey().getTypeName()), 155 to)); 156 } 157 } 158 ); 159 } 160 161 @Override 162 public void write(CheckedDataOutputStream out) throws IOException { 163 if (providesList.isEmpty()) { 164 out.writeShort(exportsOpensList.size()); // u2 {exports|opens}_count; 165 for (Triplet<ConstantPool.ConstCell, Integer, List<ConstantPool.ConstCell>> triplet : exportsOpensList) { 166 out.writeShort(triplet.first.arg); // { u2 {exports|opens}_index; 167 out.writeShort(triplet.second); // u2 {exports|opens}_flags; 168 out.writeShort(triplet.third.size()); // u2 {exports|opens}_to_count; 169 for (ConstantPool.ConstCell to : triplet.third) 170 out.writeShort(to.arg); // u2 {exports|opens}_to_index[{exports|opens}_to_count]; } 171 } 172 } else { 173 out.writeShort(providesList.size()); // u2 provides_count; 174 for (Pair<ConstantPool.ConstCell, List<ConstantPool.ConstCell>> pair : providesList) { 175 out.writeShort(pair.first.arg); // { u2 provides_index; 176 out.writeShort(pair.second.size()); // u2 provides_with_count; 177 for (ConstantPool.ConstCell to : pair.second) 178 out.writeShort(to.arg); // u2 provides_with_index[provides_with_count]; } 179 } 180 } 181 } 182 183 @Override 184 public int getLength() { 185 if (providesList.isEmpty()) { 186 // (u2:{exports|opens}_count) + (u2:{exports|opens}_index + u2:{exports|opens}_flags u2:{exports|opens}_to_count) * {exports|opens}_count + 187 return 2 + 6 * exportsOpensList.size() + 188 // (u2:{exports|opens}_to_index) * {exports|opens}_to_count 189 exportsOpensList.stream().mapToInt(p -> p.third.size()).filter(s -> s > 0).sum() * 2; 190 } else { 191 // (u2 : provides_count) + (u2:provides_index + u2:provides_with_count) * provides_count + 192 return 2 + 4 * providesList.size() + 193 // (u2:provides_with_index) * provides_with_count 194 providesList.stream().mapToInt(p -> p.second.size()).filter(s -> s > 0).sum() * 2; 195 } 196 } 197 } 198 199 private class HeaderStruct implements Data { 200 final ConstantPool.ConstCell index; 201 final int flags; 202 final ConstantPool.ConstCell versionIndex; 203 204 HeaderStruct(Module.Header source, 205 Function<String,ConstantPool.ConstCell> nameFinder, 206 Function<String,ConstantPool.ConstCell> versionFinder) { 207 index = nameFinder.apply(source.getModuleName()); 208 versionIndex = (source.getModuleVersion() == null ) ? null : versionFinder.apply(source.getModuleVersion()); 209 flags = source.getModuleFlags(); 210 } 211 212 @Override 213 public void write(CheckedDataOutputStream out) throws IOException { 214 out.writeShort(index.arg); // u2 module_name_index; 215 out.writeShort(flags); // u2 module_flags; 216 out.writeShort(versionIndex == null ? 0 : versionIndex.arg); // u2 module_version_index; 217 } 218 219 @Override 220 public int getLength() { 221 // u2:module_name_index) + u2:module_flags +u2:module_version_index 222 return 6; 223 } 224 } 225 226 /** 227 * u2 uses_count; 228 * u2 uses_index[uses_count]; 229 * or 230 * u2 requires_count; 231 * { u2 requires_index; 232 * u2 requires_flags; 233 * u2 requires_version_index; 234 * } requires[requires_count]; 235 */ 236 private class SetStruct<T extends Module.TargetType> implements Data { 237 final List<ConstantPool.ConstCell> usesList = new ArrayList<>(); 238 final List<Triplet<ConstantPool.ConstCell, Integer, ConstantPool.ConstCell>> requiresList = new ArrayList<>(); 239 240 SetStruct(Set<T> source, 241 Function<String,ConstantPool.ConstCell> nameFinder, 242 Function<String,ConstantPool.ConstCell> versionFinder) { 243 Objects.requireNonNull(source); 244 source.forEach(e -> { 245 if (e.isFlagged()) { 246 requiresList.add(new Triplet<>( 247 nameFinder.apply(e.getTypeName()), 248 ((Module.FlaggedTargetType) e).getFlags(), 249 (((Module.VersionedFlaggedTargetType) e).getVersion() == null) ? 250 null : 251 versionFinder.apply(((Module.VersionedFlaggedTargetType) e).getVersion()))); 252 } else { 253 usesList.add(nameFinder.apply((e.getTypeName()))); 254 } 255 }); 256 } 257 258 @Override 259 public void write(CheckedDataOutputStream out) throws IOException { 260 if (usesList.isEmpty()) { 261 out.writeShort(requiresList.size()); // u2 requires_count; 262 for (Triplet<ConstantPool.ConstCell, Integer, ConstantPool.ConstCell> r : requiresList) { 263 out.writeShort(r.first.arg); // u2 requires_index; 264 out.writeShort(r.second); // u2 requires_flags; 265 out.writeShort(r.third == null ? 0 : r.third.arg); // u2 requires_version_index; 266 } 267 } else { 268 out.writeShort(usesList.size()); // u2 uses_count; 269 for (ConstantPool.ConstCell u : usesList) 270 out.writeShort(u.arg); // u2 uses_index[uses_count]; 271 } 272 } 273 274 @Override 275 public int getLength() { 276 return usesList.isEmpty() ? 277 // (u2:requires_count) + (u2:requires_index + u2:requires_flags + u2:requires_version_index) * requires_count 278 2 + 6 * requiresList.size() : 279 // (u2:uses_count) + (u2:uses_index) * uses_count 280 2 + 2 * usesList.size(); 281 } 282 } 283 284 // Helper classes 285 private class Pair<F, S> { 286 final F first; 287 final S second; 288 289 Pair(F first, S second) { 290 this.first = first; 291 this.second = second; 292 } 293 } 294 295 public class Triplet<F, S, T> extends Pair<F,S> { 296 private final T third; 297 Triplet(F first, S second, T third) { 298 super(first,second); 299 this.third = third; 300 } 301 } 302 303 }