C: improve generation of string pool for incremental mode

This commit is contained in:
Alexey Andreev 2019-05-16 16:53:40 +03:00
parent 0003ed0bb2
commit 8e08cf6dcd
20 changed files with 313 additions and 154 deletions

View File

@ -47,7 +47,6 @@ import org.teavm.backend.c.generate.NameProvider;
import org.teavm.backend.c.generate.OutputFileUtil; import org.teavm.backend.c.generate.OutputFileUtil;
import org.teavm.backend.c.generate.SimpleIncludeManager; import org.teavm.backend.c.generate.SimpleIncludeManager;
import org.teavm.backend.c.generate.SimpleStringPool; import org.teavm.backend.c.generate.SimpleStringPool;
import org.teavm.backend.c.generate.StringPool;
import org.teavm.backend.c.generate.StringPoolGenerator; import org.teavm.backend.c.generate.StringPoolGenerator;
import org.teavm.backend.c.generators.ArrayGenerator; import org.teavm.backend.c.generators.ArrayGenerator;
import org.teavm.backend.c.generators.Generator; import org.teavm.backend.c.generators.Generator;
@ -145,15 +144,7 @@ public class CTarget implements TeaVMTarget, TeaVMCHost {
private Set<MethodReference> asyncMethods; private Set<MethodReference> asyncMethods;
private boolean incremental; private boolean incremental;
private boolean lineNumbersGenerated; private boolean lineNumbersGenerated;
private StringPool stringPool; private SimpleStringPool stringPool;
public CTarget() {
this(new SimpleStringPool());
}
public CTarget(StringPool stringPool) {
this.stringPool = stringPool;
}
public void setMinHeapSize(int minHeapSize) { public void setMinHeapSize(int minHeapSize) {
this.minHeapSize = minHeapSize; this.minHeapSize = minHeapSize;
@ -333,6 +324,7 @@ public class CTarget implements TeaVMTarget, TeaVMCHost {
List<Generator> generators = new ArrayList<>(); List<Generator> generators = new ArrayList<>();
generators.add(new ArrayGenerator()); generators.add(new ArrayGenerator());
stringPool = new SimpleStringPool();
GenerationContext context = new GenerationContext(vtableProvider, characteristics, GenerationContext context = new GenerationContext(vtableProvider, characteristics,
controller.getDependencyInfo(), stringPool, nameProvider, controller.getDiagnostics(), classes, controller.getDependencyInfo(), stringPool, nameProvider, controller.getDiagnostics(), classes,
intrinsics, generators, asyncMethods::contains, buildTarget, incremental); intrinsics, generators, asyncMethods::contains, buildTarget, incremental);
@ -363,9 +355,12 @@ public class CTarget implements TeaVMTarget, TeaVMCHost {
generateSpecialFunctions(context, runtimeWriter); generateSpecialFunctions(context, runtimeWriter);
OutputFileUtil.write(runtimeWriter, "runtime.c", buildTarget); OutputFileUtil.write(runtimeWriter, "runtime.c", buildTarget);
OutputFileUtil.write(runtimeHeaderWriter, "runtime.h", buildTarget); OutputFileUtil.write(runtimeHeaderWriter, "runtime.h", buildTarget);
BufferedCodeWriter stringhashWriter = new BufferedCodeWriter(false);
emitResource(stringhashWriter, "stringhash.c");
OutputFileUtil.write(stringhashWriter, "stringhash.c", buildTarget);
generateCallSites(buildTarget, context, classes.getClassNames()); generateCallSites(buildTarget, context, classes.getClassNames());
generateStrings(buildTarget, stringPool); generateStrings(buildTarget, context);
List<ValueType> types = classGenerator.getTypes().stream() List<ValueType> types = classGenerator.getTypes().stream()
.filter(c -> ClassGenerator.needsVirtualTable(characteristics, c)) .filter(c -> ClassGenerator.needsVirtualTable(characteristics, c))
@ -374,7 +369,6 @@ public class CTarget implements TeaVMTarget, TeaVMCHost {
generateAllFile(classes, types, buildTarget); generateAllFile(classes, types, buildTarget);
} }
private void emitResource(CodeWriter writer, String resourceName) { private void emitResource(CodeWriter writer, String resourceName) {
ClassLoader classLoader = CTarget.class.getClassLoader(); ClassLoader classLoader = CTarget.class.getClassLoader();
try (BufferedReader reader = new BufferedReader(new InputStreamReader( try (BufferedReader reader = new BufferedReader(new InputStreamReader(
@ -407,6 +401,9 @@ public class CTarget implements TeaVMTarget, TeaVMCHost {
String name = ClassGenerator.fileName(className); String name = ClassGenerator.fileName(className);
OutputFileUtil.write(writer, name + ".c", buildTarget); OutputFileUtil.write(writer, name + ".c", buildTarget);
OutputFileUtil.write(headerWriter, name + ".h", buildTarget); OutputFileUtil.write(headerWriter, name + ".h", buildTarget);
if (incremental) {
stringPool.reset();
}
} }
for (ValueType type : classGenerator.getTypes()) { for (ValueType type : classGenerator.getTypes()) {
@ -419,6 +416,9 @@ public class CTarget implements TeaVMTarget, TeaVMCHost {
String name = ClassGenerator.fileName(type); String name = ClassGenerator.fileName(type);
OutputFileUtil.write(writer, name + ".c", buildTarget); OutputFileUtil.write(writer, name + ".c", buildTarget);
OutputFileUtil.write(headerWriter, name + ".h", buildTarget); OutputFileUtil.write(headerWriter, name + ".h", buildTarget);
if (incremental) {
stringPool.reset();
}
} }
} }
@ -495,16 +495,28 @@ public class CTarget implements TeaVMTarget, TeaVMCHost {
+ "*) ((void**) frame)[3]) + id)"); + "*) ((void**) frame)[3]) + id)");
} }
private void generateStrings(BuildTarget buildTarget, StringPool stringPool) throws IOException { private void generateStrings(BuildTarget buildTarget, GenerationContext context) throws IOException {
BufferedCodeWriter writer = new BufferedCodeWriter(false); BufferedCodeWriter writer = new BufferedCodeWriter(false);
IncludeManager includes = new SimpleIncludeManager(writer);
includes.init("strings.c");
BufferedCodeWriter headerWriter = new BufferedCodeWriter(false); BufferedCodeWriter headerWriter = new BufferedCodeWriter(false);
headerWriter.println("#pragma once"); headerWriter.println("#pragma once");
headerWriter.println("#include \"runtime.h\""); headerWriter.println("#include \"runtime.h\"");
headerWriter.println("extern TeaVM_String teavm_stringPool[];"); headerWriter.println("extern void teavm_initStringPool();");
if (!incremental) {
headerWriter.println("extern TeaVM_String* teavm_stringPool[];");
headerWriter.println("#define TEAVM_GET_STRING(i) teavm_stringPool[i]");
writer.println("#include \"strings.h\""); writer.println("#include \"strings.h\"");
new StringPoolGenerator(writer).generate(stringPool.getStrings()); StringPoolGenerator poolGenerator = new StringPoolGenerator(context, "teavm_stringPool");
poolGenerator.generate(writer);
writer.println("void teavm_initStringPool() {").indent();
poolGenerator.generateStringPoolHeaders(writer, includes);
writer.outdent().println("}");
} else {
writer.println("void teavm_initStringPool() {}");
}
OutputFileUtil.write(writer, "strings.c", buildTarget); OutputFileUtil.write(writer, "strings.c", buildTarget);
OutputFileUtil.write(headerWriter, "strings.h", buildTarget); OutputFileUtil.write(headerWriter, "strings.h", buildTarget);
@ -652,10 +664,10 @@ public class CTarget implements TeaVMTarget, TeaVMCHost {
writer.println("teavm_beforeInit();"); writer.println("teavm_beforeInit();");
writer.println("teavm_initHeap(" + minHeapSize + ");"); writer.println("teavm_initHeap(" + minHeapSize + ");");
generateVirtualTableHeaders(context, writer, types); generateVirtualTableHeaders(context, writer, types);
generateStringPoolHeaders(context, writer); writer.println("teavm_initStringPool();");
for (String className : classes.getClassNames()) { for (ValueType type : types) {
includes.includeClass(className); includes.includeType(type);
writer.println(context.getNames().forClassSystemInitializer(className) + "();"); writer.println(context.getNames().forClassSystemInitializer(type) + "();");
} }
writer.println("teavm_afterInitClasses();"); writer.println("teavm_afterInitClasses();");
generateStaticInitializerCalls(context, writer, includes, classes); generateStaticInitializerCalls(context, writer, includes, classes);
@ -705,19 +717,6 @@ public class CTarget implements TeaVMTarget, TeaVMCHost {
writer.outdent().println("}"); writer.outdent().println("}");
} }
private void generateStringPoolHeaders(GenerationContext context, CodeWriter writer) {
String stringClassName = context.getNames().forClassInstance(ValueType.object("java.lang.String"));
writer.print("int32_t stringHeader = TEAVM_PACK_CLASS(&" + stringClassName + ") | ");
CodeGeneratorUtil.writeIntValue(writer, RuntimeObject.GC_MARKED);
writer.println(";");
int size = context.getStringPool().getStrings().size();
writer.println("for (int i = 0; i < " + size + "; ++i) {").indent();
writer.println("TeaVM_Object *s = (TeaVM_Object*) (teavm_stringPool + i);");
writer.println("if (s != NULL) s->header = stringHeader;");
writer.outdent().println("}");
}
private void generateFiberStart(GenerationContext context, CodeWriter writer, IncludeManager includes) { private void generateFiberStart(GenerationContext context, CodeWriter writer, IncludeManager includes) {
String startName = context.getNames().forMethod(new MethodReference(Fiber.class, String startName = context.getNames().forMethod(new MethodReference(Fiber.class,
"startMain", String[].class, void.class)); "startMain", String[].class, void.class));

View File

@ -183,6 +183,6 @@ public class CallSiteGenerator {
} }
private String getStringExpr(String s) { private String getStringExpr(String s) {
return s != null ? "teavm_stringPool + " + context.getStringPool().getStringIndex(s) : "NULL"; return s != null ? "&TEAVM_GET_STRING(" + context.getStringPool().getStringIndex(s) + ")" : "NULL";
} }
} }

View File

@ -84,7 +84,6 @@ public class ClassGenerator {
private CodeWriter headerWriter; private CodeWriter headerWriter;
private IncludeManager includes; private IncludeManager includes;
private IncludeManager headerIncludes; private IncludeManager headerIncludes;
private boolean stackDefined;
public ClassGenerator(GenerationContext context, ClassReaderSource unprocessedClassSource, public ClassGenerator(GenerationContext context, ClassReaderSource unprocessedClassSource,
TagRegistry tagRegistry, Decompiler decompiler) { TagRegistry tagRegistry, Decompiler decompiler) {
@ -165,18 +164,10 @@ public class ClassGenerator {
}; };
public void generateClass(CodeWriter writer, CodeWriter headerWriter, ClassHolder cls) { public void generateClass(CodeWriter writer, CodeWriter headerWriter, ClassHolder cls) {
stackDefined = false; ValueType type = ValueType.object(cls.getName());
init(writer, headerWriter, fileName(cls.getName())); init(writer, headerWriter, fileName(cls.getName()), type);
codeGenerator = new CodeGenerator(context, codeWriter, includes);
String sysInitializerName = context.getNames().forClassSystemInitializer(cls.getName());
headerWriter.println("extern void " + sysInitializerName + "();");
writer.println("void " + sysInitializerName + "() {").indent();
initWriter = writer.fragment();
writer.outdent().println("}");
includes.includeClass(cls.getName());
generateStringPoolDecl(type);
generateClassStructure(cls); generateClassStructure(cls);
generateClassStaticFields(cls); generateClassStaticFields(cls);
generateClassMethods(cls); generateClassMethods(cls);
@ -184,6 +175,7 @@ public class ClassGenerator {
generateVirtualTable(ValueType.object(cls.getName())); generateVirtualTable(ValueType.object(cls.getName()));
generateStaticGCRoots(cls.getName()); generateStaticGCRoots(cls.getName());
generateLayoutArray(cls.getName()); generateLayoutArray(cls.getName());
generateStringPool(type);
} }
private void generateCallSites(List<? extends CallSiteDescriptor> callSites, String callSitesName) { private void generateCallSites(List<? extends CallSiteDescriptor> callSites, String callSitesName) {
@ -193,12 +185,14 @@ public class ClassGenerator {
} }
public void generateType(CodeWriter writer, CodeWriter headerWriter, ValueType type) { public void generateType(CodeWriter writer, CodeWriter headerWriter, ValueType type) {
init(writer, headerWriter, fileName(type)); init(writer, headerWriter, fileName(type), type);
generateStringPoolDecl(type);
includes.includeType(type); includes.includeType(type);
generateVirtualTable(type); generateVirtualTable(type);
generateStringPool(type);
} }
private void init(CodeWriter writer, CodeWriter headerWriter, String fileName) { private void init(CodeWriter writer, CodeWriter headerWriter, String fileName, ValueType type) {
staticGcRoots = null; staticGcRoots = null;
classLayout = null; classLayout = null;
@ -211,6 +205,38 @@ public class ClassGenerator {
headerIncludes = new SimpleIncludeManager(headerWriter); headerIncludes = new SimpleIncludeManager(headerWriter);
headerIncludes.init(fileName + ".h"); headerIncludes.init(fileName + ".h");
headerIncludes.includePath("runtime.h"); headerIncludes.includePath("runtime.h");
codeGenerator = new CodeGenerator(context, codeWriter, includes);
String sysInitializerName = context.getNames().forClassSystemInitializer(type);
headerWriter.println("extern void " + sysInitializerName + "();");
writer.println("void " + sysInitializerName + "() {").indent();
initWriter = writer.fragment();
writer.outdent().println("}");
includes.includeType(type);
}
private void generateStringPoolDecl(ValueType type) {
if (!context.isIncremental()) {
return;
}
String poolName = "strings_" + context.getNames().forClassInstance(type);
codeWriter.println("TeaVM_String* " + poolName + "[];");
codeWriter.println("#define TEAVM_GET_STRING(i) " + poolName + "[i]");
}
private void generateStringPool(ValueType type) {
if (!context.isIncremental()) {
return;
}
codeWriter.println("#undef TEAVM_GET_STRING");
String poolName = "strings_" + context.getNames().forClassInstance(type);
StringPoolGenerator poolGenerator = new StringPoolGenerator(context, poolName);
poolGenerator.generate(codeWriter);
poolGenerator.generateStringPoolHeaders(initWriter, includes);
} }
public Set<ValueType> getTypes() { public Set<ValueType> getTypes() {
@ -242,17 +268,17 @@ public class ClassGenerator {
} else { } else {
callSitesName = "NULL"; callSitesName = "NULL";
} }
if (stackDefined) {
codeWriter.println("#undef TEAVM_ALLOC_STACK");
}
codeWriter.println("#define TEAVM_ALLOC_STACK(size) TEAVM_ALLOC_STACK_DEF(size, " codeWriter.println("#define TEAVM_ALLOC_STACK(size) TEAVM_ALLOC_STACK_DEF(size, "
+ callSitesName + ")"); + callSitesName + ")");
stackDefined = true;
} }
generateMethodForwardDeclaration(method); generateMethodForwardDeclaration(method);
RegularMethodNode methodNode = decompiler.decompileRegular(method); RegularMethodNode methodNode = decompiler.decompileRegular(method);
codeGenerator.generateMethod(methodNode); codeGenerator.generateMethod(methodNode);
if (context.isIncremental()) {
codeWriter.println("#undef TEAVM_ALLOC_STACK");
}
} }
} }
@ -579,7 +605,7 @@ public class ClassGenerator {
codeWriter.println(".flags = " + flags + ","); codeWriter.println(".flags = " + flags + ",");
codeWriter.println(".tag = " + tag + ","); codeWriter.println(".tag = " + tag + ",");
codeWriter.println(".canary = 0,"); codeWriter.println(".canary = 0,");
codeWriter.println(".name = (TeaVM_Object*) (teavm_stringPool + " + nameRef + "),"); codeWriter.println(".name = (TeaVM_Object**) &TEAVM_GET_STRING(" + nameRef + "),");
codeWriter.println(".simpleName = NULL,"); codeWriter.println(".simpleName = NULL,");
codeWriter.println(".arrayType = " + arrayTypeExpr + ","); codeWriter.println(".arrayType = " + arrayTypeExpr + ",");
codeWriter.println(".itemType = " + itemTypeExpr + ","); codeWriter.println(".itemType = " + itemTypeExpr + ",");

View File

@ -43,7 +43,7 @@ public final class CodeGeneratorUtil {
} else if (value instanceof String) { } else if (value instanceof String) {
includes.includePath("strings.h"); includes.includePath("strings.h");
int index = context.getStringPool().getStringIndex((String) value); int index = context.getStringPool().getStringIndex((String) value);
writer.print("(teavm_stringPool + " + index + ")"); writer.print("TEAVM_GET_STRING(" + index + ")");
} else if (value instanceof Integer) { } else if (value instanceof Integer) {
writeIntValue(writer, (Integer) value); writeIntValue(writer, (Integer) value);
} else if (value instanceof Long) { } else if (value instanceof Long) {

View File

@ -25,81 +25,25 @@ public class SimpleStringPool implements StringPool {
private ObjectIntMap<String> stringIndexes = new ObjectIntHashMap<>(); private ObjectIntMap<String> stringIndexes = new ObjectIntHashMap<>();
private final List<String> strings = new ArrayList<>(); private final List<String> strings = new ArrayList<>();
private final List<String> readonlyStrings = Collections.unmodifiableList(strings); private final List<String> readonlyStrings = Collections.unmodifiableList(strings);
private final List<FreeIndex> freeIndexes = new ArrayList<>();
private FreeIndex firstFreeIndex;
private FreeIndex lastFreeIndex;
private ObjectIntMap<String> lastStringIndexes = new ObjectIntHashMap<>();
@Override @Override
public int getStringIndex(String string) { public int getStringIndex(String string) {
int index = stringIndexes.getOrDefault(string, -1); int index = stringIndexes.getOrDefault(string, -1);
if (index < 0) { if (index < 0) {
index = lastStringIndexes.getOrDefault(string, -1);
if (index >= 0) {
removeFreeIndex(index);
strings.set(index, string);
} else if (firstFreeIndex != null) {
index = firstFreeIndex.value;
freeIndexes.set(index, null);
firstFreeIndex = firstFreeIndex.next;
if (firstFreeIndex == null) {
lastFreeIndex = null;
}
strings.set(index, string);
} else {
index = strings.size(); index = strings.size();
strings.add(string); strings.add(string);
}
stringIndexes.put(string, index); stringIndexes.put(string, index);
} }
return index; return index;
} }
private void removeFreeIndex(int index) {
FreeIndex freeIndex = freeIndexes.get(index);
if (freeIndex == null) {
return;
}
freeIndexes.set(index, null);
if (freeIndex.previous != null) {
freeIndex.previous.next = freeIndex.next;
} else {
firstFreeIndex = freeIndex.next;
}
if (freeIndex.next != null) {
freeIndex.next.previous = freeIndex.previous;
} else {
lastFreeIndex = freeIndex.previous;
}
}
@Override @Override
public List<String> getStrings() { public List<? extends String> getStrings() {
return readonlyStrings; return readonlyStrings;
} }
public void reset() { public void reset() {
for (int i = freeIndexes.size(); i < strings.size(); ++i) { strings.clear();
FreeIndex freeIndex = new FreeIndex();
freeIndexes.add(freeIndex);
if (lastFreeIndex != null) {
freeIndex.previous = lastFreeIndex;
lastFreeIndex.next = freeIndex;
}
lastFreeIndex = freeIndex;
}
lastStringIndexes.clear();
lastStringIndexes.putAll(stringIndexes);
stringIndexes.clear(); stringIndexes.clear();
for (int i = 0; i < strings.size(); ++i) {
strings.set(i, null);
}
}
static class FreeIndex {
int value;
FreeIndex previous;
FreeIndex next;
} }
} }

View File

@ -20,5 +20,5 @@ import java.util.List;
public interface StringPool { public interface StringPool {
int getStringIndex(String string); int getStringIndex(String string);
List<String> getStrings(); List<? extends String> getStrings();
} }

View File

@ -16,16 +16,21 @@
package org.teavm.backend.c.generate; package org.teavm.backend.c.generate;
import java.util.List; import java.util.List;
import org.teavm.model.ValueType;
import org.teavm.runtime.RuntimeObject;
public class StringPoolGenerator { public class StringPoolGenerator {
private CodeWriter writer; private GenerationContext context;
private String poolVariable;
public StringPoolGenerator(CodeWriter writer) { public StringPoolGenerator(GenerationContext context, String poolVariable) {
this.writer = writer; this.context = context;
this.poolVariable = poolVariable;
} }
public void generate(List<? extends String> strings) { public void generate(CodeWriter writer) {
writer.println("TeaVM_String teavm_stringPool[" + strings.size() + "] = {").indent(); List<? extends String> strings = context.getStringPool().getStrings();
writer.println("TeaVM_String* " + poolVariable + "[" + strings.size() + "] = {").indent();
for (int i = 0; i < strings.size(); ++i) { for (int i = 0; i < strings.size(); ++i) {
String s = strings.get(i); String s = strings.get(i);
if (s == null) { if (s == null) {
@ -35,7 +40,7 @@ public class StringPoolGenerator {
String macroName = codes ? "TEAVM_STRING_FROM_CODES" : "TEAVM_STRING"; String macroName = codes ? "TEAVM_STRING_FROM_CODES" : "TEAVM_STRING";
writer.print(macroName + "(" + s.length() + ", " + s.hashCode() + ","); writer.print(macroName + "(" + s.length() + ", " + s.hashCode() + ",");
if (codes) { if (codes) {
generateNumericStringLiteral(s); generateNumericStringLiteral(writer, s);
} else { } else {
writer.print("u"); writer.print("u");
generateSimpleStringLiteral(writer, s); generateSimpleStringLiteral(writer, s);
@ -50,6 +55,24 @@ public class StringPoolGenerator {
writer.outdent().println("};"); writer.outdent().println("};");
} }
public void generateStringPoolHeaders(CodeWriter writer, IncludeManager includes) {
includes.includeClass("java.lang.String");
String stringClassName = context.getNames().forClassInstance(ValueType.object("java.lang.String"));
writer.print("int32_t stringHeader = TEAVM_PACK_CLASS(&" + stringClassName + ") | ");
CodeGeneratorUtil.writeIntValue(writer, RuntimeObject.GC_MARKED);
writer.println(";");
int size = context.getStringPool().getStrings().size();
writer.println("for (int i = 0; i < " + size + "; ++i) {").indent();
writer.println("TeaVM_String *s = " + poolVariable + "[i];");
writer.println("if (s != NULL) {").indent();
writer.println("s = teavm_registerString(s);");
writer.println("((TeaVM_Object*) s)->header = stringHeader;");
writer.println(poolVariable + "[i] = s;");
writer.outdent().println("}");
writer.outdent().println("}");
}
private boolean hasBadCharacters(String string) { private boolean hasBadCharacters(String string) {
for (int i = 0; i < string.length(); ++i) { for (int i = 0; i < string.length(); ++i) {
char c = string.charAt(i); char c = string.charAt(i);
@ -112,7 +135,7 @@ public class StringPoolGenerator {
} }
} }
private void generateNumericStringLiteral(String string) { private void generateNumericStringLiteral(CodeWriter writer, String string) {
for (int i = 0; i < string.length(); ++i) { for (int i = 0; i < string.length(); ++i) {
if (i > 0) { if (i > 0) {
writer.print(", "); writer.print(", ");

View File

@ -53,6 +53,7 @@ public class PlatformClassMetadataIntrinsic implements Intrinsic {
printFieldAccess(context, invocation, SUPERCLASS_FIELD); printFieldAccess(context, invocation, SUPERCLASS_FIELD);
break; break;
case "getName": case "getName":
context.writer().print("*");
printFieldAccess(context, invocation, NAME_FIELD); printFieldAccess(context, invocation, NAME_FIELD);
break; break;
} }

View File

@ -46,7 +46,7 @@ public abstract class LowLevelNameProvider {
protected Map<String, String> classNames = new HashMap<>(); protected Map<String, String> classNames = new HashMap<>();
protected Map<String, String> classInitializerNames = new HashMap<>(); protected Map<String, String> classInitializerNames = new HashMap<>();
protected Map<String, String> classClassNames = new HashMap<>(); protected Map<String, String> classClassNames = new HashMap<>();
protected Map<String, String> classSystemInitializerNames = new HashMap<>(); protected Map<ValueType, String> classSystemInitializerNames = new HashMap<>();
protected Map<ValueType, String> classInstanceNames = new HashMap<>(); protected Map<ValueType, String> classInstanceNames = new HashMap<>();
protected Map<ValueType, String> supertypeNames = new HashMap<>(); protected Map<ValueType, String> supertypeNames = new HashMap<>();
@ -109,9 +109,9 @@ public abstract class LowLevelNameProvider {
return classInitializerNames.computeIfAbsent(className, k -> pickUnoccupied("initclass_" + suggestForClass(k))); return classInitializerNames.computeIfAbsent(className, k -> pickUnoccupied("initclass_" + suggestForClass(k)));
} }
public String forClassSystemInitializer(String className) { public String forClassSystemInitializer(ValueType type) {
return classSystemInitializerNames.computeIfAbsent(className, k -> pickUnoccupied("sysinitclass_" return classSystemInitializerNames.computeIfAbsent(type, k -> pickUnoccupied("sysinitclass_"
+ suggestForClass(k))); + suggestForType(k)));
} }
public String forClassClass(String className) { public String forClassClass(String className) {

View File

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

View File

@ -39,13 +39,13 @@ public final class ExceptionHandling {
if (location.className == null || location.methodName == null) { if (location.className == null || location.methodName == null) {
Console.printString("(Unknown method)"); Console.printString("(Unknown method)");
} else { } else {
Console.printString(location.className); Console.printString(location.className.value);
Console.printString("."); Console.printString(".");
Console.printString(location.methodName); Console.printString(location.methodName.value);
} }
Console.printString("("); Console.printString("(");
if (location.fileName != null && location.lineNumber >= 0) { if (location.fileName != null && location.lineNumber >= 0) {
Console.printString(location.fileName); Console.printString(location.fileName.value);
Console.printString(":"); Console.printString(":");
Console.printInt(location.lineNumber); Console.printInt(location.lineNumber);
} }
@ -120,8 +120,10 @@ 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;
StackTraceElement element = createElement(location != null ? location.className : "", StackTraceElement element = createElement(
location != null ? location.methodName : "", location != null ? location.fileName : null, 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 ? location.lineNumber : -1); location != null ? location.lineNumber : -1);
target[index++] = element; target[index++] = element;
stackFrame = ShadowStack.getNextStackFrame(stackFrame); stackFrame = ShadowStack.getNextStackFrame(stackFrame);

View File

@ -39,7 +39,7 @@ public class RuntimeClass extends RuntimeObject {
public int flags; public int flags;
public int tag; public int tag;
public int canary; public int canary;
public RuntimeObject name; public RuntimeObjectPtr name;
public RuntimeClass itemType; public RuntimeClass itemType;
public RuntimeClass arrayType; public RuntimeClass arrayType;
public IsSupertypeFunction isSupertypeOf; public IsSupertypeFunction isSupertypeOf;

View File

@ -0,0 +1,22 @@
/*
* 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.Structure;
public class RuntimeObjectPtr extends Structure {
RuntimeObject value;
}

View File

@ -0,0 +1,22 @@
/*
* 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.Structure;
public class StringPtr extends Structure {
String value;
}

View File

@ -44,7 +44,7 @@ TeaVM_ResourceMapEntry* teavm_lookupResource(TeaVM_ResourceMap *map, TeaVM_Strin
if (map->entries[index].key == NULL) { if (map->entries[index].key == NULL) {
return NULL; return NULL;
} }
if (teavm_equals(map->entries[index].key, string)) { if (teavm_equals(*map->entries[index].key, string)) {
return &map->entries[index]; return &map->entries[index];
} }
} }

View File

@ -29,7 +29,7 @@ typedef struct TeaVM_Class {
int32_t flags; int32_t flags;
int32_t tag; int32_t tag;
int32_t canary; int32_t canary;
TeaVM_Object* name; TeaVM_Object** name;
struct TeaVM_Class* itemType; struct TeaVM_Class* itemType;
struct TeaVM_Class* arrayType; struct TeaVM_Class* arrayType;
int32_t (*isSupertypeOf)(struct TeaVM_Class*); int32_t (*isSupertypeOf)(struct TeaVM_Class*);
@ -134,12 +134,7 @@ static inline void* teavm_checkcast(void* obj, int32_t (*cls)(TeaVM_Class*)) {
#define TEAVM_ADDRESS_ADD(address, offset) ((char *) (address) + (offset)) #define TEAVM_ADDRESS_ADD(address, offset) ((char *) (address) + (offset))
#define TEAVM_STRUCTURE_ADD(structure, address, offset) (((structure*) (address)) + offset) #define TEAVM_STRUCTURE_ADD(structure, address, offset) (((structure*) (address)) + offset)
#define TEAVM_NULL_STRING { \ #define TEAVM_STRING(length, hash, s) &(TeaVM_String) { \
.characters = NULL, \
.hashCode = 0 \
}
#define TEAVM_STRING(length, hash, s) { \
.characters = (TeaVM_Array*) & (struct { TeaVM_Array hdr; char16_t data[(length) + 1]; }) { \ .characters = (TeaVM_Array*) & (struct { TeaVM_Array hdr; char16_t data[(length) + 1]; }) { \
.hdr = { .size = length }, \ .hdr = { .size = length }, \
.data = s \ .data = s \
@ -147,7 +142,7 @@ static inline void* teavm_checkcast(void* obj, int32_t (*cls)(TeaVM_Class*)) {
.hashCode = INT32_C(hash) \ .hashCode = INT32_C(hash) \
} }
#define TEAVM_STRING_FROM_CODES(length, hash, ...) { \ #define TEAVM_STRING_FROM_CODES(length, hash, ...) &(TeaVM_String) { \
.characters = (TeaVM_Array*) & (struct { TeaVM_Array hdr; char16_t data[(length) + 1]; }) { \ .characters = (TeaVM_Array*) & (struct { TeaVM_Array hdr; char16_t data[(length) + 1]; }) { \
.hdr = { .size = length }, \ .hdr = { .size = length }, \
.data = { __VA_ARGS__ } \ .data = { __VA_ARGS__ } \
@ -177,7 +172,7 @@ typedef struct {
} TeaVM_ResourceArray; } TeaVM_ResourceArray;
typedef struct { typedef struct {
TeaVM_String* key; TeaVM_String** key;
void* value; void* value;
} TeaVM_ResourceMapEntry; } TeaVM_ResourceMapEntry;
@ -248,3 +243,9 @@ extern void teavm_printInt(int32_t i);
extern TeaVM_Array* teavm_parseArguments(int argc, char** argv); extern TeaVM_Array* teavm_parseArguments(int argc, char** argv);
extern void teavm_registerStaticGcRoots(void***, int count); extern void teavm_registerStaticGcRoots(void***, int count);
extern TeaVM_String* teavm_registerString(TeaVM_String*);
static inline TeaVM_Object* teavm_dereferenceNullable(TeaVM_Object** o) {
return o != NULL ? *o : NULL;
}

View File

@ -0,0 +1,115 @@
#include "runtime.h"
#include <string.h>
#include <stdint.h>
#include <stdlib.h>
#include <uchar.h>
#include <wchar.h>
#define TEAVM_HASHTABLE_ENTRIES 512
typedef struct TeaVM_HashtableEntry {
TeaVM_String* data;
int32_t hash;
struct TeaVM_HashtableEntry* next;
} TeaVM_HashtableEntry;
typedef struct TeaVM_HashtableEntrySet {
TeaVM_HashtableEntry data[TEAVM_HASHTABLE_ENTRIES];
int32_t size;
struct TeaVM_HashtableEntrySet* next;
} TeaVM_HashtableEntrySet;
static TeaVM_HashtableEntry** teavm_stringHashtable = NULL;
static TeaVM_HashtableEntrySet* teavm_stringHashtableData = NULL;
static int32_t teavm_stringHashtableSize = 0;
static int32_t teavm_stringHashtableFill = 0;
static int32_t teavm_stringHashtableThreshold = 0;
static void teavm_updateStringHashtableThreshold() {
teavm_stringHashtableThreshold = (int32_t) (0.6f * teavm_stringHashtableSize) - INT32_C(1);
}
static TeaVM_HashtableEntry* teavm_stringHashtableNewEntry() {
TeaVM_HashtableEntrySet* data = teavm_stringHashtableData;
if (data == NULL || data->size == TEAVM_HASHTABLE_ENTRIES) {
data = malloc(sizeof(TeaVM_HashtableEntrySet));
data->next = teavm_stringHashtableData;
data->size = 0;
teavm_stringHashtableData = data;
}
return &data->data[data->size++];
}
static void teavm_putStringIntoHashtable(TeaVM_String* str, int32_t hash) {
int32_t index = (uint32_t) hash % teavm_stringHashtableSize;
if (teavm_stringHashtable[index] == NULL) {
teavm_stringHashtableFill++;
}
TeaVM_HashtableEntry* entry = teavm_stringHashtableNewEntry();
entry->next = teavm_stringHashtable[index];
entry->hash = hash;
entry->data = str;
teavm_stringHashtable[index] = entry;
}
static void teavm_rehashStrings() {
TeaVM_HashtableEntry** oldHashtable = teavm_stringHashtable;
TeaVM_HashtableEntrySet* oldHashtableData = teavm_stringHashtableData;
int32_t oldHashtableSize = teavm_stringHashtableSize;
teavm_stringHashtableSize = teavm_stringHashtableSize * INT32_C(2);
teavm_updateStringHashtableThreshold();
teavm_stringHashtable = malloc(sizeof(TeaVM_HashtableEntry*) * teavm_stringHashtableSize);
memset(teavm_stringHashtable, 0, sizeof(TeaVM_HashtableEntry*) * teavm_stringHashtableSize);
teavm_stringHashtableData = NULL;
for (int32_t i = 0; i < oldHashtableSize; ++i) {
TeaVM_HashtableEntry* entry = oldHashtable[i];
while (entry != NULL) {
teavm_putStringIntoHashtable(entry->data, entry->hash);
entry = entry->next;
}
}
free(oldHashtable);
while (oldHashtableData != NULL) {
TeaVM_HashtableEntrySet* next = oldHashtableData->next;
free(oldHashtableData);
oldHashtableData = next;
}
}
TeaVM_String* teavm_registerString(TeaVM_String* str) {
if (teavm_stringHashtable == NULL) {
teavm_stringHashtableSize = 256;
teavm_updateStringHashtableThreshold();
teavm_stringHashtable = malloc(sizeof(TeaVM_HashtableEntry*) * teavm_stringHashtableSize);
memset(teavm_stringHashtable, 0, sizeof(TeaVM_HashtableEntry*) * teavm_stringHashtableSize);
}
int32_t hash = teavm_hashCode(str);
int32_t index = (uint32_t) hash % teavm_stringHashtableSize;
TeaVM_HashtableEntry* entry = teavm_stringHashtable[index];
while (entry != NULL) {
if (entry->hash == hash && teavm_equals(entry->data, str)) {
return entry->data;
}
entry = entry->next;
}
if (teavm_stringHashtable[index] == NULL) {
if (teavm_stringHashtableFill >= teavm_stringHashtableThreshold) {
teavm_rehashStrings();
int32_t index = (uint32_t) hash % teavm_stringHashtableSize;
}
teavm_stringHashtableFill++;
}
entry = teavm_stringHashtableNewEntry();
entry->next = teavm_stringHashtable[index];
entry->hash = hash;
entry->data = str;
teavm_stringHashtable[index] = entry;
return str;
}

View File

@ -65,7 +65,7 @@ class MetadataCIntrinsic implements Generator {
} else if (value instanceof String) { } else if (value instanceof String) {
int stringIndex = context.stringPool().getStringIndex((String) value); int stringIndex = context.stringPool().getStringIndex((String) value);
context.includes().includePath("strings.h"); context.includes().includePath("strings.h");
context.writerBefore().print("(TeaVM_Object*) (teavm_stringPool + " + stringIndex + ")"); context.writerBefore().print("(TeaVM_Object**) &TEAVM_GET_STRING(" + stringIndex + ")");
} else if (value instanceof Boolean) { } else if (value instanceof Boolean) {
context.writerBefore().print((Boolean) value ? "1" : "0"); context.writerBefore().print((Boolean) value ? "1" : "0");
} else if (value instanceof Integer) { } else if (value instanceof Integer) {
@ -164,7 +164,7 @@ class MetadataCIntrinsic implements Generator {
} else if (Resource.class.isAssignableFrom(cls)) { } else if (Resource.class.isAssignableFrom(cls)) {
return "void*"; return "void*";
} else if (cls == String.class) { } else if (cls == String.class) {
return "TeaVM_Object*"; return "TeaVM_Object**";
} else { } else {
throw new IllegalArgumentException("Don't know how to write resource type " + cls); throw new IllegalArgumentException("Don't know how to write resource type " + cls);
} }
@ -237,8 +237,8 @@ class MetadataCIntrinsic implements Generator {
if (key == null) { if (key == null) {
context.writerBefore().print("{ NULL, NULL }"); context.writerBefore().print("{ NULL, NULL }");
} else { } else {
context.writerBefore().print("{ teavm_stringPool + " context.writerBefore().print("{ &TEAVM_GET_STRING("
+ context.stringPool().getStringIndex(key) + ", "); + context.stringPool().getStringIndex(key) + "), ");
writeValue(context, resourceMap.get(key)); writeValue(context, resourceMap.get(key));
context.writerBefore().print("}"); context.writerBefore().print("}");
} }

View File

@ -59,10 +59,17 @@ public class ResourceReadCIntrinsic implements Intrinsic {
String resourceName = "resources/" + context.escapeFileName(invocation.getMethod().getClassName()) + ".h"; String resourceName = "resources/" + context.escapeFileName(invocation.getMethod().getClassName()) + ".h";
context.includes().includePath(resourceName); context.includes().includePath(resourceName);
boolean isString = invocation.getMethod().getReturnType().isObject("java.lang.String");
if (isString) {
context.writer().print("teavm_dereferenceNullable(");
}
context.writer().print("TEAVM_FIELD("); context.writer().print("TEAVM_FIELD(");
context.emit(invocation.getArguments().get(0)); context.emit(invocation.getArguments().get(0));
context.writer().print(", ").print(context.names().forClass(invocation.getMethod().getClassName())); context.writer().print(", ").print(context.names().forClass(invocation.getMethod().getClassName()));
context.writer().print(", ").print(name).print(")"); context.writer().print(", ").print(name).print(")");
if (isString) {
context.writer().print(")");
}
} }
private void applyForResourceMap(IntrinsicContext context, InvocationExpr invocation) { private void applyForResourceMap(IntrinsicContext context, InvocationExpr invocation) {

View File

@ -33,7 +33,6 @@ import java.util.Set;
import java.util.function.Consumer; import java.util.function.Consumer;
import java.util.function.Function; import java.util.function.Function;
import org.teavm.backend.c.CTarget; import org.teavm.backend.c.CTarget;
import org.teavm.backend.c.generate.SimpleStringPool;
import org.teavm.cache.InMemoryMethodNodeCache; import org.teavm.cache.InMemoryMethodNodeCache;
import org.teavm.cache.InMemoryProgramCache; import org.teavm.cache.InMemoryProgramCache;
import org.teavm.cache.InMemorySymbolTable; import org.teavm.cache.InMemorySymbolTable;
@ -75,7 +74,6 @@ public class IncrementalCBuilder {
private MemoryCachedClassReaderSource classSource; private MemoryCachedClassReaderSource classSource;
private ReferenceCache referenceCache = new ReferenceCache(); private ReferenceCache referenceCache = new ReferenceCache();
private SimpleStringPool stringPool = new SimpleStringPool();
private InMemorySymbolTable symbolTable = new InMemorySymbolTable(); private InMemorySymbolTable symbolTable = new InMemorySymbolTable();
private InMemorySymbolTable fileSymbolTable = new InMemorySymbolTable(); private InMemorySymbolTable fileSymbolTable = new InMemorySymbolTable();
private InMemorySymbolTable variableSymbolTable = new InMemorySymbolTable(); private InMemorySymbolTable variableSymbolTable = new InMemorySymbolTable();
@ -309,7 +307,7 @@ public class IncrementalCBuilder {
classSource.setProvider(name -> PreOptimizingClassHolderSource.optimize(classPathMapper, name)); classSource.setProvider(name -> PreOptimizingClassHolderSource.optimize(classPathMapper, name));
long startTime = System.currentTimeMillis(); long startTime = System.currentTimeMillis();
CTarget cTarget = new CTarget(stringPool); CTarget cTarget = new CTarget();
TeaVM vm = new TeaVMBuilder(cTarget) TeaVM vm = new TeaVMBuilder(cTarget)
.setReferenceCache(referenceCache) .setReferenceCache(referenceCache)
@ -369,7 +367,6 @@ public class IncrementalCBuilder {
astCache.discard(); astCache.discard();
programCache.discard(); programCache.discard();
buildTarget.reset(); buildTarget.reset();
stringPool.reset();
cancelRequested = false; cancelRequested = false;
} }