From 0e7c1e5ef9c45a2e616b5d877af864a47c7f0773 Mon Sep 17 00:00:00 2001 From: Alexey Andreev Date: Fri, 21 Feb 2020 17:29:31 +0300 Subject: [PATCH] Wasm: don't generate class metadata if it's not used. Don't generate names and call site metadata in minified mode --- .../org/teavm/backend/wasm/WasmTarget.java | 14 ++- .../generate/CallSiteBinaryGenerator.java | 93 +++++++++++-------- .../wasm/generate/WasmClassGenerator.java | 24 +++-- .../ExceptionHandlingIntrinsic.java | 4 +- .../wasm/render/WasmBinaryRenderer.java | 8 +- .../java/org/teavm/tooling/TeaVMTool.java | 1 + 6 files changed, 90 insertions(+), 54 deletions(-) diff --git a/core/src/main/java/org/teavm/backend/wasm/WasmTarget.java b/core/src/main/java/org/teavm/backend/wasm/WasmTarget.java index aead98dad..8d5e302ef 100644 --- a/core/src/main/java/org/teavm/backend/wasm/WasmTarget.java +++ b/core/src/main/java/org/teavm/backend/wasm/WasmTarget.java @@ -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)) { diff --git a/core/src/main/java/org/teavm/backend/wasm/generate/CallSiteBinaryGenerator.java b/core/src/main/java/org/teavm/backend/wasm/generate/CallSiteBinaryGenerator.java index 7ad1af475..fe0d02037 100644 --- a/core/src/main/java/org/teavm/backend/wasm/generate/CallSiteBinaryGenerator.java +++ b/core/src/main/java/org/teavm/backend/wasm/generate/CallSiteBinaryGenerator.java @@ -62,11 +62,14 @@ public class CallSiteBinaryGenerator { private WasmClassGenerator classGenerator; private WasmStringPool stringPool; private ObjectIntMap 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 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 methodLocationCache, + ObjectIntMap 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) { diff --git a/core/src/main/java/org/teavm/backend/wasm/generate/WasmClassGenerator.java b/core/src/main/java/org/teavm/backend/wasm/generate/WasmClassGenerator.java index 8103d9a62..799a7646f 100644 --- a/core/src/main/java/org/teavm/backend/wasm/generate/WasmClassGenerator.java +++ b/core/src/main/java/org/teavm/backend/wasm/generate/WasmClassGenerator.java @@ -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("", ValueType.VOID)) != null) { + && cls.getMethod(new MethodDescriptor("", ValueType.VOID)) != null + && classInitializerInfo.isDynamicInitializer(name)) { header.setInt(CLASS_INIT, functionTable.size()); functionTable.add(names.forClassInitializer(name)); } else { diff --git a/core/src/main/java/org/teavm/backend/wasm/intrinsics/ExceptionHandlingIntrinsic.java b/core/src/main/java/org/teavm/backend/wasm/intrinsics/ExceptionHandlingIntrinsic.java index 24e9479e3..8d1795497 100644 --- a/core/src/main/java/org/teavm/backend/wasm/intrinsics/ExceptionHandlingIntrinsic.java +++ b/core/src/main/java/org/teavm/backend/wasm/intrinsics/ExceptionHandlingIntrinsic.java @@ -39,8 +39,8 @@ public class ExceptionHandlingIntrinsic implements WasmIntrinsic { private List 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; } diff --git a/core/src/main/java/org/teavm/backend/wasm/render/WasmBinaryRenderer.java b/core/src/main/java/org/teavm/backend/wasm/render/WasmBinaryRenderer.java index 159009b92..42293ce9c 100644 --- a/core/src/main/java/org/teavm/backend/wasm/render/WasmBinaryRenderer.java +++ b/core/src/main/java/org/teavm/backend/wasm/render/WasmBinaryRenderer.java @@ -49,10 +49,12 @@ public class WasmBinaryRenderer { private List signatures = new ArrayList<>(); private Map signatureIndexes = new HashMap<>(); private Map 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) { diff --git a/tools/core/src/main/java/org/teavm/tooling/TeaVMTool.java b/tools/core/src/main/java/org/teavm/tooling/TeaVMTool.java index c8f9ae9b7..a9d796dd9 100644 --- a/tools/core/src/main/java/org/teavm/tooling/TeaVMTool.java +++ b/tools/core/src/main/java/org/teavm/tooling/TeaVMTool.java @@ -332,6 +332,7 @@ public class TeaVMTool { webAssemblyTarget.setVersion(wasmVersion); webAssemblyTarget.setMinHeapSize(minHeapSize); webAssemblyTarget.setMaxHeapSize(maxHeapSize); + webAssemblyTarget.setObfuscated(minifying); return webAssemblyTarget; }