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.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());
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));

View File

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

View File

@ -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 + ",");

View File

@ -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) {

View File

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

View File

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

View File

@ -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(", ");

View File

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

View File

@ -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) {

View File

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

View File

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

View File

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

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) {
return NULL;
}
if (teavm_equals(map->entries[index].key, string)) {
if (teavm_equals(*map->entries[index].key, string)) {
return &map->entries[index];
}
}

View File

@ -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;
@ -248,3 +243,9 @@ extern void teavm_printInt(int32_t i);
extern TeaVM_Array* teavm_parseArguments(int argc, char** argv);
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) {
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("}");
}

View File

@ -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) {

View File

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