Wasm: don't generate class metadata if it's not used. Don't generate names and call site metadata in minified mode

This commit is contained in:
Alexey Andreev 2020-02-21 17:29:31 +03:00
parent 3f2c52000f
commit 0e7c1e5ef9
6 changed files with 90 additions and 54 deletions

View File

@ -129,6 +129,7 @@ import org.teavm.model.MethodReader;
import org.teavm.model.MethodReference;
import org.teavm.model.Program;
import org.teavm.model.ValueType;
import org.teavm.model.analysis.ClassMetadataRequirements;
import org.teavm.model.classes.TagRegistry;
import org.teavm.model.classes.VirtualTableBuilder;
import org.teavm.model.classes.VirtualTableProvider;
@ -184,6 +185,7 @@ public class WasmTarget implements TeaVMTarget, TeaVMWasmHost {
private CheckInstructionTransformation checkTransformation = new CheckInstructionTransformation();
private int minHeapSize = 2 * 1024 * 1024;
private int maxHeapSize = 128 * 1024 * 1024;
private boolean obfuscated;
@Override
public void setController(TeaVMTargetController controller) {
@ -272,6 +274,10 @@ public class WasmTarget implements TeaVMTarget, TeaVMWasmHost {
this.maxHeapSize = maxHeapSize;
}
public void setObfuscated(boolean obfuscated) {
this.obfuscated = obfuscated;
}
@Override
public void contributeDependencies(DependencyAnalyzer dependencyAnalyzer) {
for (Class<?> type : Arrays.asList(int.class, long.class, float.class, double.class)) {
@ -374,8 +380,10 @@ public class WasmTarget implements TeaVMTarget, TeaVMWasmHost {
BinaryWriter binaryWriter = new BinaryWriter(256);
NameProvider names = new NameProviderWithSpecialNames(new WasmNameProvider(),
controller.getUnprocessedClassSource());
ClassMetadataRequirements metadataRequirements = new ClassMetadataRequirements(controller.getDependencyInfo());
WasmClassGenerator classGenerator = new WasmClassGenerator(classes, controller.getUnprocessedClassSource(),
vtableProvider, tagRegistry, binaryWriter, names);
vtableProvider, tagRegistry, binaryWriter, names, metadataRequirements,
controller.getClassInitializerInfo());
Decompiler decompiler = new Decompiler(classes, new HashSet<>(), false);
WasmStringPool stringPool = classGenerator.getStringPool();
@ -417,7 +425,7 @@ public class WasmTarget implements TeaVMTarget, TeaVMWasmHost {
context.addIntrinsic(mutatorIntrinsic);
context.addIntrinsic(new ShadowStackIntrinsic());
ExceptionHandlingIntrinsic exceptionHandlingIntrinsic = new ExceptionHandlingIntrinsic(binaryWriter,
classGenerator, stringPool);
classGenerator, stringPool, obfuscated);
context.addIntrinsic(exceptionHandlingIntrinsic);
WasmGenerator generator = new WasmGenerator(decompiler, classes, context, classGenerator, binaryWriter);
@ -471,7 +479,7 @@ public class WasmTarget implements TeaVMTarget, TeaVMWasmHost {
}
WasmBinaryWriter writer = new WasmBinaryWriter();
WasmBinaryRenderer renderer = new WasmBinaryRenderer(writer, version);
WasmBinaryRenderer renderer = new WasmBinaryRenderer(writer, version, obfuscated);
renderer.render(module);
try (OutputStream output = buildTarget.createResource(outputName)) {

View File

@ -62,11 +62,14 @@ public class CallSiteBinaryGenerator {
private WasmClassGenerator classGenerator;
private WasmStringPool stringPool;
private ObjectIntMap<String> stringIndirectPointerCache = new ObjectIntHashMap<>();
private boolean obfuscated;
public CallSiteBinaryGenerator(BinaryWriter writer, WasmClassGenerator classGenerator, WasmStringPool stringPool) {
public CallSiteBinaryGenerator(BinaryWriter writer, WasmClassGenerator classGenerator, WasmStringPool stringPool,
boolean obfuscated) {
this.writer = writer;
this.classGenerator = classGenerator;
this.stringPool = stringPool;
this.obfuscated = obfuscated;
}
public int writeCallSites(List<? extends CallSiteDescriptor> callSites) {
@ -120,52 +123,60 @@ public class CallSiteBinaryGenerator {
}
}
CallSiteLocation[] locations = callSite.getLocations();
LocationList prevList = null;
int locationAddress = 0;
int previousLocationAddress = 0;
for (int i = locations.length - 1; i >= 0; --i) {
LocationList list = new LocationList(locations[i], prevList);
locationAddress = locationCache.getOrDefault(list, 0);
if (locationAddress == 0) {
DataValue binaryLocation = locationStructure.createValue();
locationAddress = writer.append(binaryLocation);
locationCache.put(list, locationAddress);
CallSiteLocation location = list.location;
MethodLocation methodLocation = new MethodLocation(location.getFileName(), location.getClassName(),
location.getMethodName());
int methodLocationAddress = methodLocationCache.getOrDefault(methodLocation, -1);
if (methodLocationAddress < 0) {
DataValue binaryMethodLocation = methodLocationStructure.createValue();
methodLocationAddress = writer.append(binaryMethodLocation);
methodLocationCache.put(methodLocation, methodLocationAddress);
if (location.getFileName() != null) {
binaryMethodLocation.setAddress(METHOD_LOCATION_FILE,
getStringIndirectPointer(location.getFileName()));
}
if (location.getClassName() != null) {
binaryMethodLocation.setAddress(METHOD_LOCATION_CLASS,
getStringIndirectPointer(location.getClassName()));
}
if (location.getMethodName() != null) {
binaryMethodLocation.setAddress(METHOD_LOCATION_METHOD,
getStringIndirectPointer(location.getMethodName()));
}
}
binaryLocation.setAddress(LOCATION_METHOD, methodLocationAddress);
binaryLocation.setInt(LOCATION_LINE, location.getLineNumber());
binaryLocation.setAddress(LOCATION_NEXT, previousLocationAddress);
}
previousLocationAddress = locationAddress;
if (!obfuscated) {
binaryCallSite.setAddress(CALL_SITE_LOCATION,
generateLocations(methodLocationCache, locationCache, callSite));
}
binaryCallSite.setAddress(CALL_SITE_LOCATION, locationAddress);
}
return firstCallSite;
}
private int generateLocations(ObjectIntMap<MethodLocation> methodLocationCache,
ObjectIntMap<LocationList> locationCache, CallSiteDescriptor callSite) {
CallSiteLocation[] locations = callSite.getLocations();
LocationList prevList = null;
int locationAddress = 0;
int previousLocationAddress = 0;
for (int i = locations.length - 1; i >= 0; --i) {
LocationList list = new LocationList(locations[i], prevList);
locationAddress = locationCache.getOrDefault(list, 0);
if (locationAddress == 0) {
DataValue binaryLocation = locationStructure.createValue();
locationAddress = writer.append(binaryLocation);
locationCache.put(list, locationAddress);
CallSiteLocation location = list.location;
MethodLocation methodLocation = new MethodLocation(location.getFileName(),
location.getClassName(), location.getMethodName());
int methodLocationAddress = methodLocationCache.getOrDefault(methodLocation, -1);
if (methodLocationAddress < 0) {
DataValue binaryMethodLocation = methodLocationStructure.createValue();
methodLocationAddress = writer.append(binaryMethodLocation);
methodLocationCache.put(methodLocation, methodLocationAddress);
if (location.getFileName() != null) {
binaryMethodLocation.setAddress(METHOD_LOCATION_FILE,
getStringIndirectPointer(location.getFileName()));
}
if (location.getClassName() != null) {
binaryMethodLocation.setAddress(METHOD_LOCATION_CLASS,
getStringIndirectPointer(location.getClassName()));
}
if (location.getMethodName() != null) {
binaryMethodLocation.setAddress(METHOD_LOCATION_METHOD,
getStringIndirectPointer(location.getMethodName()));
}
}
binaryLocation.setAddress(LOCATION_METHOD, methodLocationAddress);
binaryLocation.setInt(LOCATION_LINE, location.getLineNumber());
binaryLocation.setAddress(LOCATION_NEXT, previousLocationAddress);
}
previousLocationAddress = locationAddress;
}
return locationAddress;
}
private int getStringIndirectPointer(String str) {
int result = stringIndirectPointerCache.getOrDefault(str, -1);
if (result < 0) {

View File

@ -43,6 +43,8 @@ import org.teavm.model.FieldReference;
import org.teavm.model.MethodDescriptor;
import org.teavm.model.MethodReference;
import org.teavm.model.ValueType;
import org.teavm.model.analysis.ClassInitializerInfo;
import org.teavm.model.analysis.ClassMetadataRequirements;
import org.teavm.model.classes.TagRegistry;
import org.teavm.model.classes.VirtualTable;
import org.teavm.model.classes.VirtualTableEntry;
@ -91,6 +93,8 @@ public class WasmClassGenerator {
private int staticGcRootsAddress;
private int classesAddress;
private int classCount;
private ClassMetadataRequirements metadataRequirements;
private ClassInitializerInfo classInitializerInfo;
private static final int CLASS_SIZE = 1;
private static final int CLASS_FLAGS = 2;
@ -110,7 +114,8 @@ public class WasmClassGenerator {
public WasmClassGenerator(ClassReaderSource processedClassSource, ClassReaderSource classSource,
VirtualTableProvider vtableProvider, TagRegistry tagRegistry, BinaryWriter binaryWriter,
NameProvider names) {
NameProvider names, ClassMetadataRequirements metadataRequirements,
ClassInitializerInfo classInitializerInfo) {
this.processedClassSource = processedClassSource;
this.classSource = classSource;
this.vtableProvider = vtableProvider;
@ -118,6 +123,8 @@ public class WasmClassGenerator {
this.binaryWriter = binaryWriter;
this.stringPool = new WasmStringPool(this, binaryWriter);
this.names = names;
this.metadataRequirements = metadataRequirements;
this.classInitializerInfo = classInitializerInfo;
}
public WasmStringPool getStringPool() {
@ -259,6 +266,7 @@ public class WasmClassGenerator {
: 0;
String name = ((ValueType.Object) binaryData.type).getClassName();
ClassMetadataRequirements.Info requirements = metadataRequirements.getInfo(name);
int flags = 0;
VirtualTable vtable = vtableProvider.lookup(name);
@ -279,7 +287,8 @@ public class WasmClassGenerator {
int tag = ranges.stream().mapToInt(range -> range.lower).min().orElse(0);
header.setInt(CLASS_TAG, tag);
header.setInt(CLASS_CANARY, RuntimeClass.computeCanary(occupiedSize, tag));
header.setAddress(CLASS_NAME, stringPool.getStringPointer(name));
int nameAddress = requirements.name() ? stringPool.getStringPointer(name) : 0;
header.setAddress(CLASS_NAME, nameAddress);
header.setInt(CLASS_IS_INSTANCE, functionTable.size());
functionTable.add(names.forSupertypeFunction(ValueType.object(name)));
header.setAddress(CLASS_PARENT, parentPtr);
@ -287,14 +296,16 @@ public class WasmClassGenerator {
ClassReader cls = processedClassSource.get(name);
if (cls != null) {
if (cls.getSimpleName() != null) {
if (cls.getSimpleName() != null && requirements.simpleName()) {
header.setAddress(CLASS_SIMPLE_NAME, stringPool.getStringPointer(cls.getSimpleName()));
}
if (cls.getOwnerName() != null && processedClassSource.get(cls.getOwnerName()) != null) {
if (cls.getOwnerName() != null && processedClassSource.get(cls.getOwnerName()) != null
&& requirements.enclosingClass()) {
header.setAddress(CLASS_ENCLOSING_CLASS, getClassPointer(ValueType.object(cls.getOwnerName())));
}
if (cls.getDeclaringClassName() != null && processedClassSource.get(cls.getDeclaringClassName()) != null) {
if (cls.getDeclaringClassName() != null && processedClassSource.get(cls.getDeclaringClassName()) != null
&& requirements.declaringClass()) {
header.setAddress(CLASS_DECLARING_CLASS,
getClassPointer(ValueType.object(cls.getDeclaringClassName())));
}
@ -332,7 +343,8 @@ public class WasmClassGenerator {
}
if (cls != null && binaryData.start >= 0
&& cls.getMethod(new MethodDescriptor("<clinit>", ValueType.VOID)) != null) {
&& cls.getMethod(new MethodDescriptor("<clinit>", ValueType.VOID)) != null
&& classInitializerInfo.isDynamicInitializer(name)) {
header.setInt(CLASS_INIT, functionTable.size());
functionTable.add(names.forClassInitializer(name));
} else {

View File

@ -39,8 +39,8 @@ public class ExceptionHandlingIntrinsic implements WasmIntrinsic {
private List<WasmInt32Constant> constants = new ArrayList<>();
public ExceptionHandlingIntrinsic(BinaryWriter binaryWriter, WasmClassGenerator classGenerator,
WasmStringPool stringPool) {
callSiteBinaryGenerator = new CallSiteBinaryGenerator(binaryWriter, classGenerator, stringPool);
WasmStringPool stringPool, boolean obfuscated) {
callSiteBinaryGenerator = new CallSiteBinaryGenerator(binaryWriter, classGenerator, stringPool, obfuscated);
this.classGenerator = classGenerator;
}

View File

@ -49,10 +49,12 @@ public class WasmBinaryRenderer {
private List<WasmSignature> signatures = new ArrayList<>();
private Map<WasmSignature, Integer> signatureIndexes = new HashMap<>();
private Map<String, Integer> functionIndexes = new HashMap<>();
private boolean obfuscated;
public WasmBinaryRenderer(WasmBinaryWriter output, WasmBinaryVersion version) {
public WasmBinaryRenderer(WasmBinaryWriter output, WasmBinaryVersion version, boolean obfuscated) {
this.output = output;
this.version = version;
this.obfuscated = obfuscated;
}
public void render(WasmModule module) {
@ -73,7 +75,9 @@ public class WasmBinaryRenderer {
renderElement(module);
renderCode(module);
renderData(module);
renderNames(module);
if (!obfuscated) {
renderNames(module);
}
}
private void renderSignatures(WasmModule module) {

View File

@ -332,6 +332,7 @@ public class TeaVMTool {
webAssemblyTarget.setVersion(wasmVersion);
webAssemblyTarget.setMinHeapSize(minHeapSize);
webAssemblyTarget.setMaxHeapSize(maxHeapSize);
webAssemblyTarget.setObfuscated(minifying);
return webAssemblyTarget;
}