mirror of
https://github.com/Eaglercraft-TeaVM-Fork/eagler-teavm.git
synced 2024-12-22 08:14:09 -08:00
C: improve generation of string pool for incremental mode
This commit is contained in:
parent
0003ed0bb2
commit
8e08cf6dcd
|
@ -47,7 +47,6 @@ import org.teavm.backend.c.generate.NameProvider;
|
|||
import org.teavm.backend.c.generate.OutputFileUtil;
|
||||
import org.teavm.backend.c.generate.SimpleIncludeManager;
|
||||
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.generators.ArrayGenerator;
|
||||
import org.teavm.backend.c.generators.Generator;
|
||||
|
@ -145,15 +144,7 @@ public class CTarget implements TeaVMTarget, TeaVMCHost {
|
|||
private Set<MethodReference> asyncMethods;
|
||||
private boolean incremental;
|
||||
private boolean lineNumbersGenerated;
|
||||
private StringPool stringPool;
|
||||
|
||||
public CTarget() {
|
||||
this(new SimpleStringPool());
|
||||
}
|
||||
|
||||
public CTarget(StringPool stringPool) {
|
||||
this.stringPool = stringPool;
|
||||
}
|
||||
private SimpleStringPool stringPool;
|
||||
|
||||
public void setMinHeapSize(int minHeapSize) {
|
||||
this.minHeapSize = minHeapSize;
|
||||
|
@ -333,6 +324,7 @@ public class CTarget implements TeaVMTarget, TeaVMCHost {
|
|||
List<Generator> generators = new ArrayList<>();
|
||||
generators.add(new ArrayGenerator());
|
||||
|
||||
stringPool = new SimpleStringPool();
|
||||
GenerationContext context = new GenerationContext(vtableProvider, characteristics,
|
||||
controller.getDependencyInfo(), stringPool, nameProvider, controller.getDiagnostics(), classes,
|
||||
intrinsics, generators, asyncMethods::contains, buildTarget, incremental);
|
||||
|
@ -363,9 +355,12 @@ public class CTarget implements TeaVMTarget, TeaVMCHost {
|
|||
generateSpecialFunctions(context, runtimeWriter);
|
||||
OutputFileUtil.write(runtimeWriter, "runtime.c", 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());
|
||||
generateStrings(buildTarget, stringPool);
|
||||
generateStrings(buildTarget, context);
|
||||
|
||||
List<ValueType> types = classGenerator.getTypes().stream()
|
||||
.filter(c -> ClassGenerator.needsVirtualTable(characteristics, c))
|
||||
|
@ -374,7 +369,6 @@ public class CTarget implements TeaVMTarget, TeaVMCHost {
|
|||
generateAllFile(classes, types, buildTarget);
|
||||
}
|
||||
|
||||
|
||||
private void emitResource(CodeWriter writer, String resourceName) {
|
||||
ClassLoader classLoader = CTarget.class.getClassLoader();
|
||||
try (BufferedReader reader = new BufferedReader(new InputStreamReader(
|
||||
|
@ -407,6 +401,9 @@ public class CTarget implements TeaVMTarget, TeaVMCHost {
|
|||
String name = ClassGenerator.fileName(className);
|
||||
OutputFileUtil.write(writer, name + ".c", buildTarget);
|
||||
OutputFileUtil.write(headerWriter, name + ".h", buildTarget);
|
||||
if (incremental) {
|
||||
stringPool.reset();
|
||||
}
|
||||
}
|
||||
|
||||
for (ValueType type : classGenerator.getTypes()) {
|
||||
|
@ -419,6 +416,9 @@ public class CTarget implements TeaVMTarget, TeaVMCHost {
|
|||
String name = ClassGenerator.fileName(type);
|
||||
OutputFileUtil.write(writer, name + ".c", 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)");
|
||||
}
|
||||
|
||||
private void generateStrings(BuildTarget buildTarget, StringPool stringPool) throws IOException {
|
||||
private void generateStrings(BuildTarget buildTarget, GenerationContext context) throws IOException {
|
||||
BufferedCodeWriter writer = new BufferedCodeWriter(false);
|
||||
IncludeManager includes = new SimpleIncludeManager(writer);
|
||||
includes.init("strings.c");
|
||||
BufferedCodeWriter headerWriter = new BufferedCodeWriter(false);
|
||||
|
||||
headerWriter.println("#pragma once");
|
||||
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\"");
|
||||
new StringPoolGenerator(writer).generate(stringPool.getStrings());
|
||||
writer.println("#include \"strings.h\"");
|
||||
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(headerWriter, "strings.h", buildTarget);
|
||||
|
@ -652,10 +664,10 @@ public class CTarget implements TeaVMTarget, TeaVMCHost {
|
|||
writer.println("teavm_beforeInit();");
|
||||
writer.println("teavm_initHeap(" + minHeapSize + ");");
|
||||
generateVirtualTableHeaders(context, writer, types);
|
||||
generateStringPoolHeaders(context, writer);
|
||||
for (String className : classes.getClassNames()) {
|
||||
includes.includeClass(className);
|
||||
writer.println(context.getNames().forClassSystemInitializer(className) + "();");
|
||||
writer.println("teavm_initStringPool();");
|
||||
for (ValueType type : types) {
|
||||
includes.includeType(type);
|
||||
writer.println(context.getNames().forClassSystemInitializer(type) + "();");
|
||||
}
|
||||
writer.println("teavm_afterInitClasses();");
|
||||
generateStaticInitializerCalls(context, writer, includes, classes);
|
||||
|
@ -705,19 +717,6 @@ public class CTarget implements TeaVMTarget, TeaVMCHost {
|
|||
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) {
|
||||
String startName = context.getNames().forMethod(new MethodReference(Fiber.class,
|
||||
"startMain", String[].class, void.class));
|
||||
|
|
|
@ -183,6 +183,6 @@ public class CallSiteGenerator {
|
|||
}
|
||||
|
||||
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";
|
||||
}
|
||||
}
|
||||
|
|
|
@ -84,7 +84,6 @@ public class ClassGenerator {
|
|||
private CodeWriter headerWriter;
|
||||
private IncludeManager includes;
|
||||
private IncludeManager headerIncludes;
|
||||
private boolean stackDefined;
|
||||
|
||||
public ClassGenerator(GenerationContext context, ClassReaderSource unprocessedClassSource,
|
||||
TagRegistry tagRegistry, Decompiler decompiler) {
|
||||
|
@ -165,18 +164,10 @@ public class ClassGenerator {
|
|||
};
|
||||
|
||||
public void generateClass(CodeWriter writer, CodeWriter headerWriter, ClassHolder cls) {
|
||||
stackDefined = false;
|
||||
init(writer, headerWriter, fileName(cls.getName()));
|
||||
|
||||
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());
|
||||
ValueType type = ValueType.object(cls.getName());
|
||||
init(writer, headerWriter, fileName(cls.getName()), type);
|
||||
|
||||
generateStringPoolDecl(type);
|
||||
generateClassStructure(cls);
|
||||
generateClassStaticFields(cls);
|
||||
generateClassMethods(cls);
|
||||
|
@ -184,6 +175,7 @@ public class ClassGenerator {
|
|||
generateVirtualTable(ValueType.object(cls.getName()));
|
||||
generateStaticGCRoots(cls.getName());
|
||||
generateLayoutArray(cls.getName());
|
||||
generateStringPool(type);
|
||||
}
|
||||
|
||||
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) {
|
||||
init(writer, headerWriter, fileName(type));
|
||||
init(writer, headerWriter, fileName(type), type);
|
||||
generateStringPoolDecl(type);
|
||||
includes.includeType(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;
|
||||
classLayout = null;
|
||||
|
||||
|
@ -211,6 +205,38 @@ public class ClassGenerator {
|
|||
headerIncludes = new SimpleIncludeManager(headerWriter);
|
||||
headerIncludes.init(fileName + ".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() {
|
||||
|
@ -242,17 +268,17 @@ public class ClassGenerator {
|
|||
} else {
|
||||
callSitesName = "NULL";
|
||||
}
|
||||
if (stackDefined) {
|
||||
codeWriter.println("#undef TEAVM_ALLOC_STACK");
|
||||
}
|
||||
codeWriter.println("#define TEAVM_ALLOC_STACK(size) TEAVM_ALLOC_STACK_DEF(size, "
|
||||
+ callSitesName + ")");
|
||||
stackDefined = true;
|
||||
}
|
||||
|
||||
generateMethodForwardDeclaration(method);
|
||||
RegularMethodNode methodNode = decompiler.decompileRegular(method);
|
||||
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(".tag = " + tag + ",");
|
||||
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(".arrayType = " + arrayTypeExpr + ",");
|
||||
codeWriter.println(".itemType = " + itemTypeExpr + ",");
|
||||
|
|
|
@ -43,7 +43,7 @@ public final class CodeGeneratorUtil {
|
|||
} else if (value instanceof String) {
|
||||
includes.includePath("strings.h");
|
||||
int index = context.getStringPool().getStringIndex((String) value);
|
||||
writer.print("(teavm_stringPool + " + index + ")");
|
||||
writer.print("TEAVM_GET_STRING(" + index + ")");
|
||||
} else if (value instanceof Integer) {
|
||||
writeIntValue(writer, (Integer) value);
|
||||
} else if (value instanceof Long) {
|
||||
|
|
|
@ -25,81 +25,25 @@ public class SimpleStringPool implements StringPool {
|
|||
private ObjectIntMap<String> stringIndexes = new ObjectIntHashMap<>();
|
||||
private final List<String> strings = new ArrayList<>();
|
||||
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
|
||||
public int getStringIndex(String string) {
|
||||
int index = stringIndexes.getOrDefault(string, -1);
|
||||
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();
|
||||
strings.add(string);
|
||||
}
|
||||
index = strings.size();
|
||||
strings.add(string);
|
||||
stringIndexes.put(string, 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
|
||||
public List<String> getStrings() {
|
||||
public List<? extends String> getStrings() {
|
||||
return readonlyStrings;
|
||||
}
|
||||
|
||||
public void reset() {
|
||||
for (int i = freeIndexes.size(); i < strings.size(); ++i) {
|
||||
FreeIndex freeIndex = new FreeIndex();
|
||||
freeIndexes.add(freeIndex);
|
||||
if (lastFreeIndex != null) {
|
||||
freeIndex.previous = lastFreeIndex;
|
||||
lastFreeIndex.next = freeIndex;
|
||||
}
|
||||
lastFreeIndex = freeIndex;
|
||||
}
|
||||
lastStringIndexes.clear();
|
||||
lastStringIndexes.putAll(stringIndexes);
|
||||
strings.clear();
|
||||
stringIndexes.clear();
|
||||
for (int i = 0; i < strings.size(); ++i) {
|
||||
strings.set(i, null);
|
||||
}
|
||||
}
|
||||
|
||||
static class FreeIndex {
|
||||
int value;
|
||||
FreeIndex previous;
|
||||
FreeIndex next;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,5 +20,5 @@ import java.util.List;
|
|||
public interface StringPool {
|
||||
int getStringIndex(String string);
|
||||
|
||||
List<String> getStrings();
|
||||
List<? extends String> getStrings();
|
||||
}
|
||||
|
|
|
@ -16,16 +16,21 @@
|
|||
package org.teavm.backend.c.generate;
|
||||
|
||||
import java.util.List;
|
||||
import org.teavm.model.ValueType;
|
||||
import org.teavm.runtime.RuntimeObject;
|
||||
|
||||
public class StringPoolGenerator {
|
||||
private CodeWriter writer;
|
||||
private GenerationContext context;
|
||||
private String poolVariable;
|
||||
|
||||
public StringPoolGenerator(CodeWriter writer) {
|
||||
this.writer = writer;
|
||||
public StringPoolGenerator(GenerationContext context, String poolVariable) {
|
||||
this.context = context;
|
||||
this.poolVariable = poolVariable;
|
||||
}
|
||||
|
||||
public void generate(List<? extends String> strings) {
|
||||
writer.println("TeaVM_String teavm_stringPool[" + strings.size() + "] = {").indent();
|
||||
public void generate(CodeWriter writer) {
|
||||
List<? extends String> strings = context.getStringPool().getStrings();
|
||||
writer.println("TeaVM_String* " + poolVariable + "[" + strings.size() + "] = {").indent();
|
||||
for (int i = 0; i < strings.size(); ++i) {
|
||||
String s = strings.get(i);
|
||||
if (s == null) {
|
||||
|
@ -35,7 +40,7 @@ public class StringPoolGenerator {
|
|||
String macroName = codes ? "TEAVM_STRING_FROM_CODES" : "TEAVM_STRING";
|
||||
writer.print(macroName + "(" + s.length() + ", " + s.hashCode() + ",");
|
||||
if (codes) {
|
||||
generateNumericStringLiteral(s);
|
||||
generateNumericStringLiteral(writer, s);
|
||||
} else {
|
||||
writer.print("u");
|
||||
generateSimpleStringLiteral(writer, s);
|
||||
|
@ -50,6 +55,24 @@ public class StringPoolGenerator {
|
|||
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) {
|
||||
for (int i = 0; i < string.length(); ++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) {
|
||||
if (i > 0) {
|
||||
writer.print(", ");
|
||||
|
|
|
@ -53,6 +53,7 @@ public class PlatformClassMetadataIntrinsic implements Intrinsic {
|
|||
printFieldAccess(context, invocation, SUPERCLASS_FIELD);
|
||||
break;
|
||||
case "getName":
|
||||
context.writer().print("*");
|
||||
printFieldAccess(context, invocation, NAME_FIELD);
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -46,7 +46,7 @@ public abstract class LowLevelNameProvider {
|
|||
protected Map<String, String> classNames = new HashMap<>();
|
||||
protected Map<String, String> classInitializerNames = 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> supertypeNames = new HashMap<>();
|
||||
|
||||
|
@ -109,9 +109,9 @@ public abstract class LowLevelNameProvider {
|
|||
return classInitializerNames.computeIfAbsent(className, k -> pickUnoccupied("initclass_" + suggestForClass(k)));
|
||||
}
|
||||
|
||||
public String forClassSystemInitializer(String className) {
|
||||
return classSystemInitializerNames.computeIfAbsent(className, k -> pickUnoccupied("sysinitclass_"
|
||||
+ suggestForClass(k)));
|
||||
public String forClassSystemInitializer(ValueType type) {
|
||||
return classSystemInitializerNames.computeIfAbsent(type, k -> pickUnoccupied("sysinitclass_"
|
||||
+ suggestForType(k)));
|
||||
}
|
||||
|
||||
public String forClassClass(String className) {
|
||||
|
|
|
@ -22,8 +22,8 @@ import org.teavm.interop.Unmanaged;
|
|||
@Unmanaged
|
||||
@StaticInit
|
||||
public class CallSiteLocation extends Structure {
|
||||
public String fileName;
|
||||
public String className;
|
||||
public String methodName;
|
||||
public StringPtr fileName;
|
||||
public StringPtr className;
|
||||
public StringPtr methodName;
|
||||
public int lineNumber;
|
||||
}
|
||||
|
|
|
@ -39,13 +39,13 @@ public final class ExceptionHandling {
|
|||
if (location.className == null || location.methodName == null) {
|
||||
Console.printString("(Unknown method)");
|
||||
} else {
|
||||
Console.printString(location.className);
|
||||
Console.printString(location.className.value);
|
||||
Console.printString(".");
|
||||
Console.printString(location.methodName);
|
||||
Console.printString(location.methodName.value);
|
||||
}
|
||||
Console.printString("(");
|
||||
if (location.fileName != null && location.lineNumber >= 0) {
|
||||
Console.printString(location.fileName);
|
||||
Console.printString(location.fileName.value);
|
||||
Console.printString(":");
|
||||
Console.printInt(location.lineNumber);
|
||||
}
|
||||
|
@ -120,8 +120,10 @@ public final class ExceptionHandling {
|
|||
int callSiteId = ShadowStack.getCallSiteId(stackFrame);
|
||||
CallSite callSite = findCallSiteById(callSiteId, stackFrame);
|
||||
CallSiteLocation location = callSite.location;
|
||||
StackTraceElement element = createElement(location != null ? location.className : "",
|
||||
location != null ? location.methodName : "", location != null ? location.fileName : null,
|
||||
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 ? location.lineNumber : -1);
|
||||
target[index++] = element;
|
||||
stackFrame = ShadowStack.getNextStackFrame(stackFrame);
|
||||
|
|
|
@ -39,7 +39,7 @@ public class RuntimeClass extends RuntimeObject {
|
|||
public int flags;
|
||||
public int tag;
|
||||
public int canary;
|
||||
public RuntimeObject name;
|
||||
public RuntimeObjectPtr name;
|
||||
public RuntimeClass itemType;
|
||||
public RuntimeClass arrayType;
|
||||
public IsSupertypeFunction isSupertypeOf;
|
||||
|
|
22
core/src/main/java/org/teavm/runtime/RuntimeObjectPtr.java
Normal file
22
core/src/main/java/org/teavm/runtime/RuntimeObjectPtr.java
Normal 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;
|
||||
}
|
22
core/src/main/java/org/teavm/runtime/StringPtr.java
Normal file
22
core/src/main/java/org/teavm/runtime/StringPtr.java
Normal 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;
|
||||
}
|
|
@ -44,7 +44,7 @@ TeaVM_ResourceMapEntry* teavm_lookupResource(TeaVM_ResourceMap *map, TeaVM_Strin
|
|||
if (map->entries[index].key == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
if (teavm_equals(map->entries[index].key, string)) {
|
||||
if (teavm_equals(*map->entries[index].key, string)) {
|
||||
return &map->entries[index];
|
||||
}
|
||||
}
|
||||
|
|
|
@ -29,7 +29,7 @@ typedef struct TeaVM_Class {
|
|||
int32_t flags;
|
||||
int32_t tag;
|
||||
int32_t canary;
|
||||
TeaVM_Object* name;
|
||||
TeaVM_Object** name;
|
||||
struct TeaVM_Class* itemType;
|
||||
struct TeaVM_Class* arrayType;
|
||||
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_STRUCTURE_ADD(structure, address, offset) (((structure*) (address)) + offset)
|
||||
|
||||
#define TEAVM_NULL_STRING { \
|
||||
.characters = NULL, \
|
||||
.hashCode = 0 \
|
||||
}
|
||||
|
||||
#define TEAVM_STRING(length, hash, s) { \
|
||||
#define TEAVM_STRING(length, hash, s) &(TeaVM_String) { \
|
||||
.characters = (TeaVM_Array*) & (struct { TeaVM_Array hdr; char16_t data[(length) + 1]; }) { \
|
||||
.hdr = { .size = length }, \
|
||||
.data = s \
|
||||
|
@ -147,7 +142,7 @@ static inline void* teavm_checkcast(void* obj, int32_t (*cls)(TeaVM_Class*)) {
|
|||
.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]; }) { \
|
||||
.hdr = { .size = length }, \
|
||||
.data = { __VA_ARGS__ } \
|
||||
|
@ -177,7 +172,7 @@ typedef struct {
|
|||
} TeaVM_ResourceArray;
|
||||
|
||||
typedef struct {
|
||||
TeaVM_String* key;
|
||||
TeaVM_String** key;
|
||||
void* value;
|
||||
} TeaVM_ResourceMapEntry;
|
||||
|
||||
|
@ -247,4 +242,10 @@ extern void teavm_printInt(int32_t i);
|
|||
|
||||
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;
|
||||
}
|
115
core/src/main/resources/org/teavm/backend/c/stringhash.c
Normal file
115
core/src/main/resources/org/teavm/backend/c/stringhash.c
Normal 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;
|
||||
}
|
|
@ -65,7 +65,7 @@ class MetadataCIntrinsic implements Generator {
|
|||
} else if (value instanceof String) {
|
||||
int stringIndex = context.stringPool().getStringIndex((String) value);
|
||||
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) {
|
||||
context.writerBefore().print((Boolean) value ? "1" : "0");
|
||||
} else if (value instanceof Integer) {
|
||||
|
@ -164,7 +164,7 @@ class MetadataCIntrinsic implements Generator {
|
|||
} else if (Resource.class.isAssignableFrom(cls)) {
|
||||
return "void*";
|
||||
} else if (cls == String.class) {
|
||||
return "TeaVM_Object*";
|
||||
return "TeaVM_Object**";
|
||||
} else {
|
||||
throw new IllegalArgumentException("Don't know how to write resource type " + cls);
|
||||
}
|
||||
|
@ -237,8 +237,8 @@ class MetadataCIntrinsic implements Generator {
|
|||
if (key == null) {
|
||||
context.writerBefore().print("{ NULL, NULL }");
|
||||
} else {
|
||||
context.writerBefore().print("{ teavm_stringPool + "
|
||||
+ context.stringPool().getStringIndex(key) + ", ");
|
||||
context.writerBefore().print("{ &TEAVM_GET_STRING("
|
||||
+ context.stringPool().getStringIndex(key) + "), ");
|
||||
writeValue(context, resourceMap.get(key));
|
||||
context.writerBefore().print("}");
|
||||
}
|
||||
|
|
|
@ -59,10 +59,17 @@ public class ResourceReadCIntrinsic implements Intrinsic {
|
|||
|
||||
String resourceName = "resources/" + context.escapeFileName(invocation.getMethod().getClassName()) + ".h";
|
||||
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.emit(invocation.getArguments().get(0));
|
||||
context.writer().print(", ").print(context.names().forClass(invocation.getMethod().getClassName()));
|
||||
context.writer().print(", ").print(name).print(")");
|
||||
if (isString) {
|
||||
context.writer().print(")");
|
||||
}
|
||||
}
|
||||
|
||||
private void applyForResourceMap(IntrinsicContext context, InvocationExpr invocation) {
|
||||
|
|
|
@ -33,7 +33,6 @@ import java.util.Set;
|
|||
import java.util.function.Consumer;
|
||||
import java.util.function.Function;
|
||||
import org.teavm.backend.c.CTarget;
|
||||
import org.teavm.backend.c.generate.SimpleStringPool;
|
||||
import org.teavm.cache.InMemoryMethodNodeCache;
|
||||
import org.teavm.cache.InMemoryProgramCache;
|
||||
import org.teavm.cache.InMemorySymbolTable;
|
||||
|
@ -75,7 +74,6 @@ public class IncrementalCBuilder {
|
|||
private MemoryCachedClassReaderSource classSource;
|
||||
|
||||
private ReferenceCache referenceCache = new ReferenceCache();
|
||||
private SimpleStringPool stringPool = new SimpleStringPool();
|
||||
private InMemorySymbolTable symbolTable = new InMemorySymbolTable();
|
||||
private InMemorySymbolTable fileSymbolTable = new InMemorySymbolTable();
|
||||
private InMemorySymbolTable variableSymbolTable = new InMemorySymbolTable();
|
||||
|
@ -309,7 +307,7 @@ public class IncrementalCBuilder {
|
|||
classSource.setProvider(name -> PreOptimizingClassHolderSource.optimize(classPathMapper, name));
|
||||
|
||||
long startTime = System.currentTimeMillis();
|
||||
CTarget cTarget = new CTarget(stringPool);
|
||||
CTarget cTarget = new CTarget();
|
||||
|
||||
TeaVM vm = new TeaVMBuilder(cTarget)
|
||||
.setReferenceCache(referenceCache)
|
||||
|
@ -369,7 +367,6 @@ public class IncrementalCBuilder {
|
|||
astCache.discard();
|
||||
programCache.discard();
|
||||
buildTarget.reset();
|
||||
stringPool.reset();
|
||||
cancelRequested = false;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue
Block a user