304 lines
12 KiB
Java
304 lines
12 KiB
Java
/*
|
|
* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
|
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
|
*
|
|
* This code is free software; you can redistribute it and/or modify it
|
|
* under the terms of the GNU General Public License version 2 only, as
|
|
* published by the Free Software Foundation.
|
|
*
|
|
* This code is distributed in the hope that it will be useful, but WITHOUT
|
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
|
* version 2 for more details (a copy is included in the LICENSE file that
|
|
* accompanied this code).
|
|
*
|
|
* You should have received a copy of the GNU General Public License version
|
|
* 2 along with this work; if not, write to the Free Software Foundation,
|
|
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
*
|
|
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
|
* or visit www.oracle.com if you need additional information or have any
|
|
* questions.
|
|
*/
|
|
package org.openjdk.asmtools.jasm;
|
|
|
|
import org.openjdk.asmtools.common.Module;
|
|
|
|
import java.io.IOException;
|
|
import java.util.*;
|
|
import java.util.function.BiConsumer;
|
|
import java.util.function.Consumer;
|
|
import java.util.function.Function;
|
|
|
|
/**
|
|
* The module attribute
|
|
*/
|
|
class ModuleAttr extends AttrData {
|
|
// shared data
|
|
private Module.Builder builder;
|
|
private final ClassData clsData;
|
|
private final Function<String, ConstantPool.ConstCell> findCellAsciz;
|
|
private final Function<String, ConstantPool.ConstCell> findCellClassByName;
|
|
private final Function<String, ConstantPool.ConstCell> findCellModuleByName;
|
|
private final Function<String, ConstantPool.ConstCell> findCellPackageByName;
|
|
|
|
// entries to populate tables of the module attribute
|
|
BiConsumer<String, Integer> requires = (mn, f) -> this.builder.require(mn, f);
|
|
BiConsumer<String, Set<String>> exports = (pn, ms) -> this.builder.exports(new Module.Exported(pn), ms);
|
|
BiConsumer<String, Set<String>> opens = (pn, ms) -> this.builder.opens(new Module.Opened(pn), ms);
|
|
BiConsumer<String, Set<String>> provides = (tn, ts) -> this.builder.provides(new Module.Provided(tn), ts);
|
|
Consumer<Set<String>> uses = (ts) -> this.builder.uses(ts);
|
|
|
|
ModuleAttr(ClassData cdata) {
|
|
super(cdata, Tables.AttrTag.ATT_Module.parsekey());
|
|
builder = new Module.Builder();
|
|
clsData = cdata;
|
|
findCellAsciz = (name) -> clsData.pool.FindCellAsciz(name);
|
|
findCellClassByName = (name) -> clsData.pool.FindCellClassByName(name);
|
|
findCellModuleByName = (name) -> clsData.pool.FindCellModuleByName(name);
|
|
findCellPackageByName = (name) -> clsData.pool.FindCellPackageByName(name);
|
|
}
|
|
|
|
void openModule() {
|
|
builder.setModuleFlags(Module.Modifier.ACC_OPEN);
|
|
}
|
|
void setModuleName(String value) { builder.setModuleName(value);}
|
|
|
|
ModuleAttr build() {
|
|
Module module = builder.build();
|
|
Content.instance.header = new HeaderStruct(module.header, findCellModuleByName, findCellAsciz);
|
|
Content.instance.requiresStruct = new SetStruct<>(module.requires, findCellModuleByName, findCellAsciz);
|
|
Content.instance.exportsMapStruct = new MapStruct<>(module.exports, findCellPackageByName, findCellModuleByName );
|
|
Content.instance.opensMapStruct = new MapStruct<>(module.opens,findCellPackageByName, findCellModuleByName );
|
|
Content.instance.usesStruct = new SetStruct<>(module.uses, findCellClassByName, null);
|
|
Content.instance.providesMapStruct = new MapStruct<>(module.provides, findCellClassByName, findCellClassByName);
|
|
return this;
|
|
}
|
|
|
|
@Override
|
|
public int attrLength() {
|
|
return Content.instance.getLength();
|
|
}
|
|
|
|
@Override
|
|
public void write(CheckedDataOutputStream out) throws IOException {
|
|
super.write(out);
|
|
Content.instance.write(out);
|
|
}
|
|
|
|
private enum Content implements Data {
|
|
instance {
|
|
@Override
|
|
public int getLength() {
|
|
return header.getLength() +
|
|
requiresStruct.getLength() +
|
|
exportsMapStruct.getLength() +
|
|
opensMapStruct.getLength() +
|
|
usesStruct.getLength() +
|
|
providesMapStruct.getLength();
|
|
}
|
|
|
|
@Override
|
|
public void write(CheckedDataOutputStream out) throws IOException {
|
|
// keep order!
|
|
header.write(out);
|
|
requiresStruct.write(out);
|
|
exportsMapStruct.write(out);
|
|
opensMapStruct.write(out);
|
|
usesStruct.write(out);
|
|
providesMapStruct.write(out);
|
|
}
|
|
};
|
|
|
|
HeaderStruct header ;
|
|
SetStruct<Module.Dependence> requiresStruct;
|
|
MapStruct<Module.Exported> exportsMapStruct;
|
|
MapStruct<Module.Opened> opensMapStruct;
|
|
SetStruct<Module.Uses> usesStruct;
|
|
MapStruct<Module.Provided> providesMapStruct;
|
|
}
|
|
|
|
/**
|
|
* u2 {exports|opens}_count;
|
|
* { u2 {exports|opens}_index;
|
|
* u2 {exports|opens}_flags;
|
|
* u2 {exports|opens}_to_count;
|
|
* u2 {exports|opens}_to_index[{exports|opens}_to_count];
|
|
* } {exports|opens}[{exports|opens}_count];
|
|
* or
|
|
* u2 provides_count;
|
|
* { u2 provides_index;
|
|
* u2 provides_with_count;
|
|
* u2 provides_with_index[provides_with_count];
|
|
* } provides[provides_count];
|
|
*/
|
|
private class MapStruct<T extends Module.TargetType> implements Data {
|
|
final List<Triplet<ConstantPool.ConstCell, Integer, List<ConstantPool.ConstCell>>> exportsOpensList = new ArrayList<>();
|
|
final List<Pair<ConstantPool.ConstCell, List<ConstantPool.ConstCell>>> providesList = new ArrayList<>();
|
|
|
|
MapStruct(Map<T, Set<String>> source,
|
|
Function<String,ConstantPool.ConstCell> nameFinder,
|
|
Function<String,ConstantPool.ConstCell> targetFinder) {
|
|
Objects.requireNonNull(source);
|
|
source.entrySet().stream()
|
|
.sorted(Map.Entry.comparingByKey())
|
|
.forEach(e -> {
|
|
ArrayList<ConstantPool.ConstCell> to = new ArrayList<>();
|
|
e.getValue().forEach(mn -> to.add(targetFinder.apply(mn)));
|
|
if (e.getKey().isFlagged()) {
|
|
exportsOpensList.add(new Triplet<>
|
|
( nameFinder.apply(e.getKey().getTypeName()),
|
|
((Module.FlaggedTargetType) e.getKey()).getFlags(),
|
|
to));
|
|
} else {
|
|
providesList.add(new Pair<>(nameFinder.apply(e.getKey().getTypeName()),
|
|
to));
|
|
}
|
|
}
|
|
);
|
|
}
|
|
|
|
@Override
|
|
public void write(CheckedDataOutputStream out) throws IOException {
|
|
if (providesList.isEmpty()) {
|
|
out.writeShort(exportsOpensList.size()); // u2 {exports|opens}_count;
|
|
for (Triplet<ConstantPool.ConstCell, Integer, List<ConstantPool.ConstCell>> triplet : exportsOpensList) {
|
|
out.writeShort(triplet.first.arg); // { u2 {exports|opens}_index;
|
|
out.writeShort(triplet.second); // u2 {exports|opens}_flags;
|
|
out.writeShort(triplet.third.size()); // u2 {exports|opens}_to_count;
|
|
for (ConstantPool.ConstCell to : triplet.third)
|
|
out.writeShort(to.arg); // u2 {exports|opens}_to_index[{exports|opens}_to_count]; }
|
|
}
|
|
} else {
|
|
out.writeShort(providesList.size()); // u2 provides_count;
|
|
for (Pair<ConstantPool.ConstCell, List<ConstantPool.ConstCell>> pair : providesList) {
|
|
out.writeShort(pair.first.arg); // { u2 provides_index;
|
|
out.writeShort(pair.second.size()); // u2 provides_with_count;
|
|
for (ConstantPool.ConstCell to : pair.second)
|
|
out.writeShort(to.arg); // u2 provides_with_index[provides_with_count]; }
|
|
}
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public int getLength() {
|
|
if (providesList.isEmpty()) {
|
|
// (u2:{exports|opens}_count) + (u2:{exports|opens}_index + u2:{exports|opens}_flags u2:{exports|opens}_to_count) * {exports|opens}_count +
|
|
return 2 + 6 * exportsOpensList.size() +
|
|
// (u2:{exports|opens}_to_index) * {exports|opens}_to_count
|
|
exportsOpensList.stream().mapToInt(p -> p.third.size()).filter(s -> s > 0).sum() * 2;
|
|
} else {
|
|
// (u2 : provides_count) + (u2:provides_index + u2:provides_with_count) * provides_count +
|
|
return 2 + 4 * providesList.size() +
|
|
// (u2:provides_with_index) * provides_with_count
|
|
providesList.stream().mapToInt(p -> p.second.size()).filter(s -> s > 0).sum() * 2;
|
|
}
|
|
}
|
|
}
|
|
|
|
private class HeaderStruct implements Data {
|
|
final ConstantPool.ConstCell index;
|
|
final int flags;
|
|
final ConstantPool.ConstCell versionIndex;
|
|
|
|
HeaderStruct(Module.Header source,
|
|
Function<String,ConstantPool.ConstCell> nameFinder,
|
|
Function<String,ConstantPool.ConstCell> versionFinder) {
|
|
index = nameFinder.apply(source.getModuleName());
|
|
versionIndex = (source.getModuleVersion() == null ) ? null : versionFinder.apply(source.getModuleVersion());
|
|
flags = source.getModuleFlags();
|
|
}
|
|
|
|
@Override
|
|
public void write(CheckedDataOutputStream out) throws IOException {
|
|
out.writeShort(index.arg); // u2 module_name_index;
|
|
out.writeShort(flags); // u2 module_flags;
|
|
out.writeShort(versionIndex == null ? 0 : versionIndex.arg); // u2 module_version_index;
|
|
}
|
|
|
|
@Override
|
|
public int getLength() {
|
|
// u2:module_name_index) + u2:module_flags +u2:module_version_index
|
|
return 6;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* u2 uses_count;
|
|
* u2 uses_index[uses_count];
|
|
* or
|
|
* u2 requires_count;
|
|
* { u2 requires_index;
|
|
* u2 requires_flags;
|
|
* u2 requires_version_index;
|
|
* } requires[requires_count];
|
|
*/
|
|
private class SetStruct<T extends Module.TargetType> implements Data {
|
|
final List<ConstantPool.ConstCell> usesList = new ArrayList<>();
|
|
final List<Triplet<ConstantPool.ConstCell, Integer, ConstantPool.ConstCell>> requiresList = new ArrayList<>();
|
|
|
|
SetStruct(Set<T> source,
|
|
Function<String,ConstantPool.ConstCell> nameFinder,
|
|
Function<String,ConstantPool.ConstCell> versionFinder) {
|
|
Objects.requireNonNull(source);
|
|
source.forEach(e -> {
|
|
if (e.isFlagged()) {
|
|
requiresList.add(new Triplet<>(
|
|
nameFinder.apply(e.getTypeName()),
|
|
((Module.FlaggedTargetType) e).getFlags(),
|
|
(((Module.VersionedFlaggedTargetType) e).getVersion() == null) ?
|
|
null :
|
|
versionFinder.apply(((Module.VersionedFlaggedTargetType) e).getVersion())));
|
|
} else {
|
|
usesList.add(nameFinder.apply((e.getTypeName())));
|
|
}
|
|
});
|
|
}
|
|
|
|
@Override
|
|
public void write(CheckedDataOutputStream out) throws IOException {
|
|
if (usesList.isEmpty()) {
|
|
out.writeShort(requiresList.size()); // u2 requires_count;
|
|
for (Triplet<ConstantPool.ConstCell, Integer, ConstantPool.ConstCell> r : requiresList) {
|
|
out.writeShort(r.first.arg); // u2 requires_index;
|
|
out.writeShort(r.second); // u2 requires_flags;
|
|
out.writeShort(r.third == null ? 0 : r.third.arg); // u2 requires_version_index;
|
|
}
|
|
} else {
|
|
out.writeShort(usesList.size()); // u2 uses_count;
|
|
for (ConstantPool.ConstCell u : usesList)
|
|
out.writeShort(u.arg); // u2 uses_index[uses_count];
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public int getLength() {
|
|
return usesList.isEmpty() ?
|
|
// (u2:requires_count) + (u2:requires_index + u2:requires_flags + u2:requires_version_index) * requires_count
|
|
2 + 6 * requiresList.size() :
|
|
// (u2:uses_count) + (u2:uses_index) * uses_count
|
|
2 + 2 * usesList.size();
|
|
}
|
|
}
|
|
|
|
// Helper classes
|
|
private class Pair<F, S> {
|
|
final F first;
|
|
final S second;
|
|
|
|
Pair(F first, S second) {
|
|
this.first = first;
|
|
this.second = second;
|
|
}
|
|
}
|
|
|
|
public class Triplet<F, S, T> extends Pair<F,S> {
|
|
private final T third;
|
|
Triplet(F first, S second, T third) {
|
|
super(first,second);
|
|
this.third = third;
|
|
}
|
|
}
|
|
|
|
}
|