From 871e9a011324eba8104c7d8f8916009bc02dcd8a Mon Sep 17 00:00:00 2001 From: Alexey Andreev Date: Thu, 23 May 2019 18:43:31 +0300 Subject: [PATCH] C: reduce size occupied by call site descriptors --- .../backend/c/generate/CallSiteGenerator.java | 135 +++++++++++++++--- .../main/java/org/teavm/runtime/CallSite.java | 1 - .../org/teavm/runtime/CallSiteLocation.java | 4 +- .../org/teavm/runtime/ExceptionHandler.java | 1 + .../org/teavm/runtime/ExceptionHandling.java | 24 ++-- .../org/teavm/runtime/MethodLocation.java | 28 ++++ samples/benchmark/pom.xml | 2 + 7 files changed, 157 insertions(+), 38 deletions(-) create mode 100644 core/src/main/java/org/teavm/runtime/MethodLocation.java diff --git a/core/src/main/java/org/teavm/backend/c/generate/CallSiteGenerator.java b/core/src/main/java/org/teavm/backend/c/generate/CallSiteGenerator.java index 240d10389..251ba4041 100644 --- a/core/src/main/java/org/teavm/backend/c/generate/CallSiteGenerator.java +++ b/core/src/main/java/org/teavm/backend/c/generate/CallSiteGenerator.java @@ -19,6 +19,7 @@ import com.carrotsearch.hppc.ObjectIntHashMap; import com.carrotsearch.hppc.ObjectIntMap; import java.util.ArrayList; import java.util.List; +import java.util.Objects; import org.teavm.model.FieldReference; import org.teavm.model.ValueType; import org.teavm.model.lowlevel.CallSiteDescriptor; @@ -28,6 +29,7 @@ import org.teavm.model.lowlevel.ExceptionHandlerDescriptor; public class CallSiteGenerator { public static final String CALL_SITE = "org.teavm.runtime.CallSite"; private static final String CALL_SITE_LOCATION = "org.teavm.runtime.CallSiteLocation"; + private static final String METHOD_LOCATION = "org.teavm.runtime.MethodLocation"; private static final String EXCEPTION_HANDLER = "org.teavm.runtime.ExceptionHandler"; private GenerationContext context; @@ -35,8 +37,11 @@ public class CallSiteGenerator { private IncludeManager includes; private ObjectIntMap locationMap = new ObjectIntHashMap<>(); private List locations = new ArrayList<>(); - private List exceptionHandlers = new ArrayList<>(); + private List exceptionHandlers = new ArrayList<>(); + private ObjectIntMap methodLocationMap = new ObjectIntHashMap<>(); + private List methodLocations = new ArrayList<>(); private String callSiteLocationName; + private String methodLocationName; private String exceptionHandlerName; private String callSitesName; private boolean isStatic; @@ -47,6 +52,7 @@ public class CallSiteGenerator { this.writer = writer; this.includes = includes; callSiteLocationName = context.getNames().forClass(CALL_SITE_LOCATION); + methodLocationName = context.getNames().forClass(METHOD_LOCATION); exceptionHandlerName = context.getNames().forClass(EXCEPTION_HANDLER); this.callSitesName = callSitesName; } @@ -56,12 +62,15 @@ public class CallSiteGenerator { } public void generate(List callSites) { + CodeWriter writerForMethodLocations = writer.fragment(); CodeWriter writerForLocations = writer.fragment(); generateCallSites(callSites); CodeWriter oldWriter = writer; writer = writerForLocations; generateLocations(); + writer = writerForMethodLocations; + generateMethodLocations(); generateHandlers(); writer = oldWriter; } @@ -75,7 +84,6 @@ public class CallSiteGenerator { writer.print("static "); } writer.print(callSiteName).print(" " + callSitesName + "[" + callSites.size() + "] = {").indent(); - String handlerCountName = fieldName(CALL_SITE, "handlerCount"); String firstHandlerName = fieldName(CALL_SITE, "firstHandler"); String locationName = fieldName(CALL_SITE, "location"); @@ -100,14 +108,17 @@ public class CallSiteGenerator { ? "exceptionHandlers_" + callSitesName + " + " + exceptionHandlers.size() : "NULL"; writer.println().print("{ "); - writer.print(".").print(handlerCountName).print(" = ") - .print(String.valueOf(callSite.getHandlers().size())).print(", "); writer.print(".").print(firstHandlerName).print(" = ").print(firstHandlerExpr).print(", "); writer.print(".").print(locationName).print(" = ") .print(locationIndex >= 0 ? "callSiteLocations_" + callSitesName + " + " + locationIndex : "NULL"); writer.print(" }"); - exceptionHandlers.addAll(callSite.getHandlers()); + for (int i = 0; i < callSite.getHandlers().size(); ++i) { + if (i > 0) { + exceptionHandlers.get(exceptionHandlers.size() - 1).nextIndex = exceptionHandlers.size(); + } + exceptionHandlers.add(new HandlerContainer(callSite.getHandlers().get(i))); + } } writer.println().outdent().println("};"); @@ -121,9 +132,7 @@ public class CallSiteGenerator { writer.print("static ").print(callSiteLocationName).print(" callSiteLocations_" + callSitesName + "[" + locations.size() + "] = {").indent(); - String fileNameName = fieldName(CALL_SITE_LOCATION, "fileName"); - String classNameName = fieldName(CALL_SITE_LOCATION, "className"); - String methodNameName = fieldName(CALL_SITE_LOCATION, "methodName"); + String methodName = fieldName(CALL_SITE_LOCATION, "method"); String lineNumberName = fieldName(CALL_SITE_LOCATION, "lineNumber"); boolean first = true; @@ -134,12 +143,16 @@ public class CallSiteGenerator { first = false; writer.println().print("{ "); - writer.print(".").print(fileNameName).print(" = ") - .print(getStringExpr(location.getFileName())).print(", "); - writer.print(".").print(classNameName).print(" = ") - .print(getStringExpr(location.getClassName())).print(", "); - writer.print(".").print(methodNameName).print(" = ") - .print(getStringExpr(location.getMethodName())).print(", "); + MethodLocation methodLocation = new MethodLocation(location.getFileName(), location.getClassName(), + location.getMethodName()); + int index = methodLocationMap.getOrDefault(methodLocation, -1); + if (index < 0) { + index = methodLocations.size(); + methodLocationMap.put(methodLocation, index); + methodLocations.add(methodLocation); + } + writer.print(".").print(methodName).print(" = ").print("methodLocations_" + callSitesName + " + " + index) + .print(", "); writer.print(".").print(lineNumberName).print(" = ") .print(String.valueOf(location.getLineNumber())); @@ -149,19 +162,55 @@ public class CallSiteGenerator { writer.println().outdent().println("};"); } + private void generateMethodLocations() { + if (methodLocations.isEmpty()) { + return; + } + + includes.includeClass(METHOD_LOCATION); + writer.print("static ").print(methodLocationName).print(" methodLocations_" + callSitesName + + "[" + methodLocations.size() + "] = {").indent(); + + String fileNameName = fieldName(METHOD_LOCATION, "fileName"); + String classNameName = fieldName(METHOD_LOCATION, "className"); + String methodNameName = fieldName(METHOD_LOCATION, "methodName"); + + boolean first = true; + for (MethodLocation location : methodLocations) { + if (!first) { + writer.print(","); + } + first = false; + + writer.println().print("{ "); + writer.print(".").print(fileNameName).print(" = ") + .print(getStringExpr(location.file)).print(", "); + writer.print(".").print(classNameName).print(" = ") + .print(getStringExpr(location.className)).print(", "); + writer.print(".").print(methodNameName).print(" = ") + .print(getStringExpr(location.methodName)); + + writer.print(" }"); + } + + writer.println().outdent().println("};"); + } + private void generateHandlers() { if (exceptionHandlers.isEmpty()) { return; } includes.includeClass(EXCEPTION_HANDLER); - writer.print("static ").print(exceptionHandlerName).print(" exceptionHandlers_" + callSitesName + "[" + String name = "exceptionHandlers_" + callSitesName; + writer.print("static ").print(exceptionHandlerName).print(" " + name + "[" + exceptionHandlers.size() + "] = {").indent(); String idName = fieldName(EXCEPTION_HANDLER, "id"); String exceptionClassName = fieldName(EXCEPTION_HANDLER, "exceptionClass"); + String nextName = fieldName(EXCEPTION_HANDLER, "next"); boolean first = true; - for (ExceptionHandlerDescriptor handler : exceptionHandlers) { + for (HandlerContainer handler : exceptionHandlers) { if (!first) { writer.print(","); } @@ -169,14 +218,16 @@ public class CallSiteGenerator { writer.println().print("{ "); - if (handler.getClassName() != null) { - includes.includeClass(handler.getClassName()); + if (handler.descriptor.getClassName() != null) { + includes.includeClass(handler.descriptor.getClassName()); } - String classExpr = handler.getClassName() != null - ? "&" + context.getNames().forClassInstance(ValueType.object(handler.getClassName())) + String classExpr = handler.descriptor.getClassName() != null + ? "&" + context.getNames().forClassInstance(ValueType.object(handler.descriptor.getClassName())) : "NULL"; - writer.print(".").print(idName).print(" = ").print(String.valueOf(handler.getId())).print(","); - writer.print(".").print(exceptionClassName).print(" = ").print(classExpr); + writer.print(".").print(idName).print(" = ").print(String.valueOf(handler.descriptor.getId())).print(", "); + writer.print(".").print(exceptionClassName).print(" = ").print(classExpr).print(", "); + writer.print(".").print(nextName).print(" = ") + .print(handler.nextIndex < 0 ? "NULL" : name + "+" + handler.nextIndex); writer.print(" }"); } @@ -191,4 +242,44 @@ public class CallSiteGenerator { private String getStringExpr(String s) { return s != null ? "&TEAVM_GET_STRING(" + context.getStringPool().getStringIndex(s) + ")" : "NULL"; } + + static class HandlerContainer { + ExceptionHandlerDescriptor descriptor; + int nextIndex = -1; + + HandlerContainer(ExceptionHandlerDescriptor descriptor) { + this.descriptor = descriptor; + } + } + + final static class MethodLocation { + final String file; + final String className; + final String methodName; + + MethodLocation(String file, String className, String methodName) { + this.file = file; + this.className = className; + this.methodName = methodName; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (!(o instanceof MethodLocation)) { + return false; + } + MethodLocation that = (MethodLocation) o; + return Objects.equals(file, that.file) + && Objects.equals(className, that.className) + && Objects.equals(methodName, that.methodName); + } + + @Override + public int hashCode() { + return Objects.hash(file, className, methodName); + } + } } diff --git a/core/src/main/java/org/teavm/runtime/CallSite.java b/core/src/main/java/org/teavm/runtime/CallSite.java index 0db59557f..4f10bf1fa 100644 --- a/core/src/main/java/org/teavm/runtime/CallSite.java +++ b/core/src/main/java/org/teavm/runtime/CallSite.java @@ -22,7 +22,6 @@ import org.teavm.interop.Unmanaged; @Unmanaged @StaticInit public class CallSite extends Structure { - public int handlerCount; public ExceptionHandler firstHandler; public CallSiteLocation location; } diff --git a/core/src/main/java/org/teavm/runtime/CallSiteLocation.java b/core/src/main/java/org/teavm/runtime/CallSiteLocation.java index 6c3bfacf6..412d9abd0 100644 --- a/core/src/main/java/org/teavm/runtime/CallSiteLocation.java +++ b/core/src/main/java/org/teavm/runtime/CallSiteLocation.java @@ -22,8 +22,6 @@ import org.teavm.interop.Unmanaged; @Unmanaged @StaticInit public class CallSiteLocation extends Structure { - public StringPtr fileName; - public StringPtr className; - public StringPtr methodName; + public MethodLocation method; public int lineNumber; } diff --git a/core/src/main/java/org/teavm/runtime/ExceptionHandler.java b/core/src/main/java/org/teavm/runtime/ExceptionHandler.java index 1b3c0f7c2..7e964c180 100644 --- a/core/src/main/java/org/teavm/runtime/ExceptionHandler.java +++ b/core/src/main/java/org/teavm/runtime/ExceptionHandler.java @@ -24,4 +24,5 @@ import org.teavm.interop.Unmanaged; public class ExceptionHandler extends Structure { public int id; public RuntimeClass exceptionClass; + public ExceptionHandler next; } diff --git a/core/src/main/java/org/teavm/runtime/ExceptionHandling.java b/core/src/main/java/org/teavm/runtime/ExceptionHandling.java index 1bcef45c3..fe8c22b26 100644 --- a/core/src/main/java/org/teavm/runtime/ExceptionHandling.java +++ b/core/src/main/java/org/teavm/runtime/ExceptionHandling.java @@ -18,7 +18,6 @@ package org.teavm.runtime; import org.teavm.interop.Address; import org.teavm.interop.Export; import org.teavm.interop.StaticInit; -import org.teavm.interop.Structure; import org.teavm.interop.Unmanaged; @StaticInit @@ -34,18 +33,19 @@ public final class ExceptionHandling { int callSiteId = ShadowStack.getCallSiteId(stackFrame); CallSite callSite = findCallSiteById(callSiteId, stackFrame); CallSiteLocation location = callSite.location; + MethodLocation methodLocation = location.method; Console.printString(" at "); - if (location.className == null || location.methodName == null) { + if (methodLocation.className == null || methodLocation.methodName == null) { Console.printString("(Unknown method)"); } else { - Console.printString(location.className.value); + Console.printString(methodLocation.className.value); Console.printString("."); - Console.printString(location.methodName.value); + Console.printString(methodLocation.methodName.value); } Console.printString("("); - if (location.fileName != null && location.lineNumber >= 0) { - Console.printString(location.fileName.value); + if (methodLocation.fileName != null && location.lineNumber >= 0) { + Console.printString(methodLocation.fileName.value); Console.printString(":"); Console.printInt(location.lineNumber); } @@ -77,13 +77,12 @@ public final class ExceptionHandling { CallSite callSite = findCallSiteById(callSiteId, stackFrame); ExceptionHandler handler = callSite.firstHandler; - for (int i = 0; i < callSite.handlerCount; ++i) { + while (handler != null) { if (handler.exceptionClass == null || handler.exceptionClass.isSupertypeOf.apply(exceptionClass)) { ShadowStack.setExceptionHandlerId(stackFrame, handler.id); break stackLoop; } - - handler = Structure.add(ExceptionHandler.class, handler, 1); + handler = handler.next; } ShadowStack.setExceptionHandlerId(stackFrame, callSiteId - 1); @@ -120,10 +119,11 @@ public final class ExceptionHandling { int callSiteId = ShadowStack.getCallSiteId(stackFrame); CallSite callSite = findCallSiteById(callSiteId, stackFrame); CallSiteLocation location = callSite.location; + MethodLocation methodLocation = location.method; StackTraceElement element = createElement( - location != null && location.className != null ? location.className.value : "", - location != null && location.methodName != null ? location.methodName.value : "", - location != null && location.fileName != null ? location.fileName.value : null, + location != null && methodLocation.className != null ? methodLocation.className.value : "", + location != null && methodLocation.methodName != null ? methodLocation.methodName.value : "", + location != null && methodLocation.fileName != null ? methodLocation.fileName.value : null, location != null ? location.lineNumber : -1); target[index++] = element; stackFrame = ShadowStack.getNextStackFrame(stackFrame); diff --git a/core/src/main/java/org/teavm/runtime/MethodLocation.java b/core/src/main/java/org/teavm/runtime/MethodLocation.java new file mode 100644 index 000000000..814ceabe0 --- /dev/null +++ b/core/src/main/java/org/teavm/runtime/MethodLocation.java @@ -0,0 +1,28 @@ +/* + * Copyright 2019 Alexey Andreev. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.teavm.runtime; + +import org.teavm.interop.StaticInit; +import org.teavm.interop.Structure; +import org.teavm.interop.Unmanaged; + +@Unmanaged +@StaticInit +public class MethodLocation extends Structure { + public StringPtr fileName; + public StringPtr className; + public StringPtr methodName; +} diff --git a/samples/benchmark/pom.xml b/samples/benchmark/pom.xml index f1ab7abb7..307562bba 100644 --- a/samples/benchmark/pom.xml +++ b/samples/benchmark/pom.xml @@ -154,6 +154,7 @@ FULL + native-client