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 69d18a0de..712f413f2 100644 --- a/core/src/main/java/org/teavm/backend/c/CTarget.java +++ b/core/src/main/java/org/teavm/backend/c/CTarget.java @@ -33,15 +33,12 @@ import java.util.Set; import org.teavm.ast.decompilation.Decompiler; import org.teavm.backend.c.analyze.CDependencyListener; import org.teavm.backend.c.analyze.Characteristics; -import org.teavm.backend.c.analyze.StringPoolFiller; -import org.teavm.backend.c.analyze.TypeCollector; -import org.teavm.backend.c.generate.CallSiteGenerator; +import org.teavm.backend.c.generate.BufferedCodeWriter; import org.teavm.backend.c.generate.ClassGenerator; import org.teavm.backend.c.generate.CodeWriter; import org.teavm.backend.c.generate.GenerationContext; import org.teavm.backend.c.generate.NameProvider; 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; import org.teavm.backend.c.intrinsic.AddressIntrinsic; @@ -214,26 +211,20 @@ public class CTarget implements TeaVMTarget { GenerationContext context = new GenerationContext(vtableProvider, characteristics, stringPool, nameProvider, controller.getDiagnostics(), classes, intrinsics, generators); + BufferedCodeWriter codeWriter = new BufferedCodeWriter(); + copyResource(codeWriter, "runtime.c"); + + ClassGenerator classGenerator = new ClassGenerator(context, controller.getUnprocessedClassSource(), + tagRegistry, decompiler, codeWriter); + + generateClasses(classes, classGenerator); + generateSpecialFunctions(context, codeWriter); + copyResource(codeWriter, "runtime-epilogue.c"); + generateMain(context, codeWriter, classes, classGenerator.getTypes()); + try (PrintWriter writer = new PrintWriter(new OutputStreamWriter( buildTarget.createResource(outputName), "UTF-8"))) { - CodeWriter codeWriter = new CodeWriter(writer); - ClassGenerator classGenerator = new ClassGenerator(context, tagRegistry, decompiler, codeWriter); - - copyResource(codeWriter, "runtime.c"); - TypeCollector typeCollector = new TypeCollector(); - typeCollector.collect(classes); - typeCollector.collectFromCallSites(shadowStackTransformer.getCallSites()); - StringPoolFiller stringPoolFiller = new StringPoolFiller(stringPool); - stringPoolFiller.fillFrom(classes); - stringPoolFiller.fillCallSites(shadowStackTransformer.getCallSites()); - for (ValueType type : typeCollector.getTypes()) { - stringPool.getStringIndex(ClassGenerator.nameOfType(type)); - } - - generateClasses(classes, classGenerator, context, codeWriter, typeCollector); - generateSpecialFunctions(context, codeWriter); - copyResource(codeWriter, "runtime-epilogue.c"); - generateMain(context, codeWriter, classes, typeCollector); + codeWriter.writeTo(writer); } } @@ -253,47 +244,15 @@ public class CTarget implements TeaVMTarget { } } - private void generateClasses(ListableClassHolderSource classes, ClassGenerator classGenerator, - GenerationContext context, CodeWriter writer, TypeCollector typeCollector) { + private void generateClasses(ListableClassHolderSource classes, ClassGenerator classGenerator) { List classNames = sortClassNames(classes); for (String className : classNames) { - ClassHolder cls = classes.get(className); - classGenerator.generateForwardDeclarations(cls); - } - - for (String className : classNames) { - ClassHolder cls = classes.get(className); - classGenerator.generateStructures(cls); - } - - for (String className : classNames) { - classGenerator.generateVirtualTableStructures(classes.get(className)); - } - - new StringPoolGenerator(writer, context.getNames()).generate(context.getStringPool().getStrings()); - - classGenerator.generateLayoutArray(classNames); - - for (ValueType type : typeCollector.getTypes()) { - classGenerator.generateVirtualTableForwardDeclaration(type); - } - for (ValueType type : typeCollector.getTypes()) { - classGenerator.generateVirtualTable(type, typeCollector.getTypes()); - } - - for (ValueType type : typeCollector.getTypes()) { - classGenerator.generateIsSupertypeFunction(type); - } - - classGenerator.generateStaticGCRoots(classNames); - - new CallSiteGenerator(context, writer).generate(shadowStackTransformer.getCallSites()); - - for (String className : classes.getClassNames()) { ClassHolder cls = classes.get(className); classGenerator.generateClass(cls); } + + classGenerator.generateRemainingData(classNames, shadowStackTransformer); } private List sortClassNames(ListableClassReaderSource classes) { @@ -372,7 +331,7 @@ public class CTarget implements TeaVMTarget { } private void generateMain(GenerationContext context, CodeWriter writer, ListableClassHolderSource classes, - TypeCollector types) { + Set types) { writer.println("int main(int argc, char** argv) {").indent(); writer.println("initHeap(" + minHeapSize + ");"); @@ -405,11 +364,11 @@ public class CTarget implements TeaVMTarget { } private void generateVirtualTableHeaders(GenerationContext context, CodeWriter writer, - TypeCollector typeCollector) { + Set types) { String classClassName = context.getNames().forClassInstance(ValueType.object("java.lang.Class")); writer.println("int32_t classHeader = PACK_CLASS(&" + classClassName + ") | " + RuntimeObject.GC_MARKED + ";"); - for (ValueType type : typeCollector.getTypes()) { + for (ValueType type : types) { if (!ClassGenerator.needsVirtualTable(context.getCharacteristics(), type)) { continue; } diff --git a/core/src/main/java/org/teavm/backend/c/Example.java b/core/src/main/java/org/teavm/backend/c/Example.java deleted file mode 100644 index c0b246f3e..000000000 --- a/core/src/main/java/org/teavm/backend/c/Example.java +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright 2018 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.backend.c; - -import java.math.BigInteger; - -public final class Example { - private Example() { - } - - public static void main(String[] args) { - System.out.println("Running BigInteger benchmark"); - BigInteger result = BigInteger.ONE; - for (int j = 0; j < 100; ++j) { - long start = System.currentTimeMillis(); - - for (int k = 0; k < 5000; ++k) { - BigInteger a = BigInteger.ZERO; - BigInteger b = BigInteger.ONE; - for (int i = 0; i < 1000; ++i) { - BigInteger c = a.add(b); - a = b; - b = c; - } - result = a; - } - - long end = System.currentTimeMillis(); - - System.out.println("Operation took " + (end - start) + " milliseconds"); - } - System.out.println(result.toString()); - } -} diff --git a/core/src/main/java/org/teavm/backend/c/analyze/StringPoolFiller.java b/core/src/main/java/org/teavm/backend/c/analyze/StringPoolFiller.java deleted file mode 100644 index f4bd91030..000000000 --- a/core/src/main/java/org/teavm/backend/c/analyze/StringPoolFiller.java +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Copyright 2018 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.backend.c.analyze; - -import java.util.List; -import org.teavm.backend.c.generate.StringPool; -import org.teavm.model.BasicBlockReader; -import org.teavm.model.ClassReader; -import org.teavm.model.ListableClassReaderSource; -import org.teavm.model.MethodReader; -import org.teavm.model.ProgramReader; -import org.teavm.model.VariableReader; -import org.teavm.model.instructions.AbstractInstructionReader; -import org.teavm.model.lowlevel.CallSiteDescriptor; - -public class StringPoolFiller extends AbstractInstructionReader { - private StringPool pool; - - public StringPoolFiller(StringPool pool) { - this.pool = pool; - } - - public void fillFrom(ListableClassReaderSource classSource) { - for (String className : classSource.getClassNames()) { - addClass(classSource.get(className)); - } - } - - public void fillCallSites(List callSites) { - for (CallSiteDescriptor callSite : callSites) { - if (callSite.getLocation() != null) { - if (callSite.getLocation().getClassName() != null) { - pool.getStringIndex(callSite.getLocation().getClassName()); - } - if (callSite.getLocation().getFileName() != null) { - pool.getStringIndex(callSite.getLocation().getFileName()); - } - if (callSite.getLocation().getMethodName() != null) { - pool.getStringIndex(callSite.getLocation().getMethodName()); - } - } - } - } - - private void addClass(ClassReader cls) { - pool.getStringIndex(cls.getName()); - for (MethodReader method : cls.getMethods()) { - ProgramReader program = method.getProgram(); - if (program != null) { - for (BasicBlockReader block : program.getBasicBlocks()) { - block.readAllInstructions(this); - } - } - } - } - - @Override - public void stringConstant(VariableReader receiver, String cst) { - pool.getStringIndex(cst); - } -} diff --git a/core/src/main/java/org/teavm/backend/c/analyze/TemporaryVariableEstimator.java b/core/src/main/java/org/teavm/backend/c/analyze/TemporaryVariableEstimator.java deleted file mode 100644 index c0194e3c0..000000000 --- a/core/src/main/java/org/teavm/backend/c/analyze/TemporaryVariableEstimator.java +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright 2018 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.backend.c.analyze; - -import org.teavm.ast.InvocationExpr; -import org.teavm.ast.InvocationType; -import org.teavm.ast.RecursiveVisitor; - -public class TemporaryVariableEstimator extends RecursiveVisitor { - private int currentReceiverIndex; - private int maxReceiverIndex; - - public int getMaxReceiverIndex() { - return maxReceiverIndex; - } - - @Override - public void visit(InvocationExpr expr) { - if (expr.getType() == InvocationType.DYNAMIC || expr.getType() == InvocationType.CONSTRUCTOR) { - currentReceiverIndex++; - maxReceiverIndex = Math.max(maxReceiverIndex, currentReceiverIndex); - } - - super.visit(expr); - - if (expr.getType() == InvocationType.DYNAMIC) { - currentReceiverIndex--; - } - } -} diff --git a/core/src/main/java/org/teavm/backend/c/analyze/TypeCollector.java b/core/src/main/java/org/teavm/backend/c/analyze/TypeCollector.java deleted file mode 100644 index 34d78b914..000000000 --- a/core/src/main/java/org/teavm/backend/c/analyze/TypeCollector.java +++ /dev/null @@ -1,118 +0,0 @@ -/* - * Copyright 2018 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.backend.c.analyze; - -import java.util.HashSet; -import java.util.List; -import java.util.Set; -import org.teavm.interop.DelegateTo; -import org.teavm.model.BasicBlockReader; -import org.teavm.model.ClassReader; -import org.teavm.model.ListableClassReaderSource; -import org.teavm.model.MethodReader; -import org.teavm.model.ProgramReader; -import org.teavm.model.ValueType; -import org.teavm.model.VariableReader; -import org.teavm.model.instructions.AbstractInstructionReader; -import org.teavm.model.lowlevel.CallSiteDescriptor; -import org.teavm.model.lowlevel.ExceptionHandlerDescriptor; - -public class TypeCollector extends AbstractInstructionReader { - private Set types = new HashSet<>(); - - public Set getTypes() { - return types; - } - - public void collect(ListableClassReaderSource classSource) { - for (String className : classSource.getClassNames()) { - ClassReader cls = classSource.get(className); - collect(cls); - } - } - - public void collectFromCallSites(List callSites) { - for (CallSiteDescriptor callSite : callSites) { - for (ExceptionHandlerDescriptor handler : callSite.getHandlers()) { - if (handler.getClassName() != null) { - types.add(ValueType.object(handler.getClassName())); - } - } - } - } - - private void collect(ClassReader cls) { - for (MethodReader method : cls.getMethods()) { - collect(method); - types.add(ValueType.object(cls.getName())); - } - } - - private void collect(MethodReader method) { - if (method.getAnnotations().get(DelegateTo.class.getName()) != null) { - return; - } - - if (method.getProgram() != null) { - collect(method.getProgram()); - } - } - - private void collect(ProgramReader program) { - for (BasicBlockReader block : program.getBasicBlocks()) { - block.readAllInstructions(this); - } - } - - @Override - public void createArray(VariableReader receiver, ValueType itemType, List dimensions) { - ValueType type = itemType; - for (int i = 1; i <= dimensions.size(); ++i) { - type = ValueType.arrayOf(type); - } - addType(type); - } - - @Override - public void createArray(VariableReader receiver, ValueType itemType, VariableReader size) { - addType(ValueType.arrayOf(itemType)); - } - - @Override - public void classConstant(VariableReader receiver, ValueType cst) { - addType(cst); - } - - @Override - public void isInstance(VariableReader receiver, VariableReader value, ValueType type) { - addType(type); - } - - @Override - public void cast(VariableReader receiver, VariableReader value, ValueType targetType) { - addType(targetType); - } - - private void addType(ValueType type) { - types.add(type); - while (type instanceof ValueType.Array) { - type = ((ValueType.Array) type).getItemType(); - if (!types.add(type)) { - break; - } - } - } -} diff --git a/core/src/main/java/org/teavm/backend/c/generate/BufferedCodeWriter.java b/core/src/main/java/org/teavm/backend/c/generate/BufferedCodeWriter.java new file mode 100644 index 000000000..c4841a54a --- /dev/null +++ b/core/src/main/java/org/teavm/backend/c/generate/BufferedCodeWriter.java @@ -0,0 +1,140 @@ +/* + * Copyright 2018 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.backend.c.generate; + +import java.io.PrintWriter; +import java.util.ArrayList; +import java.util.List; + +public class BufferedCodeWriter extends CodeWriter { + private List fragments = new ArrayList<>(); + private int currentIndent; + private int lastIndent; + private StringBuilder buffer = new StringBuilder(); + + public BufferedCodeWriter() { + } + + public void writeTo(PrintWriter writer) { + WriterWithContext writerWithContext = new WriterWithContext(writer); + for (Fragment fragment : fragments) { + fragment.writeTo(writerWithContext); + } + } + + @Override + public CodeWriter fragment() { + flush(); + BufferedCodeWriter innerWriter = new BufferedCodeWriter(); + fragments.add(new InnerWriterFragment(innerWriter.fragments)); + return innerWriter; + } + + @Override + protected void newLine() { + fragments.add(new SimpleFragment(true, lastIndent, buffer.toString())); + buffer.setLength(0); + lastIndent = currentIndent; + currentIndent = 0; + } + + @Override + protected void append(String text) { + buffer.append(text); + } + + @Override + protected void indentBy(int amount) { + if (buffer.length() == 0) { + lastIndent += amount; + } else { + currentIndent += amount; + } + } + + @Override + public void flush() { + fragments.add(new SimpleFragment(false, lastIndent, buffer.toString())); + lastIndent = currentIndent; + currentIndent = 0; + buffer.setLength(0); + } + + static class WriterWithContext { + PrintWriter writer; + boolean isNewLine = true; + int indentLevel; + + WriterWithContext(PrintWriter writer) { + this.writer = writer; + } + + void append(String text) { + if (isNewLine) { + for (int i = 0; i < indentLevel; ++i) { + writer.print(" "); + } + isNewLine = false; + } + writer.print(text); + } + + void newLine() { + writer.println(); + isNewLine = true; + } + } + + static abstract class Fragment { + abstract void writeTo(WriterWithContext writer); + } + + static class SimpleFragment extends Fragment { + boolean newLine; + int indentLevel; + String text; + + SimpleFragment(boolean newLine, int indentLevel, String text) { + this.newLine = newLine; + this.indentLevel = indentLevel; + this.text = text; + } + + @Override + void writeTo(WriterWithContext writer) { + writer.indentLevel += indentLevel; + writer.append(text); + if (newLine) { + writer.newLine(); + } + } + } + + static class InnerWriterFragment extends Fragment { + List fragments; + + InnerWriterFragment(List fragments) { + this.fragments = fragments; + } + + @Override + void writeTo(WriterWithContext writer) { + for (Fragment fragment : fragments) { + fragment.writeTo(writer); + } + } + } +} 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 d8c5e0dd2..80eaf1b37 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 @@ -19,7 +19,7 @@ import com.carrotsearch.hppc.ObjectIntHashMap; import com.carrotsearch.hppc.ObjectIntMap; import java.util.ArrayList; import java.util.Arrays; -import java.util.Collection; +import java.util.LinkedHashSet; import java.util.List; import java.util.Set; import org.teavm.ast.RegularMethodNode; @@ -37,7 +37,6 @@ import org.teavm.model.ClassReader; import org.teavm.model.ClassReaderSource; import org.teavm.model.ElementModifier; import org.teavm.model.FieldHolder; -import org.teavm.model.FieldReader; import org.teavm.model.FieldReference; import org.teavm.model.MethodDescriptor; import org.teavm.model.MethodHolder; @@ -46,268 +45,228 @@ import org.teavm.model.ValueType; import org.teavm.model.classes.TagRegistry; import org.teavm.model.classes.VirtualTable; import org.teavm.model.classes.VirtualTableEntry; +import org.teavm.model.lowlevel.ShadowStackTransformer; import org.teavm.runtime.RuntimeClass; import org.teavm.runtime.RuntimeObject; public class ClassGenerator { private GenerationContext context; + private ClassReaderSource unprocessedClassSource; private Decompiler decompiler; private TagRegistry tagRegistry; - private CodeWriter writer; private CodeGenerator codeGenerator; private ObjectIntMap classLayoutOffsets = new ObjectIntHashMap<>(); + private List staticGcRoots = new ArrayList<>(); + private List layouts = new ArrayList<>(); + private int currentLayoutIndex; + private Set types = new LinkedHashSet<>(); + private CodeWriter forwardDeclarationsWriter; + private CodeWriter structuresWriter; + private CodeWriter vtableStructuresWriter; + private CodeWriter stringPoolWriter; + private CodeWriter layoutWriter; + private CodeWriter vtableForwardWriter; + private CodeWriter vtableWriter; + private CodeWriter isSupertypeWriter; + private CodeWriter staticGcRootsWriter; + private CodeWriter callSiteWriter; + private CodeWriter codeWriter; - public ClassGenerator(GenerationContext context, TagRegistry tagRegistry, Decompiler decompiler, - CodeWriter writer) { + public ClassGenerator(GenerationContext context, ClassReaderSource unprocessedClassSource, + TagRegistry tagRegistry, Decompiler decompiler, CodeWriter writer) { this.context = context; + this.unprocessedClassSource = unprocessedClassSource; this.tagRegistry = tagRegistry; this.decompiler = decompiler; - this.writer = writer; - codeGenerator = new CodeGenerator(context, writer); + + forwardDeclarationsWriter = writer.fragment(); + structuresWriter = writer.fragment(); + vtableStructuresWriter = writer.fragment(); + stringPoolWriter = writer.fragment(); + layoutWriter = writer.fragment(); + vtableForwardWriter = writer.fragment(); + vtableWriter = writer.fragment(); + isSupertypeWriter = writer.fragment(); + staticGcRootsWriter = writer.fragment(); + callSiteWriter = writer.fragment(); + codeWriter = writer.fragment(); + + codeGenerator = new CodeGenerator(context, codeWriter); } - public void generateForwardDeclarations(ClassHolder cls) { - generateForwardClassStructure(cls); + public void generateClass(ClassHolder cls) { + generateClassStructure(cls); + generateClassMethods(cls); + generateInitializer(cls); + } + public void generateRemainingData(List classNames, ShadowStackTransformer shadowStackTransformer) { + generateCallSites(shadowStackTransformer); + + collectTypes(classNames); + for (ValueType type : types) { + generateVirtualTable(type); + } + generateStaticGCRoots(); + generateLayoutArray(); + + new StringPoolGenerator(stringPoolWriter, context.getNames()).generate(context.getStringPool().getStrings()); + } + + public Set getTypes() { + return types; + } + + private void collectTypes(List classNames) { + for (String className : classNames) { + types.add(ValueType.object(className)); + } + + types.add(ValueType.object("java.lang.Class")); + for (ValueType type : context.getNames().getTypes()) { + if (type instanceof ValueType.Array) { + types.add(ValueType.object("java.lang.Object")); + } + while (true) { + if (!types.add(type)) { + break; + } + if (!(type instanceof ValueType.Array)) { + break; + } + type = ((ValueType.Array) type).getItemType(); + } + } + } + + private void generateCallSites(ShadowStackTransformer shadowStackTransformer) { + new CallSiteGenerator(context, callSiteWriter).generate(shadowStackTransformer.getCallSites()); + } + + private void generateClassMethods(ClassHolder cls) { for (MethodHolder method : cls.getMethods()) { if (method.hasModifier(ElementModifier.ABSTRACT)) { continue; } - if (method.hasModifier(ElementModifier.NATIVE) - && method.getAnnotations().get(DelegateTo.class.getName()) == null - && context.getGenerator(method.getReference()) == null) { + + if (method.hasModifier(ElementModifier.NATIVE)) { + if (!tryDelegateToMethod(cls, method)) { + tryUsingGenerator(method); + } continue; } - codeGenerator.generateMethodSignature(method.getReference(), method.hasModifier(ElementModifier.STATIC), - false); - writer.println(";"); - } - - if (needsInitializer(cls)) { - writer.print("static void ").print(context.getNames().forClassInitializer(cls.getName())).println("();"); + generateMethodForwardDeclaration(method); + RegularMethodNode methodNode = decompiler.decompileRegular(method); + codeGenerator.generateMethod(methodNode); } } - private void generateForwardClassStructure(ClassHolder cls) { - if (!needsData(cls) || isSystemClass(cls)) { + private void generateMethodForwardDeclaration(MethodHolder method) { + codeGenerator.generateMethodSignature(forwardDeclarationsWriter, method.getReference(), + method.hasModifier(ElementModifier.STATIC), false); + forwardDeclarationsWriter.println(";"); + + } + + private void generateInitializer(ClassHolder cls) { + if (!needsInitializer(cls)) { return; } - writer.print("struct ").print(context.getNames().forClass(cls.getName())).println(";"); - } + forwardDeclarationsWriter.print("static void ") + .print(context.getNames().forClassInitializer(cls.getName())).println("();"); - public void generateStructures(ClassHolder cls) { - generateClassStructure(cls); - generateStaticFields(cls); - } + codeWriter.print("static void ").print(context.getNames().forClassInitializer(cls.getName())) + .println("() {").indent(); - public void generateVirtualTableStructures(ClassHolder cls) { - generateVirtualTableStructure(cls); + String classInstanceName = context.getNames().forClassInstance(ValueType.object(cls.getName())); + String clinitName = context.getNames().forMethod( + new MethodReference(cls.getName(), "", ValueType.VOID)); + codeWriter.print("JavaClass* cls = (JavaClass*) &").print(classInstanceName).println(";"); + codeWriter.println("if (!(cls->flags & INT32_C(" + RuntimeClass.INITIALIZED + "))) {").indent(); + codeWriter.println("cls->flags |= INT32_C(" + RuntimeClass.INITIALIZED + ");"); + codeWriter.print(clinitName).println("();"); + codeWriter.outdent().println("}"); + + codeWriter.outdent().println("}"); } private void generateClassStructure(ClassHolder cls) { if (!needsData(cls)) { return; } + generateForwardClassStructure(cls); String name = context.getNames().forClass(cls.getName()); - writer.print("typedef struct ").print(name).println(" {").indent(); + CodeWriter structWriter = structuresWriter.fragment(); + CodeWriter fieldsWriter = structuresWriter.fragment(); + + structWriter.print("typedef struct ").print(name).println(" {").indent(); if (cls.getParent() == null || !cls.getParent().equals(Structure.class.getName())) { String parentName = cls.getParent(); if (parentName == null) { parentName = RuntimeObject.class.getName(); } - writer.print("struct ").print(context.getNames().forClass(parentName)).println(" parent;"); + structWriter.print("struct ").print(context.getNames().forClass(parentName)).println(" parent;"); } + int layoutIndex = currentLayoutIndex; + + FieldReference[] staticFields = new FieldReference[cls.getFields().size()]; + int staticIndex = 0; + FieldReference[] instanceFields = new FieldReference[cls.getFields().size()]; + int instanceIndex = 0; for (FieldHolder field : cls.getFields()) { if (field.hasModifier(ElementModifier.STATIC)) { - continue; + String fieldName = context.getNames().forStaticField(field.getReference()); + fieldsWriter.print("static ").printStrictType(field.getType()).print(" ").print(fieldName) + .println(";"); + if (isReferenceType(field.getType())) { + staticFields[staticIndex++] = field.getReference(); + } + } else { + String fieldName = context.getNames().forMemberField(field.getReference()); + structWriter.printStrictType(field.getType()).print(" ").print(fieldName).println(";"); + if (isReferenceType(field.getType())) { + instanceFields[instanceIndex++] = field.getReference(); + } } - String fieldName = context.getNames().forMemberField(field.getReference()); - writer.printStrictType(field.getType()).print(" ").print(fieldName).println(";"); } - writer.outdent().print("} ").print(name).println(";"); + if (staticIndex > 0) { + staticGcRoots.add(Arrays.copyOf(staticFields, staticIndex)); + } + if (instanceIndex > 0) { + classLayoutOffsets.put(cls.getName(), layoutIndex); + layouts.add(Arrays.copyOf(instanceFields, instanceIndex)); + currentLayoutIndex += instanceIndex + 1; + } + + structWriter.outdent().print("} ").print(name).println(";"); } - private void generateStaticFields(ClassHolder cls) { - if (!needsData(cls)) { + private void generateForwardClassStructure(ClassHolder cls) { + if (isSystemClass(cls)) { return; } - for (FieldHolder field : cls.getFields()) { - if (!field.hasModifier(ElementModifier.STATIC)) { - continue; - } - String fieldName = context.getNames().forStaticField(field.getReference()); - writer.print("static ").printStrictType(field.getType()).print(" ").print(fieldName).println(";"); - } + forwardDeclarationsWriter.print("struct ").print(context.getNames().forClass(cls.getName())).println(";"); } - public void generateStaticGCRoots(Collection classNames) { - List data = new ArrayList<>(); - int total = 0; - - for (String className : classNames) { - ClassReader cls = context.getClassSource().get(className); - if (!needsData(cls)) { - continue; - } - - FieldReference[] fields = new FieldReference[cls.getFields().size()]; - int index = 0; - - for (FieldReader field : cls.getFields()) { - if (!field.hasModifier(ElementModifier.STATIC) || !isReferenceType(field.getType())) { - continue; - } - - fields[index++] = field.getReference(); - } - - if (index == 0) { - continue; - } - - fields = Arrays.copyOf(fields, index); - total += fields.length; - data.add(fields); - } - - writer.println("static void** gc_staticRoots[" + (total + 1) + "] = {").indent(); - writer.print("(void**) (intptr_t) " + total); - - for (FieldReference[] fields : data) { - writer.print(",").println(); - - boolean first = true; - for (FieldReference field : fields) { - if (!first) { - writer.print(", "); - } - first = false; - String name = context.getNames().forStaticField(field); - writer.print("(void**) &").print(name); - } - } - - writer.println().outdent().println("};"); - } - - private boolean isReferenceType(ValueType type) { - if (type instanceof ValueType.Object) { - String className = ((ValueType.Object) type).getClassName(); - return !context.getCharacteristics().isStructure(className) - && !className.equals(Address.class.getName()); - } else { - return type instanceof ValueType.Array; - } - } - - public void generateVirtualTableForwardDeclaration(ValueType type) { + private void generateVirtualTable(ValueType type) { if (!needsVirtualTable(context.getCharacteristics(), type)) { return; } - String className; - if (type instanceof ValueType.Object) { - className = ((ValueType.Object) type).getClassName(); - } else if (type instanceof ValueType.Array) { - className = "java.lang.Object"; - } else { - className = null; - } - String structName = className != null ? context.getNames().forClassClass(className) : "JavaClass"; - String name = context.getNames().forClassInstance(type); - - writer.print("static ").print(structName).print(" ").print(name).println(";"); - } - - private void generateVirtualTableStructure(ClassHolder cls) { - if (!needsVirtualTable(context.getCharacteristics(), ValueType.object(cls.getName()))) { - return; - } - - String name = context.getNames().forClassClass(cls.getName()); - - writer.print("typedef struct ").print(name).println(" {").indent(); - writer.println("JavaClass parent;"); - - VirtualTable virtualTable = context.getVirtualTableProvider().lookup(cls.getName()); - CodeGenerator codeGenerator = new CodeGenerator(context, writer); - for (VirtualTableEntry entry : virtualTable.getEntries().values()) { - String methodName = context.getNames().forVirtualMethod( - new MethodReference(cls.getName(), entry.getMethod())); - writer.printType(entry.getMethod().getResultType()) - .print(" (*").print(methodName).print(")("); - codeGenerator.generateMethodParameters(entry.getMethod(), false, false); - writer.println(");"); - } - - writer.outdent().print("} ").print(name).println(";"); - } - - public void generateLayoutArray(List classNames) { - List data = new ArrayList<>(); - int totalSize = 0; - - for (String className : classNames) { - ClassReader cls = context.getClassSource().get(className); - if (!needsData(cls) || !needsVirtualTable(context.getCharacteristics(), ValueType.object(className))) { - continue; - } - - FieldReference[] fields = new FieldReference[cls.getFields().size()]; - int index = 0; - for (FieldReader field : cls.getFields()) { - if (field.hasModifier(ElementModifier.STATIC) || !isReferenceType(field.getType())) { - continue; - } - fields[index++] = field.getReference(); - } - - if (index == 0) { - continue; - } - - fields = Arrays.copyOf(fields, index); - - classLayoutOffsets.put(className, totalSize); - totalSize += fields.length + 1; - data.add(fields); - } - - writer.print("static int16_t classLayouts[" + totalSize + "] = {").indent(); - for (int i = 0; i < data.size(); ++i) { - if (i > 0) { - writer.print(","); - } - FieldReference[] fields = data.get(i); - writer.println().print("INT16_C(" + fields.length + ")"); - - for (FieldReference field : fields) { - String className = context.getNames().forClass(field.getClassName()); - String fieldName = context.getNames().forMemberField(field); - writer.print(", (int16_t) offsetof(" + className + ", " + fieldName + ")"); - } - } - writer.println().outdent().println("};"); - } - - public void generateVirtualTable(ValueType type, Set allTypes) { - if (!needsVirtualTable(context.getCharacteristics(), type)) { - return; - } - - generateIsSupertypeForwardDeclaration(type); + generateIsSupertypeFunction(type); String className = null; if (type instanceof ValueType.Object) { className = ((ValueType.Object) type).getClassName(); + generateVirtualTableStructure(unprocessedClassSource.get(className)); } else if (type instanceof ValueType.Array) { className = "java.lang.Object"; } @@ -316,12 +275,13 @@ public class ClassGenerator { : "JavaClass"; String name = context.getNames().forClassInstance(type); - writer.print("static ").print(structName).print(" ").print(name).println(" = {").indent(); + vtableForwardWriter.print("static ").print(structName).print(" ").print(name).println(";"); + vtableWriter.print("static ").print(structName).print(" ").print(name).println(" = {").indent(); if (className != null) { - writer.println(".parent = {").indent(); - generateRuntimeClassInitializer(type, allTypes); - writer.outdent().println("},"); + vtableWriter.println(".parent = {").indent(); + generateRuntimeClassInitializer(type); + vtableWriter.outdent().println("},"); VirtualTable virtualTable = context.getVirtualTableProvider().lookup(className); if (virtualTable != null) { @@ -333,21 +293,21 @@ public class ClassGenerator { String implName = entry.getImplementor() != null ? "&" + context.getNames().forMethod(entry.getImplementor()) : "NULL"; - writer.print(".").print(methodName).print(" = ").print(implName); + vtableWriter.print(".").print(methodName).print(" = ").print(implName); if (i < entries.size() - 1) { - writer.print(","); + vtableWriter.print(","); } - writer.println(); + vtableWriter.println(); } } } else { - generateRuntimeClassInitializer(type, allTypes); + generateRuntimeClassInitializer(type); } - writer.outdent().println("};"); + vtableWriter.outdent().println("};"); } - private void generateRuntimeClassInitializer(ValueType type, Set allTypes) { + private void generateRuntimeClassInitializer(ValueType type) { String sizeExpr; int tag; String parent; @@ -371,7 +331,7 @@ public class ClassGenerator { } tag = tagRegistry.getRanges(className).get(0).lower; - parent = cls != null && cls.getParent() != null && allTypes.contains(ValueType.object(cls.getParent())) + parent = cls != null && cls.getParent() != null && types.contains(ValueType.object(cls.getParent())) ? "&" + context.getNames().forClassInstance(ValueType.object(cls.getParent())) : "NULL"; itemTypeExpr = "NULL"; @@ -406,24 +366,96 @@ public class ClassGenerator { ValueType arrayType = ValueType.arrayOf(type); String arrayTypeExpr; - if (allTypes.contains(arrayType)) { + if (types.contains(arrayType)) { arrayTypeExpr = "&" + context.getNames().forClassInstance(arrayType); } else { arrayTypeExpr = "NULL"; } - writer.println(".parent = {},"); - writer.print(".").print(classFieldName("size")).print(" = ").print(sizeExpr).println(","); - writer.print(".").print(classFieldName("flags")).println(" = " + flags + ","); - writer.print(".").print(classFieldName("tag")).print(" = ").print(String.valueOf(tag)).println(","); - writer.print(".").print(classFieldName("canary")).println(" = 0,"); - writer.print(".").print(classFieldName("name")).println(" = stringPool + " + nameRef + ","); - writer.print(".").print(classFieldName("arrayType")).println(" = " + arrayTypeExpr + ","); - writer.print(".").print(classFieldName("itemType")).println(" = " + itemTypeExpr + ","); - writer.print(".").print(classFieldName("isSupertypeOf")).println(" = &" + superTypeFunction + ","); - writer.print(".").print(classFieldName("parent")).println(" = " + parent + ","); - writer.print(".").print(classFieldName("enumValues")).println(" = NULL,"); - writer.print(".").print(classFieldName("layout")).println(" = " + layout); + vtableWriter.println(".parent = {},"); + vtableWriter.print(".").print(classFieldName("size")).print(" = ").print(sizeExpr).println(","); + vtableWriter.print(".").print(classFieldName("flags")).println(" = " + flags + ","); + vtableWriter.print(".").print(classFieldName("tag")).print(" = ").print(String.valueOf(tag)).println(","); + vtableWriter.print(".").print(classFieldName("canary")).println(" = 0,"); + vtableWriter.print(".").print(classFieldName("name")).println(" = stringPool + " + nameRef + ","); + vtableWriter.print(".").print(classFieldName("arrayType")).println(" = " + arrayTypeExpr + ","); + vtableWriter.print(".").print(classFieldName("itemType")).println(" = " + itemTypeExpr + ","); + vtableWriter.print(".").print(classFieldName("isSupertypeOf")).println(" = &" + superTypeFunction + ","); + vtableWriter.print(".").print(classFieldName("parent")).println(" = " + parent + ","); + vtableWriter.print(".").print(classFieldName("enumValues")).println(" = NULL,"); + vtableWriter.print(".").print(classFieldName("layout")).println(" = " + layout); + } + + private void generateVirtualTableStructure(ClassReader cls) { + String name = context.getNames().forClassClass(cls.getName()); + + vtableStructuresWriter.print("typedef struct ").print(name).println(" {").indent(); + vtableStructuresWriter.println("JavaClass parent;"); + + VirtualTable virtualTable = context.getVirtualTableProvider().lookup(cls.getName()); + for (VirtualTableEntry entry : virtualTable.getEntries().values()) { + String methodName = context.getNames().forVirtualMethod( + new MethodReference(cls.getName(), entry.getMethod())); + vtableStructuresWriter.printType(entry.getMethod().getResultType()) + .print(" (*").print(methodName).print(")("); + codeGenerator.generateMethodParameters(vtableStructuresWriter, entry.getMethod(), false, false); + vtableStructuresWriter.println(");"); + } + + vtableStructuresWriter.outdent().print("} ").print(name).println(";"); + } + + private boolean isReferenceType(ValueType type) { + if (type instanceof ValueType.Object) { + String className = ((ValueType.Object) type).getClassName(); + return !context.getCharacteristics().isStructure(className) + && !className.equals(Address.class.getName()); + } else { + return type instanceof ValueType.Array; + } + } + + private void generateStaticGCRoots() { + int total = staticGcRoots.stream().mapToInt(c -> c.length).sum(); + + staticGcRootsWriter.println("static void** gc_staticRoots[" + (total + 1) + "] = {").indent(); + staticGcRootsWriter.print("(void**) (intptr_t) " + total); + + for (FieldReference[] fields : staticGcRoots) { + staticGcRootsWriter.print(",").println(); + + boolean first = true; + for (FieldReference field : fields) { + if (!first) { + staticGcRootsWriter.print(", "); + } + first = false; + String name = context.getNames().forStaticField(field); + staticGcRootsWriter.print("(void**) &").print(name); + } + } + + staticGcRootsWriter.println().outdent().println("};"); + } + + private void generateLayoutArray() { + int totalSize = layouts.stream().mapToInt(c -> c.length + 1).sum(); + + layoutWriter.print("static int16_t classLayouts[" + totalSize + "] = {").indent(); + for (int i = 0; i < layouts.size(); ++i) { + if (i > 0) { + layoutWriter.print(","); + } + FieldReference[] fields = layouts.get(i); + layoutWriter.println().print("INT16_C(" + fields.length + ")"); + + for (FieldReference field : fields) { + String className = context.getNames().forClass(field.getClassName()); + String fieldName = context.getNames().forMemberField(field); + layoutWriter.print(", (int16_t) offsetof(" + className + ", " + fieldName + ")"); + } + } + layoutWriter.println().outdent().println("};"); } private int getPrimitiveFlag(ValueType.Primitive type) { @@ -486,40 +518,6 @@ public class ClassGenerator { } } - public void generateClass(ClassHolder cls) { - for (MethodHolder method : cls.getMethods()) { - if (method.hasModifier(ElementModifier.NATIVE)) { - if (!tryDelegateToMethod(cls, method)) { - tryUsingGenerator(method); - } - continue; - } - - if (method.hasModifier(ElementModifier.ABSTRACT)) { - continue; - } - - RegularMethodNode methodNode = decompiler.decompileRegular(method); - codeGenerator.generateMethod(methodNode); - } - - if (needsInitializer(cls)) { - writer.print("static void ").print(context.getNames().forClassInitializer(cls.getName())) - .println("() {").indent(); - - String classInstanceName = context.getNames().forClassInstance(ValueType.object(cls.getName())); - String clinitName = context.getNames().forMethod( - new MethodReference(cls.getName(), "", ValueType.VOID)); - writer.print("JavaClass* cls = (JavaClass*) &").print(classInstanceName).println(";"); - writer.println("if (!(cls->flags & INT32_C(" + RuntimeClass.INITIALIZED + "))) {").indent(); - writer.println("cls->flags |= INT32_C(" + RuntimeClass.INITIALIZED + ");"); - writer.print(clinitName).println("();"); - writer.outdent().println("}"); - - writer.outdent().println("}"); - } - } - private boolean needsInitializer(ClassHolder cls) { return !context.getCharacteristics().isStaticInit(cls.getName()) && !context.getCharacteristics().isStructure(cls.getName()) @@ -535,6 +533,7 @@ public class ClassGenerator { String methodName = delegateToAnnot.getValue("value").getString(); for (MethodHolder candidate : cls.getMethods()) { if (candidate.getName().equals(methodName)) { + generateMethodForwardDeclaration(method); delegateToMethod(method, candidate); return true; } @@ -544,34 +543,34 @@ public class ClassGenerator { } private void delegateToMethod(MethodHolder callingMethod, MethodHolder delegateMethod) { - codeGenerator.generateMethodSignature(callingMethod.getReference(), + codeGenerator.generateMethodSignature(codeWriter, callingMethod.getReference(), callingMethod.hasModifier(ElementModifier.STATIC), true); - writer.println(" {").indent(); + codeWriter.println(" {").indent(); if (callingMethod.getResultType() != ValueType.VOID) { - writer.print("return "); + codeWriter.print("return "); } - writer.print(context.getNames().forMethod(delegateMethod.getReference())).print("("); + codeWriter.print(context.getNames().forMethod(delegateMethod.getReference())).print("("); boolean isStatic = callingMethod.hasModifier(ElementModifier.STATIC); int start = 0; if (!isStatic) { - writer.print("_this_"); + codeWriter.print("_this_"); } else { if (callingMethod.parameterCount() > 0) { - writer.print("local_1"); + codeWriter.print("local_1"); } start++; } for (int i = start; i < callingMethod.parameterCount(); ++i) { - writer.print(", ").print("local_").print(String.valueOf(i + 1)); + codeWriter.print(", ").print("local_").print(String.valueOf(i + 1)); } - writer.println(");"); + codeWriter.println(");"); - writer.outdent().println("}"); + codeWriter.outdent().println("}"); } private void tryUsingGenerator(MethodHolder method) { @@ -581,9 +580,10 @@ public class ClassGenerator { return; } + generateMethodForwardDeclaration(method); boolean isStatic = method.hasModifier(ElementModifier.STATIC); - codeGenerator.generateMethodSignature(methodRef, isStatic, true); - writer.println(" {").indent(); + codeGenerator.generateMethodSignature(codeWriter, methodRef, isStatic, true); + codeWriter.println(" {").indent(); generator.generate(new GeneratorContext() { @Override @@ -605,9 +605,9 @@ public class ClassGenerator { public String getParameterName(int index) { return index == 0 ? "_this_" : "local_" + index; } - }, writer, methodRef); + }, codeWriter, methodRef); - writer.outdent().println("}"); + codeWriter.outdent().println("}"); } public static String nameOfType(ValueType type) { @@ -643,14 +643,10 @@ public class ClassGenerator { } } - private void generateIsSupertypeForwardDeclaration(ValueType type) { + private void generateIsSupertypeFunction(ValueType type) { String name = context.getNames().forSupertypeFunction(type); - writer.println("static int32_t " + name + "(JavaClass*);"); - } - - public void generateIsSupertypeFunction(ValueType type) { - String name = context.getNames().forSupertypeFunction(type); - writer.println("static int32_t " + name + "(JavaClass* cls) {").indent(); + vtableForwardWriter.println("static int32_t " + name + "(JavaClass*);"); + isSupertypeWriter.println("static int32_t " + name + "(JavaClass* cls) {").indent(); if (type instanceof ValueType.Object) { generateIsSuperclassFunction(((ValueType.Object) type).getClassName()); @@ -662,43 +658,43 @@ public class ClassGenerator { generateIsSuperArrayFunction(((ValueType.Array) type).getItemType()); } - writer.outdent().println("}"); + isSupertypeWriter.outdent().println("}"); } private void generateIsSuperclassFunction(String className) { List ranges = tagRegistry.getRanges(className); if (ranges.isEmpty()) { - writer.println("return INT32_C(0);"); + isSupertypeWriter.println("return INT32_C(0);"); return; } String tagName = context.getNames().forMemberField(new FieldReference( RuntimeClass.class.getName(), "tag")); - writer.println("int32_t tag = cls->" + tagName + ";"); + isSupertypeWriter.println("int32_t tag = cls->" + tagName + ";"); int lower = ranges.get(0).lower; int upper = ranges.get(ranges.size() - 1).upper; - writer.println("if (tag < " + lower + " || tag > " + upper + ") return INT32_C(0);"); + isSupertypeWriter.println("if (tag < " + lower + " || tag > " + upper + ") return INT32_C(0);"); for (int i = 1; i < ranges.size(); ++i) { lower = ranges.get(i - 1).upper; upper = ranges.get(i).lower; - writer.println("if (tag < " + lower + " || tag > " + upper + ") return INT32_C(0);"); + isSupertypeWriter.println("if (tag < " + lower + " || tag > " + upper + ") return INT32_C(0);"); } - writer.println("return INT32_C(1);"); + isSupertypeWriter.println("return INT32_C(1);"); } private void generateIsSuperArrayFunction(ValueType itemType) { String itemTypeName = context.getNames().forMemberField(new FieldReference( RuntimeClass.class.getName(), "itemType")); - writer.println("JavaClass* itemType = cls->" + itemTypeName + ";"); - writer.println("if (itemType == NULL) return INT32_C(0);"); + isSupertypeWriter.println("JavaClass* itemType = cls->" + itemTypeName + ";"); + isSupertypeWriter.println("if (itemType == NULL) return INT32_C(0);"); if (itemType instanceof ValueType.Primitive) { - writer.println("return itemType == &" + context.getNames().forClassInstance(itemType) + ";"); + isSupertypeWriter.println("return itemType == &" + context.getNames().forClassInstance(itemType) + ";"); } else { - writer.println("return " + context.getNames().forSupertypeFunction(itemType) + "(itemType);"); + isSupertypeWriter.println("return " + context.getNames().forSupertypeFunction(itemType) + "(itemType);"); } } diff --git a/core/src/main/java/org/teavm/backend/c/generate/CodeGenerationVisitor.java b/core/src/main/java/org/teavm/backend/c/generate/CodeGenerationVisitor.java index 11f77a5f6..b985e2631 100644 --- a/core/src/main/java/org/teavm/backend/c/generate/CodeGenerationVisitor.java +++ b/core/src/main/java/org/teavm/backend/c/generate/CodeGenerationVisitor.java @@ -78,6 +78,7 @@ public class CodeGenerationVisitor implements ExprVisitor, StatementVisitor { private NameProvider names; private CodeWriter writer; private int temporaryReceiverLevel; + private int maxTemporaryReceiverLevel; private MethodReference callingMethod; public CodeGenerationVisitor(GenerationContext context, CodeWriter writer) { @@ -86,6 +87,10 @@ public class CodeGenerationVisitor implements ExprVisitor, StatementVisitor { this.names = context.getNames(); } + public int getTemporaryReceivers() { + return maxTemporaryReceiverLevel; + } + public void setCallingMethod(MethodReference callingMethod) { this.callingMethod = callingMethod; } @@ -334,6 +339,7 @@ public class CodeGenerationVisitor implements ExprVisitor, StatementVisitor { switch (expr.getType()) { case CONSTRUCTOR: { String receiver = "recv_" + temporaryReceiverLevel++; + maxTemporaryReceiverLevel = Math.max(maxTemporaryReceiverLevel, temporaryReceiverLevel); writer.print("(" + receiver + " = "); allocObject(expr.getMethod().getClassName()); writer.print(", "); @@ -371,6 +377,7 @@ public class CodeGenerationVisitor implements ExprVisitor, StatementVisitor { } case DYNAMIC: { String receiver = "recv_" + temporaryReceiverLevel++; + maxTemporaryReceiverLevel = Math.max(maxTemporaryReceiverLevel, temporaryReceiverLevel); writer.print("((").print(receiver).print(" = "); expr.getArguments().get(0).acceptVisitor(this); diff --git a/core/src/main/java/org/teavm/backend/c/generate/CodeGenerator.java b/core/src/main/java/org/teavm/backend/c/generate/CodeGenerator.java index e5cf2d994..7a9139345 100644 --- a/core/src/main/java/org/teavm/backend/c/generate/CodeGenerator.java +++ b/core/src/main/java/org/teavm/backend/c/generate/CodeGenerator.java @@ -17,7 +17,6 @@ package org.teavm.backend.c.generate; import org.teavm.ast.RegularMethodNode; import org.teavm.ast.VariableNode; -import org.teavm.backend.c.analyze.TemporaryVariableEstimator; import org.teavm.model.ElementModifier; import org.teavm.model.MethodDescriptor; import org.teavm.model.MethodReference; @@ -25,6 +24,7 @@ import org.teavm.model.MethodReference; public class CodeGenerator { private GenerationContext context; private CodeWriter writer; + private CodeWriter localsWriter; private NameProvider names; public CodeGenerator(GenerationContext context, CodeWriter writer) { @@ -34,30 +34,34 @@ public class CodeGenerator { } public void generateMethod(RegularMethodNode methodNode) { - generateMethodSignature(methodNode.getReference(), + generateMethodSignature(writer, methodNode.getReference(), methodNode.getModifiers().contains(ElementModifier.STATIC), true); writer.print(" {").indent().println(); - generateLocals(methodNode); + localsWriter = writer.fragment(); CodeGenerationVisitor visitor = new CodeGenerationVisitor(context, writer); visitor.setCallingMethod(methodNode.getReference()); methodNode.getBody().acceptVisitor(visitor); + generateLocals(methodNode, visitor.getTemporaryReceivers()); + writer.outdent().println("}"); } - public void generateMethodSignature(MethodReference methodRef, boolean isStatic, boolean withNames) { + public void generateMethodSignature(CodeWriter writer, MethodReference methodRef, boolean isStatic, + boolean withNames) { writer.print("static "); writer.printType(methodRef.getReturnType()).print(" ").print(names.forMethod(methodRef)).print("("); - generateMethodParameters(methodRef.getDescriptor(), isStatic, withNames); + generateMethodParameters(writer, methodRef.getDescriptor(), isStatic, withNames); writer.print(")"); } - public void generateMethodParameters(MethodDescriptor methodRef, boolean isStatic, boolean withNames) { + public void generateMethodParameters(CodeWriter writer, MethodDescriptor methodRef, boolean isStatic, + boolean withNames) { if (methodRef.parameterCount() == 0 && isStatic) { return; } @@ -84,17 +88,15 @@ public class CodeGenerator { } } - private void generateLocals(RegularMethodNode methodNode) { + private void generateLocals(RegularMethodNode methodNode, int receiverCount) { int start = methodNode.getReference().parameterCount() + 1; for (int i = start; i < methodNode.getVariables().size(); ++i) { VariableNode variableNode = methodNode.getVariables().get(i); - writer.printType(variableNode.getType()).print(" local_").print(String.valueOf(i)).println(";"); + localsWriter.printType(variableNode.getType()).print(" local_").print(String.valueOf(i)).println(";"); } - TemporaryVariableEstimator temporaryEstimator = new TemporaryVariableEstimator(); - methodNode.getBody().acceptVisitor(temporaryEstimator); - for (int i = 0; i < temporaryEstimator.getMaxReceiverIndex(); ++i) { - writer.print("void* recv_").print(String.valueOf(i)).println(";"); + for (int i = 0; i < receiverCount; ++i) { + localsWriter.print("void* recv_").print(String.valueOf(i)).println(";"); } } } diff --git a/core/src/main/java/org/teavm/backend/c/generate/CodeWriter.java b/core/src/main/java/org/teavm/backend/c/generate/CodeWriter.java index 65e7420b3..1dab9a7cb 100644 --- a/core/src/main/java/org/teavm/backend/c/generate/CodeWriter.java +++ b/core/src/main/java/org/teavm/backend/c/generate/CodeWriter.java @@ -15,56 +15,37 @@ */ package org.teavm.backend.c.generate; -import java.io.PrintWriter; import org.teavm.model.ValueType; import org.teavm.model.util.VariableType; -public class CodeWriter { - private PrintWriter writer; - private int indentLevel; - private boolean isLineStart; - - public CodeWriter(PrintWriter writer) { - this.writer = writer; - } +public abstract class CodeWriter { + public abstract CodeWriter fragment(); public CodeWriter println() { return println(""); } public CodeWriter println(String string) { - addIndentIfNecessary(); - writer.print(string); - writer.print("\n"); - isLineStart = true; + append(string); + newLine(); return this; } public CodeWriter print(String string) { - addIndentIfNecessary(); - writer.print(string); + append(string); return this; } public CodeWriter indent() { - indentLevel++; + indentBy(1); return this; } public CodeWriter outdent() { - indentLevel--; + indentBy(-1); return this; } - private void addIndentIfNecessary() { - if (isLineStart) { - for (int i = 0; i < indentLevel; ++i) { - writer.print(" "); - } - isLineStart = false; - } - } - public CodeWriter printType(ValueType type) { print(typeAsString(type)); return this; @@ -148,4 +129,12 @@ public class CodeWriter { return this; } + + protected abstract void newLine(); + + protected abstract void append(String text); + + protected abstract void indentBy(int amount); + + public abstract void flush(); } diff --git a/core/src/main/java/org/teavm/backend/c/generate/NameProvider.java b/core/src/main/java/org/teavm/backend/c/generate/NameProvider.java index ab8e057bb..d2f20554c 100644 --- a/core/src/main/java/org/teavm/backend/c/generate/NameProvider.java +++ b/core/src/main/java/org/teavm/backend/c/generate/NameProvider.java @@ -18,6 +18,7 @@ package org.teavm.backend.c.generate; import java.util.Arrays; import java.util.HashMap; import java.util.HashSet; +import java.util.LinkedHashSet; import java.util.Map; import java.util.Set; import org.teavm.interop.Export; @@ -51,6 +52,8 @@ public class NameProvider { private Map classInstanceNames = new HashMap<>(); private Map supertypeNames = new HashMap<>(); + private Set types = new LinkedHashSet<>(); + public NameProvider(ClassReaderSource classSource) { this.classSource = classSource; @@ -126,10 +129,12 @@ public class NameProvider { } public String forClassClass(String className) { + types.add(ValueType.object(className)); return classClassNames.computeIfAbsent(className, k -> pickUnoccupied(suggestForClass(k) + "_VT")); } public String forClassInstance(ValueType type) { + types.add(type); return classInstanceNames.computeIfAbsent(type, k -> pickUnoccupied(suggestForType(k) + "_Cls")); } @@ -226,4 +231,8 @@ public class NameProvider { return result; } + + public Set getTypes() { + return types; + } } diff --git a/core/src/main/java/org/teavm/runtime/FreeChunk.java b/core/src/main/java/org/teavm/runtime/FreeChunk.java index 829ebc46f..e7c9c0957 100644 --- a/core/src/main/java/org/teavm/runtime/FreeChunk.java +++ b/core/src/main/java/org/teavm/runtime/FreeChunk.java @@ -15,6 +15,11 @@ */ package org.teavm.runtime; -class FreeChunk extends RuntimeObject { +import org.teavm.interop.StaticInit; +import org.teavm.interop.Structure; + +@StaticInit +class FreeChunk extends Structure { + int classReference; int size; } diff --git a/core/src/main/java/org/teavm/runtime/GC.java b/core/src/main/java/org/teavm/runtime/GC.java index 658b5c1f4..121fecc85 100644 --- a/core/src/main/java/org/teavm/runtime/GC.java +++ b/core/src/main/java/org/teavm/runtime/GC.java @@ -80,7 +80,7 @@ public final class GC { } currentChunk.classReference = 0; freeMemory -= size; - return current; + return current.toAddress().toStructure(); } private static void getAvailableChunk(int size) { @@ -204,7 +204,7 @@ public final class GC { FreeChunkHolder freeChunkPtr = gcStorageAddress().toStructure(); freeChunks = 0; - RuntimeObject object = heapAddress().toStructure(); + FreeChunk object = heapAddress().toStructure(); FreeChunk lastFreeSpace = null; long heapSize = availableBytes(); long reclaimedSpace = 0; @@ -229,7 +229,7 @@ public final class GC { if (free) { if (lastFreeSpace == null) { - lastFreeSpace = (FreeChunk) object; + lastFreeSpace = object; } if (!object.toAddress().isLessThan(currentRegionEnd)) { @@ -335,18 +335,18 @@ public final class GC { return Structure.add(FreeChunkHolder.class, currentChunkPointer, index); } - private static int objectSize(RuntimeObject object) { + private static int objectSize(FreeChunk object) { if (object.classReference == 0) { - return ((FreeChunk) object).size; + return object.size; } else { - RuntimeClass cls = RuntimeClass.getClass(object); + RuntimeClass cls = RuntimeClass.getClass(object.toAddress().toStructure()); if (cls.itemType == null) { return cls.size; } else { int itemSize = (cls.itemType.flags & RuntimeClass.PRIMITIVE) == 0 ? Address.sizeOf() : cls.itemType.size; - RuntimeArray array = (RuntimeArray) object; + RuntimeArray array = object.toAddress().toStructure(); Address address = Address.fromInt(Structure.sizeOf(RuntimeArray.class)); address = Address.align(address, itemSize); address = address.add(itemSize * array.size); diff --git a/core/src/main/resources/org/teavm/backend/c/runtime.c b/core/src/main/resources/org/teavm/backend/c/runtime.c index dbade4f91..e30d26f26 100644 --- a/core/src/main/resources/org/teavm/backend/c/runtime.c +++ b/core/src/main/resources/org/teavm/backend/c/runtime.c @@ -115,5 +115,5 @@ static int64_t currentTimeMillis() { struct timespec time; clock_gettime(CLOCK_REALTIME, &time); - return time.tv_sec * 1000 + round(time.tv_nsec / 1000000); + return time.tv_sec * 1000 + (int64_t) round(time.tv_nsec / 1000000); } \ No newline at end of file