Store class names in metadata as a pair of package and simple name

This commit is contained in:
Alexey Andreev 2018-10-03 16:01:37 +03:00
parent 0a94c91ff2
commit 681e21ecca
2 changed files with 120 additions and 22 deletions

View File

@ -20,8 +20,10 @@ import com.carrotsearch.hppc.ObjectIntMap;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import java.util.stream.Collectors;
@ -487,22 +489,17 @@ public class Renderer implements RenderingManager {
}
private void renderClassMetadata(List<ClassNode> classes) {
Set<String> classesRequiringName = new HashSet<>();
MethodDependencyInfo getNameMethod = context.getDependencyInfo().getMethod(
new MethodReference(Class.class, "getName", String.class));
if (getNameMethod != null) {
classesRequiringName.addAll(Arrays.asList(getNameMethod.getVariable(0).getClassValueNode().getTypes()));
}
MethodDependencyInfo getSimpleNameMethod = context.getDependencyInfo().getMethod(
new MethodReference(Class.class, "getSimpleName", String.class));
if (getSimpleNameMethod != null) {
classesRequiringName.addAll(Arrays.asList(
getSimpleNameMethod.getVariable(0).getClassValueNode().getTypes()));
if (classes.isEmpty()) {
return;
}
Set<String> classesRequiringName = findClassesRequiringName();
int start = writer.getOffset();
try {
writer.append("$rt_metadata([");
ObjectIntMap<String> packageIndexes = generatePackageMetadata(classes, classesRequiringName);
boolean first = true;
for (ClassNode cls : classes) {
if (!first) {
@ -512,7 +509,12 @@ public class Renderer implements RenderingManager {
writer.appendClass(cls.getName()).append(",").ws();
if (classesRequiringName.contains(cls.getName())) {
writer.append("\"").append(RenderingUtil.escapeString(cls.getName())).append("\"");
String className = cls.getName();
int dotIndex = className.lastIndexOf('.') + 1;
String packageName = className.substring(0, dotIndex);
className = className.substring(dotIndex);
writer.append("\"").append(RenderingUtil.escapeString(className)).append("\"").append(",").ws();
writer.append(String.valueOf(packageIndexes.getOrDefault(packageName, -1)));
} else {
writer.append("0");
}
@ -566,6 +568,85 @@ public class Renderer implements RenderingManager {
metadataSize = writer.getOffset() - start;
}
private ObjectIntMap<String> generatePackageMetadata(List<ClassNode> classes, Set<String> classesRequiringName)
throws IOException {
PackageNode root = new PackageNode(null);
for (ClassNode classNode : classes) {
String className = classNode.getName();
if (!classesRequiringName.contains(className)) {
continue;
}
int dotIndex = className.lastIndexOf('.');
if (dotIndex < 0) {
continue;
}
addPackageName(root, className.substring(0, dotIndex));
}
ObjectIntMap<String> indexes = new ObjectIntHashMap<>();
writer.append(String.valueOf(root.count())).append(",").ws();
writePackageStructure(root, -1, "", indexes);
writer.softNewLine();
return indexes;
}
private int writePackageStructure(PackageNode node, int startIndex, String prefix, ObjectIntMap<String> indexes)
throws IOException {
int index = startIndex;
for (PackageNode child : node.children.values()) {
writer.append(String.valueOf(startIndex)).append(",").ws()
.append("\"").append(RenderingUtil.escapeString(child.name)).append("\",").ws();
String fullName = prefix + child.name + ".";
++index;
indexes.put(fullName, index);
index = writePackageStructure(child, index, fullName, indexes);
}
return index;
}
static class PackageNode {
String name;
Map<String, PackageNode> children = new HashMap<>();
PackageNode(String name) {
this.name = name;
}
int count() {
int result = 0;
for (PackageNode child : children.values()) {
result += 1 + child.count();
}
return result;
}
}
private void addPackageName(PackageNode node, String name) {
String[] parts = name.split("\\.");
for (String part : parts) {
node = node.children.computeIfAbsent(part, PackageNode::new);
}
}
private Set<String> findClassesRequiringName() {
Set<String> classesRequiringName = new HashSet<>();
MethodDependencyInfo getNameMethod = context.getDependencyInfo().getMethod(
new MethodReference(Class.class, "getName", String.class));
if (getNameMethod != null) {
classesRequiringName.addAll(Arrays.asList(getNameMethod.getVariable(0).getClassValueNode().getTypes()));
}
MethodDependencyInfo getSimpleNameMethod = context.getDependencyInfo().getMethod(
new MethodReference(Class.class, "getSimpleName", String.class));
if (getSimpleNameMethod != null) {
classesRequiringName.addAll(Arrays.asList(
getSimpleNameMethod.getVariable(0).getClassValueNode().getTypes()));
}
return classesRequiringName;
}
private void collectMethodsToCopyFromInterfaces(ClassReader cls, List<MethodReference> targetList) {
Set<MethodDescriptor> implementedMethods = new HashSet<>();
implementedMethods.addAll(targetList.stream().map(method -> method.getDescriptor())

View File

@ -429,23 +429,40 @@ function $rt_putStderr(ch) {
}
}
function $rt_metadata(data) {
for (var i = 0; i < data.length; i += 8) {
var cls = data[i];
var i = 0;
var packageCount = data[i++];
var packages = new Array(packageCount);
for (var j = 0; j < packageCount; ++j) {
var prefixIndex = data[i++];
var prefix = prefixIndex >= 0 ? packages[prefixIndex] : "";
packages[j] = prefix + data[i++] + ".";
}
while (i < data.length) {
var cls = data[i++];
cls.$meta = {};
var m = cls.$meta;
var className = data[i + 1];
var className = data[i++];
m.name = className !== 0 ? className : null;
if (m.name !== null) {
var packageIndex = data[i++];
if (packageIndex >= 0) {
m.name = packages[packageIndex] + m.name;
}
}
m.binaryName = "L" + m.name + ";";
var superclass = data[i + 2];
var superclass = data[i++];
m.superclass = superclass !== 0 ? superclass : null;
m.supertypes = data[i + 3];
m.supertypes = data[i++];
if (m.superclass) {
m.supertypes.push(m.superclass);
cls.prototype = Object.create(m.superclass.prototype);
} else {
cls.prototype = {};
}
var flags = data[i + 4];
var flags = data[i++];
m.enum = (flags & 16) !== 0;
m.flags = flags;
m.primitive = false;
@ -453,13 +470,13 @@ function $rt_metadata(data) {
cls.prototype.constructor = cls;
cls.classObject = null;
m.accessLevel = data[i + 5];
m.accessLevel = data[i++];
var clinit = data[i + 6];
var clinit = data[i++];
cls.$clinit = clinit !== 0 ? clinit : function() {};
var virtualMethods = data[i + 7];
for (var j = 0; j < virtualMethods.length; j += 2) {
var virtualMethods = data[i++];
for (j = 0; j < virtualMethods.length; j += 2) {
var name = virtualMethods[j];
var func = virtualMethods[j + 1];
if (typeof name === 'string') {