C: reduce size occupied by call site descriptors

This commit is contained in:
Alexey Andreev 2019-05-23 18:43:31 +03:00
parent 9de7df6fdf
commit 871e9a0113
7 changed files with 157 additions and 38 deletions

View File

@ -19,6 +19,7 @@ import com.carrotsearch.hppc.ObjectIntHashMap;
import com.carrotsearch.hppc.ObjectIntMap; import com.carrotsearch.hppc.ObjectIntMap;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Objects;
import org.teavm.model.FieldReference; import org.teavm.model.FieldReference;
import org.teavm.model.ValueType; import org.teavm.model.ValueType;
import org.teavm.model.lowlevel.CallSiteDescriptor; import org.teavm.model.lowlevel.CallSiteDescriptor;
@ -28,6 +29,7 @@ import org.teavm.model.lowlevel.ExceptionHandlerDescriptor;
public class CallSiteGenerator { public class CallSiteGenerator {
public static final String CALL_SITE = "org.teavm.runtime.CallSite"; 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 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 static final String EXCEPTION_HANDLER = "org.teavm.runtime.ExceptionHandler";
private GenerationContext context; private GenerationContext context;
@ -35,8 +37,11 @@ public class CallSiteGenerator {
private IncludeManager includes; private IncludeManager includes;
private ObjectIntMap<CallSiteLocation> locationMap = new ObjectIntHashMap<>(); private ObjectIntMap<CallSiteLocation> locationMap = new ObjectIntHashMap<>();
private List<CallSiteLocation> locations = new ArrayList<>(); private List<CallSiteLocation> locations = new ArrayList<>();
private List<ExceptionHandlerDescriptor> exceptionHandlers = new ArrayList<>(); private List<HandlerContainer> exceptionHandlers = new ArrayList<>();
private ObjectIntMap<MethodLocation> methodLocationMap = new ObjectIntHashMap<>();
private List<MethodLocation> methodLocations = new ArrayList<>();
private String callSiteLocationName; private String callSiteLocationName;
private String methodLocationName;
private String exceptionHandlerName; private String exceptionHandlerName;
private String callSitesName; private String callSitesName;
private boolean isStatic; private boolean isStatic;
@ -47,6 +52,7 @@ public class CallSiteGenerator {
this.writer = writer; this.writer = writer;
this.includes = includes; this.includes = includes;
callSiteLocationName = context.getNames().forClass(CALL_SITE_LOCATION); callSiteLocationName = context.getNames().forClass(CALL_SITE_LOCATION);
methodLocationName = context.getNames().forClass(METHOD_LOCATION);
exceptionHandlerName = context.getNames().forClass(EXCEPTION_HANDLER); exceptionHandlerName = context.getNames().forClass(EXCEPTION_HANDLER);
this.callSitesName = callSitesName; this.callSitesName = callSitesName;
} }
@ -56,12 +62,15 @@ public class CallSiteGenerator {
} }
public void generate(List<? extends CallSiteDescriptor> callSites) { public void generate(List<? extends CallSiteDescriptor> callSites) {
CodeWriter writerForMethodLocations = writer.fragment();
CodeWriter writerForLocations = writer.fragment(); CodeWriter writerForLocations = writer.fragment();
generateCallSites(callSites); generateCallSites(callSites);
CodeWriter oldWriter = writer; CodeWriter oldWriter = writer;
writer = writerForLocations; writer = writerForLocations;
generateLocations(); generateLocations();
writer = writerForMethodLocations;
generateMethodLocations();
generateHandlers(); generateHandlers();
writer = oldWriter; writer = oldWriter;
} }
@ -75,7 +84,6 @@ public class CallSiteGenerator {
writer.print("static "); writer.print("static ");
} }
writer.print(callSiteName).print(" " + callSitesName + "[" + callSites.size() + "] = {").indent(); writer.print(callSiteName).print(" " + callSitesName + "[" + callSites.size() + "] = {").indent();
String handlerCountName = fieldName(CALL_SITE, "handlerCount");
String firstHandlerName = fieldName(CALL_SITE, "firstHandler"); String firstHandlerName = fieldName(CALL_SITE, "firstHandler");
String locationName = fieldName(CALL_SITE, "location"); String locationName = fieldName(CALL_SITE, "location");
@ -100,14 +108,17 @@ public class CallSiteGenerator {
? "exceptionHandlers_" + callSitesName + " + " + exceptionHandlers.size() ? "exceptionHandlers_" + callSitesName + " + " + exceptionHandlers.size()
: "NULL"; : "NULL";
writer.println().print("{ "); 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(firstHandlerName).print(" = ").print(firstHandlerExpr).print(", ");
writer.print(".").print(locationName).print(" = ") writer.print(".").print(locationName).print(" = ")
.print(locationIndex >= 0 ? "callSiteLocations_" + callSitesName + " + " + locationIndex : "NULL"); .print(locationIndex >= 0 ? "callSiteLocations_" + callSitesName + " + " + locationIndex : "NULL");
writer.print(" }"); 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("};"); writer.println().outdent().println("};");
@ -121,9 +132,7 @@ public class CallSiteGenerator {
writer.print("static ").print(callSiteLocationName).print(" callSiteLocations_" + callSitesName writer.print("static ").print(callSiteLocationName).print(" callSiteLocations_" + callSitesName
+ "[" + locations.size() + "] = {").indent(); + "[" + locations.size() + "] = {").indent();
String fileNameName = fieldName(CALL_SITE_LOCATION, "fileName"); String methodName = fieldName(CALL_SITE_LOCATION, "method");
String classNameName = fieldName(CALL_SITE_LOCATION, "className");
String methodNameName = fieldName(CALL_SITE_LOCATION, "methodName");
String lineNumberName = fieldName(CALL_SITE_LOCATION, "lineNumber"); String lineNumberName = fieldName(CALL_SITE_LOCATION, "lineNumber");
boolean first = true; boolean first = true;
@ -134,12 +143,16 @@ public class CallSiteGenerator {
first = false; first = false;
writer.println().print("{ "); writer.println().print("{ ");
writer.print(".").print(fileNameName).print(" = ") MethodLocation methodLocation = new MethodLocation(location.getFileName(), location.getClassName(),
.print(getStringExpr(location.getFileName())).print(", "); location.getMethodName());
writer.print(".").print(classNameName).print(" = ") int index = methodLocationMap.getOrDefault(methodLocation, -1);
.print(getStringExpr(location.getClassName())).print(", "); if (index < 0) {
writer.print(".").print(methodNameName).print(" = ") index = methodLocations.size();
.print(getStringExpr(location.getMethodName())).print(", "); methodLocationMap.put(methodLocation, index);
methodLocations.add(methodLocation);
}
writer.print(".").print(methodName).print(" = ").print("methodLocations_" + callSitesName + " + " + index)
.print(", ");
writer.print(".").print(lineNumberName).print(" = ") writer.print(".").print(lineNumberName).print(" = ")
.print(String.valueOf(location.getLineNumber())); .print(String.valueOf(location.getLineNumber()));
@ -149,19 +162,55 @@ public class CallSiteGenerator {
writer.println().outdent().println("};"); 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() { private void generateHandlers() {
if (exceptionHandlers.isEmpty()) { if (exceptionHandlers.isEmpty()) {
return; return;
} }
includes.includeClass(EXCEPTION_HANDLER); 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(); + exceptionHandlers.size() + "] = {").indent();
String idName = fieldName(EXCEPTION_HANDLER, "id"); String idName = fieldName(EXCEPTION_HANDLER, "id");
String exceptionClassName = fieldName(EXCEPTION_HANDLER, "exceptionClass"); String exceptionClassName = fieldName(EXCEPTION_HANDLER, "exceptionClass");
String nextName = fieldName(EXCEPTION_HANDLER, "next");
boolean first = true; boolean first = true;
for (ExceptionHandlerDescriptor handler : exceptionHandlers) { for (HandlerContainer handler : exceptionHandlers) {
if (!first) { if (!first) {
writer.print(","); writer.print(",");
} }
@ -169,14 +218,16 @@ public class CallSiteGenerator {
writer.println().print("{ "); writer.println().print("{ ");
if (handler.getClassName() != null) { if (handler.descriptor.getClassName() != null) {
includes.includeClass(handler.getClassName()); includes.includeClass(handler.descriptor.getClassName());
} }
String classExpr = handler.getClassName() != null String classExpr = handler.descriptor.getClassName() != null
? "&" + context.getNames().forClassInstance(ValueType.object(handler.getClassName())) ? "&" + context.getNames().forClassInstance(ValueType.object(handler.descriptor.getClassName()))
: "NULL"; : "NULL";
writer.print(".").print(idName).print(" = ").print(String.valueOf(handler.getId())).print(","); writer.print(".").print(idName).print(" = ").print(String.valueOf(handler.descriptor.getId())).print(", ");
writer.print(".").print(exceptionClassName).print(" = ").print(classExpr); writer.print(".").print(exceptionClassName).print(" = ").print(classExpr).print(", ");
writer.print(".").print(nextName).print(" = ")
.print(handler.nextIndex < 0 ? "NULL" : name + "+" + handler.nextIndex);
writer.print(" }"); writer.print(" }");
} }
@ -191,4 +242,44 @@ public class CallSiteGenerator {
private String getStringExpr(String s) { private String getStringExpr(String s) {
return s != null ? "&TEAVM_GET_STRING(" + context.getStringPool().getStringIndex(s) + ")" : "NULL"; 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);
}
}
} }

View File

@ -22,7 +22,6 @@ import org.teavm.interop.Unmanaged;
@Unmanaged @Unmanaged
@StaticInit @StaticInit
public class CallSite extends Structure { public class CallSite extends Structure {
public int handlerCount;
public ExceptionHandler firstHandler; public ExceptionHandler firstHandler;
public CallSiteLocation location; public CallSiteLocation location;
} }

View File

@ -22,8 +22,6 @@ import org.teavm.interop.Unmanaged;
@Unmanaged @Unmanaged
@StaticInit @StaticInit
public class CallSiteLocation extends Structure { public class CallSiteLocation extends Structure {
public StringPtr fileName; public MethodLocation method;
public StringPtr className;
public StringPtr methodName;
public int lineNumber; public int lineNumber;
} }

View File

@ -24,4 +24,5 @@ import org.teavm.interop.Unmanaged;
public class ExceptionHandler extends Structure { public class ExceptionHandler extends Structure {
public int id; public int id;
public RuntimeClass exceptionClass; public RuntimeClass exceptionClass;
public ExceptionHandler next;
} }

View File

@ -18,7 +18,6 @@ package org.teavm.runtime;
import org.teavm.interop.Address; import org.teavm.interop.Address;
import org.teavm.interop.Export; import org.teavm.interop.Export;
import org.teavm.interop.StaticInit; import org.teavm.interop.StaticInit;
import org.teavm.interop.Structure;
import org.teavm.interop.Unmanaged; import org.teavm.interop.Unmanaged;
@StaticInit @StaticInit
@ -34,18 +33,19 @@ public final class ExceptionHandling {
int callSiteId = ShadowStack.getCallSiteId(stackFrame); int callSiteId = ShadowStack.getCallSiteId(stackFrame);
CallSite callSite = findCallSiteById(callSiteId, stackFrame); CallSite callSite = findCallSiteById(callSiteId, stackFrame);
CallSiteLocation location = callSite.location; CallSiteLocation location = callSite.location;
MethodLocation methodLocation = location.method;
Console.printString(" at "); Console.printString(" at ");
if (location.className == null || location.methodName == null) { if (methodLocation.className == null || methodLocation.methodName == null) {
Console.printString("(Unknown method)"); Console.printString("(Unknown method)");
} else { } else {
Console.printString(location.className.value); Console.printString(methodLocation.className.value);
Console.printString("."); Console.printString(".");
Console.printString(location.methodName.value); Console.printString(methodLocation.methodName.value);
} }
Console.printString("("); Console.printString("(");
if (location.fileName != null && location.lineNumber >= 0) { if (methodLocation.fileName != null && location.lineNumber >= 0) {
Console.printString(location.fileName.value); Console.printString(methodLocation.fileName.value);
Console.printString(":"); Console.printString(":");
Console.printInt(location.lineNumber); Console.printInt(location.lineNumber);
} }
@ -77,13 +77,12 @@ public final class ExceptionHandling {
CallSite callSite = findCallSiteById(callSiteId, stackFrame); CallSite callSite = findCallSiteById(callSiteId, stackFrame);
ExceptionHandler handler = callSite.firstHandler; ExceptionHandler handler = callSite.firstHandler;
for (int i = 0; i < callSite.handlerCount; ++i) { while (handler != null) {
if (handler.exceptionClass == null || handler.exceptionClass.isSupertypeOf.apply(exceptionClass)) { if (handler.exceptionClass == null || handler.exceptionClass.isSupertypeOf.apply(exceptionClass)) {
ShadowStack.setExceptionHandlerId(stackFrame, handler.id); ShadowStack.setExceptionHandlerId(stackFrame, handler.id);
break stackLoop; break stackLoop;
} }
handler = handler.next;
handler = Structure.add(ExceptionHandler.class, handler, 1);
} }
ShadowStack.setExceptionHandlerId(stackFrame, callSiteId - 1); ShadowStack.setExceptionHandlerId(stackFrame, callSiteId - 1);
@ -120,10 +119,11 @@ public final class ExceptionHandling {
int callSiteId = ShadowStack.getCallSiteId(stackFrame); int callSiteId = ShadowStack.getCallSiteId(stackFrame);
CallSite callSite = findCallSiteById(callSiteId, stackFrame); CallSite callSite = findCallSiteById(callSiteId, stackFrame);
CallSiteLocation location = callSite.location; CallSiteLocation location = callSite.location;
MethodLocation methodLocation = location.method;
StackTraceElement element = createElement( StackTraceElement element = createElement(
location != null && location.className != null ? location.className.value : "", location != null && methodLocation.className != null ? methodLocation.className.value : "",
location != null && location.methodName != null ? location.methodName.value : "", location != null && methodLocation.methodName != null ? methodLocation.methodName.value : "",
location != null && location.fileName != null ? location.fileName.value : null, location != null && methodLocation.fileName != null ? methodLocation.fileName.value : null,
location != null ? location.lineNumber : -1); location != null ? location.lineNumber : -1);
target[index++] = element; target[index++] = element;
stackFrame = ShadowStack.getNextStackFrame(stackFrame); stackFrame = ShadowStack.getNextStackFrame(stackFrame);

View File

@ -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;
}

View File

@ -154,6 +154,7 @@
<optimizationLevel>FULL</optimizationLevel> <optimizationLevel>FULL</optimizationLevel>
</configuration> </configuration>
</execution> </execution>
<!--
<execution> <execution>
<id>wasm-client</id> <id>wasm-client</id>
<goals> <goals>
@ -168,6 +169,7 @@
<heapSize>8</heapSize> <heapSize>8</heapSize>
</configuration> </configuration>
</execution> </execution>
-->
<execution> <execution>
<id>native-client</id> <id>native-client</id>
<goals> <goals>