mirror of
https://github.com/Eaglercraft-TeaVM-Fork/eagler-teavm.git
synced 2025-01-03 05:44:10 -08:00
C backend: generate code to buffer, simplify generator
This commit is contained in:
parent
dc227e1e42
commit
0d1cb85067
|
@ -33,15 +33,12 @@ import java.util.Set;
|
||||||
import org.teavm.ast.decompilation.Decompiler;
|
import org.teavm.ast.decompilation.Decompiler;
|
||||||
import org.teavm.backend.c.analyze.CDependencyListener;
|
import org.teavm.backend.c.analyze.CDependencyListener;
|
||||||
import org.teavm.backend.c.analyze.Characteristics;
|
import org.teavm.backend.c.analyze.Characteristics;
|
||||||
import org.teavm.backend.c.analyze.StringPoolFiller;
|
import org.teavm.backend.c.generate.BufferedCodeWriter;
|
||||||
import org.teavm.backend.c.analyze.TypeCollector;
|
|
||||||
import org.teavm.backend.c.generate.CallSiteGenerator;
|
|
||||||
import org.teavm.backend.c.generate.ClassGenerator;
|
import org.teavm.backend.c.generate.ClassGenerator;
|
||||||
import org.teavm.backend.c.generate.CodeWriter;
|
import org.teavm.backend.c.generate.CodeWriter;
|
||||||
import org.teavm.backend.c.generate.GenerationContext;
|
import org.teavm.backend.c.generate.GenerationContext;
|
||||||
import org.teavm.backend.c.generate.NameProvider;
|
import org.teavm.backend.c.generate.NameProvider;
|
||||||
import org.teavm.backend.c.generate.StringPool;
|
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.ArrayGenerator;
|
||||||
import org.teavm.backend.c.generators.Generator;
|
import org.teavm.backend.c.generators.Generator;
|
||||||
import org.teavm.backend.c.intrinsic.AddressIntrinsic;
|
import org.teavm.backend.c.intrinsic.AddressIntrinsic;
|
||||||
|
@ -214,26 +211,20 @@ public class CTarget implements TeaVMTarget {
|
||||||
GenerationContext context = new GenerationContext(vtableProvider, characteristics, stringPool, nameProvider,
|
GenerationContext context = new GenerationContext(vtableProvider, characteristics, stringPool, nameProvider,
|
||||||
controller.getDiagnostics(), classes, intrinsics, generators);
|
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(
|
try (PrintWriter writer = new PrintWriter(new OutputStreamWriter(
|
||||||
buildTarget.createResource(outputName), "UTF-8"))) {
|
buildTarget.createResource(outputName), "UTF-8"))) {
|
||||||
CodeWriter codeWriter = new CodeWriter(writer);
|
codeWriter.writeTo(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);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -253,47 +244,15 @@ public class CTarget implements TeaVMTarget {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void generateClasses(ListableClassHolderSource classes, ClassGenerator classGenerator,
|
private void generateClasses(ListableClassHolderSource classes, ClassGenerator classGenerator) {
|
||||||
GenerationContext context, CodeWriter writer, TypeCollector typeCollector) {
|
|
||||||
List<String> classNames = sortClassNames(classes);
|
List<String> classNames = sortClassNames(classes);
|
||||||
|
|
||||||
for (String className : classNames) {
|
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);
|
ClassHolder cls = classes.get(className);
|
||||||
classGenerator.generateClass(cls);
|
classGenerator.generateClass(cls);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
classGenerator.generateRemainingData(classNames, shadowStackTransformer);
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<String> sortClassNames(ListableClassReaderSource classes) {
|
private List<String> sortClassNames(ListableClassReaderSource classes) {
|
||||||
|
@ -372,7 +331,7 @@ public class CTarget implements TeaVMTarget {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void generateMain(GenerationContext context, CodeWriter writer, ListableClassHolderSource classes,
|
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("int main(int argc, char** argv) {").indent();
|
||||||
|
|
||||||
writer.println("initHeap(" + minHeapSize + ");");
|
writer.println("initHeap(" + minHeapSize + ");");
|
||||||
|
@ -405,11 +364,11 @@ public class CTarget implements TeaVMTarget {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void generateVirtualTableHeaders(GenerationContext context, CodeWriter writer,
|
private void generateVirtualTableHeaders(GenerationContext context, CodeWriter writer,
|
||||||
TypeCollector typeCollector) {
|
Set<? extends ValueType> types) {
|
||||||
String classClassName = context.getNames().forClassInstance(ValueType.object("java.lang.Class"));
|
String classClassName = context.getNames().forClassInstance(ValueType.object("java.lang.Class"));
|
||||||
writer.println("int32_t classHeader = PACK_CLASS(&" + classClassName + ") | " + RuntimeObject.GC_MARKED + ";");
|
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)) {
|
if (!ClassGenerator.needsVirtualTable(context.getCharacteristics(), type)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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());
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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--;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -19,7 +19,7 @@ import com.carrotsearch.hppc.ObjectIntHashMap;
|
||||||
import com.carrotsearch.hppc.ObjectIntMap;
|
import com.carrotsearch.hppc.ObjectIntMap;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Collection;
|
import java.util.LinkedHashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import org.teavm.ast.RegularMethodNode;
|
import org.teavm.ast.RegularMethodNode;
|
||||||
|
@ -37,7 +37,6 @@ import org.teavm.model.ClassReader;
|
||||||
import org.teavm.model.ClassReaderSource;
|
import org.teavm.model.ClassReaderSource;
|
||||||
import org.teavm.model.ElementModifier;
|
import org.teavm.model.ElementModifier;
|
||||||
import org.teavm.model.FieldHolder;
|
import org.teavm.model.FieldHolder;
|
||||||
import org.teavm.model.FieldReader;
|
|
||||||
import org.teavm.model.FieldReference;
|
import org.teavm.model.FieldReference;
|
||||||
import org.teavm.model.MethodDescriptor;
|
import org.teavm.model.MethodDescriptor;
|
||||||
import org.teavm.model.MethodHolder;
|
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.TagRegistry;
|
||||||
import org.teavm.model.classes.VirtualTable;
|
import org.teavm.model.classes.VirtualTable;
|
||||||
import org.teavm.model.classes.VirtualTableEntry;
|
import org.teavm.model.classes.VirtualTableEntry;
|
||||||
|
import org.teavm.model.lowlevel.ShadowStackTransformer;
|
||||||
import org.teavm.runtime.RuntimeClass;
|
import org.teavm.runtime.RuntimeClass;
|
||||||
import org.teavm.runtime.RuntimeObject;
|
import org.teavm.runtime.RuntimeObject;
|
||||||
|
|
||||||
public class ClassGenerator {
|
public class ClassGenerator {
|
||||||
private GenerationContext context;
|
private GenerationContext context;
|
||||||
|
private ClassReaderSource unprocessedClassSource;
|
||||||
private Decompiler decompiler;
|
private Decompiler decompiler;
|
||||||
private TagRegistry tagRegistry;
|
private TagRegistry tagRegistry;
|
||||||
private CodeWriter writer;
|
|
||||||
private CodeGenerator codeGenerator;
|
private CodeGenerator codeGenerator;
|
||||||
private ObjectIntMap<String> classLayoutOffsets = new ObjectIntHashMap<>();
|
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,
|
public ClassGenerator(GenerationContext context, ClassReaderSource unprocessedClassSource,
|
||||||
CodeWriter writer) {
|
TagRegistry tagRegistry, Decompiler decompiler, CodeWriter writer) {
|
||||||
this.context = context;
|
this.context = context;
|
||||||
|
this.unprocessedClassSource = unprocessedClassSource;
|
||||||
this.tagRegistry = tagRegistry;
|
this.tagRegistry = tagRegistry;
|
||||||
this.decompiler = decompiler;
|
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) {
|
public void generateClass(ClassHolder cls) {
|
||||||
generateForwardClassStructure(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()) {
|
for (MethodHolder method : cls.getMethods()) {
|
||||||
if (method.hasModifier(ElementModifier.ABSTRACT)) {
|
if (method.hasModifier(ElementModifier.ABSTRACT)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (method.hasModifier(ElementModifier.NATIVE)
|
|
||||||
&& method.getAnnotations().get(DelegateTo.class.getName()) == null
|
if (method.hasModifier(ElementModifier.NATIVE)) {
|
||||||
&& context.getGenerator(method.getReference()) == null) {
|
if (!tryDelegateToMethod(cls, method)) {
|
||||||
|
tryUsingGenerator(method);
|
||||||
|
}
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
codeGenerator.generateMethodSignature(method.getReference(), method.hasModifier(ElementModifier.STATIC),
|
generateMethodForwardDeclaration(method);
|
||||||
false);
|
RegularMethodNode methodNode = decompiler.decompileRegular(method);
|
||||||
writer.println(";");
|
codeGenerator.generateMethod(methodNode);
|
||||||
}
|
|
||||||
|
|
||||||
if (needsInitializer(cls)) {
|
|
||||||
writer.print("static void ").print(context.getNames().forClassInitializer(cls.getName())).println("();");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void generateForwardClassStructure(ClassHolder cls) {
|
private void generateMethodForwardDeclaration(MethodHolder method) {
|
||||||
if (!needsData(cls) || isSystemClass(cls)) {
|
codeGenerator.generateMethodSignature(forwardDeclarationsWriter, method.getReference(),
|
||||||
|
method.hasModifier(ElementModifier.STATIC), false);
|
||||||
|
forwardDeclarationsWriter.println(";");
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private void generateInitializer(ClassHolder cls) {
|
||||||
|
if (!needsInitializer(cls)) {
|
||||||
return;
|
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) {
|
codeWriter.print("static void ").print(context.getNames().forClassInitializer(cls.getName()))
|
||||||
generateClassStructure(cls);
|
.println("() {").indent();
|
||||||
generateStaticFields(cls);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void generateVirtualTableStructures(ClassHolder cls) {
|
String classInstanceName = context.getNames().forClassInstance(ValueType.object(cls.getName()));
|
||||||
generateVirtualTableStructure(cls);
|
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) {
|
private void generateClassStructure(ClassHolder cls) {
|
||||||
if (!needsData(cls)) {
|
if (!needsData(cls)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
generateForwardClassStructure(cls);
|
||||||
|
|
||||||
String name = context.getNames().forClass(cls.getName());
|
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())) {
|
if (cls.getParent() == null || !cls.getParent().equals(Structure.class.getName())) {
|
||||||
String parentName = cls.getParent();
|
String parentName = cls.getParent();
|
||||||
if (parentName == null) {
|
if (parentName == null) {
|
||||||
parentName = RuntimeObject.class.getName();
|
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()) {
|
for (FieldHolder field : cls.getFields()) {
|
||||||
if (field.hasModifier(ElementModifier.STATIC)) {
|
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) {
|
private void generateForwardClassStructure(ClassHolder cls) {
|
||||||
if (!needsData(cls)) {
|
if (isSystemClass(cls)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (FieldHolder field : cls.getFields()) {
|
forwardDeclarationsWriter.print("struct ").print(context.getNames().forClass(cls.getName())).println(";");
|
||||||
if (!field.hasModifier(ElementModifier.STATIC)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
String fieldName = context.getNames().forStaticField(field.getReference());
|
|
||||||
writer.print("static ").printStrictType(field.getType()).print(" ").print(fieldName).println(";");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void generateStaticGCRoots(Collection<String> classNames) {
|
private void generateVirtualTable(ValueType type) {
|
||||||
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) {
|
|
||||||
if (!needsVirtualTable(context.getCharacteristics(), type)) {
|
if (!needsVirtualTable(context.getCharacteristics(), type)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
String className;
|
generateIsSupertypeFunction(type);
|
||||||
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);
|
|
||||||
|
|
||||||
String className = null;
|
String className = null;
|
||||||
if (type instanceof ValueType.Object) {
|
if (type instanceof ValueType.Object) {
|
||||||
className = ((ValueType.Object) type).getClassName();
|
className = ((ValueType.Object) type).getClassName();
|
||||||
|
generateVirtualTableStructure(unprocessedClassSource.get(className));
|
||||||
} else if (type instanceof ValueType.Array) {
|
} else if (type instanceof ValueType.Array) {
|
||||||
className = "java.lang.Object";
|
className = "java.lang.Object";
|
||||||
}
|
}
|
||||||
|
@ -316,12 +275,13 @@ public class ClassGenerator {
|
||||||
: "JavaClass";
|
: "JavaClass";
|
||||||
String name = context.getNames().forClassInstance(type);
|
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) {
|
if (className != null) {
|
||||||
writer.println(".parent = {").indent();
|
vtableWriter.println(".parent = {").indent();
|
||||||
generateRuntimeClassInitializer(type, allTypes);
|
generateRuntimeClassInitializer(type);
|
||||||
writer.outdent().println("},");
|
vtableWriter.outdent().println("},");
|
||||||
|
|
||||||
VirtualTable virtualTable = context.getVirtualTableProvider().lookup(className);
|
VirtualTable virtualTable = context.getVirtualTableProvider().lookup(className);
|
||||||
if (virtualTable != null) {
|
if (virtualTable != null) {
|
||||||
|
@ -333,21 +293,21 @@ public class ClassGenerator {
|
||||||
String implName = entry.getImplementor() != null
|
String implName = entry.getImplementor() != null
|
||||||
? "&" + context.getNames().forMethod(entry.getImplementor())
|
? "&" + context.getNames().forMethod(entry.getImplementor())
|
||||||
: "NULL";
|
: "NULL";
|
||||||
writer.print(".").print(methodName).print(" = ").print(implName);
|
vtableWriter.print(".").print(methodName).print(" = ").print(implName);
|
||||||
if (i < entries.size() - 1) {
|
if (i < entries.size() - 1) {
|
||||||
writer.print(",");
|
vtableWriter.print(",");
|
||||||
}
|
}
|
||||||
writer.println();
|
vtableWriter.println();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} 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;
|
String sizeExpr;
|
||||||
int tag;
|
int tag;
|
||||||
String parent;
|
String parent;
|
||||||
|
@ -371,7 +331,7 @@ public class ClassGenerator {
|
||||||
}
|
}
|
||||||
tag = tagRegistry.getRanges(className).get(0).lower;
|
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()))
|
? "&" + context.getNames().forClassInstance(ValueType.object(cls.getParent()))
|
||||||
: "NULL";
|
: "NULL";
|
||||||
itemTypeExpr = "NULL";
|
itemTypeExpr = "NULL";
|
||||||
|
@ -406,24 +366,96 @@ public class ClassGenerator {
|
||||||
|
|
||||||
ValueType arrayType = ValueType.arrayOf(type);
|
ValueType arrayType = ValueType.arrayOf(type);
|
||||||
String arrayTypeExpr;
|
String arrayTypeExpr;
|
||||||
if (allTypes.contains(arrayType)) {
|
if (types.contains(arrayType)) {
|
||||||
arrayTypeExpr = "&" + context.getNames().forClassInstance(arrayType);
|
arrayTypeExpr = "&" + context.getNames().forClassInstance(arrayType);
|
||||||
} else {
|
} else {
|
||||||
arrayTypeExpr = "NULL";
|
arrayTypeExpr = "NULL";
|
||||||
}
|
}
|
||||||
|
|
||||||
writer.println(".parent = {},");
|
vtableWriter.println(".parent = {},");
|
||||||
writer.print(".").print(classFieldName("size")).print(" = ").print(sizeExpr).println(",");
|
vtableWriter.print(".").print(classFieldName("size")).print(" = ").print(sizeExpr).println(",");
|
||||||
writer.print(".").print(classFieldName("flags")).println(" = " + flags + ",");
|
vtableWriter.print(".").print(classFieldName("flags")).println(" = " + flags + ",");
|
||||||
writer.print(".").print(classFieldName("tag")).print(" = ").print(String.valueOf(tag)).println(",");
|
vtableWriter.print(".").print(classFieldName("tag")).print(" = ").print(String.valueOf(tag)).println(",");
|
||||||
writer.print(".").print(classFieldName("canary")).println(" = 0,");
|
vtableWriter.print(".").print(classFieldName("canary")).println(" = 0,");
|
||||||
writer.print(".").print(classFieldName("name")).println(" = stringPool + " + nameRef + ",");
|
vtableWriter.print(".").print(classFieldName("name")).println(" = stringPool + " + nameRef + ",");
|
||||||
writer.print(".").print(classFieldName("arrayType")).println(" = " + arrayTypeExpr + ",");
|
vtableWriter.print(".").print(classFieldName("arrayType")).println(" = " + arrayTypeExpr + ",");
|
||||||
writer.print(".").print(classFieldName("itemType")).println(" = " + itemTypeExpr + ",");
|
vtableWriter.print(".").print(classFieldName("itemType")).println(" = " + itemTypeExpr + ",");
|
||||||
writer.print(".").print(classFieldName("isSupertypeOf")).println(" = &" + superTypeFunction + ",");
|
vtableWriter.print(".").print(classFieldName("isSupertypeOf")).println(" = &" + superTypeFunction + ",");
|
||||||
writer.print(".").print(classFieldName("parent")).println(" = " + parent + ",");
|
vtableWriter.print(".").print(classFieldName("parent")).println(" = " + parent + ",");
|
||||||
writer.print(".").print(classFieldName("enumValues")).println(" = NULL,");
|
vtableWriter.print(".").print(classFieldName("enumValues")).println(" = NULL,");
|
||||||
writer.print(".").print(classFieldName("layout")).println(" = " + layout);
|
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) {
|
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) {
|
private boolean needsInitializer(ClassHolder cls) {
|
||||||
return !context.getCharacteristics().isStaticInit(cls.getName())
|
return !context.getCharacteristics().isStaticInit(cls.getName())
|
||||||
&& !context.getCharacteristics().isStructure(cls.getName())
|
&& !context.getCharacteristics().isStructure(cls.getName())
|
||||||
|
@ -535,6 +533,7 @@ public class ClassGenerator {
|
||||||
String methodName = delegateToAnnot.getValue("value").getString();
|
String methodName = delegateToAnnot.getValue("value").getString();
|
||||||
for (MethodHolder candidate : cls.getMethods()) {
|
for (MethodHolder candidate : cls.getMethods()) {
|
||||||
if (candidate.getName().equals(methodName)) {
|
if (candidate.getName().equals(methodName)) {
|
||||||
|
generateMethodForwardDeclaration(method);
|
||||||
delegateToMethod(method, candidate);
|
delegateToMethod(method, candidate);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -544,34 +543,34 @@ public class ClassGenerator {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void delegateToMethod(MethodHolder callingMethod, MethodHolder delegateMethod) {
|
private void delegateToMethod(MethodHolder callingMethod, MethodHolder delegateMethod) {
|
||||||
codeGenerator.generateMethodSignature(callingMethod.getReference(),
|
codeGenerator.generateMethodSignature(codeWriter, callingMethod.getReference(),
|
||||||
callingMethod.hasModifier(ElementModifier.STATIC), true);
|
callingMethod.hasModifier(ElementModifier.STATIC), true);
|
||||||
writer.println(" {").indent();
|
codeWriter.println(" {").indent();
|
||||||
|
|
||||||
if (callingMethod.getResultType() != ValueType.VOID) {
|
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);
|
boolean isStatic = callingMethod.hasModifier(ElementModifier.STATIC);
|
||||||
int start = 0;
|
int start = 0;
|
||||||
if (!isStatic) {
|
if (!isStatic) {
|
||||||
writer.print("_this_");
|
codeWriter.print("_this_");
|
||||||
} else {
|
} else {
|
||||||
if (callingMethod.parameterCount() > 0) {
|
if (callingMethod.parameterCount() > 0) {
|
||||||
writer.print("local_1");
|
codeWriter.print("local_1");
|
||||||
}
|
}
|
||||||
start++;
|
start++;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = start; i < callingMethod.parameterCount(); ++i) {
|
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) {
|
private void tryUsingGenerator(MethodHolder method) {
|
||||||
|
@ -581,9 +580,10 @@ public class ClassGenerator {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
generateMethodForwardDeclaration(method);
|
||||||
boolean isStatic = method.hasModifier(ElementModifier.STATIC);
|
boolean isStatic = method.hasModifier(ElementModifier.STATIC);
|
||||||
codeGenerator.generateMethodSignature(methodRef, isStatic, true);
|
codeGenerator.generateMethodSignature(codeWriter, methodRef, isStatic, true);
|
||||||
writer.println(" {").indent();
|
codeWriter.println(" {").indent();
|
||||||
|
|
||||||
generator.generate(new GeneratorContext() {
|
generator.generate(new GeneratorContext() {
|
||||||
@Override
|
@Override
|
||||||
|
@ -605,9 +605,9 @@ public class ClassGenerator {
|
||||||
public String getParameterName(int index) {
|
public String getParameterName(int index) {
|
||||||
return index == 0 ? "_this_" : "local_" + index;
|
return index == 0 ? "_this_" : "local_" + index;
|
||||||
}
|
}
|
||||||
}, writer, methodRef);
|
}, codeWriter, methodRef);
|
||||||
|
|
||||||
writer.outdent().println("}");
|
codeWriter.outdent().println("}");
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String nameOfType(ValueType type) {
|
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);
|
String name = context.getNames().forSupertypeFunction(type);
|
||||||
writer.println("static int32_t " + name + "(JavaClass*);");
|
vtableForwardWriter.println("static int32_t " + name + "(JavaClass*);");
|
||||||
}
|
isSupertypeWriter.println("static int32_t " + name + "(JavaClass* cls) {").indent();
|
||||||
|
|
||||||
public void generateIsSupertypeFunction(ValueType type) {
|
|
||||||
String name = context.getNames().forSupertypeFunction(type);
|
|
||||||
writer.println("static int32_t " + name + "(JavaClass* cls) {").indent();
|
|
||||||
|
|
||||||
if (type instanceof ValueType.Object) {
|
if (type instanceof ValueType.Object) {
|
||||||
generateIsSuperclassFunction(((ValueType.Object) type).getClassName());
|
generateIsSuperclassFunction(((ValueType.Object) type).getClassName());
|
||||||
|
@ -662,43 +658,43 @@ public class ClassGenerator {
|
||||||
generateIsSuperArrayFunction(((ValueType.Array) type).getItemType());
|
generateIsSuperArrayFunction(((ValueType.Array) type).getItemType());
|
||||||
}
|
}
|
||||||
|
|
||||||
writer.outdent().println("}");
|
isSupertypeWriter.outdent().println("}");
|
||||||
}
|
}
|
||||||
|
|
||||||
private void generateIsSuperclassFunction(String className) {
|
private void generateIsSuperclassFunction(String className) {
|
||||||
List<TagRegistry.Range> ranges = tagRegistry.getRanges(className);
|
List<TagRegistry.Range> ranges = tagRegistry.getRanges(className);
|
||||||
if (ranges.isEmpty()) {
|
if (ranges.isEmpty()) {
|
||||||
writer.println("return INT32_C(0);");
|
isSupertypeWriter.println("return INT32_C(0);");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
String tagName = context.getNames().forMemberField(new FieldReference(
|
String tagName = context.getNames().forMemberField(new FieldReference(
|
||||||
RuntimeClass.class.getName(), "tag"));
|
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 lower = ranges.get(0).lower;
|
||||||
int upper = ranges.get(ranges.size() - 1).upper;
|
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) {
|
for (int i = 1; i < ranges.size(); ++i) {
|
||||||
lower = ranges.get(i - 1).upper;
|
lower = ranges.get(i - 1).upper;
|
||||||
upper = ranges.get(i).lower;
|
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) {
|
private void generateIsSuperArrayFunction(ValueType itemType) {
|
||||||
String itemTypeName = context.getNames().forMemberField(new FieldReference(
|
String itemTypeName = context.getNames().forMemberField(new FieldReference(
|
||||||
RuntimeClass.class.getName(), "itemType"));
|
RuntimeClass.class.getName(), "itemType"));
|
||||||
writer.println("JavaClass* itemType = cls->" + itemTypeName + ";");
|
isSupertypeWriter.println("JavaClass* itemType = cls->" + itemTypeName + ";");
|
||||||
writer.println("if (itemType == NULL) return INT32_C(0);");
|
isSupertypeWriter.println("if (itemType == NULL) return INT32_C(0);");
|
||||||
|
|
||||||
if (itemType instanceof ValueType.Primitive) {
|
if (itemType instanceof ValueType.Primitive) {
|
||||||
writer.println("return itemType == &" + context.getNames().forClassInstance(itemType) + ";");
|
isSupertypeWriter.println("return itemType == &" + context.getNames().forClassInstance(itemType) + ";");
|
||||||
} else {
|
} else {
|
||||||
writer.println("return " + context.getNames().forSupertypeFunction(itemType) + "(itemType);");
|
isSupertypeWriter.println("return " + context.getNames().forSupertypeFunction(itemType) + "(itemType);");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -78,6 +78,7 @@ public class CodeGenerationVisitor implements ExprVisitor, StatementVisitor {
|
||||||
private NameProvider names;
|
private NameProvider names;
|
||||||
private CodeWriter writer;
|
private CodeWriter writer;
|
||||||
private int temporaryReceiverLevel;
|
private int temporaryReceiverLevel;
|
||||||
|
private int maxTemporaryReceiverLevel;
|
||||||
private MethodReference callingMethod;
|
private MethodReference callingMethod;
|
||||||
|
|
||||||
public CodeGenerationVisitor(GenerationContext context, CodeWriter writer) {
|
public CodeGenerationVisitor(GenerationContext context, CodeWriter writer) {
|
||||||
|
@ -86,6 +87,10 @@ public class CodeGenerationVisitor implements ExprVisitor, StatementVisitor {
|
||||||
this.names = context.getNames();
|
this.names = context.getNames();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public int getTemporaryReceivers() {
|
||||||
|
return maxTemporaryReceiverLevel;
|
||||||
|
}
|
||||||
|
|
||||||
public void setCallingMethod(MethodReference callingMethod) {
|
public void setCallingMethod(MethodReference callingMethod) {
|
||||||
this.callingMethod = callingMethod;
|
this.callingMethod = callingMethod;
|
||||||
}
|
}
|
||||||
|
@ -334,6 +339,7 @@ public class CodeGenerationVisitor implements ExprVisitor, StatementVisitor {
|
||||||
switch (expr.getType()) {
|
switch (expr.getType()) {
|
||||||
case CONSTRUCTOR: {
|
case CONSTRUCTOR: {
|
||||||
String receiver = "recv_" + temporaryReceiverLevel++;
|
String receiver = "recv_" + temporaryReceiverLevel++;
|
||||||
|
maxTemporaryReceiverLevel = Math.max(maxTemporaryReceiverLevel, temporaryReceiverLevel);
|
||||||
writer.print("(" + receiver + " = ");
|
writer.print("(" + receiver + " = ");
|
||||||
allocObject(expr.getMethod().getClassName());
|
allocObject(expr.getMethod().getClassName());
|
||||||
writer.print(", ");
|
writer.print(", ");
|
||||||
|
@ -371,6 +377,7 @@ public class CodeGenerationVisitor implements ExprVisitor, StatementVisitor {
|
||||||
}
|
}
|
||||||
case DYNAMIC: {
|
case DYNAMIC: {
|
||||||
String receiver = "recv_" + temporaryReceiverLevel++;
|
String receiver = "recv_" + temporaryReceiverLevel++;
|
||||||
|
maxTemporaryReceiverLevel = Math.max(maxTemporaryReceiverLevel, temporaryReceiverLevel);
|
||||||
writer.print("((").print(receiver).print(" = ");
|
writer.print("((").print(receiver).print(" = ");
|
||||||
expr.getArguments().get(0).acceptVisitor(this);
|
expr.getArguments().get(0).acceptVisitor(this);
|
||||||
|
|
||||||
|
|
|
@ -17,7 +17,6 @@ package org.teavm.backend.c.generate;
|
||||||
|
|
||||||
import org.teavm.ast.RegularMethodNode;
|
import org.teavm.ast.RegularMethodNode;
|
||||||
import org.teavm.ast.VariableNode;
|
import org.teavm.ast.VariableNode;
|
||||||
import org.teavm.backend.c.analyze.TemporaryVariableEstimator;
|
|
||||||
import org.teavm.model.ElementModifier;
|
import org.teavm.model.ElementModifier;
|
||||||
import org.teavm.model.MethodDescriptor;
|
import org.teavm.model.MethodDescriptor;
|
||||||
import org.teavm.model.MethodReference;
|
import org.teavm.model.MethodReference;
|
||||||
|
@ -25,6 +24,7 @@ import org.teavm.model.MethodReference;
|
||||||
public class CodeGenerator {
|
public class CodeGenerator {
|
||||||
private GenerationContext context;
|
private GenerationContext context;
|
||||||
private CodeWriter writer;
|
private CodeWriter writer;
|
||||||
|
private CodeWriter localsWriter;
|
||||||
private NameProvider names;
|
private NameProvider names;
|
||||||
|
|
||||||
public CodeGenerator(GenerationContext context, CodeWriter writer) {
|
public CodeGenerator(GenerationContext context, CodeWriter writer) {
|
||||||
|
@ -34,30 +34,34 @@ public class CodeGenerator {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void generateMethod(RegularMethodNode methodNode) {
|
public void generateMethod(RegularMethodNode methodNode) {
|
||||||
generateMethodSignature(methodNode.getReference(),
|
generateMethodSignature(writer, methodNode.getReference(),
|
||||||
methodNode.getModifiers().contains(ElementModifier.STATIC), true);
|
methodNode.getModifiers().contains(ElementModifier.STATIC), true);
|
||||||
|
|
||||||
writer.print(" {").indent().println();
|
writer.print(" {").indent().println();
|
||||||
|
|
||||||
generateLocals(methodNode);
|
localsWriter = writer.fragment();
|
||||||
|
|
||||||
CodeGenerationVisitor visitor = new CodeGenerationVisitor(context, writer);
|
CodeGenerationVisitor visitor = new CodeGenerationVisitor(context, writer);
|
||||||
visitor.setCallingMethod(methodNode.getReference());
|
visitor.setCallingMethod(methodNode.getReference());
|
||||||
methodNode.getBody().acceptVisitor(visitor);
|
methodNode.getBody().acceptVisitor(visitor);
|
||||||
|
|
||||||
|
generateLocals(methodNode, visitor.getTemporaryReceivers());
|
||||||
|
|
||||||
writer.outdent().println("}");
|
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.print("static ");
|
||||||
writer.printType(methodRef.getReturnType()).print(" ").print(names.forMethod(methodRef)).print("(");
|
writer.printType(methodRef.getReturnType()).print(" ").print(names.forMethod(methodRef)).print("(");
|
||||||
|
|
||||||
generateMethodParameters(methodRef.getDescriptor(), isStatic, withNames);
|
generateMethodParameters(writer, methodRef.getDescriptor(), isStatic, withNames);
|
||||||
|
|
||||||
writer.print(")");
|
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) {
|
if (methodRef.parameterCount() == 0 && isStatic) {
|
||||||
return;
|
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;
|
int start = methodNode.getReference().parameterCount() + 1;
|
||||||
for (int i = start; i < methodNode.getVariables().size(); ++i) {
|
for (int i = start; i < methodNode.getVariables().size(); ++i) {
|
||||||
VariableNode variableNode = methodNode.getVariables().get(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();
|
for (int i = 0; i < receiverCount; ++i) {
|
||||||
methodNode.getBody().acceptVisitor(temporaryEstimator);
|
localsWriter.print("void* recv_").print(String.valueOf(i)).println(";");
|
||||||
for (int i = 0; i < temporaryEstimator.getMaxReceiverIndex(); ++i) {
|
|
||||||
writer.print("void* recv_").print(String.valueOf(i)).println(";");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,56 +15,37 @@
|
||||||
*/
|
*/
|
||||||
package org.teavm.backend.c.generate;
|
package org.teavm.backend.c.generate;
|
||||||
|
|
||||||
import java.io.PrintWriter;
|
|
||||||
import org.teavm.model.ValueType;
|
import org.teavm.model.ValueType;
|
||||||
import org.teavm.model.util.VariableType;
|
import org.teavm.model.util.VariableType;
|
||||||
|
|
||||||
public class CodeWriter {
|
public abstract class CodeWriter {
|
||||||
private PrintWriter writer;
|
public abstract CodeWriter fragment();
|
||||||
private int indentLevel;
|
|
||||||
private boolean isLineStart;
|
|
||||||
|
|
||||||
public CodeWriter(PrintWriter writer) {
|
|
||||||
this.writer = writer;
|
|
||||||
}
|
|
||||||
|
|
||||||
public CodeWriter println() {
|
public CodeWriter println() {
|
||||||
return println("");
|
return println("");
|
||||||
}
|
}
|
||||||
|
|
||||||
public CodeWriter println(String string) {
|
public CodeWriter println(String string) {
|
||||||
addIndentIfNecessary();
|
append(string);
|
||||||
writer.print(string);
|
newLine();
|
||||||
writer.print("\n");
|
|
||||||
isLineStart = true;
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public CodeWriter print(String string) {
|
public CodeWriter print(String string) {
|
||||||
addIndentIfNecessary();
|
append(string);
|
||||||
writer.print(string);
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public CodeWriter indent() {
|
public CodeWriter indent() {
|
||||||
indentLevel++;
|
indentBy(1);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public CodeWriter outdent() {
|
public CodeWriter outdent() {
|
||||||
indentLevel--;
|
indentBy(-1);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void addIndentIfNecessary() {
|
|
||||||
if (isLineStart) {
|
|
||||||
for (int i = 0; i < indentLevel; ++i) {
|
|
||||||
writer.print(" ");
|
|
||||||
}
|
|
||||||
isLineStart = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public CodeWriter printType(ValueType type) {
|
public CodeWriter printType(ValueType type) {
|
||||||
print(typeAsString(type));
|
print(typeAsString(type));
|
||||||
return this;
|
return this;
|
||||||
|
@ -148,4 +129,12 @@ public class CodeWriter {
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected abstract void newLine();
|
||||||
|
|
||||||
|
protected abstract void append(String text);
|
||||||
|
|
||||||
|
protected abstract void indentBy(int amount);
|
||||||
|
|
||||||
|
public abstract void flush();
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,6 +18,7 @@ package org.teavm.backend.c.generate;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
|
import java.util.LinkedHashSet;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import org.teavm.interop.Export;
|
import org.teavm.interop.Export;
|
||||||
|
@ -51,6 +52,8 @@ public class NameProvider {
|
||||||
private Map<ValueType, String> classInstanceNames = new HashMap<>();
|
private Map<ValueType, String> classInstanceNames = new HashMap<>();
|
||||||
private Map<ValueType, String> supertypeNames = new HashMap<>();
|
private Map<ValueType, String> supertypeNames = new HashMap<>();
|
||||||
|
|
||||||
|
private Set<ValueType> types = new LinkedHashSet<>();
|
||||||
|
|
||||||
public NameProvider(ClassReaderSource classSource) {
|
public NameProvider(ClassReaderSource classSource) {
|
||||||
this.classSource = classSource;
|
this.classSource = classSource;
|
||||||
|
|
||||||
|
@ -126,10 +129,12 @@ public class NameProvider {
|
||||||
}
|
}
|
||||||
|
|
||||||
public String forClassClass(String className) {
|
public String forClassClass(String className) {
|
||||||
|
types.add(ValueType.object(className));
|
||||||
return classClassNames.computeIfAbsent(className, k -> pickUnoccupied(suggestForClass(k) + "_VT"));
|
return classClassNames.computeIfAbsent(className, k -> pickUnoccupied(suggestForClass(k) + "_VT"));
|
||||||
}
|
}
|
||||||
|
|
||||||
public String forClassInstance(ValueType type) {
|
public String forClassInstance(ValueType type) {
|
||||||
|
types.add(type);
|
||||||
return classInstanceNames.computeIfAbsent(type, k -> pickUnoccupied(suggestForType(k) + "_Cls"));
|
return classInstanceNames.computeIfAbsent(type, k -> pickUnoccupied(suggestForType(k) + "_Cls"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -226,4 +231,8 @@ public class NameProvider {
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Set<? extends ValueType> getTypes() {
|
||||||
|
return types;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,6 +15,11 @@
|
||||||
*/
|
*/
|
||||||
package org.teavm.runtime;
|
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;
|
int size;
|
||||||
}
|
}
|
||||||
|
|
|
@ -80,7 +80,7 @@ public final class GC {
|
||||||
}
|
}
|
||||||
currentChunk.classReference = 0;
|
currentChunk.classReference = 0;
|
||||||
freeMemory -= size;
|
freeMemory -= size;
|
||||||
return current;
|
return current.toAddress().toStructure();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void getAvailableChunk(int size) {
|
private static void getAvailableChunk(int size) {
|
||||||
|
@ -204,7 +204,7 @@ public final class GC {
|
||||||
FreeChunkHolder freeChunkPtr = gcStorageAddress().toStructure();
|
FreeChunkHolder freeChunkPtr = gcStorageAddress().toStructure();
|
||||||
freeChunks = 0;
|
freeChunks = 0;
|
||||||
|
|
||||||
RuntimeObject object = heapAddress().toStructure();
|
FreeChunk object = heapAddress().toStructure();
|
||||||
FreeChunk lastFreeSpace = null;
|
FreeChunk lastFreeSpace = null;
|
||||||
long heapSize = availableBytes();
|
long heapSize = availableBytes();
|
||||||
long reclaimedSpace = 0;
|
long reclaimedSpace = 0;
|
||||||
|
@ -229,7 +229,7 @@ public final class GC {
|
||||||
|
|
||||||
if (free) {
|
if (free) {
|
||||||
if (lastFreeSpace == null) {
|
if (lastFreeSpace == null) {
|
||||||
lastFreeSpace = (FreeChunk) object;
|
lastFreeSpace = object;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!object.toAddress().isLessThan(currentRegionEnd)) {
|
if (!object.toAddress().isLessThan(currentRegionEnd)) {
|
||||||
|
@ -335,18 +335,18 @@ public final class GC {
|
||||||
return Structure.add(FreeChunkHolder.class, currentChunkPointer, index);
|
return Structure.add(FreeChunkHolder.class, currentChunkPointer, index);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static int objectSize(RuntimeObject object) {
|
private static int objectSize(FreeChunk object) {
|
||||||
if (object.classReference == 0) {
|
if (object.classReference == 0) {
|
||||||
return ((FreeChunk) object).size;
|
return object.size;
|
||||||
} else {
|
} else {
|
||||||
RuntimeClass cls = RuntimeClass.getClass(object);
|
RuntimeClass cls = RuntimeClass.getClass(object.toAddress().toStructure());
|
||||||
if (cls.itemType == null) {
|
if (cls.itemType == null) {
|
||||||
return cls.size;
|
return cls.size;
|
||||||
} else {
|
} else {
|
||||||
int itemSize = (cls.itemType.flags & RuntimeClass.PRIMITIVE) == 0
|
int itemSize = (cls.itemType.flags & RuntimeClass.PRIMITIVE) == 0
|
||||||
? Address.sizeOf()
|
? Address.sizeOf()
|
||||||
: cls.itemType.size;
|
: cls.itemType.size;
|
||||||
RuntimeArray array = (RuntimeArray) object;
|
RuntimeArray array = object.toAddress().toStructure();
|
||||||
Address address = Address.fromInt(Structure.sizeOf(RuntimeArray.class));
|
Address address = Address.fromInt(Structure.sizeOf(RuntimeArray.class));
|
||||||
address = Address.align(address, itemSize);
|
address = Address.align(address, itemSize);
|
||||||
address = address.add(itemSize * array.size);
|
address = address.add(itemSize * array.size);
|
||||||
|
|
|
@ -115,5 +115,5 @@ static int64_t currentTimeMillis() {
|
||||||
struct timespec time;
|
struct timespec time;
|
||||||
clock_gettime(CLOCK_REALTIME, &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);
|
||||||
}
|
}
|
Loading…
Reference in New Issue
Block a user