C backend: generate code to buffer, simplify generator

This commit is contained in:
Alexey Andreev 2018-03-26 22:45:41 +03:00 committed by Alexey Andreev
parent dc227e1e42
commit 0d1cb85067
14 changed files with 498 additions and 673 deletions

View File

@ -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<String> 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<String> sortClassNames(ListableClassReaderSource classes) {
@ -372,7 +331,7 @@ public class CTarget implements TeaVMTarget {
}
private void generateMain(GenerationContext context, CodeWriter writer, ListableClassHolderSource classes,
TypeCollector types) {
Set<? extends ValueType> 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<? extends ValueType> 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;
}

View File

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

View File

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

View File

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

View File

@ -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<ValueType> types = new HashSet<>();
public Set<? extends ValueType> getTypes() {
return types;
}
public void collect(ListableClassReaderSource classSource) {
for (String className : classSource.getClassNames()) {
ClassReader cls = classSource.get(className);
collect(cls);
}
}
public void collectFromCallSites(List<CallSiteDescriptor> 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<? extends VariableReader> 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;
}
}
}
}

View File

@ -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<Fragment> 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<Fragment> fragments;
InnerWriterFragment(List<Fragment> fragments) {
this.fragments = fragments;
}
@Override
void writeTo(WriterWithContext writer) {
for (Fragment fragment : fragments) {
fragment.writeTo(writer);
}
}
}
}

View File

@ -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<String> classLayoutOffsets = new ObjectIntHashMap<>();
private List<FieldReference[]> staticGcRoots = new ArrayList<>();
private List<FieldReference[]> layouts = new ArrayList<>();
private int currentLayoutIndex;
private Set<ValueType> 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<String> 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<ValueType> getTypes() {
return types;
}
private void collectTypes(List<String> 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(), "<clinit>", 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<String> classNames) {
List<FieldReference[]> 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<String> classNames) {
List<FieldReference[]> 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<? extends ValueType> 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<? extends ValueType> 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(), "<clinit>", 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<TagRegistry.Range> 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);");
}
}

View File

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

View File

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

View File

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

View File

@ -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<ValueType, String> classInstanceNames = new HashMap<>();
private Map<ValueType, String> supertypeNames = new HashMap<>();
private Set<ValueType> 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<? extends ValueType> getTypes() {
return types;
}
}

View File

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

View File

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

View File

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