mirror of
https://github.com/konsoletyper/teavm.git
synced 2024-11-27 01:30:35 +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.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;
|
||||
}
|
||||
|
@ -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 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);");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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(";");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
}
|
Loading…
Reference in New Issue
Block a user