diff --git a/core/src/main/java/org/teavm/backend/c/CTarget.java b/core/src/main/java/org/teavm/backend/c/CTarget.java index de79e69dd..c6762ae29 100644 --- a/core/src/main/java/org/teavm/backend/c/CTarget.java +++ b/core/src/main/java/org/teavm/backend/c/CTarget.java @@ -76,6 +76,8 @@ import org.teavm.backend.lowlevel.dependency.ExceptionHandlingDependencyListener import org.teavm.backend.lowlevel.dependency.WeakReferenceDependencyListener; import org.teavm.backend.lowlevel.transform.CoroutineTransformation; import org.teavm.backend.lowlevel.transform.WeakReferenceTransformation; +import org.teavm.cache.EmptyMethodNodeCache; +import org.teavm.cache.MethodNodeCache; import org.teavm.dependency.ClassDependency; import org.teavm.dependency.DependencyAnalyzer; import org.teavm.dependency.DependencyListener; @@ -148,6 +150,7 @@ public class CTarget implements TeaVMTarget, TeaVMCHost { private List generatorFactories = new ArrayList<>(); private Characteristics characteristics; private Set asyncMethods; + private MethodNodeCache astCache = EmptyMethodNodeCache.INSTANCE; private boolean incremental; private boolean lineNumbersGenerated; private SimpleStringPool stringPool; @@ -164,6 +167,10 @@ public class CTarget implements TeaVMTarget, TeaVMCHost { this.lineNumbersGenerated = lineNumbersGenerated; } + public void setAstCache(MethodNodeCache astCache) { + this.astCache = astCache; + } + @Override public List getTransformers() { List transformers = new ArrayList<>(); @@ -352,7 +359,9 @@ public class CTarget implements TeaVMTarget, TeaVMCHost { } emitResource(runtimeHeaderWriter, "runtime.h"); - ClassGenerator classGenerator = new ClassGenerator(context, tagRegistry, decompiler); + ClassGenerator classGenerator = new ClassGenerator(context, tagRegistry, decompiler, + controller.getCacheStatus()); + classGenerator.setAstCache(astCache); IntrinsicFactoryContextImpl intrinsicFactoryContext = new IntrinsicFactoryContextImpl( controller.getUnprocessedClassSource(), controller.getClassLoader(), controller.getServices(), controller.getProperties()); @@ -642,6 +651,8 @@ public class CTarget implements TeaVMTarget, TeaVMCHost { private void generateAllFile(ListableClassHolderSource classes, List types, BuildTarget buildTarget) throws IOException { + List allFiles = getGeneratedFiles(classes, types); + BufferedCodeWriter writer = new BufferedCodeWriter(false); writer.println("#define _XOPEN_SOURCE"); writer.println("#define __USE_XOPEN"); @@ -649,23 +660,38 @@ public class CTarget implements TeaVMTarget, TeaVMCHost { IncludeManager includes = new SimpleIncludeManager(writer); includes.init("all.c"); - includes.includePath("runtime.c"); - includes.includePath("stringhash.c"); - includes.includePath("strings.c"); - includes.includePath("callsites.c"); - includes.includePath("references.c"); - includes.includePath("date.c"); - - for (String className : classes.getClassNames()) { - includes.includePath(ClassGenerator.fileName(className) + ".c"); + for (String file : allFiles) { + includes.includePath(file); } - for (ValueType type : types) { - includes.includePath(ClassGenerator.fileName(type) + ".c"); - } - - includes.includePath("main.c"); OutputFileUtil.write(writer, "all.c", buildTarget); + + writer = new BufferedCodeWriter(false); + for (String file : allFiles) { + writer.println(file); + } + OutputFileUtil.write(writer, "all.txt", buildTarget); + } + + private List getGeneratedFiles(ListableClassHolderSource classes, List types) { + List files = new ArrayList<>(); + files.add("runtime.c"); + files.add("stringhash.c"); + files.add("strings.c"); + files.add("callsites.c"); + files.add("references.c"); + files.add("date.c"); + + for (String className : classes.getClassNames()) { + files.add(ClassGenerator.fileName(className) + ".c"); + } + for (ValueType type : types) { + files.add(ClassGenerator.fileName(type) + ".c"); + } + + files.add("main.c"); + + return files; } private void generateArrayOfClassReferences(GenerationContext context, CodeWriter writer, IncludeManager includes, diff --git a/core/src/main/java/org/teavm/backend/c/generate/ClassGenerator.java b/core/src/main/java/org/teavm/backend/c/generate/ClassGenerator.java index 18a320f11..c1cc87d29 100644 --- a/core/src/main/java/org/teavm/backend/c/generate/ClassGenerator.java +++ b/core/src/main/java/org/teavm/backend/c/generate/ClassGenerator.java @@ -25,10 +25,16 @@ import java.util.LinkedHashSet; import java.util.List; import java.util.Set; import java.util.stream.Collectors; +import org.teavm.ast.ControlFlowEntry; import org.teavm.ast.RegularMethodNode; import org.teavm.ast.decompilation.Decompiler; import org.teavm.backend.c.generators.Generator; import org.teavm.backend.lowlevel.generate.ClassGeneratorUtil; +import org.teavm.cache.AstCacheEntry; +import org.teavm.cache.AstDependencyExtractor; +import org.teavm.cache.CacheStatus; +import org.teavm.cache.EmptyMethodNodeCache; +import org.teavm.cache.MethodNodeCache; import org.teavm.interop.Address; import org.teavm.interop.DelegateTo; import org.teavm.interop.NoGcRoot; @@ -77,6 +83,7 @@ public class ClassGenerator { private GenerationContext context; private Decompiler decompiler; + private CacheStatus cacheStatus; private TagRegistry tagRegistry; private CodeGenerator codeGenerator; private FieldReference[] staticGcRoots; @@ -87,11 +94,19 @@ public class ClassGenerator { private CodeWriter headerWriter; private IncludeManager includes; private IncludeManager headerIncludes; + private MethodNodeCache astCache = EmptyMethodNodeCache.INSTANCE; + private AstDependencyExtractor dependencyExtractor = new AstDependencyExtractor(); - public ClassGenerator(GenerationContext context, TagRegistry tagRegistry, Decompiler decompiler) { + public ClassGenerator(GenerationContext context, TagRegistry tagRegistry, Decompiler decompiler, + CacheStatus cacheStatus) { this.context = context; this.tagRegistry = tagRegistry; this.decompiler = decompiler; + this.cacheStatus = cacheStatus; + } + + public void setAstCache(MethodNodeCache astCache) { + this.astCache = astCache; } public void prepare(ListableClassHolderSource classes) { @@ -274,7 +289,16 @@ public class ClassGenerator { } generateMethodForwardDeclaration(method); - RegularMethodNode methodNode = decompiler.decompileRegular(method); + RegularMethodNode methodNode; + AstCacheEntry entry = astCache.get(method.getReference(), cacheStatus); + if (entry == null) { + methodNode = decompiler.decompileRegular(method); + astCache.store(method.getReference(), new AstCacheEntry(methodNode, new ControlFlowEntry[0]), + () -> dependencyExtractor.extract(methodNode)); + } else { + methodNode = entry.method; + } + codeGenerator.generateMethod(methodNode); if (context.isIncremental()) { diff --git a/tools/c-incremental/src/main/java/org/teavm/tooling/c/incremental/IncrementalCBuilder.java b/tools/c-incremental/src/main/java/org/teavm/tooling/c/incremental/IncrementalCBuilder.java index 0b4a21c2f..e740cf956 100644 --- a/tools/c-incremental/src/main/java/org/teavm/tooling/c/incremental/IncrementalCBuilder.java +++ b/tools/c-incremental/src/main/java/org/teavm/tooling/c/incremental/IncrementalCBuilder.java @@ -308,6 +308,7 @@ public class IncrementalCBuilder { long startTime = System.currentTimeMillis(); CTarget cTarget = new CTarget(); + cTarget.setAstCache(astCache); TeaVM vm = new TeaVMBuilder(cTarget) .setReferenceCache(referenceCache)